diff --git a/lib/CMT2300a/cmt2300wrapper.cpp b/lib/CMT2300a/cmt2300wrapper.cpp index df3fdfbf3..21265f50a 100644 --- a/lib/CMT2300a/cmt2300wrapper.cpp +++ b/lib/CMT2300a/cmt2300wrapper.cpp @@ -25,6 +25,46 @@ bool CMT2300A::isChipConnected() return CMT2300A_IsExist(); } +bool CMT2300A::startListening(void) +{ + CMT2300A_GoStby(); + CMT2300A_ClearInterruptFlags(); + + /* Must clear FIFO after enable SPI to read or write the FIFO */ + CMT2300A_EnableReadFifo(); + CMT2300A_ClearRxFifo(); + + if (!CMT2300A_GoRx()) { + return false; + } else { + return true; + } +} + +bool CMT2300A::stopListening(void) +{ + CMT2300A_ClearInterruptFlags(); + return CMT2300A_GoSleep(); +} + +bool CMT2300A::available(void) +{ + return ( + CMT2300A_MASK_PREAM_OK_FLG | + CMT2300A_MASK_SYNC_OK_FLG | + CMT2300A_MASK_CRC_OK_FLG | + CMT2300A_MASK_PKT_OK_FLG + ) & CMT2300A_ReadReg(CMT2300A_CUS_INT_FLAG); +} + +void CMT2300A::read(void* buf, uint8_t len) +{ + // Fetch the payload + CMT2300A_ReadFifo(static_cast(buf), len); + + CMT2300A_ClearInterruptFlags(); +} + bool CMT2300A::write(const uint8_t* buf, uint8_t len) { CMT2300A_GoStby(); @@ -70,6 +110,18 @@ uint8_t CMT2300A::getChannel(void) return CMT2300A_ReadReg(CMT2300A_CUS_FREQ_CHNL); } +uint8_t CMT2300A::getDynamicPayloadSize(void) +{ + uint8_t result; + CMT2300A_ReadFifo(&result, 1); // first byte in FiFo is length + return result; +} + +int CMT2300A::getRssiDBm() +{ + return CMT2300A_GetRssiDBm(); +} + bool CMT2300A::setPALevel(int8_t level) { uint16_t Tx_dBm_word; @@ -183,6 +235,18 @@ bool CMT2300A::setPALevel(int8_t level) return true; } +bool CMT2300A::rxFifoAvailable() +{ + return ( + CMT2300A_MASK_PKT_OK_FLG + ) & CMT2300A_ReadReg(CMT2300A_CUS_INT_FLAG); +} + +void CMT2300A::flush_rx(void) +{ + CMT2300A_ClearRxFifo(); +} + bool CMT2300A::_init_pins() { CMT2300A_InitSpi(_pin_sdio, _pin_clk, _pin_cs, _pin_fcs, _spi_speed); diff --git a/lib/CMT2300a/cmt2300wrapper.h b/lib/CMT2300a/cmt2300wrapper.h index 6ae68fdc8..5f76b06f2 100644 --- a/lib/CMT2300a/cmt2300wrapper.h +++ b/lib/CMT2300a/cmt2300wrapper.h @@ -19,6 +19,43 @@ class CMT2300A { */ bool isChipConnected(); + bool startListening(void); + + bool stopListening(void); + + /** + * Check whether there are bytes available to be read + * @code + * if(radio.available()){ + * radio.read(&data,sizeof(data)); + * } + * @endcode + * + * @see available(uint8_t*) + * + * @return True if there is a payload available, false if none is + */ + bool available(void); + + /** + * Read payload data from the RX FIFO buffer(s). + * + * The length of data read is usually the next available payload's length + * @see + * - getDynamicPayloadSize() + * + * @note I specifically chose `void*` as a data type to make it easier + * for beginners to use. No casting needed. + * + * @param buf Pointer to a buffer where the data should be written + * @param len Maximum number of bytes to read into the buffer. This + * value should match the length of the object referenced using the + * `buf` parameter. The absolute maximum number of bytes that can be read + * in one call is 32 (for dynamic payload lengths) or whatever number was + * previously passed to setPayloadSize() (for static payload lengths). + */ + void read(void* buf, uint8_t len); + bool write(const uint8_t* buf, uint8_t len); /** @@ -33,8 +70,27 @@ class CMT2300A { */ uint8_t getChannel(void); + /** + * Get Dynamic Payload Size + * + * For dynamic payloads, this pulls the size of the payload off + * the chip + * + * @return Payload length of last-received dynamic payload + */ + uint8_t getDynamicPayloadSize(void); + + int getRssiDBm(); + bool setPALevel(int8_t level); + bool rxFifoAvailable(); + + /** + * Empty the RX (receive) FIFO buffers. + */ + void flush_rx(void); + private: /** * initialize the GPIO pins diff --git a/lib/Hoymiles/src/HoymilesRadio_CMT.cpp b/lib/Hoymiles/src/HoymilesRadio_CMT.cpp index 771895d6e..fe32afc2e 100644 --- a/lib/Hoymiles/src/HoymilesRadio_CMT.cpp +++ b/lib/Hoymiles/src/HoymilesRadio_CMT.cpp @@ -6,7 +6,6 @@ #include "Hoymiles.h" #include "crc.h" #include -#include #define HOY_BOOT_FREQ 868000000 // Hoymiles boot/init frequency after power up inverter or connection lost for 15 min #define HOY_BASE_FREQ 860000000 @@ -54,128 +53,6 @@ bool HoymilesRadio_CMT::cmtSwitchDtuFreq(const uint32_t to_freq_kHz) return true; } -enumCMTresult HoymilesRadio_CMT::cmtProcess(void) -{ - enumCMTresult nRes = CMT_BUSY; - - switch (cmtNextState) { - case CMT_STATE_IDLE: - nRes = CMT_IDLE; - break; - - case CMT_STATE_RX_START: - CMT2300A_GoStby(); - CMT2300A_ClearInterruptFlags(); - - /* Must clear FIFO after enable SPI to read or write the FIFO */ - CMT2300A_EnableReadFifo(); - CMT2300A_ClearRxFifo(); - - if (!CMT2300A_GoRx()) { - cmtNextState = CMT_STATE_ERROR; - } else { - cmtNextState = CMT_STATE_RX_WAIT; - } - - cmtRxTimeCount = CMT2300A_GetTickCount(); - cmtRxTimeout = 200; - - break; - - case CMT_STATE_RX_WAIT: - if (!_gpio3_configured) { - if (CMT2300A_MASK_PKT_OK_FLG & CMT2300A_ReadReg(CMT2300A_CUS_INT_FLAG)) { // read INT2, PKT_OK flag - _packetReceived = true; - } - } - - if (_packetReceived) - { - Hoymiles.getMessageOutput()->println("Interrupt 2 received"); - _packetReceived = false; // reset interrupt 2 - cmtNextState = CMT_STATE_RX_DONE; - } - - if ((CMT2300A_GetTickCount() - cmtRxTimeCount) > cmtRxTimeout) { - cmtNextState = CMT_STATE_RX_TIMEOUT; - } - - break; - - case CMT_STATE_RX_DONE: { - CMT2300A_GoStby(); - - bool isLastFrame = false; - - uint8_t state = CMT2300A_ReadReg(CMT2300A_CUS_INT_FLAG); - if ((state & 0x1b) == 0x1b) { - - if (!(_rxBuffer.size() > FRAGMENT_BUFFER_SIZE)) { - fragment_t f; - memset(f.fragment, 0xcc, MAX_RF_PAYLOAD_SIZE); - CMT2300A_ReadFifo(&f.len, 1); // first byte in FiFo is length - f.channel = _radio->getChannel(); - f.rssi = CMT2300A_GetRssiDBm(); - if (f.len > MAX_RF_PAYLOAD_SIZE) { - f.len = MAX_RF_PAYLOAD_SIZE; - } - CMT2300A_ReadFifo(f.fragment, f.len); - if (f.fragment[9] & 0x80) { // last frame detection for end Rx - isLastFrame = true; - } - _rxBuffer.push(f); - } else { - Hoymiles.getMessageOutput()->println("Buffer full"); - } - } else if ((state & 0x19) == 0x19) { - Hoymiles.getMessageOutput()->printf("[CMT_STATE_RX_DONE] state: %x (CRC_ERROR)\r\n", state); - } else { - Hoymiles.getMessageOutput()->printf("[CMT_STATE_RX_DONE] wrong state: %x\r\n", state); - } - - CMT2300A_ClearInterruptFlags(); - - CMT2300A_GoSleep(); - - if (isLastFrame) { // last frame received - cmtNextState = CMT_STATE_IDLE; - } else { - cmtNextState = CMT_STATE_RX_START; // receive next frame(s) - } - - nRes = CMT_RX_DONE; - break; - } - - case CMT_STATE_RX_TIMEOUT: - CMT2300A_GoSleep(); - - Hoymiles.getMessageOutput()->println("RX timeout!"); - - cmtNextState = CMT_STATE_IDLE; - - nRes = CMT_RX_TIMEOUT; - break; - - case CMT_STATE_ERROR: - CMT2300A_SoftReset(); - CMT2300A_DelayMs(20); - - CMT2300A_GoStby(); - _radio->begin(); - - cmtNextState = CMT_STATE_IDLE; - - nRes = CMT_ERROR; - break; - - default: - break; - } - - return nRes; -} - void HoymilesRadio_CMT::init(int8_t pin_sdio, int8_t pin_clk, int8_t pin_cs, int8_t pin_fcs, int8_t pin_gpio2, int8_t pin_gpio3) { _dtuSerial.u64 = 0; @@ -210,9 +87,37 @@ void HoymilesRadio_CMT::loop() if (!_isInitialized) { return; } - enumCMTresult mCMTstate = cmtProcess(); - if (mCMTstate != CMT_RX_DONE) { // Perform package parsing only if no packages are received + if (!_gpio3_configured) { + if (_radio->rxFifoAvailable()) { // read INT2, PKT_OK flag + _packetReceived = true; + } + } + + 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->getRssiDBm(); + 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(); + } + } + _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)) { @@ -360,6 +265,8 @@ void HoymilesRadio_CMT::sendEsbPacket(CommandAbstract* cmd) cmd->setRouterAddress(DtuSerial().u64); + _radio->stopListening(); + uint8_t oldChannel; oldChannel = _radio->getChannel(); if (cmd->getDataPayload()[0] == 0x56) { // @todo(tbnobody) Bad hack to identify ChannelChange Command @@ -370,13 +277,11 @@ void HoymilesRadio_CMT::sendEsbPacket(CommandAbstract* cmd) cmd->getCommandName().c_str(), getFrequencyFromChannel(_radio->getChannel())); cmd->dumpDataPayload(Hoymiles.getMessageOutput()); - if (_radio->write(cmd->getDataPayload(), cmd->getDataSize())) { - cmtNextState = CMT_STATE_RX_START; - } else { + if (!_radio->write(cmd->getDataPayload(), cmd->getDataSize())) { Hoymiles.getMessageOutput()->println("TX SPI Timeout"); } _radio->setChannel(oldChannel); - + _radio->startListening(); _busyFlag = true; _rxTimeout.set(cmd->getTimeout()); } diff --git a/lib/Hoymiles/src/HoymilesRadio_CMT.h b/lib/Hoymiles/src/HoymilesRadio_CMT.h index 0ba8f97cb..b1cfa7c4c 100644 --- a/lib/Hoymiles/src/HoymilesRadio_CMT.h +++ b/lib/Hoymiles/src/HoymilesRadio_CMT.h @@ -6,9 +6,9 @@ #include "commands/CommandAbstract.h" #include "types.h" #include +#include #include #include -#include // number of fragments hold in buffer #define FRAGMENT_BUFFER_SIZE 30 @@ -17,25 +17,6 @@ #define HOYMILES_CMT_WORK_FREQ 865000 #endif -/* CMT states */ -typedef enum { - CMT_STATE_IDLE = 0, - CMT_STATE_RX_START, - CMT_STATE_RX_WAIT, - CMT_STATE_RX_DONE, - CMT_STATE_RX_TIMEOUT, - CMT_STATE_ERROR, -} enumCMTstate; - -/* CMT process function results */ -typedef enum { - CMT_IDLE = 0, - CMT_BUSY, - CMT_RX_DONE, - CMT_RX_TIMEOUT, - CMT_ERROR, -} enumCMTresult; - class HoymilesRadio_CMT : public HoymilesRadio { public: void init(int8_t pin_sdio, int8_t pin_clk, int8_t pin_cs, int8_t pin_fcs, int8_t pin_gpio2, int8_t pin_gpio3); @@ -73,10 +54,4 @@ class HoymilesRadio_CMT : public HoymilesRadio { uint32_t _inverterTargetFrequency = HOYMILES_CMT_WORK_FREQ; bool cmtSwitchDtuFreq(const uint32_t to_freq_kHz); - enumCMTresult cmtProcess(void); - - enumCMTstate cmtNextState = CMT_STATE_IDLE; - - uint32_t cmtRxTimeout = 200; - uint32_t cmtRxTimeCount = 0; }; \ No newline at end of file