summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBertrik Sikken <bertrik@sikken.nl>2011-09-25 12:19:33 +0000
committerBertrik Sikken <bertrik@sikken.nl>2011-09-25 12:19:33 +0000
commit93e748ac840da04b72f7ad02d4937f9ef09e4cb3 (patch)
tree070b63ff104bd2f86f66e84c2c9389d321665905
parent7e44438936091746fd5b192ca2fae3cd1b105713 (diff)
downloadrockbox-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
-rw-r--r--apps/iap.c144
-rw-r--r--firmware/export/iap.h2
2 files changed, 100 insertions, 46 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;
56static bool iap_btnrepeat = false, iap_btnshuffle = false; 57static bool iap_btnrepeat = false, iap_btnshuffle = false;
57 58
58static unsigned char serbuf[RX_BUFLEN]; 59static unsigned char serbuf[RX_BUFLEN];
59static int serbuf_i = 0;
60 60
61static unsigned char response[TX_BUFLEN]; 61static unsigned char response[TX_BUFLEN];
62static int responselen;
63 62
64static char cur_dbrecord[5] = {0}; 63static char cur_dbrecord[5] = {0};
65 64
65/* states of the iap de-framing state machine */
66enum 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
76static 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
66static void put_u32(unsigned char *buf, uint32_t data) 86static 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
143void iap_send_pkt(const unsigned char * data, int len) 163void 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
169bool iap_getc(unsigned char x) 189bool 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
204void iap_periodic(void) 262void iap_periodic(void)
@@ -1004,8 +1062,9 @@ static void iap_handlepkt_mode7(unsigned int len, const unsigned char *buf)
1004 1062
1005void iap_handlepkt(void) 1063void 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
1034int remote_control_rx(void) 1088int remote_control_rx(void)
diff --git a/firmware/export/iap.h b/firmware/export/iap.h
index c9a670a05f..8ee26cbe9f 100644
--- a/firmware/export/iap.h
+++ b/firmware/export/iap.h
@@ -22,7 +22,7 @@
22 22
23#include <stdbool.h> 23#include <stdbool.h>
24 24
25#define RX_BUFLEN 260 25#define RX_BUFLEN 512
26#define TX_BUFLEN 128 26#define TX_BUFLEN 128
27 27
28extern bool iap_getc(unsigned char x); 28extern bool iap_getc(unsigned char x);