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                 rotating_t recv_cks = be16_to_cpu(*((rotating_t *)(ctx->buf + ctx->len)));
00212 
00213                 /* Checksum check */
00214                 if (recv_cks == ctx->in_cks)
00215                 {
00216                     PocketBusHdr *hdr = (PocketBusHdr *)(ctx->buf);
00217                     /* Check packet version */
00218                     if (hdr->ver == POCKETBUS_VER)
00219                     {
00220                         /* Packet received, set msg fields */
00221                         msg->payload = ctx->buf + sizeof(PocketBusHdr);
00222                         msg->addr = be16_to_cpu(hdr->addr);
00223                         msg->len = ctx->len - sizeof(PocketBusHdr);
00224                         msg->ctx = ctx;
00225                         return true;
00226                     }
00227                     else
00228                     {
00229                         kprintf("pocketBus version mismatch, here[%d], there[%d]\n", POCKETBUS_VER, hdr->ver);
00230                         continue;
00231                     }
00232                 }
00233                 else
00234                 {
00235                     kprintf("pocketBus cks error, here[%04X], there[%04X]\n", ctx->in_cks, recv_cks);
00236                     continue;
00237                 }
00238 
00239             }
00240 
00241             ctx->escape = false;
00242 
00243             /* Check buffer overflow: simply ignore
00244                received data and go to unsynced state. */
00245             if (ctx->len >= CONFIG_POCKETBUS_BUFLEN)
00246             {
00247                 kprintf("pocketBus buffer overflow\n");
00248                 ctx->sync = false;
00249                 continue;
00250             }
00251 
00252             /* Put received data in the buffer */
00253             ctx->buf[ctx->len] = c;
00254             ctx->len++;
00255         }
00256     }
00257 
00258     /*
00259      * Check stream status.
00260      */
00261     if (kfile_error(ctx->fd))
00262     {
00263         TRACEMSG("fd status[%04X]", kfile_error(ctx->fd));
00264         kfile_clearerr(ctx->fd);
00265     }
00266 
00267     return false;
00268 }
00269 
00270 
00274 void pocketbus_init(struct PocketBusCtx *ctx, struct KFile *fd)
00275 {
00276     ASSERT(ctx);
00277     ASSERT(fd);
00278 
00279     memset(ctx, 0, sizeof(*ctx));
00280     ctx->fd = fd;
00281 }