/*
|
|
|
|
TUYA MODULE
|
|
|
|
Copyright (C) 2019 by Maxim Prokhorov <prokhorov dot max at outlook dot com>
|
|
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <vector>
|
|
|
|
#include "tuya_types.h"
|
|
#include "tuya_transport.h"
|
|
|
|
namespace tuya {
|
|
|
|
using container = std::vector<uint8_t>;
|
|
using const_iterator = container::const_iterator;
|
|
|
|
namespace util {
|
|
|
|
template <typename T>
|
|
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<uint8_t>(frame.length() >> 8) & 0xff);
|
|
result.push_back(static_cast<uint8_t>(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 <typename T>
|
|
DataFrame(Command command, uint8_t version, T&& data) :
|
|
_data(std::forward<T>(data)),
|
|
_command(static_cast<uint8_t>(command)),
|
|
_version(version)
|
|
{}
|
|
|
|
template <typename T>
|
|
DataFrame(Command command, T&& data) :
|
|
_data(std::forward<T>(data)),
|
|
_command(static_cast<uint8_t>(command))
|
|
{}
|
|
|
|
explicit DataFrame(uint8_t command) :
|
|
_command(command)
|
|
{}
|
|
|
|
explicit DataFrame(Command command) :
|
|
DataFrame(static_cast<uint8_t>(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
|