_stateMachine.ino 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959
  1. // 1-channel LoRa Gateway for ESP8266
  2. // Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
  3. // Version 6.1.5
  4. // Date: 2019-12-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 state machine code enabling to receive
  19. // and transmit packages/messages.
  20. // ============================================================================================
  21. //
  22. // --------------------------------------------------------------------------------------------
  23. // stateMachine handler of the state machine.
  24. // We use ONE state machine for all kind of interrupts. This assures that we take
  25. // the correct action upon receiving an interrupt.
  26. //
  27. // _event is the software interrupt: If set this function is executed from loop(),
  28. // the function should itself take care of setting or resetting the variable.
  29. //
  30. // STATE MACHINE
  31. // The program uses the following state machine (in _state), all states
  32. // are done in interrupt routine, only the follow-up of S-RXDONE is done
  33. // in the main loop() program. This is because otherwise the interrupt processing
  34. // would take too long to finish
  35. //
  36. // So _state has one of the following state values:
  37. //
  38. // S-INIT=0, The commands in this state are executed only once
  39. // - Goto S_SCAN
  40. //
  41. // S-SCAN, CadScanner() part
  42. // - Upon CDDECT (int1) goto S_RX,
  43. // - upon CDDONE (int0) goto S_CAD, walk through all SF until CDDETD
  44. // - Else stay in SCAN state
  45. //
  46. // S-CAD,
  47. // - Upon CDDECT (int1) goto S_RX,
  48. // - Upon CDDONE (int0) goto S_SCAN, start with SF7 recognition again
  49. //
  50. // S-RX, Received CDDECT so message detected, RX cycle started.
  51. // - Upon RXDONE (int0) package read. If read ok continue to read message
  52. // - upon RXTOUT (int1) error, goto S_SCAN
  53. //
  54. // S-TX Transmitting a message
  55. // - Upon TXDONE goto S_SCAN
  56. //
  57. // S-TXDONE Transmission complete by loop() now again in interrupt
  58. // - Set the Mask
  59. // - reset the Flags
  60. // - Goto either SCAN or RX
  61. //
  62. // This interrupt routine has been kept as simple and short as possible.
  63. // If we receive an interrupt that does not belong to a _state then print error.
  64. // _event is a special variable which indicate that an interrupt event has happened
  65. // and we need to take action OR that we generate a soft interrupt for state machine.
  66. //
  67. // NOTE: We may clear the interrupt but leave the flag for the moment.
  68. // The eventHandler should take care of repairing flags between interrupts.
  69. // --------------------------------------------------------------------------------------------
  70. void stateMachine()
  71. {
  72. // Determine what interrupt flags are set
  73. //
  74. uint8_t flags = readRegister(REG_IRQ_FLAGS);
  75. uint8_t mask = readRegister(REG_IRQ_FLAGS_MASK);
  76. uint8_t intr = flags & ( ~ mask ); // Only react on non masked interrupts
  77. uint8_t rssi;
  78. _event=0; // Reset the interrupt detector
  79. # if _MONITOR>=1
  80. if (intr != flags) {
  81. Serial.print(F("FLAG ::"));
  82. SerialStat(intr);
  83. }
  84. String response = "";
  85. # endif //_MONITOR
  86. // If Hopping is selected AND if there is NO event interrupt detected
  87. // and the state machine is called anyway
  88. // then we know its a soft interrupt and we do nothing and return to main loop.
  89. //
  90. if ((_hop) && (intr == 0x00) )
  91. {
  92. // eventWait is the time since we have had a CDDETD event (preamble detected)
  93. // If we are not in scanning state, and there will be an interrupt coming,
  94. // In state S_RX it could be RXDONE in which case allow kernel time
  95. //
  96. if ((_state == S_SCAN) || (_state == S_CAD)) {
  97. _event=0;
  98. uint32_t eventWait = EVENT_WAIT;
  99. switch (_state) {
  100. case S_INIT: eventWait = 0; break;
  101. // Next two are most important
  102. case S_SCAN: eventWait = EVENT_WAIT * 1; break;
  103. case S_CAD: eventWait = EVENT_WAIT * 1; break;
  104. case S_RX: eventWait = EVENT_WAIT * 8; break;
  105. case S_TX: eventWait = EVENT_WAIT * 1; break;
  106. case S_TXDONE: eventWait = EVENT_WAIT * 4; break;
  107. default:
  108. eventWait=0;
  109. # if _MONITOR>=1
  110. response = "DEFAULT :: ";
  111. mStat(intr, response);
  112. mPrint(response);
  113. # endif //_MONITOR
  114. }
  115. // doneWait is the time that we received CDDONE interrupt
  116. // So we init the wait time for RXDONE based on the current SF.
  117. // As for highter CF it takes longer to receive symbols
  118. // Assume symbols in SF8 take twice the time of SF7
  119. //
  120. uint32_t doneWait = DONE_WAIT; // Initial value
  121. switch (sf) {
  122. case SF7: break;
  123. case SF8: doneWait *= 2; break;
  124. case SF9: doneWait *= 4; break;
  125. case SF10: doneWait *= 8; break;
  126. case SF11: doneWait *= 16; break;
  127. case SF12: doneWait *= 32; break;
  128. default:
  129. doneWait *= 1;
  130. # if _MONITOR>=1
  131. if (( debug>=0 ) && ( pdebug & P_PRE )) {
  132. mPrint("PRE:: DEF set");
  133. }
  134. # endif //_MONITOR
  135. break;
  136. }
  137. // If micros is starting over again after 51 minutes
  138. // it's value is smaller than an earlier value of eventTime/doneTime
  139. //
  140. if (eventTime > micros()) eventTime=micros();
  141. if (doneTime > micros()) doneTime=micros();
  142. if (((micros() - doneTime) > doneWait ) &&
  143. (( _state == S_SCAN ) || ( _state == S_CAD )))
  144. {
  145. _state = S_SCAN;
  146. hop(); // increment ifreq = (ifreq + 1) % NUM_HOPS ;
  147. cadScanner(); // Reset to initial SF, leave frequency "freqs[ifreq]"
  148. # if _MONITOR>=1
  149. if (( debug >= 1 ) && ( pdebug & P_PRE )) {
  150. response = "DONE :: ";
  151. mStat(intr, response);
  152. mPrint(response); // Can move down for timing reasons
  153. }
  154. # endif //_MONITOR
  155. eventTime=micros(); // reset the timer on timeout
  156. doneTime=micros(); // reset the timer on timeout
  157. return;
  158. }
  159. // If timeout occurs and still no _event, then hop
  160. // and start scanning again
  161. //
  162. if ((micros() - eventTime) > eventWait )
  163. {
  164. _state = S_SCAN;
  165. hop(); // increment ifreq = (ifreq + 1) % NUM_HOPS ;
  166. cadScanner(); // Reset to initial SF, leave frequency "freqs[ifreq]"
  167. # if _MONITOR>=1
  168. if (( debug >= 2 ) && ( pdebug & P_PRE )) {
  169. response = "HOP :: ";
  170. mStat(intr, response);
  171. mPrint(response);
  172. }
  173. # endif //_MONITOR
  174. eventTime=micros(); // reset the timer on timeout
  175. doneTime=micros(); // reset the timer on timeout
  176. return;
  177. }
  178. // If we are here, NO timeout has occurred
  179. // So we need to return to the main State Machine
  180. // as there was NO interrupt
  181. # if _MONITOR>=1
  182. if (( debug>=3 ) && ( pdebug & P_PRE )) {
  183. response = "PRE:: eventTime=";
  184. response += String(eventTime);
  185. response += ", micros=";
  186. response += String(micros());
  187. response += ": ";
  188. mStat(intr, response);
  189. mPrint(response);
  190. }
  191. # endif //_MONITOR
  192. } // if SCAN or CAD
  193. // else, S_RX of S_TX for example
  194. else {
  195. //yield(); // May take too much time for RX
  196. } // else S_RX or S_TX, TXDONE
  197. yield();
  198. }// intr==0 && _hop
  199. // ========================================================================================
  200. // This is the actual state machine of the gateway
  201. // and its next actions are depending on the state we are in.
  202. // For hop situations we do not get interrupts, so we have to
  203. // simulate and generate events ourselves.
  204. //
  205. switch (_state)
  206. {
  207. // ----------------------------------------------------------------------------------------
  208. // If the state is init, we are starting up.
  209. // The initLoraModem() function is already called in setup();
  210. //
  211. case S_INIT:
  212. # if _MONITOR>=1
  213. if (( debug>=1 ) && ( pdebug & P_PRE )) {
  214. mPrint("S_INIT");
  215. }
  216. # endif //_MONITOR
  217. // new state, needed to startup the radio (to S_SCAN)
  218. writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF ); // Clear ALL interrupts
  219. writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00 ); // Clear ALL interrupts
  220. _event=0;
  221. break;
  222. // ----------------------------------------------------------------------------------------
  223. // In S_SCAN we measure a high RSSI this means that there (probably) is a message
  224. // coming in at that freq. But not necessarily on the current SF.
  225. // If so find the right SF with CDDETD.
  226. //
  227. case S_SCAN:
  228. //
  229. // Intr==IRQ_LORA_CDDETD_MASK
  230. // We detected a message on this frequency and SF when scanning
  231. // We clear both CDDETD and swich to reading state to read the message
  232. //
  233. if (intr & IRQ_LORA_CDDETD_MASK) {
  234. _state = S_RX; // Set state to receiving
  235. // Set RXDONE interrupt to dio0, RXTOUT to dio1
  236. writeRegister(REG_DIO_MAPPING_1, (
  237. MAP_DIO0_LORA_RXDONE |
  238. MAP_DIO1_LORA_RXTOUT |
  239. MAP_DIO2_LORA_NOP |
  240. MAP_DIO3_LORA_CRC));
  241. // Since new state is S_RX, accept no interrupts except RXDONE or RXTOUT
  242. // HEADER and CRCERR
  243. writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) ~(
  244. IRQ_LORA_RXDONE_MASK |
  245. IRQ_LORA_RXTOUT_MASK |
  246. IRQ_LORA_HEADER_MASK |
  247. IRQ_LORA_CRCERR_MASK));
  248. // Starting with version 5.0.1 the waittime is dependent on the SF
  249. // So for SF12 we wait longer (2^7 == 128 uSec) and for SF7 4 uSec.
  250. //delayMicroseconds( (0x01 << ((uint8_t)sf - 5 )) );
  251. //if (_cad) // XXX 180520 make sure we start reading asap in hop
  252. // delayMicroseconds( RSSI_WAIT ); // Wait some microseconds less
  253. rssi = readRegister(REG_RSSI); // Read the RSSI
  254. _rssi = rssi; // Read the RSSI in the state variable
  255. _event = 0; // Make 0, as soon as we have an interrupt
  256. detTime = micros(); // mark time that preamble detected
  257. # if _MONITOR>=1
  258. if (( debug>=1 ) && ( pdebug & P_SCAN )) {
  259. response = "SCAN:: ";
  260. mStat(intr, response);
  261. mPrint(response);
  262. }
  263. # endif //_MONITOR
  264. writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF ); // reset all interrupt flags
  265. opmode(OPMODE_RX_SINGLE); // set reg 0x01 to 0x06 for receiving
  266. }//if
  267. // CDDONE
  268. // We received a CDDONE int telling us that we received a message on this
  269. // frequency and possibly on one of its SF. Only when the incoming message
  270. // matches the SF then also CDDETD is raised.
  271. // If so, we switch to CAD state where we will wait for CDDETD event.
  272. //
  273. else if (intr & IRQ_LORA_CDDONE_MASK) {
  274. opmode(OPMODE_CAD);
  275. rssi = readRegister(REG_RSSI); // Read the RSSI
  276. # if _MONITOR>=1
  277. if (( debug>=2 ) && ( pdebug & P_SCAN )) {
  278. response = "SCAN:: CDDONE: ";
  279. mStat(intr, response);
  280. mPrint(response);
  281. }
  282. # endif //_MONITOR
  283. // We choose the generic RSSI as a sorting mechanism for packages/messages
  284. // The pRSSI (package RSSI) is calculated upon successful reception of message
  285. // So we expect that this value makes little sense for the moment with CDDONE.
  286. // Set the rssi as low as the noise floor. Lower values are not recognized then.
  287. // Every cycle starts with ifreq==0 and sf=SF7 (or the set init SF)
  288. //
  289. if ( rssi > (RSSI_LIMIT - (_hop * 7))) // Is set to 35, or 29 for HOP
  290. {
  291. # if _MONITOR>=1
  292. if (( debug>=2 ) && ( pdebug & P_SCAN )) {
  293. response = "SCAN:: -> CAD: ";
  294. mStat(intr, response);
  295. mPrint(response);
  296. }
  297. # endif //_MONITOR
  298. _state = S_CAD; // promote to next level
  299. _event=0;
  300. }
  301. // If the RSSI is not big enough we skip the CDDONE
  302. // and go back to scanning
  303. else {
  304. # if _MONITOR>=1
  305. if (( debug>=2 ) && ( pdebug & P_SCAN )) {
  306. response = "SCAN:: rssi=";
  307. response += String(rssi);
  308. response += ": ";
  309. mStat(intr, response);
  310. mPrint(response);
  311. }
  312. # endif //_MONITOR
  313. _state = S_SCAN;
  314. }
  315. // Clear the CADDONE flag
  316. writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);
  317. writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);
  318. doneTime = micros(); // Need CDDONE or other intr to reset timeout
  319. }//SCAN CDDONE
  320. // So if we are here then we are in S_SCAN and the interrupt is not
  321. // CDDECT or CDDONE. it is probably soft interrupt _event==1
  322. // So if _hop we change the frequency and restart the
  323. // interrupt in order to check for CDONE on other frequencies
  324. // if _hop we start at the next frequency, hop () sets the sf to SF7.
  325. // If we are at the end of all frequencies, reset frequencies and sf
  326. // and go to S_SCAN state.
  327. //
  328. // Note:: We should make sure that all frequencies are scanned in a row
  329. // and when we switch to ifreq==0 we should stop for a while
  330. // to allow system processing.
  331. // We should make sure that we enable webserver etc every once in a while.
  332. // We do this by changing _event to 1 in loop() only for _hop and
  333. // use _event=0 for non hop.
  334. //
  335. else if (intr == 0x00)
  336. {
  337. _event=0; // XXX 26/12/2017 !!! NEED
  338. }
  339. // Unkown Interrupt, so we have an error
  340. //
  341. else {
  342. # if _MONITOR>=1
  343. if (( debug>=0 ) && ( pdebug & P_SCAN )) {
  344. response = "SCAN unknown:: ";
  345. mStat(intr, response);
  346. mPrint(response);
  347. }
  348. # endif //_MONITOR
  349. _state=S_SCAN;
  350. //_event=1; // XXX 06/03 loop until interrupt
  351. writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);
  352. writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);
  353. }
  354. break; // S_SCAN
  355. // ----------------------------------------------------------------------------------------
  356. // S_CAD: In CAD mode we scan every SF for high RSSI until we have a DETECT.
  357. // Reason is the we received a CADDONE interrupt so we know a message is received
  358. // on the frequency but may be on another SF.
  359. //
  360. // If message is of the right frequency and SF, IRQ_LORA_CDDETD_MSAK interrupt
  361. // is raised, indicating that we can start beging reading the message from SPI.
  362. //
  363. // DIO0 interrupt IRQ_LORA_CDDONE_MASK in state S_CAD==2 means that we might have
  364. // a lock on the Freq but not the right SF. So we increase the SF
  365. //
  366. case S_CAD:
  367. // Intr=IRQ_LORA_CDDETD_MASK
  368. // We have to set the sf based on a strong RSSI for this channel
  369. // Also we set the state to S_RX and start receiving the message
  370. //
  371. if (intr & IRQ_LORA_CDDETD_MASK) {
  372. // Set RXDONE interrupt to dio0, RXTOUT to dio1
  373. writeRegister(REG_DIO_MAPPING_1, (
  374. MAP_DIO0_LORA_RXDONE |
  375. MAP_DIO1_LORA_RXTOUT |
  376. MAP_DIO2_LORA_NOP |
  377. MAP_DIO3_LORA_CRC ));
  378. // Accept no interrupts except RXDONE or RXTOUT
  379. _event=0;
  380. // if CDECT, make state S_RX so we wait for RXDONE intr
  381. writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) ~(
  382. IRQ_LORA_RXDONE_MASK |
  383. IRQ_LORA_RXTOUT_MASK |
  384. IRQ_LORA_HEADER_MASK |
  385. IRQ_LORA_CRCERR_MASK ));
  386. // Reset all interrupts as soon as possible
  387. // But listen ONLY to RXDONE and RXTOUT interrupts
  388. //writeRegister(REG_IRQ_FLAGS, IRQ_LORA_CDDETD_MASK | IRQ_LORA_RXDONE_MASK);
  389. // If we want to reset CRC, HEADER and RXTOUT flags as well
  390. writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF ); // XXX 180326, reset all CAD Detect interrupt flags
  391. //_state = S_RX; // XXX 180521 Set state to start receiving
  392. opmode(OPMODE_RX_SINGLE); // set reg 0x01 to 0x06, initiate READ
  393. delayMicroseconds( RSSI_WAIT ); // Wait some microseconds less
  394. //delayMicroseconds( (0x01 << ((uint8_t)sf - 5 )) );
  395. rssi = readRegister(REG_RSSI); // Read the RSSI
  396. _rssi = rssi; // Read the RSSI in the state variable
  397. detTime = micros();
  398. # if _MONITOR>=1
  399. if (( debug>=1 ) && ( pdebug & P_CAD )) {
  400. response = "CAD:: ";
  401. mStat(intr, response);
  402. mPrint(response);
  403. }
  404. # endif //_MONITOR
  405. _state = S_RX; // Set state to start receiving
  406. }// CDDETD
  407. // Intr == CADDONE
  408. // So we scan this SF and if not high enough ... next
  409. //
  410. else if (intr & IRQ_LORA_CDDONE_MASK) {
  411. // If this is not the max SF, increment the SF and try again
  412. // Depending on the frequency scheme this is for example SF8, SF10 or SF12
  413. // We expect on other SF get CDDETD
  414. //
  415. if (((uint8_t)sf) < freqs[ifreq].upHi) {
  416. sf = (sf_t)((uint8_t)sf+1); // Increment sf
  417. setRate(sf, 0x04); // Set SF with CRC==on
  418. // reset interrupt flags for CAD Done
  419. _event=0; // XXX 180324, when increasing SF loop, ws 0x00
  420. writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00); // Reset the interrupt mask
  421. //writeRegister(REG_IRQ_FLAGS, IRQ_LORA_CDDONE_MASK | IRQ_LORA_CDDETD_MASK);
  422. writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF ); // This will prevent the CDDETD from being read
  423. opmode(OPMODE_CAD); // Scanning mode
  424. delayMicroseconds(RSSI_WAIT);
  425. rssi = readRegister(REG_RSSI); // Read the RSSI
  426. # if _MONITOR>=1
  427. if (( debug>=3 ) && ( pdebug & P_CAD )) {
  428. mPrint("S_CAD:: CDONE, SF=" + String(sf) );
  429. }
  430. # endif //_MONIYOT
  431. }
  432. // If we reach the highest SF for the frequency plan,
  433. // we should go back to SCAN state
  434. //
  435. else {
  436. // Reset Interrupts
  437. _event=1; // reset soft intr, to state machine again
  438. writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00); // Reset the interrupt mask
  439. writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF ); // or IRQ_LORA_CDDONE_MASK
  440. _state = S_SCAN; // As soon as we reach SF12 do something
  441. sf = (sf_t) freqs[ifreq].upLo;
  442. cadScanner(); // Which will reset SF to lowest SF
  443. # if _MONITOR>=1
  444. if (( debug>=3 ) && ( pdebug & P_CAD )) {
  445. mPrint("CAD->SCAN:: " + String(intr) );
  446. }
  447. # endif //_MONITOR
  448. }
  449. doneTime = micros(); // We need CDDONE or other intr to reset timeout
  450. } //CAD CDDONE
  451. // if this interrupt is not CDECT or CDDONE then probably is 0x00
  452. // This means _event was set but there was no real interrupt (yet).
  453. // So we clear _event and wait for next (soft) interrupt.
  454. // We stay in the CAD state because CDDONE means something is
  455. // coming on this frequency so we wait on CDECT.
  456. //
  457. else if (intr == 0x00) {
  458. # if _MONITOR>=1
  459. if (( debug>=3 ) && ( pdebug & P_CAD )) {
  460. mPrint ("CAD:: intr is 0x00");
  461. }
  462. # endif //_MONITOR
  463. _event=1; // Stay in CAD _state until real interrupt
  464. }
  465. // else we do not recognize the interrupt. We print an error
  466. // and restart scanning. If hop we even start at ifreq==1
  467. //
  468. else {
  469. # if _MONITOR>=1
  470. if (( debug>=0) && ( pdebug & P_CAD )) {
  471. mPrint("Err CAD: Unknown::" + String(intr) );
  472. }
  473. # endif //_MONITOR
  474. _state = S_SCAN;
  475. sf = SF7;
  476. cadScanner(); // Scan and set SF7
  477. // Reset Interrupts
  478. _event=1; // If unknown interrupt, restarts
  479. writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00); // Reset the interrupt mask
  480. writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF); // Reset all interrupts
  481. }
  482. break; //S_CAD
  483. // ----------------------------------------------------------------------------------------
  484. // If we receive an RXDONE interrupt on dio0 with state==S_RX
  485. // So we should handle the received message
  486. // Else if it is RXTOUT interrupt
  487. // Timeout, so we handle this interrupt, and get modem out of standby
  488. // Else
  489. // Go back to SCAN
  490. //
  491. case S_RX:
  492. if (intr & IRQ_LORA_RXDONE_MASK) {
  493. # if _CRCCHECK>=1
  494. // We have to check for CRC error which will be visible AFTER RXDONE is set.
  495. // CRC errors might indicate that the reception is not OK.
  496. // Could be CRC error or message too large.
  497. // CRC error checking requires DIO3
  498. //
  499. if (intr & IRQ_LORA_CRCERR_MASK) {
  500. # if _MONITOR>=1
  501. if (( debug>=0 ) && ( pdebug & P_RX )) {
  502. Serial.print(F("Rx CRC err: "));
  503. SerialStat(intr);
  504. }
  505. # endif //_MONITOR
  506. if ((_cad) || (_hop)) {
  507. sf = SF7;
  508. _state = S_SCAN;
  509. cadScanner();
  510. }
  511. else {
  512. _state = S_RX;
  513. rxLoraModem();
  514. }
  515. // Reset interrupts
  516. _event=0; // CRC error
  517. writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00); // Reset the interrupt mask
  518. writeRegister(REG_IRQ_FLAGS, (uint8_t)(
  519. IRQ_LORA_RXDONE_MASK |
  520. IRQ_LORA_RXTOUT_MASK |
  521. IRQ_LORA_HEADER_MASK |
  522. IRQ_LORA_CRCERR_MASK ));
  523. break; // Get out of loop
  524. }// RX-CRC mask
  525. # endif //_CRCCHECK
  526. // If we are here, no CRC error occurred, start timer
  527. # if _DUSB>=1 || _MONITOR>=1
  528. unsigned long ffTime = micros();
  529. # endif
  530. // There should not be an error in the message
  531. LoraUp.payLoad[0]= 0x00; // Empty the message
  532. // If receive S_RX error,
  533. // - print Error message
  534. // - Set _state to SCAN
  535. // - Set _event=1 so that we loop until we have an interrupt
  536. // - Reset the interrupts
  537. // - break
  538. // NOTE: receivePacket also increases .ok0 - .ok2 counter
  539. if((LoraUp.payLength = receivePkt(LoraUp.payLoad)) <= 0) {
  540. # if _MONITOR>=1
  541. if (( debug>=1 ) && ( pdebug & P_RX )) {
  542. response += "sMachine:: Error S-RX: payLenth=";
  543. response += String(LoraUp.payLength);
  544. mPrint(response);
  545. }
  546. # endif //_MONITOR
  547. _event=1;
  548. writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00); // Reset the interrupt mask
  549. writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);
  550. _state = S_SCAN;
  551. break;
  552. }
  553. # if _MONITOR>=1
  554. if ((pdebug & P_RX) && (debug >= 2)) {
  555. response = "RXDONE:: dT=";
  556. response += String(ffTime - detTime);
  557. mStat(intr, response);
  558. mPrint(response);
  559. }
  560. # endif //_MONITOR
  561. // Do all register processing in this section
  562. uint8_t value = readRegister(REG_PKT_SNR_VALUE); // 0x19;
  563. if ( value & 0x80 ) { // The SNR sign bit is 1
  564. value = ( ( ~value + 1 ) & 0xFF ) >> 2; // Invert and divide by 4
  565. LoraUp.snr = -value;
  566. }
  567. else {
  568. // Divide by 4
  569. LoraUp.snr = ( value & 0xFF ) >> 2;
  570. }
  571. // Packet RSSI
  572. LoraUp.prssi = readRegister(REG_PKT_RSSI); // read register 0x1A, packet rssi
  573. // Correction of RSSI value based on chip used.
  574. if (sx1272) { // Is it a sx1272 radio?
  575. LoraUp.rssicorr = 139;
  576. } else { // Probably SX1276 or RFM95
  577. LoraUp.rssicorr = 157;
  578. }
  579. LoraUp.sf = readRegister(REG_MODEM_CONFIG2) >> 4;
  580. // If read was successful, read the package from the LoRa bus
  581. //
  582. if (receivePacket() <= 0) { // read is not successful
  583. # if _MONITOR>=1
  584. if (( debug>=0 ) && ( pdebug & P_RX )) {
  585. mPrint("sMach:: Error receivePacket");
  586. }
  587. # endif //_MONITOR
  588. }
  589. // Set the modem to receiving BEFORE going back to user space.
  590. //
  591. if ((_cad) || (_hop)) {
  592. _state = S_SCAN;
  593. sf = SF7;
  594. cadScanner();
  595. }
  596. else {
  597. _state = S_RX;
  598. rxLoraModem();
  599. }
  600. writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);
  601. writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF); // Reset the interrupt mask
  602. eventTime=micros(); // There was an event for receive
  603. _event=0;
  604. }// RXDONE
  605. // RXOUT:
  606. // We did receive message receive timeout
  607. // This is the most common event in hop mode, possibly due to the fact
  608. // that receiving has started too late in the middle of a message
  609. // (according to the documentation). So is there a way to start receiving
  610. // immediately without delay.
  611. //
  612. else if (intr & IRQ_LORA_RXTOUT_MASK) {
  613. // Make sure we reset all interrupts
  614. // and get back to scanning
  615. _event=0; // Is set by interrupt handlers
  616. writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00 );
  617. writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF); // reset all interrupts
  618. // If RXTOUT we put the modem in cad state and reset to SF7
  619. // If a timeout occurs here we reset the cadscanner
  620. //
  621. if ((_cad) || (_hop)) {
  622. // Set the state to CAD scanning
  623. # if _MONITOR>=1
  624. if (( debug>=2 ) && ( pdebug & P_RX )) {
  625. response = "RXTOUT:: ";
  626. mStat(intr, response);
  627. mPrint(response);
  628. }
  629. # endif //_MONITOR
  630. sf = SF7;
  631. cadScanner(); // Start the scanner after RXTOUT
  632. _state = S_SCAN; // New state is scan
  633. }
  634. // If not in cad mode we are in single channel single sf mode.
  635. //
  636. else {
  637. _state = S_RX; // Receive when interrupted
  638. rxLoraModem();
  639. }
  640. eventTime=micros(); //There was an event for receive
  641. doneTime = micros(); // We need CDDONE or other intr to reset timeout
  642. }// RXTOUT
  643. else if (intr & IRQ_LORA_HEADER_MASK) {
  644. // This interrupt means we received an header successfully
  645. // which is normall an indication of RXDONE
  646. //writeRegister(REG_IRQ_FLAGS, IRQ_LORA_HEADER_MASK);
  647. # if _MONITOR>=1
  648. if (( debug>=3 ) && ( pdebug & P_RX )) {
  649. mPrint("RX HEADER:: " + String(intr));
  650. }
  651. # endif //_MONITOR
  652. //_event=1;
  653. }
  654. // If we did not receive a hard interrupt
  655. // Then probably do not do anything, because in the S_RX
  656. // state there always comes a RXTOUT or RXDONE interrupt
  657. //
  658. else if (intr == 0x00) {
  659. # if _MONITOR>=1
  660. if (( debug>=3) && ( pdebug & P_RX )) {
  661. mPrint("S_RX no INTR:: " + String(intr));
  662. }
  663. # endif //_MONITOR
  664. }
  665. // The interrupt received is not RXDONE, RXTOUT or HEADER
  666. // therefore we wait. Make sure to clear the interrupt
  667. // as HEADER interrupt comes just before RXDONE
  668. else {
  669. # if _MONITOR>=1
  670. if (( debug>=0 ) && ( pdebug & P_RX )) {
  671. mPrint("R S_RX:: no RXDONE, RXTOUT, HEADER:: " + String(intr));
  672. }
  673. # endif //_MONITOR
  674. //writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00 );
  675. //writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);
  676. }// int not RXDONE or RXTOUT
  677. break; // S_RX
  678. // ----------------------------------------------------------------------------------------
  679. // Start the transmission of a message in state S-TX
  680. // This is not an interrupt state, we use this state to start transmission
  681. // the interrupt TX-DONE tells us that the transmission was successful.
  682. // It therefore is no use to set _event==1 as transmission might
  683. // not be finished in the next loop iteration
  684. //
  685. case S_TX:
  686. // We need a timeout for this case. In case there does not come an interrupt,
  687. // then there will nog be a TXDONE but probably another CDDONE/CDDETD before
  688. // we have a timeout in the main program (Keep Alive)
  689. if (intr == 0x00) {
  690. # if _MONITOR>=1
  691. if (( debug>=2 ) && ( pdebug & P_TX )) {
  692. mPrint("TX:: 0x00");
  693. }
  694. # endif //_MONITOR
  695. _event=1;
  696. _state=S_TXDONE;
  697. }
  698. // Set state to transmit
  699. _state = S_TXDONE;
  700. // Clear interrupt flags and masks
  701. writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);
  702. writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF); // reset interrupt flags
  703. // Initiate the transmission of the buffer (in Interrupt space)
  704. // We react on ALL interrupts if we are in TX state.
  705. txLoraModem(
  706. LoraDown.payLoad,
  707. LoraDown.payLength,
  708. LoraDown.tmst,
  709. LoraDown.sfTx,
  710. LoraDown.powe,
  711. LoraDown.fff,
  712. LoraDown.crc,
  713. LoraDown.iiq
  714. );
  715. // After filling the buffer we only react on TXDONE interrupt
  716. # if _MONITOR>=1
  717. if (( debug>=1 ) && ( pdebug & P_TX )) {
  718. mPrint("TX done:: " + String(intr) );
  719. }
  720. # endif //_MONITOR
  721. // More or less start at the "case TXDONE:" below
  722. _state=S_TXDONE;
  723. _event=1; // Or remove the break below
  724. break; // S_TX
  725. // ----------------------------------------------------------------------------------------
  726. // After the transmission is completed by the hardware,
  727. // the interrupt TXDONE is raised telling us that the tranmission
  728. // was successful.
  729. // If we receive an interrupt on dio0 _state==S_TX it is a TxDone interrupt
  730. // Do nothing with the interrupt, it is just an indication.
  731. // send Packet switch back to scanner mode after transmission finished OK
  732. //
  733. case S_TXDONE:
  734. if (intr & IRQ_LORA_TXDONE_MASK) {
  735. # if _MONITOR>=1
  736. if (( debug>=0 ) && ( pdebug & P_TX )) {
  737. response = "T TXDONE:: rcvd=" + String(micros());
  738. response += ", diff=" + String(micros()-LoraDown.tmst);
  739. mPrint(response);
  740. }
  741. # endif
  742. # if _MONITOR>=2
  743. if (pdebug & P_TX) {
  744. response = "T TXDONE:: rcvd=" + micros();
  745. response += ", diff=" + String(micros()-LoraDown.tmst);
  746. mPrint(response);
  747. }
  748. # endif
  749. // After transmission reset to receiver
  750. if ((_cad) || (_hop)) { // XXX 26/02
  751. // Set the state to CAD scanning
  752. _state = S_SCAN;
  753. sf = SF7;
  754. cadScanner(); // Start the scanner after TX cycle
  755. }
  756. else {
  757. _state = S_RX;
  758. rxLoraModem();
  759. }
  760. _event=0;
  761. writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);
  762. writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF); // reset interrupt flags
  763. # if _MONITOR>=1
  764. if (( debug>=1 ) && ( pdebug & P_TX )) {
  765. mPrint("T TXDONE:: done OK");
  766. }
  767. # endif //_MONITOR
  768. }
  769. // If a soft _event==0 interrupt and no transmission finished:
  770. else if ( intr != 0 ) {
  771. # if _MONITOR>=1
  772. if (( debug>=0 ) && ( pdebug & P_TX )) {
  773. response = "TXDONE:: unknown int:";
  774. mStat(intr, response);
  775. mPrint(response);
  776. } //_MONITOR
  777. # endif
  778. writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);
  779. writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF); // reset interrupt flags
  780. _event=0;
  781. _state=S_SCAN;
  782. }
  783. // intr == 0
  784. else {
  785. // Increase timer. If timer exceeds certain value (7 seconds!), reset
  786. // After sending a message with S_TX, we have to receive a TXDONE interrupt
  787. // within 7 seconds according to spec, of here is a problem.
  788. if ( sendTime > micros() ) sendTime = 0; // This could be omitted for usigned ints
  789. if (( _state == S_TXDONE ) && (( micros() - sendTime) > 7000000 )) {
  790. # if _MONITOR>=1
  791. if (( debug>=1 ) && ( pdebug & P_TX )) {
  792. mPrint("TXDONE:: reset TX");
  793. }
  794. # endif //_MONITOR
  795. startReceiver();
  796. }
  797. # if _MONITOR>=1
  798. if (( debug>=3 ) && ( pdebug & P_TX )) {
  799. mPrint("T TXDONE:: No Interrupt");
  800. }
  801. # endif //_MONITOR
  802. }
  803. break; // S_TXDONE
  804. // ----------------------------------------------------------------------------------------
  805. // If _STATE is in an undefined state
  806. // If such a thing happens, we should re-init the interface and
  807. // make sure that we pick up next interrupt
  808. default:
  809. # if _MONITOR>=1
  810. if (( debug>=0) && ( pdebug & P_PRE )) {
  811. mPrint("ERR state=" + String(_state));
  812. }
  813. # endif //_MONITOR
  814. if ((_cad) || (_hop)) {
  815. # if _MONITOR>=1
  816. if (debug>=0) {
  817. response = "default:: Unknown _state ";
  818. mStat(intr, response);
  819. mPrint(response);
  820. }
  821. # endif //_MONITOR
  822. _state = S_SCAN;
  823. sf = SF7;
  824. cadScanner(); // Restart the state machine
  825. _event=0;
  826. }
  827. else // Single channel AND single SF
  828. {
  829. _state = S_RX;
  830. rxLoraModem();
  831. _event=0;
  832. }
  833. writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);
  834. writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF); // Reset all interrupts
  835. eventTime=micros(); // Reset event for unkonwn state
  836. break;// default
  837. }// switch(_state)
  838. return;
  839. }