chiark / gitweb /
468580c08b556672c09ff56e2ad5ecc04d7a6678
[jog] / serial.c
1 /* -*-c-*-
2  *
3  * $Id: serial.c,v 1.2 2002/01/30 09:23:58 mdw Exp $
4  *
5  * Common serial functionality
6  *
7  * (c) 2001 Mark Wooding
8  */
9
10 /*----- Licensing notice --------------------------------------------------* 
11  *
12  * This file is part of Jog: Programming for a jogging machine.
13  *
14  * Jog is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  * 
19  * Jog is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  * 
24  * You should have received a copy of the GNU General Public License
25  * along with Jog; if not, write to the Free Software Foundation,
26  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27  */
28
29 /*----- Header files ------------------------------------------------------*/
30
31 #include <ctype.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include "serial.h"
36
37 /*----- Main code ---------------------------------------------------------*/
38
39 /* --- @getbaud@ --- *
40  *
41  * Arguments:   @const char *p@ = pointer to string
42  *              @const char **pp@ = where to store final pointer
43  *
44  * Returns:     Baud rate, or @-1@ on failure.
45  *
46  * Use:         Parses a baud rate, either as a raw number or as an
47  *              expression like `9k6'.
48  */
49
50 static long getbaud(const char *p, const char **pp)
51 {
52   long x = 0;
53   long f = 1, s = 10;
54   int ok = 0;
55
56   /* --- Main loop --- */
57
58   for (;;) {
59     int ch = (unsigned char)*p;
60
61     switch (ch) {
62       case 'k':
63       case 'K':
64         f = 1000;
65         goto factor;
66       case 'm':
67       case 'M':
68         f = 1000000;
69         goto factor;
70       factor:
71         if (ok != 1)
72           return (-1);
73         x *= f;
74         s = 1;
75         ok = 2;
76         break;
77       default:
78         if (!isdigit(ch))
79           goto done;
80         if (!ok)
81           ok = 1;
82         if (ok == 2) {
83           if (f == 1)
84             return (-1);
85           f /= 10;
86         }
87         x = x * s + (ch - '0') * f;
88         break;
89     }
90     p++;
91   }
92 done:
93   if (!ok)
94     return (-1);
95   if (pp)
96     *pp = p;
97   return (x);
98 }
99
100 /* --- @getparity@ --- *
101  *
102  * Arguments:   @const char *p@ = pointer to string
103  *              @const char **pp@ = where to store final pointer
104  *
105  * Returns:     Parity constant or @-1@ on error.
106  *
107  * Use:         Parses a parity setting.
108  */
109
110 static int getparity(const char *p, const char **pp)
111 {
112   const char *q;
113
114   for (q = p; isalpha((unsigned char)*q); q++)
115     ;
116   if (q == p)
117     return (-1);
118   if (pp)
119     *pp = q;
120   if (strncmp(p, "none", q - p) == 0)
121     return (PARITY_NONE);
122   else if (strncmp(p, "odd", q - p) == 0)
123     return (PARITY_ODD);
124   else if (strncmp(p, "even", q - p) == 0)
125     return (PARITY_EVEN);
126   else
127     return (-1);
128 }
129
130 /* --- @getflow@ --- *
131  *
132  * Arguments:   @const char *p@ = pointer to string
133  *              @const char **pp@ = where to store final pointer
134  *
135  * Returns:     Flow control constant or @-1@ on error.
136  *
137  * Use:         Parses a flow control setting.
138  */
139
140 static int getflow(const char *p, const char **pp)
141 {
142   const char *q;
143
144   for (q = p; isalpha((unsigned char)*q); q++)
145     ;
146   if (q == p)
147     return (-1);
148   if (pp)
149     *pp = q;
150   if (strncmp(p, "none", q - p) == 0)
151     return (FLOW_NONE);
152   else if (strncmp(p, "soft", q - p) == 0 ||
153            strncmp(p, "xon-xoff", q - p) == 0 ||
154            strncmp(p, "xon/xoff", q - p) == 0 ||
155            strncmp(p, "xonxoff", q - p) == 0)
156     return (FLOW_XONXOFF);
157   else if (strncmp(p, "hard", q - p) == 0 ||
158            strncmp(p, "cts-rts", q - p) == 0 ||
159            strncmp(p, "cts/rts", q - p) == 0 ||
160            strncmp(p, "ctsrts", q - p) == 0 ||
161            strncmp(p, "rts/cts", q - p) == 0 ||
162            strncmp(p, "rts-cts", q - p) == 0 ||
163            strncmp(p, "rtscts", q - p) == 0)
164     return (FLOW_RTSCTS);
165   else
166     return (-1);
167 }
168
169 /* --- @serial_parse@ --- *
170  *
171  * Arguments:   @serial_config *sc@ = pointer to serial config structure
172  *              @const char *k, *v@ = keyword and value pair
173  *
174  * Returns:     Zero if OK, or @-1@ on error.
175  *
176  * Use:         Parses a serial config string into something more
177  *              reasonable.  The config structure should have been
178  *              initialized to something sensible (e.g., @SERIAL_INIT@)
179  *              already.
180  */
181
182 int serial_parse(serial_config *sc, const char *k, const char *v)
183 {
184   long x;
185   const char *q;
186   char *qq;
187
188   if (strcmp(k, "baud") == 0 || strcmp(k, "bps") == 0) {
189     if (!v || (x = getbaud(v, &q)) < 0 || *q)
190       return (-1);
191     sc->baud = x;
192   } else if (strcmp(k, "data") == 0 || strcmp(k, "data-bits") == 0 ||
193              strcmp(k, "databits") == 0 || strcmp(k, "data-len") == 0 ||
194              strcmp(k, "datalen") == 0 || strcmp(k, "word") == 0 ||
195              strcmp(k, "word-len") == 0 || strcmp(k, "wordlen") == 0) {
196     if (!v || (x = strtol(v, &qq, 10)) == 0 || *qq)
197       return (-1);
198     sc->wordlen = x;
199   } else if (strcmp(k, "parity") == 0) {
200     if (!v || (x = getparity(v, &q)) < 0 || *q)
201       return (-1);
202     sc->parity = x;
203   } else if (strcmp(k, "stop") == 0 || strcmp(k, "stop-bits") == 0 ||
204              strcmp(k, "stopbits") == 0) {
205     if (!v || (x = strtol(v, &qq, 10)) == 0 || *qq)
206       return (-1);
207     sc->stopbits = x;
208   } else if (strcmp(k, "flow") == 0 || strcmp(k, "flow-control") == 0 ||
209              strcmp(k, "flowcontrol") == 0) {
210     if (!v || (x = getflow(v, &q)) < 0 || *q)
211       return (-1);
212     sc->flow = x;
213   } else if (strcmp(k, "format") == 0) {
214     if (!v)
215       return (-1);
216     if ((x = strtol(v, &qq, 10)) == 0)
217       return (-1);
218     v = qq;
219     sc->wordlen = x;
220     if (*v == '-')
221       v++;
222     if ((x = getparity(v, &q)) < 0)
223       return (-1);
224     sc->parity = x;
225     v = q;
226     if (*v == '-')
227       v++;
228     if ((x = strtol(v, &qq, 10)) == 0)
229       return (-1);
230     v = qq;
231     sc->stopbits = x;
232     if (*v)
233       return (-1);
234   } else
235     return (-1);
236
237   return (0);
238 }
239
240 /*----- Test rig ----------------------------------------------------------*/
241
242 #ifdef TEST_RIG
243
244 #include <stdio.h>
245 #include <string.h>
246
247 int main(int argc, char *argv[])
248 {
249   int i;
250   static const char *ptab[] = { "none", "odd", "even" };
251   static const char *ftab[] = { "none", "xon/xoff", "rts/cts" };
252
253   for (i = 1; i < argc; i++) {
254     serial_config sc = SERIAL_INIT;
255     char *k, *v;
256
257     for (k = strtok(argv[i], ";"); k; k = strtok(0, ";")) {
258       if ((v = strchr(k, '=')) != 0)
259         *v++ = 0;
260       if (serial_parse(&sc, k, v)) {
261         printf("invalid serial configuration `%s=%s'\n", k, v);
262         goto next;
263       }
264     }
265     printf("%lu %u-%s-%u %s\n", sc.baud, sc.wordlen,
266            ptab[sc.parity], sc.stopbits, ftab[sc.flow]);
267   next:;
268   }
269   return (0);
270 }
271
272 #endif
273
274 /*----- That's all, folks -------------------------------------------------*/