main.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. //#include <string>
  2. //#include "freertos/FreeRTOS.h"
  3. //#include "freertos/task.h"
  4. //#include "freertos/event_groups.h"
  5. //#include "driver/gpio.h"
  6. //#include "sdkconfig.h"
  7. //#include "esp_psram.h" // Comming in IDF 5.0, see https://docs.espressif.com/projects/esp-idf/en/v5.0-beta1/esp32/migration-guides/release-5.x/system.html?highlight=esp_psram_get_size
  8. //#include "spiram.h"
  9. #include "esp32/spiram.h"
  10. // SD-Card ////////////////////
  11. //#include "nvs_flash.h"
  12. #include "esp_vfs_fat.h"
  13. //#include "sdmmc_cmd.h"
  14. #include "driver/sdmmc_host.h"
  15. //#include "driver/sdmmc_defs.h"
  16. ///////////////////////////////
  17. #include "ClassLogFile.h"
  18. #include "connect_wlan.h"
  19. #include "read_wlanini.h"
  20. #include "server_main.h"
  21. #include "server_tflite.h"
  22. #include "server_file.h"
  23. #include "server_ota.h"
  24. #include "time_sntp.h"
  25. //#include "ClassControllCamera.h"
  26. #include "server_main.h"
  27. #include "server_camera.h"
  28. #ifdef ENABLE_MQTT
  29. #include "server_mqtt.h"
  30. #endif //ENABLE_MQTT
  31. //#include "Helper.h"
  32. #include "../../include/defines.h"
  33. //#include "server_GPIO.h"
  34. #ifdef ENABLE_SOFTAP
  35. #include "softAP.h"
  36. #endif //ENABLE_SOFTAP
  37. #ifdef DISABLE_BROWNOUT_DETECTOR
  38. #include "soc/soc.h"
  39. #include "soc/rtc_cntl_reg.h"
  40. #endif
  41. #ifdef DEBUG_ENABLE_SYSINFO
  42. #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL( 4, 0, 0 )
  43. #include "esp_sys.h"
  44. #endif
  45. #endif //DEBUG_ENABLE_SYSINFO
  46. #ifdef USE_HIMEM_IF_AVAILABLE
  47. #include "esp32/himem.h"
  48. #ifdef DEBUG_HIMEM_MEMORY_CHECK
  49. #include "himem_memory_check.h"
  50. #endif
  51. #endif
  52. //#ifdef CONFIG_HEAP_TRACING_STANDALONE
  53. #if defined HEAP_TRACING_MAIN_WIFI || defined HEAP_TRACING_MAIN_START
  54. #include <esp_heap_trace.h>
  55. #define NUM_RECORDS 300
  56. static heap_trace_record_t trace_record[NUM_RECORDS]; // This buffer must be in internal RAM
  57. #endif
  58. extern const char* GIT_TAG;
  59. extern const char* GIT_REV;
  60. extern const char* GIT_BRANCH;
  61. extern const char* BUILD_TIME;
  62. extern std::string getFwVersion(void);
  63. extern std::string getHTMLversion(void);
  64. extern std::string getHTMLcommit(void);
  65. static const char *TAG = "MAIN";
  66. bool Init_NVS_SDCard()
  67. {
  68. esp_err_t ret = nvs_flash_init();
  69. if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
  70. ESP_ERROR_CHECK(nvs_flash_erase());
  71. ret = nvs_flash_init();
  72. }
  73. ////////////////////////////////////////////////
  74. ESP_LOGI(TAG, "Using SDMMC peripheral");
  75. sdmmc_host_t host = SDMMC_HOST_DEFAULT();
  76. // This initializes the slot without card detect (CD) and write protect (WP) signals.
  77. // Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
  78. sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
  79. // To use 1-line SD mode, uncomment the following line:
  80. #ifdef __SD_USE_ONE_LINE_MODE__
  81. slot_config.width = 1;
  82. #endif
  83. // GPIOs 15, 2, 4, 12, 13 should have external 10k pull-ups.
  84. // Internal pull-ups are not sufficient. However, enabling internal pull-ups
  85. // does make a difference some boards, so we do that here.
  86. gpio_set_pull_mode(GPIO_NUM_15, GPIO_PULLUP_ONLY); // CMD, needed in 4- and 1- line modes
  87. gpio_set_pull_mode(GPIO_NUM_2, GPIO_PULLUP_ONLY); // D0, needed in 4- and 1-line modes
  88. #ifndef __SD_USE_ONE_LINE_MODE__
  89. gpio_set_pull_mode(GPIO_NUM_4, GPIO_PULLUP_ONLY); // D1, needed in 4-line mode only
  90. gpio_set_pull_mode(GPIO_NUM_12, GPIO_PULLUP_ONLY); // D2, needed in 4-line mode only
  91. #endif
  92. gpio_set_pull_mode(GPIO_NUM_13, GPIO_PULLUP_ONLY); // D3, needed in 4- and 1-line modes
  93. // Options for mounting the filesystem.
  94. // If format_if_mount_failed is set to true, SD card will be partitioned and
  95. // formatted in case when mounting fails.
  96. esp_vfs_fat_sdmmc_mount_config_t mount_config = {
  97. .format_if_mount_failed = false,
  98. .max_files = 12, // previously -> 2022-09-21: 5, 2023-01-02: 7
  99. .allocation_unit_size = 16 * 1024
  100. };
  101. // Use settings defined above to initialize SD card and mount FAT filesystem.
  102. // Note: esp_vfs_fat_sdmmc_mount is an all-in-one convenience function.
  103. // Please check its source code and implement error recovery when developing
  104. // production applications.
  105. sdmmc_card_t* card;
  106. ret = esp_vfs_fat_sdmmc_mount("/sdcard", &host, &slot_config, &mount_config, &card);
  107. if (ret != ESP_OK) {
  108. if (ret == ESP_FAIL) {
  109. ESP_LOGE(TAG, "Failed to mount filesystem. "
  110. "If you want the card to be formatted, set format_if_mount_failed = true.");
  111. } else {
  112. ESP_LOGE(TAG, "Failed to initialize the card (%s). "
  113. "Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret));
  114. }
  115. return false;
  116. }
  117. sdmmc_card_print_info(stdout, card);
  118. SaveSDCardInfo(card);
  119. return true;
  120. }
  121. void task_MainInitError_blink(void *pvParameter)
  122. {
  123. gpio_pad_select_gpio(BLINK_GPIO);
  124. gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT);
  125. TickType_t xDelay;
  126. xDelay = 100 / portTICK_PERIOD_MS;
  127. ESP_LOGD(TAG, "SD-Card could not be inialized - STOP THE PROGRAMM HERE");
  128. while (1)
  129. {
  130. gpio_set_level(BLINK_GPIO, 1);
  131. vTaskDelay( xDelay );
  132. gpio_set_level(BLINK_GPIO, 0);
  133. vTaskDelay( xDelay );
  134. }
  135. vTaskDelete(NULL); //Delete this task if it exits from the loop above
  136. }
  137. extern "C" void app_main(void)
  138. {
  139. //#ifdef CONFIG_HEAP_TRACING_STANDALONE
  140. #if defined HEAP_TRACING_MAIN_WIFI || defined HEAP_TRACING_MAIN_START
  141. //register a buffer to record the memory trace
  142. ESP_ERROR_CHECK( heap_trace_init_standalone(trace_record, NUM_RECORDS) );
  143. #endif
  144. TickType_t xDelay;
  145. #ifdef DISABLE_BROWNOUT_DETECTOR
  146. WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
  147. #endif
  148. ESP_LOGI(TAG, "\n\n\n\n\n"); // Add mark on log to see when it restarted
  149. PowerResetCamera();
  150. esp_err_t camStatus = Camera.InitCam();
  151. Camera.LightOnOff(false);
  152. xDelay = 2000 / portTICK_PERIOD_MS;
  153. ESP_LOGD(TAG, "After camera initialization: sleep for: %ldms", (long) xDelay);
  154. vTaskDelay( xDelay );
  155. if (!Init_NVS_SDCard())
  156. {
  157. xTaskCreate(&task_MainInitError_blink, "task_MainInitError_blink", configMINIMAL_STACK_SIZE * 64, NULL, tskIDLE_PRIORITY+1, NULL);
  158. return; // No way to continue without SD-Card!
  159. }
  160. setupTime();
  161. string versionFormated = getFwVersion() + ", Date/Time: " + std::string(BUILD_TIME) + \
  162. ", Web UI: " + getHTMLversion();
  163. if (std::string(GIT_TAG) != "") { // We are on a tag, add it as prefix
  164. string versionFormated = "Tag: '" + std::string(GIT_TAG) + "', " + versionFormated;
  165. }
  166. LogFile.CreateLogDirectories();
  167. MakeDir("/sdcard/demo"); // needed for demo mode
  168. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "=================================================");
  169. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "==================== Startup ====================");
  170. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "=================================================");
  171. LogFile.WriteToFile(ESP_LOG_INFO, TAG, versionFormated);
  172. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Reset reason: " + getResetReason());
  173. #ifdef DEBUG_ENABLE_SYSINFO
  174. #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL( 4, 0, 0 )
  175. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Device Info : " + get_device_info() );
  176. ESP_LOGD(TAG, "Device infos %s", get_device_info().c_str());
  177. #endif
  178. #endif //DEBUG_ENABLE_SYSINFO
  179. #ifdef USE_HIMEM_IF_AVAILABLE
  180. #ifdef DEBUG_HIMEM_MEMORY_CHECK
  181. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Himem mem check : " + himem_memory_check() );
  182. ESP_LOGD(TAG, "Himem mem check %s", himem_memory_check().c_str());
  183. #endif
  184. #endif
  185. CheckIsPlannedReboot();
  186. CheckOTAUpdate();
  187. CheckUpdate();
  188. #ifdef ENABLE_SOFTAP
  189. CheckStartAPMode(); // if no wlan.ini and/or config.ini --> AP ist startet and this function does not exit anymore until reboot
  190. #endif
  191. #ifdef HEAP_TRACING_MAIN_WIFI
  192. ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) );
  193. #endif
  194. char *ssid = NULL, *passwd = NULL, *hostname = NULL, *ip = NULL, *gateway = NULL, *netmask = NULL, *dns = NULL; int rssithreashold = 0;
  195. LoadWlanFromFile(WLAN_CONFIG_FILE, ssid, passwd, hostname, ip, gateway, netmask, dns, rssithreashold);
  196. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "WLAN-Settings - RSSI-Threashold: " + to_string(rssithreashold));
  197. if (ssid != NULL && passwd != NULL)
  198. #ifdef __HIDE_PASSWORD
  199. ESP_LOGD(TAG, "WLan: %s, XXXXXX", ssid);
  200. #else
  201. ESP_LOGD(TAG, "WLan: %s, %s", ssid, passwd);
  202. #endif
  203. else
  204. ESP_LOGD(TAG, "No SSID and PASSWORD set!!!");
  205. if (hostname != NULL)
  206. ESP_LOGD(TAG, "Hostname: %s", hostname);
  207. else
  208. ESP_LOGD(TAG, "Hostname not set");
  209. if (ip != NULL && gateway != NULL && netmask != NULL)
  210. ESP_LOGD(TAG, "Fixed IP: %s, Gateway %s, Netmask %s", ip, gateway, netmask);
  211. if (dns != NULL)
  212. ESP_LOGD(TAG, "DNS IP: %s", dns);
  213. wifi_init_sta(ssid, passwd, hostname, ip, gateway, netmask, dns, rssithreashold);
  214. xDelay = 2000 / portTICK_PERIOD_MS;
  215. ESP_LOGD(TAG, "main: sleep for: %ldms", (long) xDelay);
  216. vTaskDelay( xDelay );
  217. #ifdef HEAP_TRACING_MAIN_WIFI
  218. ESP_ERROR_CHECK( heap_trace_stop() );
  219. heap_trace_dump();
  220. #endif
  221. #ifdef HEAP_TRACING_MAIN_START
  222. ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) );
  223. #endif
  224. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "=================================================");
  225. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "================== Main Started =================");
  226. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "=================================================");
  227. if (getHTMLcommit().substr(0, 7) != std::string(GIT_REV).substr(0, 7)) { // Compare the first 7 characters of both hashes
  228. LogFile.WriteToFile(ESP_LOG_WARN, TAG, std::string("Web UI version (") + getHTMLcommit() + ") does not match firmware version (" + std::string(GIT_REV) + ") !");
  229. LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Please make sure to setup the SD-Card properly (check the documentation) or re-install using the AI-on-the-edge-device__update__*.zip!");
  230. }
  231. std::string zw = getCurrentTimeString("%Y%m%d-%H%M%S");
  232. ESP_LOGD(TAG, "time %s", zw.c_str());
  233. #ifdef HEAP_TRACING_MAIN_START
  234. ESP_ERROR_CHECK( heap_trace_stop() );
  235. heap_trace_dump();
  236. #endif
  237. /* Check if PSRAM can be initalized */
  238. esp_err_t ret;
  239. ret = esp_spiram_init();
  240. if (ret == ESP_FAIL) { // Failed to init PSRAM, most likely not available or broken
  241. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to initialize PSRAM (" + std::to_string(ret) + ")!");
  242. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Either your device misses the PSRAM chip or it is broken!");
  243. setSystemStatusFlag(SYSTEM_STATUS_PSRAM_BAD);
  244. }
  245. else { // PSRAM init ok
  246. /* Check if PSRAM provides at least 4 MB */
  247. size_t psram_size = esp_spiram_get_size();
  248. // size_t psram_size = esp_psram_get_size(); // comming in IDF 5.0
  249. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "The device has " + std::to_string(psram_size/1024/1024) + " MBytes of PSRAM");
  250. if (psram_size < (4*1024*1024)) { // PSRAM is below 4 MBytes
  251. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "At least 4 MBytes are required!");
  252. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Does the device really have a 4 Mbytes PSRAM?");
  253. setSystemStatusFlag(SYSTEM_STATUS_PSRAM_BAD);
  254. }
  255. }
  256. /* Check available Heap memory */
  257. size_t _hsize = getESPHeapSize();
  258. if (_hsize < 4000000) { // Check available Heap memory for a bit less than 4 MB (a test on a good device showed 4187558 bytes to be available)
  259. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Not enough Heap memory available. Expected around 4 MBytes, but only " + std::to_string(_hsize) + " Bytes are available! That is not enough for this firmware!");
  260. setSystemStatusFlag(SYSTEM_STATUS_HEAP_TOO_SMALL);
  261. } else { // Heap memory is ok
  262. if (camStatus != ESP_OK) {
  263. LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Failed to initialize camera module, retrying...");
  264. PowerResetCamera();
  265. esp_err_t camStatus = Camera.InitCam();
  266. Camera.LightOnOff(false);
  267. xDelay = 2000 / portTICK_PERIOD_MS;
  268. ESP_LOGD(TAG, "After camera initialization: sleep for: %ldms", (long) xDelay);
  269. vTaskDelay( xDelay );
  270. if (camStatus != ESP_OK) {
  271. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to initialize camera module!");
  272. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Check that your camera module is working and connected properly!");
  273. setSystemStatusFlag(SYSTEM_STATUS_CAM_BAD);
  274. }
  275. } else { // Test Camera
  276. if (!Camera.testCamera()) {
  277. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Camera Framebuffer cannot be initialized!");
  278. /* Easiest would be to simply restart here and try again,
  279. how ever there seem to be systems where it fails at startup but still work corectly later.
  280. Therefore we treat it still as successed! */
  281. setSystemStatusFlag(SYSTEM_STATUS_CAM_FB_BAD);
  282. }
  283. else {
  284. Camera.LightOnOff(false);
  285. }
  286. }
  287. }
  288. xDelay = 2000 / portTICK_PERIOD_MS;
  289. ESP_LOGD(TAG, "main: sleep for: %ldms", (long) xDelay*10);
  290. vTaskDelay( xDelay );
  291. ESP_LOGD(TAG, "starting servers");
  292. server = start_webserver();
  293. register_server_camera_uri(server);
  294. register_server_tflite_uri(server);
  295. register_server_file_uri(server, "/sdcard");
  296. register_server_ota_sdcard_uri(server);
  297. #ifdef ENABLE_MQTT
  298. register_server_mqtt_uri(server);
  299. #endif //ENABLE_MQTT
  300. gpio_handler_create(server);
  301. ESP_LOGD(TAG, "Before reg server main");
  302. register_server_main_uri(server, "/sdcard");
  303. /* Testing */
  304. //setSystemStatusFlag(SYSTEM_STATUS_CAM_FB_BAD);
  305. //setSystemStatusFlag(SYSTEM_STATUS_PSRAM_BAD);
  306. /* Main Init has successed or only an error which allows to continue operation */
  307. if (getSystemStatus() == 0) { // No error flag is set
  308. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Initialization completed successfully!");
  309. ESP_LOGD(TAG, "Before do autostart");
  310. TFliteDoAutoStart();
  311. }
  312. else if (isSetSystemStatusFlag(SYSTEM_STATUS_CAM_FB_BAD) || // Non critical errors occured, we try to continue...
  313. isSetSystemStatusFlag(SYSTEM_STATUS_NTP_BAD)) {
  314. LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Initialization completed with errors, but trying to continue...");
  315. ESP_LOGD(TAG, "Before do autostart");
  316. TFliteDoAutoStart();
  317. }
  318. else { // Any other error is critical and makes running the flow impossible.
  319. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Initialization failed. Not starting flows!");
  320. }
  321. }