OpenDTU/lib/Hoymiles/src/HoymilesRadio_NRF.cpp
2023-12-12 13:26:07 +01:00

198 lines
5.2 KiB
C++

// 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 <Every.h>
#include <FunctionalInterrupt.h>
void HoymilesRadio_NRF::init(SPIClass* initialisedSpiBus, const uint8_t pinCE, const 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("NRF: Connection error!!");
return;
}
Hoymiles.getMessageOutput()->println("NRF: Connection successful");
attachInterrupt(digitalPinToInterrupt(pinIRQ), std::bind(&HoymilesRadio_NRF::handleIntr, this), FALLING);
openReadingPipe();
_radio->startListening();
_isInitialized = true;
}
void HoymilesRadio_NRF::loop()
{
if (!_isInitialized) {
return;
}
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();
f.rssi = _radio->testRPD() ? -30 : -80;
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("NRF: 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
Hoymiles.getMessageOutput()->printf("RX Channel: %d --> ", f.channel);
dumpBuf(f.fragment, f.len, false);
Hoymiles.getMessageOutput()->printf("| %d dBm\r\n", f.rssi);
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();
}
}
handleReceivedPackage();
}
void HoymilesRadio_NRF::setPALevel(const rf24_pa_dbm_e paLevel)
{
if (!_isInitialized) {
return;
}
_radio->setPALevel(paLevel);
}
void HoymilesRadio_NRF::setDtuSerial(const uint64_t serial)
{
HoymilesRadio::setDtuSerial(serial);
if (!_isInitialized) {
return;
}
openReadingPipe();
}
bool HoymilesRadio_NRF::isConnected() const
{
if (!_isInitialized) {
return false;
}
return _radio->isChipConnected();
}
bool HoymilesRadio_NRF::isPVariant() const
{
if (!_isInitialized) {
return false;
}
return _radio->isPVariant();
}
void HoymilesRadio_NRF::openReadingPipe()
{
const serial_u s = convertSerialToRadioId(_dtuSerial);
_radio->openReadingPipe(1, s.u64);
}
void HoymilesRadio_NRF::openWritingPipe(const serial_u serial)
{
const serial_u 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();
}
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()->printf("TX %s Channel: %d --> ",
cmd.getCommandName().c_str(), _radio->getChannel());
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());
}