diff options
author | Bertrik Sikken <bertrik@sikken.nl> | 2011-09-25 12:19:33 +0000 |
---|---|---|
committer | Bertrik Sikken <bertrik@sikken.nl> | 2011-09-25 12:19:33 +0000 |
commit | 93e748ac840da04b72f7ad02d4937f9ef09e4cb3 (patch) | |
tree | 070b63ff104bd2f86f66e84c2c9389d321665905 /apps | |
parent | 7e44438936091746fd5b192ca2fae3cd1b105713 (diff) | |
download | rockbox-93e748ac840da04b72f7ad02d4937f9ef09e4cb3.tar.gz rockbox-93e748ac840da04b72f7ad02d4937f9ef09e4cb3.zip |
IAP: use a state machine for handling iap packets, based on FS#12135
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30598 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps')
-rw-r--r-- | apps/iap.c | 144 |
1 files changed, 99 insertions, 45 deletions
diff --git a/apps/iap.c b/apps/iap.c index eaee21bc89..6fe0a03281 100644 --- a/apps/iap.c +++ b/apps/iap.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <stdarg.h> | 21 | #include <stdarg.h> |
22 | #include <string.h> | 22 | #include <string.h> |
23 | 23 | ||
24 | #include "panic.h" | ||
24 | #include "iap.h" | 25 | #include "iap.h" |
25 | #include "button.h" | 26 | #include "button.h" |
26 | #include "config.h" | 27 | #include "config.h" |
@@ -56,13 +57,32 @@ static int iap_repeatbtn = 0; | |||
56 | static bool iap_btnrepeat = false, iap_btnshuffle = false; | 57 | static bool iap_btnrepeat = false, iap_btnshuffle = false; |
57 | 58 | ||
58 | static unsigned char serbuf[RX_BUFLEN]; | 59 | static unsigned char serbuf[RX_BUFLEN]; |
59 | static int serbuf_i = 0; | ||
60 | 60 | ||
61 | static unsigned char response[TX_BUFLEN]; | 61 | static unsigned char response[TX_BUFLEN]; |
62 | static int responselen; | ||
63 | 62 | ||
64 | static char cur_dbrecord[5] = {0}; | 63 | static char cur_dbrecord[5] = {0}; |
65 | 64 | ||
65 | /* states of the iap de-framing state machine */ | ||
66 | enum fsm_state { | ||
67 | ST_SYNC, /* wait for 0xFF sync byte */ | ||
68 | ST_SOF, /* wait for 0x55 start-of-frame byte */ | ||
69 | ST_LEN, /* receive length byte (small packet) */ | ||
70 | ST_LENH, /* receive length high byte (large packet) */ | ||
71 | ST_LENL, /* receive length low byte (large packet) */ | ||
72 | ST_DATA, /* receive data */ | ||
73 | ST_CHECK /* verify checksum */ | ||
74 | }; | ||
75 | |||
76 | static struct state_t { | ||
77 | enum fsm_state state; /* current fsm state */ | ||
78 | unsigned int len; /* payload data length */ | ||
79 | unsigned char *payload; /* payload data pointer */ | ||
80 | unsigned int check; /* running checksum over [len,payload,check] */ | ||
81 | unsigned int count; /* playload bytes counter */ | ||
82 | } frame_state = { | ||
83 | .state = ST_SYNC | ||
84 | }; | ||
85 | |||
66 | static void put_u32(unsigned char *buf, uint32_t data) | 86 | static void put_u32(unsigned char *buf, uint32_t data) |
67 | { | 87 | { |
68 | buf[0] = (data >> 24) & 0xFF; | 88 | buf[0] = (data >> 24) & 0xFF; |
@@ -142,7 +162,7 @@ void iap_bitrate_set(int ratenum) | |||
142 | 162 | ||
143 | void iap_send_pkt(const unsigned char * data, int len) | 163 | void iap_send_pkt(const unsigned char * data, int len) |
144 | { | 164 | { |
145 | int i, chksum; | 165 | int i, chksum, responselen; |
146 | 166 | ||
147 | if(len > TX_BUFLEN-4) len = TX_BUFLEN-4; | 167 | if(len > TX_BUFLEN-4) len = TX_BUFLEN-4; |
148 | responselen = len + 4; | 168 | responselen = len + 4; |
@@ -168,37 +188,75 @@ void iap_send_pkt(const unsigned char * data, int len) | |||
168 | 188 | ||
169 | bool iap_getc(unsigned char x) | 189 | bool iap_getc(unsigned char x) |
170 | { | 190 | { |
171 | static unsigned char last_x = 0; | 191 | struct state_t *s = &frame_state; |
172 | static bool newpkt = true; | 192 | |
173 | static unsigned char chksum = 0; | 193 | /* run state machine to detect and extract a valid frame */ |
174 | 194 | switch (s->state) { | |
175 | /* Restart if the sync word is seen */ | 195 | case ST_SYNC: |
176 | if(x == 0x55 && last_x == 0xff/* && newpkt*/) | 196 | if (x == 0xFF) { |
177 | { | 197 | s->state = ST_SOF; |
178 | serbuf[0] = 0; | 198 | } |
179 | serbuf_i = 0; | 199 | break; |
180 | chksum = 0; | 200 | case ST_SOF: |
181 | newpkt = false; | 201 | if (x == 0x55) { |
182 | } | 202 | /* received a valid sync/SOF pair */ |
183 | else | 203 | s->state = ST_LEN; |
184 | { | 204 | } else { |
185 | if(serbuf_i >= RX_BUFLEN) | 205 | s->state = ST_SYNC; |
186 | serbuf_i = 0; | 206 | return iap_getc(x); |
187 | 207 | } | |
188 | serbuf[serbuf_i++] = x; | 208 | break; |
189 | chksum += x; | 209 | case ST_LEN: |
190 | } | 210 | s->check = x; |
191 | last_x = x; | 211 | s->count = 0; |
192 | 212 | s->payload = serbuf; | |
193 | /* Broadcast to queue if we have a complete message */ | 213 | if (x == 0) { |
194 | if(serbuf_i && (serbuf_i == serbuf[0]+2)) | 214 | /* large packet */ |
195 | { | 215 | s->state = ST_LENH; |
196 | serbuf_i = 0; | 216 | } else { |
197 | newpkt = true; | 217 | /* small packet */ |
198 | if(chksum == 0) | 218 | s->len = x; |
219 | s->state = ST_DATA; | ||
220 | } | ||
221 | break; | ||
222 | case ST_LENH: | ||
223 | s->check += x; | ||
224 | s->len = x << 8; | ||
225 | s->state = ST_LENL; | ||
226 | break; | ||
227 | case ST_LENL: | ||
228 | s->check += x; | ||
229 | s->len += x; | ||
230 | if ((s->len == 0) || (s->len > RX_BUFLEN)) { | ||
231 | /* invalid length */ | ||
232 | s->state = ST_SYNC; | ||
233 | return iap_getc(x); | ||
234 | } else { | ||
235 | s->state = ST_DATA; | ||
236 | } | ||
237 | break; | ||
238 | case ST_DATA: | ||
239 | s->check += x; | ||
240 | s->payload[s->count++] = x; | ||
241 | if (s->count == s->len) { | ||
242 | s->state = ST_CHECK; | ||
243 | } | ||
244 | break; | ||
245 | case ST_CHECK: | ||
246 | s->check += x; | ||
247 | if ((s->check & 0xFF) == 0) { | ||
248 | /* done, received a valid frame */ | ||
199 | queue_post(&button_queue, SYS_IAP_HANDLEPKT, 0); | 249 | queue_post(&button_queue, SYS_IAP_HANDLEPKT, 0); |
250 | } | ||
251 | s->state = ST_SYNC; | ||
252 | break; | ||
253 | default: | ||
254 | panicf("Unhandled iap state %d", (int) s->state); | ||
255 | break; | ||
200 | } | 256 | } |
201 | return newpkt; | 257 | |
258 | /* return true while still hunting for the sync and start-of-frame byte */ | ||
259 | return (s->state == ST_SYNC) || (s->state == ST_SOF); | ||
202 | } | 260 | } |
203 | 261 | ||
204 | void iap_periodic(void) | 262 | void iap_periodic(void) |
@@ -1004,8 +1062,9 @@ static void iap_handlepkt_mode7(unsigned int len, const unsigned char *buf) | |||
1004 | 1062 | ||
1005 | void iap_handlepkt(void) | 1063 | void iap_handlepkt(void) |
1006 | { | 1064 | { |
1065 | struct state_t *s = &frame_state; | ||
1066 | |||
1007 | if(!iap_setupflag) return; | 1067 | if(!iap_setupflag) return; |
1008 | if(serbuf[0] == 0) return; | ||
1009 | 1068 | ||
1010 | /* if we are waiting for a remote button to go out, | 1069 | /* if we are waiting for a remote button to go out, |
1011 | delay the handling of the new packet */ | 1070 | delay the handling of the new packet */ |
@@ -1015,20 +1074,15 @@ void iap_handlepkt(void) | |||
1015 | return; | 1074 | return; |
1016 | } | 1075 | } |
1017 | 1076 | ||
1018 | /* get length and payload from serbuf */ | 1077 | /* handle command by mode */ |
1019 | unsigned int len = serbuf[0]; | 1078 | unsigned char mode = s->payload[0]; |
1020 | unsigned char *payload = &serbuf[1]; | ||
1021 | |||
1022 | unsigned char mode = payload[0]; | ||
1023 | switch (mode) { | 1079 | switch (mode) { |
1024 | case 0: iap_handlepkt_mode0(len, payload); break; | 1080 | case 0: iap_handlepkt_mode0(s->len, s->payload); break; |
1025 | case 2: iap_handlepkt_mode2(len, payload); break; | 1081 | case 2: iap_handlepkt_mode2(s->len, s->payload); break; |
1026 | case 3: iap_handlepkt_mode3(len, payload); break; | 1082 | case 3: iap_handlepkt_mode3(s->len, s->payload); break; |
1027 | case 4: iap_handlepkt_mode4(len, payload); break; | 1083 | case 4: iap_handlepkt_mode4(s->len, s->payload); break; |
1028 | case 7: iap_handlepkt_mode7(len, payload); break; | 1084 | case 7: iap_handlepkt_mode7(s->len, s->payload); break; |
1029 | } | 1085 | } |
1030 | |||
1031 | serbuf[0] = 0; | ||
1032 | } | 1086 | } |
1033 | 1087 | ||
1034 | int remote_control_rx(void) | 1088 | int remote_control_rx(void) |