Index: apps/iap.c
===================================================================
--- apps/iap.c  (revision 29879)
+++ apps/iap.c  (working copy)
@@ -21,6 +21,7 @@
 #include <stdarg.h>
 #include <string.h>

+#include "panic.h"
 #include "iap.h"
 #include "button.h"
 #include "config.h"
@@ -63,6 +64,27 @@

 static char cur_dbrecord[5] = {0};

+/* states of the iap de-framing state machine */
+enum fsm_state {
+    ST_SYNC,    /* wait for 0xFF sync byte */
+    ST_SOF,     /* wait for 0x55 start-of-frame byte */
+    ST_LEN,     /* receive length byte (small packet) */
+    ST_LENH,    /* receive length high byte (large packet) */
+    ST_LENL,    /* receive length low byte (large packet) */
+    ST_DATA,    /* receive data */
+    ST_CHECK    /* verify checksum */
+};
+
+static struct state_t {
+    enum fsm_state state;   /* current fsm state */
+    int len;                /* payload data length */
+    unsigned char *payload; /* payload data pointer */
+    int check;              /* running checksum */
+    int count;              /* playload bytes counter */
+} fsm_state = {
+    .state = ST_SYNC
+};
+
 static void put_u32(unsigned char *buf, uint32_t data)
 {
     buf[0] = (data >> 24) & 0xFF;
@@ -168,36 +190,80 @@

 bool iap_getc(unsigned char x)
 {
-    static unsigned char last_x = 0;
     static bool newpkt = true;
-    static unsigned char chksum = 0;
-            
-    /* Restart if the sync word is seen */
-    if(x == 0x55 && last_x == 0xff/* && newpkt*/)
-    {
-        serbuf[0] = 0;
+    struct state_t *s = &fsm_state;
+    
+    /* run FSM to detect and extract a valid frame */
+    switch (s->state) {
+    case ST_SYNC:
         serbuf_i = 0;
-        chksum = 0;
-        newpkt = false;
-    }
-    else
-    {
-        if(serbuf_i >= RX_BUFLEN)
-            serbuf_i = 0;
-
-        serbuf[serbuf_i++] = x;
-        chksum += x;
-    }
-    last_x = x;
-
-    /* Broadcast to queue if we have a complete message */
-    if(serbuf_i && (serbuf_i == serbuf[0]+2))
-    {
-        serbuf_i = 0;
-        newpkt = true;
-        if(chksum == 0)
+        if (x == 0xFF) {
+            s->state = ST_SOF;
+        }
+        break;
+    case ST_SOF:
+        if (x == 0x55) {
+            /* received a valid sync-SOF pair */
+            newpkt = false;
+            s->state = ST_LEN;
+        } else {
+            s->state = ST_SYNC;
+            return iap_getc(x);
+        }
+        break;
+    case ST_LEN:
+        s->check = x;
+        s->count = 0;
+        if (x == 0) {
+            /* large packet */
+            s->state = ST_LENH;
+        } else {
+            /* small packet */
+            s->len = x;
+            s->payload = &serbuf[3];
+            s->state = ST_DATA;
+        }
+        break;
+    case ST_LENH:
+        s->check += x;
+        s->len = x << 8;
+        s->state = ST_LENL;
+        break;
+    case ST_LENL:
+        s->check += x;
+        s->len += x;
+        s->payload = &serbuf[5];
+        if ((s->len == 0) || (s->len > (RX_BUFLEN - 6))) {
+            /* invalid length */
+            s->state = ST_SYNC;
+            return iap_getc(x);
+        } else {
+            s->state = ST_DATA;
+        }
+        break;
+    case ST_DATA:
+        s->check += x;
+        if (++s->count == s->len) {
+            s->state = ST_CHECK;
+        }
+        break;
+    case ST_CHECK:
+        s->check += x;
+        if ((s->check & 0xFF) == 0) {
+            /* done, received a valid frame */
+            newpkt = true;
             queue_post(&button_queue, SYS_IAP_HANDLEPKT, 0);
+        }
+        s->state = ST_SYNC;
+        break;
+    default:
+        panicf("Unhandled iap state %d", (int) s->state);
+        break;
     }
+    
+    /* store all incoming data in serbuf */
+    serbuf[serbuf_i++] = x;
+    
     return newpkt;
 }

@@ -1004,8 +1070,10 @@

 void iap_handlepkt(void)
 {
+    struct state_t *s = &fsm_state;
+
     if(!iap_setupflag) return;
-    if(serbuf[0] == 0) return;
+    if (s->len == 0) return;

     /* if we are waiting for a remote button to go out,
        delay the handling of the new packet */
@@ -1015,20 +1083,17 @@
         return;
     }

-    /* get length and payload from serbuf */
-    unsigned int len = serbuf[0];
-    unsigned char *payload = &serbuf[1];
-    
-    unsigned char mode = payload[0];
+    /* handle command by mode */
+    unsigned char mode = s->payload[0];
     switch (mode) {
-    case 0: iap_handlepkt_mode0(len, payload); break;
-    case 2: iap_handlepkt_mode2(len, payload); break;
-    case 3: iap_handlepkt_mode3(len, payload); break;
-    case 4: iap_handlepkt_mode4(len, payload); break;
-    case 7: iap_handlepkt_mode7(len, payload); break;
+    case 0: iap_handlepkt_mode0(s->len, s->payload); break;
+    case 2: iap_handlepkt_mode2(s->len, s->payload); break;
+    case 3: iap_handlepkt_mode3(s->len, s->payload); break;
+    case 4: iap_handlepkt_mode4(s->len, s->payload); break;
+    case 7: iap_handlepkt_mode7(s->len, s->payload); break;
     }

-    serbuf[0] = 0;
+    s->len = 0;
 }

 int remote_control_rx(void)
Index: firmware/export/iap.h
===================================================================
--- firmware/export/iap.h  (revision 29879)
+++ firmware/export/iap.h  (working copy)
@@ -22,7 +22,7 @@

 #include <stdbool.h>

-#define RX_BUFLEN 260
+#define RX_BUFLEN 512
 #define TX_BUFLEN 128

 extern bool iap_getc(unsigned char x);