ESP32 Native version of Blinky, featureful controller code for WS2811/WS2812/NeoPixels
No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

164 líneas
4.6KB

  1. static const char *TAG = "ota";
  2. #include <esp_log.h>
  3. #include <mdns.h>
  4. #include <esp_ota_ops.h>
  5. #include <freertos/FreeRTOS.h>
  6. #include <freertos/task.h>
  7. #include "ota.hpp"
  8. // The real version probably lives somewhere else. Too lazy to find it
  9. template <class T> static inline T MIN(T a, T b) { return a < b ? a : b; }
  10. // TODO: Stick this somewhere useful?
  11. static void reboot_soon_task(void*) {
  12. int delay_s = 1;
  13. ESP_LOGI(TAG, "Rebooting in %d second%s",
  14. delay_s, delay_s == 1 ? "" : "s");
  15. vTaskDelay(pdMS_TO_TICKS(delay_s * 1000));
  16. esp_restart();
  17. }
  18. static void reboot_soon() {
  19. xTaskCreate(
  20. reboot_soon_task, "reboot_task",
  21. configMINIMAL_STACK_SIZE * 2, // TODO: Choose the best size
  22. NULL, 1, NULL
  23. );
  24. }
  25. // HTTP Server Helpers.
  26. // TODO: Share these?
  27. static inline esp_err_t serv_err(httpd_req_t *req, const char *msg) {
  28. ESP_LOGE(TAG, "%s", msg);
  29. return httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, msg);
  30. }
  31. static inline esp_err_t serv_progress(httpd_req_t *req, int progress) {
  32. ESP_LOGI(TAG, "%d%% complete", progress);
  33. /*
  34. char msg[100];
  35. snprintf(msg, sizeof(msg), "%d%% complete\n", progress);
  36. httpd_resp_set_status(req, "102 Processing");
  37. httpd_resp_set_type(req, HTTPD_TYPE_TEXT);
  38. return httpd_resp_send(req, msg, HTTPD_RESP_USE_STRLEN);
  39. */
  40. return ESP_OK;
  41. }
  42. // OTA POST
  43. static esp_err_t ota_post_handler(httpd_req_t *req)
  44. {
  45. esp_err_t err;
  46. const esp_partition_t *part = esp_ota_get_next_update_partition(NULL);
  47. if (!part) return serv_err(req, "Could not find update partition");
  48. int remaining = req->content_len;
  49. ESP_LOGI(TAG, "Starting OTA: %d bytes", remaining);
  50. esp_ota_handle_t ota;
  51. err = esp_ota_begin(part, remaining, &ota);
  52. if (err != ESP_OK) {
  53. ESP_LOGE(TAG, "esp_ota_begin: %d", err);
  54. return serv_err(req, "Could not start OTA");
  55. }
  56. constexpr int progress_step = 10;
  57. int next_progress = 0;
  58. constexpr size_t CHUNK_MAX = 4096;
  59. char *chunk_buf = new char[CHUNK_MAX];
  60. while (remaining > 0) {
  61. int chunk_size = MIN((unsigned int)remaining, CHUNK_MAX);
  62. int nread = httpd_req_recv(req, chunk_buf, chunk_size);
  63. if (nread <= 0) { /* 0 return value indicates connection closed */
  64. ESP_LOGE(TAG, "httpd_req_recv(%d): %d", chunk_size, nread);
  65. esp_ota_abort(ota);
  66. delete[] chunk_buf;
  67. /* Check if timeout occurred */
  68. if (nread == HTTPD_SOCK_ERR_TIMEOUT) {
  69. /* In case of timeout one can choose to retry calling
  70. * httpd_req_recv(), but to keep it simple, here we
  71. * respond with an HTTP 408 (Request Timeout) error */
  72. httpd_resp_send_408(req);
  73. }
  74. /* In case of error, returning ESP_FAIL will
  75. * ensure that the underlying socket is closed */
  76. return ESP_FAIL;
  77. }
  78. err = esp_ota_write(ota, chunk_buf, nread);
  79. if (err != ESP_OK) {
  80. ESP_LOGE(TAG, "esp_ota_write(%d): %d", nread, err);
  81. esp_ota_abort(ota);
  82. delete[] chunk_buf;
  83. return serv_err(req, "Failed to write OTA chunk");
  84. }
  85. remaining -= nread;
  86. int progress = 100 * (req->content_len - remaining) / req->content_len;
  87. if (progress >= next_progress) {
  88. serv_progress(req, progress);
  89. next_progress += progress_step;
  90. }
  91. }
  92. delete[] chunk_buf;
  93. ESP_LOGI(TAG, "Finalizing OTA");
  94. err = esp_ota_end(ota);
  95. if (err != ESP_OK) {
  96. ESP_LOGE(TAG, "esp_ota_end: %d", err);
  97. esp_ota_abort(ota);
  98. return serv_err(req, "Failed to finalize OTA");
  99. }
  100. ESP_LOGI(TAG, "Setting new boot partition");
  101. err = esp_ota_set_boot_partition(part);
  102. if (err != ESP_OK) {
  103. ESP_LOGE(TAG, "esp_ota_set_boot_partition: %d", err);
  104. return serv_err(req, "Failed to set partition");
  105. }
  106. ESP_LOGI(TAG, "OTA Successful");
  107. httpd_resp_sendstr(req, "OTA Successful\n");
  108. reboot_soon();
  109. return ESP_FAIL;
  110. }
  111. int start_ota_serv(httpd_handle_t server) {
  112. ESP_LOGI(TAG, "Starting OTA server");
  113. // Register handlers (move these to components)
  114. httpd_uri_t uri_ota_post = {
  115. .uri = "/ota",
  116. .method = HTTP_POST,
  117. .handler = ota_post_handler,
  118. .user_ctx = NULL
  119. };
  120. ESP_ERROR_CHECK(httpd_register_uri_handler(server, &uri_ota_post));
  121. // mDNS Entry
  122. mdns_service_add(NULL, "_http", "_tcp", 80, NULL, 0);
  123. mdns_service_instance_name_set("_http", "_tcp", "ESP32S2 OTA");
  124. return 0;
  125. }
  126. int stop_ota_serv() {
  127. // TODO
  128. return -1;
  129. }