pocketbus.c

Go to the documentation of this file.
00001 
00079 #include "pocketbus.h"
00080 
00081 #include <cfg/macros.h>
00082 #include <cfg/debug.h>
00083 
00084 #include <kern/kfile.h>
00085 
00086 #include <cpu/byteorder.h>
00087 
00088 #include <string.h>
00089 
00093 void pocketbus_putchar(struct PocketBusCtx *ctx, uint8_t c)
00094 {
00095     /* Update checksum */
00096     rotating_update1(c, &ctx->out_cks);
00097 
00098     /* Escape characters with special meaning */
00099     if (c == POCKETBUS_ESC || c == POCKETBUS_STX || c == POCKETBUS_ETX)
00100         kfile_putc(POCKETBUS_ESC, ctx->fd);
00101 
00102     kfile_putc(c, ctx->fd);
00103 }
00104 
00108 void pocketbus_begin(struct PocketBusCtx *ctx, pocketbus_addr_t addr)
00109 {
00110     PocketBusHdr hdr;
00111 
00112     hdr.ver = POCKETBUS_VER;
00113     hdr.addr = cpu_to_be16(addr);
00114     rotating_init(&ctx->out_cks);
00115 
00116     /* Send STX */
00117     kfile_putc(POCKETBUS_STX, ctx->fd);
00118 
00119     /* Send header */
00120     pocketbus_write(ctx, &hdr, sizeof(hdr));
00121 }
00122 
00126 void pocketbus_write(struct PocketBusCtx *ctx, const void *_data, size_t len)
00127 {
00128     const uint8_t *data = (const uint8_t *)_data;
00129 
00130     while (len--)
00131         pocketbus_putchar(ctx, *data++);
00132 }
00133 
00137 void pocketbus_end(struct PocketBusCtx *ctx)
00138 {
00139     /* Send checksum */
00140     rotating_t cks = cpu_to_be16(ctx->out_cks);
00141     pocketbus_write(ctx, &cks, sizeof(cks));
00142 
00143     /* Send ETX */
00144     kfile_putc(POCKETBUS_ETX, ctx->fd);
00145 }
00146 
00150 void pocketbus_send(struct PocketBusCtx *ctx, pocketbus_addr_t addr, const void *data, size_t len)
00151 {
00152     pocketbus_begin(ctx, addr);
00153 
00154     /* Send data */
00155     pocketbus_write(ctx, data, len);
00156 
00157     pocketbus_end(ctx);
00158 }
00159 
00160 
00165 bool pocketbus_recv(struct PocketBusCtx *ctx, struct PocketMsg *msg)
00166 {
00167     int c;
00168 
00169     /* Process incoming characters until buffer is not empty */
00170     while ((c = kfile_getc(ctx->fd)) != EOF)
00171     {
00172         /* Look for STX char */
00173         if (c == POCKETBUS_STX && !ctx->escape)
00174         {
00175             /* When an STX is found, inconditionally start a new packet */
00176             if (ctx->sync)
00177                 kprintf("pocketBus double sync!\n");
00178 
00179             ctx->sync = true;
00180             ctx->len = 0;
00181             rotating_init(&ctx->in_cks);
00182             continue;
00183         }
00184 
00185         if (ctx->sync)
00186         {
00187             /* Handle escape mode */
00188             if (c == POCKETBUS_ESC && !ctx->escape)
00189             {
00190                 ctx->escape = true;
00191                 continue;
00192             }
00193 
00194             /* Handle message end */
00195             if (c == POCKETBUS_ETX && !ctx->escape)
00196             {
00197                 ctx->sync = false;
00198 
00199                 /* Check minimum size */
00200                 if (ctx->len < sizeof(PocketBusHdr) + sizeof(rotating_t))
00201                 {
00202                     kprintf("pocketBus short pkt!\n");
00203                     continue;
00204                 }
00205 
00206                 /* Remove checksum bytes from packet len */
00207                 ctx->len -= sizeof(rotating_t);
00208 
00209                 /* Compute checksum */
00210                 rotating_update(ctx->buf, ctx->len, &ctx->in_cks);
00211                 uint8_t cks_h = *(ctx->buf + ctx->len);
00212                 uint8_t cks_l = *(ctx->buf + ctx->len + 1);
00213 
00214                 rotating_t recv_cks = (cks_h << 8) | cks_l;
00215 
00216                 /* Checksum check */
00217                 if (recv_cks == ctx->in_cks)
00218                 {
00219                     PocketBusHdr *hdr = (PocketBusHdr *)ctx;
00220 
00221                     /* Check packet version */
00222                     if (hdr->ver == POCKETBUS_VER)
00223                     {
00224                         /* Packet received, set msg fields */
00225                         msg->payload = ctx->buf + sizeof(PocketBusHdr);
00226                         msg->addr = be16_to_cpu(hdr->addr);
00227                         msg->len = ctx->len - sizeof(PocketBusHdr);
00228                         msg->ctx = ctx;
00229                         return true;
00230                     }
00231                     else
00232                     {
00233                         kprintf("pocketBus version mismatch, here[%d], there[%d]\n", POCKETBUS_VER, hdr->ver);
00234                         continue;
00235                     }
00236                 }
00237                 else
00238                 {
00239                     kprintf("pocketBus cks error, here[%04X], there[%04X]\n", ctx->in_cks, recv_cks);
00240                     continue;
00241                 }
00242 
00243             }
00244 
00245             ctx->escape = false;
00246 
00247             /* Check buffer overflow: simply ignore
00248                received data and go to unsynced state. */
00249             if (ctx->len >= CONFIG_POCKETBUS_BUFLEN)
00250             {
00251                 kprintf("pocketBus buffer overflow\n");
00252                 ctx->sync = false;
00253                 continue;
00254             }
00255 
00256             /* Put received data in the buffer */
00257             ctx->buf[ctx->len] = c;
00258             ctx->len++;
00259         }
00260     }
00261 
00262     /*
00263      * Check stream status.
00264      */
00265     if (kfile_error(ctx->fd))
00266     {
00267         TRACEMSG("fd status[%04X]", kfile_error(ctx->fd));
00268         kfile_clearerr(ctx->fd);
00269     }
00270 
00271     return false;
00272 }
00273 
00274 
00278 void pocketbus_init(struct PocketBusCtx *ctx, struct KFile *fd)
00279 {
00280     ASSERT(ctx);
00281     ASSERT(fd);
00282 
00283     memset(ctx, 0, sizeof(*ctx));
00284     ctx->fd = fd;
00285 }