_txRx.ino 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754
  1. // 1-channel LoRa Gateway for ESP8266
  2. // Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
  3. // Version 6.1.3
  4. // Date: 2019-11-20
  5. //
  6. // based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
  7. // and many others.
  8. //
  9. // All rights reserved. This program and the accompanying materials
  10. // are made available under the terms of the MIT License
  11. // which accompanies this distribution, and is available at
  12. // https://opensource.org/licenses/mit-license.php
  13. //
  14. // NO WARRANTY OF ANY KIND IS PROVIDED
  15. //
  16. // Author: Maarten Westenberg (mw12554@hotmail.com)
  17. //
  18. // This file contains the LoRa modem specific code enabling to receive
  19. // and transmit packages/messages.
  20. // ========================================================================================
  21. // ----------------------------------------------------------------------------
  22. // DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN
  23. // Send DOWN a LoRa packet over the air to the node. This function does all the
  24. // decoding of the server message and prepares a Payload buffer.
  25. // The payload is actually transmitted by the sendPkt() function.
  26. // This function is used for regular downstream messages and for JOIN_ACCEPT
  27. // messages.
  28. // NOTE: This is not an interrupt function, but is started by loop().
  29. // The _status is set an the end of the function to TX and in _stateMachine
  30. // function the actual transmission function is executed.
  31. // The LoraDown.tmst contains the timestamp that the tranmission should finish.
  32. // ----------------------------------------------------------------------------
  33. int sendPacket(uint8_t *buf, uint8_t length)
  34. {
  35. // Received package with Meta Data (for example):
  36. // codr : "4/5"
  37. // data : "Kuc5CSwJ7/a5JgPHrP29X9K6kf/Vs5kU6g==" // for example
  38. // freq : 868.1 // 868100000
  39. // ipol : true/false
  40. // modu : "LORA"
  41. // powe : 14 // Set by default
  42. // rfch : 0 // Set by default
  43. // size : 21
  44. // tmst : 1800642 // for example
  45. // datr : "SF7BW125"
  46. // 12-byte header;
  47. // HDR (1 byte)
  48. //
  49. //
  50. // Data Reply for JOIN_ACCEPT as sent by server:
  51. // AppNonce (3 byte)
  52. // NetID (3 byte)
  53. // DevAddr (4 byte) [ 31..25]:NwkID , [24..0]:NwkAddr
  54. // DLSettings (1 byte)
  55. // RxDelay (1 byte)
  56. // CFList (fill to 16 bytes)
  57. int i=0;
  58. StaticJsonDocument<312> jsonBuffer; // Use of arduinoJson version 6!
  59. char * bufPtr = (char *) (buf);
  60. buf[length] = 0;
  61. #if _DUSB>=1
  62. if (( debug>=2) && (pdebug & P_TX)) {
  63. Serial.println((char *)buf);
  64. Serial.print(F("<"));
  65. Serial.flush();
  66. }
  67. #endif
  68. // Use JSON to decode the string after the first 4 bytes.
  69. // The data for the node is in the "data" field. This function destroys original buffer
  70. auto error = deserializeJson(jsonBuffer, bufPtr);
  71. if (error) {
  72. #if _DUSB>=1
  73. if (( debug>=1) && (pdebug & P_TX)) {
  74. Serial.print (F("T sendPacket:: ERROR Json Decode"));
  75. if (debug>=2) {
  76. Serial.print(':');
  77. Serial.println(bufPtr);
  78. }
  79. Serial.flush();
  80. }
  81. #endif
  82. return(-1);
  83. }
  84. yield();
  85. // Meta Data sent by server (example)
  86. // {"txpk":{"codr":"4/5","data":"YCkEAgIABQABGmIwYX/kSn4Y","freq":868.1,"ipol":true,"modu":"LORA","powe":14,"rfch":0,"size":18,"tmst":1890991792,"datr":"SF7BW125"}}
  87. // Used in the protocol of Gateway:
  88. JsonObject root = jsonBuffer.as<JsonObject>(); // 191111 Avoid Crashes
  89. const char * data = root["txpk"]["data"]; // Downstream Payload
  90. uint8_t psize = root["txpk"]["size"]; // Payload size
  91. bool ipol = root["txpk"]["ipol"];
  92. uint8_t powe = root["txpk"]["powe"]; // power, e.g. 14 or 27
  93. LoraDown.tmst = (uint32_t) root["txpk"]["tmst"].as<unsigned long>();
  94. const float ff = root["txpk"]["freq"]; // eg 869.525
  95. // Not used in the protocol of Gateway TTN:
  96. const char * datr = root["txpk"]["datr"]; // eg "SF7BW125"
  97. const char * modu = root["txpk"]["modu"]; // =="LORA"
  98. const char * codr = root["txpk"]["codr"]; // e.g. "4/5"
  99. //if (root["txpk"].containsKey("imme") ) {
  100. // const bool imme = root["txpk"]["imme"]; // Immediate Transmit (tmst don't care)
  101. //}
  102. if ( data != NULL ) {
  103. #if _DUSB>=1
  104. if (( debug>=2 ) && ( pdebug & P_TX )) {
  105. Serial.print(F("T data: "));
  106. Serial.println((char *) data);
  107. if (debug>=2) Serial.flush();
  108. }
  109. #endif
  110. }
  111. else { // There is data!
  112. #if _DUSB>=1
  113. if ((debug>0) && ( pdebug & P_TX )) {
  114. Serial.println(F("T sendPacket:: ERROR: data is NULL"));
  115. if (debug>=2) Serial.flush();
  116. }
  117. #endif
  118. return(-1);
  119. }
  120. LoraDown.sfTx = atoi(datr+2); // Convert "SF9BW125" or what is received from gateway to number
  121. LoraDown.iiq = (ipol? 0x40: 0x27); // if ipol==true 0x40 else 0x27
  122. LoraDown.crc = 0x00; // switch CRC off for TX
  123. LoraDown.payLength = base64_dec_len((char *) data, strlen(data));// Length of the Payload data
  124. base64_decode((char *) payLoad, (char *) data, strlen(data)); // Fill payload w decoded message
  125. // Compute wait time in microseconds
  126. uint32_t w = (uint32_t) (LoraDown.tmst - micros()); // Wait Time compute
  127. // _STRICT_1CH determines how we will react on downstream messages.
  128. //
  129. // If STRICT==1, we will answer (in the RX1 timeslot) on the frequency we receive on.
  130. // This way, we can better communicate as a single gateway machine
  131. //
  132. #if _STRICT_1CH == 1
  133. // RX1 is requested frequency
  134. // RX2 is SF12
  135. // If possible use RX1 timeslot as this is our frequency.
  136. // Do not use RX2 or JOIN2 as they contain other frequencies
  137. // Wait time RX1
  138. if ((w>1000000) && (w<3000000)) {
  139. LoraDown.tmst-=1000000;
  140. }
  141. // RX2. Is tmst correction necessary
  142. else if ((w>6000000) && (w<7000000)) {
  143. LoraDown.tmst-=500000;
  144. }
  145. LoraDown.powe = 14; // On all freqs except 869.5MHz power is limited
  146. LoraDown.sfTx = sfi; // Take care, TX sf not to be mixed with SCAN
  147. LoraDown.fff = freqs[ifreq].dwnFreq; // Use the corresponsing Down frequency
  148. #else
  149. // If _STRICT_1CH == 0, we will receive messags from the TTN gateway presumably on SF9/869.5MHz
  150. // And since the Gateway is a single channel gateway, and its nodes are probably
  151. // single channel too. They will not listen to that frequency at all.
  152. // Pleae note that this parameter is more for nodes (that cannot change freqs)
  153. // than for gateways.
  154. //
  155. LoraDown.powe = powe;
  156. // convert double frequency (MHz) into uint32_t frequency in Hz.
  157. LoraDown.fff = (uint32_t) ((uint32_t)((ff+0.000035)*1000)) * 1000;
  158. #endif
  159. LoraDown.payLoad = payLoad;
  160. #if _DUSB>=1
  161. if (( debug>=1 ) && ( pdebug & P_TX)) {
  162. Serial.print(F("T LoraDown tmst="));
  163. Serial.print(LoraDown.tmst);
  164. //Serial.print(F(", w="));
  165. //Serial.print(w);
  166. if ( debug>=2 ) {
  167. Serial.print(F(" Request:: "));
  168. Serial.print(F(" tmst=")); Serial.print(LoraDown.tmst); Serial.print(F(" wait=")); Serial.println(w);
  169. Serial.print(F(" strict=")); Serial.print(_STRICT_1CH);
  170. Serial.print(F(" datr=")); Serial.println(datr);
  171. Serial.print(F(" Rfreq=")); Serial.print(freqs[ifreq].dwnFreq);
  172. //Serial.print(F(", Request=")); Serial.print(freqs[ifreq].dwnFreq);
  173. Serial.print(F(" ->")); Serial.println(LoraDown.fff);
  174. Serial.print(F(" sf =")); Serial.print(atoi(datr+2)); Serial.print(F(" ->")); Serial.println(LoraDown.sfTx);
  175. Serial.print(F(" modu=")); Serial.println(modu);
  176. Serial.print(F(" powe=")); Serial.println(powe);
  177. Serial.print(F(" codr=")); Serial.println(codr);
  178. Serial.print(F(" ipol=")); Serial.println(ipol);
  179. }
  180. Serial.println();
  181. }
  182. #endif
  183. if (LoraDown.payLength != psize) {
  184. #if _DUSB>=1
  185. Serial.print(F("sendPacket:: WARNING payLength: "));
  186. Serial.print(LoraDown.payLength);
  187. Serial.print(F(", psize="));
  188. Serial.println(psize);
  189. if (debug>=2) Serial.flush();
  190. #endif
  191. }
  192. #if _DUSB>=1
  193. else if (( debug >= 2 ) && ( pdebug & P_TX )) {
  194. Serial.print(F("T Payload="));
  195. for (i=0; i<LoraDown.payLength; i++) {
  196. Serial.print(payLoad[i],HEX);
  197. Serial.print(':');
  198. }
  199. Serial.println();
  200. }
  201. #endif
  202. // Update downstream statistics
  203. statc.msg_down++;
  204. switch(statr[0].ch) {
  205. case 0: statc.msg_down_0++; break;
  206. case 1: statc.msg_down_1++; break;
  207. case 2: statc.msg_down_2++; break;
  208. }
  209. #if _DUSB>=1
  210. if (( debug>=2 ) && ( pdebug & P_TX )) {
  211. Serial.println(F("T sendPacket:: fini OK"));
  212. Serial.flush();
  213. }
  214. #endif // _DUSB
  215. // All data is in Payload and parameters and need to be transmitted.
  216. // The function is called in user-space
  217. _state = S_TX; // _state set to transmit
  218. return 1;
  219. }//sendPacket
  220. // ----------------------------------------------------------------------------
  221. // UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP
  222. // Based on the information read from the LoRa transceiver (or fake message)
  223. // build a gateway message to send upstream (to the user somewhere on the web).
  224. //
  225. // parameters:
  226. // tmst: Timestamp to include in the upstream message
  227. // buff_up: The buffer that is generated for upstream
  228. // message: The payload message to include in the the buff_up
  229. // messageLength: The number of bytes received by the LoRa transceiver
  230. // internal: Boolean value to indicate whether the local sensor is processed
  231. //
  232. // returns:
  233. // buff_index
  234. // ----------------------------------------------------------------------------
  235. int buildPacket(uint32_t tmst, uint8_t *buff_up, struct LoraUp LoraUp, bool internal)
  236. {
  237. long SNR;
  238. int rssicorr;
  239. int prssi; // packet rssi
  240. char cfreq[12] = {0}; // Character array to hold freq in MHz
  241. //lastTmst = tmst; // Following/according to spec
  242. int buff_index=0;
  243. char b64[256];
  244. uint8_t *message = LoraUp.payLoad;
  245. char messageLength = LoraUp.payLength;
  246. #if _CHECK_MIC==1
  247. unsigned char NwkSKey[16] = _NWKSKEY;
  248. checkMic(message, messageLength, NwkSKey);
  249. #endif // _CHECK_MIC
  250. // Read SNR and RSSI from the register. Note: Not for internal sensors!
  251. // For internal sensor we fake these values as we cannot read a register
  252. if (internal) {
  253. SNR = 12;
  254. prssi = 50;
  255. rssicorr = 157;
  256. }
  257. else {
  258. SNR = LoraUp.snr;
  259. prssi = LoraUp.prssi; // read register 0x1A, packet rssi
  260. rssicorr = LoraUp.rssicorr;
  261. }
  262. #if _STATISTICS >= 1
  263. // Receive statistics, move old statistics down 1 position
  264. // and fill the new top line with the latest received sensor values.
  265. // This works fine for the sensor, EXCEPT when we decode data for _LOCALSERVER
  266. //
  267. for (int m=( MAX_STAT -1); m>0; m--) statr[m]=statr[m-1];
  268. // From now on we can fill statr[0] with sensor data
  269. #if _LOCALSERVER==1
  270. statr[0].datal=0;
  271. int index;
  272. if ((index = inDecodes((char *)(LoraUp.payLoad+1))) >=0 ) {
  273. uint16_t frameCount=LoraUp.payLoad[7]*256 + LoraUp.payLoad[6];
  274. for (int k=0; (k<LoraUp.payLength) && (k<23); k++) {
  275. statr[0].data[k] = LoraUp.payLoad[k+9];
  276. };
  277. // XXX Check that k<23 when leaving the for loop
  278. // XXX or we can not display in statr
  279. uint8_t DevAddr[4];
  280. DevAddr[0]= LoraUp.payLoad[4];
  281. DevAddr[1]= LoraUp.payLoad[3];
  282. DevAddr[2]= LoraUp.payLoad[2];
  283. DevAddr[3]= LoraUp.payLoad[1];
  284. statr[0].datal = encodePacket((uint8_t *)(statr[0].data),
  285. LoraUp.payLength-9-4,
  286. (uint16_t)frameCount,
  287. DevAddr,
  288. decodes[index].appKey,
  289. 0);
  290. }
  291. #endif //_LOCALSERVER
  292. statr[0].tmst = now();
  293. statr[0].ch= ifreq;
  294. statr[0].prssi = prssi - rssicorr;
  295. #if RSSI==1
  296. statr[0].rssi = _rssi - rssicorr;
  297. #endif // RSII
  298. statr[0].sf = LoraUp.sf;
  299. #if _DUSB>=2
  300. if (debug>=0) {
  301. if ((message[4] != 0x26) || (message[1]==0x99)) {
  302. Serial.print(F("addr="));
  303. for (int i=messageLength; i>0; i--) {
  304. if (message[i]<0x10) Serial.print('0');
  305. Serial.print(message[i],HEX);
  306. Serial.print(' ');
  307. }
  308. Serial.println();
  309. }
  310. }
  311. #endif //DUSB
  312. statr[0].node = ( message[1]<<24 | message[2]<<16 | message[3]<<8 | message[4] );
  313. #if _STATISTICS >= 2
  314. // Fill in the statistics that we will also need for the GUI.
  315. // So
  316. switch (statr[0].sf) {
  317. case SF7: statc.sf7++; break;
  318. case SF8: statc.sf8++; break;
  319. case SF9: statc.sf9++; break;
  320. case SF10: statc.sf10++; break;
  321. case SF11: statc.sf11++; break;
  322. case SF12: statc.sf12++; break;
  323. }
  324. #endif // _STATISTICS >= 2
  325. #if _STATISTICS >= 3
  326. if (statr[0].ch == 0) {
  327. statc.msg_ttl_0++;
  328. switch (statr[0].sf) {
  329. case SF7: statc.sf7_0++; break;
  330. case SF8: statc.sf8_0++; break;
  331. case SF9: statc.sf9_0++; break;
  332. case SF10: statc.sf10_0++; break;
  333. case SF11: statc.sf11_0++; break;
  334. case SF12: statc.sf12_0++; break;
  335. }
  336. }
  337. else
  338. if (statr[0].ch == 1) {
  339. statc.msg_ttl_1++;
  340. switch (statr[0].sf) {
  341. case SF7: statc.sf7_1++; break;
  342. case SF8: statc.sf8_1++; break;
  343. case SF9: statc.sf9_1++; break;
  344. case SF10: statc.sf10_1++; break;
  345. case SF11: statc.sf11_1++; break;
  346. case SF12: statc.sf12_1++; break;
  347. }
  348. }
  349. else
  350. if (statr[0].ch == 2) {
  351. statc.msg_ttl_2++;
  352. switch (statr[0].sf) {
  353. case SF7: statc.sf7_2++; break;
  354. case SF8: statc.sf8_2++; break;
  355. case SF9: statc.sf9_2++; break;
  356. case SF10: statc.sf10_2++; break;
  357. case SF11: statc.sf11_2++; break;
  358. case SF12: statc.sf12_2++; break;
  359. }
  360. }
  361. #endif //_STATISTICS >= 3
  362. #endif //_STATISTICS >= 2
  363. #if _DUSB>=1
  364. if (( debug>=2 ) && ( pdebug & P_RADIO )){
  365. Serial.print(F("R buildPacket:: pRSSI="));
  366. Serial.print(prssi-rssicorr);
  367. Serial.print(F(" RSSI: "));
  368. Serial.print(_rssi - rssicorr);
  369. Serial.print(F(" SNR: "));
  370. Serial.print(SNR);
  371. Serial.print(F(" Length: "));
  372. Serial.print((int)messageLength);
  373. Serial.print(F(" -> "));
  374. int i;
  375. for (i=0; i< messageLength; i++) {
  376. Serial.print(message[i],HEX);
  377. Serial.print(' ');
  378. }
  379. Serial.println();
  380. yield();
  381. }
  382. #endif // _DUSB
  383. // Show received message status on OLED display
  384. #if OLED>=1
  385. char timBuff[20];
  386. sprintf(timBuff, "%02i:%02i:%02i", hour(), minute(), second());
  387. display.clear();
  388. display.setFont(ArialMT_Plain_16);
  389. display.setTextAlignment(TEXT_ALIGN_LEFT);
  390. // msg_oLED(timBuff, prssi-rssicorr, SNR, message)
  391. display.drawString(0, 0, "Time: " );
  392. display.drawString(40, 0, timBuff);
  393. display.drawString(0, 16, "RSSI: " );
  394. display.drawString(40, 16, String(prssi-rssicorr));
  395. display.drawString(70, 16, ",SNR: " );
  396. display.drawString(110, 16, String(SNR) );
  397. display.drawString(0, 32, "Addr: " );
  398. if (message[4] < 0x10) display.drawString( 40, 32, "0"+String(message[4], HEX)); else display.drawString( 40, 32, String(message[4], HEX));
  399. if (message[3] < 0x10) display.drawString( 61, 32, "0"+String(message[3], HEX)); else display.drawString( 61, 32, String(message[3], HEX));
  400. if (message[2] < 0x10) display.drawString( 82, 32, "0"+String(message[2], HEX)); else display.drawString( 82, 32, String(message[2], HEX));
  401. if (message[1] < 0x10) display.drawString(103, 32, "0"+String(message[1], HEX)); else display.drawString(103, 32, String(message[1], HEX));
  402. display.drawString(0, 48, "LEN: " );
  403. display.drawString(40, 48, String((int)messageLength) );
  404. display.display();
  405. //yield();
  406. #endif //OLED>=1
  407. int j;
  408. // XXX Base64 library is nopad. So we may have to add padding characters until
  409. // message Length is multiple of 4!
  410. // Encode message with messageLength into b64
  411. int encodedLen = base64_enc_len(messageLength); // max 341
  412. #if _DUSB>=1
  413. if ((debug>=1) && (encodedLen>255) && ( pdebug & P_RADIO )) {
  414. Serial.print(F("R buildPacket:: b64 err, len="));
  415. Serial.println(encodedLen);
  416. if (debug>=2) Serial.flush();
  417. return(-1);
  418. }
  419. #endif // _DUSB
  420. base64_encode(b64, (char *) message, messageLength);// max 341
  421. // start composing datagram with the header
  422. uint8_t token_h = (uint8_t)rand(); // random token
  423. uint8_t token_l = (uint8_t)rand(); // random token
  424. // pre-fill the data buffer with fixed fields
  425. buff_up[0] = PROTOCOL_VERSION; // 0x01 still
  426. buff_up[1] = token_h;
  427. buff_up[2] = token_l;
  428. buff_up[3] = PKT_PUSH_DATA; // 0x00
  429. // READ MAC ADDRESS OF ESP8266, and insert 0xFF 0xFF in the middle
  430. buff_up[4] = MAC_array[0];
  431. buff_up[5] = MAC_array[1];
  432. buff_up[6] = MAC_array[2];
  433. buff_up[7] = 0xFF;
  434. buff_up[8] = 0xFF;
  435. buff_up[9] = MAC_array[3];
  436. buff_up[10] = MAC_array[4];
  437. buff_up[11] = MAC_array[5];
  438. buff_index = 12; // 12-byte binary (!) header
  439. // start of JSON structure that will make payload
  440. memcpy((void *)(buff_up + buff_index), (void *)"{\"rxpk\":[", 9);
  441. buff_index += 9;
  442. buff_up[buff_index] = '{';
  443. ++buff_index;
  444. j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, "\"tmst\":%u", tmst);
  445. #if _DUSB>=1
  446. if ((j<0) && ( debug>=1 ) && ( pdebug & P_RADIO )) {
  447. Serial.println(F("buildPacket:: Error "));
  448. }
  449. #endif
  450. buff_index += j;
  451. ftoa((double)freqs[ifreq].upFreq / 1000000, cfreq, 6); // XXX This can be done better
  452. j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, ",\"chan\":%1u,\"rfch\":%1u,\"freq\":%s", 0, 0, cfreq);
  453. buff_index += j;
  454. memcpy((void *)(buff_up + buff_index), (void *)",\"stat\":1", 9);
  455. buff_index += 9;
  456. memcpy((void *)(buff_up + buff_index), (void *)",\"modu\":\"LORA\"", 14);
  457. buff_index += 14;
  458. /* Lora datarate & bandwidth, 16-19 useful chars */
  459. switch (LoraUp.sf) {
  460. case SF6:
  461. memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF6", 12);
  462. buff_index += 12;
  463. break;
  464. case SF7:
  465. memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF7", 12);
  466. buff_index += 12;
  467. break;
  468. case SF8:
  469. memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF8", 12);
  470. buff_index += 12;
  471. break;
  472. case SF9:
  473. memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF9", 12);
  474. buff_index += 12;
  475. break;
  476. case SF10:
  477. memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF10", 13);
  478. buff_index += 13;
  479. break;
  480. case SF11:
  481. memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF11", 13);
  482. buff_index += 13;
  483. break;
  484. case SF12:
  485. memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF12", 13);
  486. buff_index += 13;
  487. break;
  488. default:
  489. memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF?", 12);
  490. buff_index += 12;
  491. }
  492. memcpy((void *)(buff_up + buff_index), (void *)"BW125\"", 6);
  493. buff_index += 6;
  494. memcpy((void *)(buff_up + buff_index), (void *)",\"codr\":\"4/5\"", 13);
  495. buff_index += 13;
  496. j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, ",\"lsnr\":%li", SNR);
  497. buff_index += j;
  498. j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, ",\"rssi\":%d,\"size\":%u", prssi-rssicorr, messageLength);
  499. buff_index += j;
  500. memcpy((void *)(buff_up + buff_index), (void *)",\"data\":\"", 9);
  501. buff_index += 9;
  502. // Use gBase64 library to fill in the data string
  503. encodedLen = base64_enc_len(messageLength); // max 341
  504. j = base64_encode((char *)(buff_up + buff_index), (char *) message, messageLength);
  505. buff_index += j;
  506. buff_up[buff_index] = '"';
  507. ++buff_index;
  508. // End of packet serialization
  509. buff_up[buff_index] = '}';
  510. ++buff_index;
  511. buff_up[buff_index] = ']';
  512. ++buff_index;
  513. // end of JSON datagram payload */
  514. buff_up[buff_index] = '}';
  515. ++buff_index;
  516. buff_up[buff_index] = 0; // add string terminator, for safety
  517. #if STAT_LOG == 1
  518. // Do statistics logging. In first version we might only
  519. // write part of the record to files, later more
  520. addLog( (unsigned char *)(buff_up), buff_index );
  521. #endif
  522. // When we have the node address and the SF, fill the array
  523. // listSeen with the required data. SEENMAX must be >0 for this to happen.
  524. #if _SEENMAX > 0
  525. addSeen(listSeen, statr[0].node, statr[0].sf, now());
  526. #endif
  527. #if _DUSB>=1
  528. if (( debug>=2 ) && ( pdebug & P_RX )) {
  529. Serial.print(F("R RXPK:: "));
  530. Serial.println((char *)(buff_up + 12)); // debug: display JSON payload
  531. Serial.print(F("R RXPK:: package length="));
  532. Serial.println(buff_index);
  533. }
  534. #endif
  535. return(buff_index);
  536. }// buildPacket
  537. // ----------------------------------------------------------------------------
  538. // UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP
  539. // Receive a LoRa package over the air, LoRa and deliver to server(s)
  540. //
  541. // Receive a LoRa message and fill the buff_up char buffer.
  542. // returns values:
  543. // - returns the length of string returned in buff_up
  544. // - returns -1 or -2 when no message arrived, depending connection.
  545. //
  546. // This is the "highlevel" function called by loop()
  547. // ----------------------------------------------------------------------------
  548. int receivePacket()
  549. {
  550. uint8_t buff_up[TX_BUFF_SIZE]; // buffer to compose the upstream packet to backend server
  551. long SNR;
  552. uint8_t message[128] = { 0x00 }; // MSG size is 128 bytes for rx
  553. uint8_t messageLength = 0;
  554. // Regular message received, see SX1276 spec table 18
  555. // Next statement could also be a "while" to combine several messages received
  556. // in one UDP message as the Semtech Gateway spec does allow this.
  557. // XXX Not yet supported
  558. // Take the timestamp as soon as possible, to have accurate reception timestamp
  559. // TODO: tmst can jump if micros() overflow.
  560. uint32_t tmst = (uint32_t) micros(); // Only microseconds, rollover in 5X minutes
  561. //lastTmst = tmst; // Following/according to spec
  562. // Handle the physical data read from LoraUp
  563. if (LoraUp.payLength > 0) {
  564. // externally received packet, so last parameter is false (==LoRa external)
  565. int build_index = buildPacket(tmst, buff_up, LoraUp, false);
  566. // REPEATER is a special function where we retransmit received
  567. // message on _ICHANN to _OCHANN.
  568. // Note:: For the moment _OCHANN is not allowed to be same as _ICHANN
  569. #if _REPEATER==1
  570. if (!sendLora(LoraUp.payLoad, LoraUp.payLength)) {
  571. return(-3);
  572. }
  573. #endif
  574. // This is one of the potential problem areas.
  575. // If possible, USB traffic should be left out of interrupt routines
  576. // rxpk PUSH_DATA received from node is rxpk (*2, par. 3.2)
  577. #ifdef _TTNSERVER
  578. if (!sendUdp(ttnServer, _TTNPORT, buff_up, build_index)) {
  579. return(-1); // received a message
  580. }
  581. yield();
  582. #endif
  583. // Use our own defined server or a second well kon server
  584. #ifdef _THINGSERVER
  585. if (!sendUdp(thingServer, _THINGPORT, buff_up, build_index)) {
  586. return(-2); // received a message
  587. }
  588. #endif
  589. #if _LOCALSERVER==1
  590. // Or special case, we do not use a local server to receive
  591. // and decode the server. We use buildPacket() to call decode
  592. // and use statr[0] information to store decoded message
  593. //DecodePayload: para 4.3.1 of Lora 1.1 Spec
  594. // MHDR
  595. // 1 byte Payload[0]
  596. // FHDR
  597. // 4 byte Dev Addr Payload[1-4]
  598. // 1 byte FCtrl Payload[5]
  599. // 2 bytes FCnt Payload[6-7]
  600. // = Optional 0 to 15 bytes Options
  601. // FPort
  602. // 1 bytes, 0x00 Payload[8]
  603. // ------------
  604. // +=9 BYTES HEADER
  605. //
  606. // FRMPayload
  607. // N bytes (Payload )
  608. //
  609. // 4 bytes MIC trailer
  610. int index=0;
  611. if ((index = inDecodes((char *)(LoraUp.payLoad+1))) >=0 ) {
  612. uint8_t DevAddr[4];
  613. DevAddr[0]= LoraUp.payLoad[4];
  614. DevAddr[1]= LoraUp.payLoad[3];
  615. DevAddr[2]= LoraUp.payLoad[2];
  616. DevAddr[3]= LoraUp.payLoad[1];
  617. uint16_t frameCount=LoraUp.payLoad[7]*256 + LoraUp.payLoad[6];
  618. #if _DUSB>=1
  619. if (( debug>=1 ) && ( pdebug & P_RX )) {
  620. Serial.print(F("R receivePacket:: Ind="));
  621. Serial.print(index);
  622. Serial.print(F(", Len="));
  623. Serial.print(LoraUp.payLength);
  624. Serial.print(F(", A="));
  625. for (int i=0; i<4; i++) {
  626. if (DevAddr[i]<0x0F) Serial.print('0');
  627. Serial.print(DevAddr[i],HEX);
  628. //Serial.print(' ');
  629. }
  630. Serial.print(F(", Msg="));
  631. for (int i=0; (i<statr[0].datal) && (i<23); i++) {
  632. if (statr[0].data[i]<0x0F) Serial.print('0');
  633. Serial.print(statr[0].data[i],HEX);
  634. Serial.print(' ');
  635. }
  636. Serial.println();
  637. }
  638. #endif //DUSB
  639. }
  640. #if _DUSB>=1
  641. else if (( debug>=2 ) && ( pdebug & P_RX )) {
  642. Serial.println(F("receivePacket:: No Index"));
  643. }
  644. #endif //DUSB
  645. #endif // _LOCALSERVER
  646. // Reset the message area
  647. LoraUp.payLength = 0;
  648. LoraUp.payLoad[0] = 0x00;
  649. return(build_index);
  650. }
  651. return(0); // failure no message read
  652. }//receivePacket