-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathCANObject.h
More file actions
1400 lines (1204 loc) · 60.5 KB
/
Copy pathCANObject.h
File metadata and controls
1400 lines (1204 loc) · 60.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#pragma once
#include <stdint.h>
#include <string.h>
#include "CAN_common.h"
/******************************************************************************************
*
******************************************************************************************/
class CANObjectInterface
{
public:
virtual ~CANObjectInterface() = default;
/// @brief Registers an external handler for events. It will be called when event occurs.
/// @param event_handler Pointer to the event handler.
/// @param error_delay_ms Delay for the error events in milliseconds.
/// @return CANObjectInterface reference
virtual CANObjectInterface &RegisterFunctionEvent(event_handler_t event_handler, uint16_t error_delay_ms) = 0;
/// @brief Registers an external handler for events. It will be called when event occurs.
/// @param event_handler Pointer to the event handler.
/// @return CANObjectInterface reference
virtual CANObjectInterface &RegisterFunctionEvent(event_handler_t event_handler) = 0;
/// @brief Sets the value of error events resending delay.
/// @param delay_ms Delay for the error evends in milliseconds.
/// @return CANObjectInterface reference
virtual CANObjectInterface &SetErrorEventDelay(uint16_t delay_ms) = 0;
/// @brief Sets the hardware dependent error code.
/// @param error_code Error code to set.
/// @return CANObjectInterface reference
virtual CANObjectInterface &SetHardwareErrorCode(error_code_hardware_t error_code) = 0;
/// @brief Checks whether the external event function handler is set.
/// @return 'true' if the external handler exists, `false` if not
virtual bool HasExternalFunctionEvent() = 0;
/// @brief Registers an external handler for set commands. It will be called when set command comes.
/// @param set_handler Pointer to the set command handler.
/// @return CANObjectInterface reference
virtual CANObjectInterface &RegisterFunctionSet(set_handler_t set_handler) = 0;
/// @brief Checks whether the external set function handler is set.
/// @return 'true' if the external handler exists, `false` if not
virtual bool HasExternalFunctionSet() = 0;
/// @brief Register an external handler for set real-time commands. It will be called when set_realtime command comes.
/// @param set_realtime_handler Pointer to the set real-time external handler.
/// @param error_handler Pointer to the external error handler
/// @param data_interval_ms The interval between frames in milliseconds.
/// @param data_zero_point The data zero point.
/// @param is_silent 'true' if the object is 'slave' and it is just listening the CAN bus. 'false' in case the object is 'master' and it is sending real-time data.
/// @param frames_can_lost The number of frames which can be lost before the object generates an error.
/// @return CANObjectInterface reference
virtual CANObjectInterface &RegisterFunctionSetRealtime(set_realtime_handler_t set_realtime_handler, set_realtime_error_handler_t error_handler, uint16_t data_interval_ms,
void *data_zero_point, bool is_silent = true, uint8_t frames_can_lost = 3) = 0;
/// @brief Register an external handler for set real-time commands. It will be called when set_realtime command comes.
/// @param set_realtime_handler Pointer to the set real-time external handler.
/// @param error_handler Pointer to the external error handler
/// @return CANObjectInterface reference
virtual CANObjectInterface &RegisterFunctionSetRealtime(set_realtime_handler_t set_realtime_handler, set_realtime_error_handler_t error_handler) = 0;
/// @brief Sets the interval between CAN frames in milliseconds for real-time data.
/// @param data_interval_ms The interval in milliseconds.
/// @return CANObjectInterface reference
virtual CANObjectInterface &SetRealtimeDataInterval(uint16_t data_interval_ms) = 0;
/// @brief Returns real-time data interval of the object.
/// @return Real-time data interval.
virtual uint16_t GetRealtimeDataInterval() = 0;
/// @brief Sets zero point for real-time data.
/// @param data_zero_point Pointer to the data zero point.
/// @return CANObjectInterface reference
virtual CANObjectInterface &SetRealtimeZeroPoint(void *data_zero_point) = 0;
/// @brief Returns zero point of the real-time object.
/// @return Pointer to the real-time zero point.
virtual void *GetRealtimeZeroPoint() = 0;
/// @brief Sets the number of CAN frames which can be lost before the silent object generates an error.
/// @param frames_can_lost The number of CAN frames.
/// @return CANObjectInterface reference
virtual CANObjectInterface &SetRealtimeFramesCanLost(uint8_t frames_can_lost) = 0;
/// @brief Returns a number of CAN framse that can be lost by the silent listener object before it falls into the error state.
/// @return The number of CAN frames that can be lost.
virtual uint8_t GetRealtimeFramesCanLost() = 0;
/// @brief Checks whether the external set real-time function handler is set.
/// @return 'true' if the external handler exists, `false` if not
virtual bool HasExternalFunctionSetRealtime() = 0;
/// @brief Checks the error state of silent real-time object
/// @return 'true' if object is silent and it is in error state
virtual bool HasRealtimeError() = 0;
/// @brief Resets the error state of the silent object
virtual void ResetRealtimeErrorState() = 0;
/// @brief Checks whether the real-time function is stopped. The sender object is stoppet if current value is in zero-point. The silent listener object becomes stopped after receiving zero-point value.
/// @return 'true' if real-time object is stopped.
virtual bool DoesRealtimeStopped() = 0;
/// @brief Returns last real-time CAN frame received or sended by the object.
/// @return Last real-time CAN frame ID.
virtual uint8_t GetRealtimeLastFrameId() = 0;
/// @brief Registers an external handler for timer. It will be called when timer occurs.
/// @param timer_handler Pointer to the timer handler.
/// @param period_ms Timer's period in milliseconds.
/// @param flood_mode 'true' for work in flood mode: timer will send frame every period regardless of actual data updates
/// 'false' for work in frame limit mode: timer will send frames every period when the data was changed; but not more often than actual data updates.
/// Example #1: timer in the frame limit mode, period is 250 ms, data updates every 30 ms, frame will be sent every 250 ms.
/// Example #2: timer in the frame limit mode, period is 250 ms, data updates every 800 ms, frame will be sent every 800 ms.
/// Example #3: timer in the flood mode, period is 250 ms, data was updated once on boot, frame will be sent every 250 ms.
/// @return CANObjectInterface reference
virtual CANObjectInterface &RegisterFunctionTimer(timer_handler_t timer_handler, uint16_t period_ms, bool flood_mode = false) = 0;
/// @brief Registers an external handler for timer. It will be called when timer occurs.
/// @param timer_handler Pointer to the timer handler.
/// @return CANObjectInterface reference
virtual CANObjectInterface &RegisterFunctionTimer(timer_handler_t timer_handler) = 0;
/// @brief Sets the value of timer's period.
/// @param period_ms Timer's period in milliseconds.
/// @return CANObjectInterface reference
virtual CANObjectInterface &SetTimerPeriod(uint16_t period_ms) = 0;
/// @brief Specify the mode of the timer (flood or frame limit)
/// @param flood_mode 'true' for work in flood mode: timer will send frame every period regardless of actual data updates
/// 'false' for work in frame limit mode: timer will send frames every period when the data was changed; but not more often than actual data updates.
/// @return CANObjectInterface reference
virtual CANObjectInterface &SetTimerFloodMode(bool flood_mode) = 0;
/// @brief Checks whether the external timer function handler is set.
/// @return 'true' if the external handler exists, `false` if not
virtual bool HasExternalFunctionTimer() = 0;
/// @brief Registers an external handler for lock commands. It will be called when lock command comes.
/// @param lock_handler Pointer to the lock command handler.
/// @return CANObjectInterface reference
virtual CANObjectInterface &RegisterFunctionLock(lock_handler_t lock_handler) = 0;
/// @brief Checks whether the external lock function handler is set.
/// @return 'true' if the external handler exists, `false` if not
virtual bool HasExternalFunctionLock() = 0;
/// @brief Registers an external handler for request commands. It will be called when request command comes.
/// @param request_handler Pointer to the request command handler.
/// @return CANObjectInterface reference
virtual CANObjectInterface &RegisterFunctionRequest(request_handler_t request_handler) = 0;
/// @brief Checks whether the external request function handler is set.
/// @return 'true' if the external handler exists, `false` if not
virtual bool HasExternalFunctionRequest() = 0;
/// @brief Registers an external handler for toggle commands. It will be called when toggle command comes.
/// @param toggle_handler Pointer to the toggle command handler.
/// @return CANObjectInterface reference
virtual CANObjectInterface &RegisterFunctionToggle(toggle_handler_t toggle_handler) = 0;
/// @brief Checks whether the external toggle function handler is set.
/// @return 'true' if the external handler exists, `false` if not
virtual bool HasExternalFunctionToggle() = 0;
/// @brief Registers an external handler for action commands. It will be called when action command comes.
/// @param action_handler Pointer to the action command handler.
/// @return CANObjectInterface reference
virtual CANObjectInterface &RegisterFunctionAction(action_handler_t action_handler) = 0;
/// @brief Checks whether the external action function handler is set.
/// @return 'true' if the external handler exists, `false` if not
virtual bool HasExternalFunctionAction() = 0;
/// @brief Sets type of object.
/// @param object_type type of the object ot set.
/// @return CANObjectInterface reference
virtual CANObjectInterface &SetObjectType(object_type_t object_type) = 0;
/// @brief Performs CANObjects processing
/// @param time Current time
/// @param can_frame [OUT] CAN frame for storing the outgoing data
/// @param error [OUT] An outgoing error structure. It will be filled by object if something went wrong.
/// @return The result of CANObject processing (should we send any CAN frames or not)
virtual can_result_t Process(uint32_t time, can_frame_t &can_frame, can_error_t &error) = 0;
/// @brief Process incoming CAN frame
/// @param can_frame [OUT] CAN frame for processing
/// @param error [OUT] An outgoing error structure. It will be filled by object if something went wrong.
/// @return The result of incoming can frame processing (should we send any CAN frames or not)
virtual can_result_t InputCanFrame(can_frame_t &can_frame, can_error_t &error) = 0;
/// @brief Fills CAN frame from the object with specified data
/// @param can_frame [OUT] CAN frame for processing
/// @param error [OUT] An outgoing error structure. It will be filled by object if something went wrong.
/// @param function_id [IN] CAN function ID
/// @param data [IN] Frame data to send in CAN frame
/// @param data_length [IN] Frame data length
/// @return The result of incoming can frame processing (should we send any CAN frames or not)
virtual can_result_t FillRawCanFrame(can_frame_t &can_frame, can_error_t &error, can_function_id_t function_id, uint8_t *data = nullptr, uint8_t data_length = 0) = 0;
/// @brief Returns CANObject ID
/// @return Returns CANObject ID
virtual can_object_id_t GetId() = 0;
/// @brief Returns the value of error events resending delay.
/// @return Delay for the error evends in milliseconds.
virtual uint16_t GetErrorEventDelay() = 0;
/// @brief Returns the value of timer's period.
/// @return Timer's period in milliseconds.
virtual uint16_t GetTimerPeriod() = 0;
/// @brief Return the timer's mode.
/// @return 'true' if timer works in flood mode, 'false' if timer works in frame limit mode.
virtual bool IsTimerInFloodMode() = 0;
/// @brief Checks whether the data has been updated by SetValue() since the last frame was sent.
/// @return 'true' if there is new data.
virtual bool DoesTimerHaveNewData() = 0;
/// @brief Returns the type of the object.
/// @return Type code of the object.
virtual object_type_t GetObjectType() = 0;
/// @brief Checks if the object is the system one.
/// @return 'true' if the object is the system one (not ordinary).
virtual bool IsObjectTypeSystem() = 0;
/// @brief Checks if the object is ordinary.
/// @return 'true' it the object is ordinary.
virtual bool IsObjectTypeOrdinary() = 0;
/// @brief Checks if the object is silent.
/// @return 'true' it the object is silent.
virtual bool IsObjectTypeSilent() = 0;
/// @brief Checks if the object type is unknown.
/// @return 'true' if the object type is unknown.
virtual bool IsObjectTypeUnknown() = 0;
/// @brief Returns the current lock level of the object.
/// @return Lock level code of the object.
virtual lock_func_level_t GetLockLevel() = 0;
/// @brief Returns number of data fields in the CANObject
/// @return Returns number of data fields in the CANObject
virtual uint8_t GetDataFieldCount() = 0;
/// @brief Returns size of the CANObject's one data field item
/// @return Returns size of the CANObject's one data field item
virtual uint8_t GetOneDataFieldSize() = 0;
/// @brief Universal setter for CANObject's data fields
/// @param index Index of data field to set. If the index is out of range, nothing will be done.
/// @param value Pointer to the variable with data. The size of data depends of CANObject.
/// @param timer_type The type of value for timer. With this we can specify is value normal, in warning range or in critical range.
/// @param event_type The type of value for event. With this we can specify whether an event and what kind of event it is.
virtual void SetValue(uint8_t index, void *value,
timer_type_t timer_type = CAN_TIMER_TYPE_NONE,
event_type_t event_type = CAN_EVENT_TYPE_NONE) = 0;
/// @brief Universal getter for CANObject's data fields
/// @param index Index of data field to get value from. If the index is out of range, nullpointer will be returned.
/// @return Pointer to the data field value. If the index is out of range, nullpointer will be returned.
virtual void *GetValuePtr(uint8_t index) = 0;
};
/******************************************************************************************
*
******************************************************************************************/
template <typename T, uint8_t _item_count = 1>
class CANObject : public CANObjectInterface
{
static_assert(_item_count > 0); // 0 data fields isn't allowed
static_assert(_item_count * sizeof(T) <= 7); // static data size validation (to fit it into the can frame)
public:
/// @brief Default constructor is forbidden.
CANObject() = delete;
/// @brief Constructor of the CANObject
/// @param id ID of the object
/// @param timer_period_ms Period of a timer function. If CAN_TIMER_DISABLED then timer is disabled
/// @param error_period_ms Repeation delay of an error event. If CAN_ERROR_DISABLED then error event is disabled
/// @param flood_mode 'true' for work in flood mode: timer will send frame every period regardless of actual data updates
/// 'false' for work in frame limit mode: timer will send frames every period when the data was changed; but not more often than actual data updates.
/// Example #1: timer in the frame limit mode, period is 250 ms, data updates every 30 ms, frame will be sent every 250 ms.
/// Example #2: timer in the frame limit mode, period is 250 ms, data updates every 800 ms, frame will be sent every 800 ms.
/// Example #3: timer in the flood mode, period is 250 ms, data was updated once on boot, frame will be sent every 250 ms.
/// @param object_type The type of the object. By default, it is set to CAN_OBJECT_TYPE_ORDINARY, which means that the object isn't a system one.
CANObject(can_object_id_t id,
uint16_t timer_period_ms = CAN_TIMER_DISABLED, uint16_t error_period_ms = CAN_ERROR_DISABLED,
bool flood_mode = false, object_type_t object_type = CAN_OBJECT_TYPE_ORDINARY)
: _id(id), _timer_period(timer_period_ms), _error_period(error_period_ms), _flood_mode(flood_mode), _object_type(object_type)
{
ClearDataFields();
};
virtual ~CANObject() = default;
/// @brief Clears all data fields and related structures.
void ClearDataFields()
{
memset(_data_fields, 0, _item_count * sizeof(T));
memset(_states_of_data_fields, 0, _item_count * sizeof(T));
}
/// @brief Timer type checker with upper limits
/// @param value Current object value
/// @param max_norm Upper limit of the normal value range
/// @param max_warn Upper limit of the warning value range
/// @return Type of the timer for specified value
static inline timer_type_t TernaryExDown(T value, T max_norm, T max_warn)
{
if (value <= max_norm)
return CAN_TIMER_TYPE_NORMAL;
if (value <= max_warn)
return CAN_TIMER_TYPE_WARNING;
return CAN_TIMER_TYPE_CRITICAL;
}
/// @brief Timer type checker with lower limits
/// @param value Current object value
/// @param min_norm Lower limit of the normal value range
/// @param min_warn Lower limit of the warning value range
/// @return Type of the timer for specified value
static inline timer_type_t TernaryExUp(T value, T min_norm, T min_warn)
{
if (value >= min_norm)
return CAN_TIMER_TYPE_NORMAL;
if (value >= min_warn)
return CAN_TIMER_TYPE_WARNING;
return CAN_TIMER_TYPE_CRITICAL;
}
/// @brief Registers an external handler for events. It will be called when event occurs.
/// @param event_handler Pointer to the event handler.
/// @param error_delay_ms Delay for the error evends in milliseconds.
/// @return CANObjectInterface reference
virtual CANObjectInterface &RegisterFunctionEvent(event_handler_t event_handler, uint16_t error_delay_ms) override
{
RegisterFunctionEvent(event_handler);
SetErrorEventDelay(error_delay_ms);
return *this;
};
/// @brief Registers an external handler for events. It will be called when event occurs.
/// @param event_handler Pointer to the event handler.
/// @return CANObjectInterface reference
virtual CANObjectInterface &RegisterFunctionEvent(event_handler_t event_handler) override
{
_event_handler = event_handler;
return *this;
};
/// @brief Sets the value of error events resending delay.
/// @param delay_ms Delay for the error evends in milliseconds.
/// @return CANObjectInterface reference
virtual CANObjectInterface &SetErrorEventDelay(uint16_t delay_ms) override
{
_error_period = delay_ms;
return *this;
};
/// @brief Sets the hardware dependent error code.
/// @param error_code Error code to set.
/// @return CANObjectInterface reference
virtual CANObjectInterface &SetHardwareErrorCode(error_code_hardware_t error_code) override
{
_error_code_hardware = error_code;
return *this;
}
/// @brief Checks whether the external event function handler is set.
/// @return 'true' if the external handler exists, `false` if not
virtual bool HasExternalFunctionEvent() override
{
return _event_handler != nullptr;
};
/// @brief Registers an external handler for set commands. It will be called when set command comes.
/// @param set_handler Pointer to the set command handler.
/// @return CANObjectInterface reference
virtual CANObjectInterface &RegisterFunctionSet(set_handler_t set_handler) override
{
_set_handler = set_handler;
return *this;
};
/// @brief Checks whether the external set function handler is set.
/// @return 'true' if the external handler exists, `false` if not
virtual bool HasExternalFunctionSet() override
{
return _set_handler != nullptr;
};
/// @brief Register an external handler for set realtime commands. It will be called when set_realtime command comes.
/// @param set_realtime_handler Pointer to the set realtime external handler.
/// @param error_handler Pointer to the external error handler.
/// @param data_interval_ms The interval between frames in milliseconds.
/// @param data_zero_point The data zero point.
/// @param is_silent 'true' if the object is 'slave' and it is just listening the CAN bus. 'false' in case the object is 'master' and it is sending realtime data.
/// @param frames_can_lost The number of frames which can be lost before the object generates an error.
/// @return CANObjectInterface reference
virtual CANObjectInterface &RegisterFunctionSetRealtime(set_realtime_handler_t set_realtime_handler, set_realtime_error_handler_t error_handler, uint16_t data_interval_ms,
void *data_zero_point, bool is_silent = true, uint8_t frames_can_lost = 3) override
{
RegisterFunctionSetRealtime(set_realtime_handler, error_handler);
SetRealtimeDataInterval(data_interval_ms);
SetRealtimeZeroPoint(data_zero_point);
SetRealtimeFramesCanLost(frames_can_lost);
if (is_silent)
{
SetObjectType(CAN_OBJECT_TYPE_SILENT);
_realtime_stopped = true;
}
return *this;
};
/// @brief Register an external handler for set realtime commands. It will be called when set_realtime command comes.
/// @param set_realtime_handler Pointer to the set realtime external handler.
/// @param error_handler Pointer to the external error handler.
/// @return CANObjectInterface reference
virtual CANObjectInterface &RegisterFunctionSetRealtime(set_realtime_handler_t set_realtime_handler, set_realtime_error_handler_t error_handler) override
{
_set_realtime_handler = set_realtime_handler;
_set_realtime_error_handler = error_handler;
return *this;
};
/// @brief Sets the interval between CAN frames in milliseconds for realtime data.
/// @param data_interval_ms The interval in milliseconds.
/// @return CANObjectInterface reference
virtual CANObjectInterface &SetRealtimeDataInterval(uint16_t data_interval_ms) override
{
_realtime_frame_interval = data_interval_ms;
return *this;
};
/// @brief Returns real-time data interval of the object.
/// @return Real-time data interval.
virtual uint16_t GetRealtimeDataInterval() override
{
return _realtime_frame_interval;
};
/// @brief Sets zero point for real-time data.
/// @param data_zero_point Pointer to the data zero point.
/// @return CANObjectInterface reference
virtual CANObjectInterface &SetRealtimeZeroPoint(void *data_zero_point) override
{
_realtime_zero_point = *(T *)data_zero_point;
return *this;
};
/// @brief Returns zero point of the real-time object.
/// @return Pointer to the real-time zero point.
virtual void *GetRealtimeZeroPoint() override
{
return &_realtime_zero_point;
};
/// @brief Sets the number of CAN frames which can be lost before the object generates an error.
/// @param frames_can_lost The number of CAN frames.
/// @return CANObjectInterface reference
virtual CANObjectInterface &SetRealtimeFramesCanLost(uint8_t frames_can_lost) override
{
_realtime_frames_can_lost = frames_can_lost;
return *this;
}
/// @brief Returns a number of CAN framse that can be lost by the silent listener object before it falls into the error state.
/// @return The number of CAN frames that can be lost.
virtual uint8_t GetRealtimeFramesCanLost() override
{
return _realtime_frames_can_lost;
};
/// @brief Checks whether the external set realtime function handler is set.
/// @return 'true' if the external handler exists, `false` if not
virtual bool HasExternalFunctionSetRealtime() override
{
return _set_realtime_handler != nullptr && _set_realtime_error_handler != nullptr;
};
/// @brief Checks error state of silent real-time object
/// @return 'true' if object is silent and it is in error state
virtual bool HasRealtimeError() override
{
return /*IsObjectTypeSilent() &&*/ _realtime_has_error;
};
/// @brief Resets the error state of the silent object
virtual void ResetRealtimeErrorState() override
{
_realtime_has_error = false;
_realtime_silent_should_ignore_frame_id_once = true;
};
/// @brief Checks whether the real-time function is stopped. The sender object is stoppet if current value is in zero-point. The silent listener object becomes stopped after receiving zero-point value.
/// @return 'true' if real-time object is stopped.
virtual bool DoesRealtimeStopped() override
{
return _realtime_stopped;
};
/// @brief Returns last real-time CAN frame received or sended by the object.
/// @return Last real-time CAN frame ID.
virtual uint8_t GetRealtimeLastFrameId() override
{
return _realtime_frame_id;
};
/// @brief Registers an external handler for timer. It will be called when timer occurs.
/// @param timer_handler Pointer to the timer handler.
/// @param period_ms Timer's period in milliseconds.
/// @param flood_mode 'true' for work in flood mode: timer will send frame every period regardless of actual data updates
/// 'false' for work in frame limit mode: timer will send frames every period when the data was changed; but not more often than actual data updates.
/// Example #1: timer in the frame limit mode, period is 250 ms, data updates every 30 ms, frame will be sent every 250 ms.
/// Example #2: timer in the frame limit mode, period is 250 ms, data updates every 800 ms, frame will be sent every 800 ms.
/// Example #3: timer in the flood mode, period is 250 ms, data was updated once on boot, frame will be sent every 250 ms.
/// @return CANObjectInterface reference
virtual CANObjectInterface &RegisterFunctionTimer(timer_handler_t timer_handler, uint16_t period_ms, bool flood_mode = false) override
{
RegisterFunctionTimer(timer_handler);
SetTimerPeriod(period_ms);
SetTimerFloodMode(flood_mode);
return *this;
};
/// @brief Registers an external handler for timer. It will be called when timer occurs.
/// @param timer_handler Pointer to the timer handler.
/// @return CANObjectInterface reference
virtual CANObjectInterface &RegisterFunctionTimer(timer_handler_t timer_handler) override
{
_timer_handler = timer_handler;
return *this;
};
/// @brief Sets the value of timer's period.
/// @param period_ms Timer's period in milliseconds.
/// @return CANObjectInterface reference
virtual CANObjectInterface &SetTimerPeriod(uint16_t period_ms) override
{
_timer_period = period_ms;
return *this;
};
/// @brief Specify the mode of the timer (flood or frame limit)
/// @param flood_mode 'true' for work in flood mode: timer will send frame every period regardless of actual data updates
/// 'false' for work in frame limit mode: timer will send frames every period when the data was changed; but not more often than actual data updates.
/// @return CANObjectInterface reference
virtual CANObjectInterface &SetTimerFloodMode(bool flood_mode) override
{
_flood_mode = flood_mode;
return *this;
};
/// @brief Checks whether the external timer function handler is set.
/// @return 'true' if the external handler exists, `false` if not
virtual bool HasExternalFunctionTimer() override
{
return _timer_handler != nullptr;
};
/// @brief Registers an external handler for lock commands. It will be called when lock command comes.
/// @param lock_handler Pointer to the lock command handler.
/// @return CANObjectInterface reference
virtual CANObjectInterface &RegisterFunctionLock(lock_handler_t lock_handler) override
{
_lock_handler = lock_handler;
return *this;
};
/// @brief Checks whether the external lock function handler is set.
/// @return 'true' if the external handler exists, `false` if not
virtual bool HasExternalFunctionLock() override
{
return _lock_handler != nullptr;
};
/// @brief Registers an external handler for request commands. It will be called when request command comes.
/// @param request_handler Pointer to the request command handler.
/// @return CANObjectInterface reference
virtual CANObjectInterface &RegisterFunctionRequest(request_handler_t request_handler) override
{
_request_handler = request_handler;
return *this;
};
/// @brief Checks whether the external request function handler is set.
/// @return 'true' if the external handler exists, `false` if not
virtual bool HasExternalFunctionRequest() override
{
return _request_handler != nullptr;
};
/// @brief Registers an external handler for toggle commands. It will be called when toggle command comes.
/// @param toggle_handler Pointer to the toggle command handler.
/// @return CANObjectInterface reference
virtual CANObjectInterface &RegisterFunctionToggle(toggle_handler_t toggle_handler) override
{
_toggle_handler = toggle_handler;
return *this;
};
/// @brief Checks whether the external toggle function handler is set.
/// @return 'true' if the external handler exists, `false` if not
virtual bool HasExternalFunctionToggle() override
{
return _toggle_handler != nullptr;
};
/// @brief Registers an external handler for action commands. It will be called when action command comes.
/// @param action_handler Pointer to the action command handler.
/// @return CANObjectInterface reference
virtual CANObjectInterface &RegisterFunctionAction(action_handler_t action_handler) override
{
_action_handler = action_handler;
return *this;
};
/// @brief Checks whether the external action function handler is set.
/// @return 'true' if the external handler exists, `false` if not
virtual bool HasExternalFunctionAction() override
{
return _action_handler != nullptr;
};
/// @brief Sets type of object.
/// @param object_type type of the object ot set.
/// @return CANObjectInterface reference
virtual CANObjectInterface &SetObjectType(object_type_t object_type) override
{
_object_type = object_type;
return *this;
};
/// @brief Performs processing of CANObjects
/// @param time Current time
/// @param can_frame [OUT] CAN frame for storing the outgoing data
/// @param error [OUT] An outgoing error structure. It will be filled by object if something went wrong.
/// @return The result of CANObject processing (should we send any CAN frames or not)
virtual can_result_t Process(uint32_t time, can_frame_t &can_frame, can_error_t &error) override
{
// Check data timeout for real-time silent (listener) objects
if (IsObjectTypeSilent())
{
if (HasExternalFunctionSetRealtime() &&
!DoesRealtimeStopped() &&
_realtime_frame_interval > 0 &&
time - _last_realtime_frame_time >= (uint32_t)(_realtime_frame_interval * (_realtime_frames_can_lost + 1) + (_realtime_frame_interval >> 1))) // _realtime_frames_can_lost+1.5 interframe time interval
{
_realtime_has_error = true;
_set_realtime_error_handler(time - _last_realtime_frame_time);
_realtime_stopped = true;
}
return CAN_RESULT_IGNORE; // all other functions are ignored for silent objects
}
timer_type_t max_timer_type = CAN_TIMER_TYPE_NONE;
event_type_t max_event_type = CAN_EVENT_TYPE_NONE;
for (uint8_t i = 0; i < _item_count; i++)
{
if ((_states_of_data_fields[i] & CAN_TIMER_TYPE_MASK) > max_timer_type)
max_timer_type = (timer_type_t)(_states_of_data_fields[i] & (uint8_t)CAN_TIMER_TYPE_MASK);
if ((_states_of_data_fields[i] & CAN_EVENT_TYPE_MASK) > max_event_type)
max_event_type = (event_type_t)(_states_of_data_fields[i] & (uint8_t)CAN_EVENT_TYPE_MASK);
}
if (max_event_type > CAN_EVENT_TYPE_NONE &&
max_event_type != CAN_EVENT_TYPE_ERROR &&
_error_code_hardware > 0)
{
// clear hardware error code if all field's error levels are not CAN_EVENT_TYPE_ERROR
_error_code_hardware = 0;
}
can_result_t handler_result = CAN_RESULT_IGNORE;
clear_can_frame_struct(can_frame);
if (_realtime_frame_interval > 0 &&
!DoesRealtimeStopped() &&
time - _last_realtime_frame_time >= _realtime_frame_interval)
{
// Automatic sending of real-time data by sender object
handler_result = _PrepareRealtimeCanFrame(can_frame, error);
if (handler_result == CAN_RESULT_CAN_FRAME)
{
_last_realtime_frame_time = time;
if (_realtime_zero_point == GetValue(0))
{
_realtime_stopped = true;
}
}
}
else if (max_event_type == CAN_EVENT_TYPE_NORMAL)
{
// CAN_EVENT_TYPE_NORMAL should be sent immediately, we don't need to check the time
if (HasExternalFunctionEvent())
{
handler_result = _event_handler(can_frame, max_event_type, error);
}
else
{
handler_result = _PrepareEventCanFrame(max_event_type, can_frame, error);
}
// we need to flush the NORMAL event state of all data fields
for (uint8_t i = 0; i < _item_count; i++)
{
if ((_states_of_data_fields[i] & CAN_EVENT_TYPE_MASK) == CAN_EVENT_TYPE_NORMAL)
_states_of_data_fields[i] = (_states_of_data_fields[i] & (uint8_t)CAN_TIMER_TYPE_MASK) | CAN_EVENT_TYPE_NONE;
}
}
else if (max_event_type > CAN_EVENT_TYPE_NORMAL && _error_period != CAN_ERROR_DISABLED)
{
// error flood prevention
if (time - _last_event_time >= _error_period)
{
if (HasExternalFunctionEvent())
{
handler_result = _event_handler(can_frame, max_event_type, error);
}
else
{
handler_result = _PrepareEventCanFrame(max_event_type, can_frame, error);
}
_last_event_time = time;
}
}
else if (max_timer_type != CAN_TIMER_TYPE_NONE && _timer_period != CAN_TIMER_DISABLED && time - _last_timer_time >= _timer_period)
{
if (DoesTimerHaveNewData() || IsTimerInFloodMode())
{
if (HasExternalFunctionTimer())
{
handler_result = _timer_handler(can_frame, max_timer_type, error);
}
else
{
handler_result = _PrepareTimerCanFrame(max_timer_type, can_frame, error);
}
_last_timer_time = time;
_has_new_data = false;
}
}
return handler_result;
};
/// @brief Process incoming CAN frame
/// @param can_frame CAN frame for processing
/// @param error An outgoing error structure. It will be filled by object if something went wrong.
/// @param time Current time. If time not specified CAN bus listeners can't measure realtime data timeout.
/// @return The result of incoming can frame processing (should we send any CAN frames or not)
virtual can_result_t InputCanFrame(can_frame_t &can_frame, can_error_t &error) override
{
if (!can_frame.initialized)
{
error.error_section = ERROR_SECTION_CAN_OBJECT;
error.error_code = ERROR_CODE_OBJECT_BAD_INCOMING_CAN_FRAME;
error.function_id = CAN_FUNC_EVENT_ERROR;
return CAN_RESULT_ERROR;
}
if (_IsLockedForFunction(can_frame.function_id))
{
can_frame.initialized = false;
error.error_section = ERROR_SECTION_CAN_OBJECT;
error.error_code = ERROR_CODE_OBJECT_LOCKED;
error.function_id = CAN_FUNC_EVENT_ERROR;
return CAN_RESULT_ERROR;
}
can_result_t handler_result = CAN_RESULT_ERROR;
switch (can_frame.function_id)
{
case CAN_FUNC_SET_IN:
if (HasExternalFunctionSet())
{
handler_result = _set_handler(can_frame, error);
}
else
{
handler_result = CAN_RESULT_ERROR;
can_frame.initialized = false;
error.error_section = ERROR_SECTION_CAN_OBJECT;
error.error_code = ERROR_CODE_OBJECT_SET_FUNCTION_IS_MISSING;
error.function_id = CAN_FUNC_EVENT_ERROR;
}
break;
case CAN_FUNC_TOGGLE_IN:
if (HasExternalFunctionToggle())
{
if (can_frame.raw_data_length == 1)
{
handler_result = _toggle_handler(can_frame, error);
}
else
{
handler_result = CAN_RESULT_ERROR;
can_frame.initialized = false;
error.error_section = ERROR_SECTION_CAN_OBJECT;
error.error_code = ERROR_CODE_OBJECT_TOGGLE_COMMAND_FRAME_SHOULD_NOT_HAVE_DATA;
error.function_id = CAN_FUNC_EVENT_ERROR;
}
}
else
{
handler_result = CAN_RESULT_ERROR;
can_frame.initialized = false;
error.error_section = ERROR_SECTION_CAN_OBJECT;
error.error_code = ERROR_CODE_OBJECT_TOGGLE_FUNCTION_IS_MISSING;
error.function_id = CAN_FUNC_EVENT_ERROR;
}
break;
case CAN_FUNC_ACTION_IN:
if (HasExternalFunctionAction())
{
if (can_frame.raw_data_length == 1)
{
handler_result = _action_handler(can_frame, error);
}
else
{
handler_result = CAN_RESULT_ERROR;
can_frame.initialized = false;
error.error_section = ERROR_SECTION_CAN_OBJECT;
error.error_code = ERROR_CODE_OBJECT_ACTION_COMMAND_FRAME_SHOULD_NOT_HAVE_DATA;
error.function_id = CAN_FUNC_EVENT_ERROR;
}
}
else
{
handler_result = CAN_RESULT_ERROR;
can_frame.initialized = false;
error.error_section = ERROR_SECTION_CAN_OBJECT;
error.error_code = ERROR_CODE_OBJECT_ACTION_FUNCTION_IS_MISSING;
error.function_id = CAN_FUNC_EVENT_ERROR;
}
break;
case CAN_FUNC_SET_REAL_TIME_IN:
// By default sender objects shouldn't react to this type of frames, so default result is CAN_RESULT_IGNORE
handler_result = CAN_RESULT_IGNORE;
if (IsObjectTypeSilent() && HasExternalFunctionSetRealtime() && !HasRealtimeError())
{
if (can_frame.raw_data_length > 2 && _IsCorrectNextRealtimeFrameId(can_frame.data[0]))
{
_last_realtime_frame_time = can_frame.time_ms;
_realtime_silent_should_ignore_frame_id_once = false;
_realtime_frame_id = can_frame.data[0];
T data = *(T *)&can_frame.data[1];
SetValue(0, data);
handler_result = _set_realtime_handler(can_frame, error);
if (data == *(T *)GetRealtimeZeroPoint())
{
_realtime_stopped = true;
}
}
}
break;
case CAN_FUNC_LOCK_IN:
if (can_frame.raw_data_length != 2)
{
handler_result = CAN_RESULT_ERROR;
can_frame.initialized = false;
error.error_section = ERROR_SECTION_CAN_OBJECT;
error.error_code = ERROR_CODE_OBJECT_LOCK_COMMAND_FRAME_DATA_LENGTH_ERROR;
error.function_id = CAN_FUNC_LOCK_OUT_ERR;
}
else if (!_IsItKnownLockLevel((lock_func_level_t)can_frame.data[0]))
{
handler_result = CAN_RESULT_ERROR;
can_frame.initialized = false;
error.error_section = ERROR_SECTION_CAN_OBJECT;
error.error_code = ERROR_CODE_OBJECT_LOCK_LEVEL_IS_UNKNOWN;
error.function_id = CAN_FUNC_LOCK_OUT_ERR;
}
else
{
// save lock level because can frame may be rewrited by handler
lock_func_level_t specified_lock_level = (lock_func_level_t)can_frame.data[0];
if (HasExternalFunctionLock())
{
handler_result = _lock_handler(can_frame, error);
}
else
{
handler_result = _PrepareRawCanFrame(can_frame, error, CAN_FUNC_LOCK_OUT_OK, &specified_lock_level, 1);
}
// if handler was successful then we need to save specified lock level
if (handler_result == CAN_RESULT_CAN_FRAME)
{
_lock_level = specified_lock_level;
}
}
break;
case CAN_FUNC_REQUEST_IN:
if (HasExternalFunctionRequest())
{
handler_result = _request_handler(can_frame, error);
}
else
{
handler_result = _PrepareRequestCanFrame(can_frame, error);
}
break;
case CAN_FUNC_SYSTEM_REQUEST_IN:
handler_result = _PrepareSystemRequestCanFrame(can_frame, error);
break;
default:
handler_result = CAN_RESULT_ERROR;
can_frame.initialized = false;
error.error_section = ERROR_SECTION_CAN_OBJECT;
error.error_code = ERROR_CODE_OBJECT_UNSUPPORTED_FUNCTION;
error.function_id = CAN_FUNC_EVENT_ERROR;
break;
}
// restoring ID in case an external handler has overwritten it
can_frame.object_id = GetId();
if (!can_frame.initialized && error.error_section == ERROR_SECTION_NONE && handler_result != CAN_RESULT_IGNORE)
{
handler_result = CAN_RESULT_ERROR;
error.error_section = ERROR_SECTION_CAN_OBJECT;
error.error_code = ERROR_CODE_OBJECT_INCORRECT_FUNCTION_WORKFLOW;
if (error.function_id == CAN_FUNC_NONE)
error.function_id = CAN_FUNC_EVENT_ERROR;
}
return handler_result;
};
/// @brief Fills CAN frame from the object with specified data
/// @param can_frame [OUT] CAN frame for filling
/// @param error [OUT] An outgoing error structure. It will be filled by object if something went wrong.
/// @param function_id [IN] CAN function ID
/// @param data [IN] Frame data to send in CAN frame
/// @param data_length [IN] Frame data length
/// @return The result of incoming can frame processing (should we send any CAN frames or not)
virtual can_result_t FillRawCanFrame(can_frame_t &can_frame, can_error_t &error, can_function_id_t function_id, uint8_t *data = nullptr, uint8_t data_length = 0) override
{
return _PrepareRawCanFrame(can_frame, error, function_id, data, data_length);
};
/// @brief Returns CANObject ID
/// @return Returns CANObject ID
virtual can_object_id_t GetId() override
{
return _id;
};
/// @brief Returns the value of error events resending delay.
/// @return Delay for the error evends in milliseconds.
virtual uint16_t GetErrorEventDelay() override
{
return _error_period;
};
/// @brief Returns the value of timer's period.
/// @return Timer's period in milliseconds.
virtual uint16_t GetTimerPeriod() override
{
return _timer_period;
};
/// @brief Return the timer's mode.