GCC Code Coverage Report


Directory: src/gate/
File: src/gate/interfaces/senact.h
Date: 2025-09-14 13:10:38
Exec Total Coverage
Lines: 0 234 0.0%
Functions: 0 11 0.0%
Branches: 0 89 0.0%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2025, Stefan Meislinger <sm@opengate.at> |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28
29 /*
30 SENACT - SENsor & ACTor access protocol
31 =======================================
32
33 */
34
35 #ifndef SENACT_H_INCLUDED
36 #define SENACT_H_INCLUDED
37
38 #if defined(__cplusplus)
39 extern "C" {
40 #endif
41
42 /*
43 Communication protocol:
44
45 A message based on ASCII-text fields, beginning with a defined ID-Token and
46 terminated with a LINE-FEED (ASCII code 10)
47
48 this ID-Token is the message header to define which content data fields will
49 follow.
50 A KEY is a text
51
52 message:
53 "[ID]:[KEY]=[VALUE],[KEY]=[VALUE],...\n"
54
55
56
57 */
58
59 #define SENACT_DATA_TYPE_INT 0x01 /* integer (32 bit, big endian) */
60 #define SENACT_DATA_TYPE_FLOAT 0x02 /* floating point (32 bit, big endian) */
61 #define SENACT_DATA_TYPE_TEXT 0x03 /* 8-bit TEXT characters (surrounded by quotes, C-style escaped)*/
62
63 typedef unsigned char senact_device_id_t;
64 typedef unsigned char senact_data_type_t;
65 typedef unsigned char senact_data_category_t;
66 typedef unsigned char senact_data_unit_t;
67
68
69 typedef struct senact_device_type
70 {
71 senact_device_id_t device_id;
72 senact_data_type_t data_type;
73 senact_data_category_t data_category;
74 senact_data_unit_t data_unit;
75 } senact_device_type_t;
76
77 #define SENACT_DATA_CATEGORY_UNKNOWN 0x00
78 #define SENACT_DATA_CATEGORY_RAW 0x01 /* generic raw data, unspecified */
79 #define SENACT_DATA_CATEGORY_POS_X 0x10 /* position X coordinate */
80 #define SENACT_DATA_CATEGORY_POS_Y 0x11 /* position Y coordinate */
81 #define SENACT_DATA_CATEGORY_POS_Z 0x12 /* position Z coordinate */
82 #define SENACT_DATA_CATEGORY_VELOCITY 0x13 /* movement speed */
83 #define SENACT_DATA_CATEGORY_ACCEL_X 0x14
84 #define SENACT_DATA_CATEGORY_ACCEL_Y 0x15
85 #define SENACT_DATA_CATEGORY_ACCEL_Z 0x16
86 #define SENACT_DATA_CATEGORY_LENGTH 0x17 /* length measurement */
87 #define SENACT_DATA_CATEGORY_DISTANCE 0x18 /* distance measurement */
88 #define SENACT_DATA_CATEGORY_WEIGHT 0x19 /* weight measurement */
89 #define SENACT_DATA_CATEGORY_LOAD_CAPACITY 0x1a /* load capacity (e.g. battery capacity) */
90 #define SENACT_DATA_CATEGORY_LOAD 0x1b /* load amount (e.g. battery capacity) */
91 #define SENACT_DATA_CATEGORY_BUTTON 0x20
92 #define SENACT_DATA_CATEGORY_TEMPERATURE 0x21
93 #define SENACT_DATA_CATEGORY_PRESSURE 0x22
94
95
96 #define SENACT_DATA_UNIT_UNKNOWN 0x00
97 #define SENACT_DATA_UNIT_MILLIMETER 0x01 /* millimeters (position/distance) */
98 #define SENACT_DATA_UNIT_INCH 0x02 /* inch (position/distance) */
99 #define SENACT_DATA_UNIT_KMH 0x03 /* kilometers per hour (speed) */
100 #define SENACT_DATA_UNIT_MPH 0x04 /* miles per hour (speed) */
101 #define SENACT_DATA_UNIT_GRAMM 0x05 /* gramm (weight) */
102 #define SENACT_DATA_UNIT_PERCENT 0x05 /* percentage (0 - 100) */
103
104
105 static unsigned senact_strlen(char const* text)
106 {
107 unsigned length = 0;
108 if (text)
109 {
110 while (*text)
111 {
112 ++length;
113 ++text;
114 }
115 }
116 return length;
117 }
118
119 static unsigned senact_check_token(char const* target, unsigned target_len, char const* token, unsigned token_len)
120 {
121 unsigned ret = 0;
122 if (target_len >= token_len)
123 {
124 ret = token_len;
125 while (token_len-- != 0)
126 {
127 if (*token != *target)
128 {
129 ret = 0;
130 break;
131 }
132 ++target;
133 ++token;
134 }
135 }
136 return ret;
137 }
138
139 #ifndef SENACT_MAX_TEXT_LENGTH
140 #define SENACT_MAX_TEXT_LENGTH 62
141 #endif
142
143 typedef struct senact_value
144 {
145 unsigned char value_type;
146 union
147 {
148 long int_value;
149 float float_value;
150 char text_value[SENACT_MAX_TEXT_LENGTH + 1];
151 };
152 } senact_value_t;
153
154 static int senact_parse_digit(char chr)
155 {
156 if ((chr >= '0') && (chr <= '9'))
157 {
158 return (int)(chr - '0');
159 }
160 return -1;
161 }
162
163 static unsigned senact_parse_value(char const* source, unsigned source_len, senact_value_t* value)
164 {
165 unsigned chars_parsed = 0;
166 int digit;
167 int sign = 1;
168 int escape_mode = 0;
169 char* text_ptr = &value->text_value[0];
170 unsigned text_len = sizeof(value->text_value) - 1;
171 float decimal_factor;
172
173 do
174 {
175 if (source_len == 0)
176 {
177 break;
178 }
179
180 if (*source == '\"')
181 {
182 /* text value */
183 value->value_type = SENACT_DATA_TYPE_TEXT;
184 ++source;
185 --source_len;
186 ++chars_parsed;
187 while ((source_len != 0) && (text_len != 0))
188 {
189 if (escape_mode)
190 {
191 switch (*source)
192 {
193 case 'r': *text_ptr = '\r'; break;
194 case 'n': *text_ptr = '\r'; break;
195 case '\\': *text_ptr = '\r'; break;
196 case '\"': *text_ptr = '\"'; break;
197 case '\'': *text_ptr = '\''; break;
198 case 't': *text_ptr = '\r'; break;
199 case 'b': *text_ptr = '\r'; break;
200 default: *text_ptr = *source; break;
201 }
202 ++text_ptr;
203 --text_len;
204 ++source;
205 --source_len;
206 ++chars_parsed;
207 escape_mode = 0;
208 }
209 else
210 {
211 if (*source == '\"')
212 {
213 /* end of string found */
214 ++chars_parsed;
215 break;
216 }
217 else if (*source == '\\')
218 {
219 escape_mode = 1;
220 }
221 else
222 {
223 value->text_value[text_len] = *source;
224 ++text_len;
225 }
226 ++chars_parsed;
227 ++source;
228 --source_len;
229 }
230
231 }
232 *text_ptr = 0;
233 break;
234 }
235
236 /* expect a number */
237 value->value_type = SENACT_DATA_TYPE_INT;
238 value->int_value = 0;
239
240 if (*source == '-')
241 {
242 sign = -1;
243 ++source;
244 --source_len;
245 ++chars_parsed;
246 }
247
248 while (source_len != 0)
249 {
250 digit = senact_parse_digit(*source);
251 if (digit < 0)
252 {
253 break;
254 }
255 value->int_value *= 10;
256 value->int_value += (digit * sign);
257
258 ++source;
259 --source_len;
260 ++chars_parsed;
261 }
262 if (source_len == 0) break;
263
264 if (*source == '.')
265 {
266 /* seems to be a floating point value*/
267 value->float_value = (float)value->int_value;
268 value->value_type = SENACT_DATA_TYPE_FLOAT;
269 ++source;
270 --source_len;
271 ++chars_parsed;
272
273 decimal_factor = 0.1f * (float)sign;
274 while (source_len != 0)
275 {
276 digit = senact_parse_digit(*source);
277 if (digit < 0)
278 {
279 break;
280 }
281 value->float_value += (decimal_factor * (float)digit);
282 decimal_factor *= 0.1f;
283
284 ++source;
285 --source_len;
286 ++chars_parsed;
287 }
288 }
289
290 } while (0);
291
292 return chars_parsed;
293 }
294
295 static void senact_revert_string(char* target, unsigned target_len)
296 {
297 unsigned ndx, cnt;
298 char tmp;
299
300 cnt = target_len / 2;
301 for (ndx = 0; ndx != cnt; ++ndx)
302 {
303 tmp = target[ndx];
304 target[ndx] = target[target_len - 1 - ndx];
305 target[target_len - 1 - ndx] = tmp;
306 }
307 }
308
309 static unsigned senact_print_int(char* target, unsigned target_capacity, long value)
310 {
311 unsigned ret = 0;
312 unsigned long ul;
313 int digit;
314 unsigned index;
315
316
317 do
318 {
319 if (target_capacity < 2) break;
320 --target_capacity;
321
322 /*
323 if(value == 0)
324 {
325 *target = '0';
326 ++target;
327 ++ret;
328 *target = 0;
329 --target_capacity;
330 break;
331 }
332 */
333
334 if (value < 0)
335 {
336 *target = '-';
337 ++target;
338 ++ret;
339 --target_capacity;
340 ul = (unsigned long)-value;
341 }
342 else
343 {
344 ul = (unsigned long)value;
345 }
346
347 index = 0;
348 do
349 {
350 if (index >= target_capacity)
351 {
352 break;
353 }
354 digit = (int)(ul % 10);
355 ul /= 10;
356 target[index] = (char)('0' + digit);
357
358 ++index;
359 } while (ul != 0);
360
361 senact_revert_string(target, index);
362 target[index] = 0;
363 ret += index;
364 } while (0);
365 return ret;
366 }
367 static unsigned senact_print_float(char* target, unsigned target_capacity, float value, unsigned decimal_len)
368 {
369 unsigned ret = 0;
370 long int_value = (long)value;
371 float decimal = value - (float)int_value;
372 unsigned index;
373 float factor = 1.0f;
374 int digit;
375
376 do
377 {
378 if (decimal < 0.0f) decimal *= -1.0f;
379
380 ret = senact_print_int(target, target_capacity, int_value);
381 if (ret == 0) break;
382
383 target += ret;
384 target_capacity -= ret;
385
386 if (target_capacity < 2) break;
387 --target_capacity;
388
389 *target = '.';
390 ++target;
391 ++ret;
392 --target_capacity;
393
394 for (index = 0; (index < decimal_len) && (target_capacity != 0); ++index)
395 {
396 factor *= 10.0f;
397 digit = (int)(decimal * factor);
398 *target = (char)('0' + digit);
399 decimal -= (float)digit / factor;
400
401 ++target;
402 ++ret;
403 --target_capacity;
404 }
405
406 *target = 0;
407 } while (0);
408
409 return ret;
410
411 }
412 static unsigned senact_print_text(char* target, unsigned target_capacity, char const* text, unsigned text_len)
413 {
414 unsigned ret = 0;
415 char chr;
416 do
417 {
418 if (target_capacity < 4)
419 {
420 break;
421 }
422 target_capacity -= 4;
423
424 *target = '\"';
425 ++target;
426
427 while ((target_capacity != 0) && (text_len != 0))
428 {
429 chr = *text;
430 switch (chr)
431 {
432 case '\r':
433 {
434 *target = '\\';
435 ++target;
436 --target_capacity;
437 chr = 'r';
438 break;
439 }
440 case '\n':
441 {
442 *target = '\\';
443 ++target;
444 --target_capacity;
445 chr = 'n';
446 break;
447 }
448 case '\t':
449 {
450 *target = '\\';
451 ++target;
452 --target_capacity;
453 chr = 't';
454 break;
455 }
456 case '\\':
457 {
458 *target = '\\';
459 ++target;
460 --target_capacity;
461 chr = '\\';
462 break;
463 }
464 case '\"':
465 {
466 *target = '\\';
467 ++target;
468 --target_capacity;
469 chr = '\"';
470 break;
471 }
472 case '\'':
473 {
474 *target = '\\';
475 ++target;
476 --target_capacity;
477 chr = '\'';
478 break;
479 }
480 default:
481 {
482 break;
483 }
484 }
485
486 *target = chr;
487 ++target;
488 ++text;
489 if (target_capacity != 0)
490 {
491 --target_capacity;
492 }
493 --text_len;
494 }
495 } while (0);
496
497 *target = '\"';
498 ++target;
499 ++ret;
500 *target = '\0';
501
502 return ret;
503 }
504
505 static unsigned senact_print_value(senact_value_t const* value, char* target, unsigned target_capacity)
506 {
507 unsigned ret = 0;
508 switch (value->value_type)
509 {
510 case SENACT_DATA_TYPE_INT:
511 {
512 ret = senact_print_int(target, target_capacity, value->int_value);
513 break;
514 }
515 case SENACT_DATA_TYPE_FLOAT:
516 {
517 ret = senact_print_float(target, target_capacity, value->float_value, 6);
518 break;
519 }
520 case SENACT_DATA_TYPE_TEXT:
521 {
522 ret = senact_print_text(target, target_capacity, value->text_value, senact_strlen(value->text_value));
523 break;
524 }
525 default:
526 {
527 break;
528 }
529 }
530 return ret;
531 }
532
533
534 typedef int (*senact_function_inspect_sensor_t)(senact_device_id_t id, void* device_param,
535 senact_data_type_t* output_data_type,
536 senact_data_category_t* output_data_category,
537 senact_data_unit_t* output_data_unit);
538
539 typedef int (*senact_function_read_sensor_t)(senact_device_id_t id, senact_value_t* output_value);
540
541
542 typedef int (*senact_function_inspect_actor_t)(senact_device_id_t id, void* device_param,
543 senact_data_type_t* output_data_type,
544 senact_data_category_t* output_data_category,
545 senact_data_unit_t* output_data_unit);
546
547 typedef int (*senact_function_update_actor_t)(senact_device_id_t id, senact_value_t const* value);
548
549 typedef struct
550 {
551 senact_device_id_t sensor_id;
552 void* sensor_param;
553 senact_function_inspect_sensor_t inspect_sensor;
554 senact_function_read_sensor_t read_sensor;
555
556 } senact_sensor_t;
557
558 typedef struct
559 {
560 senact_device_id_t actor_id;
561 void* actor_param;
562 senact_function_inspect_actor_t inspect_actor;
563 senact_function_update_actor_t update_actor;
564 } senact_actor_t;
565
566 #ifndef SENACT_MAX_SENSOR_COUNT
567 #define SENACT_MAX_SENSOR_COUNT 16
568 #endif
569 #ifndef SENACT_MAX_ACTOR_COUNT
570 #define SENACT_MAX_ACTOR_COUNT 16
571 #endif
572
573 static senact_sensor_t sensors[SENACT_MAX_SENSOR_COUNT];
574 static senact_actor_t actors[SENACT_MAX_ACTOR_COUNT];
575
576
577
578
579
580
581
582 #define SENACT_MSG_TYPE_QUERY_SENSOR_COUNT 0x10
583 #define SENACT_MSG_TYPE_RESPONSE_SENSOR_COUNT 0x11
584 static char senact_id_query_sensor_count[] = { 'Q', 'S', 'C', ':' };
585 static char senact_id_response_sensors_count[] = { 'R', 'S', 'C', ':' };
586
587 typedef struct senact_query_sensor_count
588 {
589 unsigned char msg_type;
590 } senact_query_sensor_count_t;
591
592 static unsigned senact_print_query_sensor_count(senact_query_sensor_count_t const* msg, char* target, unsigned target_capacity)
593 {
594 unsigned ret = 0;
595 /* TODO implementation */
596 return ret;
597 }
598 static unsigned senact_parse_query_sensor_count(char const* source, unsigned source_length, senact_query_sensor_count_t* msg)
599 {
600 unsigned ret = 0;
601 /* TODO implementation */
602 return ret;
603 }
604
605
606
607 typedef struct senact_msg_header
608 {
609 unsigned char msg_type;
610 } senact_msg_header_t;
611
612
613 typedef struct senact_response_sensor_count
614 {
615 senact_msg_header_t header;
616 long sensor_count;
617 } senact_response_sensor_count_t;
618
619
620 static char senact_id_query_list_actors[] = { 'Q', 'L', 'A' };
621 static char senact_id_response_list_actors[] = { 'R', 'L', 'A' };
622
623 static char senact_id_query_sensor_value[] = { 'Q', 'S', 'V' };
624 static char senact_id_response_sensor_value[] = { 'R', 'S', 'V' };
625
626
627 typedef struct senact_msg_request_list_sensors
628 {
629 unsigned char msg_type[4];
630 unsigned short msg_length;
631 } senact_msg_request_list_sensors_t;
632
633
634
635 typedef union senact_msg
636 {
637 senact_msg_header_t header;
638
639 } senact_msg_t;
640
641 typedef struct senact_field_reflector
642 {
643 char key;
644 unsigned char data_type;
645 unsigned offset;
646 } senact_field_reflector_t;
647
648 typedef struct senact_msg_reflector
649 {
650 unsigned char msg_type;
651 char msg_id_token[3];
652 senact_field_reflector_t values[4];
653 } senact_msg_reflector_t;
654
655 static senact_msg_reflector_t senact_msg_reflectors[] =
656 {
657 {
658 SENACT_MSG_TYPE_QUERY_SENSOR_COUNT,
659 { 'Q', 'S', 'C' },
660 { 0 }
661 },
662 {
663 SENACT_MSG_TYPE_RESPONSE_SENSOR_COUNT,
664 { 'R', 'S', 'C' },
665 {
666 { 'V', SENACT_DATA_TYPE_INT, offsetof(senact_response_sensor_count_t, sensor_count) }
667 }
668 }
669
670 };
671
672
673 #if defined(__cplusplus)
674 }
675 #endif
676
677 #endif
678
679