mirror of https://github.com/lumapu/ahoy.git
				
				
			
				 13 changed files with 800 additions and 19 deletions
			
			
		@ -0,0 +1,430 @@ | 
				
			|||
//-----------------------------------------------------------------------------
 | 
				
			|||
// 2023 Ahoy, https://github.com/lumpapu/ahoy
 | 
				
			|||
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
 | 
				
			|||
//-----------------------------------------------------------------------------
 | 
				
			|||
 | 
				
			|||
#ifndef __CMT2300A_H__ | 
				
			|||
#define __CMT2300A_H__ | 
				
			|||
 | 
				
			|||
#include "esp32_3wSpi.h" | 
				
			|||
 | 
				
			|||
// detailed register infos from AN142_CMT2300AW_Quick_Start_Guide-Rev0.8.pdf
 | 
				
			|||
 | 
				
			|||
#define CMT2300A_CUS_MODE_CTL           0x60    // [7] go_switch
 | 
				
			|||
                                                // [6] go_tx
 | 
				
			|||
                                                // [5] go_tfs
 | 
				
			|||
                                                // [4] go_sleep
 | 
				
			|||
                                                // [3] go_rx
 | 
				
			|||
                                                // [2] go_rfs
 | 
				
			|||
                                                // [1] go_stby
 | 
				
			|||
                                                // [0] n/a
 | 
				
			|||
 | 
				
			|||
#define CMT2300A_CUS_MODE_STA           0x61    // [3:0] 0x00 IDLE
 | 
				
			|||
                                                //       0x01 SLEEP
 | 
				
			|||
                                                //       0x02 STBY
 | 
				
			|||
                                                //       0x03 RFS
 | 
				
			|||
                                                //       0x04 TFS
 | 
				
			|||
                                                //       0x05 RX
 | 
				
			|||
                                                //       0x06 TX
 | 
				
			|||
                                                //       0x08 UNLOCKED/LOW_VDD
 | 
				
			|||
                                                //       0x09 CAL
 | 
				
			|||
#define CMT2300A_CUS_EN_CTL             0x62 | 
				
			|||
#define CMT2300A_CUS_FREQ_CHNL          0x63 | 
				
			|||
 | 
				
			|||
#define CMT2300A_CUS_IO_SEL             0x65    // [5:4] GPIO3
 | 
				
			|||
                                                //       0x00 CLKO
 | 
				
			|||
                                                //       0x01 DOUT / DIN
 | 
				
			|||
                                                //       0x02 INT2
 | 
				
			|||
                                                //       0x03 DCLK
 | 
				
			|||
                                                // [3:2]  GPIO2
 | 
				
			|||
                                                //       0x00 INT1
 | 
				
			|||
                                                //       0x01 INT2
 | 
				
			|||
                                                //       0x02 DOUT / DIN
 | 
				
			|||
                                                //       0x03 DCLK
 | 
				
			|||
                                                // [1:0]  GPIO1
 | 
				
			|||
                                                //       0x00 DOUT / DIN
 | 
				
			|||
                                                //       0x01 INT1
 | 
				
			|||
                                                //       0x02 INT2
 | 
				
			|||
                                                //       0x03 DCLK
 | 
				
			|||
 | 
				
			|||
#define CMT2300A_CUS_INT1_CTL           0x66    // [4:0] INT1_SEL
 | 
				
			|||
                                                //       0x00 RX active
 | 
				
			|||
                                                //       0x01 TX active
 | 
				
			|||
                                                //       0x02 RSSI VLD
 | 
				
			|||
                                                //       0x03 Pream OK
 | 
				
			|||
                                                //       0x04 SYNC OK
 | 
				
			|||
                                                //       0x05 NODE OK
 | 
				
			|||
                                                //       0x06 CRC OK
 | 
				
			|||
                                                //       0x07 PKT OK
 | 
				
			|||
                                                //       0x08 SL TMO
 | 
				
			|||
                                                //       0x09 RX TMO
 | 
				
			|||
                                                //       0x0A TX DONE
 | 
				
			|||
                                                //       0x0B RX FIFO NMTY
 | 
				
			|||
                                                //       0x0C RX FIFO TH
 | 
				
			|||
                                                //       0x0D RX FIFO FULL
 | 
				
			|||
                                                //       0x0E RX FIFO WBYTE
 | 
				
			|||
                                                //       0x0F RX FIFO OVF
 | 
				
			|||
                                                //       0x10 TX FIFO NMTY
 | 
				
			|||
                                                //       0x11 TX FIFO TH
 | 
				
			|||
                                                //       0x12 TX FIFO FULL
 | 
				
			|||
                                                //       0x13 STATE IS STBY
 | 
				
			|||
                                                //       0x14 STATE IS FS
 | 
				
			|||
                                                //       0x15 STATE IS RX
 | 
				
			|||
                                                //       0x16 STATE IS TX
 | 
				
			|||
                                                //       0x17 LED
 | 
				
			|||
                                                //       0x18 TRX ACTIVE
 | 
				
			|||
                                                //       0x19 PKT DONE
 | 
				
			|||
 | 
				
			|||
#define CMT2300A_CUS_INT2_CTL           0x67    // [4:0] INT2_SEL
 | 
				
			|||
 | 
				
			|||
#define CMT2300A_CUS_INT_EN             0x68    // [7] SL TMO EN
 | 
				
			|||
                                                // [6] RX TMO EN
 | 
				
			|||
                                                // [5] TX DONE EN
 | 
				
			|||
                                                // [4] PREAM OK EN
 | 
				
			|||
                                                // [3] SYNC_OK EN
 | 
				
			|||
                                                // [2] NODE OK EN
 | 
				
			|||
                                                // [1] CRC OK EN
 | 
				
			|||
                                                // [0] PKT DONE EN
 | 
				
			|||
 | 
				
			|||
#define CMT2300A_CUS_FIFO_CTL           0x69    // [7] TX DIN EN
 | 
				
			|||
                                                // [6:5] TX DIN SEL
 | 
				
			|||
                                                //     0x00 SEL GPIO1
 | 
				
			|||
                                                //     0x01 SEL GPIO2
 | 
				
			|||
                                                //     0x02 SEL GPIO3
 | 
				
			|||
                                                // [4] FIFO AUTO CLR DIS
 | 
				
			|||
                                                // [3] FIFO TX RD EN
 | 
				
			|||
                                                // [2] FIFO RX TX SEL
 | 
				
			|||
                                                // [1] FIFO MERGE EN
 | 
				
			|||
                                                // [0] SPI FIFO RD WR SEL
 | 
				
			|||
 | 
				
			|||
#define CMT2300A_CUS_INT_CLR1           0x6A // clear interrupts Bank1
 | 
				
			|||
#define CMT2300A_CUS_INT_CLR2           0x6B // clear interrupts Bank2
 | 
				
			|||
#define CMT2300A_CUS_FIFO_CLR           0x6C | 
				
			|||
 | 
				
			|||
#define CMT2300A_CUS_INT_FLAG           0x6D    // [7] LBD FLG
 | 
				
			|||
                                                // [6] COL ERR FLG
 | 
				
			|||
                                                // [5] PKT ERR FLG
 | 
				
			|||
                                                // [4] PREAM OK FLG
 | 
				
			|||
                                                // [3] SYNC OK FLG
 | 
				
			|||
                                                // [2] NODE OK FLG
 | 
				
			|||
                                                // [1] CRC OK FLG
 | 
				
			|||
                                                // [0] PKT OK FLG
 | 
				
			|||
 | 
				
			|||
#define CMT2300A_CUS_RSSI_DBM           0x70 | 
				
			|||
 | 
				
			|||
#define CMT2300A_GO_SWITCH              0x80 | 
				
			|||
#define CMT2300A_GO_TX                  0x40 | 
				
			|||
#define CMT2300A_GO_TFS                 0x20 | 
				
			|||
#define CMT2300A_GO_SLEEP               0x10 | 
				
			|||
#define CMT2300A_GO_RX                  0x08 | 
				
			|||
#define CMT2300A_GO_RFS                 0x04 | 
				
			|||
#define CMT2300A_GO_STBY                0x02 | 
				
			|||
#define CMT2300A_GO_EEPROM              0x01 | 
				
			|||
 | 
				
			|||
#define CMT2300A_STA_IDLE               0x00 | 
				
			|||
#define CMT2300A_STA_SLEEP              0x01 | 
				
			|||
#define CMT2300A_STA_STBY               0x02 | 
				
			|||
#define CMT2300A_STA_RFS                0x03 | 
				
			|||
#define CMT2300A_STA_TFS                0x04 | 
				
			|||
#define CMT2300A_STA_RX                 0x05 | 
				
			|||
#define CMT2300A_STA_TX                 0x06 | 
				
			|||
#define CMT2300A_STA_EEPROM             0x07 | 
				
			|||
#define CMT2300A_STA_ERROR              0x08 | 
				
			|||
#define CMT2300A_STA_CAL                0x09 | 
				
			|||
 | 
				
			|||
#define CMT2300A_INT_SEL_TX_DONE        0x0A | 
				
			|||
 | 
				
			|||
#define CMT2300A_MASK_TX_DONE_FLG       0x08 | 
				
			|||
#define CMT2300A_MASK_PKT_OK_FLG        0x01 | 
				
			|||
 | 
				
			|||
// default CMT paramters
 | 
				
			|||
static uint8_t cmtConfig[0x60] PROGMEM { | 
				
			|||
    // 0x00 - 0x0f
 | 
				
			|||
    0x00, 0x66, 0xEC, 0x1D, 0x70, 0x80, 0x14, 0x08, | 
				
			|||
    0x91, 0x02, 0x02, 0xD0, 0xAE, 0xE0, 0x35, 0x00, | 
				
			|||
    // 0x10 - 0x1f
 | 
				
			|||
    0x00, 0xF4, 0x10, 0xE2, 0x42, 0x20, 0x0C, 0x81, | 
				
			|||
    0x42, 0xCF, 0xA7, 0x8C, 0x42, 0xC4, 0x4E, 0x1C, | 
				
			|||
    // 0x20 - 0x2f
 | 
				
			|||
    0xA6, 0xC9, 0x20, 0x20, 0xD2, 0x35, 0x0C, 0x0A, | 
				
			|||
    0x9F, 0x4B, 0x29, 0x29, 0xC0, 0x14, 0x05, 0x53, | 
				
			|||
    // 0x30 - 0x3f
 | 
				
			|||
    0x10, 0x00, 0xB4, 0x00, 0x00, 0x01, 0x00, 0x00, | 
				
			|||
    0x12, 0x1E, 0x00, 0xAA, 0x06, 0x00, 0x00, 0x00, | 
				
			|||
    // 0x40 - 0x4f
 | 
				
			|||
    0x00, 0xD6, 0xD5, 0xD4, 0x2D, 0x01, 0x1D, 0x00, | 
				
			|||
    0x00, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x60, | 
				
			|||
    // 0x50 - 0x5f
 | 
				
			|||
    0xFF, 0x00, 0x00, 0x1F, 0x10, 0x70, 0x4D, 0x06, | 
				
			|||
    0x00, 0x07, 0x50, 0x00, 0x8A, 0x18, 0x3F, 0x7F | 
				
			|||
}; | 
				
			|||
 | 
				
			|||
enum {CMT_SUCCESS = 0, CMT_ERR_SWITCH_STATE, CMT_ERR_TX_PENDING, CMT_ERR_REG_VAL}; | 
				
			|||
 | 
				
			|||
template<class SPI> | 
				
			|||
class Cmt2300a { | 
				
			|||
    typedef SPI SpiType; | 
				
			|||
    public: | 
				
			|||
        Cmt2300a() {} | 
				
			|||
 | 
				
			|||
        void setup() { | 
				
			|||
            mSpi.setup(); | 
				
			|||
            mTxPending = false; | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        // call as often as possible
 | 
				
			|||
        void loop() { | 
				
			|||
            if(mTxPending) { | 
				
			|||
                if(CMT2300A_MASK_TX_DONE_FLG != spi3w.readReg(CMT2300A_CUS_INT_CLR1)) { | 
				
			|||
                    if(cmtSwitchStatus(CMT2300A_GO_STBY, CMT2300A_STA_STBY)) | 
				
			|||
                        mTxPending = false; | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        inline void swichChannel(bool reset = true, uint8_t start = 0x00, uint8_t end = 0x22) { | 
				
			|||
            if(reset) | 
				
			|||
                mRxTxCh = start; | 
				
			|||
            else if(++mRxTxCh > end) | 
				
			|||
                mRxTxCh = start; | 
				
			|||
            // 0: 868.00MHz
 | 
				
			|||
            // 1: 868.23MHz
 | 
				
			|||
            // 2: 868.46MHz
 | 
				
			|||
            // 3: 868.72MHz
 | 
				
			|||
            // 4: 868.97MHz
 | 
				
			|||
            mSpi.writeReg(CMT2300A_CUS_FREQ_CHNL, mRxTxCh); | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        uint8_t checkRx(uint8_t buf[], uint8_t len, int8_t *rssi) { | 
				
			|||
            if(mTxPending) | 
				
			|||
                return CMT_ERR_TX_PENDING; | 
				
			|||
 | 
				
			|||
            mSpi.readReg(CMT2300A_CUS_INT1_CTL); | 
				
			|||
            mSpi.writeReg(CMT2300A_CUS_INT1_CTL, CMT2300A_INT_SEL_TX_DONE); | 
				
			|||
 | 
				
			|||
            uint8_t tmp = mSpi.readReg(CMT2300A_CUS_INT_CLR1); | 
				
			|||
            if(0x08 == tmp) // first time after TX this reg is 0x08
 | 
				
			|||
                mSpi.writeReg(CMT2300A_CUS_INT_CLR1, 0x04); | 
				
			|||
            else | 
				
			|||
                mSpi.writeReg(CMT2300A_CUS_INT_CLR1, 0x00); | 
				
			|||
 | 
				
			|||
            if(0x10 == tmp) | 
				
			|||
                mSpi.writeReg(CMT2300A_CUS_INT_CLR2, 0x10); | 
				
			|||
            else | 
				
			|||
                mSpi.writeReg(CMT2300A_CUS_INT_CLR2, 0x00); | 
				
			|||
 | 
				
			|||
            mSpi.readReg(CMT2300A_CUS_FIFO_CTL); // necessary? -> if 0x02 last was read
 | 
				
			|||
                                                  //                  0x07 last was write
 | 
				
			|||
            mSpi.writeReg(CMT2300A_CUS_FIFO_CTL, 0x02); | 
				
			|||
 | 
				
			|||
            mSpi.writeReg(CMT2300A_CUS_FIFO_CLR, 0x02); | 
				
			|||
            mSpi.writeReg(0x16, 0x0C); // [4:3]: RSSI_DET_SEL, [2:0]: RSSI_AVG_MODE
 | 
				
			|||
 | 
				
			|||
            mSpi.writeReg(CMT2300A_CUS_FREQ_CHNL, 0x00); // 863.0 MHz
 | 
				
			|||
 | 
				
			|||
            if(!cmtSwitchStatus(CMT2300A_GO_RX, CMT2300A_STA_RX)) | 
				
			|||
                return CMT_ERR_SWITCH_STATE; | 
				
			|||
 | 
				
			|||
            uint8_t state    = 0x00; | 
				
			|||
            uint16_t timeout = 5000; | 
				
			|||
            for(uint8_t i = 0; i < 52; i++) { | 
				
			|||
                state = mSpi.readReg(CMT2300A_CUS_INT_FLAG); | 
				
			|||
                if(0x00 != state) | 
				
			|||
                    break; | 
				
			|||
            } | 
				
			|||
 | 
				
			|||
            if((state & 0x10) == 0x10) { | 
				
			|||
                while(0 == digitalRead(INTR_PIN)) { | 
				
			|||
                    usleep(10); | 
				
			|||
                    if(0 == --timeout) | 
				
			|||
                        break; | 
				
			|||
                } | 
				
			|||
                if(0 != timeout) { | 
				
			|||
                    uint16_t timeout2 = 5000; | 
				
			|||
                    while(0x18 != (state & 0x18)) { | 
				
			|||
                        state = mSpi.readReg(CMT2300A_CUS_INT_FLAG); | 
				
			|||
                        if(0 == timeout2--) | 
				
			|||
                            break; | 
				
			|||
                    } | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
 | 
				
			|||
            if(0 != digitalRead(INTR_PIN)) { | 
				
			|||
                uint32_t loops = 0; | 
				
			|||
                while((state & 0x1b) != 0x1b) { | 
				
			|||
                    state = mSpi.readReg(CMT2300A_CUS_INT_FLAG); | 
				
			|||
 | 
				
			|||
                    if((state & 0x20) == 0x20) | 
				
			|||
                        return CMT_ERR_REG_VAL; | 
				
			|||
                    else if((state & 0x40) == 0x40) | 
				
			|||
                        return CMT_ERR_REG_VAL; | 
				
			|||
                    if(++loops > 5000) | 
				
			|||
                        break; | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
 | 
				
			|||
            // receive ok (pream, sync, node, crc)
 | 
				
			|||
            if((state & 0x1b) == 0x1b) { | 
				
			|||
                if(!cmtSwitchStatus(CMT2300A_GO_STBY, CMT2300A_STA_STBY)) | 
				
			|||
                    return CMT_ERR_SWITCH_STATE; | 
				
			|||
 | 
				
			|||
                mSpi.readFifo(buf, len); | 
				
			|||
                *rssi = mSpi.readReg(CMT2300A_CUS_RSSI_DBM) - 128; | 
				
			|||
 | 
				
			|||
                if(!cmtSwitchStatus(CMT2300A_GO_SLEEP, CMT2300A_STA_SLEEP)) | 
				
			|||
                    return CMT_ERR_SWITCH_STATE; | 
				
			|||
            } | 
				
			|||
 | 
				
			|||
            if(!cmtSwitchStatus(CMT2300A_GO_STBY, CMT2300A_STA_STBY)) | 
				
			|||
                return CMT_ERR_SWITCH_STATE; | 
				
			|||
 | 
				
			|||
            return CMT_SUCCESS; | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        bool tx(uint8_t buf[], uint8_t len) { | 
				
			|||
            if(mTxPending) | 
				
			|||
                return CMT_ERR_TX_PENDING; | 
				
			|||
 | 
				
			|||
            spi3w.writeReg(CMT2300A_CUS_INT1_CTL, CMT2300A_INT_SEL_TX_DONE); | 
				
			|||
 | 
				
			|||
            if(0x00 == spi3w.readReg(CMT2300A_CUS_INT_FLAG)) { | 
				
			|||
                // no data received
 | 
				
			|||
                spi3w.readReg(CMT2300A_CUS_INT_CLR1); | 
				
			|||
                spi3w.writeReg(CMT2300A_CUS_INT_CLR1, 0x00); | 
				
			|||
                spi3w.writeReg(CMT2300A_CUS_INT_CLR2, 0x00); | 
				
			|||
 | 
				
			|||
                //spi3w.readReg(CMT2300A_CUS_FIFO_CTL); // necessary?
 | 
				
			|||
                spi3w.writeReg(CMT2300A_CUS_FIFO_CTL, 0x07); | 
				
			|||
                spi3w.writeReg(CMT2300A_CUS_FIFO_CLR, 0x01); | 
				
			|||
 | 
				
			|||
                spi3w.writeReg(0x45, 0x01); | 
				
			|||
                spi3w.writeReg(0x46, len); // payload length
 | 
				
			|||
 | 
				
			|||
                spi3w.writeFifo(buf, len); | 
				
			|||
 | 
				
			|||
                // send only on base frequency: here 863.0 MHz
 | 
				
			|||
                spi3w.writeReg(CMT2300A_CUS_FREQ_CHNL, 0x00); | 
				
			|||
 | 
				
			|||
                if(!cmtSwitchStatus(CMT2300A_GO_TX, CMT2300A_STA_TX)) | 
				
			|||
                    return CMT_ERR_SWITCH_STATE; | 
				
			|||
 | 
				
			|||
                // wait for tx done
 | 
				
			|||
                mTxPending = CMT_SUCCESS; | 
				
			|||
            } | 
				
			|||
            else | 
				
			|||
                return CMT_ERR_RX_IN_FIFO; | 
				
			|||
 | 
				
			|||
            return CMT_SUCCESS; | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        // initialize CMT2300A, returns true on success
 | 
				
			|||
        bool void reset(void) { | 
				
			|||
            mSpi.writeReg(0x7f, 0xff); // soft reset
 | 
				
			|||
            delay(30); | 
				
			|||
 | 
				
			|||
            if(cmtSwitchStatus(CMT2300A_GO_STBY, CMT2300A_STA_STBY)) | 
				
			|||
                return false; | 
				
			|||
 | 
				
			|||
            if(0xAA != mSpi.readReg(0x48)) | 
				
			|||
                mSpi.writeReg(0x48, 0xAA); | 
				
			|||
            //mSpi.readReg(0x48);
 | 
				
			|||
            mSpi.writeReg(0x4c, 0x00); | 
				
			|||
 | 
				
			|||
            if(0x52 != mSpi.readReg(CMT2300A_CUS_MODE_STA)) | 
				
			|||
                mSpi.writeReg(CMT2300A_CUS_MODE_STA, 0x52); | 
				
			|||
            if(0x20 != mSpi.readReg(0x62)) | 
				
			|||
                mSpi.writeReg(0x62, 0x20); | 
				
			|||
            //mSpi.readReg(0x0D);
 | 
				
			|||
            mSpi.writeReg(0x0F, 0x00); | 
				
			|||
 | 
				
			|||
            for(uint8_t i = 0; i < 0x60; i++) { | 
				
			|||
                mSpi.writeReg(i, cmtConfig[i]); | 
				
			|||
            } | 
				
			|||
 | 
				
			|||
            if(0x02 != mSpi.readReg(0x09)) | 
				
			|||
                mSpi.writeReg(0x09, 0x02); | 
				
			|||
 | 
				
			|||
            mSpi.writeReg(CMT2300A_CUS_IO_SEL, 0x20); // -> GPIO3_SEL[1:0] = 0x02
 | 
				
			|||
 | 
				
			|||
            // interrupt 1 control selection to TX DONE
 | 
				
			|||
            if(CMT2300A_INT_SEL_TX_DONE != mSpi.readReg(CMT2300A_CUS_INT1_CTL)) | 
				
			|||
                mSpi.writeReg(CMT2300A_CUS_INT1_CTL, CMT2300A_INT_SEL_TX_DONE); | 
				
			|||
 | 
				
			|||
            // select interrupt 2
 | 
				
			|||
            if(0x07 != mSpi.readReg(CMT2300A_CUS_INT2_CTL)) | 
				
			|||
                mSpi.writeReg(CMT2300A_CUS_INT2_CTL, 0x07); | 
				
			|||
 | 
				
			|||
            // interrupt enable (TX_DONE, PREAM_OK, SYNC_OK, CRC_OK, PKT_DONE)
 | 
				
			|||
            mSpi.writeReg(CMT2300A_CUS_INT_EN, 0x3B); | 
				
			|||
 | 
				
			|||
            mSpi.writeReg(0x41, 0x48); | 
				
			|||
            mSpi.writeReg(0x42, 0x5A); | 
				
			|||
            mSpi.writeReg(0x43, 0x48); | 
				
			|||
            mSpi.writeReg(0x44, 0x4D); | 
				
			|||
            mSpi.writeReg(0x64, 0x64); | 
				
			|||
 | 
				
			|||
            if(0x00 == mSpi.readReg(CMT2300A_CUS_FIFO_CTL)) | 
				
			|||
                mSpi.writeReg(CMT2300A_CUS_FIFO_CTL, 0x02); // FIFO_MERGE_EN
 | 
				
			|||
 | 
				
			|||
            if(!cmtSwitchStatus(CMT2300A_GO_SLEEP, CMT2300A_STA_SLEEP)) | 
				
			|||
                return false; | 
				
			|||
 | 
				
			|||
            delayMicroseconds(95); | 
				
			|||
 | 
				
			|||
            // base frequency 863MHz, with value of CMT2300A_CUS_FREQ_CHNL
 | 
				
			|||
            // the frequency can be increase in a step size of ~0.24Hz
 | 
				
			|||
            mSpi.writeReg(0x18, 0x42); | 
				
			|||
            mSpi.writeReg(0x19, 0x6D); | 
				
			|||
            mSpi.writeReg(0x1A, 0x80); | 
				
			|||
            mSpi.writeReg(0x1B, 0x86); | 
				
			|||
            mSpi.writeReg(0x1C, 0x42); | 
				
			|||
            mSpi.writeReg(0x1D, 0x62); | 
				
			|||
            mSpi.writeReg(0x1E, 0x27); | 
				
			|||
            mSpi.writeReg(0x1F, 0x16); | 
				
			|||
 | 
				
			|||
            mSpi.writeReg(0x22, 0x20); | 
				
			|||
            mSpi.writeReg(0x23, 0x20); | 
				
			|||
            mSpi.writeReg(0x24, 0xD2); | 
				
			|||
            mSpi.writeReg(0x25, 0x35); | 
				
			|||
            mSpi.writeReg(0x26, 0x0C); | 
				
			|||
            mSpi.writeReg(0x27, 0x0A); | 
				
			|||
            mSpi.writeReg(0x28, 0x9F); | 
				
			|||
            mSpi.writeReg(0x29, 0x4B); | 
				
			|||
            mSpi.writeReg(0x27, 0x0A); | 
				
			|||
 | 
				
			|||
            if(!cmtSwitchStatus(CMT2300A_GO_STBY, CMT2300A_STA_STBY)) | 
				
			|||
                return false; | 
				
			|||
 | 
				
			|||
            mSpi.writeReg(0x03, 0x1D); | 
				
			|||
            mSpi.writeReg(0x5C, 0x8A); | 
				
			|||
            mSpi.writeReg(0x5D, 0x18); | 
				
			|||
 | 
				
			|||
            if(!cmtSwitchStatus(CMT2300A_GO_SLEEP, CMT2300A_STA_SLEEP)) | 
				
			|||
                return false; | 
				
			|||
 | 
				
			|||
            if(!cmtSwitchStatus(CMT2300A_GO_STBY, CMT2300A_STA_STBY)) | 
				
			|||
                return false; | 
				
			|||
 | 
				
			|||
            return true; | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
    private: | 
				
			|||
        // CMT state machine, wait for next state, true on success
 | 
				
			|||
        bool cmtSwitchStatus(uint8_t cmd, uint8_t waitFor, uint16_t cycles = 40) { | 
				
			|||
            mSpi.writeReg(CMT2300A_CUS_MODE_CTL, cmd); | 
				
			|||
            while(cycles--) { | 
				
			|||
                yield(); | 
				
			|||
                delayMicroseconds(10); | 
				
			|||
                if(waitFor == (getChipStatus() & waitFor)) | 
				
			|||
                    return true; | 
				
			|||
            } | 
				
			|||
            //Serial.println("status wait for: " + String(waitFor, HEX) + " read: " + String(getChipStatus(), HEX));
 | 
				
			|||
            return false; | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        SpiType mSpi; | 
				
			|||
        bool mTxPending; | 
				
			|||
        uint8_t mRxTxCh; | 
				
			|||
}; | 
				
			|||
 | 
				
			|||
#endif /*__CMT2300A_H__*/ | 
				
			|||
@ -0,0 +1,138 @@ | 
				
			|||
//-----------------------------------------------------------------------------
 | 
				
			|||
// 2023 Ahoy, https://github.com/lumpapu/ahoy
 | 
				
			|||
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
 | 
				
			|||
//-----------------------------------------------------------------------------
 | 
				
			|||
 | 
				
			|||
#ifndef __ESP32_3WSPI_H__ | 
				
			|||
#define __ESP32_3WSPI_H__ | 
				
			|||
 | 
				
			|||
#include "driver/spi_master.h" | 
				
			|||
#include "esp_rom_gpio.h" // for esp_rom_gpio_connect_out_signal | 
				
			|||
#include "Arduino.h" | 
				
			|||
 | 
				
			|||
#if defined(ESP32) | 
				
			|||
    #define CLK_PIN     18 | 
				
			|||
    #define MOSI_PIN    23 | 
				
			|||
    #define MISO_PIN    -1 | 
				
			|||
#endif | 
				
			|||
 | 
				
			|||
#define SPI_CLK     1 * 1000 * 1000 // 1MHz
 | 
				
			|||
 | 
				
			|||
template<uint8_t CSB_PIN=5, uint8_t FCSB_PIN=4, uint8_t GPIO3_PIN=15> | 
				
			|||
class esp32_3wSpi { | 
				
			|||
    public: | 
				
			|||
        esp32_3wSpi() {} | 
				
			|||
        void setup() { | 
				
			|||
            spi_bus_config_t buscfg = { | 
				
			|||
                .mosi_io_num = MOSI_PIN, | 
				
			|||
                .miso_io_num = MISO_PIN, | 
				
			|||
                .sclk_io_num = CLK_PIN, | 
				
			|||
                .quadwp_io_num = -1, | 
				
			|||
                .quadhd_io_num = -1, | 
				
			|||
                .max_transfer_sz = 32, | 
				
			|||
            }; | 
				
			|||
            spi_device_interface_config_t devcfg = { | 
				
			|||
                .command_bits = 0, | 
				
			|||
                .address_bits = 0, | 
				
			|||
                .dummy_bits = 0, | 
				
			|||
                .mode = 0,                 // SPI mode 0
 | 
				
			|||
                .clock_speed_hz = SPI_CLK, // 1 MHz
 | 
				
			|||
                .spics_io_num = CS_PIN, | 
				
			|||
                .flags = SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_3WIRE, | 
				
			|||
                .queue_size = 1, | 
				
			|||
                .pre_cb = NULL, | 
				
			|||
                .post_cb = NULL, | 
				
			|||
            }; | 
				
			|||
 | 
				
			|||
            ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, 0)); | 
				
			|||
            ESP_ERROR_CHECK(spi_bus_add_device(SPI2_HOST, &devcfg, &spi_reg)); | 
				
			|||
 | 
				
			|||
            // FiFo
 | 
				
			|||
            spi_device_interface_config_t devcfg2 = { | 
				
			|||
                .command_bits = 0, | 
				
			|||
                .address_bits = 0, | 
				
			|||
                .dummy_bits = 0, | 
				
			|||
                .mode = 0, // SPI mode 0
 | 
				
			|||
                .cs_ena_pretrans = 2, | 
				
			|||
                .cs_ena_posttrans = (uint8_t)(1 / (SPI_CLK * 10e6 * 2) + 2), // >2 us
 | 
				
			|||
                .clock_speed_hz = SPI_CLK,                                   // 1 MHz
 | 
				
			|||
                .spics_io_num = FCS_PIN, | 
				
			|||
                .flags = SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_3WIRE, | 
				
			|||
                .queue_size = 1, | 
				
			|||
                .pre_cb = NULL, | 
				
			|||
                .post_cb = NULL, | 
				
			|||
            }; | 
				
			|||
            ESP_ERROR_CHECK(spi_bus_add_device(SPI2_HOST, &devcfg2, &spi_fifo)); | 
				
			|||
 | 
				
			|||
            esp_rom_gpio_connect_out_signal(MOSI_PIN, spi_periph_signal[SPI2_HOST].spid_out, true, false); | 
				
			|||
            delay(100); | 
				
			|||
 | 
				
			|||
            pinMode(INTR_PIN, INPUT); | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        void writeReg(uint8_t addr, uint8_t reg) { | 
				
			|||
            uint8_t tx_data[2]; | 
				
			|||
            tx_data[0] = ~addr; | 
				
			|||
            tx_data[1] = ~reg; | 
				
			|||
            spi_transaction_t t = { | 
				
			|||
                .length = 2 * 8, | 
				
			|||
                .tx_buffer = &tx_data, | 
				
			|||
                .rx_buffer = NULL | 
				
			|||
            }; | 
				
			|||
            ESP_ERROR_CHECK(spi_device_polling_transmit(spi_reg, &t)); | 
				
			|||
            delayMicroseconds(100); | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        uint8_t readReg(uint8_t addr) { | 
				
			|||
            uint8_t tx_data, rx_data; | 
				
			|||
            tx_data = ~(addr | 0x80); // negation and MSB high (read command)
 | 
				
			|||
            spi_transaction_t t = { | 
				
			|||
                .length = 8, | 
				
			|||
                .rxlength = 8, | 
				
			|||
                .tx_buffer = &tx_data, | 
				
			|||
                .rx_buffer = &rx_data | 
				
			|||
            }; | 
				
			|||
            ESP_ERROR_CHECK(spi_device_polling_transmit(spi_reg, &t)); | 
				
			|||
            delayMicroseconds(100); | 
				
			|||
            return rx_data; | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        void writeFifo(uint8_t buf[], uint8_t len) { | 
				
			|||
            uint8_t tx_data; | 
				
			|||
 | 
				
			|||
            spi_transaction_t t = { | 
				
			|||
                .flags     = SPI_TRANS_MODE_OCT, | 
				
			|||
                .length    = 8, | 
				
			|||
                .tx_buffer = &tx_data, // reference to write data
 | 
				
			|||
                .rx_buffer = NULL | 
				
			|||
            }; | 
				
			|||
 | 
				
			|||
            for(uint8_t i = 0; i < len; i++) { | 
				
			|||
                tx_data = ~buf[i]; // negate buffer contents
 | 
				
			|||
                ESP_ERROR_CHECK(spi_device_polling_transmit(spi_fifo, &t)); | 
				
			|||
                delayMicroseconds(4); // > 4 us
 | 
				
			|||
            } | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        void readFifo(uint8_t buf[], uint8_t len) { | 
				
			|||
            uint8_t rx_data; | 
				
			|||
 | 
				
			|||
            spi_transaction_t t = { | 
				
			|||
                .length = 8, | 
				
			|||
                .rxlength = 8, | 
				
			|||
                .tx_buffer = NULL, | 
				
			|||
                .rx_buffer = &rx_data | 
				
			|||
            }; | 
				
			|||
 | 
				
			|||
            for(uint8_t i = 0; i < len; i++) { | 
				
			|||
                ESP_ERROR_CHECK(spi_device_polling_transmit(spi_fifo, &t)); | 
				
			|||
                delayMicroseconds(4); // > 4 us
 | 
				
			|||
                buf[i] = rx_data; | 
				
			|||
            } | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
    private: | 
				
			|||
        spi_device_handle_t spi_reg, spi_fifo; | 
				
			|||
}; | 
				
			|||
 | 
				
			|||
#endif /*__ESP32_3WSPI_H__*/ | 
				
			|||
@ -0,0 +1,191 @@ | 
				
			|||
//-----------------------------------------------------------------------------
 | 
				
			|||
// 2023 Ahoy, https://github.com/lumpapu/ahoy
 | 
				
			|||
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
 | 
				
			|||
//-----------------------------------------------------------------------------
 | 
				
			|||
 | 
				
			|||
#ifndef __HMS_RADIO_H__ | 
				
			|||
#define __HMS_RADIO_H__ | 
				
			|||
 | 
				
			|||
#include "../utils/dbg.h" | 
				
			|||
#include "cmt2300a.h" | 
				
			|||
 | 
				
			|||
typedef struct { | 
				
			|||
    int8_t rssi; | 
				
			|||
    uint8_t data[28]; | 
				
			|||
} hmsPacket_t; | 
				
			|||
 | 
				
			|||
#define U32_B3(val) ((uint8_t)((val >> 24) & 0xff)) | 
				
			|||
#define U32_B2(val) ((uint8_t)((val >> 16) & 0xff)) | 
				
			|||
#define U32_B1(val) ((uint8_t)((val >>  8) & 0xff)) | 
				
			|||
#define U32_B0(val) ((uint8_t)((val      ) & 0xff)) | 
				
			|||
 | 
				
			|||
template<class SPI, uint32_t DTU_SN = 0x87654321> | 
				
			|||
class HmsRadio { | 
				
			|||
    typedef SPI SpiType; | 
				
			|||
    typedef Cmt2300a<SpiType> CmtType; | 
				
			|||
    public: | 
				
			|||
        HmsRadio() { | 
				
			|||
            mDtuSn = DTU_SN; | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        void setup(bool genDtuSn = true) { | 
				
			|||
            if(genDtuSn) | 
				
			|||
                generateDtuSn(); | 
				
			|||
            if(!mCmt.resetCMT()) | 
				
			|||
                DPRINTLN(DBG_WARN, F("Initializing CMT2300A failed!")); | 
				
			|||
 | 
				
			|||
            mSendCnt        = 0; | 
				
			|||
            mRetransmits    = 0 | 
				
			|||
            mSerialDebug    = false; | 
				
			|||
            mIvIdChannelSet = NULL; | 
				
			|||
            mIrqRcvd        = false; | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        void loop() { | 
				
			|||
            mCmt.loop(); | 
				
			|||
            if(!mIrqRcvd) | 
				
			|||
                return; | 
				
			|||
            mIrqRcvd = false; | 
				
			|||
            getRx(); | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        void tickSecond() { | 
				
			|||
            if(NULL != mIvIdChannelSet) | 
				
			|||
                prepareSwitchFreqCmd(mIvIdChannelSet); | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        void handeIntr(void) { | 
				
			|||
            mIrqRcvd = true; | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        void enableDebug() { | 
				
			|||
            mSerialDebug = true; | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        void setIvBackChannel(const uint32_t *ivId) { | 
				
			|||
            mIvIdChannelSet = ivId; | 
				
			|||
            prepareSwitchFreqCmd(); | 
				
			|||
 | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        void prepareDevInformCmd(const uint32_t *ivId, uint8_t cmd, uint32_t ts, uint16_t alarmMesId, bool isRetransmit, uint8_t reqfld=TX_REQ_INFO) { // might not be necessary to add additional arg.
 | 
				
			|||
            initPacket(ivId, reqfld, ALL_FRAMES); | 
				
			|||
            mTxBuf[10] = cmd; | 
				
			|||
            mTxBuf[12] = U32_B3(ts); | 
				
			|||
            mTxBuf[13] = U32_B2(ts); | 
				
			|||
            mTxBuf[14] = U32_B1(ts); | 
				
			|||
            mTxBuf[15] = U32_B0(ts); | 
				
			|||
            /*if (cmd == RealTimeRunData_Debug || cmd == AlarmData ) {
 | 
				
			|||
                mTxBuf[18] = (alarmMesId >> 8) & 0xff; | 
				
			|||
                mTxBuf[19] = (alarmMesId     ) & 0xff; | 
				
			|||
            }*/ | 
				
			|||
            mCmt.swichChannel(true); | 
				
			|||
            sendPacket(24, isRetransmit); | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        inline void prepareSwitchChannelCmd(const uint32_t *ivId, uint8_t freqSel = 0x0c) { | 
				
			|||
            /** freqSel:
 | 
				
			|||
             * 0x0c: 863.00 MHz | 
				
			|||
             * 0x0d: 863.24 MHz | 
				
			|||
             * 0x0e: 863.48 MHz | 
				
			|||
             * 0x0f: 863.72 MHz | 
				
			|||
             * 0x10: 863.96 MHz | 
				
			|||
             * */ | 
				
			|||
            initPacket(ivId, 0x56, 0x02); | 
				
			|||
            mTxBuf[10] = 0x15; | 
				
			|||
            mTxBuf[11] = 0x21; | 
				
			|||
            mTxBuf[12] = freqSel; | 
				
			|||
            mTxBuf[13] = 0x14; | 
				
			|||
            mCmt.swichChannel(); | 
				
			|||
            sendPacket(14, false); | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        void sendPacket(uint8_t len, bool isRetransmit) { | 
				
			|||
            if (len > 14) { | 
				
			|||
                uint16_t crc = ah::crc16(&mTxBuf[10], len - 10); | 
				
			|||
                mTxBuf[len++] = (crc >> 8) & 0xff; | 
				
			|||
                mTxBuf[len++] = (crc     ) & 0xff; | 
				
			|||
            } | 
				
			|||
            mTxBuf[len] = ah::crc8(mTxBuf, len); | 
				
			|||
            len++; | 
				
			|||
 | 
				
			|||
            if(mSerialDebug) { | 
				
			|||
                DPRINT(DBG_INFO, F("TX ")); | 
				
			|||
                DBGPRINT(String(len)); | 
				
			|||
                DBGPRINT("B Ch"); | 
				
			|||
                DBGPRINT(String(mRfChLst[mTxChIdx])); | 
				
			|||
                DBGPRINT(F(" | ")); | 
				
			|||
                ah::dumpBuf(mTxBuf, len); | 
				
			|||
            } | 
				
			|||
 | 
				
			|||
            uint8_t status = mCmt.tx(mTxBuf, len); | 
				
			|||
            if(CMT_SUCCESS != status) { | 
				
			|||
                DPRINT(DBG_WARN, F("CMT TX failed, code: ")); | 
				
			|||
                DBGPRINTLN(String(status)); | 
				
			|||
            } | 
				
			|||
 | 
				
			|||
            if(isRetransmit) | 
				
			|||
                mRetransmits++; | 
				
			|||
            else | 
				
			|||
                mSendCnt++; | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        uint32_t mSendCnt; | 
				
			|||
        uint32_t mRetransmits; | 
				
			|||
        std::queue<hmsPacket_t> mBufCtrl; | 
				
			|||
 | 
				
			|||
    private: | 
				
			|||
        void initPacket(const uint32_t *ivId, uint8_t mid, uint8_t pid) { | 
				
			|||
            mTxBuf[0] = mid; | 
				
			|||
            mTxBuf[1] = U32_B3(*ivId); | 
				
			|||
            mTxBuf[2] = U32_B2(*ivId); | 
				
			|||
            mTxBuf[3] = U32_B1(*ivId); | 
				
			|||
            mTxBuf[4] = U32_B0(*ivId); | 
				
			|||
            mTxBuf[5] = U32_B3(mDtuSn); | 
				
			|||
            mTxBuf[6] = U32_B2(mDtuSn); | 
				
			|||
            mTxBuf[7] = U32_B1(mDtuSn); | 
				
			|||
            mTxBuf[8] = U32_B0(mDtuSn); | 
				
			|||
            mTxBuf[9] = pid; | 
				
			|||
            memset(&mTxBuf[10], 0x00, 17); | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        inline void generateDtuSn(void) { | 
				
			|||
            uint32_t chipID = 0; | 
				
			|||
            #ifdef ESP32 | 
				
			|||
            uint64_t MAC = ESP.getEfuseMac(); | 
				
			|||
            chipID = ((MAC >> 8) & 0xFF0000) | ((MAC >> 24) & 0xFF00) | ((MAC >> 40) & 0xFF); | 
				
			|||
            #endif | 
				
			|||
            dtuSn = 0x80000000; // the first digit is an 8 for DTU production year 2022, the rest is filled with the ESP chipID in decimal
 | 
				
			|||
            for(int i = 0; i < 7; i++) { | 
				
			|||
                dtuSn |= (chipID % 10) << (i * 4); | 
				
			|||
                chipID /= 10; | 
				
			|||
            } | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        inline void getRx(void) { | 
				
			|||
            hmsPacket_t p; | 
				
			|||
            uint8_t status = mCmt.checkRx(p.data, 28, &p.rssi); | 
				
			|||
            if(CMT_SUCCESS == status) | 
				
			|||
                mBufCtrl.push(p); | 
				
			|||
            if(NULL != mIvIdChannelSet) { | 
				
			|||
                if(U32_B3(*mIvIdChannelSet) != p.data[2]) | 
				
			|||
                    return; | 
				
			|||
                if(U32_B2(*mIvIdChannelSet) != p.data[3]) | 
				
			|||
                    return; | 
				
			|||
                if(U32_B1(*mIvIdChannelSet) != p.data[4]) | 
				
			|||
                    return; | 
				
			|||
                if(U32_B0(*mIvIdChannelSet) != p.data[5]) | 
				
			|||
                    return; | 
				
			|||
                *mIvIdChannelSet = NULL; | 
				
			|||
            } | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        CmtType mCmt; | 
				
			|||
        uint32_t mDtuSn; | 
				
			|||
        uint8_t[27] mTxBuf; | 
				
			|||
        bool mSerialDebug; | 
				
			|||
        uint32_t *mIvIdChannelSet; | 
				
			|||
        bool mIrqRcvd; | 
				
			|||
}; | 
				
			|||
 | 
				
			|||
#endif /*__HMS_RADIO_H__*/ | 
				
			|||
					Loading…
					
					
				
		Reference in new issue