_loraFiles.ino 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  1. // 1-channel LoRa Gateway for ESP8266
  2. // Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
  3. // Version 6.1.1
  4. // Date: 2019-11-06
  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 filesystem specific code
  19. // ============================================================================
  20. // LORA SPIFFS FILESYSTEM FUNCTIONS
  21. //
  22. // The LoRa supporting functions are in the section below
  23. // ----------------------------------------------------------------------------
  24. // Supporting function to readConfig
  25. // ----------------------------------------------------------------------------
  26. void id_print (String id, String val) {
  27. #if _DUSB>=1
  28. if (( debug>=0 ) && ( pdebug & P_MAIN )) {
  29. Serial.print(id);
  30. Serial.print(F("=\t"));
  31. Serial.println(val);
  32. }
  33. #endif
  34. }
  35. // ----------------------------------------------------------------------------
  36. // INITCONFIG; Init the gateway configuration file
  37. // Espcecially when calling SPIFFS.format() the gateway is left in an init
  38. // which is not very well defined. This function will init some of the settings
  39. // to well known settings.
  40. // ----------------------------------------------------------------------------
  41. int initConfig(struct espGwayConfig *c) {
  42. (*c).ch = 0;
  43. (*c).sf = _SPREADING;
  44. (*c).debug = 1;
  45. (*c).pdebug = P_GUI;
  46. (*c).cad = _CAD;
  47. (*c).hop = false;
  48. (*c).expert = false;
  49. (*c).txDelay = 0; // First Value without saving is 0;
  50. }
  51. // ----------------------------------------------------------------------------
  52. // Read the gateway configuration file
  53. // ----------------------------------------------------------------------------
  54. int readConfig(const char *fn, struct espGwayConfig *c) {
  55. int tries = 0;
  56. #if _DUSB>=1
  57. Serial.println(F("readConfig:: Starting "));
  58. #endif
  59. if (!SPIFFS.exists(fn)) {
  60. #if _DUSB>=1
  61. Serial.print(F("readConfig ERR:: file="));
  62. Serial.print(fn);
  63. Serial.println(F(" does not exist .. Formatting"));
  64. #endif
  65. SPIFFS.format();
  66. initConfig(c); // If we cannot read teh config, at least init known values
  67. return(-1);
  68. }
  69. File f = SPIFFS.open(fn, "r");
  70. if (!f) {
  71. #if _DUSB>=1
  72. Serial.println(F("ERROR:: SPIFFS open failed"));
  73. #endif
  74. return(-1);
  75. }
  76. while (f.available()) {
  77. #if _DUSB>=1
  78. if (( debug>=0 ) && ( pdebug & P_MAIN )) {
  79. Serial.print('.');
  80. }
  81. #endif
  82. // If we wait for more than 10 times, reformat the filesystem
  83. // We do this so that the system will be responsive (over OTA for example).
  84. //
  85. if (tries >= 10) {
  86. f.close();
  87. #if _DUSB>=1
  88. if (( debug>=0 ) && ( pdebug & P_MAIN ))
  89. Serial.println(F("Formatting"));
  90. #endif
  91. SPIFFS.format();
  92. initConfig(c);
  93. f = SPIFFS.open(fn, "r");
  94. tries = 0;
  95. }
  96. String id =f.readStringUntil('='); // Read keyword until '=', C++ thing
  97. String val=f.readStringUntil('\n'); // Read value until End of Line (EOL)
  98. #if _DUSB>=2
  99. Serial.print(F("readConfig:: reading line="));
  100. Serial.print(id);
  101. Serial.print(F("="));
  102. Serial.print(val);
  103. Serial.println();
  104. #endif
  105. if (id == "SSID") { // WiFi SSID
  106. id_print(id, val);
  107. (*c).ssid = val; // val contains ssid, we do NO check
  108. }
  109. else if (id == "PASS") { // WiFi Password
  110. id_print(id, val);
  111. (*c).pass = val;
  112. }
  113. else if (id == "CH") { // Frequency Channel
  114. id_print(id,val);
  115. (*c).ch = (uint32_t) val.toInt();
  116. }
  117. else if (id == "SF") { // Spreading Factor
  118. id_print(id, val);
  119. (*c).sf = (uint32_t) val.toInt();
  120. }
  121. else if (id == "FCNT") { // Frame Counter
  122. id_print(id, val);
  123. (*c).fcnt = (uint32_t) val.toInt();
  124. }
  125. else if (id == "DEBUG") { // Debug Level
  126. id_print(id, val);
  127. (*c).debug = (uint8_t) val.toInt();
  128. }
  129. else if (id == "PDEBUG") { // pDebug Pattern
  130. Serial.print(F("PDEBUG=")); Serial.println(val);
  131. (*c).pdebug = (uint8_t) val.toInt();
  132. }
  133. else if (id == "CAD") { // CAD setting
  134. Serial.print(F("CAD=")); Serial.println(val);
  135. (*c).cad = (uint8_t) val.toInt();
  136. }
  137. else if (id == "HOP") { // HOP setting
  138. Serial.print(F("HOP=")); Serial.println(val);
  139. (*c).hop = (uint8_t) val.toInt();
  140. }
  141. else if (id == "BOOTS") { // BOOTS setting
  142. id_print(id, val);
  143. (*c).boots = (uint8_t) val.toInt();
  144. }
  145. else if (id == "RESETS") { // RESET setting
  146. id_print(id, val);
  147. (*c).resets = (uint8_t) val.toInt();
  148. }
  149. else if (id == "WIFIS") { // WIFIS setting
  150. id_print(id, val);
  151. (*c).wifis = (uint8_t) val.toInt();
  152. }
  153. else if (id == "VIEWS") { // VIEWS setting
  154. id_print(id, val);
  155. (*c).views = (uint8_t) val.toInt();
  156. }
  157. else if (id == "NODE") { // NODE setting
  158. id_print(id, val);
  159. (*c).isNode = (uint8_t) val.toInt();
  160. }
  161. else if (id == "REFR") { // REFR setting
  162. id_print(id, val);
  163. (*c).refresh = (uint8_t) val.toInt();
  164. }
  165. else if (id == "REENTS") { // REENTS setting
  166. id_print(id, val);
  167. (*c).reents = (uint8_t) val.toInt();
  168. }
  169. else if (id == "NTPERR") { // NTPERR setting
  170. id_print(id, val);
  171. (*c).ntpErr = (uint8_t) val.toInt();
  172. }
  173. else if (id == "NTPETIM") { // NTPERR setting
  174. id_print(id, val);
  175. (*c).ntpErrTime = (uint32_t) val.toInt();
  176. }
  177. else if (id == "NTPS") { // NTPS setting
  178. id_print(id, val);
  179. (*c).ntps = (uint8_t) val.toInt();
  180. }
  181. else if (id == "FILENO") { // FILENO setting
  182. id_print(id, val);
  183. (*c).logFileNo = (uint8_t) val.toInt();
  184. }
  185. else if (id == "FILEREC") { // FILEREC setting
  186. id_print(id, val);
  187. (*c).logFileRec = (uint16_t) val.toInt();
  188. }
  189. else if (id == "FILENUM") { // FILEREC setting
  190. id_print(id, val);
  191. (*c).logFileNum = (uint16_t) val.toInt();
  192. }
  193. else if (id == "EXPERT") { // EXPERT setting
  194. id_print(id, val);
  195. (*c).expert = (uint8_t) val.toInt();
  196. }
  197. else if (id == "DELAY") { // DELAY setting
  198. id_print(id, val);
  199. (*c).txDelay = (int32_t) val.toInt();
  200. }
  201. else {
  202. #if _DUSB>=1
  203. Serial.print(F("readConfig:: tries++"));
  204. #endif
  205. tries++;
  206. }
  207. }
  208. f.close();
  209. #if _DUSB>=1
  210. if (debug>=0) {
  211. Serial.println(F("readConfig:: Fini"));
  212. }
  213. #endif
  214. Serial.println();
  215. return(1);
  216. }//readConfig
  217. // ----------------------------------------------------------------------------
  218. // Write the current gateway configuration to SPIFFS. First copy all the
  219. // separate data items to the gwayConfig structure
  220. //
  221. // Note: gwayConfig.expert contains the expert setting already
  222. // gwayConfig.txDelay
  223. // ----------------------------------------------------------------------------
  224. int writeGwayCfg(const char *fn) {
  225. gwayConfig.ssid = WiFi.SSID();
  226. gwayConfig.pass = WiFi.psk(); // XXX We should find a way to store the password too
  227. gwayConfig.ch = ifreq; // Frequency Index
  228. gwayConfig.sf = (uint8_t) sf; // Spreading Factor
  229. gwayConfig.debug = debug;
  230. gwayConfig.pdebug = pdebug;
  231. gwayConfig.cad = _cad;
  232. gwayConfig.hop = _hop;
  233. #if GATEWAYNODE==1
  234. gwayConfig.fcnt = frameCount;
  235. #endif
  236. return(writeConfig(fn, &gwayConfig));
  237. }
  238. // ----------------------------------------------------------------------------
  239. // Write the configuration as found in the espGwayConfig structure
  240. // to SPIFFS
  241. // Parameters:
  242. // fn; Filename
  243. // c; struct config
  244. // Returns:
  245. // 1 when successful, -1 on error
  246. // ----------------------------------------------------------------------------
  247. int writeConfig(const char *fn, struct espGwayConfig *c) {
  248. if (!SPIFFS.exists(fn)) {
  249. Serial.print("WARNING:: writeConfig, file not exists, formatting ");
  250. SPIFFS.format();
  251. initConfig(c); // XXX make all initial declarations here if config vars need to have a value
  252. Serial.println(fn);
  253. }
  254. File f = SPIFFS.open(fn, "w");
  255. if (!f) {
  256. Serial.print("ERROR:: writeConfig, open file=");
  257. Serial.print(fn);
  258. Serial.println();
  259. return(-1);
  260. }
  261. f.print("SSID"); f.print('='); f.print((*c).ssid); f.print('\n');
  262. f.print("PASS"); f.print('='); f.print((*c).pass); f.print('\n');
  263. f.print("CH"); f.print('='); f.print((*c).ch); f.print('\n');
  264. f.print("SF"); f.print('='); f.print((*c).sf); f.print('\n');
  265. f.print("FCNT"); f.print('='); f.print((*c).fcnt); f.print('\n');
  266. f.print("DEBUG"); f.print('='); f.print((*c).debug); f.print('\n');
  267. f.print("PDEBUG"); f.print('='); f.print((*c).pdebug); f.print('\n');
  268. f.print("CAD"); f.print('='); f.print((*c).cad); f.print('\n');
  269. f.print("HOP"); f.print('='); f.print((*c).hop); f.print('\n');
  270. f.print("NODE"); f.print('='); f.print((*c).isNode); f.print('\n');
  271. f.print("BOOTS"); f.print('='); f.print((*c).boots); f.print('\n');
  272. f.print("RESETS"); f.print('='); f.print((*c).resets); f.print('\n');
  273. f.print("WIFIS"); f.print('='); f.print((*c).wifis); f.print('\n');
  274. f.print("VIEWS"); f.print('='); f.print((*c).views); f.print('\n');
  275. f.print("REFR"); f.print('='); f.print((*c).refresh); f.print('\n');
  276. f.print("REENTS"); f.print('='); f.print((*c).reents); f.print('\n');
  277. f.print("NTPETIM"); f.print('='); f.print((*c).ntpErrTime); f.print('\n');
  278. f.print("NTPERR"); f.print('='); f.print((*c).ntpErr); f.print('\n');
  279. f.print("NTPS"); f.print('='); f.print((*c).ntps); f.print('\n');
  280. f.print("FILEREC"); f.print('='); f.print((*c).logFileRec); f.print('\n');
  281. f.print("FILENO"); f.print('='); f.print((*c).logFileNo); f.print('\n');
  282. f.print("FILENUM"); f.print('='); f.print((*c).logFileNum); f.print('\n');
  283. f.print("DELAY"); f.print('='); f.print((*c).txDelay); f.print('\n');
  284. f.print("EXPERT"); f.print('='); f.print((*c).expert); f.print('\n');
  285. f.close();
  286. return(1);
  287. }
  288. // ----------------------------------------------------------------------------
  289. // Add a line with statistics to the log.
  290. //
  291. // We put the check in the function to protect against calling
  292. // the function without STAT_LOG being proper defined
  293. // ToDo: Store the fileNo and the fileRec in the status file to save for
  294. // restarts
  295. // Parameters:
  296. // line; char array with characters to write to log
  297. // cnt;
  298. // Returns:
  299. // <none>
  300. // ----------------------------------------------------------------------------
  301. int addLog(const unsigned char * line, int cnt)
  302. {
  303. #if STAT_LOG==1
  304. char fn[16];
  305. if (gwayConfig.logFileRec > LOGFILEREC) { // Have to make define for this
  306. gwayConfig.logFileRec = 0; // In new logFile start with record 0
  307. gwayConfig.logFileNo++; // Increase file ID
  308. gwayConfig.logFileNum++; // Increase number of log files
  309. }
  310. gwayConfig.logFileRec++;
  311. // If we have too many logfies, delete the oldest
  312. //
  313. if (gwayConfig.logFileNum > LOGFILEMAX){
  314. sprintf(fn,"/log-%d", gwayConfig.logFileNo - LOGFILEMAX);
  315. #if _DUSB>=1
  316. if (( debug>=0 ) && ( pdebug & P_GUI )) {
  317. Serial.print(F("G addLog:: Too many logfile, deleting="));
  318. Serial.println(fn);
  319. }
  320. #endif
  321. SPIFFS.remove(fn);
  322. gwayConfig.logFileNum--;
  323. }
  324. // Make sure we have the right fileno
  325. sprintf(fn,"/log-%d", gwayConfig.logFileNo);
  326. // If there is no SPIFFS, Error
  327. // Make sure to write the config record/line also
  328. if (!SPIFFS.exists(fn)) {
  329. #if _DUSB>=1
  330. if (( debug >= 1 ) && ( pdebug & P_GUI )) {
  331. Serial.print(F("G ERROR:: addLog:: file="));
  332. Serial.print(fn);
  333. Serial.print(F(" does not exist .. rec="));
  334. Serial.print(gwayConfig.logFileRec);
  335. Serial.println();
  336. }
  337. #endif
  338. }
  339. File f = SPIFFS.open(fn, "a");
  340. if (!f) {
  341. #if _DUSB>=1
  342. if (( debug>=1 ) && ( pdebug & P_GUI )) {
  343. Serial.println("G file open failed=");
  344. Serial.println(fn);
  345. }
  346. #endif
  347. return(0); // If file open failed, return
  348. }
  349. int i;
  350. #if _DUSB>=1
  351. if (( debug>=1 ) && ( pdebug & P_GUI )) {
  352. Serial.print(F("G addLog:: fileno="));
  353. Serial.print(gwayConfig.logFileNo);
  354. Serial.print(F(", rec="));
  355. Serial.print(gwayConfig.logFileRec);
  356. Serial.print(F(": "));
  357. #if _DUSB>=2
  358. for (i=0; i< 12; i++) { // The first 12 bytes contain non printable characters
  359. Serial.print(line[i],HEX);
  360. Serial.print(' ');
  361. }
  362. #else
  363. i+=12;
  364. #endif
  365. Serial.print((char *) &line[i]); // The rest if the buffer contains ascii
  366. Serial.println();
  367. }
  368. #endif //DUSB
  369. for (i=0; i< 12; i++) { // The first 12 bytes contain non printable characters
  370. // f.print(line[i],HEX);
  371. f.print('*');
  372. }
  373. f.write(&(line[i]), cnt-12); // write/append the line to the file
  374. f.print('\n');
  375. f.close(); // Close the file after appending to it
  376. #endif //STAT_LOG
  377. return(1);
  378. }
  379. // ----------------------------------------------------------------------------
  380. // Print (all) logfiles
  381. //
  382. // ----------------------------------------------------------------------------
  383. void printLog()
  384. {
  385. char fn[16];
  386. int i=0;
  387. #if _DUSB>=1
  388. while (i< LOGFILEMAX ) {
  389. sprintf(fn,"/log-%d", gwayConfig.logFileNo - i);
  390. if (!SPIFFS.exists(fn)) break; // break the loop
  391. // Open the file for reading
  392. File f = SPIFFS.open(fn, "r");
  393. int j;
  394. for (j=0; j<LOGFILEREC; j++) {
  395. String s=f.readStringUntil('\n');
  396. if (s.length() == 0) break;
  397. Serial.println(s.substring(12)); // Skip the first 12 Gateway specific binary characters
  398. yield();
  399. }
  400. i++;
  401. }
  402. #endif
  403. } //printLog
  404. #if _SEENMAX>0
  405. // ----------------------------------------------------------------------------
  406. // writeSeen
  407. // - Once every few messages, update the SPIFFS file and write the array.
  408. //
  409. // ----------------------------------------------------------------------------
  410. int writeSeen(struct nodeSeen *listSeen) {
  411. return(1);
  412. }
  413. // ----------------------------------------------------------------------------
  414. // printSeen
  415. // - Once every few messages, update the SPIFFS file and write the array.
  416. // ----------------------------------------------------------------------------
  417. int printSeen(struct nodeSeen *listSeen) {
  418. #if _DUSB>=1
  419. if (( debug>=0 ) && ( pdebug & P_MAIN )) {
  420. Serial.print(F("printSeen:: print list"));
  421. Serial.println();
  422. }
  423. #endif
  424. int i;
  425. #if _DUSB>=1
  426. if (( debug>=0 ) && ( pdebug & P_MAIN )) {
  427. for (i=0; i<_SEENMAX; i++) {
  428. if (listSeen[i].idSeen != 0) {
  429. String response;
  430. Serial.print(i);
  431. Serial.print(F(", TM="));
  432. stringTime(listSeen[i].timSeen, response);
  433. Serial.print(response);
  434. Serial.print(F(", addr=0x"));
  435. Serial.print(listSeen[i].idSeen,HEX);
  436. Serial.print(F(", SF=0x"));
  437. Serial.print(listSeen[i].sfSeen,HEX);
  438. Serial.println();
  439. }
  440. }
  441. }
  442. #endif
  443. return(1);
  444. }
  445. // ----------------------------------------------------------------------------
  446. // addSeen
  447. // With every new message received:
  448. // - Look whether the message is already in the array, if so update existing
  449. // message. If not, create new record.
  450. // - With this record, update the SF settings
  451. // ----------------------------------------------------------------------------
  452. int addSeen(struct nodeSeen *listSeen, uint32_t idSeen, uint8_t sfSeen, unsigned long timSeen) {
  453. int i;
  454. // ( message[4]<<24 | message[3]<<16 | message[2]<<8 | message[1] )
  455. #if _DUSB>=1
  456. if (( debug>=1 ) && ( pdebug & P_MAIN )) {
  457. Serial.print(F("addSeen:: "));
  458. // Serial.print(F(" listSeen[0]="));
  459. // Serial.print(listSeen[0].idSeen,HEX);
  460. // Serial.print(F(", "));
  461. Serial.print(F("tim="));
  462. Serial.print(timSeen);
  463. Serial.print(F(", idSeen="));
  464. Serial.print(idSeen,HEX);
  465. Serial.print(F(", sfSeen="));
  466. Serial.print(sfSeen,HEX);
  467. Serial.println();
  468. }
  469. #endif
  470. for (i=0; i< _SEENMAX; i++) {
  471. if ((listSeen[i].idSeen==idSeen) ||
  472. (listSeen[i].idSeen==0))
  473. {
  474. break;
  475. }
  476. }
  477. if (i>=_SEENMAX) {
  478. #if _DUSB>=1
  479. if (( debug>=0 ) && ( pdebug & P_MAIN )) {
  480. Serial.print(F("addSeen:: exit=0, index="));
  481. Serial.println(i);
  482. }
  483. #endif
  484. return(0);
  485. }
  486. #if _DUSB>=2
  487. if (( debug>=0 ) && ( pdebug & P_MAIN )) {
  488. Serial.print(F("addSeen:: index="));
  489. Serial.print(i);
  490. }
  491. #endif
  492. listSeen[i].idSeen = idSeen;
  493. listSeen[i].sfSeen |= sfSeen;
  494. listSeen[i].timSeen = timSeen;
  495. return(1);
  496. }
  497. // ----------------------------------------------------------------------------
  498. // initSeen
  499. // Init the lisrScreen array
  500. // ----------------------------------------------------------------------------
  501. int initSeen(struct nodeSeen *listSeen) {
  502. int i;
  503. for (i=0; i< _SEENMAX; i++) {
  504. listSeen[i].idSeen=0;
  505. listSeen[i].sfSeen=0;
  506. listSeen[i].timSeen=0;
  507. }
  508. return(1);
  509. }
  510. // ----------------------------------------------------------------------------
  511. // listDir
  512. // List the directory and put it in
  513. // ----------------------------------------------------------------------------
  514. void listDir(char * dir)
  515. {
  516. #if _DUSB>=1
  517. // Nothing here
  518. #endif
  519. }
  520. #endif //_SEENMAX>0