From 4daa121663e64494f909116ee6fb8566d8d31757 Mon Sep 17 00:00:00 2001 From: Thomas Basler Date: Fri, 29 Jul 2022 23:31:28 +0200 Subject: [PATCH] Added several classes to encapsulate the packet generation --- .../src/commands/AlarmDataCommand.cpp | 9 ++ lib/Hoymiles/src/commands/AlarmDataCommand.h | 10 ++ lib/Hoymiles/src/commands/CommandAbstract.cpp | 93 +++++++++++++++++++ lib/Hoymiles/src/commands/CommandAbstract.h | 48 ++++++++++ .../src/commands/MultiDataCommand.cpp | 51 ++++++++++ lib/Hoymiles/src/commands/MultiDataCommand.h | 16 ++++ .../src/commands/RealTimeRunDataCommand.cpp | 9 ++ .../src/commands/RealTimeRunDataCommand.h | 10 ++ .../src/commands/RequestFrameCommand.cpp | 21 +++++ .../src/commands/RequestFrameCommand.h | 11 +++ .../src/commands/SingleDataCommand.cpp | 7 ++ lib/Hoymiles/src/commands/SingleDataCommand.h | 10 ++ 12 files changed, 295 insertions(+) create mode 100644 lib/Hoymiles/src/commands/AlarmDataCommand.cpp create mode 100644 lib/Hoymiles/src/commands/AlarmDataCommand.h create mode 100644 lib/Hoymiles/src/commands/CommandAbstract.cpp create mode 100644 lib/Hoymiles/src/commands/CommandAbstract.h create mode 100644 lib/Hoymiles/src/commands/MultiDataCommand.cpp create mode 100644 lib/Hoymiles/src/commands/MultiDataCommand.h create mode 100644 lib/Hoymiles/src/commands/RealTimeRunDataCommand.cpp create mode 100644 lib/Hoymiles/src/commands/RealTimeRunDataCommand.h create mode 100644 lib/Hoymiles/src/commands/RequestFrameCommand.cpp create mode 100644 lib/Hoymiles/src/commands/RequestFrameCommand.h create mode 100644 lib/Hoymiles/src/commands/SingleDataCommand.cpp create mode 100644 lib/Hoymiles/src/commands/SingleDataCommand.h diff --git a/lib/Hoymiles/src/commands/AlarmDataCommand.cpp b/lib/Hoymiles/src/commands/AlarmDataCommand.cpp new file mode 100644 index 0000000..b602ded --- /dev/null +++ b/lib/Hoymiles/src/commands/AlarmDataCommand.cpp @@ -0,0 +1,9 @@ +#include "AlarmDataCommand.h" + +AlarmDataCommand::AlarmDataCommand(uint64_t target_address, uint64_t router_address, time_t time) + : MultiDataCommand(target_address, router_address) +{ + setTime(time); + setDataType(0x11); + setTimeout(200); +} \ No newline at end of file diff --git a/lib/Hoymiles/src/commands/AlarmDataCommand.h b/lib/Hoymiles/src/commands/AlarmDataCommand.h new file mode 100644 index 0000000..410d2b7 --- /dev/null +++ b/lib/Hoymiles/src/commands/AlarmDataCommand.h @@ -0,0 +1,10 @@ +#pragma once + +#include "MultiDataCommand.h" + +class AlarmDataCommand : public MultiDataCommand { +public: + AlarmDataCommand(uint64_t target_address = 0, uint64_t router_address = 0, time_t time = 0); + + RequestType getRequestType() { return RequestType::AlarmLog; }; +}; \ No newline at end of file diff --git a/lib/Hoymiles/src/commands/CommandAbstract.cpp b/lib/Hoymiles/src/commands/CommandAbstract.cpp new file mode 100644 index 0000000..5156f65 --- /dev/null +++ b/lib/Hoymiles/src/commands/CommandAbstract.cpp @@ -0,0 +1,93 @@ +#include "CommandAbstract.h" +#include "crc.h" +#include + +CommandAbstract::CommandAbstract(uint64_t target_address, uint64_t router_address) +{ + memset(_payload, 0, RF_LEN); + _payload_size = 0; + + setTargetAddress(target_address); + setRouterAddress(router_address); +} + +template +bool CommandAbstract::isA() +{ + return dynamic_cast(this) != NULL; +} + +const uint8_t* CommandAbstract::getDataPayload() +{ + _payload[_payload_size] = crc8(_payload, _payload_size); + return _payload; +} + +void CommandAbstract::dumpDataPayload(Stream& stream) +{ + const uint8_t* payload = getDataPayload(); + for (uint8_t i = 0; i < getDataSize(); i++) { + stream.print(payload[i], HEX); + stream.print(" "); + } + stream.println(""); +} + +uint8_t CommandAbstract::getDataSize() +{ + return _payload_size + 1; // Original payload plus crc8 +} + +void CommandAbstract::setTargetAddress(uint64_t address) +{ + convertSerialToPacketId(&_payload[1], address); +} +const uint64_t CommandAbstract::getTargetAddress() +{ + return _targetAddress; +} + +void CommandAbstract::setRouterAddress(uint64_t address) +{ + convertSerialToPacketId(&_payload[5], address); +} + +const uint64_t CommandAbstract::getRouterAddress() +{ + return _routerAddress; +} + +void CommandAbstract::setTimeout(uint32_t timeout) +{ + _timeout = timeout; +} + +uint32_t CommandAbstract::getTimeout() +{ + return _timeout; +} + +void CommandAbstract::setSendCount(uint8_t count) +{ + _sendCount = count; +} + +uint8_t CommandAbstract::getSendCount() +{ + return _sendCount; +} + +uint8_t CommandAbstract::incrementSendCount() +{ + return _sendCount++; +} + +void CommandAbstract::convertSerialToPacketId(uint8_t buffer[], uint64_t serial) +{ + serial_u s; + s.u64 = serial; + buffer[3] = s.b[0]; + buffer[2] = s.b[1]; + buffer[1] = s.b[2]; + buffer[0] = s.b[3]; +} \ No newline at end of file diff --git a/lib/Hoymiles/src/commands/CommandAbstract.h b/lib/Hoymiles/src/commands/CommandAbstract.h new file mode 100644 index 0000000..3786779 --- /dev/null +++ b/lib/Hoymiles/src/commands/CommandAbstract.h @@ -0,0 +1,48 @@ +#pragma once + +#include "types.h" +#include +#include + +#define RF_LEN 32 + +class CommandAbstract { +public: + CommandAbstract(uint64_t target_address = 0, uint64_t router_address = 0); + virtual ~CommandAbstract() {}; + + template + bool isA(); + + const uint8_t* getDataPayload(); + void dumpDataPayload(Stream& stream); + + uint8_t getDataSize(); + + void setTargetAddress(uint64_t address); + const uint64_t getTargetAddress(); + + void setRouterAddress(uint64_t address); + const uint64_t getRouterAddress(); + + void setTimeout(uint32_t timeout); + uint32_t getTimeout(); + + void setSendCount(uint8_t count); + uint8_t getSendCount(); + uint8_t incrementSendCount(); + + virtual RequestType getRequestType() = 0; + +protected: + uint8_t _payload[RF_LEN]; + uint8_t _payload_size; + uint32_t _timeout; + uint8_t _sendCount; + + uint64_t _targetAddress; + uint64_t _routerAddress; + +private: + void convertSerialToPacketId(uint8_t buffer[], uint64_t serial); +}; \ No newline at end of file diff --git a/lib/Hoymiles/src/commands/MultiDataCommand.cpp b/lib/Hoymiles/src/commands/MultiDataCommand.cpp new file mode 100644 index 0000000..0399511 --- /dev/null +++ b/lib/Hoymiles/src/commands/MultiDataCommand.cpp @@ -0,0 +1,51 @@ +#include "MultiDataCommand.h" +#include "crc.h" + +MultiDataCommand::MultiDataCommand(uint64_t target_address, uint64_t router_address, uint8_t data_type, time_t time) + : CommandAbstract(target_address, router_address) +{ + _payload[0] = 0x15; + _payload[9] = 0x80; + setDataType(data_type); + _payload[11] = 0x00; + setTime(time); + _payload[16] = 0x00; // Gap + _payload[17] = 0x00; // Gap + _payload[18] = 0x00; + _payload[19] = 0x00; + _payload[20] = 0x00; // Password + _payload[21] = 0x00; // Password + _payload[22] = 0x00; // Password + _payload[23] = 0x00; // Password + + uint16_t crc = crc16(&_payload[10], 14); // From data_type till password + _payload[24] = (uint8_t)(crc >> 8); + _payload[25] = (uint8_t)(crc); + + _payload_size = 26; +} + +void MultiDataCommand::setDataType(uint8_t data_type) +{ + _payload[10] = data_type; +} +uint8_t MultiDataCommand::getDataType() +{ + return _payload[10]; +} + +void MultiDataCommand::setTime(time_t time) +{ + _payload[12] = (uint8_t)(time >> 24); + _payload[13] = (uint8_t)(time >> 16); + _payload[14] = (uint8_t)(time >> 8); + _payload[15] = (uint8_t)(time); +} + +time_t MultiDataCommand::getTime() +{ + return (time_t)(_payload[12] << 24) + | (time_t)(_payload[13] << 16) + | (time_t)(_payload[14] << 8) + | (time_t)(_payload[15]); +} \ No newline at end of file diff --git a/lib/Hoymiles/src/commands/MultiDataCommand.h b/lib/Hoymiles/src/commands/MultiDataCommand.h new file mode 100644 index 0000000..f57c9b1 --- /dev/null +++ b/lib/Hoymiles/src/commands/MultiDataCommand.h @@ -0,0 +1,16 @@ +#pragma once + +#include "CommandAbstract.h" +#include + +class MultiDataCommand : public CommandAbstract { +public: + MultiDataCommand(uint64_t target_address = 0, uint64_t router_address = 0, uint8_t data_type = 0, time_t time = 0); + + void setTime(time_t time); + time_t getTime(); + +protected: + void setDataType(uint8_t data_type); + uint8_t getDataType(); +}; \ No newline at end of file diff --git a/lib/Hoymiles/src/commands/RealTimeRunDataCommand.cpp b/lib/Hoymiles/src/commands/RealTimeRunDataCommand.cpp new file mode 100644 index 0000000..6cc364d --- /dev/null +++ b/lib/Hoymiles/src/commands/RealTimeRunDataCommand.cpp @@ -0,0 +1,9 @@ +#include "RealTimeRunDataCommand.h" + +RealTimeRunDataCommand::RealTimeRunDataCommand(uint64_t target_address, uint64_t router_address, time_t time) + : MultiDataCommand(target_address, router_address) +{ + setTime(time); + setDataType(0x0b); + setTimeout(200); +} \ No newline at end of file diff --git a/lib/Hoymiles/src/commands/RealTimeRunDataCommand.h b/lib/Hoymiles/src/commands/RealTimeRunDataCommand.h new file mode 100644 index 0000000..5dec09d --- /dev/null +++ b/lib/Hoymiles/src/commands/RealTimeRunDataCommand.h @@ -0,0 +1,10 @@ +#pragma once + +#include "MultiDataCommand.h" + +class RealTimeRunDataCommand : public MultiDataCommand { +public: + RealTimeRunDataCommand(uint64_t target_address = 0, uint64_t router_address = 0, time_t time = 0); + + RequestType getRequestType() { return RequestType::Stats; }; +}; \ No newline at end of file diff --git a/lib/Hoymiles/src/commands/RequestFrameCommand.cpp b/lib/Hoymiles/src/commands/RequestFrameCommand.cpp new file mode 100644 index 0000000..eeaff02 --- /dev/null +++ b/lib/Hoymiles/src/commands/RequestFrameCommand.cpp @@ -0,0 +1,21 @@ +#include "RequestFrameCommand.h" + +RequestFrameCommand::RequestFrameCommand(uint64_t target_address, uint64_t router_address, uint8_t frame_no) + : SingleDataCommand(target_address, router_address) +{ + if (frame_no > 127) { + frame_no = 0; + } + setFrameNo(frame_no); + _payload_size = 10; +} + +void RequestFrameCommand::setFrameNo(uint8_t frame_no) +{ + _payload[9] = frame_no | 0x80; +} + +uint8_t RequestFrameCommand::getFrameNo() +{ + return _payload[9] & (~0x80); +} \ No newline at end of file diff --git a/lib/Hoymiles/src/commands/RequestFrameCommand.h b/lib/Hoymiles/src/commands/RequestFrameCommand.h new file mode 100644 index 0000000..53d49ad --- /dev/null +++ b/lib/Hoymiles/src/commands/RequestFrameCommand.h @@ -0,0 +1,11 @@ +#pragma once + +#include "SingleDataCommand.h" + +class RequestFrameCommand : public SingleDataCommand { +public: + RequestFrameCommand(uint64_t target_address = 0, uint64_t router_address = 0, uint8_t frame_no = 0); + + void setFrameNo(uint8_t frame_no); + uint8_t getFrameNo(); +}; \ No newline at end of file diff --git a/lib/Hoymiles/src/commands/SingleDataCommand.cpp b/lib/Hoymiles/src/commands/SingleDataCommand.cpp new file mode 100644 index 0000000..9e3f985 --- /dev/null +++ b/lib/Hoymiles/src/commands/SingleDataCommand.cpp @@ -0,0 +1,7 @@ +#include "SingleDataCommand.h" + +SingleDataCommand::SingleDataCommand(uint64_t target_address, uint64_t router_address) + : CommandAbstract(target_address, router_address) +{ + _payload[0] = 0x15; +} diff --git a/lib/Hoymiles/src/commands/SingleDataCommand.h b/lib/Hoymiles/src/commands/SingleDataCommand.h new file mode 100644 index 0000000..811300c --- /dev/null +++ b/lib/Hoymiles/src/commands/SingleDataCommand.h @@ -0,0 +1,10 @@ +#pragma once + +#include "CommandAbstract.h" + +class SingleDataCommand : public CommandAbstract { +public: + SingleDataCommand(uint64_t target_address = 0, uint64_t router_address = 0); + + RequestType getRequestType() { return RequestType::None; }; +}; \ No newline at end of file