Browse Source

basic implementation of HMS/HMT inverters

pull/935/head
lumapu 2 years ago
parent
commit
c56c785a1f
  1. 1
      src/CHANGES.md
  2. 2
      src/app.cpp
  3. 8
      src/app.h
  4. 7
      src/config/settings.h
  5. 430
      src/hm/cmt2300a.h
  6. 138
      src/hm/esp32_3wSpi.h
  7. 2
      src/hm/hmPayload.h
  8. 19
      src/hm/hmRadio.h
  9. 191
      src/hm/hmsRadio.h
  10. 2
      src/hm/miPayload.h
  11. 7
      src/main.cpp
  12. 9
      src/utils/helper.cpp
  13. 3
      src/utils/helper.h

1
src/CHANGES.md

@ -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

2
src/app.cpp

@ -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++;

8
src/app.h

@ -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)

7
src/config/settings.h

@ -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

@ -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

@ -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__*/

2
src/hm/hmPayload.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) {

19
src/hm/hmRadio.h

@ -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

@ -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__*/

2
src/hm/miPayload.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) {

7
src/main.cpp

@ -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);
}

9
src/utils/helper.cpp

@ -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("");
}
}

3
src/utils/helper.h

@ -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…
Cancel
Save