KissModem.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. #include "KissModem.h"
  2. #include <CayenneLPP.h>
  3. KissModem::KissModem(Stream& serial, mesh::LocalIdentity& identity, mesh::RNG& rng,
  4. mesh::Radio& radio, mesh::MainBoard& board, SensorManager& sensors)
  5. : _serial(serial), _identity(identity), _rng(rng), _radio(radio), _board(board), _sensors(sensors) {
  6. _rx_len = 0;
  7. _rx_escaped = false;
  8. _rx_active = false;
  9. _has_pending_tx = false;
  10. _pending_tx_len = 0;
  11. _txdelay = KISS_DEFAULT_TXDELAY;
  12. _persistence = KISS_DEFAULT_PERSISTENCE;
  13. _slottime = KISS_DEFAULT_SLOTTIME;
  14. _txtail = 0;
  15. _fullduplex = 0;
  16. _tx_state = TX_IDLE;
  17. _tx_timer = 0;
  18. _setRadioCallback = nullptr;
  19. _setTxPowerCallback = nullptr;
  20. _getCurrentRssiCallback = nullptr;
  21. _getStatsCallback = nullptr;
  22. _sendPacketCallback = nullptr;
  23. _isSendCompleteCallback = nullptr;
  24. _onSendFinishedCallback = nullptr;
  25. _config = {0, 0, 0, 0, 0};
  26. }
  27. void KissModem::begin() {
  28. _rx_len = 0;
  29. _rx_escaped = false;
  30. _rx_active = false;
  31. _has_pending_tx = false;
  32. _tx_state = TX_IDLE;
  33. }
  34. void KissModem::writeByte(uint8_t b) {
  35. if (b == KISS_FEND) {
  36. _serial.write(KISS_FESC);
  37. _serial.write(KISS_TFEND);
  38. } else if (b == KISS_FESC) {
  39. _serial.write(KISS_FESC);
  40. _serial.write(KISS_TFESC);
  41. } else {
  42. _serial.write(b);
  43. }
  44. }
  45. void KissModem::writeFrame(uint8_t type, const uint8_t* data, uint16_t len) {
  46. _serial.write(KISS_FEND);
  47. writeByte(type);
  48. for (uint16_t i = 0; i < len; i++) {
  49. writeByte(data[i]);
  50. }
  51. _serial.write(KISS_FEND);
  52. }
  53. void KissModem::writeHardwareFrame(uint8_t sub_cmd, const uint8_t* data, uint16_t len) {
  54. _serial.write(KISS_FEND);
  55. writeByte(KISS_CMD_SETHARDWARE);
  56. writeByte(sub_cmd);
  57. for (uint16_t i = 0; i < len; i++) {
  58. writeByte(data[i]);
  59. }
  60. _serial.write(KISS_FEND);
  61. }
  62. void KissModem::writeHardwareError(uint8_t error_code) {
  63. writeHardwareFrame(HW_RESP_ERROR, &error_code, 1);
  64. }
  65. void KissModem::loop() {
  66. while (_serial.available()) {
  67. uint8_t b = _serial.read();
  68. if (b == KISS_FEND) {
  69. if (_rx_active && _rx_len > 0) {
  70. processFrame();
  71. }
  72. _rx_len = 0;
  73. _rx_escaped = false;
  74. _rx_active = true;
  75. continue;
  76. }
  77. if (!_rx_active) continue;
  78. if (b == KISS_FESC) {
  79. _rx_escaped = true;
  80. continue;
  81. }
  82. if (_rx_escaped) {
  83. _rx_escaped = false;
  84. if (b == KISS_TFEND) b = KISS_FEND;
  85. else if (b == KISS_TFESC) b = KISS_FESC;
  86. else continue;
  87. }
  88. if (_rx_len < KISS_MAX_FRAME_SIZE) {
  89. _rx_buf[_rx_len++] = b;
  90. }
  91. }
  92. processTx();
  93. }
  94. void KissModem::processFrame() {
  95. if (_rx_len < 1) return;
  96. uint8_t type_byte = _rx_buf[0];
  97. if (type_byte == KISS_CMD_RETURN) return;
  98. uint8_t port = (type_byte >> 4) & 0x0F;
  99. uint8_t cmd = type_byte & 0x0F;
  100. if (port != 0) return;
  101. const uint8_t* data = &_rx_buf[1];
  102. uint16_t data_len = _rx_len - 1;
  103. switch (cmd) {
  104. case KISS_CMD_DATA:
  105. if (data_len > 0 && data_len <= KISS_MAX_PACKET_SIZE && !_has_pending_tx) {
  106. memcpy(_pending_tx, data, data_len);
  107. _pending_tx_len = data_len;
  108. _has_pending_tx = true;
  109. }
  110. break;
  111. case KISS_CMD_TXDELAY:
  112. if (data_len >= 1) _txdelay = data[0];
  113. break;
  114. case KISS_CMD_PERSISTENCE:
  115. if (data_len >= 1) _persistence = data[0];
  116. break;
  117. case KISS_CMD_SLOTTIME:
  118. if (data_len >= 1) _slottime = data[0];
  119. break;
  120. case KISS_CMD_TXTAIL:
  121. if (data_len >= 1) _txtail = data[0];
  122. break;
  123. case KISS_CMD_FULLDUPLEX:
  124. if (data_len >= 1) _fullduplex = data[0];
  125. break;
  126. case KISS_CMD_SETHARDWARE:
  127. if (data_len >= 1) {
  128. handleHardwareCommand(data[0], data + 1, data_len - 1);
  129. }
  130. break;
  131. default:
  132. break;
  133. }
  134. }
  135. void KissModem::handleHardwareCommand(uint8_t sub_cmd, const uint8_t* data, uint16_t len) {
  136. switch (sub_cmd) {
  137. case HW_CMD_GET_IDENTITY:
  138. handleGetIdentity();
  139. break;
  140. case HW_CMD_GET_RANDOM:
  141. handleGetRandom(data, len);
  142. break;
  143. case HW_CMD_VERIFY_SIGNATURE:
  144. handleVerifySignature(data, len);
  145. break;
  146. case HW_CMD_SIGN_DATA:
  147. handleSignData(data, len);
  148. break;
  149. case HW_CMD_ENCRYPT_DATA:
  150. handleEncryptData(data, len);
  151. break;
  152. case HW_CMD_DECRYPT_DATA:
  153. handleDecryptData(data, len);
  154. break;
  155. case HW_CMD_KEY_EXCHANGE:
  156. handleKeyExchange(data, len);
  157. break;
  158. case HW_CMD_HASH:
  159. handleHash(data, len);
  160. break;
  161. case HW_CMD_SET_RADIO:
  162. handleSetRadio(data, len);
  163. break;
  164. case HW_CMD_SET_TX_POWER:
  165. handleSetTxPower(data, len);
  166. break;
  167. case HW_CMD_GET_RADIO:
  168. handleGetRadio();
  169. break;
  170. case HW_CMD_GET_TX_POWER:
  171. handleGetTxPower();
  172. break;
  173. case HW_CMD_GET_VERSION:
  174. handleGetVersion();
  175. break;
  176. case HW_CMD_GET_CURRENT_RSSI:
  177. handleGetCurrentRssi();
  178. break;
  179. case HW_CMD_IS_CHANNEL_BUSY:
  180. handleIsChannelBusy();
  181. break;
  182. case HW_CMD_GET_AIRTIME:
  183. handleGetAirtime(data, len);
  184. break;
  185. case HW_CMD_GET_NOISE_FLOOR:
  186. handleGetNoiseFloor();
  187. break;
  188. case HW_CMD_GET_STATS:
  189. handleGetStats();
  190. break;
  191. case HW_CMD_GET_BATTERY:
  192. handleGetBattery();
  193. break;
  194. case HW_CMD_PING:
  195. handlePing();
  196. break;
  197. case HW_CMD_GET_SENSORS:
  198. handleGetSensors(data, len);
  199. break;
  200. case HW_CMD_GET_MCU_TEMP:
  201. handleGetMCUTemp();
  202. break;
  203. case HW_CMD_REBOOT:
  204. handleReboot();
  205. break;
  206. case HW_CMD_GET_DEVICE_NAME:
  207. handleGetDeviceName();
  208. break;
  209. default:
  210. writeHardwareError(HW_ERR_UNKNOWN_CMD);
  211. break;
  212. }
  213. }
  214. void KissModem::processTx() {
  215. switch (_tx_state) {
  216. case TX_IDLE:
  217. if (_has_pending_tx) {
  218. if (_fullduplex) {
  219. _tx_timer = millis();
  220. _tx_state = TX_DELAY;
  221. } else {
  222. _tx_state = TX_WAIT_CLEAR;
  223. }
  224. }
  225. break;
  226. case TX_WAIT_CLEAR:
  227. if (!_radio.isReceiving()) {
  228. uint8_t rand_val;
  229. _rng.random(&rand_val, 1);
  230. if (rand_val <= _persistence) {
  231. _tx_timer = millis();
  232. _tx_state = TX_DELAY;
  233. } else {
  234. _tx_timer = millis();
  235. _tx_state = TX_SLOT_WAIT;
  236. }
  237. }
  238. break;
  239. case TX_SLOT_WAIT:
  240. if (millis() - _tx_timer >= (uint32_t)_slottime * 10) {
  241. _tx_state = TX_WAIT_CLEAR;
  242. }
  243. break;
  244. case TX_DELAY:
  245. if (millis() - _tx_timer >= (uint32_t)_txdelay * 10) {
  246. if (_sendPacketCallback) {
  247. _sendPacketCallback(_pending_tx, _pending_tx_len);
  248. _tx_state = TX_SENDING;
  249. } else {
  250. _has_pending_tx = false;
  251. _tx_state = TX_IDLE;
  252. }
  253. }
  254. break;
  255. case TX_SENDING:
  256. if (_isSendCompleteCallback && _isSendCompleteCallback()) {
  257. if (_onSendFinishedCallback) _onSendFinishedCallback();
  258. uint8_t result = 0x01;
  259. writeHardwareFrame(HW_RESP_TX_DONE, &result, 1);
  260. _has_pending_tx = false;
  261. _tx_state = TX_IDLE;
  262. }
  263. break;
  264. }
  265. }
  266. void KissModem::onPacketReceived(int8_t snr, int8_t rssi, const uint8_t* packet, uint16_t len) {
  267. writeFrame(KISS_CMD_DATA, packet, len);
  268. uint8_t meta[2] = { (uint8_t)snr, (uint8_t)rssi };
  269. writeHardwareFrame(HW_RESP_RX_META, meta, 2);
  270. }
  271. void KissModem::handleGetIdentity() {
  272. writeHardwareFrame(HW_RESP_IDENTITY, _identity.pub_key, PUB_KEY_SIZE);
  273. }
  274. void KissModem::handleGetRandom(const uint8_t* data, uint16_t len) {
  275. if (len < 1) {
  276. writeHardwareError(HW_ERR_INVALID_LENGTH);
  277. return;
  278. }
  279. uint8_t requested = data[0];
  280. if (requested < 1 || requested > 64) {
  281. writeHardwareError(HW_ERR_INVALID_PARAM);
  282. return;
  283. }
  284. uint8_t buf[64];
  285. _rng.random(buf, requested);
  286. writeHardwareFrame(HW_RESP_RANDOM, buf, requested);
  287. }
  288. void KissModem::handleVerifySignature(const uint8_t* data, uint16_t len) {
  289. if (len < PUB_KEY_SIZE + SIGNATURE_SIZE + 1) {
  290. writeHardwareError(HW_ERR_INVALID_LENGTH);
  291. return;
  292. }
  293. mesh::Identity signer(data);
  294. const uint8_t* signature = data + PUB_KEY_SIZE;
  295. const uint8_t* msg = data + PUB_KEY_SIZE + SIGNATURE_SIZE;
  296. uint16_t msg_len = len - PUB_KEY_SIZE - SIGNATURE_SIZE;
  297. uint8_t result = signer.verify(signature, msg, msg_len) ? 0x01 : 0x00;
  298. writeHardwareFrame(HW_RESP_VERIFY, &result, 1);
  299. }
  300. void KissModem::handleSignData(const uint8_t* data, uint16_t len) {
  301. if (len < 1) {
  302. writeHardwareError(HW_ERR_INVALID_LENGTH);
  303. return;
  304. }
  305. uint8_t signature[SIGNATURE_SIZE];
  306. _identity.sign(signature, data, len);
  307. writeHardwareFrame(HW_RESP_SIGNATURE, signature, SIGNATURE_SIZE);
  308. }
  309. void KissModem::handleEncryptData(const uint8_t* data, uint16_t len) {
  310. if (len < PUB_KEY_SIZE + 1) {
  311. writeHardwareError(HW_ERR_INVALID_LENGTH);
  312. return;
  313. }
  314. const uint8_t* key = data;
  315. const uint8_t* plaintext = data + PUB_KEY_SIZE;
  316. uint16_t plaintext_len = len - PUB_KEY_SIZE;
  317. uint8_t buf[KISS_MAX_FRAME_SIZE];
  318. int encrypted_len = mesh::Utils::encryptThenMAC(key, buf, plaintext, plaintext_len);
  319. if (encrypted_len > 0) {
  320. writeHardwareFrame(HW_RESP_ENCRYPTED, buf, encrypted_len);
  321. } else {
  322. writeHardwareError(HW_ERR_ENCRYPT_FAILED);
  323. }
  324. }
  325. void KissModem::handleDecryptData(const uint8_t* data, uint16_t len) {
  326. if (len < PUB_KEY_SIZE + CIPHER_MAC_SIZE + 1) {
  327. writeHardwareError(HW_ERR_INVALID_LENGTH);
  328. return;
  329. }
  330. const uint8_t* key = data;
  331. const uint8_t* ciphertext = data + PUB_KEY_SIZE;
  332. uint16_t ciphertext_len = len - PUB_KEY_SIZE;
  333. uint8_t buf[KISS_MAX_FRAME_SIZE];
  334. int decrypted_len = mesh::Utils::MACThenDecrypt(key, buf, ciphertext, ciphertext_len);
  335. if (decrypted_len > 0) {
  336. writeHardwareFrame(HW_RESP_DECRYPTED, buf, decrypted_len);
  337. } else {
  338. writeHardwareError(HW_ERR_MAC_FAILED);
  339. }
  340. }
  341. void KissModem::handleKeyExchange(const uint8_t* data, uint16_t len) {
  342. if (len < PUB_KEY_SIZE) {
  343. writeHardwareError(HW_ERR_INVALID_LENGTH);
  344. return;
  345. }
  346. uint8_t shared_secret[PUB_KEY_SIZE];
  347. _identity.calcSharedSecret(shared_secret, data);
  348. writeHardwareFrame(HW_RESP_SHARED_SECRET, shared_secret, PUB_KEY_SIZE);
  349. }
  350. void KissModem::handleHash(const uint8_t* data, uint16_t len) {
  351. if (len < 1) {
  352. writeHardwareError(HW_ERR_INVALID_LENGTH);
  353. return;
  354. }
  355. uint8_t hash[32];
  356. mesh::Utils::sha256(hash, 32, data, len);
  357. writeHardwareFrame(HW_RESP_HASH, hash, 32);
  358. }
  359. void KissModem::handleSetRadio(const uint8_t* data, uint16_t len) {
  360. if (len < 10) {
  361. writeHardwareError(HW_ERR_INVALID_LENGTH);
  362. return;
  363. }
  364. if (!_setRadioCallback) {
  365. writeHardwareError(HW_ERR_NO_CALLBACK);
  366. return;
  367. }
  368. uint32_t freq_hz, bw_hz;
  369. memcpy(&freq_hz, data, 4);
  370. memcpy(&bw_hz, data + 4, 4);
  371. uint8_t sf = data[8];
  372. uint8_t cr = data[9];
  373. _config.freq_hz = freq_hz;
  374. _config.bw_hz = bw_hz;
  375. _config.sf = sf;
  376. _config.cr = cr;
  377. float freq = freq_hz / 1000000.0f;
  378. float bw = bw_hz / 1000.0f;
  379. _setRadioCallback(freq, bw, sf, cr);
  380. writeHardwareFrame(HW_RESP_OK, nullptr, 0);
  381. }
  382. void KissModem::handleSetTxPower(const uint8_t* data, uint16_t len) {
  383. if (len < 1) {
  384. writeHardwareError(HW_ERR_INVALID_LENGTH);
  385. return;
  386. }
  387. if (!_setTxPowerCallback) {
  388. writeHardwareError(HW_ERR_NO_CALLBACK);
  389. return;
  390. }
  391. _config.tx_power = data[0];
  392. _setTxPowerCallback(data[0]);
  393. writeHardwareFrame(HW_RESP_OK, nullptr, 0);
  394. }
  395. void KissModem::handleGetRadio() {
  396. uint8_t buf[10];
  397. memcpy(buf, &_config.freq_hz, 4);
  398. memcpy(buf + 4, &_config.bw_hz, 4);
  399. buf[8] = _config.sf;
  400. buf[9] = _config.cr;
  401. writeHardwareFrame(HW_RESP_RADIO, buf, 10);
  402. }
  403. void KissModem::handleGetTxPower() {
  404. writeHardwareFrame(HW_RESP_TX_POWER, &_config.tx_power, 1);
  405. }
  406. void KissModem::handleGetVersion() {
  407. uint8_t buf[2];
  408. buf[0] = KISS_FIRMWARE_VERSION;
  409. buf[1] = 0;
  410. writeHardwareFrame(HW_RESP_VERSION, buf, 2);
  411. }
  412. void KissModem::handleGetCurrentRssi() {
  413. if (!_getCurrentRssiCallback) {
  414. writeHardwareError(HW_ERR_NO_CALLBACK);
  415. return;
  416. }
  417. float rssi = _getCurrentRssiCallback();
  418. int8_t rssi_byte = (int8_t)rssi;
  419. writeHardwareFrame(HW_RESP_CURRENT_RSSI, (uint8_t*)&rssi_byte, 1);
  420. }
  421. void KissModem::handleIsChannelBusy() {
  422. uint8_t busy = _radio.isReceiving() ? 0x01 : 0x00;
  423. writeHardwareFrame(HW_RESP_CHANNEL_BUSY, &busy, 1);
  424. }
  425. void KissModem::handleGetAirtime(const uint8_t* data, uint16_t len) {
  426. if (len < 1) {
  427. writeHardwareError(HW_ERR_INVALID_LENGTH);
  428. return;
  429. }
  430. uint8_t packet_len = data[0];
  431. uint32_t airtime = _radio.getEstAirtimeFor(packet_len);
  432. writeHardwareFrame(HW_RESP_AIRTIME, (uint8_t*)&airtime, 4);
  433. }
  434. void KissModem::handleGetNoiseFloor() {
  435. int16_t noise_floor = _radio.getNoiseFloor();
  436. writeHardwareFrame(HW_RESP_NOISE_FLOOR, (uint8_t*)&noise_floor, 2);
  437. }
  438. void KissModem::handleGetStats() {
  439. if (!_getStatsCallback) {
  440. writeHardwareError(HW_ERR_NO_CALLBACK);
  441. return;
  442. }
  443. uint32_t rx, tx, errors;
  444. _getStatsCallback(&rx, &tx, &errors);
  445. uint8_t buf[12];
  446. memcpy(buf, &rx, 4);
  447. memcpy(buf + 4, &tx, 4);
  448. memcpy(buf + 8, &errors, 4);
  449. writeHardwareFrame(HW_RESP_STATS, buf, 12);
  450. }
  451. void KissModem::handleGetBattery() {
  452. uint16_t mv = _board.getBattMilliVolts();
  453. writeHardwareFrame(HW_RESP_BATTERY, (uint8_t*)&mv, 2);
  454. }
  455. void KissModem::handlePing() {
  456. writeHardwareFrame(HW_RESP_PONG, nullptr, 0);
  457. }
  458. void KissModem::handleGetSensors(const uint8_t* data, uint16_t len) {
  459. if (len < 1) {
  460. writeHardwareError(HW_ERR_INVALID_LENGTH);
  461. return;
  462. }
  463. uint8_t permissions = data[0];
  464. CayenneLPP telemetry(255);
  465. if (_sensors.querySensors(permissions, telemetry)) {
  466. writeHardwareFrame(HW_RESP_SENSORS, telemetry.getBuffer(), telemetry.getSize());
  467. } else {
  468. writeHardwareFrame(HW_RESP_SENSORS, nullptr, 0);
  469. }
  470. }
  471. void KissModem::handleGetMCUTemp() {
  472. float temp = _board.getMCUTemperature();
  473. if (isnan(temp)) {
  474. writeHardwareError(HW_ERR_NO_CALLBACK);
  475. return;
  476. }
  477. int16_t temp_tenths = (int16_t)(temp * 10.0f);
  478. writeHardwareFrame(HW_RESP_MCU_TEMP, (uint8_t*)&temp_tenths, 2);
  479. }
  480. void KissModem::handleReboot() {
  481. writeHardwareFrame(HW_RESP_OK, nullptr, 0);
  482. _serial.flush();
  483. delay(50);
  484. _board.reboot();
  485. }
  486. void KissModem::handleGetDeviceName() {
  487. const char* name = _board.getManufacturerName();
  488. writeHardwareFrame(HW_RESP_DEVICE_NAME, (const uint8_t*)name, strlen(name));
  489. }