support.ino 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173
  1. /*
  2. support.ino - support for Sonoff-Tasmota
  3. Copyright (C) 2018 Theo Arends
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. IPAddress syslog_host_addr; // Syslog host IP address
  16. uint32_t syslog_host_hash = 0; // Syslog host name hash
  17. /*********************************************************************************************\
  18. * Watchdog extension (https://github.com/esp8266/Arduino/issues/1532)
  19. \*********************************************************************************************/
  20. #include <Ticker.h>
  21. Ticker tickerOSWatch;
  22. #define OSWATCH_RESET_TIME 120
  23. static unsigned long oswatch_last_loop_time;
  24. byte oswatch_blocked_loop = 0;
  25. #ifndef USE_WS2812_DMA // Collides with Neopixelbus but solves exception
  26. //void OsWatchTicker() ICACHE_RAM_ATTR;
  27. #endif // USE_WS2812_DMA
  28. #ifdef USE_KNX
  29. bool knx_started = false;
  30. #endif // USE_KNX
  31. void OsWatchTicker(void)
  32. {
  33. unsigned long t = millis();
  34. unsigned long last_run = abs(t - oswatch_last_loop_time);
  35. #ifdef DEBUG_THEO
  36. snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_OSWATCH " FreeRam %d, rssi %d, last_run %d"), ESP.getFreeHeap(), WifiGetRssiAsQuality(WiFi.RSSI()), last_run);
  37. AddLog(LOG_LEVEL_DEBUG);
  38. #endif // DEBUG_THEO
  39. if (last_run >= (OSWATCH_RESET_TIME * 1000)) {
  40. // AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION D_OSWATCH " " D_BLOCKED_LOOP ". " D_RESTARTING)); // Save iram space
  41. RtcSettings.oswatch_blocked_loop = 1;
  42. RtcSettingsSave();
  43. // ESP.restart(); // normal reboot
  44. ESP.reset(); // hard reset
  45. }
  46. }
  47. void OsWatchInit(void)
  48. {
  49. oswatch_blocked_loop = RtcSettings.oswatch_blocked_loop;
  50. RtcSettings.oswatch_blocked_loop = 0;
  51. oswatch_last_loop_time = millis();
  52. tickerOSWatch.attach_ms(((OSWATCH_RESET_TIME / 3) * 1000), OsWatchTicker);
  53. }
  54. void OsWatchLoop(void)
  55. {
  56. oswatch_last_loop_time = millis();
  57. // while(1) delay(1000); // this will trigger the os watch
  58. }
  59. String GetResetReason(void)
  60. {
  61. char buff[32];
  62. if (oswatch_blocked_loop) {
  63. strncpy_P(buff, PSTR(D_JSON_BLOCKED_LOOP), sizeof(buff));
  64. return String(buff);
  65. } else {
  66. return ESP.getResetReason();
  67. }
  68. }
  69. boolean OsWatchBlockedLoop(void)
  70. {
  71. return oswatch_blocked_loop;
  72. }
  73. /*********************************************************************************************\
  74. * Miscellaneous
  75. \*********************************************************************************************/
  76. #ifdef ARDUINO_ESP8266_RELEASE_2_3_0
  77. // Functions not available in 2.3.0
  78. // http://clc-wiki.net/wiki/C_standard_library:string.h:memchr
  79. void* memchr(const void* ptr, int value, size_t num)
  80. {
  81. unsigned char *p = (unsigned char*)ptr;
  82. while (num--) {
  83. if (*p != (unsigned char)value) {
  84. p++;
  85. } else {
  86. return p;
  87. }
  88. }
  89. return 0;
  90. }
  91. // http://clc-wiki.net/wiki/C_standard_library:string.h:strspn
  92. // Get span until any character in string
  93. size_t strcspn(const char *str1, const char *str2)
  94. {
  95. size_t ret = 0;
  96. while (*str1) {
  97. if (strchr(str2, *str1)) { // Slow
  98. return ret;
  99. } else {
  100. str1++;
  101. ret++;
  102. }
  103. }
  104. return ret;
  105. }
  106. #endif // ARDUINO_ESP8266_RELEASE_2_3_0
  107. // Get span until single character in string
  108. size_t strchrspn(const char *str1, int character)
  109. {
  110. size_t ret = 0;
  111. char *start = (char*)str1;
  112. char *end = strchr(str1, character);
  113. if (end) ret = end - start;
  114. return ret;
  115. }
  116. // Function to return a substring defined by a delimiter at an index
  117. char* subStr(char* dest, char* str, const char *delim, int index)
  118. {
  119. char *act;
  120. char *sub;
  121. char *ptr;
  122. int i;
  123. // Since strtok consumes the first arg, make a copy
  124. strncpy(dest, str, strlen(str)+1);
  125. for (i = 1, act = dest; i <= index; i++, act = NULL) {
  126. sub = strtok_r(act, delim, &ptr);
  127. if (sub == NULL) break;
  128. }
  129. sub = Trim(sub);
  130. return sub;
  131. }
  132. double CharToDouble(char *str)
  133. {
  134. // simple ascii to double, because atof or strtod are too large
  135. char strbuf[24];
  136. strlcpy(strbuf, str, sizeof(strbuf));
  137. char *pt;
  138. double left = atoi(strbuf);
  139. double right = 0;
  140. short len = 0;
  141. pt = strtok (strbuf, ".");
  142. if (pt) {
  143. pt = strtok (NULL, ".");
  144. if (pt) {
  145. right = atoi(pt);
  146. len = strlen(pt);
  147. double fac = 1;
  148. while (len) {
  149. fac /= 10.0;
  150. len--;
  151. }
  152. // pow is also very large
  153. //double fac=pow(10,-len);
  154. right *= fac;
  155. }
  156. }
  157. double result = left + right;
  158. if (left < 0) { result = left - right; }
  159. return result;
  160. }
  161. int TextToInt(char *str)
  162. {
  163. char *p;
  164. uint8_t radix = 10;
  165. if ('#' == str[0]) {
  166. radix = 16;
  167. str++;
  168. }
  169. return strtol(str, &p, radix);
  170. }
  171. char* dtostrfd(double number, unsigned char prec, char *s)
  172. {
  173. if ((isnan(number)) || (isinf(number))) { // Fix for JSON output (https://stackoverflow.com/questions/1423081/json-left-out-infinity-and-nan-json-status-in-ecmascript)
  174. strcpy(s, "null");
  175. return s;
  176. } else {
  177. return dtostrf(number, 1, prec, s);
  178. }
  179. }
  180. char* Unescape(char* buffer, uint16_t* size)
  181. {
  182. uint8_t* read = (uint8_t*)buffer;
  183. uint8_t* write = (uint8_t*)buffer;
  184. uint16_t start_size = *size;
  185. uint16_t end_size = *size;
  186. uint8_t che = 0;
  187. while (start_size > 0) {
  188. uint8_t ch = *read++;
  189. start_size--;
  190. if (ch != '\\') {
  191. *write++ = ch;
  192. } else {
  193. if (start_size > 0) {
  194. uint8_t chi = *read++;
  195. start_size--;
  196. end_size--;
  197. switch (chi) {
  198. case '\\': che = '\\'; break; // 5C Backslash
  199. case 'a': che = '\a'; break; // 07 Bell (Alert)
  200. case 'b': che = '\b'; break; // 08 Backspace
  201. case 'e': che = '\e'; break; // 1B Escape
  202. case 'f': che = '\f'; break; // 0C Formfeed
  203. case 'n': che = '\n'; break; // 0A Linefeed (Newline)
  204. case 'r': che = '\r'; break; // 0D Carriage return
  205. case 's': che = ' '; break; // 20 Space
  206. case 't': che = '\t'; break; // 09 Horizontal tab
  207. case 'v': che = '\v'; break; // 0B Vertical tab
  208. // case '?': che = '\?'; break; // 3F Question mark
  209. default : {
  210. che = chi;
  211. *write++ = ch;
  212. end_size++;
  213. }
  214. }
  215. *write++ = che;
  216. }
  217. }
  218. }
  219. *size = end_size;
  220. return buffer;
  221. }
  222. char* RemoveSpace(char* p)
  223. {
  224. char* write = p;
  225. char* read = p;
  226. char ch = '.';
  227. while (ch != '\0') {
  228. ch = *read++;
  229. if (!isspace(ch)) {
  230. *write++ = ch;
  231. }
  232. }
  233. *write = '\0';
  234. return p;
  235. }
  236. char* UpperCase(char* dest, const char* source)
  237. {
  238. char* write = dest;
  239. const char* read = source;
  240. char ch = '.';
  241. while (ch != '\0') {
  242. ch = *read++;
  243. *write++ = toupper(ch);
  244. }
  245. return dest;
  246. }
  247. char* UpperCase_P(char* dest, const char* source)
  248. {
  249. char* write = dest;
  250. const char* read = source;
  251. char ch = '.';
  252. while (ch != '\0') {
  253. ch = pgm_read_byte(read++);
  254. *write++ = toupper(ch);
  255. }
  256. return dest;
  257. }
  258. /*
  259. char* LTrim(char* p)
  260. {
  261. while ((*p != '\0') && (isblank(*p))) {
  262. p++; // Trim leading spaces
  263. }
  264. return p;
  265. }
  266. char* RTrim(char* p)
  267. {
  268. char* q = p + strlen(p) -1;
  269. while ((q >= p) && (isblank(*q))) {
  270. q--; // Trim trailing spaces
  271. }
  272. q++;
  273. *q = '\0';
  274. return p;
  275. }
  276. */
  277. char* Trim(char* p)
  278. {
  279. while ((*p != '\0') && isblank(*p)) { p++; } // Trim leading spaces
  280. char* q = p + strlen(p) -1;
  281. while ((q >= p) && isblank(*q)) { q--; } // Trim trailing spaces
  282. q++;
  283. *q = '\0';
  284. return p;
  285. }
  286. char* NoAlNumToUnderscore(char* dest, const char* source)
  287. {
  288. char* write = dest;
  289. const char* read = source;
  290. char ch = '.';
  291. while (ch != '\0') {
  292. ch = *read++;
  293. *write++ = (isalnum(ch) || ('\0' == ch)) ? ch : '_';
  294. }
  295. return dest;
  296. }
  297. void SetShortcut(char* str, uint8_t action)
  298. {
  299. if ('\0' != str[0]) { // There must be at least one character in the buffer
  300. str[0] = '0' + action; // SC_CLEAR, SC_DEFAULT, SC_USER
  301. str[1] = '\0';
  302. }
  303. }
  304. uint8_t Shortcut(const char* str)
  305. {
  306. uint8_t result = 10;
  307. if ('\0' == str[1]) { // Only allow single character input for shortcut
  308. if (('"' == str[0]) || ('0' == str[0])) {
  309. result = SC_CLEAR;
  310. } else {
  311. result = atoi(str); // 1 = SC_DEFAULT, 2 = SC_USER
  312. if (0 == result) {
  313. result = 10;
  314. }
  315. }
  316. }
  317. return result;
  318. }
  319. boolean ParseIp(uint32_t* addr, const char* str)
  320. {
  321. uint8_t *part = (uint8_t*)addr;
  322. byte i;
  323. *addr = 0;
  324. for (i = 0; i < 4; i++) {
  325. part[i] = strtoul(str, NULL, 10); // Convert byte
  326. str = strchr(str, '.');
  327. if (str == NULL || *str == '\0') {
  328. break; // No more separators, exit
  329. }
  330. str++; // Point to next character after separator
  331. }
  332. return (3 == i);
  333. }
  334. void MakeValidMqtt(byte option, char* str)
  335. {
  336. // option 0 = replace by underscore
  337. // option 1 = delete character
  338. uint16_t i = 0;
  339. while (str[i] > 0) {
  340. // if ((str[i] == '/') || (str[i] == '+') || (str[i] == '#') || (str[i] == ' ')) {
  341. if ((str[i] == '+') || (str[i] == '#') || (str[i] == ' ')) {
  342. if (option) {
  343. uint16_t j = i;
  344. while (str[j] > 0) {
  345. str[j] = str[j +1];
  346. j++;
  347. }
  348. i--;
  349. } else {
  350. str[i] = '_';
  351. }
  352. }
  353. i++;
  354. }
  355. }
  356. // Function to parse & check if version_str is newer than our currently installed version.
  357. bool NewerVersion(char* version_str)
  358. {
  359. uint32_t version = 0;
  360. uint8_t i = 0;
  361. char *str_ptr;
  362. char* version_dup = strdup(version_str); // Duplicate the version_str as strtok_r will modify it.
  363. if (!version_dup) {
  364. return false; // Bail if we can't duplicate. Assume bad.
  365. }
  366. // Loop through the version string, splitting on '.' seperators.
  367. for (char *str = strtok_r(version_dup, ".", &str_ptr); str && i < sizeof(VERSION); str = strtok_r(NULL, ".", &str_ptr), i++) {
  368. int field = atoi(str);
  369. // The fields in a version string can only range from 0-255.
  370. if ((field < 0) || (field > 255)) {
  371. free(version_dup);
  372. return false;
  373. }
  374. // Shuffle the accumulated bytes across, and add the new byte.
  375. version = (version << 8) + field;
  376. // Check alpha delimiter after 1.2.3 only
  377. if ((2 == i) && isalpha(str[strlen(str)-1])) {
  378. field = str[strlen(str)-1] & 0x1f;
  379. version = (version << 8) + field;
  380. i++;
  381. }
  382. }
  383. free(version_dup); // We no longer need this.
  384. // A version string should have 2-4 fields. e.g. 1.2, 1.2.3, or 1.2.3a (= 1.2.3.1).
  385. // If not, then don't consider it a valid version string.
  386. if ((i < 2) || (i > sizeof(VERSION))) {
  387. return false;
  388. }
  389. // Keep shifting the parsed version until we hit the maximum number of tokens.
  390. // VERSION stores the major number of the version in the most significant byte of the uint32_t.
  391. while (i < sizeof(VERSION)) {
  392. version <<= 8;
  393. i++;
  394. }
  395. // Now we should have a fully constructed version number in uint32_t form.
  396. return (version > VERSION);
  397. }
  398. char* GetPowerDevice(char* dest, uint8_t idx, size_t size, uint8_t option)
  399. {
  400. char sidx[8];
  401. strncpy_P(dest, S_RSLT_POWER, size); // POWER
  402. if ((devices_present + option) > 1) {
  403. snprintf_P(sidx, sizeof(sidx), PSTR("%d"), idx); // x
  404. strncat(dest, sidx, size - strlen(dest) -1); // POWERx
  405. }
  406. return dest;
  407. }
  408. char* GetPowerDevice(char* dest, uint8_t idx, size_t size)
  409. {
  410. return GetPowerDevice(dest, idx, size, 0);
  411. }
  412. float ConvertTemp(float c)
  413. {
  414. float result = c;
  415. if (!isnan(c) && Settings.flag.temperature_conversion) {
  416. result = c * 1.8 + 32; // Fahrenheit
  417. }
  418. return result;
  419. }
  420. char TempUnit(void)
  421. {
  422. return (Settings.flag.temperature_conversion) ? 'F' : 'C';
  423. }
  424. float ConvertPressure(float p)
  425. {
  426. float result = p;
  427. if (!isnan(p) && Settings.flag.pressure_conversion) {
  428. result = p * 0.75006375541921; // mmHg
  429. }
  430. return result;
  431. }
  432. String PressureUnit(void)
  433. {
  434. return (Settings.flag.pressure_conversion) ? String(D_UNIT_MILLIMETER_MERCURY) : String(D_UNIT_PRESSURE);
  435. }
  436. void SetGlobalValues(float temperature, float humidity)
  437. {
  438. global_update = uptime;
  439. global_temperature = temperature;
  440. global_humidity = humidity;
  441. }
  442. void ResetGlobalValues(void)
  443. {
  444. if ((uptime - global_update) > GLOBAL_VALUES_VALID) { // Reset after 5 minutes
  445. global_update = 0;
  446. global_temperature = 0;
  447. global_humidity = 0;
  448. }
  449. }
  450. double FastPrecisePow(double a, double b)
  451. {
  452. // https://martin.ankerl.com/2012/01/25/optimized-approximative-pow-in-c-and-cpp/
  453. // calculate approximation with fraction of the exponent
  454. int e = (int)b;
  455. union {
  456. double d;
  457. int x[2];
  458. } u = { a };
  459. u.x[1] = (int)((b - e) * (u.x[1] - 1072632447) + 1072632447);
  460. u.x[0] = 0;
  461. // exponentiation by squaring with the exponent's integer part
  462. // double r = u.d makes everything much slower, not sure why
  463. double r = 1.0;
  464. while (e) {
  465. if (e & 1) {
  466. r *= a;
  467. }
  468. a *= a;
  469. e >>= 1;
  470. }
  471. return r * u.d;
  472. }
  473. uint32_t SqrtInt(uint32_t num)
  474. {
  475. if (num <= 1) {
  476. return num;
  477. }
  478. uint32_t x = num / 2;
  479. uint32_t y;
  480. do {
  481. y = (x + num / x) / 2;
  482. if (y >= x) {
  483. return x;
  484. }
  485. x = y;
  486. } while (true);
  487. }
  488. uint32_t RoundSqrtInt(uint32_t num)
  489. {
  490. uint32_t s = SqrtInt(4 * num);
  491. if (s & 1) {
  492. s++;
  493. }
  494. return s / 2;
  495. }
  496. char* GetTextIndexed(char* destination, size_t destination_size, uint16_t index, const char* haystack)
  497. {
  498. // Returns empty string if not found
  499. // Returns text of found
  500. char* write = destination;
  501. const char* read = haystack;
  502. index++;
  503. while (index--) {
  504. size_t size = destination_size -1;
  505. write = destination;
  506. char ch = '.';
  507. while ((ch != '\0') && (ch != '|')) {
  508. ch = pgm_read_byte(read++);
  509. if (size && (ch != '|')) {
  510. *write++ = ch;
  511. size--;
  512. }
  513. }
  514. if (0 == ch) {
  515. if (index) {
  516. write = destination;
  517. }
  518. break;
  519. }
  520. }
  521. *write = '\0';
  522. return destination;
  523. }
  524. int GetCommandCode(char* destination, size_t destination_size, const char* needle, const char* haystack)
  525. {
  526. // Returns -1 of not found
  527. // Returns index and command if found
  528. int result = -1;
  529. const char* read = haystack;
  530. char* write = destination;
  531. while (true) {
  532. result++;
  533. size_t size = destination_size -1;
  534. write = destination;
  535. char ch = '.';
  536. while ((ch != '\0') && (ch != '|')) {
  537. ch = pgm_read_byte(read++);
  538. if (size && (ch != '|')) {
  539. *write++ = ch;
  540. size--;
  541. }
  542. }
  543. *write = '\0';
  544. if (!strcasecmp(needle, destination)) {
  545. break;
  546. }
  547. if (0 == ch) {
  548. result = -1;
  549. break;
  550. }
  551. }
  552. return result;
  553. }
  554. int GetStateNumber(char *state_text)
  555. {
  556. char command[CMDSZ];
  557. int state_number = -1;
  558. if (GetCommandCode(command, sizeof(command), state_text, kOptionOff) >= 0) {
  559. state_number = 0;
  560. }
  561. else if (GetCommandCode(command, sizeof(command), state_text, kOptionOn) >= 0) {
  562. state_number = 1;
  563. }
  564. else if (GetCommandCode(command, sizeof(command), state_text, kOptionToggle) >= 0) {
  565. state_number = 2;
  566. }
  567. else if (GetCommandCode(command, sizeof(command), state_text, kOptionBlink) >= 0) {
  568. state_number = 3;
  569. }
  570. else if (GetCommandCode(command, sizeof(command), state_text, kOptionBlinkOff) >= 0) {
  571. state_number = 4;
  572. }
  573. return state_number;
  574. }
  575. boolean GetUsedInModule(byte val, uint8_t *arr)
  576. {
  577. int offset = 0;
  578. if (!val) { return false; } // None
  579. if ((val >= GPIO_KEY1) && (val < GPIO_KEY1 + MAX_KEYS)) {
  580. offset = (GPIO_KEY1_NP - GPIO_KEY1);
  581. }
  582. if ((val >= GPIO_KEY1_NP) && (val < GPIO_KEY1_NP + MAX_KEYS)) {
  583. offset = -(GPIO_KEY1_NP - GPIO_KEY1);
  584. }
  585. if ((val >= GPIO_SWT1) && (val < GPIO_SWT1 + MAX_SWITCHES)) {
  586. offset = (GPIO_SWT1_NP - GPIO_SWT1);
  587. }
  588. if ((val >= GPIO_SWT1_NP) && (val < GPIO_SWT1_NP + MAX_SWITCHES)) {
  589. offset = -(GPIO_SWT1_NP - GPIO_SWT1);
  590. }
  591. if ((val >= GPIO_REL1) && (val < GPIO_REL1 + MAX_RELAYS)) {
  592. offset = (GPIO_REL1_INV - GPIO_REL1);
  593. }
  594. if ((val >= GPIO_REL1_INV) && (val < GPIO_REL1_INV + MAX_RELAYS)) {
  595. offset = -(GPIO_REL1_INV - GPIO_REL1);
  596. }
  597. if ((val >= GPIO_LED1) && (val < GPIO_LED1 + MAX_LEDS)) {
  598. offset = (GPIO_LED1_INV - GPIO_LED1);
  599. }
  600. if ((val >= GPIO_LED1_INV) && (val < GPIO_LED1_INV + MAX_LEDS)) {
  601. offset = -(GPIO_LED1_INV - GPIO_LED1);
  602. }
  603. if ((val >= GPIO_PWM1) && (val < GPIO_PWM1 + MAX_PWMS)) {
  604. offset = (GPIO_PWM1_INV - GPIO_PWM1);
  605. }
  606. if ((val >= GPIO_PWM1_INV) && (val < GPIO_PWM1_INV + MAX_PWMS)) {
  607. offset = -(GPIO_PWM1_INV - GPIO_PWM1);
  608. }
  609. if ((val >= GPIO_CNTR1) && (val < GPIO_CNTR1 + MAX_COUNTERS)) {
  610. offset = (GPIO_CNTR1_NP - GPIO_CNTR1);
  611. }
  612. if ((val >= GPIO_CNTR1_NP) && (val < GPIO_CNTR1_NP + MAX_COUNTERS)) {
  613. offset = -(GPIO_CNTR1_NP - GPIO_CNTR1);
  614. }
  615. for (byte i = 0; i < MAX_GPIO_PIN; i++) {
  616. if (arr[i] == val) { return true; }
  617. if (arr[i] == val + offset) { return true; }
  618. }
  619. return false;
  620. }
  621. void SetSerialBaudrate(int baudrate)
  622. {
  623. Settings.baudrate = baudrate / 1200;
  624. if (Serial.baudRate() != baudrate) {
  625. if (seriallog_level) {
  626. snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_SET_BAUDRATE_TO " %d"), baudrate);
  627. AddLog(LOG_LEVEL_INFO);
  628. }
  629. delay(100);
  630. Serial.flush();
  631. Serial.begin(baudrate, serial_config);
  632. delay(10);
  633. Serial.println();
  634. }
  635. }
  636. void ClaimSerial(void)
  637. {
  638. serial_local = 1;
  639. AddLog_P(LOG_LEVEL_INFO, PSTR("SNS: Hardware Serial"));
  640. SetSeriallog(LOG_LEVEL_NONE);
  641. baudrate = Serial.baudRate();
  642. Settings.baudrate = baudrate / 1200;
  643. }
  644. void SerialSendRaw(char *codes)
  645. {
  646. char *p;
  647. char stemp[3];
  648. uint8_t code;
  649. int size = strlen(codes);
  650. while (size > 0) {
  651. snprintf(stemp, sizeof(stemp), codes);
  652. code = strtol(stemp, &p, 16);
  653. Serial.write(code);
  654. size -= 2;
  655. codes += 2;
  656. }
  657. }
  658. uint32_t GetHash(const char *buffer, size_t size)
  659. {
  660. uint32_t hash = 0;
  661. for (uint16_t i = 0; i <= size; i++) {
  662. hash += (uint8_t)*buffer++ * (i +1);
  663. }
  664. return hash;
  665. }
  666. void ShowSource(int source)
  667. {
  668. if ((source > 0) && (source < SRC_MAX)) {
  669. char stemp1[20];
  670. snprintf_P(log_data, sizeof(log_data), PSTR("SRC: %s"), GetTextIndexed(stemp1, sizeof(stemp1), source, kCommandSource));
  671. AddLog(LOG_LEVEL_DEBUG);
  672. }
  673. }
  674. uint8_t ValidGPIO(uint8_t pin, uint8_t gpio)
  675. {
  676. uint8_t result = gpio;
  677. if ((WEMOS == Settings.module) && (!Settings.flag3.user_esp8285_enable)) {
  678. if ((pin == 9) || (pin == 10)) { result = GPIO_NONE; } // Disable possible flash GPIO9 and GPIO10
  679. }
  680. return result;
  681. }
  682. /*********************************************************************************************\
  683. * Sleep aware time scheduler functions borrowed from ESPEasy
  684. \*********************************************************************************************/
  685. long TimeDifference(unsigned long prev, unsigned long next)
  686. {
  687. // Return the time difference as a signed value, taking into account the timers may overflow.
  688. // Returned timediff is between -24.9 days and +24.9 days.
  689. // Returned value is positive when "next" is after "prev"
  690. long signed_diff = 0;
  691. // To cast a value to a signed long, the difference may not exceed half 0xffffffffUL (= 4294967294)
  692. const unsigned long half_max_unsigned_long = 2147483647u; // = 2^31 -1
  693. if (next >= prev) {
  694. const unsigned long diff = next - prev;
  695. if (diff <= half_max_unsigned_long) { // Normal situation, just return the difference.
  696. signed_diff = static_cast<long>(diff); // Difference is a positive value.
  697. } else {
  698. // prev has overflow, return a negative difference value
  699. signed_diff = static_cast<long>((0xffffffffUL - next) + prev + 1u);
  700. signed_diff = -1 * signed_diff;
  701. }
  702. } else {
  703. // next < prev
  704. const unsigned long diff = prev - next;
  705. if (diff <= half_max_unsigned_long) { // Normal situation, return a negative difference value
  706. signed_diff = static_cast<long>(diff);
  707. signed_diff = -1 * signed_diff;
  708. } else {
  709. // next has overflow, return a positive difference value
  710. signed_diff = static_cast<long>((0xffffffffUL - prev) + next + 1u);
  711. }
  712. }
  713. return signed_diff;
  714. }
  715. long TimePassedSince(unsigned long timestamp)
  716. {
  717. // Compute the number of milliSeconds passed since timestamp given.
  718. // Note: value can be negative if the timestamp has not yet been reached.
  719. return TimeDifference(timestamp, millis());
  720. }
  721. bool TimeReached(unsigned long timer)
  722. {
  723. // Check if a certain timeout has been reached.
  724. const long passed = TimePassedSince(timer);
  725. return (passed >= 0);
  726. }
  727. void SetNextTimeInterval(unsigned long& timer, const unsigned long step)
  728. {
  729. timer += step;
  730. const long passed = TimePassedSince(timer);
  731. if (passed < 0) { return; } // Event has not yet happened, which is fine.
  732. if (static_cast<unsigned long>(passed) > step) {
  733. // No need to keep running behind, start again.
  734. timer = millis() + step;
  735. return;
  736. }
  737. // Try to get in sync again.
  738. timer = millis() + (step - passed);
  739. }
  740. /*********************************************************************************************\
  741. * Basic I2C routines
  742. \*********************************************************************************************/
  743. #ifdef USE_I2C
  744. #define I2C_RETRY_COUNTER 3
  745. uint32_t i2c_buffer = 0;
  746. bool I2cValidRead(uint8_t addr, uint8_t reg, uint8_t size)
  747. {
  748. byte x = I2C_RETRY_COUNTER;
  749. i2c_buffer = 0;
  750. do {
  751. Wire.beginTransmission(addr); // start transmission to device
  752. Wire.write(reg); // sends register address to read from
  753. if (0 == Wire.endTransmission(false)) { // Try to become I2C Master, send data and collect bytes, keep master status for next request...
  754. Wire.requestFrom((int)addr, (int)size); // send data n-bytes read
  755. if (Wire.available() == size) {
  756. for (byte i = 0; i < size; i++) {
  757. i2c_buffer = i2c_buffer << 8 | Wire.read(); // receive DATA
  758. }
  759. }
  760. }
  761. x--;
  762. } while (Wire.endTransmission(true) != 0 && x != 0); // end transmission
  763. return (x);
  764. }
  765. bool I2cValidRead8(uint8_t *data, uint8_t addr, uint8_t reg)
  766. {
  767. bool status = I2cValidRead(addr, reg, 1);
  768. *data = (uint8_t)i2c_buffer;
  769. return status;
  770. }
  771. bool I2cValidRead16(uint16_t *data, uint8_t addr, uint8_t reg)
  772. {
  773. bool status = I2cValidRead(addr, reg, 2);
  774. *data = (uint16_t)i2c_buffer;
  775. return status;
  776. }
  777. bool I2cValidReadS16(int16_t *data, uint8_t addr, uint8_t reg)
  778. {
  779. bool status = I2cValidRead(addr, reg, 2);
  780. *data = (int16_t)i2c_buffer;
  781. return status;
  782. }
  783. bool I2cValidRead16LE(uint16_t *data, uint8_t addr, uint8_t reg)
  784. {
  785. uint16_t ldata;
  786. bool status = I2cValidRead16(&ldata, addr, reg);
  787. *data = (ldata >> 8) | (ldata << 8);
  788. return status;
  789. }
  790. bool I2cValidReadS16_LE(int16_t *data, uint8_t addr, uint8_t reg)
  791. {
  792. uint16_t ldata;
  793. bool status = I2cValidRead16LE(&ldata, addr, reg);
  794. *data = (int16_t)ldata;
  795. return status;
  796. }
  797. bool I2cValidRead24(int32_t *data, uint8_t addr, uint8_t reg)
  798. {
  799. bool status = I2cValidRead(addr, reg, 3);
  800. *data = i2c_buffer;
  801. return status;
  802. }
  803. uint8_t I2cRead8(uint8_t addr, uint8_t reg)
  804. {
  805. I2cValidRead(addr, reg, 1);
  806. return (uint8_t)i2c_buffer;
  807. }
  808. uint16_t I2cRead16(uint8_t addr, uint8_t reg)
  809. {
  810. I2cValidRead(addr, reg, 2);
  811. return (uint16_t)i2c_buffer;
  812. }
  813. int16_t I2cReadS16(uint8_t addr, uint8_t reg)
  814. {
  815. I2cValidRead(addr, reg, 2);
  816. return (int16_t)i2c_buffer;
  817. }
  818. uint16_t I2cRead16LE(uint8_t addr, uint8_t reg)
  819. {
  820. I2cValidRead(addr, reg, 2);
  821. uint16_t temp = (uint16_t)i2c_buffer;
  822. return (temp >> 8) | (temp << 8);
  823. }
  824. int16_t I2cReadS16_LE(uint8_t addr, uint8_t reg)
  825. {
  826. return (int16_t)I2cRead16LE(addr, reg);
  827. }
  828. int32_t I2cRead24(uint8_t addr, uint8_t reg)
  829. {
  830. I2cValidRead(addr, reg, 3);
  831. return i2c_buffer;
  832. }
  833. bool I2cWrite(uint8_t addr, uint8_t reg, uint32_t val, uint8_t size)
  834. {
  835. byte x = I2C_RETRY_COUNTER;
  836. do {
  837. Wire.beginTransmission((uint8_t)addr); // start transmission to device
  838. Wire.write(reg); // sends register address to write to
  839. uint8_t bytes = size;
  840. while (bytes--) {
  841. Wire.write((val >> (8 * bytes)) & 0xFF); // write data
  842. }
  843. x--;
  844. } while (Wire.endTransmission(true) != 0 && x != 0); // end transmission
  845. return (x);
  846. }
  847. bool I2cWrite8(uint8_t addr, uint8_t reg, uint16_t val)
  848. {
  849. return I2cWrite(addr, reg, val, 1);
  850. }
  851. bool I2cWrite16(uint8_t addr, uint8_t reg, uint16_t val)
  852. {
  853. return I2cWrite(addr, reg, val, 2);
  854. }
  855. int8_t I2cReadBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len)
  856. {
  857. Wire.beginTransmission((uint8_t)addr);
  858. Wire.write((uint8_t)reg);
  859. Wire.endTransmission();
  860. if (len != Wire.requestFrom((uint8_t)addr, (byte)len)) {
  861. return 1;
  862. }
  863. while (len--) {
  864. *reg_data = (uint8_t)Wire.read();
  865. reg_data++;
  866. }
  867. return 0;
  868. }
  869. int8_t I2cWriteBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len)
  870. {
  871. Wire.beginTransmission((uint8_t)addr);
  872. Wire.write((uint8_t)reg);
  873. while (len--) {
  874. Wire.write(*reg_data);
  875. reg_data++;
  876. }
  877. Wire.endTransmission();
  878. return 0;
  879. }
  880. void I2cScan(char *devs, unsigned int devs_len)
  881. {
  882. // Return error codes defined in twi.h and core_esp8266_si2c.c
  883. // I2C_OK 0
  884. // I2C_SCL_HELD_LOW 1 = SCL held low by another device, no procedure available to recover
  885. // I2C_SCL_HELD_LOW_AFTER_READ 2 = I2C bus error. SCL held low beyond slave clock stretch time
  886. // I2C_SDA_HELD_LOW 3 = I2C bus error. SDA line held low by slave/another_master after n bits
  887. // I2C_SDA_HELD_LOW_AFTER_INIT 4 = line busy. SDA again held low by another device. 2nd master?
  888. byte error = 0;
  889. byte address = 0;
  890. byte any = 0;
  891. snprintf_P(devs, devs_len, PSTR("{\"" D_CMND_I2CSCAN "\":\"" D_JSON_I2CSCAN_DEVICES_FOUND_AT));
  892. for (address = 1; address <= 127; address++) {
  893. Wire.beginTransmission(address);
  894. error = Wire.endTransmission();
  895. if (0 == error) {
  896. any = 1;
  897. snprintf_P(devs, devs_len, PSTR("%s 0x%02x"), devs, address);
  898. }
  899. else if (error != 2) { // Seems to happen anyway using this scan
  900. any = 2;
  901. snprintf_P(devs, devs_len, PSTR("{\"" D_CMND_I2CSCAN "\":\"Error %d at 0x%02x"), error, address);
  902. break;
  903. }
  904. }
  905. if (any) {
  906. strncat(devs, "\"}", devs_len - strlen(devs) -1);
  907. }
  908. else {
  909. snprintf_P(devs, devs_len, PSTR("{\"" D_CMND_I2CSCAN "\":\"" D_JSON_I2CSCAN_NO_DEVICES_FOUND "\"}"));
  910. }
  911. }
  912. boolean I2cDevice(byte addr)
  913. {
  914. for (byte address = 1; address <= 127; address++) {
  915. Wire.beginTransmission(address);
  916. if (!Wire.endTransmission() && (address == addr)) {
  917. return true;
  918. }
  919. }
  920. return false;
  921. }
  922. #endif // USE_I2C
  923. /*********************************************************************************************\
  924. * Syslog
  925. *
  926. * Example:
  927. * snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_LOG "Any value %d"), value);
  928. * AddLog(LOG_LEVEL_DEBUG);
  929. *
  930. \*********************************************************************************************/
  931. void SetSeriallog(byte loglevel)
  932. {
  933. Settings.seriallog_level = loglevel;
  934. seriallog_level = loglevel;
  935. seriallog_timer = 0;
  936. }
  937. #ifdef USE_WEBSERVER
  938. void GetLog(byte idx, char** entry_pp, size_t* len_p)
  939. {
  940. char* entry_p = NULL;
  941. size_t len = 0;
  942. if (idx) {
  943. char* it = web_log;
  944. do {
  945. byte cur_idx = *it;
  946. it++;
  947. size_t tmp = strchrspn(it, '\1');
  948. tmp++; // Skip terminating '\1'
  949. if (cur_idx == idx) { // Found the requested entry
  950. len = tmp;
  951. entry_p = it;
  952. break;
  953. }
  954. it += tmp;
  955. } while (it < web_log + WEB_LOG_SIZE && *it != '\0');
  956. }
  957. *entry_pp = entry_p;
  958. *len_p = len;
  959. }
  960. #endif // USE_WEBSERVER
  961. void Syslog(void)
  962. {
  963. // Destroys log_data
  964. char syslog_preamble[64]; // Hostname + Id
  965. if (syslog_host_hash != GetHash(Settings.syslog_host, strlen(Settings.syslog_host))) {
  966. syslog_host_hash = GetHash(Settings.syslog_host, strlen(Settings.syslog_host));
  967. WiFi.hostByName(Settings.syslog_host, syslog_host_addr); // If sleep enabled this might result in exception so try to do it once using hash
  968. }
  969. if (PortUdp.beginPacket(syslog_host_addr, Settings.syslog_port)) {
  970. snprintf_P(syslog_preamble, sizeof(syslog_preamble), PSTR("%s ESP-"), my_hostname);
  971. memmove(log_data + strlen(syslog_preamble), log_data, sizeof(log_data) - strlen(syslog_preamble));
  972. log_data[sizeof(log_data) -1] = '\0';
  973. memcpy(log_data, syslog_preamble, strlen(syslog_preamble));
  974. PortUdp.write(log_data);
  975. PortUdp.endPacket();
  976. } else {
  977. syslog_level = 0;
  978. syslog_timer = SYSLOG_TIMER;
  979. snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_SYSLOG_HOST_NOT_FOUND ". " D_RETRY_IN " %d " D_UNIT_SECOND), SYSLOG_TIMER);
  980. AddLog(LOG_LEVEL_INFO);
  981. }
  982. }
  983. void AddLog(byte loglevel)
  984. {
  985. char mxtime[10]; // "13:45:21 "
  986. snprintf_P(mxtime, sizeof(mxtime), PSTR("%02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d "), RtcTime.hour, RtcTime.minute, RtcTime.second);
  987. if (loglevel <= seriallog_level) {
  988. Serial.printf("%s%s\r\n", mxtime, log_data);
  989. }
  990. #ifdef USE_WEBSERVER
  991. if (Settings.webserver && (loglevel <= Settings.weblog_level)) {
  992. // Delimited, zero-terminated buffer of log lines.
  993. // Each entry has this format: [index][log data]['\1']
  994. if (!web_log_index) web_log_index++; // Index 0 is not allowed as it is the end of char string
  995. while (web_log_index == web_log[0] || // If log already holds the next index, remove it
  996. strlen(web_log) + strlen(log_data) + 13 > WEB_LOG_SIZE) // 13 = web_log_index + mxtime + '\1' + '\0'
  997. {
  998. char* it = web_log;
  999. it++; // Skip web_log_index
  1000. it += strchrspn(it, '\1'); // Skip log line
  1001. it++; // Skip delimiting "\1"
  1002. memmove(web_log, it, WEB_LOG_SIZE -(it-web_log)); // Move buffer forward to remove oldest log line
  1003. }
  1004. snprintf_P(web_log, sizeof(web_log), PSTR("%s%c%s%s\1"), web_log, web_log_index++, mxtime, log_data);
  1005. if (!web_log_index) web_log_index++; // Index 0 is not allowed as it is the end of char string
  1006. }
  1007. #endif // USE_WEBSERVER
  1008. if (!global_state.wifi_down && (loglevel <= syslog_level)) { Syslog(); }
  1009. }
  1010. void AddLog_P(byte loglevel, const char *formatP)
  1011. {
  1012. snprintf_P(log_data, sizeof(log_data), formatP);
  1013. AddLog(loglevel);
  1014. }
  1015. void AddLog_P(byte loglevel, const char *formatP, const char *formatP2)
  1016. {
  1017. char message[100];
  1018. snprintf_P(log_data, sizeof(log_data), formatP);
  1019. snprintf_P(message, sizeof(message), formatP2);
  1020. strncat(log_data, message, sizeof(log_data) - strlen(log_data) -1);
  1021. AddLog(loglevel);
  1022. }
  1023. void AddLogSerial(byte loglevel, uint8_t *buffer, int count)
  1024. {
  1025. snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_SERIAL D_RECEIVED));
  1026. for (int i = 0; i < count; i++) {
  1027. snprintf_P(log_data, sizeof(log_data), PSTR("%s %02X"), log_data, *(buffer++));
  1028. }
  1029. AddLog(loglevel);
  1030. }
  1031. void AddLogSerial(byte loglevel)
  1032. {
  1033. AddLogSerial(loglevel, (uint8_t*)serial_in_buffer, serial_in_byte_counter);
  1034. }
  1035. void AddLogMissed(char *sensor, uint8_t misses)
  1036. {
  1037. snprintf_P(log_data, sizeof(log_data), PSTR("SNS: %s missed %d"), sensor, SENSOR_MAX_MISS - misses);
  1038. AddLog(LOG_LEVEL_DEBUG);
  1039. }