_loraFiles.ino 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. // 1-channel LoRa Gateway for ESP8266
  2. // Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
  3. // Version 6.1.0
  4. // Date: 2019-10-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 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. }
  50. // ----------------------------------------------------------------------------
  51. // Read the gateway configuration file
  52. // ----------------------------------------------------------------------------
  53. int readConfig(const char *fn, struct espGwayConfig *c) {
  54. int tries = 0;
  55. #if DUSB>=1
  56. Serial.println(F("readConfig:: Starting "));
  57. #endif
  58. if (!SPIFFS.exists(fn)) {
  59. #if DUSB>=1
  60. if (( debug>=0 ) && ( pdebug & P_MAIN ))
  61. Serial.print(F("M ERR:: readConfig, file="));
  62. Serial.print(fn);
  63. Serial.println(F(" does not exist .. Formatting"));
  64. #endif
  65. SPIFFS.format();
  66. initConfig(c);
  67. return(-1);
  68. }
  69. File f = SPIFFS.open(fn, "r");
  70. if (!f) {
  71. Serial.println(F("ERROR:: SPIFFS open failed"));
  72. return(-1);
  73. }
  74. while (f.available()) {
  75. #if DUSB>=1
  76. if (( debug>=0 ) && ( pdebug & P_MAIN )) {
  77. Serial.print('.');
  78. }
  79. #endif
  80. // If we wait for more than 10 times, reformat the filesystem
  81. // We do this so that the system will be responsive (over OTA for example).
  82. //
  83. if (tries >= 10) {
  84. f.close();
  85. #if DUSB>=1
  86. if (( debug>=0 ) && ( pdebug & P_MAIN ))
  87. Serial.println(F("Formatting"));
  88. #endif
  89. SPIFFS.format();
  90. initConfig(c);
  91. f = SPIFFS.open(fn, "r");
  92. tries = 0;
  93. }
  94. String id =f.readStringUntil('='); // C++ thing
  95. String val=f.readStringUntil('\n');
  96. if (id == "SSID") { // WiFi SSID
  97. id_print(id, val);
  98. (*c).ssid = val; // val contains ssid, we do NO check
  99. }
  100. else if (id == "PASS") { // WiFi Password
  101. id_print(id, val);
  102. (*c).pass = val;
  103. }
  104. else if (id == "CH") { // Frequency Channel
  105. id_print(id,val);
  106. (*c).ch = (uint32_t) val.toInt();
  107. }
  108. else if (id == "SF") { // Spreading Factor
  109. id_print(id, val);
  110. (*c).sf = (uint32_t) val.toInt();
  111. }
  112. else if (id == "FCNT") { // Frame Counter
  113. id_print(id, val);
  114. (*c).fcnt = (uint32_t) val.toInt();
  115. }
  116. else if (id == "DEBUG") { // Debug Level
  117. id_print(id, val);
  118. (*c).debug = (uint8_t) val.toInt();
  119. }
  120. else if (id == "PDEBUG") { // pDebug Pattern
  121. Serial.print(F("PDEBUG=")); Serial.println(val);
  122. (*c).pdebug = (uint8_t) val.toInt();
  123. }
  124. else if (id == "CAD") { // CAD setting
  125. Serial.print(F("CAD=")); Serial.println(val);
  126. (*c).cad = (uint8_t) val.toInt();
  127. }
  128. else if (id == "HOP") { // HOP setting
  129. Serial.print(F("HOP=")); Serial.println(val);
  130. (*c).hop = (uint8_t) val.toInt();
  131. }
  132. else if (id == "BOOTS") { // BOOTS setting
  133. id_print(id, val);
  134. (*c).boots = (uint8_t) val.toInt();
  135. }
  136. else if (id == "RESETS") { // RESET setting
  137. id_print(id, val);
  138. (*c).resets = (uint8_t) val.toInt();
  139. }
  140. else if (id == "WIFIS") { // WIFIS setting
  141. id_print(id, val);
  142. (*c).wifis = (uint8_t) val.toInt();
  143. }
  144. else if (id == "VIEWS") { // VIEWS setting
  145. id_print(id, val);
  146. (*c).views = (uint8_t) val.toInt();
  147. }
  148. else if (id == "NODE") { // NODE setting
  149. id_print(id, val);
  150. (*c).isNode = (uint8_t) val.toInt();
  151. }
  152. else if (id == "REFR") { // REFR setting
  153. id_print(id, val);
  154. (*c).refresh = (uint8_t) val.toInt();
  155. }
  156. else if (id == "REENTS") { // REENTS setting
  157. id_print(id, val);
  158. (*c).reents = (uint8_t) val.toInt();
  159. }
  160. else if (id == "NTPERR") { // NTPERR setting
  161. id_print(id, val);
  162. (*c).ntpErr = (uint8_t) val.toInt();
  163. }
  164. else if (id == "NTPETIM") { // NTPERR setting
  165. id_print(id, val);
  166. (*c).ntpErrTime = (uint32_t) val.toInt();
  167. }
  168. else if (id == "NTPS") { // NTPS setting
  169. id_print(id, val);
  170. (*c).ntps = (uint8_t) val.toInt();
  171. }
  172. else if (id == "FILENO") { // log FILENO setting
  173. id_print(id, val);
  174. (*c).logFileNo = (uint8_t) val.toInt();
  175. }
  176. else if (id == "FILEREC") { // FILEREC setting
  177. id_print(id, val);
  178. (*c).logFileRec = (uint16_t) val.toInt();
  179. }
  180. else if (id == "FILENUM") { // FILEREC setting
  181. id_print(id, val);
  182. (*c).logFileNum = (uint16_t) val.toInt();
  183. }
  184. else if (id == "EXPERT") { // FILEREC setting
  185. id_print(id, val);
  186. (*c).expert = (uint8_t) val.toInt();
  187. }
  188. else {
  189. tries++;
  190. }
  191. }
  192. f.close();
  193. #if DUSB>=1
  194. if (debug>=0) {
  195. Serial.println('#');
  196. }
  197. #endif
  198. Serial.println();
  199. return(1);
  200. }
  201. // ----------------------------------------------------------------------------
  202. // Write the current gateway configuration to SPIFFS. First copy all the
  203. // separate data items to the gwayConfig structure
  204. //
  205. // ----------------------------------------------------------------------------
  206. int writeGwayCfg(const char *fn) {
  207. gwayConfig.ssid = WiFi.SSID();
  208. gwayConfig.pass = WiFi.psk(); // XXX We should find a way to store the password too
  209. gwayConfig.ch = ifreq; // Frequency Index
  210. gwayConfig.sf = (uint8_t) sf; // Spreading Factor
  211. gwayConfig.debug = debug;
  212. gwayConfig.pdebug = pdebug;
  213. gwayConfig.cad = _cad;
  214. gwayConfig.hop = _hop;
  215. #if GATEWAYNODE==1
  216. gwayConfig.fcnt = frameCount;
  217. #endif
  218. return(writeConfig(fn, &gwayConfig));
  219. }
  220. // ----------------------------------------------------------------------------
  221. // Write the configuration as found in the espGwayConfig structure
  222. // to SPIFFS
  223. // Parameters:
  224. // fn; Filename
  225. // c; struct config
  226. // Returns:
  227. // 1 when successful, -1 on error
  228. // ----------------------------------------------------------------------------
  229. int writeConfig(const char *fn, struct espGwayConfig *c) {
  230. if (!SPIFFS.exists(fn)) {
  231. Serial.print("WARNING:: writeConfig, file not exists, formatting ");
  232. SPIFFS.format();
  233. initConfig(c); // XXX make all initial declarations here if config vars need to have a value
  234. Serial.println(fn);
  235. }
  236. File f = SPIFFS.open(fn, "w");
  237. if (!f) {
  238. Serial.print("ERROR:: writeConfig, open file=");
  239. Serial.print(fn);
  240. Serial.println();
  241. return(-1);
  242. }
  243. f.print("SSID"); f.print('='); f.print((*c).ssid); f.print('\n');
  244. f.print("PASS"); f.print('='); f.print((*c).pass); f.print('\n');
  245. f.print("CH"); f.print('='); f.print((*c).ch); f.print('\n');
  246. f.print("SF"); f.print('='); f.print((*c).sf); f.print('\n');
  247. f.print("FCNT"); f.print('='); f.print((*c).fcnt); f.print('\n');
  248. f.print("DEBUG"); f.print('='); f.print((*c).debug); f.print('\n');
  249. f.print("PDEBUG"); f.print('='); f.print((*c).pdebug); f.print('\n');
  250. f.print("CAD"); f.print('='); f.print((*c).cad); f.print('\n');
  251. f.print("HOP"); f.print('='); f.print((*c).hop); f.print('\n');
  252. f.print("NODE"); f.print('='); f.print((*c).isNode); f.print('\n');
  253. f.print("BOOTS"); f.print('='); f.print((*c).boots); f.print('\n');
  254. f.print("RESETS"); f.print('='); f.print((*c).resets); f.print('\n');
  255. f.print("WIFIS"); f.print('='); f.print((*c).wifis); f.print('\n');
  256. f.print("VIEWS"); f.print('='); f.print((*c).views); f.print('\n');
  257. f.print("REFR"); f.print('='); f.print((*c).refresh); f.print('\n');
  258. f.print("REENTS"); f.print('='); f.print((*c).reents); f.print('\n');
  259. f.print("NTPETIM"); f.print('='); f.print((*c).ntpErrTime); f.print('\n');
  260. f.print("NTPERR"); f.print('='); f.print((*c).ntpErr); f.print('\n');
  261. f.print("NTPS"); f.print('='); f.print((*c).ntps); f.print('\n');
  262. f.print("FILEREC"); f.print('='); f.print((*c).logFileRec); f.print('\n');
  263. f.print("FILENO"); f.print('='); f.print((*c).logFileNo); f.print('\n');
  264. f.print("FILENUM"); f.print('='); f.print((*c).logFileNum); f.print('\n');
  265. f.print("EXPERT"); f.print('='); f.print((*c).expert); f.print('\n');
  266. f.close();
  267. return(1);
  268. }
  269. // ----------------------------------------------------------------------------
  270. // Add a line with statistics to the log.
  271. //
  272. // We put the check in the function to protect against calling
  273. // the function without STAT_LOG being proper defined
  274. // ToDo: Store the fileNo and the fileRec in the status file to save for
  275. // restarts
  276. // Parameters:
  277. // line; char array with characters to write to log
  278. // cnt;
  279. // Returns:
  280. // <none>
  281. // ----------------------------------------------------------------------------
  282. void addLog(const unsigned char * line, int cnt)
  283. {
  284. #if STAT_LOG==1
  285. char fn[16];
  286. if (gwayConfig.logFileRec > LOGFILEREC) { // Have to make define for this
  287. gwayConfig.logFileRec = 0; // In new logFile start with record 0
  288. gwayConfig.logFileNo++; // Increase file ID
  289. gwayConfig.logFileNum++; // Increase number of log files
  290. }
  291. gwayConfig.logFileRec++;
  292. // If we have too many logfies, delete the oldest
  293. //
  294. if (gwayConfig.logFileNum > LOGFILEMAX){
  295. sprintf(fn,"/log-%d", gwayConfig.logFileNo - LOGFILEMAX);
  296. #if DUSB>=1
  297. if (( debug>=0 ) && ( pdebug & P_GUI )) {
  298. Serial.print(F("G addLog:: Too many logfile, deleting="));
  299. Serial.println(fn);
  300. }
  301. #endif
  302. SPIFFS.remove(fn);
  303. gwayConfig.logFileNum--;
  304. }
  305. // Make sure we have the right fileno
  306. sprintf(fn,"/log-%d", gwayConfig.logFileNo);
  307. // If there is no SPIFFS, Error
  308. // Make sure to write the config record/line also
  309. if (!SPIFFS.exists(fn)) {
  310. #if DUSB>=1
  311. if (( debug >= 1 ) && ( pdebug & P_GUI )) {
  312. Serial.print(F("G ERROR:: addLog:: file="));
  313. Serial.print(fn);
  314. Serial.print(F(" does not exist .. rec="));
  315. Serial.print(gwayConfig.logFileRec);
  316. Serial.println();
  317. }
  318. #endif
  319. }
  320. File f = SPIFFS.open(fn, "a");
  321. if (!f) {
  322. #if DUSB>=1
  323. if (( debug>=1 ) && ( pdebug & P_GUI )) {
  324. Serial.println("G file open failed=");
  325. Serial.println(fn);
  326. }
  327. #endif
  328. return; // If file open failed, return
  329. }
  330. int i;
  331. #if DUSB>=1
  332. if (( debug>=1 ) && ( pdebug & P_GUI )) {
  333. Serial.print(F("G addLog:: fileno="));
  334. Serial.print(gwayConfig.logFileNo);
  335. Serial.print(F(", rec="));
  336. Serial.print(gwayConfig.logFileRec);
  337. Serial.print(F(": "));
  338. for (i=0; i< 12; i++) { // The first 12 bytes contain non printable characters
  339. Serial.print(line[i],HEX);
  340. Serial.print(' ');
  341. }
  342. Serial.print((char *) &line[i]); // The rest if the buffer contains ascii
  343. Serial.println();
  344. }
  345. #endif //DUSB
  346. for (i=0; i< 12; i++) { // The first 12 bytes contain non printable characters
  347. // f.print(line[i],HEX);
  348. f.print('*');
  349. }
  350. f.write(&(line[i]), cnt-12); // write/append the line to the file
  351. f.print('\n');
  352. f.close(); // Close the file after appending to it
  353. #endif //STAT_LOG
  354. }
  355. // ----------------------------------------------------------------------------
  356. // Print (all) logfiles
  357. //
  358. // ----------------------------------------------------------------------------
  359. void printLog()
  360. {
  361. char fn[16];
  362. int i=0;
  363. #if DUSB>=1
  364. while (i< LOGFILEMAX ) {
  365. sprintf(fn,"/log-%d", gwayConfig.logFileNo - i);
  366. if (!SPIFFS.exists(fn)) break; // break the loop
  367. // Open the file for reading
  368. File f = SPIFFS.open(fn, "r");
  369. int j;
  370. for (j=0; j<LOGFILEREC; j++) {
  371. String s=f.readStringUntil('\n');
  372. if (s.length() == 0) break;
  373. Serial.println(s.substring(12)); // Skip the first 12 Gateway specific binary characters
  374. yield();
  375. }
  376. i++;
  377. }
  378. #endif
  379. } //printLog
  380. // ----------------------------------------------------------------------------
  381. // listDir
  382. // List the directory and put it in
  383. // ----------------------------------------------------------------------------
  384. void listDir(char * dir)
  385. {
  386. #if DUSB>=1
  387. #endif
  388. }