Skip to content

Commit

Permalink
Implement CMD56 as own command.
Browse files Browse the repository at this point in the history
By doing so, it's possible to send all packets via the sendEsbPacket method. A lot of stuff could be removed which is no more used.
  • Loading branch information
tbnobody committed Apr 15, 2023
1 parent cfb3790 commit f5767e6
Show file tree
Hide file tree
Showing 12 changed files with 121 additions and 137 deletions.
4 changes: 4 additions & 0 deletions lib/Hoymiles/src/Hoymiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ void HoymilesClass::loop()
_messageOutput->print("Fetch inverter: ");
_messageOutput->println(iv->serial(), HEX);

if (!iv->isReachable()) {
iv->sendChangeChannelRequest();
}

iv->sendStatsRequest();

// Fetch event log
Expand Down
132 changes: 12 additions & 120 deletions lib/Hoymiles/src/HoymilesRadio_CMT.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,39 +54,6 @@ bool HoymilesRadio_CMT::cmtSwitchDtuFreq(const uint32_t to_freq_kHz)
return true;
}

bool HoymilesRadio_CMT::cmtSwitchInvAndDtuFreq(const uint64_t inv_serial, const uint32_t from_freq_kHz, const uint32_t to_freq_kHz)
{
const uint8_t fromChannel = getChannelFromFrequency(from_freq_kHz);
const uint8_t toChannel = getChannelFromFrequency(to_freq_kHz);
if (fromChannel == 0xFF || toChannel == 0xFF) {
return false;
}

_radio->setChannel(fromChannel);
cmtTx56toCh = toChannel;

// CMD56 for inverter frequency/channel switch
cmtTxBuffer[0] = 0x56;
// cmtTxBuffer[1-4] = last inverter serial
// cmtTxBuffer[5-8] = dtu serial
cmtTxBuffer[9] = 0x02;
cmtTxBuffer[10] = 0x15;
cmtTxBuffer[11] = 0x21;
cmtTxBuffer[12] = (uint8_t)(CMT_BASE_CH_OFFSET860 + toChannel);
cmtTxBuffer[13] = 0x14;
cmtTxBuffer[14] = crc8(cmtTxBuffer, 14);

Hoymiles.getMessageOutput()->printf("TX CMD56 %.2f MHz --> ", getFrequencyFromChannel(_radio->getChannel()));
dumpBuf(cmtTxBuffer, 15);

cmtTxLength = 15;
_txTimeout.set(100);

cmtNextState = CMT_STATE_TX_START;

return true;
}

enumCMTresult HoymilesRadio_CMT::cmtProcess(void)
{
enumCMTresult nRes = CMT_BUSY;
Expand Down Expand Up @@ -142,7 +109,6 @@ enumCMTresult HoymilesRadio_CMT::cmtProcess(void)

uint8_t state = CMT2300A_ReadReg(CMT2300A_CUS_INT_FLAG);
if ((state & 0x1b) == 0x1b) {
cmtRxTimeoutCnt = 0;

if (!(_rxBuffer.size() > FRAGMENT_BUFFER_SIZE)) {
fragment_t f;
Expand Down Expand Up @@ -188,91 +154,9 @@ enumCMTresult HoymilesRadio_CMT::cmtProcess(void)

cmtNextState = CMT_STATE_IDLE;

// send CMD56 after 3 Rx timeouts
if (cmtRxTimeoutCnt < 2) {
cmtRxTimeoutCnt++;
} else {
uint32_t invSerial = cmtTxBuffer[1] << 24 | cmtTxBuffer[2] << 16 | cmtTxBuffer[3] << 8 | cmtTxBuffer[4]; // read inverter serial from last Tx buffer
cmtSwitchInvAndDtuFreq(invSerial, HOY_BOOT_FREQ / 1000, _inverterTargetFrequency);
}

nRes = CMT_RX_TIMEOUT;
break;

case CMT_STATE_TX_START:
CMT2300A_GoStby();
CMT2300A_ClearInterruptFlags();

/* Must clear FIFO after enable SPI to read or write the FIFO */
CMT2300A_EnableWriteFifo();
CMT2300A_ClearTxFifo();

CMT2300A_WriteReg(CMT2300A_CUS_PKT15, cmtTxLength); // set Tx length
/* The length need be smaller than 32 */
CMT2300A_WriteFifo(cmtTxBuffer, cmtTxLength);

if (!(CMT2300A_ReadReg(CMT2300A_CUS_FIFO_FLAG) & CMT2300A_MASK_TX_FIFO_NMTY_FLG)) {
cmtNextState = CMT_STATE_ERROR;
}

if (!CMT2300A_GoTx()) {
cmtNextState = CMT_STATE_ERROR;
} else {
cmtNextState = CMT_STATE_TX_WAIT;
}

_txTimeout.reset();

break;

case CMT_STATE_TX_WAIT:
if (!_gpio2_configured) {
if (CMT2300A_MASK_TX_DONE_FLG & CMT2300A_ReadReg(CMT2300A_CUS_INT_CLR1)) { // read INT1, TX_DONE flag
_packetSent = true;
}
}
if (_packetSent) {
Hoymiles.getMessageOutput()->println(F("Interrupt 1 received"));
_packetSent = false; // reset interrupt 1
cmtNextState = CMT_STATE_TX_DONE;
}

if (_txTimeout.occured()) {
cmtNextState = CMT_STATE_TX_TIMEOUT;
}

break;

case CMT_STATE_TX_DONE:
CMT2300A_ClearInterruptFlags();
CMT2300A_GoSleep();

if (cmtTx56toCh != 0xFF) {
_radio->setChannel(cmtTx56toCh);
cmtTx56toCh = 0xFF;
cmtNextState = CMT_STATE_IDLE;
} else {
cmtNextState = CMT_STATE_RX_START; // receive answer
}

nRes = CMT_TX_DONE;
break;

case CMT_STATE_TX_TIMEOUT:
CMT2300A_GoSleep();

Hoymiles.getMessageOutput()->println("TX timeout!");

if (cmtTx56toCh != 0xFF) {
cmtTx56toCh = 0xFF;
cmtNextState = CMT_STATE_IDLE;
}

cmtNextState = CMT_STATE_IDLE;

nRes = CMT_TX_TIMEOUT;
break;

case CMT_STATE_ERROR:
CMT2300A_SoftReset();
CMT2300A_DelayMs(20);
Expand Down Expand Up @@ -437,6 +321,11 @@ void HoymilesRadio_CMT::setInverterTargetFrequency(uint32_t frequency)
cmtSwitchDtuFreq(_inverterTargetFrequency);
}

uint32_t HoymilesRadio_CMT::getInverterTargetFrequency()
{
return _inverterTargetFrequency;
}

bool HoymilesRadio_CMT::isConnected()
{
if (!_isInitialized) {
Expand Down Expand Up @@ -471,19 +360,22 @@ void HoymilesRadio_CMT::sendEsbPacket(CommandAbstract* cmd)

cmd->setRouterAddress(DtuSerial().u64);

uint8_t oldChannel;
oldChannel = _radio->getChannel();
if (cmd->getDataPayload()[0] == 0x56) { // @todo(tbnobody) Bad hack to identify ChannelChange Command
cmtSwitchDtuFreq(HOY_BOOT_FREQ / 1000);
}

Hoymiles.getMessageOutput()->printf("TX %s %.2f MHz --> ",
cmd->getCommandName().c_str(), getFrequencyFromChannel(_radio->getChannel()));
cmd->dumpDataPayload(Hoymiles.getMessageOutput());

// Still here for to handle CMD56 correctly (inverter serial etc.)
memcpy(cmtTxBuffer, cmd->getDataPayload(), cmd->getDataSize());

if (_radio->write(cmd->getDataPayload(), cmd->getDataSize())) {
_packetSent = false; // still bad hack, to be removed
cmtNextState = CMT_STATE_RX_START;
} else {
Hoymiles.getMessageOutput()->println("TX SPI Timeout");
}
_radio->setChannel(oldChannel);

_busyFlag = true;
_rxTimeout.set(cmd->getTimeout());
Expand Down
20 changes: 4 additions & 16 deletions lib/Hoymiles/src/HoymilesRadio_CMT.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,6 @@ typedef enum {
CMT_STATE_RX_WAIT,
CMT_STATE_RX_DONE,
CMT_STATE_RX_TIMEOUT,
CMT_STATE_TX_START,
CMT_STATE_TX_WAIT,
CMT_STATE_TX_DONE,
CMT_STATE_TX_TIMEOUT,
CMT_STATE_ERROR,
} enumCMTstate;

Expand All @@ -37,8 +33,6 @@ typedef enum {
CMT_BUSY,
CMT_RX_DONE,
CMT_RX_TIMEOUT,
CMT_TX_DONE,
CMT_TX_TIMEOUT,
CMT_ERROR,
} enumCMTresult;

Expand All @@ -48,12 +42,16 @@ class HoymilesRadio_CMT : public HoymilesRadio {
void loop();
void setPALevel(int8_t paLevel);
void setInverterTargetFrequency(uint32_t frequency);
uint32_t getInverterTargetFrequency();

bool isConnected();

static uint32_t getMinFrequency();
static uint32_t getMaxFrequency();

static float getFrequencyFromChannel(const uint8_t channel);
static uint8_t getChannelFromFrequency(const uint32_t freq_kHz);

private:
void ARDUINO_ISR_ATTR handleInt1();
void ARDUINO_ISR_ATTR handleInt2();
Expand All @@ -74,21 +72,11 @@ class HoymilesRadio_CMT : public HoymilesRadio {

uint32_t _inverterTargetFrequency = HOYMILES_CMT_WORK_FREQ;

static float getFrequencyFromChannel(const uint8_t channel);
static uint8_t getChannelFromFrequency(const uint32_t freq_kHz);

bool cmtSwitchDtuFreq(const uint32_t to_freq_kHz);
bool cmtSwitchInvAndDtuFreq(const uint64_t inv_serial, const uint32_t from_freq_kHz, const uint32_t to_freq_kHz);
enumCMTresult cmtProcess(void);

enumCMTstate cmtNextState = CMT_STATE_IDLE;
uint8_t cmtTxBuffer[32];
uint8_t cmtTxLength = 0;

uint32_t cmtRxTimeout = 200;
uint32_t cmtRxTimeCount = 0;

uint8_t cmtTx56toCh = 0xFF; // send CMD56 active to Channel xx, inactive = 0xFF

uint8_t cmtRxTimeoutCnt = 0; // Rx timeout counter !!! should be stored per inverter !!!
};
39 changes: 39 additions & 0 deletions lib/Hoymiles/src/commands/ChannelChangeCommand.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2023 Thomas Basler and others
*/
#include "ChannelChangeCommand.h"

ChannelChangeCommand::ChannelChangeCommand(uint64_t target_address, uint64_t router_address, uint8_t channel)
: CommandAbstract(target_address, router_address)
{
_payload[0] = 0x56;
_payload[9] = 0x02;
_payload[10] = 0x15;
_payload[11] = 0x21;
_payload[13] = 0x14;
_payload_size = 14;

setChannel(channel);
setTimeout(10);
}

String ChannelChangeCommand::getCommandName()
{
return "ChannelChangeCommand";
}

void ChannelChangeCommand::setChannel(uint8_t channel)
{
_payload[12] = channel;
}

uint8_t ChannelChangeCommand::getChannel()
{
return _payload[12];
}

bool ChannelChangeCommand::handleResponse(InverterAbstract* inverter, fragment_t fragment[], uint8_t max_fragment_id)
{
return true;
}
16 changes: 16 additions & 0 deletions lib/Hoymiles/src/commands/ChannelChangeCommand.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once

#include "CommandAbstract.h"

class ChannelChangeCommand : public CommandAbstract {
public:
explicit ChannelChangeCommand(uint64_t target_address = 0, uint64_t router_address = 0, uint8_t channel = 0);

virtual String getCommandName();

void setChannel(uint8_t channel);
uint8_t getChannel();

virtual bool handleResponse(InverterAbstract* inverter, fragment_t fragment[], uint8_t max_fragment_id);
};
1 change: 1 addition & 0 deletions lib/Hoymiles/src/commands/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@
* ParaSetCommand
* SingleDataCommand
* RequestFrameCommand
* ChannelChangeCommand
20 changes: 19 additions & 1 deletion lib/Hoymiles/src/inverters/HMS_Abstract.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,24 @@
* Copyright (C) 2023 Thomas Basler and others
*/
#include "HMS_Abstract.h"
#include "Hoymiles.h"
#include "HoymilesRadio_CMT.h"
#include "commands/ChannelChangeCommand.h"

HMS_Abstract::HMS_Abstract(HoymilesRadio* radio, uint64_t serial)
: HM_Abstract(radio, serial) {};
: HM_Abstract(radio, serial)
{
}

bool HMS_Abstract::sendChangeChannelRequest()
{
if (!(getEnableCommands() && getEnablePolling())) {
return false;
}

ChannelChangeCommand* cmdChannel = _radio->enqueCommand<ChannelChangeCommand>();
cmdChannel->setChannel(HoymilesRadio_CMT::getChannelFromFrequency(Hoymiles.getRadioCmt()->getInverterTargetFrequency()));
cmdChannel->setTargetAddress(serial());

return true;
};
2 changes: 2 additions & 0 deletions lib/Hoymiles/src/inverters/HMS_Abstract.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@
class HMS_Abstract : public HM_Abstract {
public:
explicit HMS_Abstract(HoymilesRadio* radio, uint64_t serial);

virtual bool sendChangeChannelRequest();
};
16 changes: 16 additions & 0 deletions lib/Hoymiles/src/inverters/HMT_Abstract.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,26 @@
* Copyright (C) 2023 Thomas Basler and others
*/
#include "HMT_Abstract.h"
#include "Hoymiles.h"
#include "HoymilesRadio_CMT.h"
#include "commands/ChannelChangeCommand.h"
#include "parser/AlarmLogParser.h"

HMT_Abstract::HMT_Abstract(HoymilesRadio* radio, uint64_t serial)
: HM_Abstract(radio, serial)
{
EventLog()->setMessageType(AlarmMessageType_t::HMT);
};

bool HMT_Abstract::sendChangeChannelRequest()
{
if (!(getEnableCommands() && getEnablePolling())) {
return false;
}

ChannelChangeCommand* cmdChannel = _radio->enqueCommand<ChannelChangeCommand>();
cmdChannel->setChannel(HoymilesRadio_CMT::getChannelFromFrequency(Hoymiles.getRadioCmt()->getInverterTargetFrequency()));
cmdChannel->setTargetAddress(serial());

return true;
};
2 changes: 2 additions & 0 deletions lib/Hoymiles/src/inverters/HMT_Abstract.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@
class HMT_Abstract : public HM_Abstract {
public:
explicit HMT_Abstract(HoymilesRadio* radio, uint64_t serial);

virtual bool sendChangeChannelRequest();
};
5 changes: 5 additions & 0 deletions lib/Hoymiles/src/inverters/InverterAbstract.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ bool InverterAbstract::getEnableCommands()
return _enableCommands;
}

bool InverterAbstract::sendChangeChannelRequest()
{
return false;
}

HoymilesRadio* InverterAbstract::getRadio()
{
return _radio;
Expand Down
Loading

0 comments on commit f5767e6

Please sign in to comment.