-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbootloader.h
164 lines (150 loc) · 4.37 KB
/
bootloader.h
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
#ifndef TINY_BOOTLOADER_IMPL
void bootloader_run(void);
#else
#include <stdint.h>
#define MSG_START 0x7D
#define MSG_ESC 0x7E
#define MSG_END 0x7F
#define MSG_XOR 0x20
#define COMMAND_SIZE 4
#define CMD_PING 0x01
#define CMD_DESCRIBE 0x02
#define CMD_WRITE_PAGE 0x03
#define CMD_VERIFY_PAGE 0x04
#define CMD_REBOOT 0x05
#define STATUS_OK (-1)
#define STATUS_OP_FAILED (-2)
#define STATUS_UNKNOWN_COMMAND (-3)
#define STATUS_BAD_REQUEST (-4)
#define STATUS_OVERFLOW (-5)
#define STATUS_INVALID_PAGE (-6)
#ifdef TINY_BOOTLOADER_BUFFER_SIZE
#define BUFFER_SIZE TINY_BOOTLOADER_BUFFER_SIZE
#else
#define BUFFER_SIZE (COMMAND_SIZE + TINY_BOOTLOADER_PAGE_SIZE)
#endif
static char buffer[BUFFER_SIZE];
static int read_command() {
char state = 0;
int pos;
while (1) {
char ch = TINY_BOOTLOADER_READ_BYTE();
if (ch == MSG_START) {
state = 1;
pos = 0;
continue;
}
switch (state) {
case 1:
{
if (ch == MSG_END) {
state = 0;
return pos;
} else if (ch == MSG_ESC) {
state = 2;
} else if (pos == BUFFER_SIZE) {
state = 3;
} else {
buffer[pos++] = ch;
}
break;
}
case 2:
{
if (pos == BUFFER_SIZE) {
state = 3;
} else {
buffer[pos++] = ch ^ MSG_XOR;
state = 1;
}
break;
}
case 3:
{
if (ch == MSG_END) {
return STATUS_OVERFLOW;
}
break;
}
}
}
}
void send_reply(int len) {
TINY_BOOTLOADER_WRITE_BYTE(MSG_START);
for (int i = 0; i < len; ++i) {
char b = buffer[i];
if (b == MSG_START || b == MSG_ESC || b == MSG_END) {
TINY_BOOTLOADER_WRITE_BYTE(MSG_ESC);
b ^= MSG_XOR;
}
TINY_BOOTLOADER_WRITE_BYTE(b);
}
TINY_BOOTLOADER_WRITE_BYTE(MSG_END);
}
void send_status(char status) {
buffer[0] = status;
send_reply(1);
}
void bootloader_run(void) {
while (1) {
int len = read_command();
if (len < 0) {
send_status(len);
continue;
} else if (len == 0) {
send_status(STATUS_BAD_REQUEST);
continue;
}
switch (buffer[0]) {
case CMD_PING:
{
buffer[0] = STATUS_OK;
send_reply(len);
break;
}
case CMD_DESCRIBE:
{
buffer[0] = STATUS_OK;
buffer[1] = (TINY_BOOTLOADER_PAGE_SIZE >> 8);
buffer[2] = TINY_BOOTLOADER_PAGE_SIZE;
buffer[3] = (TINY_BOOTLOADER_PAGE_COUNT >> 8);
buffer[4] = TINY_BOOTLOADER_PAGE_COUNT;
send_reply(5);
break;
}
case CMD_WRITE_PAGE:
case CMD_VERIFY_PAGE:
{
if (len != BUFFER_SIZE) {
send_status(STATUS_BAD_REQUEST);
} else {
uint16_t page = (buffer[2] << 8) | buffer[3];
if (page >= TINY_BOOTLOADER_PAGE_COUNT) {
send_status(STATUS_INVALID_PAGE);
} else {
char res;
if (buffer[0] == CMD_WRITE_PAGE) {
res = TINY_BOOTLOADER_WRITE_PAGE(page, buffer + COMMAND_SIZE);
} else {
res = TINY_BOOTLOADER_COMPARE_PAGE(page, buffer + COMMAND_SIZE);
}
send_status(res == 0 ? STATUS_OK : STATUS_OP_FAILED);
}
}
break;
}
case CMD_REBOOT:
{
send_status(STATUS_OK);
TINY_BOOTLOADER_REBOOT();
break;
}
default:
{
send_status(STATUS_UNKNOWN_COMMAND);
break;
}
}
}
}
#endif