Add a HoymilesRadio base class
This enables to have multiple radio implementations while the inverter classes just refere to the base class
This commit is contained in:
parent
a7e9aaa862
commit
8404dd57a7
@ -22,20 +22,20 @@ void HoymilesClass::init(SPIClass* initialisedSpiBus, uint8_t pinCE, uint8_t pin
|
||||
HOY_SEMAPHORE_GIVE(); // release before first use
|
||||
|
||||
_pollInterval = 0;
|
||||
_radio.reset(new HoymilesRadio());
|
||||
_radio->init(initialisedSpiBus, pinCE, pinIRQ);
|
||||
_radioNrf.reset(new HoymilesRadio_NRF());
|
||||
_radioNrf->init(initialisedSpiBus, pinCE, pinIRQ);
|
||||
}
|
||||
|
||||
void HoymilesClass::loop()
|
||||
{
|
||||
HOY_SEMAPHORE_TAKE();
|
||||
_radio->loop();
|
||||
_radioNrf->loop();
|
||||
|
||||
if (getNumInverters() > 0) {
|
||||
if (millis() - _lastPoll > (_pollInterval * 1000)) {
|
||||
static uint8_t inverterPos = 0;
|
||||
|
||||
if (_radio->isIdle()) {
|
||||
if (_radioNrf->isIdle()) {
|
||||
std::shared_ptr<InverterAbstract> iv = getInverterByPos(inverterPos);
|
||||
if (iv != nullptr) {
|
||||
_messageOutput->print("Fetch inverter: ");
|
||||
@ -89,17 +89,17 @@ std::shared_ptr<InverterAbstract> HoymilesClass::addInverter(const char* name, u
|
||||
{
|
||||
std::shared_ptr<InverterAbstract> i = nullptr;
|
||||
if (HMS_4CH::isValidSerial(serial)) {
|
||||
i = std::make_shared<HMS_4CH>(_radio.get(), serial);
|
||||
i = std::make_shared<HMS_4CH>(_radioNrf.get(), serial);
|
||||
} else if (HMS_2CH::isValidSerial(serial)) {
|
||||
i = std::make_shared<HMS_2CH>(_radio.get(), serial);
|
||||
i = std::make_shared<HMS_2CH>(_radioNrf.get(), serial);
|
||||
} else if (HMS_1CH::isValidSerial(serial)) {
|
||||
i = std::make_shared<HMS_1CH>(_radio.get(), serial);
|
||||
i = std::make_shared<HMS_1CH>(_radioNrf.get(), serial);
|
||||
} else if (HM_4CH::isValidSerial(serial)) {
|
||||
i = std::make_shared<HM_4CH>(_radio.get(), serial);
|
||||
i = std::make_shared<HM_4CH>(_radioNrf.get(), serial);
|
||||
} else if (HM_2CH::isValidSerial(serial)) {
|
||||
i = std::make_shared<HM_2CH>(_radio.get(), serial);
|
||||
i = std::make_shared<HM_2CH>(_radioNrf.get(), serial);
|
||||
} else if (HM_1CH::isValidSerial(serial)) {
|
||||
i = std::make_shared<HM_1CH>(_radio.get(), serial);
|
||||
i = std::make_shared<HM_1CH>(_radioNrf.get(), serial);
|
||||
}
|
||||
|
||||
if (i) {
|
||||
@ -171,9 +171,9 @@ size_t HoymilesClass::getNumInverters()
|
||||
return _inverters.size();
|
||||
}
|
||||
|
||||
HoymilesRadio* HoymilesClass::getRadio()
|
||||
HoymilesRadio_NRF* HoymilesClass::getRadioNrf()
|
||||
{
|
||||
return _radio.get();
|
||||
return _radioNrf.get();
|
||||
}
|
||||
|
||||
uint32_t HoymilesClass::PollInterval()
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
#include "HoymilesRadio.h"
|
||||
#include "HoymilesRadio_NRF.h"
|
||||
#include "inverters/InverterAbstract.h"
|
||||
#include "types.h"
|
||||
#include <Print.h>
|
||||
@ -27,14 +27,14 @@ public:
|
||||
void removeInverterBySerial(uint64_t serial);
|
||||
size_t getNumInverters();
|
||||
|
||||
HoymilesRadio* getRadio();
|
||||
HoymilesRadio_NRF* getRadioNrf();
|
||||
|
||||
uint32_t PollInterval();
|
||||
void setPollInterval(uint32_t interval);
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<InverterAbstract>> _inverters;
|
||||
std::unique_ptr<HoymilesRadio> _radio;
|
||||
std::unique_ptr<HoymilesRadio_NRF> _radioNrf;
|
||||
|
||||
SemaphoreHandle_t _xSemaphore;
|
||||
|
||||
|
||||
@ -1,158 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2022 Thomas Basler and others
|
||||
* Copyright (C) 2023 Thomas Basler and others
|
||||
*/
|
||||
#include "HoymilesRadio.h"
|
||||
#include "Hoymiles.h"
|
||||
#include "commands/RequestFrameCommand.h"
|
||||
#include "crc.h"
|
||||
#include <Every.h>
|
||||
#include <FunctionalInterrupt.h>
|
||||
|
||||
void HoymilesRadio::init(SPIClass* initialisedSpiBus, uint8_t pinCE, uint8_t pinIRQ)
|
||||
{
|
||||
_dtuSerial.u64 = 0;
|
||||
|
||||
_spiPtr.reset(initialisedSpiBus);
|
||||
_radio.reset(new RF24(pinCE, initialisedSpiBus->pinSS()));
|
||||
|
||||
_radio->begin(_spiPtr.get());
|
||||
|
||||
_radio->setDataRate(RF24_250KBPS);
|
||||
_radio->enableDynamicPayloads();
|
||||
_radio->setCRCLength(RF24_CRC_16);
|
||||
_radio->setAddressWidth(5);
|
||||
_radio->setRetries(0, 0);
|
||||
_radio->maskIRQ(true, true, false); // enable only receiving interrupts
|
||||
if (_radio->isChipConnected()) {
|
||||
Hoymiles.getMessageOutput()->println("Connection successful");
|
||||
} else {
|
||||
Hoymiles.getMessageOutput()->println("Connection error!!");
|
||||
}
|
||||
|
||||
attachInterrupt(digitalPinToInterrupt(pinIRQ), std::bind(&HoymilesRadio::handleIntr, this), FALLING);
|
||||
|
||||
openReadingPipe();
|
||||
_radio->startListening();
|
||||
}
|
||||
|
||||
void HoymilesRadio::loop()
|
||||
{
|
||||
EVERY_N_MILLIS(4)
|
||||
{
|
||||
switchRxCh();
|
||||
}
|
||||
|
||||
if (_packetReceived) {
|
||||
Hoymiles.getMessageOutput()->println("Interrupt received");
|
||||
while (_radio->available()) {
|
||||
if (!(_rxBuffer.size() > FRAGMENT_BUFFER_SIZE)) {
|
||||
fragment_t f;
|
||||
memset(f.fragment, 0xcc, MAX_RF_PAYLOAD_SIZE);
|
||||
f.len = _radio->getDynamicPayloadSize();
|
||||
f.channel = _radio->getChannel();
|
||||
if (f.len > MAX_RF_PAYLOAD_SIZE)
|
||||
f.len = MAX_RF_PAYLOAD_SIZE;
|
||||
_radio->read(f.fragment, f.len);
|
||||
_rxBuffer.push(f);
|
||||
} else {
|
||||
Hoymiles.getMessageOutput()->println("Buffer full");
|
||||
_radio->flush_rx();
|
||||
}
|
||||
}
|
||||
_packetReceived = false;
|
||||
|
||||
} else {
|
||||
// Perform package parsing only if no packages are received
|
||||
if (!_rxBuffer.empty()) {
|
||||
fragment_t f = _rxBuffer.back();
|
||||
if (checkFragmentCrc(&f)) {
|
||||
std::shared_ptr<InverterAbstract> inv = Hoymiles.getInverterByFragment(&f);
|
||||
|
||||
if (nullptr != inv) {
|
||||
// Save packet in inverter rx buffer
|
||||
char buf[30];
|
||||
snprintf(buf, sizeof(buf), "RX Channel: %d --> ", f.channel);
|
||||
dumpBuf(buf, f.fragment, f.len);
|
||||
inv->addRxFragment(f.fragment, f.len);
|
||||
} else {
|
||||
Hoymiles.getMessageOutput()->println("Inverter Not found!");
|
||||
}
|
||||
|
||||
} else {
|
||||
Hoymiles.getMessageOutput()->println("Frame kaputt");
|
||||
}
|
||||
|
||||
// Remove paket from buffer even it was corrupted
|
||||
_rxBuffer.pop();
|
||||
}
|
||||
}
|
||||
|
||||
if (_busyFlag && _rxTimeout.occured()) {
|
||||
Hoymiles.getMessageOutput()->println("RX Period End");
|
||||
std::shared_ptr<InverterAbstract> inv = Hoymiles.getInverterBySerial(_commandQueue.front().get()->getTargetAddress());
|
||||
|
||||
if (nullptr != inv) {
|
||||
CommandAbstract* cmd = _commandQueue.front().get();
|
||||
uint8_t verifyResult = inv->verifyAllFragments(cmd);
|
||||
if (verifyResult == FRAGMENT_ALL_MISSING_RESEND) {
|
||||
Hoymiles.getMessageOutput()->println("Nothing received, resend whole request");
|
||||
sendLastPacketAgain();
|
||||
|
||||
} else if (verifyResult == FRAGMENT_ALL_MISSING_TIMEOUT) {
|
||||
Hoymiles.getMessageOutput()->println("Nothing received, resend count exeeded");
|
||||
_commandQueue.pop();
|
||||
_busyFlag = false;
|
||||
|
||||
} else if (verifyResult == FRAGMENT_RETRANSMIT_TIMEOUT) {
|
||||
Hoymiles.getMessageOutput()->println("Retransmit timeout");
|
||||
_commandQueue.pop();
|
||||
_busyFlag = false;
|
||||
|
||||
} else if (verifyResult == FRAGMENT_HANDLE_ERROR) {
|
||||
Hoymiles.getMessageOutput()->println("Packet handling error");
|
||||
_commandQueue.pop();
|
||||
_busyFlag = false;
|
||||
|
||||
} else if (verifyResult > 0) {
|
||||
// Perform Retransmit
|
||||
Hoymiles.getMessageOutput()->print("Request retransmit: ");
|
||||
Hoymiles.getMessageOutput()->println(verifyResult);
|
||||
sendRetransmitPacket(verifyResult);
|
||||
|
||||
} else {
|
||||
// Successful received all packages
|
||||
Hoymiles.getMessageOutput()->println("Success");
|
||||
_commandQueue.pop();
|
||||
_busyFlag = false;
|
||||
}
|
||||
} else {
|
||||
// If inverter was not found, assume the command is invalid
|
||||
Hoymiles.getMessageOutput()->println("RX: Invalid inverter found");
|
||||
_commandQueue.pop();
|
||||
_busyFlag = false;
|
||||
}
|
||||
} else if (!_busyFlag) {
|
||||
// Currently in idle mode --> send packet if one is in the queue
|
||||
if (!_commandQueue.empty()) {
|
||||
CommandAbstract* cmd = _commandQueue.front().get();
|
||||
|
||||
auto inv = Hoymiles.getInverterBySerial(cmd->getTargetAddress());
|
||||
if (nullptr != inv) {
|
||||
inv->clearRxFragmentBuffer();
|
||||
sendEsbPacket(cmd);
|
||||
} else {
|
||||
Hoymiles.getMessageOutput()->println("TX: Invalid inverter found");
|
||||
_commandQueue.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HoymilesRadio::setPALevel(rf24_pa_dbm_e paLevel)
|
||||
{
|
||||
_radio->setPALevel(paLevel);
|
||||
}
|
||||
|
||||
serial_u HoymilesRadio::DtuSerial()
|
||||
{
|
||||
@ -162,62 +13,6 @@ serial_u HoymilesRadio::DtuSerial()
|
||||
void HoymilesRadio::setDtuSerial(uint64_t serial)
|
||||
{
|
||||
_dtuSerial.u64 = serial;
|
||||
openReadingPipe();
|
||||
}
|
||||
|
||||
bool HoymilesRadio::isIdle()
|
||||
{
|
||||
return !_busyFlag;
|
||||
}
|
||||
|
||||
bool HoymilesRadio::isConnected()
|
||||
{
|
||||
return _radio->isChipConnected();
|
||||
}
|
||||
|
||||
bool HoymilesRadio::isPVariant()
|
||||
{
|
||||
return _radio->isPVariant();
|
||||
}
|
||||
|
||||
void HoymilesRadio::openReadingPipe()
|
||||
{
|
||||
serial_u s;
|
||||
s = convertSerialToRadioId(_dtuSerial);
|
||||
_radio->openReadingPipe(1, s.u64);
|
||||
}
|
||||
|
||||
void HoymilesRadio::openWritingPipe(serial_u serial)
|
||||
{
|
||||
serial_u s;
|
||||
s = convertSerialToRadioId(serial);
|
||||
_radio->openWritingPipe(s.u64);
|
||||
}
|
||||
|
||||
void ARDUINO_ISR_ATTR HoymilesRadio::handleIntr()
|
||||
{
|
||||
_packetReceived = true;
|
||||
}
|
||||
|
||||
uint8_t HoymilesRadio::getRxNxtChannel()
|
||||
{
|
||||
if (++_rxChIdx >= sizeof(_rxChLst))
|
||||
_rxChIdx = 0;
|
||||
return _rxChLst[_rxChIdx];
|
||||
}
|
||||
|
||||
uint8_t HoymilesRadio::getTxNxtChannel()
|
||||
{
|
||||
if (++_txChIdx >= sizeof(_txChLst))
|
||||
_txChIdx = 0;
|
||||
return _txChLst[_txChIdx];
|
||||
}
|
||||
|
||||
void HoymilesRadio::switchRxCh()
|
||||
{
|
||||
_radio->stopListening();
|
||||
_radio->setChannel(getRxNxtChannel());
|
||||
_radio->startListening();
|
||||
}
|
||||
|
||||
serial_u HoymilesRadio::convertSerialToRadioId(serial_u serial)
|
||||
@ -232,59 +27,6 @@ serial_u HoymilesRadio::convertSerialToRadioId(serial_u serial)
|
||||
return radioId;
|
||||
}
|
||||
|
||||
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(CommandAbstract* cmd)
|
||||
{
|
||||
cmd->incrementSendCount();
|
||||
|
||||
cmd->setRouterAddress(DtuSerial().u64);
|
||||
|
||||
_radio->stopListening();
|
||||
_radio->setChannel(getTxNxtChannel());
|
||||
|
||||
serial_u s;
|
||||
s.u64 = cmd->getTargetAddress();
|
||||
openWritingPipe(s);
|
||||
_radio->setRetries(3, 15);
|
||||
|
||||
Hoymiles.getMessageOutput()->print("TX ");
|
||||
Hoymiles.getMessageOutput()->print(cmd->getCommandName());
|
||||
Hoymiles.getMessageOutput()->print(" Channel: ");
|
||||
Hoymiles.getMessageOutput()->print(_radio->getChannel());
|
||||
Hoymiles.getMessageOutput()->print(" --> ");
|
||||
cmd->dumpDataPayload(Hoymiles.getMessageOutput());
|
||||
_radio->write(cmd->getDataPayload(), cmd->getDataSize());
|
||||
|
||||
_radio->setRetries(0, 0);
|
||||
openReadingPipe();
|
||||
_radio->setChannel(getRxNxtChannel());
|
||||
_radio->startListening();
|
||||
_busyFlag = true;
|
||||
_rxTimeout.set(cmd->getTimeout());
|
||||
}
|
||||
|
||||
void HoymilesRadio::sendRetransmitPacket(uint8_t fragment_id)
|
||||
{
|
||||
CommandAbstract* cmd = _commandQueue.front().get();
|
||||
|
||||
CommandAbstract* requestCmd = cmd->getRequestFrameCommand(fragment_id);
|
||||
|
||||
if (requestCmd != nullptr) {
|
||||
sendEsbPacket(requestCmd);
|
||||
}
|
||||
}
|
||||
|
||||
void HoymilesRadio::sendLastPacketAgain()
|
||||
{
|
||||
CommandAbstract* cmd = _commandQueue.front().get();
|
||||
sendEsbPacket(cmd);
|
||||
}
|
||||
|
||||
void HoymilesRadio::dumpBuf(const char* info, uint8_t buf[], uint8_t len)
|
||||
{
|
||||
|
||||
|
||||
@ -1,30 +1,15 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
#include "TimeoutHelper.h"
|
||||
#include "commands/CommandAbstract.h"
|
||||
#include "types.h"
|
||||
#include <RF24.h>
|
||||
#include <memory>
|
||||
#include <nRF24L01.h>
|
||||
#include <queue>
|
||||
#include <cmt2300a.h>
|
||||
|
||||
// number of fragments hold in buffer
|
||||
#define FRAGMENT_BUFFER_SIZE 30
|
||||
|
||||
class HoymilesRadio {
|
||||
public:
|
||||
void init(SPIClass* initialisedSpiBus, uint8_t pinCE, uint8_t pinIRQ);
|
||||
void loop();
|
||||
void setPALevel(rf24_pa_dbm_e paLevel);
|
||||
|
||||
serial_u DtuSerial();
|
||||
void setDtuSerial(uint64_t serial);
|
||||
|
||||
bool isIdle();
|
||||
bool isConnected();
|
||||
bool isPVariant();
|
||||
virtual void setDtuSerial(uint64_t serial);
|
||||
|
||||
template <typename T>
|
||||
T* enqueCommand()
|
||||
@ -33,37 +18,10 @@ public:
|
||||
return static_cast<T*>(_commandQueue.back().get());
|
||||
}
|
||||
|
||||
private:
|
||||
void ARDUINO_ISR_ATTR handleIntr();
|
||||
protected:
|
||||
static serial_u convertSerialToRadioId(serial_u serial);
|
||||
uint8_t getRxNxtChannel();
|
||||
uint8_t getTxNxtChannel();
|
||||
void switchRxCh();
|
||||
void openReadingPipe();
|
||||
void openWritingPipe(serial_u serial);
|
||||
bool checkFragmentCrc(fragment_t* fragment);
|
||||
void dumpBuf(const char* info, uint8_t buf[], uint8_t len);
|
||||
|
||||
void sendEsbPacket(CommandAbstract* cmd);
|
||||
void sendRetransmitPacket(uint8_t fragment_id);
|
||||
void sendLastPacketAgain();
|
||||
|
||||
std::unique_ptr<SPIClass> _spiPtr;
|
||||
std::unique_ptr<RF24> _radio;
|
||||
uint8_t _rxChLst[5] = { 3, 23, 40, 61, 75 };
|
||||
uint8_t _rxChIdx = 0;
|
||||
|
||||
uint8_t _txChLst[5] = { 3, 23, 40, 61, 75 };
|
||||
uint8_t _txChIdx = 0;
|
||||
|
||||
volatile bool _packetReceived = false;
|
||||
|
||||
std::queue<fragment_t> _rxBuffer;
|
||||
TimeoutHelper _rxTimeout;
|
||||
|
||||
serial_u _dtuSerial;
|
||||
|
||||
bool _busyFlag = false;
|
||||
|
||||
std::queue<std::shared_ptr<CommandAbstract>> _commandQueue;
|
||||
};
|
||||
270
lib/Hoymiles/src/HoymilesRadio_NRF.cpp
Normal file
270
lib/Hoymiles/src/HoymilesRadio_NRF.cpp
Normal file
@ -0,0 +1,270 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2022 Thomas Basler and others
|
||||
*/
|
||||
#include "HoymilesRadio_NRF.h"
|
||||
#include "Hoymiles.h"
|
||||
#include "commands/RequestFrameCommand.h"
|
||||
#include "crc.h"
|
||||
#include <Every.h>
|
||||
#include <FunctionalInterrupt.h>
|
||||
|
||||
void HoymilesRadio_NRF::init(SPIClass* initialisedSpiBus, uint8_t pinCE, uint8_t pinIRQ)
|
||||
{
|
||||
_dtuSerial.u64 = 0;
|
||||
|
||||
_spiPtr.reset(initialisedSpiBus);
|
||||
_radio.reset(new RF24(pinCE, initialisedSpiBus->pinSS()));
|
||||
|
||||
_radio->begin(_spiPtr.get());
|
||||
|
||||
_radio->setDataRate(RF24_250KBPS);
|
||||
_radio->enableDynamicPayloads();
|
||||
_radio->setCRCLength(RF24_CRC_16);
|
||||
_radio->setAddressWidth(5);
|
||||
_radio->setRetries(0, 0);
|
||||
_radio->maskIRQ(true, true, false); // enable only receiving interrupts
|
||||
if (_radio->isChipConnected()) {
|
||||
Hoymiles.getMessageOutput()->println("Connection successful");
|
||||
} else {
|
||||
Hoymiles.getMessageOutput()->println("Connection error!!");
|
||||
}
|
||||
|
||||
attachInterrupt(digitalPinToInterrupt(pinIRQ), std::bind(&HoymilesRadio_NRF::handleIntr, this), FALLING);
|
||||
|
||||
openReadingPipe();
|
||||
_radio->startListening();
|
||||
}
|
||||
|
||||
void HoymilesRadio_NRF::loop()
|
||||
{
|
||||
EVERY_N_MILLIS(4)
|
||||
{
|
||||
switchRxCh();
|
||||
}
|
||||
|
||||
if (_packetReceived) {
|
||||
Hoymiles.getMessageOutput()->println("Interrupt received");
|
||||
while (_radio->available()) {
|
||||
if (!(_rxBuffer.size() > FRAGMENT_BUFFER_SIZE)) {
|
||||
fragment_t f;
|
||||
memset(f.fragment, 0xcc, MAX_RF_PAYLOAD_SIZE);
|
||||
f.len = _radio->getDynamicPayloadSize();
|
||||
f.channel = _radio->getChannel();
|
||||
if (f.len > MAX_RF_PAYLOAD_SIZE)
|
||||
f.len = MAX_RF_PAYLOAD_SIZE;
|
||||
_radio->read(f.fragment, f.len);
|
||||
_rxBuffer.push(f);
|
||||
} else {
|
||||
Hoymiles.getMessageOutput()->println("Buffer full");
|
||||
_radio->flush_rx();
|
||||
}
|
||||
}
|
||||
_packetReceived = false;
|
||||
|
||||
} else {
|
||||
// Perform package parsing only if no packages are received
|
||||
if (!_rxBuffer.empty()) {
|
||||
fragment_t f = _rxBuffer.back();
|
||||
if (checkFragmentCrc(&f)) {
|
||||
std::shared_ptr<InverterAbstract> inv = Hoymiles.getInverterByFragment(&f);
|
||||
|
||||
if (nullptr != inv) {
|
||||
// Save packet in inverter rx buffer
|
||||
char buf[30];
|
||||
snprintf(buf, sizeof(buf), "RX Channel: %d --> ", f.channel);
|
||||
dumpBuf(buf, f.fragment, f.len);
|
||||
inv->addRxFragment(f.fragment, f.len);
|
||||
} else {
|
||||
Hoymiles.getMessageOutput()->println("Inverter Not found!");
|
||||
}
|
||||
|
||||
} else {
|
||||
Hoymiles.getMessageOutput()->println("Frame kaputt");
|
||||
}
|
||||
|
||||
// Remove paket from buffer even it was corrupted
|
||||
_rxBuffer.pop();
|
||||
}
|
||||
}
|
||||
|
||||
if (_busyFlag && _rxTimeout.occured()) {
|
||||
Hoymiles.getMessageOutput()->println("RX Period End");
|
||||
std::shared_ptr<InverterAbstract> inv = Hoymiles.getInverterBySerial(_commandQueue.front().get()->getTargetAddress());
|
||||
|
||||
if (nullptr != inv) {
|
||||
CommandAbstract* cmd = _commandQueue.front().get();
|
||||
uint8_t verifyResult = inv->verifyAllFragments(cmd);
|
||||
if (verifyResult == FRAGMENT_ALL_MISSING_RESEND) {
|
||||
Hoymiles.getMessageOutput()->println("Nothing received, resend whole request");
|
||||
sendLastPacketAgain();
|
||||
|
||||
} else if (verifyResult == FRAGMENT_ALL_MISSING_TIMEOUT) {
|
||||
Hoymiles.getMessageOutput()->println("Nothing received, resend count exeeded");
|
||||
_commandQueue.pop();
|
||||
_busyFlag = false;
|
||||
|
||||
} else if (verifyResult == FRAGMENT_RETRANSMIT_TIMEOUT) {
|
||||
Hoymiles.getMessageOutput()->println("Retransmit timeout");
|
||||
_commandQueue.pop();
|
||||
_busyFlag = false;
|
||||
|
||||
} else if (verifyResult == FRAGMENT_HANDLE_ERROR) {
|
||||
Hoymiles.getMessageOutput()->println("Packet handling error");
|
||||
_commandQueue.pop();
|
||||
_busyFlag = false;
|
||||
|
||||
} else if (verifyResult > 0) {
|
||||
// Perform Retransmit
|
||||
Hoymiles.getMessageOutput()->print("Request retransmit: ");
|
||||
Hoymiles.getMessageOutput()->println(verifyResult);
|
||||
sendRetransmitPacket(verifyResult);
|
||||
|
||||
} else {
|
||||
// Successful received all packages
|
||||
Hoymiles.getMessageOutput()->println("Success");
|
||||
_commandQueue.pop();
|
||||
_busyFlag = false;
|
||||
}
|
||||
} else {
|
||||
// If inverter was not found, assume the command is invalid
|
||||
Hoymiles.getMessageOutput()->println("RX: Invalid inverter found");
|
||||
_commandQueue.pop();
|
||||
_busyFlag = false;
|
||||
}
|
||||
} else if (!_busyFlag) {
|
||||
// Currently in idle mode --> send packet if one is in the queue
|
||||
if (!_commandQueue.empty()) {
|
||||
CommandAbstract* cmd = _commandQueue.front().get();
|
||||
|
||||
auto inv = Hoymiles.getInverterBySerial(cmd->getTargetAddress());
|
||||
if (nullptr != inv) {
|
||||
inv->clearRxFragmentBuffer();
|
||||
sendEsbPacket(cmd);
|
||||
} else {
|
||||
Hoymiles.getMessageOutput()->println("TX: Invalid inverter found");
|
||||
_commandQueue.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HoymilesRadio_NRF::setPALevel(rf24_pa_dbm_e paLevel)
|
||||
{
|
||||
_radio->setPALevel(paLevel);
|
||||
}
|
||||
|
||||
void HoymilesRadio_NRF::setDtuSerial(uint64_t serial)
|
||||
{
|
||||
HoymilesRadio::setDtuSerial(serial);
|
||||
openReadingPipe();
|
||||
}
|
||||
|
||||
bool HoymilesRadio_NRF::isIdle()
|
||||
{
|
||||
return !_busyFlag;
|
||||
}
|
||||
|
||||
bool HoymilesRadio_NRF::isConnected()
|
||||
{
|
||||
return _radio->isChipConnected();
|
||||
}
|
||||
|
||||
bool HoymilesRadio_NRF::isPVariant()
|
||||
{
|
||||
return _radio->isPVariant();
|
||||
}
|
||||
|
||||
void HoymilesRadio_NRF::openReadingPipe()
|
||||
{
|
||||
serial_u s;
|
||||
s = convertSerialToRadioId(_dtuSerial);
|
||||
_radio->openReadingPipe(1, s.u64);
|
||||
}
|
||||
|
||||
void HoymilesRadio_NRF::openWritingPipe(serial_u serial)
|
||||
{
|
||||
serial_u s;
|
||||
s = convertSerialToRadioId(serial);
|
||||
_radio->openWritingPipe(s.u64);
|
||||
}
|
||||
|
||||
void ARDUINO_ISR_ATTR HoymilesRadio_NRF::handleIntr()
|
||||
{
|
||||
_packetReceived = true;
|
||||
}
|
||||
|
||||
uint8_t HoymilesRadio_NRF::getRxNxtChannel()
|
||||
{
|
||||
if (++_rxChIdx >= sizeof(_rxChLst))
|
||||
_rxChIdx = 0;
|
||||
return _rxChLst[_rxChIdx];
|
||||
}
|
||||
|
||||
uint8_t HoymilesRadio_NRF::getTxNxtChannel()
|
||||
{
|
||||
if (++_txChIdx >= sizeof(_txChLst))
|
||||
_txChIdx = 0;
|
||||
return _txChLst[_txChIdx];
|
||||
}
|
||||
|
||||
void HoymilesRadio_NRF::switchRxCh()
|
||||
{
|
||||
_radio->stopListening();
|
||||
_radio->setChannel(getRxNxtChannel());
|
||||
_radio->startListening();
|
||||
}
|
||||
|
||||
bool HoymilesRadio_NRF::checkFragmentCrc(fragment_t* fragment)
|
||||
{
|
||||
uint8_t crc = crc8(fragment->fragment, fragment->len - 1);
|
||||
return (crc == fragment->fragment[fragment->len - 1]);
|
||||
}
|
||||
|
||||
void HoymilesRadio_NRF::sendEsbPacket(CommandAbstract* cmd)
|
||||
{
|
||||
cmd->incrementSendCount();
|
||||
|
||||
cmd->setRouterAddress(DtuSerial().u64);
|
||||
|
||||
_radio->stopListening();
|
||||
_radio->setChannel(getTxNxtChannel());
|
||||
|
||||
serial_u s;
|
||||
s.u64 = cmd->getTargetAddress();
|
||||
openWritingPipe(s);
|
||||
_radio->setRetries(3, 15);
|
||||
|
||||
Hoymiles.getMessageOutput()->print("TX ");
|
||||
Hoymiles.getMessageOutput()->print(cmd->getCommandName());
|
||||
Hoymiles.getMessageOutput()->print(" Channel: ");
|
||||
Hoymiles.getMessageOutput()->print(_radio->getChannel());
|
||||
Hoymiles.getMessageOutput()->print(" --> ");
|
||||
cmd->dumpDataPayload(Hoymiles.getMessageOutput());
|
||||
_radio->write(cmd->getDataPayload(), cmd->getDataSize());
|
||||
|
||||
_radio->setRetries(0, 0);
|
||||
openReadingPipe();
|
||||
_radio->setChannel(getRxNxtChannel());
|
||||
_radio->startListening();
|
||||
_busyFlag = true;
|
||||
_rxTimeout.set(cmd->getTimeout());
|
||||
}
|
||||
|
||||
void HoymilesRadio_NRF::sendRetransmitPacket(uint8_t fragment_id)
|
||||
{
|
||||
CommandAbstract* cmd = _commandQueue.front().get();
|
||||
|
||||
CommandAbstract* requestCmd = cmd->getRequestFrameCommand(fragment_id);
|
||||
|
||||
if (requestCmd != nullptr) {
|
||||
sendEsbPacket(requestCmd);
|
||||
}
|
||||
}
|
||||
|
||||
void HoymilesRadio_NRF::sendLastPacketAgain()
|
||||
{
|
||||
CommandAbstract* cmd = _commandQueue.front().get();
|
||||
sendEsbPacket(cmd);
|
||||
}
|
||||
|
||||
54
lib/Hoymiles/src/HoymilesRadio_NRF.h
Normal file
54
lib/Hoymiles/src/HoymilesRadio_NRF.h
Normal file
@ -0,0 +1,54 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
#include "HoymilesRadio.h"
|
||||
#include "TimeoutHelper.h"
|
||||
#include "commands/CommandAbstract.h"
|
||||
#include <RF24.h>
|
||||
#include <memory>
|
||||
#include <nRF24L01.h>
|
||||
#include <queue>
|
||||
|
||||
// number of fragments hold in buffer
|
||||
#define FRAGMENT_BUFFER_SIZE 30
|
||||
|
||||
class HoymilesRadio_NRF : public HoymilesRadio {
|
||||
public:
|
||||
void init(SPIClass* initialisedSpiBus, uint8_t pinCE, uint8_t pinIRQ);
|
||||
void loop();
|
||||
void setPALevel(rf24_pa_dbm_e paLevel);
|
||||
|
||||
virtual void setDtuSerial(uint64_t serial);
|
||||
|
||||
bool isIdle();
|
||||
bool isConnected();
|
||||
bool isPVariant();
|
||||
|
||||
private:
|
||||
void ARDUINO_ISR_ATTR handleIntr();
|
||||
uint8_t getRxNxtChannel();
|
||||
uint8_t getTxNxtChannel();
|
||||
void switchRxCh();
|
||||
void openReadingPipe();
|
||||
void openWritingPipe(serial_u serial);
|
||||
bool checkFragmentCrc(fragment_t* fragment);
|
||||
|
||||
void sendEsbPacket(CommandAbstract* cmd);
|
||||
void sendRetransmitPacket(uint8_t fragment_id);
|
||||
void sendLastPacketAgain();
|
||||
|
||||
std::unique_ptr<SPIClass> _spiPtr;
|
||||
std::unique_ptr<RF24> _radio;
|
||||
uint8_t _rxChLst[5] = { 3, 23, 40, 61, 75 };
|
||||
uint8_t _rxChIdx = 0;
|
||||
|
||||
uint8_t _txChLst[5] = { 3, 23, 40, 61, 75 };
|
||||
uint8_t _txChIdx = 0;
|
||||
|
||||
volatile bool _packetReceived = false;
|
||||
|
||||
std::queue<fragment_t> _rxBuffer;
|
||||
TimeoutHelper _rxTimeout;
|
||||
|
||||
bool _busyFlag = false;
|
||||
};
|
||||
@ -29,10 +29,10 @@ void InverterSettingsClass::init()
|
||||
Hoymiles.init(spiClass, pin.nrf24_en, pin.nrf24_irq);
|
||||
|
||||
MessageOutput.println(" Setting radio PA level... ");
|
||||
Hoymiles.getRadio()->setPALevel((rf24_pa_dbm_e)config.Dtu_PaLevel);
|
||||
Hoymiles.getRadioNrf()->setPALevel((rf24_pa_dbm_e)config.Dtu_PaLevel);
|
||||
|
||||
MessageOutput.println(" Setting DTU serial... ");
|
||||
Hoymiles.getRadio()->setDtuSerial(config.Dtu_Serial);
|
||||
Hoymiles.getRadioNrf()->setDtuSerial(config.Dtu_Serial);
|
||||
|
||||
MessageOutput.println(" Setting poll interval... ");
|
||||
Hoymiles.setPollInterval(config.Dtu_PollInterval);
|
||||
|
||||
@ -16,7 +16,7 @@ void MqttHandleDtuClass::init()
|
||||
|
||||
void MqttHandleDtuClass::loop()
|
||||
{
|
||||
if (!MqttSettings.getConnected() || !Hoymiles.getRadio()->isIdle()) {
|
||||
if (!MqttSettings.getConnected() || !Hoymiles.getRadioNrf()->isIdle()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -41,7 +41,7 @@ void MqttHandleHassClass::publishConfig()
|
||||
return;
|
||||
}
|
||||
|
||||
if (!MqttSettings.getConnected() && Hoymiles.getRadio()->isIdle()) {
|
||||
if (!MqttSettings.getConnected() && Hoymiles.getRadioNrf()->isIdle()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@ void MqttHandleInverterClass::init()
|
||||
|
||||
void MqttHandleInverterClass::loop()
|
||||
{
|
||||
if (!MqttSettings.getConnected() || !Hoymiles.getRadio()->isIdle()) {
|
||||
if (!MqttSettings.getConnected() || !Hoymiles.getRadioNrf()->isIdle()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -132,7 +132,7 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request)
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
|
||||
Hoymiles.getRadio()->setPALevel((rf24_pa_dbm_e)config.Dtu_PaLevel);
|
||||
Hoymiles.getRadio()->setDtuSerial(config.Dtu_Serial);
|
||||
Hoymiles.getRadioNrf()->setPALevel((rf24_pa_dbm_e)config.Dtu_PaLevel);
|
||||
Hoymiles.getRadioNrf()->setDtuSerial(config.Dtu_Serial);
|
||||
Hoymiles.setPollInterval(config.Dtu_PollInterval);
|
||||
}
|
||||
@ -69,8 +69,8 @@ void WebApiSysstatusClass::onSystemStatus(AsyncWebServerRequest* request)
|
||||
|
||||
root["uptime"] = esp_timer_get_time() / 1000000;
|
||||
|
||||
root["radio_connected"] = Hoymiles.getRadio()->isConnected();
|
||||
root["radio_pvariant"] = Hoymiles.getRadio()->isPVariant();
|
||||
root["radio_connected"] = Hoymiles.getRadioNrf()->isConnected();
|
||||
root["radio_pvariant"] = Hoymiles.getRadioNrf()->isPVariant();
|
||||
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
|
||||
@ -175,7 +175,7 @@ void WebApiWsLiveClass::generateJsonResponse(JsonVariant& root)
|
||||
JsonObject hintObj = root.createNestedObject("hints");
|
||||
struct tm timeinfo;
|
||||
hintObj["time_sync"] = !getLocalTime(&timeinfo, 5);
|
||||
hintObj["radio_problem"] = (!Hoymiles.getRadio()->isConnected() || !Hoymiles.getRadio()->isPVariant());
|
||||
hintObj["radio_problem"] = (!Hoymiles.getRadioNrf()->isConnected() || !Hoymiles.getRadioNrf()->isPVariant());
|
||||
if (!strcmp(Configuration.get().Security_Password, ACCESS_POINT_PASSWORD)) {
|
||||
hintObj["default_password"] = true;
|
||||
} else {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user