server_main.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. #include "server_main.h"
  2. #include <string>
  3. #include "server_help.h"
  4. #include "ClassLogFile.h"
  5. #include "time_sntp.h"
  6. #include "connect_wlan.h"
  7. #include "read_wlanini.h"
  8. #include "version.h"
  9. #include "esp_wifi.h"
  10. #include <netdb.h>
  11. #include "MainFlowControl.h"
  12. #include "esp_log.h"
  13. #include "esp_chip_info.h"
  14. #include <stdio.h>
  15. #include "Helper.h"
  16. httpd_handle_t server = NULL;
  17. std::string starttime = "";
  18. static const char *TAG = "MAIN SERVER";
  19. /* An HTTP GET handler */
  20. esp_err_t info_get_handler(httpd_req_t *req)
  21. {
  22. #ifdef DEBUG_DETAIL_ON
  23. LogFile.WriteHeapInfo("info_get_handler - Start");
  24. #endif
  25. LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "info_get_handler");
  26. char _query[200];
  27. char _valuechar[30];
  28. std::string _task;
  29. if (httpd_req_get_url_query_str(req, _query, 200) != ESP_OK)
  30. {
  31. return httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "invalid query string");
  32. }
  33. ESP_LOGD(TAG, "Query: %s", _query);
  34. if (httpd_query_key_value(_query, "type", _valuechar, 30) != ESP_OK)
  35. {
  36. return httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "missing or invalid 'type' query parameter (too long value?)");
  37. }
  38. ESP_LOGD(TAG, "type is found: %s", _valuechar);
  39. _task = std::string(_valuechar);
  40. httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
  41. if (_task.compare("GitBranch") == 0)
  42. {
  43. httpd_resp_sendstr(req, libfive_git_branch());
  44. return ESP_OK;
  45. }
  46. else if (_task.compare("GitTag") == 0)
  47. {
  48. httpd_resp_sendstr(req, libfive_git_version());
  49. return ESP_OK;
  50. }
  51. else if (_task.compare("GitRevision") == 0)
  52. {
  53. httpd_resp_sendstr(req, libfive_git_revision());
  54. return ESP_OK;
  55. }
  56. else if (_task.compare("BuildTime") == 0)
  57. {
  58. httpd_resp_sendstr(req, build_time());
  59. return ESP_OK;
  60. }
  61. else if (_task.compare("FirmwareVersion") == 0)
  62. {
  63. httpd_resp_sendstr(req, getFwVersion().c_str());
  64. return ESP_OK;
  65. }
  66. else if (_task.compare("HTMLVersion") == 0)
  67. {
  68. httpd_resp_sendstr(req, getHTMLversion().c_str());
  69. return ESP_OK;
  70. }
  71. else if (_task.compare("Hostname") == 0)
  72. {
  73. std::string zw;
  74. zw = std::string(wlan_config.hostname);
  75. httpd_resp_sendstr(req, zw.c_str());
  76. return ESP_OK;
  77. }
  78. else if (_task.compare("IP") == 0)
  79. {
  80. std::string *zw;
  81. zw = getIPAddress();
  82. httpd_resp_sendstr(req, zw->c_str());
  83. return ESP_OK;
  84. }
  85. else if (_task.compare("SSID") == 0)
  86. {
  87. std::string *zw;
  88. zw = getSSID();
  89. httpd_resp_sendstr(req, zw->c_str());
  90. return ESP_OK;
  91. }
  92. else if (_task.compare("FlowStatus") == 0)
  93. {
  94. std::string zw;
  95. zw = std::string("FlowStatus");
  96. httpd_resp_sendstr(req, zw.c_str());
  97. return ESP_OK;
  98. }
  99. else if (_task.compare("Round") == 0)
  100. {
  101. char formated[10] = "";
  102. snprintf(formated, sizeof(formated), "%d", getCountFlowRounds());
  103. httpd_resp_sendstr(req, formated);
  104. return ESP_OK;
  105. }
  106. else if (_task.compare("SDCardPartitionSize") == 0)
  107. {
  108. std::string zw;
  109. zw = getSDCardPartitionSize();
  110. httpd_resp_sendstr(req, zw.c_str());
  111. return ESP_OK;
  112. }
  113. else if (_task.compare("SDCardFreePartitionSpace") == 0)
  114. {
  115. std::string zw;
  116. zw = getSDCardFreePartitionSpace();
  117. httpd_resp_sendstr(req, zw.c_str());
  118. return ESP_OK;
  119. }
  120. else if (_task.compare("SDCardPartitionAllocationSize") == 0)
  121. {
  122. std::string zw;
  123. zw = getSDCardPartitionAllocationSize();
  124. httpd_resp_sendstr(req, zw.c_str());
  125. return ESP_OK;
  126. }
  127. else if (_task.compare("SDCardManufacturer") == 0)
  128. {
  129. std::string zw;
  130. zw = getSDCardManufacturer();
  131. httpd_resp_sendstr(req, zw.c_str());
  132. return ESP_OK;
  133. }
  134. else if (_task.compare("SDCardName") == 0)
  135. {
  136. std::string zw;
  137. zw = getSDCardName();
  138. httpd_resp_sendstr(req, zw.c_str());
  139. return ESP_OK;
  140. }
  141. else if (_task.compare("SDCardCapacity") == 0)
  142. {
  143. std::string zw;
  144. zw = getSDCardCapacity();
  145. httpd_resp_sendstr(req, zw.c_str());
  146. return ESP_OK;
  147. }
  148. else if (_task.compare("SDCardSectorSize") == 0)
  149. {
  150. std::string zw;
  151. zw = getSDCardSectorSize();
  152. httpd_resp_sendstr(req, zw.c_str());
  153. return ESP_OK;
  154. }
  155. else if (_task.compare("ChipCores") == 0)
  156. {
  157. esp_chip_info_t chipInfo;
  158. esp_chip_info(&chipInfo);
  159. httpd_resp_sendstr(req, to_string(chipInfo.cores).c_str());
  160. return ESP_OK;
  161. }
  162. else if (_task.compare("ChipRevision") == 0)
  163. {
  164. esp_chip_info_t chipInfo;
  165. esp_chip_info(&chipInfo);
  166. httpd_resp_sendstr(req, to_string(chipInfo.revision).c_str());
  167. return ESP_OK;
  168. }
  169. else if (_task.compare("ChipFeatures") == 0)
  170. {
  171. esp_chip_info_t chipInfo;
  172. esp_chip_info(&chipInfo);
  173. httpd_resp_sendstr(req, to_string(chipInfo.features).c_str());
  174. return ESP_OK;
  175. }
  176. else
  177. {
  178. char formatted[256];
  179. snprintf(formatted, sizeof(formatted), "Unknown value for parameter info 'type': '%s'\n", _task.c_str());
  180. return httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, formatted);
  181. }
  182. return ESP_OK;
  183. }
  184. esp_err_t starttime_get_handler(httpd_req_t *req)
  185. {
  186. httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
  187. httpd_resp_send(req, starttime.c_str(), starttime.length());
  188. return ESP_OK;
  189. }
  190. esp_err_t hello_main_handler(httpd_req_t *req)
  191. {
  192. #ifdef DEBUG_DETAIL_ON
  193. LogFile.WriteHeapInfo("hello_main_handler - Start");
  194. #endif
  195. char filepath[50];
  196. ESP_LOGD(TAG, "uri: %s\n", req->uri);
  197. int _pos;
  198. esp_err_t res;
  199. char *base_path = (char*) req->user_ctx;
  200. std::string filetosend(base_path);
  201. const char *filename = get_path_from_uri(filepath, base_path,
  202. req->uri - 1, sizeof(filepath));
  203. ESP_LOGD(TAG, "1 uri: %s, filename: %s, filepath: %s", req->uri, filename, filepath);
  204. if ((strcmp(req->uri, "/") == 0))
  205. {
  206. {
  207. filetosend = filetosend + "/html/index.html";
  208. }
  209. }
  210. else
  211. {
  212. filetosend = filetosend + "/html" + std::string(req->uri);
  213. _pos = filetosend.find("?");
  214. if (_pos > -1){
  215. filetosend = filetosend.substr(0, _pos);
  216. }
  217. }
  218. if (filetosend == "/sdcard/html/index.html") {
  219. if (isSetSystemStatusFlag(SYSTEM_STATUS_PSRAM_BAD) || // Initialization failed with crritical errors!
  220. isSetSystemStatusFlag(SYSTEM_STATUS_CAM_BAD) ||
  221. isSetSystemStatusFlag(SYSTEM_STATUS_SDCARD_CHECK_BAD) ||
  222. isSetSystemStatusFlag(SYSTEM_STATUS_FOLDER_CHECK_BAD))
  223. {
  224. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "We have a critical error, not serving main page!");
  225. char buf[20];
  226. std::string message = "<h1>AI on the Edge Device</h1><b>We have one or more critical errors:</b><br>";
  227. for (int i = 0; i < 32; i++) {
  228. if (isSetSystemStatusFlag((SystemStatusFlag_t)(1<<i))) {
  229. snprintf(buf, sizeof(buf), "0x%08X", 1<<i);
  230. message += std::string(buf) + "<br>";
  231. }
  232. }
  233. message += "<br>Please check logs with log viewer and/or <a href=\"https://jomjol.github.io/AI-on-the-edge-device-docs/Error-Codes\" target=_blank>jomjol.github.io/AI-on-the-edge-device-docs/Error-Codes</a> for more information!";
  234. message += "<br><br><button onclick=\"window.location.href='/reboot';\">Reboot</button>";
  235. message += "&nbsp;<button onclick=\"window.open('/ota_page.html');\">OTA Update</button>";
  236. message += "&nbsp;<button onclick=\"window.open('/log.html');\">Log Viewer</button>";
  237. message += "&nbsp;<button onclick=\"window.open('/info.html');\">Show System Info</button>";
  238. httpd_resp_send(req, message.c_str(), message.length());
  239. return ESP_OK;
  240. }
  241. else if (isSetupModusActive()) {
  242. ESP_LOGD(TAG, "System is in setup mode --> index.html --> setup.html");
  243. filetosend = "/sdcard/html/setup.html";
  244. }
  245. }
  246. ESP_LOGD(TAG, "Filename: %s", filename);
  247. ESP_LOGD(TAG, "File requested: %s", filetosend.c_str());
  248. if (!filename) {
  249. ESP_LOGE(TAG, "Filename is too long");
  250. /* Respond with 414 Error */
  251. httpd_resp_send_err(req, HTTPD_414_URI_TOO_LONG, "Filename too long");
  252. return ESP_FAIL;
  253. }
  254. res = send_file(req, filetosend);
  255. /* Respond with an empty chunk to signal HTTP response completion */
  256. httpd_resp_send_chunk(req, NULL, 0);
  257. if (res != ESP_OK)
  258. return res;
  259. /* Respond with an empty chunk to signal HTTP response completion */
  260. // httpd_resp_sendstr(req, "");
  261. // httpd_resp_send_chunk(req, NULL, 0);
  262. #ifdef DEBUG_DETAIL_ON
  263. LogFile.WriteHeapInfo("hello_main_handler - Stop");
  264. #endif
  265. return ESP_OK;
  266. }
  267. esp_err_t img_tmp_handler(httpd_req_t *req)
  268. {
  269. char filepath[50];
  270. ESP_LOGD(TAG, "uri: %s", req->uri);
  271. char *base_path = (char*) req->user_ctx;
  272. std::string filetosend(base_path);
  273. const char *filename = get_path_from_uri(filepath, base_path,
  274. req->uri + sizeof("/img_tmp/") - 1, sizeof(filepath));
  275. ESP_LOGD(TAG, "1 uri: %s, filename: %s, filepath: %s", req->uri, filename, filepath);
  276. filetosend = filetosend + "/img_tmp/" + std::string(filename);
  277. ESP_LOGD(TAG, "File to upload: %s", filetosend.c_str());
  278. esp_err_t res = send_file(req, filetosend);
  279. if (res != ESP_OK)
  280. return res;
  281. /* Respond with an empty chunk to signal HTTP response completion */
  282. httpd_resp_send_chunk(req, NULL, 0);
  283. return ESP_OK;
  284. }
  285. esp_err_t img_tmp_virtual_handler(httpd_req_t *req)
  286. {
  287. #ifdef DEBUG_DETAIL_ON
  288. LogFile.WriteHeapInfo("img_tmp_virtual_handler - Start");
  289. #endif
  290. char filepath[50];
  291. ESP_LOGD(TAG, "uri: %s", req->uri);
  292. char *base_path = (char*) req->user_ctx;
  293. std::string filetosend(base_path);
  294. const char *filename = get_path_from_uri(filepath, base_path,
  295. req->uri + sizeof("/img_tmp/") - 1, sizeof(filepath));
  296. ESP_LOGD(TAG, "1 uri: %s, filename: %s, filepath: %s", req->uri, filename, filepath);
  297. filetosend = std::string(filename);
  298. ESP_LOGD(TAG, "File to upload: %s", filetosend.c_str());
  299. // Serve raw.jpg
  300. if (filetosend == "raw.jpg")
  301. return GetRawJPG(req);
  302. // Serve alg.jpg, alg_roi.jpg or digit and analog ROIs
  303. if (ESP_OK == GetJPG(filetosend, req))
  304. return ESP_OK;
  305. #ifdef DEBUG_DETAIL_ON
  306. LogFile.WriteHeapInfo("img_tmp_virtual_handler - Done");
  307. #endif
  308. // File was not served already --> serve with img_tmp_handler
  309. return img_tmp_handler(req);
  310. }
  311. esp_err_t sysinfo_handler(httpd_req_t *req)
  312. {
  313. std::string zw;
  314. std::string cputemp = std::to_string((int)temperatureRead());
  315. std::string gitversion = libfive_git_version();
  316. std::string buildtime = build_time();
  317. std::string gitbranch = libfive_git_branch();
  318. std::string gittag = libfive_git_version();
  319. std::string gitrevision = libfive_git_revision();
  320. std::string htmlversion = getHTMLversion();
  321. char freeheapmem[11];
  322. sprintf(freeheapmem, "%lu", (long) getESPHeapSize());
  323. zw = string("[{") +
  324. "\"firmware\": \"" + gitversion + "\"," +
  325. "\"buildtime\": \"" + buildtime + "\"," +
  326. "\"gitbranch\": \"" + gitbranch + "\"," +
  327. "\"gittag\": \"" + gittag + "\"," +
  328. "\"gitrevision\": \"" + gitrevision + "\"," +
  329. "\"html\": \"" + htmlversion + "\"," +
  330. "\"cputemp\": \"" + cputemp + "\"," +
  331. "\"hostname\": \"" + *getHostname() + "\"," +
  332. "\"IPv4\": \"" + *getIPAddress() + "\"," +
  333. "\"freeHeapMem\": \"" + freeheapmem + "\"" +
  334. "}]";
  335. httpd_resp_set_type(req, "application/json");
  336. httpd_resp_send(req, zw.c_str(), zw.length());
  337. return ESP_OK;
  338. }
  339. void register_server_main_uri(httpd_handle_t server, const char *base_path)
  340. {
  341. httpd_uri_t info_get_handle = {
  342. .uri = "/info", // Match all URIs of type /path/to/file
  343. .method = HTTP_GET,
  344. .handler = info_get_handler,
  345. .user_ctx = (void*) base_path // Pass server data as context
  346. };
  347. httpd_register_uri_handler(server, &info_get_handle);
  348. httpd_uri_t sysinfo_handle = {
  349. .uri = "/sysinfo", // Match all URIs of type /path/to/file
  350. .method = HTTP_GET,
  351. .handler = sysinfo_handler,
  352. .user_ctx = (void*) base_path // Pass server data as context
  353. };
  354. httpd_register_uri_handler(server, &sysinfo_handle);
  355. httpd_uri_t starttime_tmp_handle = {
  356. .uri = "/starttime", // Match all URIs of type /path/to/file
  357. .method = HTTP_GET,
  358. .handler = starttime_get_handler,
  359. .user_ctx = NULL // Pass server data as context
  360. };
  361. httpd_register_uri_handler(server, &starttime_tmp_handle);
  362. httpd_uri_t img_tmp_handle = {
  363. .uri = "/img_tmp/*", // Match all URIs of type /path/to/file
  364. .method = HTTP_GET,
  365. .handler = img_tmp_virtual_handler,
  366. .user_ctx = (void*) base_path // Pass server data as context
  367. };
  368. httpd_register_uri_handler(server, &img_tmp_handle);
  369. httpd_uri_t main_rest_handle = {
  370. .uri = "/*", // Match all URIs of type /path/to/file
  371. .method = HTTP_GET,
  372. .handler = hello_main_handler,
  373. .user_ctx = (void*) base_path // Pass server data as context
  374. };
  375. httpd_register_uri_handler(server, &main_rest_handle);
  376. }
  377. httpd_handle_t start_webserver(void)
  378. {
  379. httpd_handle_t server = NULL;
  380. httpd_config_t config = HTTPD_DEFAULT_CONFIG();
  381. config.task_priority = tskIDLE_PRIORITY+3; // previously -> 2022-12-11: tskIDLE_PRIORITY+1; 2021-09-24: tskIDLE_PRIORITY+5
  382. config.stack_size = 12288; // previously -> 2023-01-02: 32768
  383. config.core_id = 1; // previously -> 2023-01-02: 0, 2022-12-11: tskNO_AFFINITY;
  384. config.server_port = 80;
  385. config.ctrl_port = 32768;
  386. config.max_open_sockets = 5; //20210921 --> previously 7
  387. config.max_uri_handlers = 40; // Make sure this fits all URI handlers. Memory usage in bytes: 6*max_uri_handlers
  388. config.max_resp_headers = 8;
  389. config.backlog_conn = 5;
  390. config.lru_purge_enable = true; // this cuts old connections if new ones are needed.
  391. config.recv_wait_timeout = 5; // default: 5 20210924 --> previously 30
  392. config.send_wait_timeout = 5; // default: 5 20210924 --> previously 30
  393. config.global_user_ctx = NULL;
  394. config.global_user_ctx_free_fn = NULL;
  395. config.global_transport_ctx = NULL;
  396. config.global_transport_ctx_free_fn = NULL;
  397. config.open_fn = NULL;
  398. config.close_fn = NULL;
  399. // config.uri_match_fn = NULL;
  400. config.uri_match_fn = httpd_uri_match_wildcard;
  401. starttime = getCurrentTimeString("%Y%m%d-%H%M%S");
  402. // Start the httpd server
  403. ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port);
  404. if (httpd_start(&server, &config) == ESP_OK) {
  405. // Set URI handlers
  406. ESP_LOGI(TAG, "Registering URI handlers");
  407. return server;
  408. }
  409. ESP_LOGI(TAG, "Error starting server!");
  410. return NULL;
  411. }
  412. void stop_webserver(httpd_handle_t server)
  413. {
  414. httpd_stop(server);
  415. }
  416. void disconnect_handler(void* arg, esp_event_base_t event_base,
  417. int32_t event_id, void* event_data)
  418. {
  419. httpd_handle_t* server = (httpd_handle_t*) arg;
  420. if (*server) {
  421. ESP_LOGI(TAG, "Stopping webserver");
  422. stop_webserver(*server);
  423. *server = NULL;
  424. }
  425. }
  426. void connect_handler(void* arg, esp_event_base_t event_base,
  427. int32_t event_id, void* event_data)
  428. {
  429. httpd_handle_t* server = (httpd_handle_t*) arg;
  430. if (*server == NULL) {
  431. ESP_LOGI(TAG, "Starting webserver");
  432. *server = start_webserver();
  433. }
  434. }