diff --git a/lib/Hoymiles/src/HoymilesRadio.cpp b/lib/Hoymiles/src/HoymilesRadio.cpp index 533d321..2b3f108 100644 --- a/lib/Hoymiles/src/HoymilesRadio.cpp +++ b/lib/Hoymiles/src/HoymilesRadio.cpp @@ -1,5 +1,6 @@ #include "HoymilesRadio.h" #include "Hoymiles.h" +#include "commands/RequestFrameCommand.h" #include "crc.h" #include #include @@ -85,16 +86,17 @@ void HoymilesRadio::loop() if (_busyFlag && _rxTimeout.occured()) { Serial.println(F("RX Period End")); - std::shared_ptr inv = Hoymiles.getInverterBySerial(currentTransaction.target.u64); + std::shared_ptr inv = Hoymiles.getInverterBySerial(_commandQueue.front().get()->getTargetAddress()); if (nullptr != inv) { uint8_t verifyResult = inv->verifyAllFragments(); if (verifyResult == FRAGMENT_ALL_MISSING) { - if (currentTransaction.sendCount < MAX_RESEND_COUNT) { + if (_commandQueue.front().get()->getSendCount() < MAX_RESEND_COUNT) { Serial.println(F("Nothing received, resend whole request")); sendLastPacketAgain(); } else { Serial.println(F("Nothing received, resend count exeeded")); + _commandQueue.pop(); _busyFlag = false; } @@ -115,18 +117,19 @@ void HoymilesRadio::loop() } else { // Successfull received all packages Serial.println(F("Success")); + _commandQueue.pop(); _busyFlag = false; } } } else if (!_busyFlag) { // Currently in idle mode --> send packet if one is in the queue - if (!_txBuffer.empty()) { - inverter_transaction_t* t = _txBuffer.getBack(); - auto inv = Hoymiles.getInverterBySerial(t->target.u64); - inv->setLastRequest(t->requestType); + if (!_commandQueue.empty()) { + CommandAbstract* cmd = _commandQueue.front().get(); + + auto inv = Hoymiles.getInverterBySerial(cmd->getTargetAddress()); + inv->setLastRequest(cmd->getRequestType()); inv->clearRxFragmentBuffer(); - sendEsbPacket(t->target, t->mainCmd, t->subCmd, t->payload, t->len, t->timeout); - _txBuffer.popBack(); + sendEsbPacket(cmd); } } } @@ -207,102 +210,51 @@ serial_u HoymilesRadio::convertSerialToRadioId(serial_u serial) return radioId; } -void HoymilesRadio::convertSerialToPacketId(uint8_t buffer[], serial_u serial) -{ - buffer[3] = serial.b[0]; - buffer[2] = serial.b[1]; - buffer[1] = serial.b[2]; - buffer[0] = serial.b[3]; -} - bool HoymilesRadio::checkFragmentCrc(fragment_t* fragment) { uint8_t crc = crc8(fragment->fragment, fragment->len - 1); return (crc == fragment->fragment[fragment->len - 1]); } -void HoymilesRadio::sendEsbPacket(serial_u target, uint8_t mainCmd, uint8_t subCmd, uint8_t payload[], uint8_t len, uint32_t timeout, bool resend) +void HoymilesRadio::sendEsbPacket(CommandAbstract* cmd) { - static uint8_t txBuffer[MAX_RF_PAYLOAD_SIZE]; + cmd->incrementSendCount(); - if (10 + currentTransaction.len + 1 > MAX_RF_PAYLOAD_SIZE) { - Serial.printf("FATAL: (%s, %d) payload too large\n", __FILE__, __LINE__); - return; - } - - if (!resend) { - currentTransaction.sendCount = 0; - currentTransaction.target = target; - currentTransaction.mainCmd = mainCmd; - currentTransaction.target = target; - currentTransaction.subCmd = subCmd; - memcpy(currentTransaction.payload, payload, len); - currentTransaction.len = len; - currentTransaction.timeout = timeout; - } else { - currentTransaction.sendCount++; - } - - memset(txBuffer, 0, MAX_RF_PAYLOAD_SIZE); - - txBuffer[0] = currentTransaction.mainCmd; - convertSerialToPacketId(&txBuffer[1], currentTransaction.target); // 4 byte long - convertSerialToPacketId(&txBuffer[5], DtuSerial()); // 4 byte long - txBuffer[9] = currentTransaction.subCmd; - - memcpy(&txBuffer[10], currentTransaction.payload, currentTransaction.len); - txBuffer[10 + currentTransaction.len] = crc8(txBuffer, 10 + currentTransaction.len); + cmd->setRouterAddress(DtuSerial().u64); _radio->stopListening(); _radio->setChannel(getTxNxtChannel()); - openWritingPipe(currentTransaction.target); + + serial_u s; + s.u64 = cmd->getTargetAddress(); + openWritingPipe(s); _radio->setRetries(3, 15); - dumpBuf("TX ", txBuffer, 10 + currentTransaction.len + 1); - _radio->write(txBuffer, 10 + currentTransaction.len + 1); + cmd->dumpDataPayload(Serial); + _radio->write(cmd->getDataPayload(), cmd->getDataSize()); _radio->setRetries(0, 0); openReadingPipe(); _radio->setChannel(getRxNxtChannel()); _radio->startListening(); _busyFlag = true; - _rxTimeout.set(currentTransaction.timeout); -} - -bool HoymilesRadio::enqueTransaction(inverter_transaction_t* transaction) -{ - if (!_txBuffer.full()) { - inverter_transaction_t* t; - t = _txBuffer.getFront(); - memcpy(t, transaction, sizeof(inverter_transaction_t)); - _txBuffer.pushFront(t); - return true; - } else { - Serial.println(F("TX Buffer full")); - } - - return false; + _rxTimeout.set(cmd->getTimeout()); } void HoymilesRadio::sendRetransmitPacket(uint8_t fragment_id) { - sendEsbPacket( - currentTransaction.target, - currentTransaction.mainCmd, - (uint8_t)(0x80 + fragment_id), 0, 0, 60); + RequestFrameCommand cmd( + _commandQueue.front().get()->getTargetAddress(), + DtuSerial().u64, + fragment_id); + + sendEsbPacket(&cmd); } void HoymilesRadio::sendLastPacketAgain() { - sendEsbPacket(currentTransaction.target, 0, 0, 0, 0, 60, true); -} - -void HoymilesRadio::u32CpyLittleEndian(uint8_t dest[], uint32_t src) -{ - dest[0] = ((src >> 24) & 0xff); - dest[1] = ((src >> 16) & 0xff); - dest[2] = ((src >> 8) & 0xff); - dest[3] = ((src)&0xff); + CommandAbstract* cmd = _commandQueue.front().get(); + sendEsbPacket(cmd); } void HoymilesRadio::dumpBuf(const char* info, uint8_t buf[], uint8_t len) diff --git a/lib/Hoymiles/src/HoymilesRadio.h b/lib/Hoymiles/src/HoymilesRadio.h index bea5295..0682dbf 100644 --- a/lib/Hoymiles/src/HoymilesRadio.h +++ b/lib/Hoymiles/src/HoymilesRadio.h @@ -2,16 +2,18 @@ #include "CircularBuffer.h" #include "TimeoutHelper.h" +#include "commands/CommandAbstract.h" #include "types.h" #include #include #include +#include + +using namespace std; // number of fragments hold in buffer #define FRAGMENT_BUFFER_SIZE 30 -#define TX_BUFFER_SIZE 5 - #define MAX_RESEND_COUNT 3 #ifndef HOYMILES_PIN_MISO @@ -48,17 +50,20 @@ public: void setDtuSerial(uint64_t serial); bool isIdle(); - void sendEsbPacket(serial_u target, uint8_t mainCmd, uint8_t subCmd, uint8_t payload[], uint8_t len, uint32_t timeout, bool resend = false); + void sendEsbPacket(CommandAbstract* cmd); void sendRetransmitPacket(uint8_t fragment_id); void sendLastPacketAgain(); - bool enqueTransaction(inverter_transaction_t* transaction); - static void u32CpyLittleEndian(uint8_t dest[], uint32_t src); + template + T* enqueCommand() + { + _commandQueue.push(make_shared()); + return static_cast(_commandQueue.back().get()); + } private: void ARDUINO_ISR_ATTR handleIntr(); static serial_u convertSerialToRadioId(serial_u serial); - static void convertSerialToPacketId(uint8_t buffer[], serial_u serial); uint8_t getRxNxtChannel(); uint8_t getTxNxtChannel(); void switchRxCh(); @@ -84,6 +89,5 @@ private: bool _busyFlag = false; - inverter_transaction_t currentTransaction; - CircularBuffer _txBuffer; + queue> _commandQueue; }; \ No newline at end of file diff --git a/lib/Hoymiles/src/inverters/HM_Abstract.cpp b/lib/Hoymiles/src/inverters/HM_Abstract.cpp index 9eaa95d..e11c52b 100644 --- a/lib/Hoymiles/src/inverters/HM_Abstract.cpp +++ b/lib/Hoymiles/src/inverters/HM_Abstract.cpp @@ -1,6 +1,7 @@ #include "HM_Abstract.h" #include "HoymilesRadio.h" -#include "crc.h" +#include "commands/AlarmDataCommand.h" +#include "commands/RealTimeRunDataCommand.h" HM_Abstract::HM_Abstract(uint64_t serial) : InverterAbstract(serial) {}; @@ -15,29 +16,10 @@ bool HM_Abstract::sendStatsRequest(HoymilesRadio* radio) time_t now; time(&now); - inverter_transaction_t payload; + RealTimeRunDataCommand* cmd = radio->enqueCommand(); + cmd->setTime(now); + cmd->setTargetAddress(serial()); - memset(payload.payload, 0, MAX_RF_PAYLOAD_SIZE); - - payload.target.u64 = serial(); - payload.mainCmd = 0x15; - payload.subCmd = 0x80; - payload.timeout = 200; - payload.len = 16; - - payload.payload[0] = 0x0b; - payload.payload[1] = 0x00; - - HoymilesRadio::u32CpyLittleEndian(&payload.payload[2], now); // sets the 4 following elements {2, 3, 4, 5} - payload.payload[9] = 0x05; - - uint16_t crc = crc16(&payload.payload[0], 14); - payload.payload[14] = (crc >> 8) & 0xff; - payload.payload[15] = (crc)&0xff; - - payload.requestType = RequestType::Stats; - - radio->enqueTransaction(&payload); return true; } @@ -59,27 +41,9 @@ bool HM_Abstract::sendAlarmLogRequest(HoymilesRadio* radio) time_t now; time(&now); - inverter_transaction_t payload; + AlarmDataCommand* cmd = radio->enqueCommand(); + cmd->setTime(now); + cmd->setTargetAddress(serial()); - memset(payload.payload, 0, MAX_RF_PAYLOAD_SIZE); - - payload.target.u64 = serial(); - payload.mainCmd = 0x15; - payload.subCmd = 0x80; - payload.timeout = 200; - payload.len = 16; - - payload.payload[0] = 0x11; - payload.payload[1] = 0x00; - - HoymilesRadio::u32CpyLittleEndian(&payload.payload[2], now); // sets the 4 following elements {2, 3, 4, 5} - - uint16_t crc = crc16(&payload.payload[0], 14); - payload.payload[14] = (crc >> 8) & 0xff; - payload.payload[15] = (crc)&0xff; - - payload.requestType = RequestType::AlarmLog; - - radio->enqueTransaction(&payload); return true; } \ No newline at end of file diff --git a/lib/Hoymiles/src/types.h b/lib/Hoymiles/src/types.h index e74ace8..1f7c3d3 100644 --- a/lib/Hoymiles/src/types.h +++ b/lib/Hoymiles/src/types.h @@ -20,14 +20,3 @@ enum class RequestType { Stats, AlarmLog }; - -typedef struct { - serial_u target; - RequestType requestType = RequestType::None; - uint8_t mainCmd; - uint8_t subCmd; - uint8_t payload[MAX_RF_PAYLOAD_SIZE]; - uint8_t len; - uint32_t timeout; - uint8_t sendCount; -} inverter_transaction_t; \ No newline at end of file