server_ota.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682
  1. #include "defines.h"
  2. #include "server_ota.h"
  3. #include <string>
  4. #include <string.h>
  5. /* TODO Rethink the usage of the int watchdog. It is no longer to be used, see
  6. https://docs.espressif.com/projects/esp-idf/en/latest/esp32/migration-guides/release-5.x/5.0/system.html?highlight=esp_int_wdt */
  7. #include <esp_private/esp_int_wdt.h>
  8. #include <esp_task_wdt.h>
  9. #include <freertos/FreeRTOS.h>
  10. #include <freertos/task.h>
  11. #include <esp_system.h>
  12. #include <esp_log.h>
  13. #include <esp_ota_ops.h>
  14. #include <esp_http_client.h>
  15. #include <esp_flash_partitions.h>
  16. #include <esp_partition.h>
  17. #include <nvs.h>
  18. #include <esp_app_format.h>
  19. #include <nvs_flash.h>
  20. #include <driver/gpio.h>
  21. #include <errno.h>
  22. #include <sys/stat.h>
  23. #include "MainFlowControl.h"
  24. #include "server_file.h"
  25. #include "server_GPIO.h"
  26. #include "interface_mqtt.h"
  27. #include "ClassControllCamera.h"
  28. #include "connect_wifi_sta.h"
  29. #include "ClassLogFile.h"
  30. #include "Helper.h"
  31. #include "statusled.h"
  32. #include "basic_auth.h"
  33. /*an ota data write buffer ready to write to the flash*/
  34. static char ota_write_data[SERVER_OTA_SCRATCH_BUFSIZE + 1] = {0};
  35. static const char *TAG = "OTA";
  36. esp_err_t handler_reboot(httpd_req_t *req);
  37. static bool ota_update_task(std::string fn);
  38. std::string file_name_update;
  39. bool initial_setup = false;
  40. static void infinite_loop(void)
  41. {
  42. int i = 0;
  43. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "When a new firmware is available on the server, press the reset button to download it");
  44. while (1)
  45. {
  46. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Waiting for a new firmware... (" + to_string(++i) + ")");
  47. vTaskDelay(1000 / portTICK_PERIOD_MS);
  48. }
  49. }
  50. void task_do_Update_ZIP(void *pvParameter)
  51. {
  52. set_status_led(AP_OR_OTA, 1, true); // Signaling an OTA update
  53. std::string filetype = to_upper(get_file_type(file_name_update));
  54. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "File: " + file_name_update + " Filetype: " + filetype);
  55. if (filetype == "ZIP")
  56. {
  57. std::string in, outHtml, outHtmlTmp, outHtmlOld, outbin, zw, retfirmware;
  58. outHtml = "/sdcard/html";
  59. outHtmlTmp = "/sdcard/html_tmp";
  60. outHtmlOld = "/sdcard/html_old";
  61. outbin = "/sdcard/firmware";
  62. /* Remove the old and tmp html folder in case they still exist */
  63. remove_folder(outHtmlTmp.c_str(), TAG);
  64. remove_folder(outHtmlOld.c_str(), TAG);
  65. /* Extract the ZIP file. The content of the html folder gets extracted to the temporar folder html-temp. */
  66. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Extracting ZIP file " + file_name_update + "...");
  67. retfirmware = unzip_new(file_name_update, outHtmlTmp + "/", outHtml + "/", outbin + "/", "/sdcard/", initial_setup);
  68. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Files unzipped.");
  69. /* ZIP file got extracted, replace the old html folder with the new one */
  70. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Renaming folder " + outHtml + " to " + outHtmlOld + "...");
  71. rename_folder(outHtml, outHtmlOld);
  72. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Renaming folder " + outHtmlTmp + " to " + outHtml + "...");
  73. rename_folder(outHtmlTmp, outHtml);
  74. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Deleting folder " + outHtmlOld + "...");
  75. remove_folder(outHtmlOld.c_str(), TAG);
  76. if (retfirmware.length() > 0)
  77. {
  78. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Found firmware.bin");
  79. ota_update_task(retfirmware);
  80. }
  81. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Trigger reboot due to firmware update");
  82. doRebootOTA();
  83. }
  84. else if (filetype == "BIN")
  85. {
  86. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Do firmware update - file: " + file_name_update);
  87. ota_update_task(file_name_update);
  88. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Trigger reboot due to firmware update");
  89. doRebootOTA();
  90. }
  91. else
  92. {
  93. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Only ZIP-Files support for update during startup!");
  94. }
  95. }
  96. bool CheckOTAUpdateAvailability(void)
  97. {
  98. FILE *pFile = fopen("/sdcard/update.txt", "r");
  99. if (pFile == NULL)
  100. {
  101. LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "CheckOTAUpdateAvailability() - No pending update");
  102. return false;
  103. }
  104. char data_temp[1024] = "";
  105. fgets(data_temp, 1024, pFile);
  106. file_name_update = std::string(data_temp);
  107. if (fgets(data_temp, 1024, pFile))
  108. {
  109. std::string _data_temp = std::string(data_temp);
  110. if (_data_temp == "init")
  111. {
  112. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "CheckOTAUpdateAvailability() - Inital Setup triggered");
  113. }
  114. }
  115. fclose(pFile);
  116. delete_file("/sdcard/update.txt"); // Prevent Boot Loop!!!
  117. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "CheckOTAUpdateAvailability() - Start update process (" + file_name_update + ")");
  118. xTaskCreate(&task_do_Update_ZIP, "task_do_Update_ZIP", configMINIMAL_STACK_SIZE * 35, NULL, tskIDLE_PRIORITY + 1, NULL);
  119. while (1)
  120. {
  121. // wait until reboot within task_do_Update_ZIP
  122. vTaskDelay(1000 / portTICK_PERIOD_MS);
  123. }
  124. return true;
  125. }
  126. static bool ota_update_task(std::string fn)
  127. {
  128. esp_err_t err;
  129. /* update handle : set by esp_ota_begin(), must be freed via esp_ota_end() */
  130. esp_ota_handle_t update_handle = 0;
  131. const esp_partition_t *update_partition = NULL;
  132. ESP_LOGI(TAG, "Starting OTA update");
  133. const esp_partition_t *configured = esp_ota_get_boot_partition();
  134. const esp_partition_t *running = esp_ota_get_running_partition();
  135. if (configured != running)
  136. {
  137. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Configured OTA boot partition at offset " + to_string(configured->address) + ", but running from offset " + to_string(running->address));
  138. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "(This can happen if either the OTA boot data or preferred boot image become somehow corrupted.)");
  139. }
  140. ESP_LOGI(TAG, "Running partition type %d subtype %d (offset 0x%08x)",
  141. running->type, running->subtype, (unsigned int)running->address);
  142. update_partition = esp_ota_get_next_update_partition(NULL);
  143. ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%x", update_partition->subtype, (unsigned int)update_partition->address);
  144. int binary_file_length = 0;
  145. // deal with all receive packet
  146. bool image_header_was_checked = false;
  147. int data_read;
  148. FILE *f = fopen(fn.c_str(), "rb"); // previously only "r
  149. if (f == NULL)
  150. {
  151. // File does not exist
  152. return false;
  153. }
  154. data_read = fread(ota_write_data, 1, SERVER_OTA_SCRATCH_BUFSIZE, f);
  155. while (data_read > 0)
  156. {
  157. if (data_read < 0)
  158. {
  159. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Error: SSL data read error");
  160. return false;
  161. }
  162. else if (data_read > 0)
  163. {
  164. if (image_header_was_checked == false)
  165. {
  166. esp_app_desc_t new_app_info;
  167. if (data_read > sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t))
  168. {
  169. // check current version with downloading
  170. memcpy(&new_app_info, &ota_write_data[sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t)], sizeof(esp_app_desc_t));
  171. ESP_LOGI(TAG, "New firmware version: %s", new_app_info.version);
  172. esp_app_desc_t running_app_info;
  173. if (esp_ota_get_partition_description(running, &running_app_info) == ESP_OK)
  174. {
  175. ESP_LOGI(TAG, "Running firmware version: %s", running_app_info.version);
  176. }
  177. const esp_partition_t *last_invalid_app = esp_ota_get_last_invalid_partition();
  178. esp_app_desc_t invalid_app_info;
  179. if (esp_ota_get_partition_description(last_invalid_app, &invalid_app_info) == ESP_OK)
  180. {
  181. ESP_LOGI(TAG, "Last invalid firmware version: %s", invalid_app_info.version);
  182. }
  183. // check current version with last invalid partition
  184. if (last_invalid_app != NULL)
  185. {
  186. if (memcmp(invalid_app_info.version, new_app_info.version, sizeof(new_app_info.version)) == 0)
  187. {
  188. LogFile.WriteToFile(ESP_LOG_WARN, TAG, "New version is the same as invalid version");
  189. LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Previously, there was an attempt to launch the firmware with " + string(invalid_app_info.version) + " version, but it failed");
  190. LogFile.WriteToFile(ESP_LOG_WARN, TAG, "The firmware has been rolled back to the previous version");
  191. infinite_loop();
  192. }
  193. }
  194. image_header_was_checked = true;
  195. err = esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &update_handle);
  196. if (err != ESP_OK)
  197. {
  198. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "esp_ota_begin failed (" + string(esp_err_to_name(err)) + ")");
  199. return false;
  200. }
  201. ESP_LOGI(TAG, "esp_ota_begin succeeded");
  202. }
  203. else
  204. {
  205. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "received package is not fit len");
  206. return false;
  207. }
  208. }
  209. err = esp_ota_write(update_handle, (const void *)ota_write_data, data_read);
  210. if (err != ESP_OK)
  211. {
  212. return false;
  213. }
  214. binary_file_length += data_read;
  215. ESP_LOGD(TAG, "Written image length %d", binary_file_length);
  216. }
  217. else if (data_read == 0)
  218. {
  219. // * As esp_http_client_read never returns negative error code, we rely on
  220. // * `errno` to check for underlying transport connectivity closure if any
  221. if (errno == ECONNRESET || errno == ENOTCONN)
  222. {
  223. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Connection closed, errno = " + to_string(errno));
  224. break;
  225. }
  226. }
  227. data_read = fread(ota_write_data, 1, SERVER_OTA_SCRATCH_BUFSIZE, f);
  228. }
  229. fclose(f);
  230. ESP_LOGI(TAG, "Total Write binary data length: %d", binary_file_length);
  231. err = esp_ota_end(update_handle);
  232. if (err != ESP_OK)
  233. {
  234. if (err == ESP_ERR_OTA_VALIDATE_FAILED)
  235. {
  236. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Image validation failed, image is corrupted");
  237. }
  238. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "esp_ota_end failed (" + string(esp_err_to_name(err)) + ")!");
  239. return false;
  240. }
  241. err = esp_ota_set_boot_partition(update_partition);
  242. if (err != ESP_OK)
  243. {
  244. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "esp_ota_set_boot_partition failed (" + string(esp_err_to_name(err)) + ")!");
  245. }
  246. return true;
  247. }
  248. static void print_sha256(const uint8_t *image_hash, const char *label)
  249. {
  250. char hash_print[HASH_LEN * 2 + 1];
  251. hash_print[HASH_LEN * 2] = 0;
  252. for (int i = 0; i < HASH_LEN; ++i)
  253. {
  254. sprintf(&hash_print[i * 2], "%02x", image_hash[i]);
  255. }
  256. ESP_LOGI(TAG, "%s: %s", label, hash_print);
  257. }
  258. static bool diagnostic(void)
  259. {
  260. return true;
  261. }
  262. void CheckOTAUpdateStatus(void)
  263. {
  264. ESP_LOGI(TAG, "Start CheckOTAUpdateStatus...");
  265. uint8_t sha_256[HASH_LEN] = {0};
  266. esp_partition_t partition;
  267. // get sha256 digest for the partition table
  268. partition.address = ESP_PARTITION_TABLE_OFFSET;
  269. partition.size = ESP_PARTITION_TABLE_MAX_LEN;
  270. partition.type = ESP_PARTITION_TYPE_DATA;
  271. esp_partition_get_sha256(&partition, sha_256);
  272. print_sha256(sha_256, "SHA-256 for the partition table: ");
  273. // get sha256 digest for bootloader
  274. partition.address = ESP_BOOTLOADER_OFFSET;
  275. partition.size = ESP_PARTITION_TABLE_OFFSET;
  276. partition.type = ESP_PARTITION_TYPE_APP;
  277. esp_partition_get_sha256(&partition, sha_256);
  278. print_sha256(sha_256, "SHA-256 for bootloader: ");
  279. // get sha256 digest for running partition
  280. esp_partition_get_sha256(esp_ota_get_running_partition(), sha_256);
  281. print_sha256(sha_256, "SHA-256 for current firmware: ");
  282. const esp_partition_t *running = esp_ota_get_running_partition();
  283. esp_ota_img_states_t ota_state;
  284. esp_err_t res_stat_partition = esp_ota_get_state_partition(running, &ota_state);
  285. switch (res_stat_partition)
  286. {
  287. case ESP_OK:
  288. ESP_LOGD(TAG, "CheckOTAUpdateStatus Partition: ESP_OK");
  289. if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK)
  290. {
  291. if (ota_state == ESP_OTA_IMG_PENDING_VERIFY)
  292. {
  293. // run diagnostic function ...
  294. bool diagnostic_is_ok = diagnostic();
  295. if (diagnostic_is_ok)
  296. {
  297. ESP_LOGI(TAG, "Diagnostics completed successfully! Continuing execution...");
  298. esp_ota_mark_app_valid_cancel_rollback();
  299. }
  300. else
  301. {
  302. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Diagnostics failed! Start rollback to the previous version...");
  303. esp_ota_mark_app_invalid_rollback_and_reboot();
  304. }
  305. }
  306. }
  307. break;
  308. case ESP_ERR_INVALID_ARG:
  309. ESP_LOGD(TAG, "CheckOTAUpdateStatus Partition: ESP_ERR_INVALID_ARG");
  310. break;
  311. case ESP_ERR_NOT_SUPPORTED:
  312. ESP_LOGD(TAG, "CheckOTAUpdateStatus Partition: ESP_ERR_NOT_SUPPORTED");
  313. break;
  314. case ESP_ERR_NOT_FOUND:
  315. ESP_LOGD(TAG, "CheckOTAUpdateStatus Partition: ESP_ERR_NOT_FOUND");
  316. break;
  317. }
  318. if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK)
  319. {
  320. if (ota_state == ESP_OTA_IMG_PENDING_VERIFY)
  321. {
  322. // run diagnostic function ...
  323. bool diagnostic_is_ok = diagnostic();
  324. if (diagnostic_is_ok)
  325. {
  326. ESP_LOGI(TAG, "Diagnostics completed successfully! Continuing execution...");
  327. esp_ota_mark_app_valid_cancel_rollback();
  328. }
  329. else
  330. {
  331. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Diagnostics failed! Start rollback to the previous version...");
  332. esp_ota_mark_app_invalid_rollback_and_reboot();
  333. }
  334. }
  335. }
  336. }
  337. esp_err_t handler_ota_update(httpd_req_t *req)
  338. {
  339. LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "handler_ota_update");
  340. char _query[200];
  341. char _filename[100];
  342. char _valuechar[30];
  343. std::string fn = "/sdcard/firmware/";
  344. bool _file_del = false;
  345. std::string _task = "";
  346. if (httpd_req_get_url_query_str(req, _query, 200) == ESP_OK)
  347. {
  348. ESP_LOGD(TAG, "Query: %s", _query);
  349. if (httpd_query_key_value(_query, "task", _valuechar, 30) == ESP_OK)
  350. {
  351. ESP_LOGD(TAG, "task is found: %s", _valuechar);
  352. _task = std::string(_valuechar);
  353. }
  354. if (httpd_query_key_value(_query, "file", _filename, 100) == ESP_OK)
  355. {
  356. fn.append(_filename);
  357. ESP_LOGD(TAG, "File: %s", fn.c_str());
  358. }
  359. if (httpd_query_key_value(_query, "delete", _filename, 100) == ESP_OK)
  360. {
  361. fn.append(_filename);
  362. _file_del = true;
  363. ESP_LOGD(TAG, "Delete Default File: %s", fn.c_str());
  364. }
  365. }
  366. if (_task.compare("emptyfirmwaredir") == 0)
  367. {
  368. ESP_LOGD(TAG, "Start empty directory /firmware");
  369. delete_all_in_directory("/sdcard/firmware");
  370. std::string zw = "firmware directory deleted - v2\n";
  371. ESP_LOGD(TAG, "%s", zw.c_str());
  372. printf("Ausgabe: %s\n", zw.c_str());
  373. httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
  374. httpd_resp_send(req, zw.c_str(), strlen(zw.c_str()));
  375. /* Respond with an empty chunk to signal HTTP response completion */
  376. httpd_resp_send_chunk(req, NULL, 0);
  377. ESP_LOGD(TAG, "Done empty directory /firmware");
  378. return ESP_OK;
  379. }
  380. if (_task.compare("update") == 0)
  381. {
  382. std::string filetype = to_upper(get_file_type(fn));
  383. if (filetype.length() == 0)
  384. {
  385. std::string zw = "Update failed - no file specified (zip, bin, tfl, tlite)";
  386. httpd_resp_sendstr_chunk(req, zw.c_str());
  387. httpd_resp_sendstr_chunk(req, NULL);
  388. return ESP_OK;
  389. }
  390. if ((filetype == "TFLITE") || (filetype == "TFL"))
  391. {
  392. std::string out = "/sdcard/config/" + get_file_full_filename(fn);
  393. delete_file(out);
  394. copy_file(fn, out);
  395. delete_file(fn);
  396. const char *resp_str = "Neural Network File copied.";
  397. httpd_resp_sendstr_chunk(req, resp_str);
  398. httpd_resp_sendstr_chunk(req, NULL);
  399. return ESP_OK;
  400. }
  401. if ((filetype == "ZIP") || (filetype == "BIN"))
  402. {
  403. FILE *pfile;
  404. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Update for reboot");
  405. pfile = fopen("/sdcard/update.txt", "w");
  406. fwrite(fn.c_str(), fn.length(), 1, pfile);
  407. fclose(pfile);
  408. std::string zw = "reboot\n";
  409. httpd_resp_sendstr_chunk(req, zw.c_str());
  410. httpd_resp_sendstr_chunk(req, NULL);
  411. ESP_LOGD(TAG, "Send reboot");
  412. return ESP_OK;
  413. }
  414. std::string zw = "Update failed - no valid file specified (zip, bin, tfl, tlite)!";
  415. httpd_resp_sendstr_chunk(req, zw.c_str());
  416. httpd_resp_sendstr_chunk(req, NULL);
  417. return ESP_OK;
  418. }
  419. if (_task.compare("unziphtml") == 0)
  420. {
  421. ESP_LOGD(TAG, "Task unziphtml");
  422. std::string in, out, zw;
  423. in = "/sdcard/firmware/html.zip";
  424. out = "/sdcard/html";
  425. delete_all_in_directory(out);
  426. unzip(in, out + "/");
  427. zw = "Web Interface Update Successfull!\nNo reboot necessary";
  428. httpd_resp_send(req, zw.c_str(), strlen(zw.c_str()));
  429. httpd_resp_sendstr_chunk(req, NULL);
  430. return ESP_OK;
  431. }
  432. if (_file_del)
  433. {
  434. ESP_LOGD(TAG, "Delete !! _file_del: %s", fn.c_str());
  435. struct stat file_stat;
  436. int _result = stat(fn.c_str(), &file_stat);
  437. ESP_LOGD(TAG, "Ergebnis %d\n", _result);
  438. if (_result == 0)
  439. {
  440. ESP_LOGD(TAG, "Deleting file: %s", fn.c_str());
  441. /* Delete file */
  442. unlink(fn.c_str());
  443. }
  444. else
  445. {
  446. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "File does not exist: " + fn);
  447. }
  448. /* Respond with an empty chunk to signal HTTP response completion */
  449. std::string zw = "file deleted\n";
  450. ESP_LOGD(TAG, "%s", zw.c_str());
  451. httpd_resp_send(req, zw.c_str(), strlen(zw.c_str()));
  452. httpd_resp_send_chunk(req, NULL, 0);
  453. return ESP_OK;
  454. }
  455. string zw = "ota without parameter - should not be the case!";
  456. httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
  457. httpd_resp_send(req, zw.c_str(), strlen(zw.c_str()));
  458. httpd_resp_send_chunk(req, NULL, 0);
  459. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "ota without parameter - should not be the case!");
  460. return ESP_OK;
  461. }
  462. void hard_restart(void)
  463. {
  464. esp_task_wdt_config_t twdt_config = {
  465. .timeout_ms = 1,
  466. .idle_core_mask = (1 << portNUM_PROCESSORS) - 1, // Bitmask of all cores
  467. .trigger_panic = true,
  468. };
  469. ESP_ERROR_CHECK(esp_task_wdt_init(&twdt_config));
  470. esp_task_wdt_add(NULL);
  471. while (true)
  472. ;
  473. }
  474. void task_reboot(void *DeleteMainFlow)
  475. {
  476. // write a reboot, to identify a reboot by purpouse
  477. FILE *pfile = fopen("/sdcard/reboot.txt", "w");
  478. std::string data_temp = "reboot";
  479. fwrite(data_temp.c_str(), strlen(data_temp.c_str()), 1, pfile);
  480. fclose(pfile);
  481. vTaskDelay(3000 / portTICK_PERIOD_MS);
  482. if ((bool)DeleteMainFlow)
  483. {
  484. DeleteMainFlowTask(); // Kill autoflow task if executed in extra task, if not don't kill parent task
  485. }
  486. Camera.set_camera_deep_sleep(false);
  487. esp_camera_return_all();
  488. Camera.set_flash_light_on_off(false);
  489. set_status_led_off();
  490. /* Stop service tasks */
  491. MQTTdestroy_client(true);
  492. gpio_handler_destroy();
  493. wifi_deinit_sta();
  494. vTaskDelay(3000 / portTICK_PERIOD_MS);
  495. esp_restart(); // Reset type: CPU reset (Reset both CPUs)
  496. vTaskDelay(5000 / portTICK_PERIOD_MS);
  497. hard_restart(); // Reset type: System reset (Triggered by watchdog), if esp_restart stalls (WDT needs to be activated)
  498. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Reboot failed!");
  499. vTaskDelete(NULL); // Delete this task if it comes to this point
  500. }
  501. void doReboot(void)
  502. {
  503. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "doReboot() - Reboot triggered by Software (5s)");
  504. LogFile.WriteToFile(ESP_LOG_WARN, TAG, "doReboot() - Reboot in 5sec");
  505. while (*flowctrl.getActStatus() == std::string("Take Image"))
  506. {
  507. vTaskDelay(1000 / portTICK_PERIOD_MS);
  508. }
  509. BaseType_t xReturned = xTaskCreate(&task_reboot, "task_reboot", configMINIMAL_STACK_SIZE * 4, (void *)true, 10, NULL);
  510. if (xReturned != pdPASS)
  511. {
  512. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "task_reboot not created -> force reboot without killing flow");
  513. task_reboot((void *)false);
  514. }
  515. vTaskDelay(10000 / portTICK_PERIOD_MS); // Prevent serving web client fetch response until system is shuting down
  516. }
  517. void doRebootOTA(void)
  518. {
  519. LogFile.WriteToFile(ESP_LOG_WARN, TAG, "doRebootOTA() - Reboot in 5sec");
  520. while (*flowctrl.getActStatus() == std::string("Take Image"))
  521. {
  522. vTaskDelay(1000 / portTICK_PERIOD_MS);
  523. }
  524. DeleteMainFlowTask(); // Kill autoflow task if executed in extra task, if not don't kill parent task
  525. Camera.set_camera_deep_sleep(false);
  526. esp_camera_return_all();
  527. Camera.set_flash_light_on_off(false);
  528. set_status_led_off();
  529. /* Stop service tasks */
  530. MQTTdestroy_client(true);
  531. gpio_handler_destroy();
  532. wifi_deinit_sta();
  533. vTaskDelay(5000 / portTICK_PERIOD_MS);
  534. esp_restart(); // Reset type: CPU reset (Reset both CPUs)
  535. vTaskDelay(5000 / portTICK_PERIOD_MS);
  536. hard_restart(); // Reset type: System reset (Triggered by watchdog), if esp_restart stalls (WDT needs to be activated)
  537. }
  538. esp_err_t handler_reboot(httpd_req_t *req)
  539. {
  540. LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "handler_reboot");
  541. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "!!! System will restart within 5 sec!!!");
  542. std::string response =
  543. "<html><head><script>"
  544. "function m(h) {"
  545. "document.getElementById('t').innerHTML=h;"
  546. "setInterval(function (){h +='.'; document.getElementById('t').innerHTML=h;"
  547. "fetch('reboot_page.html',{mode: 'no-cors'}).then(r=>{parent.location.href=('index.html');})}, 1000);"
  548. "}</script></head></html><body style='font-family: arial'><h3 id=t></h3>"
  549. "<script>m('Rebooting!<br>The page will automatically reload in around 25..60s.<br><br>');</script>"
  550. "</body></html>";
  551. httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
  552. httpd_resp_send(req, response.c_str(), strlen(response.c_str()));
  553. doReboot();
  554. return ESP_OK;
  555. }
  556. void ota_register_uri(httpd_handle_t server)
  557. {
  558. ESP_LOGI(TAG, "Registering URI handlers");
  559. httpd_uri_t camuri = {};
  560. camuri.method = HTTP_GET;
  561. camuri.uri = "/ota";
  562. camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_ota_update);
  563. camuri.user_ctx = (void *)"Do OTA";
  564. httpd_register_uri_handler(server, &camuri);
  565. camuri.method = HTTP_GET;
  566. camuri.uri = "/reboot";
  567. camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_reboot);
  568. camuri.user_ctx = (void *)"Reboot";
  569. httpd_register_uri_handler(server, &camuri);
  570. }