Replace inverter_transaction with new command classes

This commit is contained in:
Thomas Basler 2022-07-30 00:37:54 +02:00
parent 4daa121663
commit 4413b603e3
4 changed files with 49 additions and 140 deletions

View File

@ -1,5 +1,6 @@
#include "HoymilesRadio.h" #include "HoymilesRadio.h"
#include "Hoymiles.h" #include "Hoymiles.h"
#include "commands/RequestFrameCommand.h"
#include "crc.h" #include "crc.h"
#include <Every.h> #include <Every.h>
#include <FunctionalInterrupt.h> #include <FunctionalInterrupt.h>
@ -85,16 +86,17 @@ void HoymilesRadio::loop()
if (_busyFlag && _rxTimeout.occured()) { if (_busyFlag && _rxTimeout.occured()) {
Serial.println(F("RX Period End")); Serial.println(F("RX Period End"));
std::shared_ptr<InverterAbstract> inv = Hoymiles.getInverterBySerial(currentTransaction.target.u64); std::shared_ptr<InverterAbstract> inv = Hoymiles.getInverterBySerial(_commandQueue.front().get()->getTargetAddress());
if (nullptr != inv) { if (nullptr != inv) {
uint8_t verifyResult = inv->verifyAllFragments(); uint8_t verifyResult = inv->verifyAllFragments();
if (verifyResult == FRAGMENT_ALL_MISSING) { 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")); Serial.println(F("Nothing received, resend whole request"));
sendLastPacketAgain(); sendLastPacketAgain();
} else { } else {
Serial.println(F("Nothing received, resend count exeeded")); Serial.println(F("Nothing received, resend count exeeded"));
_commandQueue.pop();
_busyFlag = false; _busyFlag = false;
} }
@ -115,18 +117,19 @@ void HoymilesRadio::loop()
} else { } else {
// Successfull received all packages // Successfull received all packages
Serial.println(F("Success")); Serial.println(F("Success"));
_commandQueue.pop();
_busyFlag = false; _busyFlag = false;
} }
} }
} else if (!_busyFlag) { } else if (!_busyFlag) {
// Currently in idle mode --> send packet if one is in the queue // Currently in idle mode --> send packet if one is in the queue
if (!_txBuffer.empty()) { if (!_commandQueue.empty()) {
inverter_transaction_t* t = _txBuffer.getBack(); CommandAbstract* cmd = _commandQueue.front().get();
auto inv = Hoymiles.getInverterBySerial(t->target.u64);
inv->setLastRequest(t->requestType); auto inv = Hoymiles.getInverterBySerial(cmd->getTargetAddress());
inv->setLastRequest(cmd->getRequestType());
inv->clearRxFragmentBuffer(); inv->clearRxFragmentBuffer();
sendEsbPacket(t->target, t->mainCmd, t->subCmd, t->payload, t->len, t->timeout); sendEsbPacket(cmd);
_txBuffer.popBack();
} }
} }
} }
@ -207,102 +210,51 @@ serial_u HoymilesRadio::convertSerialToRadioId(serial_u serial)
return radioId; 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) bool HoymilesRadio::checkFragmentCrc(fragment_t* fragment)
{ {
uint8_t crc = crc8(fragment->fragment, fragment->len - 1); uint8_t crc = crc8(fragment->fragment, fragment->len - 1);
return (crc == 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) { cmd->setRouterAddress(DtuSerial().u64);
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);
_radio->stopListening(); _radio->stopListening();
_radio->setChannel(getTxNxtChannel()); _radio->setChannel(getTxNxtChannel());
openWritingPipe(currentTransaction.target);
serial_u s;
s.u64 = cmd->getTargetAddress();
openWritingPipe(s);
_radio->setRetries(3, 15); _radio->setRetries(3, 15);
dumpBuf("TX ", txBuffer, 10 + currentTransaction.len + 1); cmd->dumpDataPayload(Serial);
_radio->write(txBuffer, 10 + currentTransaction.len + 1); _radio->write(cmd->getDataPayload(), cmd->getDataSize());
_radio->setRetries(0, 0); _radio->setRetries(0, 0);
openReadingPipe(); openReadingPipe();
_radio->setChannel(getRxNxtChannel()); _radio->setChannel(getRxNxtChannel());
_radio->startListening(); _radio->startListening();
_busyFlag = true; _busyFlag = true;
_rxTimeout.set(currentTransaction.timeout); _rxTimeout.set(cmd->getTimeout());
}
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;
} }
void HoymilesRadio::sendRetransmitPacket(uint8_t fragment_id) void HoymilesRadio::sendRetransmitPacket(uint8_t fragment_id)
{ {
sendEsbPacket( RequestFrameCommand cmd(
currentTransaction.target, _commandQueue.front().get()->getTargetAddress(),
currentTransaction.mainCmd, DtuSerial().u64,
(uint8_t)(0x80 + fragment_id), 0, 0, 60); fragment_id);
sendEsbPacket(&cmd);
} }
void HoymilesRadio::sendLastPacketAgain() void HoymilesRadio::sendLastPacketAgain()
{ {
sendEsbPacket(currentTransaction.target, 0, 0, 0, 0, 60, true); CommandAbstract* cmd = _commandQueue.front().get();
} sendEsbPacket(cmd);
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);
} }
void HoymilesRadio::dumpBuf(const char* info, uint8_t buf[], uint8_t len) void HoymilesRadio::dumpBuf(const char* info, uint8_t buf[], uint8_t len)

View File

@ -2,16 +2,18 @@
#include "CircularBuffer.h" #include "CircularBuffer.h"
#include "TimeoutHelper.h" #include "TimeoutHelper.h"
#include "commands/CommandAbstract.h"
#include "types.h" #include "types.h"
#include <RF24.h> #include <RF24.h>
#include <memory> #include <memory>
#include <nRF24L01.h> #include <nRF24L01.h>
#include <queue>
using namespace std;
// number of fragments hold in buffer // number of fragments hold in buffer
#define FRAGMENT_BUFFER_SIZE 30 #define FRAGMENT_BUFFER_SIZE 30
#define TX_BUFFER_SIZE 5
#define MAX_RESEND_COUNT 3 #define MAX_RESEND_COUNT 3
#ifndef HOYMILES_PIN_MISO #ifndef HOYMILES_PIN_MISO
@ -48,17 +50,20 @@ public:
void setDtuSerial(uint64_t serial); void setDtuSerial(uint64_t serial);
bool isIdle(); 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 sendRetransmitPacket(uint8_t fragment_id);
void sendLastPacketAgain(); void sendLastPacketAgain();
bool enqueTransaction(inverter_transaction_t* transaction);
static void u32CpyLittleEndian(uint8_t dest[], uint32_t src); template <typename T>
T* enqueCommand()
{
_commandQueue.push(make_shared<T>());
return static_cast<T*>(_commandQueue.back().get());
}
private: private:
void ARDUINO_ISR_ATTR handleIntr(); void ARDUINO_ISR_ATTR handleIntr();
static serial_u convertSerialToRadioId(serial_u serial); static serial_u convertSerialToRadioId(serial_u serial);
static void convertSerialToPacketId(uint8_t buffer[], serial_u serial);
uint8_t getRxNxtChannel(); uint8_t getRxNxtChannel();
uint8_t getTxNxtChannel(); uint8_t getTxNxtChannel();
void switchRxCh(); void switchRxCh();
@ -84,6 +89,5 @@ private:
bool _busyFlag = false; bool _busyFlag = false;
inverter_transaction_t currentTransaction; queue<shared_ptr<CommandAbstract>> _commandQueue;
CircularBuffer<inverter_transaction_t, TX_BUFFER_SIZE> _txBuffer;
}; };

View File

@ -1,6 +1,7 @@
#include "HM_Abstract.h" #include "HM_Abstract.h"
#include "HoymilesRadio.h" #include "HoymilesRadio.h"
#include "crc.h" #include "commands/AlarmDataCommand.h"
#include "commands/RealTimeRunDataCommand.h"
HM_Abstract::HM_Abstract(uint64_t serial) HM_Abstract::HM_Abstract(uint64_t serial)
: InverterAbstract(serial) {}; : InverterAbstract(serial) {};
@ -15,29 +16,10 @@ bool HM_Abstract::sendStatsRequest(HoymilesRadio* radio)
time_t now; time_t now;
time(&now); time(&now);
inverter_transaction_t payload; RealTimeRunDataCommand* cmd = radio->enqueCommand<RealTimeRunDataCommand>();
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; return true;
} }
@ -59,27 +41,9 @@ bool HM_Abstract::sendAlarmLogRequest(HoymilesRadio* radio)
time_t now; time_t now;
time(&now); time(&now);
inverter_transaction_t payload; AlarmDataCommand* cmd = radio->enqueCommand<AlarmDataCommand>();
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; return true;
} }

View File

@ -20,14 +20,3 @@ enum class RequestType {
Stats, Stats,
AlarmLog 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;