/* TUYA MODULE Copyright (C) 2019 by Maxim Prokhorov */ #pragma once #include #include #include "tuya_types.h" #include "tuya_transport.h" namespace tuya { using container = std::vector; using const_iterator = container::const_iterator; namespace util { template container serialize_frame(const T& frame) { container result; result.reserve(6 + frame.length()); result.push_back(frame.version()); result.push_back(frame.command()); result.push_back(static_cast(frame.length() >> 8) & 0xff); result.push_back(static_cast(frame.length() & 0xff)); if (frame.length()) { result.insert(result.end(), frame.cbegin(), frame.cend()); } return result; } } // namespace util class DataFrameView { public: explicit DataFrameView(const Transport& input) : _version(input[2]), _command(input[3]), _length((input[4] << 8) + input[5]), _begin(input.cbegin() + 6), _end(_begin + _length) {} explicit DataFrameView(const_iterator it) : _version(it[0]), _command(it[1]), _length((it[2] << 8) + it[3]), _begin(it + 4), _end(_begin + _length) {} explicit DataFrameView(const container& data) : DataFrameView(data.cbegin()) {} container data() const { return container(_begin, _end); } container serialize() const { return util::serialize_frame(*this); } const_iterator cbegin() const { return _begin; }; const_iterator cend() const { return _end; }; uint8_t operator[](size_t i) const { return *(_begin + i); } uint8_t version() const { return _version; } uint8_t command() const { return _command; } uint16_t length() const { return _length; } private: uint8_t _version { 0u }; uint8_t _command { 0u }; uint16_t _length { 0u }; const_iterator _begin; const_iterator _end; }; class DataFrame { public: template DataFrame(Command command, uint8_t version, T&& data) : _data(std::forward(data)), _command(static_cast(command)), _version(version) {} template DataFrame(Command command, T&& data) : _data(std::forward(data)), _command(static_cast(command)) {} explicit DataFrame(uint8_t command) : _command(command) {} explicit DataFrame(Command command) : DataFrame(static_cast(command)) {} explicit DataFrame(const Transport& input) : _version(input[2]), _command(input[3]) { auto length = (input[4] << 8) + input[5]; _data.reserve(length); auto data = input.cbegin() + 6; _data.insert(_data.begin(), data, data + length); } explicit DataFrame(const DataFrameView& view) : _data(view.cbegin(), view.cend()), _version(view.version()), _command(view.command()) {} const container& data() const { return _data; } const_iterator cbegin() const { return _data.cbegin(); }; const_iterator cend() const { return _data.cend(); }; uint8_t operator[](size_t i) const { return _data[i]; } container serialize() const { return util::serialize_frame(*this); } uint8_t version() const { return _version; } uint8_t command() const { return _command; } uint16_t length() const { return _data.size(); } private: container _data; uint8_t _version { 0u }; uint8_t _command { 0u }; }; } // namespace