-
-
Notifications
You must be signed in to change notification settings - Fork 230
/
Copy pathCmtRadio.h
241 lines (198 loc) · 7.68 KB
/
CmtRadio.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
//-----------------------------------------------------------------------------
// 2024 Ahoy, https://github.com/lumpapu/ahoy
// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed
//-----------------------------------------------------------------------------
#ifndef __HMS_RADIO_H__
#define __HMS_RADIO_H__
#include "cmt2300a.h"
#include "../hm/Radio.h"
//#define CMT_SWITCH_CHANNEL_CYCLE 5
template<uint32_t DTU_SN = 0x81001765>
class CmtRadio : public Radio {
typedef Cmt2300a CmtType;
public:
void setup(bool *serialDebug, bool *privacyMode, bool *printWholeTrace, cfgCmt_t *cfg, uint8_t region = 0, bool genDtuSn = true) {
mCfg = cfg;
if(!cfg->enabled)
return;
mPrivacyMode = privacyMode;
mSerialDebug = serialDebug;
mPrintWholeTrace = printWholeTrace;
mTxBuf.fill(0);
mCmt.setup(cfg->pinSclk, cfg->pinSdio, cfg->pinCsb, cfg->pinFcsb);
reset(genDtuSn, static_cast<RegionCfg>(region));
}
void loop() override {
if(!mCfg->enabled)
return;
mCmt.loop();
if(nullptr != mCatchIv) {
if(mCmt.isTxReady())
catchInverterLoop();
}
if((!mIrqRcvd) && (!mRqstGetRx))
return;
getRx();
if(CmtStatus::SUCCESS == mCmt.goRx()) {
mIrqRcvd = false;
mRqstGetRx = false;
}
return;
}
bool isChipConnected(void) const override {
return mCmtAvail;
}
void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit) override {
if(!mCfg->enabled)
return;
DPRINT_IVID(DBG_INFO, iv->id);
DBGPRINT(F("sendControlPacket cmd: "));
DBGHEXLN(cmd);
initPacket(iv->radioId.u64, TX_REQ_DEVCONTROL, SINGLE_FRAME);
uint8_t cnt = 10;
mTxBuf[cnt++] = cmd; // cmd -> 0 on, 1 off, 2 restart, 11 active power, 12 reactive power, 13 power factor
mTxBuf[cnt++] = 0x00;
if(cmd >= ActivePowerContr && cmd <= PFSet) { // ActivePowerContr, ReactivePowerContr, PFSet
mTxBuf[cnt++] = (data[0] >> 8) & 0xff; // power limit, multiplied by 10 (because of fraction)
mTxBuf[cnt++] = (data[0] ) & 0xff; // power limit
mTxBuf[cnt++] = (data[1] >> 8) & 0xff; // setting for persistens handlings
mTxBuf[cnt++] = (data[1] ) & 0xff; // setting for persistens handling
}
sendPacket(iv, cnt, isRetransmit);
}
bool switchFrequency(Inverter<> *iv, uint32_t fromkHz, uint32_t tokHz) override {
if(!isChipConnected())
return false;
uint8_t fromCh = mCmt.freq2Chan(fromkHz);
uint8_t toCh = mCmt.freq2Chan(tokHz);
return switchFrequencyCh(iv, fromCh, toCh);
}
bool switchFrequencyCh(Inverter<> *iv, uint8_t fromCh, uint8_t toCh) override {
if((0xff == fromCh) || (0xff == toCh))
return false;
if(!isChipConnected())
return false;
mCmt.switchChannel(fromCh);
sendSwitchChCmd(iv, toCh);
mCmt.switchChannel(toCh);
return true;
}
void catchInverter(Inverter<> *iv, uint8_t toCh) override {
if(!isChipConnected())
return;
mCatchIv = iv;
mCatchIvCh = 1;
mCatchIvToCh = toCh;
mCmt.switchChannel(0);
sendSwitchChCmd(iv, toCh);
}
void catchInverterLoop() {
mCmt.switchChannel(mCatchIvCh);
sendSwitchChCmd(mCatchIv, mCatchIvToCh);
if(++mCatchIvCh == 0x29) {
mCmt.switchChannel(mCatchIvToCh);
mCatchIv = nullptr;
}
}
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:
void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) override {
// inverters have maybe different settings regarding frequency
if(mCmt.getCurrentChannel() != iv->config->frequency)
mCmt.switchChannel(iv->config->frequency);
updateCrcs(&len, appendCrc16);
if(*mSerialDebug) {
DPRINT_IVID(DBG_INFO, iv->id);
DBGPRINT(F("TX "));
DBGPRINT(String(mCmt.getFreqKhz()/1000.0f));
DBGPRINT(F("Mhz | "));
if(*mPrintWholeTrace) {
if(*mPrivacyMode)
ah::dumpBuf(mTxBuf.data(), len, 1, 4);
else
ah::dumpBuf(mTxBuf.data(), len);
} else {
DHEX(mTxBuf[0]);
DBGPRINT(F(" "));
DHEX(mTxBuf[10]);
DBGPRINT(F(" "));
DBGHEXLN(mTxBuf[9]);
}
}
CmtStatus status = mCmt.tx(mTxBuf.data(), len);
mMillis = millis();
if(CmtStatus::SUCCESS != status) {
DPRINT(DBG_WARN, F("CMT TX failed, code: "));
DBGPRINTLN(String(static_cast<uint8_t>(status)));
if(CmtStatus::ERR_RX_IN_FIFO == status)
mIrqRcvd = true;
}
iv->mDtuTxCnt++;
}
uint64_t getIvId(Inverter<> *iv) const override {
return iv->radioId.u64;
}
uint8_t getIvGen(Inverter<> *iv) const override {
return iv->ivGen;
}
inline void reset(bool genDtuSn, RegionCfg region) {
if(genDtuSn)
generateDtuSn();
if(!mCmt.reset(region)) {
mCmtAvail = false;
DPRINTLN(DBG_WARN, F("Initializing CMT2300A failed!"));
} else {
mCmtAvail = true;
mCmt.goRx();
}
mIrqRcvd = false;
mRqstGetRx = false;
}
inline void sendSwitchChCmd(Inverter<> *iv, uint8_t ch) {
/** ch:
* 0x00: 860.00 MHz
* 0x01: 860.25 MHz
* 0x02: 860.50 MHz
* ...
* 0x14: 865.00 MHz
* ...
* 0x28: 870.00 MHz
* */
initPacket(iv->radioId.u64, 0x56, 0x02);
mTxBuf[10] = 0x15;
mTxBuf[11] = 0x21;
mTxBuf[12] = ch;
mTxBuf[13] = 0x14;
sendPacket(iv, 14, false);
mRqstGetRx = true;
}
inline void getRx(void) {
packet_t p;
p.millis = millis() - mMillis;
if(CmtStatus::SUCCESS == mCmt.getRx(p.packet, &p.len, 28, &p.rssi)) {
p.ch = 0; // not used for CMT inverters
mBufCtrl.push(p);
}
if(p.packet[9] > ALL_FRAMES) { // indicates last frame
setExpectedFrames(p.packet[9] - ALL_FRAMES);
mRadioWaitTime.startTimeMonitor(2); // let the inverter first get back to rx mode?
}
}
CmtType mCmt;
cfgCmt_t *mCfg = nullptr;
bool mCmtAvail = false;
bool mRqstGetRx = false;
uint32_t mMillis = 0;
Inverter<> *mCatchIv = nullptr;
uint8_t mCatchIvCh = 0;
uint8_t mCatchIvToCh = 0;
};
#endif /*__HMS_RADIO_H__*/