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 "Hoymiles.h"
#include "commands/RequestFrameCommand.h"
#include "crc.h"
#include <Every.h>
#include <FunctionalInterrupt.h>
@ -85,16 +86,17 @@ void HoymilesRadio::loop()
if (_busyFlag && _rxTimeout.occured()) {
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) {
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)

View File

@ -2,16 +2,18 @@
#include "CircularBuffer.h"
#include "TimeoutHelper.h"
#include "commands/CommandAbstract.h"
#include "types.h"
#include <RF24.h>
#include <memory>
#include <nRF24L01.h>
#include <queue>
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 <typename T>
T* enqueCommand()
{
_commandQueue.push(make_shared<T>());
return static_cast<T*>(_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<inverter_transaction_t, TX_BUFFER_SIZE> _txBuffer;
queue<shared_ptr<CommandAbstract>> _commandQueue;
};

View File

@ -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<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;
}
@ -59,27 +41,9 @@ bool HM_Abstract::sendAlarmLogRequest(HoymilesRadio* radio)
time_t 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;
}

View File

@ -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;