Doc fixes.
[bertos.git] / net / pocketcmd.c
1 /**
2  * \file
3  * <!--
4  * Copyright 2007 Develer S.r.l. (http://www.develer.com/)
5  * -->
6  *
7  * \version $Id: pocketcmd.c 16587 2007-10-02 14:31:02Z batt $
8  *
9  * \author Francesco Sacchi <batt@develer.com>
10  *
11  * \brief pocketBus protocol Command layer implementation.
12  *
13  * This module implements command layer over pocketBus
14  * protocol.
15  * Payload packets received by pocketBus are first checked for
16  * address matching.
17  * If a packet is addressed to us we look for a suitable
18  * callback function to call.
19  *
20  * The received payload format is as follows:
21  * <pre>
22  * +----------------------------------------+
23  * |  CMD |            DATA                 |
24  * +----------------------------------------+
25  * |      |                                 |
26  * +  2B  +           0..N Byte             +
27  * </pre>
28  *
29  * The CMD ID used is the same supplied by the master when
30  * the command was sent.
31  */
32
33 #include "pocketcmd.h"
34 #include "pocketbus.h"
35
36 #include <cfg/macros.h>
37 #include <cfg/debug.h>
38 #include <cfg/module.h>
39
40 #include <drv/timer.h>
41
42 #include <mware/byteorder.h>
43
44 #include <string.h>
45
46 /**
47  * pocketBus Command poll function.
48  * Call it to read and process pocketBus commands.
49  */
50 void pocketcmd_poll(struct PocketCmdCtx *ctx)
51 {
52         PocketMsg msg;
53
54         /* Try to read a packet from pocketBus */
55         while (pocketbus_recv(ctx->bus_ctx, &msg))
56         {
57                 /* Check address */
58                 if (msg.addr == ctx->addr ||
59                     msg.addr == POCKETBUS_BROADCAST_ADDR)
60                 {
61                         const PocketCmdHdr *hdr = (const PocketCmdHdr *)msg.payload;
62                         pocketcmd_t cmd = be16_to_cpu(hdr->cmd);
63
64                         /* We're no longer waiting for a reply (in case we were) */
65                         if (cmd == ctx->waiting)
66                                 ctx->waiting = PKTCMD_NULL;
67
68                         /* Check for command callback */
69                         pocketcmd_hook_t callback = ctx->search(cmd);
70
71                         /* Call it if exists */
72                         if (callback)
73                         {
74                                 PocketCmdMsg cmd_msg;
75
76                                 cmd_msg.cmd_ctx = ctx;
77                                 cmd_msg.cmd = cmd;
78                                 cmd_msg.len = msg.len - sizeof(PocketCmdHdr);
79                                 cmd_msg.buf = msg.payload + sizeof(PocketCmdHdr);
80
81                                 callback(&cmd_msg);
82                         }
83                 }
84         }
85 }
86
87 /**
88  * Send command \a cmd to/from slave adding \a len arguments in \a buf.
89  * Address used is contained in \a ctx->addr .
90  * If we are master and the message has a reply, you must set \a wait_reply to true.
91  * \return true if all is ok, false if we are already waiting a replay from another slave.
92  */
93 bool pocketcmd_send(struct PocketCmdCtx *ctx, pocketcmd_t cmd, const void *buf, size_t len, bool wait_reply)
94 {
95         /* Check if we are waiting a reply from someone */
96         if (ctx->waiting != PKTCMD_NULL)
97         {
98                 /* Check is reply timeout is elapsed */
99                 if (timer_clock() - ctx->reply_timer < ms_to_ticks(PKTCMD_REPLY_TIMEOUT))
100                 {
101                         TRACEMSG("Pkt discard! waiting cmd[%04X]\n", ctx->waiting);
102                         return false;
103                 }
104                 else
105                 {
106                         TRACEMSG("Timeout waiting cmd[%04X]\n", ctx->waiting);
107                         ctx->waiting = PKTCMD_NULL;
108                 }
109         }
110
111         /* Endianess! */
112         cmd = cpu_to_be16(cmd);
113
114         /* Send packet */
115         pocketbus_begin(ctx->bus_ctx, ctx->addr);
116         pocketbus_write(ctx->bus_ctx, &cmd, sizeof(cmd));
117         pocketbus_write(ctx->bus_ctx, buf, len);
118         pocketbus_end(ctx->bus_ctx);
119
120         if (wait_reply)
121         {
122                 ctx->waiting = cmd;
123                 ctx->reply_timer = timer_clock();
124         }
125         return true;
126 }
127
128 /**
129  * Init pocketBus command layer.
130  * \a ctx is pocketBus command layer context.
131  * \a bus_ctx is pocketBus context.
132  * \a addr is slave address (see pocketcmd_setAddr for details.)
133  * \a search is the lookup function used to search command ID callbacks.
134  */
135 void pocketcmd_init(struct PocketCmdCtx *ctx, struct PocketBusCtx *bus_ctx, pocketbus_addr_t addr, pocketcmd_lookup_t search)
136 {
137         ASSERT(ctx);
138         ASSERT(bus_ctx);
139         ASSERT(search);
140         MOD_CHECK(timer);
141
142         memset(ctx, 0, sizeof(*ctx));
143         ctx->bus_ctx = bus_ctx;
144         ctx->search = search;
145         pocketcmd_setAddr(ctx, addr);
146 }
147
148 /**
149  * Helper function used to reply to master with an ACK.
150  */
151 void pocketcmd_replyAck(struct PocketCmdMsg *msg)
152 {
153         uint8_t ack[] = { POCKETBUS_ACK };
154
155         pocketcmd_slaveReply(msg->cmd_ctx, msg->cmd, ack, sizeof(ack));
156 }
157
158 /**
159  * Helper function used to reply to master with a NAK.
160  */
161 void pocketcmd_replyNak(struct PocketCmdMsg *msg)
162 {
163         uint8_t nak[] = { POCKETBUS_NAK };
164
165         pocketcmd_slaveReply(msg->cmd_ctx, msg->cmd, nak, sizeof(nak));
166 }
167