xbee: add a standalone makefile
[protos/xbee.git] / xbee.c
1 /*
2  * Copyright (c) 2011, Olivier MATZ <zer0@droids-corp.org>
3  * All rights reserved.
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *     * Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     * Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *     * Neither the name of the University of California, Berkeley nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include <stdio.h>
29 #include <stdint.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <sys/types.h>
34 #include <sys/queue.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #include <unistd.h>
38 #include <termios.h>
39
40 #include "xbee_neighbor.h"
41 #include "xbee_stats.h"
42 #include "xbee_buf.h"
43 #include "xbee_proto.h"
44 #include "xbee.h"
45
46 int xbee_init(void)
47 {
48         return 0;
49 }
50
51 static int xbee_settermios(struct xbee_dev *dev)
52 {
53         struct termios term;
54
55         memset(&term, 0, sizeof(term));
56         term.c_cflag = CREAD | HUPCL;
57
58         switch (dev->baud) {
59                 case 50: term.c_cflag |= B50; break;
60                 case 75: term.c_cflag |= B75; break;
61                 case 110: term.c_cflag |= B110; break;
62                 case 134: term.c_cflag |= B134; break;
63                 case 150: term.c_cflag |= B150; break;
64                 case 200: term.c_cflag |= B200; break;
65                 case 300: term.c_cflag |= B300; break;
66                 case 600: term.c_cflag |= B600; break;
67                 case 1200: term.c_cflag |= B1200; break;
68                 case 1800: term.c_cflag |= B1800; break;
69                 case 2400: term.c_cflag |= B2400; break;
70                 case 4800: term.c_cflag |= B4800; break;
71                 case 9600: term.c_cflag |= B9600; break;
72                 case 19200: term.c_cflag |= B19200; break;
73                 case 38400: term.c_cflag |= B38400; break;
74                 case 57600: term.c_cflag |= B57600; break;
75                 case 115200: term.c_cflag |= B115200; break;
76                 case 230400: term.c_cflag |= B230400; break;
77                 default:
78                         fprintf(stderr, "invalid baudrate\n");
79                         return -1;
80         }
81
82         /* ignore modem control lines */
83         term.c_cflag |= CLOCAL;
84
85         /* non-canonical mode */
86         term.c_lflag &= ~ICANON;
87
88         /* minimum number of chars and minimum timeout for non-canonical read */
89         term.c_cc[VMIN] = 1;
90         term.c_cc[VTIME] = 0;
91
92 #if 0
93         /* XXX later */
94         switch (dev->parity) {
95                 case PARITY_ODD: term.c_cflag |= PARENB | PARODD; break;
96                 case PARITY_EVEN: term.c_cflag |= PARENB; break;
97                 default:                break;
98         }
99
100         if (twostopb)
101                 term.c_cflag |= CSTOPB;
102
103         if (software)
104                 term.c_iflag |= IXON | IXOFF;
105         if (hardware)
106                 term.c_cflag |= CRTSCTS;
107
108 #endif
109
110         if (tcsetattr(dev->fd, TCSAFLUSH, &term) < 0) {
111                 fprintf(stderr, "ERROR: tcsetattr(TCSAFLUSH) failed: %s\n",
112                         strerror(errno));
113                 return -1;
114         }
115         return(0);
116 }
117
118 int xbee_register_channel(struct xbee_dev *dev, int channel,
119                           xbee_rx_cb_t *rx_cb, void *opaque)
120 {
121         /* user asked for any channel */
122         if (channel == XBEE_CHANNEL_ANY) {
123                 int ch;
124
125                 /* skip XBEE_DEFAULT_CHANNEL == 0 */
126                 for (ch = 1; ch < XBEE_MAX_CHANNEL; ch++) {
127                         if (dev->channel[ch].registered == 0) {
128                                 channel = ch;
129                                 break;
130                         }
131                 }
132                 /* no available channels */
133                 if (channel == XBEE_CHANNEL_ANY)
134                         return -1;
135         }
136         /* user requested a specific channel */
137         else if (channel < 0 || channel >= XBEE_MAX_CHANNEL ||
138                  dev->channel[channel].registered == 1)
139                 return -1; /* not available */
140
141         dev->channel[channel].registered = 1;
142         dev->channel[channel].rx_cb = rx_cb;
143         dev->channel[channel].arg = opaque;
144         return channel;
145 }
146
147 int xbee_unregister_channel(struct xbee_dev *dev, int channel)
148 {
149         if (channel < 0 || channel >= XBEE_MAX_CHANNEL ||
150             dev->channel[channel].registered == 0)
151                 return -1;
152         dev->channel[channel].registered = 0;
153         dev->channel[channel].rx_cb = NULL;
154         dev->channel[channel].arg = NULL;
155         return 0;
156 }
157
158 struct xbee_dev *xbee_open(const char *devname, unsigned baudrate)
159 {
160         struct xbee_dev *dev;
161         int fd;
162
163         /* allocate structure for xbee device */
164         dev = malloc(sizeof(*dev));
165         if (dev == NULL) {
166                 fprintf(stderr, "not enough memory\n");
167                 return NULL;
168         }
169         memset(dev, 0, sizeof(*dev));
170
171         /* open the serial port */
172         fd = open(devname, O_NONBLOCK|O_RDWR);
173         if (fd < 0) {
174                 fprintf(stderr, "cannot open %s: %s\n", devname,
175                         strerror(errno));
176                 free(dev);
177                 return NULL;
178         }
179
180         /* set termios */
181         dev->baud = baudrate;
182         dev->fd = fd;
183         if (xbee_settermios(dev) < 0) {
184                 close(fd);
185                 free(dev);
186                 return NULL;
187         }
188
189         dev->name = strdup(devname);
190         xbee_bufq_init(&dev->queue);
191         xbee_neigh_init(dev);
192
193         return dev;
194 }
195
196 /* read data from device fd and put it in queue */
197 int xbee_read(struct xbee_dev *dev)
198 {
199         struct xbee_buf *xbuf;
200         int n, tailroom, total = 0;
201         char *data;
202
203         do {
204                 /* get an xbuf to store data */
205                 xbuf = xbee_bufq_last(&dev->queue);
206                 if (xbuf == NULL || xbee_buf_tailroom(xbuf) == 0) {
207                         xbuf = xbee_buf_alloc();
208
209                         if (xbuf == NULL) {
210                                 fprintf(stderr, "FATAL: cannot allocate buffer\n");
211                                 return -1;
212                         }
213
214                         /* put the xbuf in queue */
215                         xbee_buf_enqueue(&dev->queue, xbuf);
216                 }
217
218                 /* read data from char device */
219                 tailroom = xbee_buf_tailroom(xbuf);
220                 data = xbee_buf_tail(xbuf);
221                 n = read(dev->fd, data, tailroom);
222
223                 /* error in read */
224                 if (n < 0) {
225                         fprintf(stderr, "read() failed: %s\n", strerror(errno));
226                         return -1;
227                 }
228
229                 /* update queue len and xbuf len */
230                 xbee_bufq_append(&dev->queue, n);
231
232                 total += n;
233
234         } while (n == tailroom);
235
236         return total;
237 }
238
239 /* process all data in queue */
240 int xbee_process_queue(struct xbee_dev *dev)
241 {
242         char buf[XBEE_MAX_FRAME_LEN];
243         int len, ret;
244
245         while (1) {
246                 len = xbee_proto_get_frame(dev, buf, sizeof(buf));
247                 if (len == 0) /* no more frame */
248                         break;
249
250                 if (len < 0) {
251                         /* a frame was dropped... */
252                         fprintf(stderr, "xbee_proto_get_frame() failed\n");
253                         continue;
254                 }
255
256                 ret = xbee_proto_parse_frame(dev, buf, len);
257                 if (ret < 0) {
258                         fprintf(stderr, "xbee_proto_parse_frame() failed\n");
259                         continue;
260                 }
261         }
262
263         return 0;
264 }