mirror of
https://github.com/lumapu/ahoy.git
synced 2025-06-16 09:31:39 +02:00
basic implementation of HMS/HMT inverters
This commit is contained in:
parent
b6a41506b6
commit
c56c785a1f
13 changed files with 800 additions and 19 deletions
|
@ -7,6 +7,7 @@
|
|||
* added part of mac address to MQTT client ID to seperate multiple ESPs in same network
|
||||
* added dictionary for MQTT to reduce heap-fragmentation
|
||||
* removed `last Alarm` from Live view, because it showed always the same alarm - will change in future
|
||||
* #671, #650
|
||||
|
||||
## 0.5.88
|
||||
* MQTT Yield Day zero, next try to fix #671, thx @beegee3
|
||||
|
|
|
@ -115,7 +115,7 @@ void app::loopStandard(void) {
|
|||
DBGPRINT(F("B Ch"));
|
||||
DBGPRINT(String(p->ch));
|
||||
DBGPRINT(F(" | "));
|
||||
mSys.Radio.dumpBuf(p->packet, p->len);
|
||||
ah::dumpBuf(p->packet, p->len);
|
||||
}
|
||||
mStat.frmCnt++;
|
||||
|
||||
|
|
|
@ -66,6 +66,10 @@ class app : public IApp, public ah::Scheduler {
|
|||
mSys.Radio.handleIntr();
|
||||
}
|
||||
|
||||
void handleHmsIntr(void) {
|
||||
//mSys.Radio.handleHmsIntr();
|
||||
}
|
||||
|
||||
uint32_t getUptime() {
|
||||
return Scheduler::getUptime();
|
||||
}
|
||||
|
@ -160,6 +164,10 @@ class app : public IApp, public ah::Scheduler {
|
|||
return mConfig->nrf.pinIrq;
|
||||
}
|
||||
|
||||
uint8_t getHmsIrqPin(void) {
|
||||
return mConfig->cmt.pinIrq;
|
||||
}
|
||||
|
||||
String getTimeStr(uint32_t offset = 0) {
|
||||
char str[10];
|
||||
if(0 == mTimestamp)
|
||||
|
|
|
@ -68,6 +68,12 @@ typedef struct {
|
|||
uint8_t amplifierPower;
|
||||
} cfgNrf24_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t pinCsb;
|
||||
uint8_t pinFcsb;
|
||||
uint8_t pinIrq;
|
||||
} cfgCmt_t;
|
||||
|
||||
typedef struct {
|
||||
char addr[NTP_ADDR_LEN];
|
||||
uint16_t port;
|
||||
|
@ -138,6 +144,7 @@ typedef struct {
|
|||
typedef struct {
|
||||
cfgSys_t sys;
|
||||
cfgNrf24_t nrf;
|
||||
cfgCmt_t cmt;
|
||||
cfgNtp_t ntp;
|
||||
cfgSun_t sun;
|
||||
cfgSerial_t serial;
|
||||
|
|
430
src/hm/cmt2300a.h
Normal file
430
src/hm/cmt2300a.h
Normal file
|
@ -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__*/
|
138
src/hm/esp32_3wSpi.h
Normal file
138
src/hm/esp32_3wSpi.h
Normal file
|
@ -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__*/
|
|
@ -307,7 +307,7 @@ class HmPayload {
|
|||
DPRINT(DBG_INFO, F("Payload ("));
|
||||
DBGPRINT(String(payloadLen));
|
||||
DBGPRINT(F("): "));
|
||||
mSys->Radio.dumpBuf(payload, payloadLen);
|
||||
ah::dumpBuf(payload, payloadLen);
|
||||
}
|
||||
|
||||
if (NULL == rec) {
|
||||
|
|
|
@ -188,7 +188,7 @@ class HmRadio {
|
|||
mTxBuf[cnt++] = ((data[1] ) >> 8) & 0xff; // setting for persistens handlings
|
||||
mTxBuf[cnt++] = ((data[1] ) ) & 0xff; // setting for persistens handling
|
||||
}
|
||||
sendPacket(invId, cnt, isRetransmit, true);
|
||||
sendPacket(invId, cnt, isRetransmit);
|
||||
}
|
||||
|
||||
void prepareDevInformCmd(uint64_t invId, 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.
|
||||
|
@ -201,21 +201,12 @@ class HmRadio {
|
|||
mTxBuf[18] = (alarmMesId >> 8) & 0xff;
|
||||
mTxBuf[19] = (alarmMesId ) & 0xff;
|
||||
}
|
||||
sendPacket(invId, 24, isRetransmit, true);
|
||||
sendPacket(invId, 24, isRetransmit);
|
||||
}
|
||||
|
||||
void sendCmdPacket(uint64_t invId, uint8_t mid, uint8_t pid, bool isRetransmit) {
|
||||
initPacket(invId, mid, pid);
|
||||
sendPacket(invId, 10, isRetransmit, false);
|
||||
}
|
||||
|
||||
void dumpBuf(uint8_t buf[], uint8_t len) {
|
||||
//DPRINTLN(DBG_VERBOSE, F("hmRadio.h:dumpBuf"));
|
||||
for(uint8_t i = 0; i < len; i++) {
|
||||
DHEX(buf[i]);
|
||||
DBGPRINT(" ");
|
||||
}
|
||||
DBGPRINTLN("");
|
||||
sendPacket(invId, 10, isRetransmit);
|
||||
}
|
||||
|
||||
uint8_t getDataRate(void) {
|
||||
|
@ -279,7 +270,7 @@ class HmRadio {
|
|||
mTxBuf[9] = pid;
|
||||
}
|
||||
|
||||
void sendPacket(uint64_t invId, uint8_t len, bool isRetransmit, bool clear=false) {
|
||||
void sendPacket(uint64_t invId, uint8_t len, bool isRetransmit) {
|
||||
//DPRINTLN(DBG_VERBOSE, F("hmRadio.h:sendPacket"));
|
||||
//DPRINTLN(DBG_VERBOSE, "sent packet: #" + String(mSendCnt));
|
||||
|
||||
|
@ -300,7 +291,7 @@ class HmRadio {
|
|||
DBGPRINT("B Ch");
|
||||
DBGPRINT(String(mRfChLst[mTxChIdx]));
|
||||
DBGPRINT(F(" | "));
|
||||
dumpBuf(mTxBuf, len);
|
||||
ah::dumpBuf(mTxBuf, len);
|
||||
}
|
||||
|
||||
mNrf24.stopListening();
|
||||
|
|
191
src/hm/hmsRadio.h
Normal file
191
src/hm/hmsRadio.h
Normal file
|
@ -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__*/
|
|
@ -194,7 +194,7 @@ class MiPayload {
|
|||
|
||||
if (mSerialDebug) {
|
||||
DPRINT(DBG_INFO, F("Payload (") + String(payloadLen) + "): ");
|
||||
mSys->Radio.dumpBuf(payload, payloadLen);
|
||||
ah::dumpBuf(payload, payloadLen);
|
||||
}
|
||||
|
||||
if (NULL == rec) {
|
||||
|
|
|
@ -15,13 +15,18 @@ IRAM_ATTR void handleIntr(void) {
|
|||
myApp.handleIntr();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
IRAM_ATTR void handleHmsIntr(void) {
|
||||
myApp.handleHmsIntr();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void setup() {
|
||||
myApp.setup();
|
||||
|
||||
// TODO: move to HmRadio
|
||||
attachInterrupt(digitalPinToInterrupt(myApp.getIrqPin()), handleIntr, FALLING);
|
||||
attachInterrupt(digitalPinToInterrupt(myApp.getHmsIrqPin()), handleHmsIntr, RISING);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "helper.h"
|
||||
#include "dbg.h"
|
||||
|
||||
namespace ah {
|
||||
void ip2Arr(uint8_t ip[], const char *ipStr) {
|
||||
|
@ -64,4 +65,12 @@ namespace ah {
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dumpBuf(uint8_t buf[], uint8_t len) {
|
||||
for(uint8_t i = 0; i < len; i++) {
|
||||
DHEX(buf[i]);
|
||||
DBGPRINT(" ");
|
||||
}
|
||||
DBGPRINTLN("");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 2022 Ahoy, https://ahoydtu.de
|
||||
// 2023 Ahoy, https://ahoydtu.de
|
||||
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
@ -23,6 +23,7 @@ namespace ah {
|
|||
String getDateTimeStr(time_t t);
|
||||
String getTimeStr(time_t t);
|
||||
uint64_t Serial2u64(const char *val);
|
||||
void dumpBuf(uint8_t buf[], uint8_t len);
|
||||
}
|
||||
|
||||
#endif /*__HELPER_H__*/
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue