Alex exoskeleton
ALEX SoftwareDocumentation
CO_comm_helpers.c
Go to the documentation of this file.
1 /*
2  * Command interface for CANopenSocket - ASCII helper functions.
3  *
4  * @file CO_comm_helpers.c
5  * @author Janez Paternoster
6  * @copyright 2015 Janez Paternoster
7  *
8  * This file is part of CANopenSocket, a Linux implementation of CANopen
9  * stack with master functionality. Project home page is
10  * <https://github.com/CANopenNode/CANopenSocket>. CANopenSocket is based
11  * on CANopenNode: <https://github.com/CANopenNode/CANopenNode>.
12  *
13  * CANopenSocket is free and open source software: you can redistribute
14  * it and/or modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation, either version 2 of the
16  * License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program. If not, see <http://www.gnu.org/licenses/>.
25  */
26 
27 
28 #include "CO_comm_helpers.h"
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <limits.h>
33 #include <ctype.h>
34 
35 
36 const char spaceDelim[] = " \t\n\r\f\v";
37 
38 
39 /* Storage for strtok_r. Functions here may be used within single thread only. */
40 static char *strtokSavePtr = NULL;
41 
42 
43 /******************************************************************************/
44 int dtpHex(char *strout, int stroutSize, char* bufSdo, int bufLen) {
45  int i;
46  char *out = strout;
47  int len = 0;
48 
49  strout[0] = 0;
50 
51  for(i=0; i<bufLen; i++) {
52  len += 3;
53  if(len >= stroutSize) {
54  break;
55  }
56  out += sprintf(out, "%02hhX ", bufSdo[i]);
57  }
58 
59  len = strlen(strout);
60 
61  /* remove end space */
62  if(len > 0) {
63  strout[--len] = 0;
64  }
65 
66  return len;
67 }
68 
69 static int dtpStr(char *strout, int stroutSize, char* bufSdo, int bufLen) {
70  int i, n = 0;
71 
72  /* A visible string with whitespace is enclosed with double quotes to denote it as
73  * single argument of the command. If a double quote is used within the string, the quotes
74  * are escaped by a second quotes, e.g. “Hello “”World””, CANopen is great”. */
75 
76  stroutSize -= 2;
77 
78  strout[n++] = '"';
79  for(i=0; i<bufLen; i++) {
80  char c = bufSdo[i];
81 
82  if(n >= stroutSize || c == 0) {
83  break;
84  }
85 
86  strout[n++] = c;
87  if(c == '"') {
88  strout[n++] = '"';
89  }
90  }
91  strout[n++] = '"';
92  strout[n] = '\0';
93 
94  return n;
95 }
96 
97 static int dtpU8 (char *strout, int stroutSize, char* bufSdo, int bufLen) {uint8_t num; memcpy(&num, bufSdo, 1); return sprintf(strout, "0x%02hhX", num);}
98 static int dtpU16(char *strout, int stroutSize, char* bufSdo, int bufLen) {uint16_t num; CO_memcpySwap2(&num, bufSdo); return sprintf(strout, "0x%04hX", num);}
99 static int dtpU32(char *strout, int stroutSize, char* bufSdo, int bufLen) {uint32_t num; CO_memcpySwap4(&num, bufSdo); return sprintf(strout, "0x%08X", num);}
100 static int dtpU64(char *strout, int stroutSize, char* bufSdo, int bufLen) {uint64_t num; CO_memcpySwap8(&num, bufSdo); return sprintf(strout, "0x%016lX", num);}
101 static int dtpI8 (char *strout, int stroutSize, char* bufSdo, int bufLen) {int8_t num; memcpy(&num, bufSdo, 1); return sprintf(strout, "%hhd", num);}
102 static int dtpI16(char *strout, int stroutSize, char* bufSdo, int bufLen) {int16_t num; CO_memcpySwap2(&num, bufSdo); return sprintf(strout, "%hd", num);}
103 static int dtpI32(char *strout, int stroutSize, char* bufSdo, int bufLen) {int32_t num; CO_memcpySwap4(&num, bufSdo); return sprintf(strout, "%d", num);}
104 static int dtpI64(char *strout, int stroutSize, char* bufSdo, int bufLen) {int64_t num; CO_memcpySwap8(&num, bufSdo); return sprintf(strout, "%ld", num);}
105 static int dtpR32(char *strout, int stroutSize, char* bufSdo, int bufLen) {float32_t num; CO_memcpySwap4(&num, bufSdo); return sprintf(strout, "%g", num);}
106 static int dtpR64(char *strout, int stroutSize, char* bufSdo, int bufLen) {float64_t num; CO_memcpySwap8(&num, bufSdo); return sprintf(strout, "%g", num);}
107 
108 
109 /******************************************************************************/
110 int dtsHex(char* bufSdo, int bufSdoSize, char *strin) {
111  char *token;
112  char *savePtr;
113  int len = 0;
114  uint8_t *ubuf = (uint8_t *) bufSdo;
115 
116  token = strtok_r(strin, spaceDelim, &savePtr);
117 
118  while(token != NULL) {
119  char *sRet;
120 
121  /* Finish if comment */
122  if(*token == '#') {
123  return len;
124  }
125 
126  /* Tokens must be two digit hex characters. Verify also memory overflow */
127  if(strlen(token) != 2 || len >= bufSdoSize) {
128  return 0;
129  }
130 
131  ubuf[len++] = (uint8_t)strtoul(token, &sRet, 16);
132 
133  if(sRet != strchr(token, '\0')) {
134  return 0;
135  }
136 
137  token = strtok_r(NULL, spaceDelim, &savePtr);
138  }
139 
140  return len;
141 }
142 
143 static int dtsStr(char* bufSdo, int bufSdoSize, char *strin) {
144  size_t len = strlen(strin);
145  int in = 0;
146  int out = 0;
147  int string_closed = 0;
148 
149  /* Remove blank spaces. Must begin with double quote. */
150  while(in < len) {
151  char c = strin[in++];
152 
153  if(isspace(c) == 0) {
154  if(c == '"') {
155  break;
156  }
157  else {
158  return 0;
159  }
160  }
161  }
162 
163  /* Get string between double quotes. Change "" into " inside string. */
164  while(in < len) {
165  char c = strin[in++];
166 
167  /* verify overflow */
168  if(out >= bufSdoSize) {
169  return 0;
170  }
171 
172  /* "" inside string means ". Single " ends the string. */
173  if(c == '"'){
174  c = strin[in++];
175  if(c != '"') {
176  string_closed = 1;
177  break;
178  }
179  }
180  bufSdo[out++] = c;
181  }
182 
183  /* Verify tail of string. */
184  if(string_closed == 1) {
185  /* Comment or nothing is allowed to follow. */
186  while(in < len) {
187  char c = strin[in++];
188 
189  if(isspace(c) == 0) {
190  if(c == '#') {
191  break;
192  }
193  else {
194  return 0;
195  }
196  }
197  }
198  }
199  else {
200  /* There was no ending quote. */
201  return 0;
202  }
203 
204  return out;
205 }
206 
207 static int dtsU8 (char* bufSdo, int bufSdoSize, char *strin) {int err = 0; uint8_t num = (uint8_t) getU32(strin, 0, UCHAR_MAX, &err); if(err != 0) return 0; memcpy(bufSdo, &num, 1); return 1;}
208 static int dtsU16(char* bufSdo, int bufSdoSize, char *strin) {int err = 0; uint16_t num = (uint16_t)getU32(strin, 0, USHRT_MAX, &err); if(err != 0) return 0; CO_memcpySwap2(bufSdo, &num); return 2;}
209 static int dtsU32(char* bufSdo, int bufSdoSize, char *strin) {int err = 0; uint32_t num = getU64(strin, 0, UINT_MAX, &err); if(err != 0) return 0; CO_memcpySwap4(bufSdo, &num); return 4;}
210 static int dtsU64(char* bufSdo, int bufSdoSize, char *strin) {int err = 0; uint64_t num = getU64(strin, 0, ULONG_MAX, &err); if(err != 0) return 0; CO_memcpySwap8(bufSdo, &num); return 8;}
211 static int dtsI8 (char* bufSdo, int bufSdoSize, char *strin) {int err = 0; int8_t num = (int8_t) getI32(strin, CHAR_MIN, CHAR_MAX, &err); if(err != 0) return 0; memcpy(bufSdo, &num, 1); return 1;}
212 static int dtsI16(char* bufSdo, int bufSdoSize, char *strin) {int err = 0; int16_t num = (int16_t) getI32(strin, SHRT_MIN, SHRT_MAX, &err); if(err != 0) return 0; CO_memcpySwap2(bufSdo, &num); return 2;}
213 static int dtsI32(char* bufSdo, int bufSdoSize, char *strin) {int err = 0; int32_t num = getI64(strin, INT_MIN, INT_MAX, &err); if(err != 0) return 0; CO_memcpySwap4(bufSdo, &num); return 4;}
214 static int dtsI64(char* bufSdo, int bufSdoSize, char *strin) {int err = 0; int64_t num = getI64(strin, LONG_MIN, LONG_MAX, &err); if(err != 0) return 0; CO_memcpySwap8(bufSdo, &num); return 8;}
215 static int dtsR32(char* bufSdo, int bufSdoSize, char *strin) {int err = 0; float32_t num = getR32(strin, &err); if(err != 0) return 0; CO_memcpySwap4(bufSdo, &num); return 4;}
216 static int dtsR64(char* bufSdo, int bufSdoSize, char *strin) {int err = 0; float64_t num = getR64(strin, &err); if(err != 0) return 0; CO_memcpySwap8(bufSdo, &num); return 8;}
217 
218 
219 static const dataType_t dataTypes[] = {
220  {"b", 1, dtpI8, dtsI8 }, /* bool_t (BOOLEAN) */
221  {"u8", 1, dtpU8, dtsU8 }, /* uint8_t (UNSIGNED8) */
222  {"u16", 2, dtpU16, dtsU16}, /* uint16_t (UNSIGNED16) */
223  {"u32", 4, dtpU32, dtsU32}, /* uint32_t (UNSIGNED32) */
224  {"u64", 8, dtpU64, dtsU64}, /* uint64_t (UNSIGNED64) */
225  {"i8", 1, dtpI8, dtsI8 }, /* int8_t (INTEGER8) */
226  {"i16", 2, dtpI16, dtsI16}, /* int16_t (INTEGER16) */
227  {"i32", 4, dtpI32, dtsI32}, /* int32_t (INTEGER32) */
228  {"i64", 8, dtpI64, dtsI64}, /* int64_t (INTEGER64) */
229  {"r32", 4, dtpR32, dtsR32}, /* float32_t (REAL32) */
230  {"r64", 8, dtpR64, dtsR64}, /* float64_t (REAL64) */
231  {"t", 0, dtpHex, dtsHex}, /* (TIME_OF_DAY (with two arguments: day, ms)) */
232  {"td", 0, dtpHex, dtsHex}, /* (TIME_DIFFERENCE) */
233  {"vs", 0, dtpStr, dtsStr}, /* char_t (VISIBLE_STRING) */
234  {"os", 0, dtpHex, dtsHex}, /* ochar_t (OCTET_STRING) (mime-base64 (RFC2045) should be used here) */
235  {"us", 0, dtpHex, dtsHex}, /* (UNICODE_STRING) (mime-base64 (RFC2045) should be used here) */
236  {"d", 0, dtpHex, dtsHex} /* domain_t (DOMAIN) (mime-base64 (RFC2045) should be used here) */
237 };
238 
239 
240 /******************************************************************************/
241 char *getTok(char* initStr, const char *delim, int *err) {
242  char *token;
243 
244  if(*err == 1) {
245  return NULL;
246  }
247 
248  if((token = strtok_r(initStr, delim, &strtokSavePtr)) == NULL) {
249  *err = 1;
250  return NULL;
251  }
252 
253  return token;
254 }
255 
256 
257 void lastTok(char* initStr, const char *delim, int *err) {
258  char *token;
259  int errTokLast = 0;
260 
261  token = getTok(initStr, delim, &errTokLast);
262 
263  if(token != NULL) {
264  if(*token != '#') {
265  *err = 1;
266  }
267  }
268 }
269 
270 
271 uint32_t getU32(char *token, uint32_t min, uint32_t max, int *err) {
272  uint32_t num;
273  char *sRet = NULL;
274 
275  if(token == NULL || *err == 1) {
276  *err = 1;
277  return 0;
278  }
279 
280  num = strtoul(token, &sRet, 0);
281  if(sRet != strchr(token, '\0') || num < min || num > max) {
282  *err = 1;
283  return 0;
284  }
285 
286  return num;
287 }
288 
289 
290 int32_t getI32(char *token, int32_t min, int32_t max, int *err) {
291  int32_t num;
292  char *sRet = NULL;
293 
294  if(token == NULL || *err == 1) {
295  *err = 1;
296  return 0;
297  }
298 
299  num = strtol(token, &sRet, 0);
300  if(sRet != strchr(token, '\0') || num < min || num > max) {
301  *err = 1;
302  return 0;
303  }
304 
305  return num;
306 }
307 
308 
309 uint64_t getU64(char *token, uint64_t min, uint64_t max, int *err) {
310  uint64_t num;
311  char *sRet = NULL;
312 
313  if(token == NULL || *err == 1) {
314  *err = 1;
315  return 0;
316  }
317 
318  num = strtoull(token, &sRet, 0);
319  if(sRet != strchr(token, '\0') || num < min || num > max) {
320  *err = 1;
321  return 0;
322  }
323 
324  return num;
325 }
326 
327 
328 int64_t getI64(char *token, int64_t min, int64_t max, int *err) {
329  int64_t num;
330  char *sRet = NULL;
331 
332  if(token == NULL || *err == 1) {
333  *err = 1;
334  return 0;
335  }
336 
337  num = strtoll(token, &sRet, 0);
338  if(sRet != strchr(token, '\0') || num < min || num > max) {
339  *err = 1;
340  return 0;
341  }
342 
343  return num;
344 }
345 
346 
347 float32_t getR32(char *token, int *err) {
348  float32_t num;
349  char *sRet = NULL;
350 
351  if(token == NULL || *err == 1) {
352  *err = 1;
353  return 0.0;
354  }
355 
356  num = strtof(token, &sRet);
357  if(sRet != strchr(token, '\0')) {
358  *err = 1;
359  return 0.0;
360  }
361 
362  return num;
363 }
364 
365 
366 float64_t getR64(char *token, int *err) {
367  float64_t num;
368  char *sRet = NULL;
369 
370  if(token == NULL || *err == 1) {
371  *err = 1;
372  return 0.0;
373  }
374 
375  num = strtod(token, &sRet);
376  if(sRet != strchr(token, '\0')) {
377  *err = 1;
378  return 0.0;
379  }
380 
381  return num;
382 }
383 
384 
385 const dataType_t *getDataType(char *token, int *err) {
386  int i, len;
387 
388  if(token == NULL || *err == 1) {
389  *err = 1;
390  return NULL;
391  }
392 
393  len = sizeof(dataTypes) / sizeof(dataType_t);
394 
395  for(i=0; i<len; i++) {
396  const dataType_t *dt = &dataTypes[i];
397  if(strcmp(token, dt->syntax) == 0) {
398  return dt;
399  }
400  }
401 
402  *err = 1;
403  return NULL;
404 }
405 
uint64_t getU64(char *token, uint64_t min, uint64_t max, int *err)
int64_t getI64(char *token, int64_t min, int64_t max, int *err)
uint32_t getU32(char *token, uint32_t min, uint32_t max, int *err)
char * getTok(char *initStr, const char *delim, int *err)
const dataType_t * getDataType(char *token, int *err)
void lastTok(char *initStr, const char *delim, int *err)
float32_t getR32(char *token, int *err)
int32_t getI32(char *token, int32_t min, int32_t max, int *err)
unsigned char uint8_t
Definition: CO_command.h:39
float64_t getR64(char *token, int *err)
unsigned short uint16_t
Definition: CO_command.h:35
unsigned int uint32_t
Definition: CO_command.h:31
Data types structure - Defined in CANOpen Code.
int dtpHex(char *strout, int stroutSize, char *bufSdo, int bufLen)
int dtsHex(char *bufSdo, int bufSdoSize, char *strin)
const char spaceDelim[]