pocketbus.c

Go to the documentation of this file.
00001 
00058 #include "pocketbus.h"
00059 
00060 #include <cfg/macros.h>
00061 #include <cfg/debug.h>
00062 
00063 #include <kern/kfile.h>
00064 
00065 #include <mware/byteorder.h>
00066 
00067 #include <string.h>
00068 
00072 void pocketbus_putchar(struct PocketBusCtx *ctx, uint8_t c)
00073 {
00074     /* Update checksum */
00075     rotating_update1(c, &ctx->out_cks);
00076 
00077     /* Escape characters with special meaning */
00078     if (c == POCKETBUS_ESC || c == POCKETBUS_STX || c == POCKETBUS_ETX)
00079         kfile_putc(POCKETBUS_ESC, ctx->fd);
00080     
00081     kfile_putc(c, ctx->fd);
00082 }
00083 
00087 void pocketbus_begin(struct PocketBusCtx *ctx, pocketbus_addr_t addr)
00088 {
00089     PocketBusHdr hdr;
00090 
00091     hdr.ver = POCKETBUS_VER;
00092     hdr.addr = cpu_to_be16(addr);
00093     rotating_init(&ctx->out_cks);
00094 
00095     /* Send STX */
00096     kfile_putc(POCKETBUS_STX, ctx->fd);
00097     
00098     /* Send header */
00099     pocketbus_write(ctx, &hdr, sizeof(hdr));
00100 }
00101 
00105 void pocketbus_write(struct PocketBusCtx *ctx, const void *_data, size_t len)
00106 {
00107     const uint8_t *data = (const uint8_t *)_data;
00108 
00109     while (len--)
00110         pocketbus_putchar(ctx, *data++);
00111 }
00112 
00116 void pocketbus_end(struct PocketBusCtx *ctx)
00117 {
00118     /* Send checksum */
00119     rotating_t cks = cpu_to_be16(ctx->out_cks);
00120     pocketbus_write(ctx, &cks, sizeof(cks));
00121 
00122     /* Send ETX */
00123     kfile_putc(POCKETBUS_ETX, ctx->fd);
00124 }
00125 
00129 void pocketbus_send(struct PocketBusCtx *ctx, pocketbus_addr_t addr, const void *data, size_t len)
00130 {
00131     pocketbus_begin(ctx, addr);
00132 
00133     /* Send data */
00134     pocketbus_write(ctx, data, len);
00135 
00136     pocketbus_end(ctx);
00137 }
00138 
00139 
00144 bool pocketbus_recv(struct PocketBusCtx *ctx, struct PocketMsg *msg)
00145 {
00146     int c;
00147 
00148     /* Process incoming characters until buffer is not empty */
00149     while ((c = kfile_getc(ctx->fd)) != EOF)
00150     {
00151         /* Look for STX char */
00152         if (c == POCKETBUS_STX && !ctx->escape)
00153         {
00154             /* When an STX is found, inconditionally start a new packet */
00155             if (ctx->sync)
00156                 kprintf("pocketBus double sync!\n");
00157 
00158             ctx->sync = true;
00159             ctx->len = 0;
00160             rotating_init(&ctx->in_cks);
00161             continue;
00162         }
00163 
00164         if (ctx->sync)
00165         {
00166             /* Handle escape mode */
00167             if (c == POCKETBUS_ESC && !ctx->escape)
00168             {
00169                 ctx->escape = true;
00170                 continue;
00171             }
00172 
00173             /* Handle message end */
00174             if (c == POCKETBUS_ETX && !ctx->escape)
00175             {
00176                 ctx->sync = false;
00177 
00178                 /* Check minimum size */
00179                 if (ctx->len < sizeof(PocketBusHdr) + sizeof(rotating_t))
00180                 {
00181                     kprintf("pocketBus short pkt!\n");
00182                     continue;
00183                 }
00184 
00185                 /* Remove checksum bytes from packet len */
00186                 ctx->len -= sizeof(rotating_t);
00187 
00188                 /* Compute checksum */
00189                 rotating_update(ctx->buf, ctx->len, &ctx->in_cks);
00190                 rotating_t recv_cks = be16_to_cpu(*((rotating_t *)(ctx->buf + ctx->len)));
00191 
00192                 /* Checksum check */
00193                 if (recv_cks == ctx->in_cks)
00194                 {
00195                     PocketBusHdr *hdr = (PocketBusHdr *)(ctx->buf);
00196                     /* Check packet version */
00197                     if (hdr->ver == POCKETBUS_VER)
00198                     {
00199                         /* Packet received, set msg fields */
00200                         msg->payload = ctx->buf + sizeof(PocketBusHdr);
00201                         msg->addr = be16_to_cpu(hdr->addr);
00202                         msg->len = ctx->len - sizeof(PocketBusHdr);
00203                         msg->ctx = ctx;
00204                         return true;
00205                     }
00206                     else
00207                     {
00208                         kprintf("pocketBus version mismatch, here[%d], there[%d]\n", POCKETBUS_VER, hdr->ver);
00209                         continue;
00210                     }
00211                 }
00212                 else
00213                 {
00214                     kprintf("pocketBus cks error, here[%04X], there[%04X]\n", ctx->in_cks, recv_cks);
00215                     continue;
00216                 }
00217 
00218             }
00219 
00220             ctx->escape = false;
00221 
00222             /* Check buffer overflow: simply ignore
00223                received data and go to unsynced state. */
00224             if (ctx->len >= CONFIG_POCKETBUS_BUFLEN)
00225             {
00226                 kprintf("pocketBus buffer overflow\n");
00227                 ctx->sync = false;
00228                 continue;
00229             }
00230 
00231             /* Put received data in the buffer */
00232             ctx->buf[ctx->len] = c;
00233             ctx->len++;
00234         }
00235     }
00236 
00237     /*
00238      * Check stream status.
00239      */
00240     if (kfile_error(ctx->fd))
00241     {
00242         TRACEMSG("fd status[%04X]", kfile_error(ctx->fd));
00243         kfile_clearerr(ctx->fd);
00244     }
00245 
00246     return false;
00247 }
00248 
00249 
00253 void pocketbus_init(struct PocketBusCtx *ctx, struct KFile *fd)
00254 {
00255     ASSERT(ctx);
00256     ASSERT(fd);
00257 
00258     memset(ctx, 0, sizeof(*ctx));
00259     ctx->fd = fd;
00260 }