mirror of
https://github.com/lumapu/ahoy.git
synced 2025-07-18 08:47:13 +02:00
individualize rx offset
for nRF
This commit is contained in:
parent
1b4b5874df
commit
e5ce1f5094
9 changed files with 210 additions and 129 deletions
|
@ -139,8 +139,10 @@ class Communication : public CommQueue<> {
|
||||||
}
|
}
|
||||||
if(!q->iv->mGotFragment) {
|
if(!q->iv->mGotFragment) {
|
||||||
if(INV_RADIO_TYPE_CMT == q->iv->ivRadioType) {
|
if(INV_RADIO_TYPE_CMT == q->iv->ivRadioType) {
|
||||||
q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, (q->iv->config->frequency*FREQ_STEP_KHZ + HOY_BASE_FREQ_KHZ));
|
#if defined(ESP32)
|
||||||
|
q->iv->radio->switchFrequency(q->iv, q->iv->radio->getBootFreqMhz() * 1000, (q->iv->config->frequency*FREQ_STEP_KHZ + q->iv->radio->getBaseFreqMhz() * 1000));
|
||||||
mWaitTime.startTimeMonitor(1000);
|
mWaitTime.startTimeMonitor(1000);
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
mHeu.setIvRetriesBad(q->iv);
|
mHeu.setIvRetriesBad(q->iv);
|
||||||
if(IV_MI == q->iv->ivGen)
|
if(IV_MI == q->iv->ivGen)
|
||||||
|
@ -526,7 +528,6 @@ class Communication : public CommQueue<> {
|
||||||
int8_t rssi = -127;
|
int8_t rssi = -127;
|
||||||
uint8_t len = 0;
|
uint8_t len = 0;
|
||||||
|
|
||||||
DPRINT_IVID(DBG_INFO, q->iv->id);
|
|
||||||
for(uint8_t i = 0; i < mMaxFrameId; i++) {
|
for(uint8_t i = 0; i < mMaxFrameId; i++) {
|
||||||
if(mLocalBuf[i].len + len > MAX_BUFFER) {
|
if(mLocalBuf[i].len + len > MAX_BUFFER) {
|
||||||
DPRINTLN(DBG_ERROR, F("payload buffer to small!"));
|
DPRINTLN(DBG_ERROR, F("payload buffer to small!"));
|
||||||
|
@ -541,7 +542,7 @@ class Communication : public CommQueue<> {
|
||||||
|
|
||||||
len -= 2;
|
len -= 2;
|
||||||
|
|
||||||
//DPRINT_IVID(DBG_INFO, q->iv->id); // it's already above "for"-loop
|
DPRINT_IVID(DBG_INFO, q->iv->id);
|
||||||
DBGPRINT(F("Payload ("));
|
DBGPRINT(F("Payload ("));
|
||||||
DBGPRINT(String(len));
|
DBGPRINT(String(len));
|
||||||
if(*mPrintWholeTrace) {
|
if(*mPrintWholeTrace) {
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
class HeuristicInv {
|
class HeuristicInv {
|
||||||
public:
|
public:
|
||||||
HeuristicInv() {
|
HeuristicInv() {
|
||||||
memset(txRfQuality, -6, RF_MAX_CHANNEL_ID);
|
memset(txRfQuality, 0, RF_MAX_CHANNEL_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -78,14 +78,6 @@ enum {CH0 = 0, CH1, CH2, CH3, CH4, CH5, CH6};
|
||||||
enum {INV_TYPE_1CH = 0, INV_TYPE_2CH, INV_TYPE_4CH, INV_TYPE_6CH};
|
enum {INV_TYPE_1CH = 0, INV_TYPE_2CH, INV_TYPE_4CH, INV_TYPE_6CH};
|
||||||
enum {INV_RADIO_TYPE_NRF = 0, INV_RADIO_TYPE_CMT};
|
enum {INV_RADIO_TYPE_NRF = 0, INV_RADIO_TYPE_CMT};
|
||||||
|
|
||||||
#define WORK_FREQ_KHZ 865000 // desired work frequency between DTU and
|
|
||||||
// inverter in kHz
|
|
||||||
#define HOY_BASE_FREQ_KHZ 860000 // in kHz
|
|
||||||
#define HOY_MAX_FREQ_KHZ 923500 // 0xFE * 250kHz + Base_freq
|
|
||||||
#define HOY_BOOT_FREQ_KHZ 868000 // Hoymiles boot/init frequency after power up inverter
|
|
||||||
#define FREQ_STEP_KHZ 250 // channel step size in kHz
|
|
||||||
#define FREQ_WARN_MIN_KHZ 863000 // for EU 863 - 870 MHz is allowed
|
|
||||||
#define FREQ_WARN_MAX_KHZ 870000 // for EU 863 - 870 MHz is allowed
|
|
||||||
|
|
||||||
#define DURATION_ONEFRAME 50 // timeout parameter for each expected frame (ms)
|
#define DURATION_ONEFRAME 50 // timeout parameter for each expected frame (ms)
|
||||||
//#define DURATION_RESERVE {90,120} // timeout parameter to still wait after last expected frame (ms)
|
//#define DURATION_RESERVE {90,120} // timeout parameter to still wait after last expected frame (ms)
|
||||||
|
|
|
@ -180,7 +180,6 @@ class Inverter {
|
||||||
tsMaxAcPower = 0;
|
tsMaxAcPower = 0;
|
||||||
|
|
||||||
memset(&radioStatistics, 0, sizeof(statistics_t));
|
memset(&radioStatistics, 0, sizeof(statistics_t));
|
||||||
|
|
||||||
memset(mOffYD, 0, sizeof(float) * 6);
|
memset(mOffYD, 0, sizeof(float) * 6);
|
||||||
memset(mLastYD, 0, sizeof(float) * 6);
|
memset(mLastYD, 0, sizeof(float) * 6);
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,7 +118,7 @@ class HmRadio : public Radio {
|
||||||
|
|
||||||
// otherwise switch to next RX channel
|
// otherwise switch to next RX channel
|
||||||
mTimeslotStart = millis();
|
mTimeslotStart = millis();
|
||||||
if(!mNRFloopChannels && ((mTimeslotStart - mLastIrqTime) > (DURATION_TXFRAME+DURATION_ONEFRAME)))
|
if(!mNRFloopChannels && ((mTimeslotStart - mLastIrqTime) > (DURATION_TXFRAME))) //(DURATION_TXFRAME+DURATION_ONEFRAME)))
|
||||||
mNRFloopChannels = true;
|
mNRFloopChannels = true;
|
||||||
|
|
||||||
rxPendular = !rxPendular;
|
rxPendular = !rxPendular;
|
||||||
|
@ -163,7 +163,7 @@ class HmRadio : public Radio {
|
||||||
mNRFloopChannels = (mLastIv->ivGen == IV_MI);
|
mNRFloopChannels = (mLastIv->ivGen == IV_MI);
|
||||||
|
|
||||||
//innerLoopTimeout = mLastIv->ivGen != IV_MI ? DURATION_TXFRAME : DURATION_ONEFRAME;
|
//innerLoopTimeout = mLastIv->ivGen != IV_MI ? DURATION_TXFRAME : DURATION_ONEFRAME;
|
||||||
innerLoopTimeout = DURATION_LISTEN_MIN;
|
innerLoopTimeout = mLastIv->ivGen != IV_MI ? DURATION_LISTEN_MIN : 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(rx_ready) {
|
if(rx_ready) {
|
||||||
|
@ -324,7 +324,13 @@ class HmRadio : public Radio {
|
||||||
if(mLastIv->mIsSingleframeReq) // we only expect one frame here...
|
if(mLastIv->mIsSingleframeReq) // we only expect one frame here...
|
||||||
isRetransmitAnswer = true;
|
isRetransmitAnswer = true;
|
||||||
if(isLastPackage)
|
if(isLastPackage)
|
||||||
mFramesExpected = p.packet[9] - ALL_FRAMES;
|
setExpectedFrames(p.packet[9] - ALL_FRAMES);
|
||||||
|
if(p.packet[9] == 1 && p.millis < DURATION_ONEFRAME)
|
||||||
|
mLastIv->rxOffset = (RF_CHANNELS + mTxChIdx - tempRxChIdx + 1) % RF_CHANNELS;
|
||||||
|
else if(mNRFloopChannels && mLastIv->rxOffset > RF_CHANNELS) { // unsure setting?
|
||||||
|
mLastIv->rxOffset = (RF_CHANNELS + mTxChIdx - tempRxChIdx + (isLastPackage ? mFramesExpected : p.packet[9])); // make clear it's not sure, start with one more offset
|
||||||
|
mNRFloopChannels = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(IV_MI == mLastIv->ivGen) {
|
if(IV_MI == mLastIv->ivGen) {
|
||||||
|
@ -332,6 +338,8 @@ class HmRadio : public Radio {
|
||||||
isLastPackage = (p.packet[9] > 0x10); // > 0x10 indicates last packet received
|
isLastPackage = (p.packet[9] > 0x10); // > 0x10 indicates last packet received
|
||||||
else if ((p.packet[0] != 0x88) && (p.packet[0] != 0x92)) // ignore MI status messages //#0 was p.packet[0] != 0x00 &&
|
else if ((p.packet[0] != 0x88) && (p.packet[0] != 0x92)) // ignore MI status messages //#0 was p.packet[0] != 0x00 &&
|
||||||
isLastPackage = true; // response from dev control command
|
isLastPackage = true; // response from dev control command
|
||||||
|
if(p.packet[9] == 0x00 && p.millis < DURATION_ONEFRAME)
|
||||||
|
mLastIv->rxOffset = (RF_CHANNELS + mTxChIdx - tempRxChIdx - 1) % RF_CHANNELS;
|
||||||
}
|
}
|
||||||
rx_ready = true; //reset in case we first read messages from other inverter or ACK zero payloads
|
rx_ready = true; //reset in case we first read messages from other inverter or ACK zero payloads
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,8 +28,7 @@ class HmSystem {
|
||||||
iv->config = &mInverter[0].generalConfig->iv[id];
|
iv->config = &mInverter[0].generalConfig->iv[id];
|
||||||
DPRINT(DBG_VERBOSE, "SERIAL: " + String(iv->config->serial.b[5], HEX));
|
DPRINT(DBG_VERBOSE, "SERIAL: " + String(iv->config->serial.b[5], HEX));
|
||||||
DPRINTLN(DBG_VERBOSE, " " + String(iv->config->serial.b[4], HEX));
|
DPRINTLN(DBG_VERBOSE, " " + String(iv->config->serial.b[4], HEX));
|
||||||
//iv->rxOffset = 5 - (iv->config->serial.b[2] % 5); //RF_CHANNELS;
|
iv->rxOffset = 13; // effective 3, but can easily be recognized as default setting
|
||||||
iv->rxOffset = (iv->config->serial.b[1] % 5); //RF_CHANNELS;
|
|
||||||
if((iv->config->serial.b[5] == 0x11) || (iv->config->serial.b[5] == 0x10)) {
|
if((iv->config->serial.b[5] == 0x11) || (iv->config->serial.b[5] == 0x10)) {
|
||||||
switch(iv->config->serial.b[4]) {
|
switch(iv->config->serial.b[4]) {
|
||||||
case 0x24: // HMS-500
|
case 0x24: // HMS-500
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// 2023 Ahoy, https://github.com/lumpapu/ahoy
|
// 2024 Ahoy, https://github.com/lumpapu/ahoy
|
||||||
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed
|
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -28,6 +28,9 @@ class Radio {
|
||||||
virtual bool switchFrequency(Inverter<> *iv, uint32_t fromkHz, uint32_t tokHz) { return true; }
|
virtual bool switchFrequency(Inverter<> *iv, uint32_t fromkHz, uint32_t tokHz) { return true; }
|
||||||
virtual bool switchFrequencyCh(Inverter<> *iv, uint8_t fromCh, uint8_t toCh) { return true; }
|
virtual bool switchFrequencyCh(Inverter<> *iv, uint8_t fromCh, uint8_t toCh) { return true; }
|
||||||
virtual bool isChipConnected(void) const { return false; }
|
virtual bool isChipConnected(void) const { return false; }
|
||||||
|
virtual uint16_t getBaseFreqMhz() { return 0; }
|
||||||
|
virtual uint16_t getBootFreqMhz() { return 0; }
|
||||||
|
virtual std::pair<uint16_t,uint16_t> getFreqRangeMhz(void) { return std::make_pair(0, 0); }
|
||||||
virtual bool loop(void) = 0;
|
virtual bool loop(void) = 0;
|
||||||
|
|
||||||
void handleIntr(void) {
|
void handleIntr(void) {
|
||||||
|
@ -115,6 +118,7 @@ class Radio {
|
||||||
chipID = ESP.getChipId();
|
chipID = ESP.getChipId();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
mDtuSn = 0;
|
||||||
uint8_t t;
|
uint8_t t;
|
||||||
for(int i = 0; i < (7 << 2); i += 4) {
|
for(int i = 0; i < (7 << 2); i += 4) {
|
||||||
t = (chipID >> i) & 0x0f;
|
t = (chipID >> i) & 0x0f;
|
||||||
|
@ -125,6 +129,7 @@ class Radio {
|
||||||
mDtuSn |= 0x80000000; // the first digit is an 8 for DTU production year 2022, the rest is filled with the ESP chipID in decimal
|
mDtuSn |= 0x80000000; // the first digit is an 8 for DTU production year 2022, the rest is filled with the ESP chipID in decimal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint32_t mDtuSn;
|
uint32_t mDtuSn;
|
||||||
volatile bool mIrqRcvd;
|
volatile bool mIrqRcvd;
|
||||||
bool *mSerialDebug, *mPrivacyMode, *mPrintWholeTrace;
|
bool *mSerialDebug, *mPrivacyMode, *mPrintWholeTrace;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// 2023 Ahoy, https://github.com/lumpapu/ahoy
|
// 2024 Ahoy, https://github.com/lumpapu/ahoy
|
||||||
// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed
|
// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -12,8 +12,23 @@
|
||||||
#include "esp32_3wSpi.h"
|
#include "esp32_3wSpi.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// detailed register infos from AN142_CMT2300AW_Quick_Start_Guide-Rev0.8.pdf
|
#include <utility>
|
||||||
|
|
||||||
|
enum class RegionCfg : uint8_t {
|
||||||
|
EUROPE, USA, BRAZIL, NUM
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class CmtStatus : uint8_t {
|
||||||
|
SUCCESS = 0,
|
||||||
|
ERR_SWITCH_STATE,
|
||||||
|
ERR_TX_PENDING,
|
||||||
|
FIFO_EMPTY,
|
||||||
|
ERR_RX_IN_FIFO
|
||||||
|
};
|
||||||
|
|
||||||
|
#define FREQ_STEP_KHZ 250 // channel step size in kHz
|
||||||
|
|
||||||
|
// detailed register infos from AN142_CMT2300AW_Quick_Start_Guide-Rev0.8.pdf
|
||||||
#define CMT2300A_MASK_CFG_RETAIN 0x10
|
#define CMT2300A_MASK_CFG_RETAIN 0x10
|
||||||
#define CMT2300A_MASK_RSTN_IN_EN 0x20
|
#define CMT2300A_MASK_RSTN_IN_EN 0x20
|
||||||
#define CMT2300A_MASK_LOCKING_EN 0x20
|
#define CMT2300A_MASK_LOCKING_EN 0x20
|
||||||
|
@ -152,67 +167,6 @@
|
||||||
#define CMT2300A_MASK_TX_DONE_FLG 0x08
|
#define CMT2300A_MASK_TX_DONE_FLG 0x08
|
||||||
#define CMT2300A_MASK_PKT_OK_FLG 0x01
|
#define CMT2300A_MASK_PKT_OK_FLG 0x01
|
||||||
|
|
||||||
// this list and the TX5, TX10 registers were compiled from the output of
|
|
||||||
// HopeRF RFPDK Tool v1.54
|
|
||||||
static uint8_t paLevelList[31][2] PROGMEM = {
|
|
||||||
{0x17, 0x01}, // -10dBm
|
|
||||||
{0x1a, 0x01}, // -09dBm
|
|
||||||
{0x1d, 0x01}, // -08dBm
|
|
||||||
{0x21, 0x01}, // -07dBm
|
|
||||||
{0x25, 0x01}, // -06dBm
|
|
||||||
{0x29, 0x01}, // -05dBm
|
|
||||||
{0x2d, 0x01}, // -04dBm
|
|
||||||
{0x33, 0x01}, // -03dBm
|
|
||||||
{0x39, 0x02}, // -02dBm
|
|
||||||
{0x41, 0x02}, // -01dBm
|
|
||||||
{0x4b, 0x02}, // 00dBm
|
|
||||||
{0x56, 0x03}, // 01dBm
|
|
||||||
{0x63, 0x03}, // 02dBm
|
|
||||||
{0x71, 0x04}, // 03dBm
|
|
||||||
{0x80, 0x04}, // 04dBm
|
|
||||||
{0x22, 0x01}, // 05dBm
|
|
||||||
{0x27, 0x04}, // 06dBm
|
|
||||||
{0x2c, 0x05}, // 07dBm
|
|
||||||
{0x31, 0x06}, // 08dBm
|
|
||||||
{0x38, 0x06}, // 09dBm
|
|
||||||
{0x3f, 0x07}, // 10dBm
|
|
||||||
{0x48, 0x08}, // 11dBm
|
|
||||||
{0x52, 0x09}, // 12dBm
|
|
||||||
{0x5d, 0x0b}, // 13dBm
|
|
||||||
{0x6a, 0x0c}, // 14dBm
|
|
||||||
{0x79, 0x0d}, // 15dBm
|
|
||||||
{0x46, 0x10}, // 16dBm
|
|
||||||
{0x51, 0x10}, // 17dBm
|
|
||||||
{0x60, 0x12}, // 18dBm
|
|
||||||
{0x71, 0x14}, // 19dBm
|
|
||||||
{0x8c, 0x1c} // 20dBm
|
|
||||||
};
|
|
||||||
|
|
||||||
// default CMT parameters
|
|
||||||
static uint8_t cmtConfig[0x60] PROGMEM {
|
|
||||||
// 0x00 - 0x0f -- RSSI offset +- 0 and 13dBm
|
|
||||||
0x00, 0x66, 0xEC, 0x1C, 0x70, 0x80, 0x14, 0x08,
|
|
||||||
0x11, 0x02, 0x02, 0x00, 0xAE, 0xE0, 0x35, 0x00,
|
|
||||||
// 0x10 - 0x1f
|
|
||||||
0x00, 0xF4, 0x10, 0xE2, 0x42, 0x20, 0x0C, 0x81,
|
|
||||||
0x42, 0x32, 0xCF, 0x82, 0x42, 0x27, 0x76, 0x12, // 860MHz as default
|
|
||||||
// 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, 0x48, 0x5A, 0x48, 0x4D, 0x01, 0x1F, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x60,
|
|
||||||
// 0x50 - 0x5f
|
|
||||||
0xFF, 0x00, 0x00, 0x1F, 0x10, 0x70, 0x4D, 0x06,
|
|
||||||
0x00, 0x07, 0x50, 0x00, 0x5D, 0x0B, 0x3F, 0x7F // - TX 13dBm
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
enum {CMT_SUCCESS = 0, CMT_ERR_SWITCH_STATE, CMT_ERR_TX_PENDING, CMT_FIFO_EMPTY, CMT_ERR_RX_IN_FIFO};
|
|
||||||
|
|
||||||
class Cmt2300a {
|
class Cmt2300a {
|
||||||
public:
|
public:
|
||||||
Cmt2300a() {}
|
Cmt2300a() {}
|
||||||
|
@ -234,12 +188,12 @@ class Cmt2300a {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t goRx(void) {
|
CmtStatus goRx(void) {
|
||||||
if(mTxPending)
|
if(mTxPending)
|
||||||
return CMT_ERR_TX_PENDING;
|
return CmtStatus::ERR_TX_PENDING;
|
||||||
|
|
||||||
if(mInRxMode)
|
if(mInRxMode)
|
||||||
return CMT_SUCCESS;
|
return CmtStatus::SUCCESS;
|
||||||
|
|
||||||
mSpi.readReg(CMT2300A_CUS_INT1_CTL);
|
mSpi.readReg(CMT2300A_CUS_INT1_CTL);
|
||||||
mSpi.writeReg(CMT2300A_CUS_INT1_CTL, CMT2300A_INT_SEL_TX_DONE);
|
mSpi.writeReg(CMT2300A_CUS_INT1_CTL, CMT2300A_INT_SEL_TX_DONE);
|
||||||
|
@ -260,47 +214,47 @@ class Cmt2300a {
|
||||||
mSpi.writeReg(0x16, 0x0C); // [4:3]: RSSI_DET_SEL, [2:0]: RSSI_AVG_MODE
|
mSpi.writeReg(0x16, 0x0C); // [4:3]: RSSI_DET_SEL, [2:0]: RSSI_AVG_MODE
|
||||||
|
|
||||||
if(!cmtSwitchStatus(CMT2300A_GO_RX, CMT2300A_STA_RX))
|
if(!cmtSwitchStatus(CMT2300A_GO_RX, CMT2300A_STA_RX))
|
||||||
return CMT_ERR_SWITCH_STATE;
|
return CmtStatus::ERR_SWITCH_STATE;
|
||||||
|
|
||||||
mInRxMode = true;
|
mInRxMode = true;
|
||||||
|
|
||||||
return CMT_SUCCESS;
|
return CmtStatus::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t getRx(uint8_t buf[], uint8_t *rxLen, uint8_t maxlen, int8_t *rssi) {
|
CmtStatus getRx(uint8_t buf[], uint8_t *rxLen, uint8_t maxlen, int8_t *rssi) {
|
||||||
if(mTxPending)
|
if(mTxPending)
|
||||||
return CMT_ERR_TX_PENDING;
|
return CmtStatus::ERR_TX_PENDING;
|
||||||
|
|
||||||
if(0x1b != (mSpi.readReg(CMT2300A_CUS_INT_FLAG) & 0x1b))
|
if(0x1b != (mSpi.readReg(CMT2300A_CUS_INT_FLAG) & 0x1b))
|
||||||
return CMT_FIFO_EMPTY;
|
return CmtStatus::FIFO_EMPTY;
|
||||||
|
|
||||||
// receive ok (pream, sync, node, crc)
|
// receive ok (pream, sync, node, crc)
|
||||||
if(!cmtSwitchStatus(CMT2300A_GO_STBY, CMT2300A_STA_STBY))
|
if(!cmtSwitchStatus(CMT2300A_GO_STBY, CMT2300A_STA_STBY))
|
||||||
return CMT_ERR_SWITCH_STATE;
|
return CmtStatus::ERR_SWITCH_STATE;
|
||||||
|
|
||||||
mSpi.readFifo(buf, rxLen, maxlen);
|
mSpi.readFifo(buf, rxLen, maxlen);
|
||||||
*rssi = mSpi.readReg(CMT2300A_CUS_RSSI_DBM) - 128;
|
*rssi = mSpi.readReg(CMT2300A_CUS_RSSI_DBM) - 128;
|
||||||
|
|
||||||
if(!cmtSwitchStatus(CMT2300A_GO_SLEEP, CMT2300A_STA_SLEEP))
|
if(!cmtSwitchStatus(CMT2300A_GO_SLEEP, CMT2300A_STA_SLEEP))
|
||||||
return CMT_ERR_SWITCH_STATE;
|
return CmtStatus::ERR_SWITCH_STATE;
|
||||||
|
|
||||||
if(!cmtSwitchStatus(CMT2300A_GO_STBY, CMT2300A_STA_STBY))
|
if(!cmtSwitchStatus(CMT2300A_GO_STBY, CMT2300A_STA_STBY))
|
||||||
return CMT_ERR_SWITCH_STATE;
|
return CmtStatus::ERR_SWITCH_STATE;
|
||||||
|
|
||||||
mInRxMode = false;
|
mInRxMode = false;
|
||||||
mCusIntFlag = mSpi.readReg(CMT2300A_CUS_INT_FLAG);
|
mCusIntFlag = mSpi.readReg(CMT2300A_CUS_INT_FLAG);
|
||||||
|
|
||||||
return CMT_SUCCESS;
|
return CmtStatus::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t tx(uint8_t buf[], uint8_t len) {
|
CmtStatus tx(uint8_t buf[], uint8_t len) {
|
||||||
if(mTxPending)
|
if(mTxPending)
|
||||||
return CMT_ERR_TX_PENDING;
|
return CmtStatus::ERR_TX_PENDING;
|
||||||
|
|
||||||
if(mInRxMode) {
|
if(mInRxMode) {
|
||||||
mInRxMode = false;
|
mInRxMode = false;
|
||||||
if(!cmtSwitchStatus(CMT2300A_GO_STBY, CMT2300A_STA_STBY))
|
if(!cmtSwitchStatus(CMT2300A_GO_STBY, CMT2300A_STA_STBY))
|
||||||
return CMT_ERR_SWITCH_STATE;
|
return CmtStatus::ERR_SWITCH_STATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
mSpi.writeReg(CMT2300A_CUS_INT1_CTL, CMT2300A_INT_SEL_TX_DONE);
|
mSpi.writeReg(CMT2300A_CUS_INT1_CTL, CMT2300A_INT_SEL_TX_DONE);
|
||||||
|
@ -325,16 +279,17 @@ class Cmt2300a {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!cmtSwitchStatus(CMT2300A_GO_TX, CMT2300A_STA_TX))
|
if(!cmtSwitchStatus(CMT2300A_GO_TX, CMT2300A_STA_TX))
|
||||||
return CMT_ERR_SWITCH_STATE;
|
return CmtStatus::ERR_SWITCH_STATE;
|
||||||
|
|
||||||
// wait for tx done
|
// wait for tx done
|
||||||
mTxPending = true;
|
mTxPending = true;
|
||||||
|
|
||||||
return CMT_SUCCESS;
|
return CmtStatus::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize CMT2300A, returns true on success
|
// initialize CMT2300A, returns true on success
|
||||||
bool reset(void) {
|
bool reset(RegionCfg region) {
|
||||||
|
mRegionCfg = region;
|
||||||
mSpi.writeReg(0x7f, 0xff); // soft reset
|
mSpi.writeReg(0x7f, 0xff); // soft reset
|
||||||
delay(30);
|
delay(30);
|
||||||
|
|
||||||
|
@ -346,9 +301,18 @@ class Cmt2300a {
|
||||||
if(mSpi.readReg(0x62) != 0x20)
|
if(mSpi.readReg(0x62) != 0x20)
|
||||||
return false; // not connected!
|
return false; // not connected!
|
||||||
|
|
||||||
for(uint8_t i = 0; i < 0x60; i++) {
|
for(uint8_t i = 0; i < 0x18; i++) {
|
||||||
mSpi.writeReg(i, cmtConfig[i]);
|
mSpi.writeReg(i, cmtConfig[i]);
|
||||||
}
|
}
|
||||||
|
for(uint8_t i = 0; i < 8; i++) {
|
||||||
|
mSpi.writeReg(0x18 + i, mBaseFreqCfg[static_cast<uint8_t>(region)][i]);
|
||||||
|
}
|
||||||
|
for(uint8_t i = 0x20; i < 0x60; i++) {
|
||||||
|
mSpi.writeReg(i, cmtConfig[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(RegionCfg::EUROPE != region)
|
||||||
|
mSpi.writeReg(0x27, 0x0B);
|
||||||
|
|
||||||
|
|
||||||
mSpi.writeReg(CMT2300A_CUS_IO_SEL, 0x20); // -> GPIO3_SEL[1:0] = 0x02
|
mSpi.writeReg(CMT2300A_CUS_IO_SEL, 0x20); // -> GPIO3_SEL[1:0] = 0x02
|
||||||
|
@ -389,23 +353,14 @@ class Cmt2300a {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint8_t freq2Chan(const uint32_t freqKhz) {
|
inline uint8_t freq2Chan(const uint32_t freqKhz) {
|
||||||
if((freqKhz % FREQ_STEP_KHZ) != 0) {
|
if((freqKhz % FREQ_STEP_KHZ) != 0)
|
||||||
DPRINT(DBG_WARN, F("switch frequency to "));
|
|
||||||
DBGPRINT(String(freqKhz));
|
|
||||||
DBGPRINT(F("kHz not possible!"));
|
|
||||||
return 0xff; // error
|
|
||||||
// apply the nearest frequency
|
|
||||||
//freqKhz = (freqKhz + FREQ_STEP_KHZ/2) / FREQ_STEP_KHZ;
|
|
||||||
//freqKhz *= FREQ_STEP_KHZ;
|
|
||||||
}
|
|
||||||
|
|
||||||
if((freqKhz < HOY_BASE_FREQ_KHZ) || (freqKhz > HOY_MAX_FREQ_KHZ))
|
|
||||||
return 0xff; // error
|
return 0xff; // error
|
||||||
|
|
||||||
if((freqKhz < FREQ_WARN_MIN_KHZ) || (freqKhz > FREQ_WARN_MAX_KHZ))
|
std::pair<uint8_t, uint8_t> range = getFreqRangeMhz();
|
||||||
DPRINTLN(DBG_WARN, F("Desired frequency is out of EU legal range! (863 - 870MHz)"));
|
if((freqKhz < range.first) || (freqKhz > range.second))
|
||||||
|
return 0xff; // error
|
||||||
|
|
||||||
return (freqKhz - HOY_BASE_FREQ_KHZ) / FREQ_STEP_KHZ;
|
return (freqKhz - getBaseFreqMhz() * 1000) / FREQ_STEP_KHZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void switchChannel(uint8_t ch) {
|
inline void switchChannel(uint8_t ch) {
|
||||||
|
@ -414,9 +369,9 @@ class Cmt2300a {
|
||||||
|
|
||||||
inline uint32_t getFreqKhz(void) {
|
inline uint32_t getFreqKhz(void) {
|
||||||
if(0xff != mRqstCh)
|
if(0xff != mRqstCh)
|
||||||
return HOY_BASE_FREQ_KHZ + (mRqstCh * FREQ_STEP_KHZ);
|
return getBaseFreqMhz() * 1000 + (mRqstCh * FREQ_STEP_KHZ);
|
||||||
else
|
else
|
||||||
return HOY_BASE_FREQ_KHZ + (mCurCh * FREQ_STEP_KHZ);
|
return getBaseFreqMhz() * 1000 + (mCurCh * FREQ_STEP_KHZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t getCurrentChannel(void) {
|
uint8_t getCurrentChannel(void) {
|
||||||
|
@ -443,6 +398,114 @@ class Cmt2300a {
|
||||||
mSpi.writeReg(CMT2300A_CUS_TX9, paLevelList[level][1]);
|
mSpi.writeReg(CMT2300A_CUS_TX9, paLevelList[level][1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
uint16_t getBaseFreqMhz(void) {
|
||||||
|
switch(mRegionCfg) {
|
||||||
|
default:
|
||||||
|
[[fallthrough]];
|
||||||
|
case RegionCfg::EUROPE:
|
||||||
|
break;
|
||||||
|
case RegionCfg::USA:
|
||||||
|
return 905;
|
||||||
|
case RegionCfg::BRAZIL:
|
||||||
|
return 915;
|
||||||
|
}
|
||||||
|
return 860;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t getBootFreqMhz(void) {
|
||||||
|
switch(mRegionCfg) {
|
||||||
|
default:
|
||||||
|
[[fallthrough]];
|
||||||
|
case RegionCfg::EUROPE:
|
||||||
|
break;
|
||||||
|
case RegionCfg::USA:
|
||||||
|
return 915;
|
||||||
|
case RegionCfg::BRAZIL:
|
||||||
|
return 915;
|
||||||
|
}
|
||||||
|
return 868;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<uint16_t,uint16_t> getFreqRangeMhz(void) {
|
||||||
|
switch(mRegionCfg) {
|
||||||
|
default:
|
||||||
|
[[fallthrough]];
|
||||||
|
case RegionCfg::EUROPE:
|
||||||
|
break;
|
||||||
|
case RegionCfg::USA:
|
||||||
|
return std::make_pair(905, 925);
|
||||||
|
case RegionCfg::BRAZIL:
|
||||||
|
return std::make_pair(915, 928);
|
||||||
|
}
|
||||||
|
return std::make_pair(860, 870); // Europe
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// this list and the TX5, TX10 registers were compiled from the output of
|
||||||
|
// HopeRF RFPDK Tool v1.54
|
||||||
|
constexpr static uint8_t paLevelList[31][2] PROGMEM = {
|
||||||
|
{0x17, 0x01}, // -10dBm
|
||||||
|
{0x1a, 0x01}, // -09dBm
|
||||||
|
{0x1d, 0x01}, // -08dBm
|
||||||
|
{0x21, 0x01}, // -07dBm
|
||||||
|
{0x25, 0x01}, // -06dBm
|
||||||
|
{0x29, 0x01}, // -05dBm
|
||||||
|
{0x2d, 0x01}, // -04dBm
|
||||||
|
{0x33, 0x01}, // -03dBm
|
||||||
|
{0x39, 0x02}, // -02dBm
|
||||||
|
{0x41, 0x02}, // -01dBm
|
||||||
|
{0x4b, 0x02}, // 00dBm
|
||||||
|
{0x56, 0x03}, // 01dBm
|
||||||
|
{0x63, 0x03}, // 02dBm
|
||||||
|
{0x71, 0x04}, // 03dBm
|
||||||
|
{0x80, 0x04}, // 04dBm
|
||||||
|
{0x22, 0x01}, // 05dBm
|
||||||
|
{0x27, 0x04}, // 06dBm
|
||||||
|
{0x2c, 0x05}, // 07dBm
|
||||||
|
{0x31, 0x06}, // 08dBm
|
||||||
|
{0x38, 0x06}, // 09dBm
|
||||||
|
{0x3f, 0x07}, // 10dBm
|
||||||
|
{0x48, 0x08}, // 11dBm
|
||||||
|
{0x52, 0x09}, // 12dBm
|
||||||
|
{0x5d, 0x0b}, // 13dBm
|
||||||
|
{0x6a, 0x0c}, // 14dBm
|
||||||
|
{0x79, 0x0d}, // 15dBm
|
||||||
|
{0x46, 0x10}, // 16dBm
|
||||||
|
{0x51, 0x10}, // 17dBm
|
||||||
|
{0x60, 0x12}, // 18dBm
|
||||||
|
{0x71, 0x14}, // 19dBm
|
||||||
|
{0x8c, 0x1c} // 20dBm
|
||||||
|
};
|
||||||
|
|
||||||
|
// default CMT parameters
|
||||||
|
constexpr static uint8_t cmtConfig[0x60] PROGMEM {
|
||||||
|
// 0x00 - 0x0f -- RSSI offset +- 0 and 13dBm
|
||||||
|
0x00, 0x66, 0xEC, 0x1C, 0x70, 0x80, 0x14, 0x08,
|
||||||
|
0x11, 0x02, 0x02, 0x00, 0xAE, 0xE0, 0x35, 0x00,
|
||||||
|
// 0x10 - 0x1f
|
||||||
|
0x00, 0xF4, 0x10, 0xE2, 0x42, 0x20, 0x0C, 0x81,
|
||||||
|
0x42, 0x32, 0xCF, 0x82, 0x42, 0x27, 0x76, 0x12, // 860MHz as default
|
||||||
|
// 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, 0x48, 0x5A, 0x48, 0x4D, 0x01, 0x1F, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x60,
|
||||||
|
// 0x50 - 0x5f
|
||||||
|
0xFF, 0x00, 0x00, 0x1F, 0x10, 0x70, 0x4D, 0x06,
|
||||||
|
0x00, 0x07, 0x50, 0x00, 0x5D, 0x0B, 0x3F, 0x7F // TX 13dBm
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr static uint8_t mBaseFreqCfg[static_cast<uint8_t>(RegionCfg::NUM)][8] {
|
||||||
|
{0x42, 0x32, 0xCF, 0x82, 0x42, 0x27, 0x76, 0x12}, // 860MHz
|
||||||
|
{0x45, 0xA8, 0x31, 0x8A, 0x45, 0x9D, 0xD8, 0x19}, // 905MHz (USA, Indonesia)
|
||||||
|
{0x46, 0x6D, 0x80, 0x86, 0x46, 0x62, 0x27, 0x16} // 915MHz (Brazil)
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void init() {
|
void init() {
|
||||||
mTxPending = false;
|
mTxPending = false;
|
||||||
|
@ -480,6 +543,7 @@ class Cmt2300a {
|
||||||
return mSpi.readReg(CMT2300A_CUS_MODE_STA) & CMT2300A_MASK_CHIP_MODE_STA;
|
return mSpi.readReg(CMT2300A_CUS_MODE_STA) & CMT2300A_MASK_CHIP_MODE_STA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
#if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(SPI_HAL)
|
#if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(SPI_HAL)
|
||||||
cmtHal mSpi;
|
cmtHal mSpi;
|
||||||
#else
|
#else
|
||||||
|
@ -490,6 +554,7 @@ class Cmt2300a {
|
||||||
bool mInRxMode;
|
bool mInRxMode;
|
||||||
uint8_t mCusIntFlag;
|
uint8_t mCusIntFlag;
|
||||||
uint8_t mRqstCh, mCurCh;
|
uint8_t mRqstCh, mCurCh;
|
||||||
|
RegionCfg mRegionCfg = RegionCfg::EUROPE;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /*__CMT2300A_H__*/
|
#endif /*__CMT2300A_H__*/
|
||||||
|
|
|
@ -17,9 +17,9 @@ class CmtRadio : public Radio {
|
||||||
mDtuSn = DTU_SN;
|
mDtuSn = DTU_SN;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup(bool *serialDebug, bool *privacyMode, bool *printWholeTrace, uint8_t pinSclk, uint8_t pinSdio, uint8_t pinCsb, uint8_t pinFcsb, bool genDtuSn = true) {
|
void setup(bool *serialDebug, bool *privacyMode, bool *printWholeTrace, uint8_t pinSclk, uint8_t pinSdio, uint8_t pinCsb, uint8_t pinFcsb, uint8_t region = 0, bool genDtuSn = true) {
|
||||||
mCmt.setup(pinSclk, pinSdio, pinCsb, pinFcsb);
|
mCmt.setup(pinSclk, pinSdio, pinCsb, pinFcsb);
|
||||||
reset(genDtuSn);
|
reset(genDtuSn, static_cast<RegionCfg>(region));
|
||||||
mPrivacyMode = privacyMode;
|
mPrivacyMode = privacyMode;
|
||||||
mSerialDebug = serialDebug;
|
mSerialDebug = serialDebug;
|
||||||
mPrintWholeTrace = printWholeTrace;
|
mPrintWholeTrace = printWholeTrace;
|
||||||
|
@ -30,7 +30,7 @@ class CmtRadio : public Radio {
|
||||||
if((!mIrqRcvd) && (!mRqstGetRx))
|
if((!mIrqRcvd) && (!mRqstGetRx))
|
||||||
return false;
|
return false;
|
||||||
getRx();
|
getRx();
|
||||||
if(CMT_SUCCESS == mCmt.goRx()) {
|
if(CmtStatus::SUCCESS == mCmt.goRx()) {
|
||||||
mIrqRcvd = false;
|
mIrqRcvd = false;
|
||||||
mRqstGetRx = false;
|
mRqstGetRx = false;
|
||||||
}
|
}
|
||||||
|
@ -76,6 +76,18 @@ class CmtRadio : public Radio {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t getBaseFreqMhz(void) override {
|
||||||
|
return mCmt.getBaseFreqMhz();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t getBootFreqMhz(void) override {
|
||||||
|
return mCmt.getBootFreqMhz();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<uint16_t,uint16_t> getFreqRangeMhz(void) override {
|
||||||
|
return mCmt.getFreqRangeMhz();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) {
|
void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) {
|
||||||
|
@ -104,12 +116,12 @@ class CmtRadio : public Radio {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t status = mCmt.tx(mTxBuf, len);
|
CmtStatus status = mCmt.tx(mTxBuf, len);
|
||||||
mMillis = millis();
|
mMillis = millis();
|
||||||
if(CMT_SUCCESS != status) {
|
if(CmtStatus::SUCCESS != status) {
|
||||||
DPRINT(DBG_WARN, F("CMT TX failed, code: "));
|
DPRINT(DBG_WARN, F("CMT TX failed, code: "));
|
||||||
DBGPRINTLN(String(status));
|
DBGPRINTLN(String(static_cast<uint8_t>(status)));
|
||||||
if(CMT_ERR_RX_IN_FIFO == status)
|
if(CmtStatus::ERR_RX_IN_FIFO == status)
|
||||||
mIrqRcvd = true;
|
mIrqRcvd = true;
|
||||||
}
|
}
|
||||||
iv->mDtuTxCnt++;
|
iv->mDtuTxCnt++;
|
||||||
|
@ -123,10 +135,10 @@ class CmtRadio : public Radio {
|
||||||
return iv->ivGen;
|
return iv->ivGen;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void reset(bool genDtuSn) {
|
inline void reset(bool genDtuSn, RegionCfg region) {
|
||||||
if(genDtuSn)
|
if(genDtuSn)
|
||||||
generateDtuSn();
|
generateDtuSn();
|
||||||
if(!mCmt.reset()) {
|
if(!mCmt.reset(region)) {
|
||||||
mCmtAvail = false;
|
mCmtAvail = false;
|
||||||
DPRINTLN(DBG_WARN, F("Initializing CMT2300A failed!"));
|
DPRINTLN(DBG_WARN, F("Initializing CMT2300A failed!"));
|
||||||
} else {
|
} else {
|
||||||
|
@ -160,8 +172,8 @@ class CmtRadio : public Radio {
|
||||||
inline void getRx(void) {
|
inline void getRx(void) {
|
||||||
packet_t p;
|
packet_t p;
|
||||||
p.millis = millis() - mMillis;
|
p.millis = millis() - mMillis;
|
||||||
uint8_t status = mCmt.getRx(p.packet, &p.len, 28, &p.rssi);
|
CmtStatus status = mCmt.getRx(p.packet, &p.len, 28, &p.rssi);
|
||||||
if(CMT_SUCCESS == status)
|
if(CmtStatus::SUCCESS == status)
|
||||||
mBufCtrl.push(p);
|
mBufCtrl.push(p);
|
||||||
|
|
||||||
if(p.packet[9] > ALL_FRAMES) // indicates last frame
|
if(p.packet[9] > ALL_FRAMES) // indicates last frame
|
||||||
|
@ -171,7 +183,7 @@ class CmtRadio : public Radio {
|
||||||
}
|
}
|
||||||
|
|
||||||
CmtType mCmt;
|
CmtType mCmt;
|
||||||
bool mCmtAvail;
|
bool mCmtAvail = false;
|
||||||
bool mRqstGetRx = false;
|
bool mRqstGetRx = false;
|
||||||
uint32_t mMillis;
|
uint32_t mMillis;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue