-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.c
328 lines (299 loc) · 10.8 KB
/
main.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
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
/* (c) 2018 HomeAccessoryKid
* OTA demo
* main body copied from esp-open-rtos sysparam_editor example
*/
#include "FreeRTOS.h"
#include "task.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <esp/uart.h>
#include <sysparam.h> //only needed for the demo to be efficient
#include <rboot-api.h> //include this in your own code
#ifndef VERSION
#error You must set VERSION=x.y.z of the ota-demo code to match github version tag x.y.z
#endif
// while the above is not essential, it can help track versions of your code
#define CMD_BUF_SIZE 5000
int timeleft=30; //30 seconds timeout
const int status_base = -6;
const char *status_messages[] = {
"SYSPARAM_ERR_NOMEM",
"SYSPARAM_ERR_CORRUPT",
"SYSPARAM_ERR_IO",
"SYSPARAM_ERR_FULL",
"SYSPARAM_ERR_BADVALUE",
"SYSPARAM_ERR_NOINIT",
"SYSPARAM_OK",
"SYSPARAM_NOTFOUND",
"SYSPARAM_PARSEFAILED",
};
void usage(void) {
printf(
"Available commands:\n"
" otareboot -- Reboot to the OTA partition\n"
" otazero -- Reset the ota_version to 0.0.0\n"
" <key>? -- Query the value of <key>\n"
" <key>=<value> -- Set <key> to text <value>\n"
" <key>:<hexdata> -- Set <key> to binary value represented as hex\n"
" led<+/-><pin#> -- Set gpio with a LED connected, >15 to remove\n"
" +- defines if LED activates with a 0 or a 1\n"
" dump -- Show all currently set keys/values\n"
" compact -- Compact the sysparam area\n"
" reformat -- Reinitialize (clear) the sysparam area\n"
" echo_off -- Disable input echo\n"
" echo_on -- Enable input echo\n"
" help -- Show this help screen\n"
);
}
size_t tty_readline(char *buffer, size_t buf_size, bool echo) {
size_t i = 0;
int c;
while (true) {
c = getchar();
if (c == '\r' || c == '\n') {
if (echo) putchar('\n');
break;
} else if (c == '\b' || c == 0x7f) {
if (i) {
if (echo) {
printf("\b \b");
fflush(stdout);
}
i--;
}
} else if (c < 0x20) {
/* Ignore other control characters */
} else if (i >= buf_size - 1) {
if (echo) {
putchar('\a');
fflush(stdout);
}
} else {
buffer[i++] = c;
if (echo) {
putchar(c);
fflush(stdout);
}
}
}
buffer[i] = 0;
return i;
}
void print_text_value(char *key, char *value) {
printf(" '%s' = '%s'\n", key, value);
}
void print_binary_value(char *key, uint8_t *value, size_t len) {
size_t i;
printf(" %s:", key);
for (i = 0; i < len; i++) {
if (!(i & 0x0f)) {
printf("\n ");
}
printf(" %02x", value[i]);
}
printf("\n");
}
sysparam_status_t dump_params(void) {
sysparam_status_t status;
sysparam_iter_t iter;
status = sysparam_iter_start(&iter);
if (status < 0) return status;
while (true) {
status = sysparam_iter_next(&iter);
if (status != SYSPARAM_OK) break;
if (!iter.binary) {
print_text_value(iter.key, (char *)iter.value);
} else {
print_binary_value(iter.key, iter.value, iter.value_len);
}
}
sysparam_iter_end(&iter);
if (status == SYSPARAM_NOTFOUND) {
// This is the normal status when we've reached the end of all entries.
return SYSPARAM_OK;
} else {
// Something apparently went wrong
return status;
}
}
uint8_t *parse_hexdata(char *string, size_t *result_length) {
size_t string_len = strlen(string);
uint8_t *buf = malloc(string_len / 2);
uint8_t c;
int i, j;
bool digit = false;
j = 0;
for (i = 0; string[i]; i++) {
c = string[i];
if (c >= 0x30 && c <= 0x39) {
c &= 0x0f;
} else if (c >= 0x41 && c <= 0x46) {
c -= 0x37;
} else if (c >= 0x61 && c <= 0x66) {
c -= 0x57;
} else if (c == ' ') {
continue;
} else {
free(buf);
return NULL;
}
if (!digit) {
buf[j] = c << 4;
} else {
buf[j++] |= c;
}
digit = !digit;
}
if (digit) {
free(buf);
return NULL;
}
*result_length = j;
return buf;
}
void ledset(int pin, int pol) {
rboot_config conf;
conf=rboot_get_config();
conf.unused[1]=(pin>15)?0:(0x40+pol*0x10+(pin&0x0f));
printf("LEDinfo = rboot_config.unused[1] set to 0x%02x\n",conf.unused[1]);
rboot_set_config(&conf);
}
void ota_task(void *arg) {
char *cmd_buffer = malloc(CMD_BUF_SIZE);
sysparam_status_t status;
char *value;
uint8_t *bin_value;
size_t len;
uint8_t *data;
uint32_t base_addr, num_sectors;
bool echo = true;
vTaskDelay(500); //5 seconds to allow connecting a console after flashing
if (!cmd_buffer) {
printf("ERROR: Cannot allocate command buffer!\n");
return;
}
printf(
"\nOTA-demo code version %s\n"
"Based on the eps-open-rtos system parameter editor\n"
"In 30 seconds will reset the version to 0.0.0 and reboot to OTA\n"
"Press enter for 5 new minutes\n"
"Enter 'help' for more information.\n\n"
, VERSION);
status = sysparam_get_info(&base_addr, &num_sectors);
if (status == SYSPARAM_OK) {
printf("[current sysparam region is at 0x%08x (%d sectors)]\n", base_addr, num_sectors);
} else {
printf("[NOTE: No current sysparam region (initialization problem during boot?)]\n");
// Default to the same place/size as the normal system initialization
// stuff, so if the user uses this utility to reformat it, it will put
// it somewhere the system will find it later
num_sectors = DEFAULT_SYSPARAM_SECTORS;
base_addr = sdk_flashchip.chip_size - (5 + num_sectors) * sdk_flashchip.sector_size;
}
while (true) {
printf("==> ");
fflush(stdout);
len = tty_readline(cmd_buffer, CMD_BUF_SIZE, echo);
timeleft=300; //5 minutes after input
status = 0;
if (!len) continue;
if (cmd_buffer[len - 1] == '?') {
cmd_buffer[len - 1] = 0;
printf("Querying '%s'...\n", cmd_buffer);
status = sysparam_get_string(cmd_buffer, &value);
if (status == SYSPARAM_OK) {
print_text_value(cmd_buffer, value);
free(value);
} else if (status == SYSPARAM_PARSEFAILED) {
// This means it's actually a binary value
status = sysparam_get_data(cmd_buffer, &bin_value, &len, NULL);
if (status == SYSPARAM_OK) {
print_binary_value(cmd_buffer, bin_value, len);
free(value);
}
}
} else if ((value = strchr(cmd_buffer, '='))) {
*value++ = 0;
printf("Setting '%s' to '%s'...\n", cmd_buffer, value);
status = sysparam_set_string(cmd_buffer, value);
} else if ((value = strchr(cmd_buffer, ':'))) {
*value++ = 0;
data = parse_hexdata(value, &len);
if (value) {
printf("Setting '%s' to binary data...\n", cmd_buffer);
status = sysparam_set_data(cmd_buffer, data, len, true);
free(data);
} else {
printf("Error: Unable to parse hex data\n");
}
} else if ((value = strchr(cmd_buffer, '+'))) {
*value++ = 0;
ledset(atoi(value),0);
} else if ((value = strchr(cmd_buffer, '-'))) {
*value++ = 0;
ledset(atoi(value),1);
} else if (!strcmp(cmd_buffer, "dump")) {
printf("Dumping all params:\n");
status = dump_params();
} else if (!strcmp(cmd_buffer, "compact")) {
printf("Compacting...\n");
status = sysparam_compact();
} else if (!strcmp(cmd_buffer, "reformat")) {
printf("Re-initializing region...\n");
status = sysparam_create_area(base_addr, num_sectors, true);
if (status == SYSPARAM_OK) {
// We need to re-init after wiping out the region we've been
// using.
status = sysparam_init(base_addr, 0);
}
} else if (!strcmp(cmd_buffer, "echo_on")) {
echo = true;
printf("Echo on\n");
} else if (!strcmp(cmd_buffer, "echo_off")) {
echo = false;
printf("Echo off\n");
} else if (!strcmp(cmd_buffer, "otareboot")) {
rboot_set_temp_rom(1); //select the OTA main routine
sdk_system_restart(); //#include <rboot-api.h>
} else if (!strcmp(cmd_buffer, "otazero")) {
sysparam_set_string("ota_version", "0.0.0"); //only needed for the demo to be efficient
} else if (!strcmp(cmd_buffer, "help")) {
usage();
} else {
printf("Unrecognized command.\n\n");
usage();
}
if (status != SYSPARAM_OK) {
printf("! Operation returned status: %d (%s)\n", status, status_messages[status - status_base]);
}
}
}
void timeout_task(void *arg) {
while(1) {
if (timeleft ==10) printf("In 10 seconds will reset the version to 0.0.0 and reboot to OTA\nPress <enter> for 5 new minutes\n==> ");
if (timeleft--==0) { //timed out
dump_params();
//sysparam_set_string("ota_repo", "HomeACcessoryKid/ota-demo");
sysparam_set_string("ota_version", "0.0.0"); //only needed for the demo to be efficient
//sysparam_set_string("ota_file", "main.bin");
printf("\n^^^ initial -> changed to vvvv\n\n");
dump_params();
// in ota-boot the user gets to set the wifi and the repository details and it then installs the ota-main binary
// the below two lines are the ONLY thing needed for a repo to support ota after having started with ota-boot
rboot_set_temp_rom(1); //select the OTA main routine
sdk_system_restart(); //#include <rboot-api.h>
// there is a bug in the esp SDK such that if you do not power cycle the chip after flashing, restart is unreliable
vTaskDelete(NULL); //should never get here
}
vTaskDelay(100); //1 second
}
}
void user_init(void) {
// uart_set_baud(0, 74880);
uart_set_baud(0, 115200);
printf("ota-demo code version %s\n", VERSION);
xTaskCreate(ota_task,"ota",512,NULL,1,NULL);
xTaskCreate(timeout_task,"ota",512,NULL,1,NULL);
printf("user-init-done\n");
}