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