GCC Code Coverage Report


Directory: src/gate/
File: src/gate/interfaces/senact.h
Date: 2026-06-15 21:53:51
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-2026, 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