-
Notifications
You must be signed in to change notification settings - Fork 8
/
OTAServer.c
303 lines (234 loc) · 8.11 KB
/
OTAServer.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <esp_log.h>
#include <sys/param.h>
#include <esp_http_server.h>
#include "esp_ota_ops.h"
#include "freertos/event_groups.h"
// Embedded Files. To add or remove make changes is component.mk file as well.
extern const uint8_t index_html_start[] asm("_binary_index_html_start");
extern const uint8_t index_html_end[] asm("_binary_index_html_end");
extern const uint8_t favicon_ico_start[] asm("_binary_favicon_ico_start");
extern const uint8_t favicon_ico_end[] asm("_binary_favicon_ico_end");
extern const uint8_t jquery_3_3_1_min_js_start[] asm("_binary_jquery_3_3_1_min_js_start");
extern const uint8_t jquery_3_3_1_min_js_end[] asm("_binary_jquery_3_3_1_min_js_end");
httpd_handle_t OTA_server = NULL;
int8_t flash_status = 0;
EventGroupHandle_t reboot_event_group;
const int REBOOT_BIT = BIT0;
/*****************************************************
systemRebootTask()
NOTES: This had to be a task because the web page needed
an ack back. So i could not call this in the handler
*****************************************************/
void systemRebootTask(void * parameter)
{
// Init the event group
reboot_event_group = xEventGroupCreate();
// Clear the bit
xEventGroupClearBits(reboot_event_group, REBOOT_BIT);
for (;;)
{
// Wait here until the bit gets set for reboot
EventBits_t staBits = xEventGroupWaitBits(reboot_event_group, REBOOT_BIT, pdTRUE, pdFALSE, portMAX_DELAY);
// Did portMAX_DELAY ever timeout, not sure so lets just check to be sure
if ((staBits & REBOOT_BIT) != 0)
{
ESP_LOGI("OTA", "Reboot Command, Restarting");
vTaskDelay(2000 / portTICK_PERIOD_MS);
esp_restart();
}
}
}
/* Send index.html Page */
esp_err_t OTA_index_html_handler(httpd_req_t *req)
{
ESP_LOGI("OTA", "index.html Requested");
// Clear this every time page is requested
flash_status = 0;
httpd_resp_set_type(req, "text/html");
httpd_resp_send(req, (const char *)index_html_start, index_html_end - index_html_start);
return ESP_OK;
}
/* Send .ICO (icon) file */
esp_err_t OTA_favicon_ico_handler(httpd_req_t *req)
{
ESP_LOGI("OTA", "favicon_ico Requested");
httpd_resp_set_type(req, "image/x-icon");
httpd_resp_send(req, (const char *)favicon_ico_start, favicon_ico_end - favicon_ico_start);
return ESP_OK;
}
/* jquery GET handler */
esp_err_t jquery_3_3_1_min_js_handler(httpd_req_t *req)
{
ESP_LOGI("OTA", "jqueryMinJs Requested");
httpd_resp_set_type(req, "application/javascript");
httpd_resp_send(req, (const char *)jquery_3_3_1_min_js_start, jquery_3_3_1_min_js_end - jquery_3_3_1_min_js_start);
return ESP_OK;
}
/* Status */
esp_err_t OTA_update_status_handler(httpd_req_t *req)
{
char ledJSON[100];
ESP_LOGI("OTA", "Status Requested");
sprintf(ledJSON, "{\"status\":%d,\"compile_time\":\"%s\",\"compile_date\":\"%s\"}", flash_status, __TIME__, __DATE__);
httpd_resp_set_type(req, "application/json");
httpd_resp_send(req, ledJSON, strlen(ledJSON));
if (flash_status == 1)
{
// We cannot directly call reboot here because we need the
// browser to get the ack back.
xEventGroupSetBits(reboot_event_group, REBOOT_BIT);
}
return ESP_OK;
}
/* Receive .Bin file */
esp_err_t OTA_update_post_handler(httpd_req_t *req)
{
esp_ota_handle_t ota_handle;
char ota_buff[1024];
int content_length = req->content_len;
int content_received = 0;
int recv_len;
bool is_req_body_started = false;
const esp_partition_t *update_partition = esp_ota_get_next_update_partition(NULL);
// Unsucessful Flashing
flash_status = -1;
do
{
/* Read the data for the request */
if ((recv_len = httpd_req_recv(req, ota_buff, MIN(content_length, sizeof(ota_buff)))) < 0)
{
if (recv_len == HTTPD_SOCK_ERR_TIMEOUT)
{
ESP_LOGI("OTA", "Socket Timeout");
/* Retry receiving if timeout occurred */
continue;
}
ESP_LOGI("OTA", "OTA Other Error %d", recv_len);
return ESP_FAIL;
}
printf("OTA RX: %d of %d\r", content_received, content_length);
// Is this the first data we are receiving
// If so, it will have the information in the header we need.
if (!is_req_body_started)
{
is_req_body_started = true;
// Lets find out where the actual data staers after the header info
char *body_start_p = strstr(ota_buff, "\r\n\r\n") + 4;
int body_part_len = recv_len - (body_start_p - ota_buff);
//int body_part_sta = recv_len - body_part_len;
//printf("OTA File Size: %d : Start Location:%d - End Location:%d\r\n", content_length, body_part_sta, body_part_len);
printf("OTA File Size: %d\r\n", content_length);
esp_err_t err = esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &ota_handle);
if (err != ESP_OK)
{
printf("Error With OTA Begin, Cancelling OTA\r\n");
return ESP_FAIL;
}
else
{
printf("Writing to partition subtype %d at offset 0x%x\r\n", update_partition->subtype, update_partition->address);
}
// Lets write this first part of data out
esp_ota_write(ota_handle, body_start_p, body_part_len);
}
else
{
// Write OTA data
esp_ota_write(ota_handle, ota_buff, recv_len);
content_received += recv_len;
}
} while (recv_len > 0 && content_received < content_length);
// End response
//httpd_resp_send_chunk(req, NULL, 0);
if (esp_ota_end(ota_handle) == ESP_OK)
{
// Lets update the partition
if(esp_ota_set_boot_partition(update_partition) == ESP_OK)
{
const esp_partition_t *boot_partition = esp_ota_get_boot_partition();
// Webpage will request status when complete
// This is to let it know it was successful
flash_status = 1;
ESP_LOGI("OTA", "Next boot partition subtype %d at offset 0x%x", boot_partition->subtype, boot_partition->address);
ESP_LOGI("OTA", "Please Restart System...");
}
else
{
ESP_LOGI("OTA", "\r\n\r\n !!! Flashed Error !!!");
}
}
else
{
ESP_LOGI("OTA", "\r\n\r\n !!! OTA End Error !!!");
}
return ESP_OK;
}
httpd_uri_t OTA_index_html = {
.uri = "/",
.method = HTTP_GET,
.handler = OTA_index_html_handler,
/* Let's pass response string in user
* context to demonstrate it's usage */
.user_ctx = NULL
};
httpd_uri_t OTA_favicon_ico = {
.uri = "/favicon.ico",
.method = HTTP_GET,
.handler = OTA_favicon_ico_handler,
/* Let's pass response string in user
* context to demonstrate it's usage */
.user_ctx = NULL
};
httpd_uri_t OTA_jquery_3_3_1_min_js = {
.uri = "/jquery-3.3.1.min.js",
.method = HTTP_GET,
.handler = jquery_3_3_1_min_js_handler,
/* Let's pass response string in user
* context to demonstrate it's usage */
.user_ctx = NULL
};
httpd_uri_t OTA_update = {
.uri = "/update",
.method = HTTP_POST,
.handler = OTA_update_post_handler,
.user_ctx = NULL
};
httpd_uri_t OTA_status = {
.uri = "/status",
.method = HTTP_POST,
.handler = OTA_update_status_handler,
.user_ctx = NULL
};
httpd_handle_t start_OTA_webserver(void)
{
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
// Need this task to spin up, see why in task
xTaskCreate(&systemRebootTask, "rebootTask", 2048, NULL, 5, NULL);
// Lets change this from port 80 (default) to 8080
//config.server_port = 8080;
// Lets bump up the stack size (default was 4096)
config.stack_size = 8192;
// Start the httpd server
ESP_LOGI("OTA", "Starting server on port: '%d'", config.server_port);
if (httpd_start(&OTA_server, &config) == ESP_OK)
{
// Set URI handlers
ESP_LOGI("OTA", "Registering URI handlers");
httpd_register_uri_handler(OTA_server, &OTA_index_html);
httpd_register_uri_handler(OTA_server, &OTA_favicon_ico);
httpd_register_uri_handler(OTA_server, &OTA_jquery_3_3_1_min_js);
httpd_register_uri_handler(OTA_server, &OTA_update);
httpd_register_uri_handler(OTA_server, &OTA_status);
return OTA_server;
}
ESP_LOGI("OTA", "Error starting server!");
return NULL;
}
void stop_OTA_webserver(httpd_handle_t server)
{
// Stop the httpd server
httpd_stop(server);
}