Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
BroadcastTimeServer.cxx
Go to the documentation of this file.
1
36
38
39namespace openlcb
40{
41
52
56 : public CallableFlow<BroadcastTimeServerDateRolloverFinishInput>
57{
58public:
63 server->node()->iface())
64 , server_(server)
65 , writer_()
66 , timer_(this)
67 , abortCnt_(0)
68 {
69 }
70
75
78 {
79 // Because these requests are very timely, we use the abort count in
80 // order to flush out any previously requested date report finishes.
81 //
82 // Because this can only be called from the same executor as the state
83 // flow, we don't need an atomic lock.
84
85 // terminate early so that we can invalidate the active request(s)
86
87 if (abortCnt_ != UINT8_MAX)
88 {
89 ++abortCnt_;
90
92
94 }
95 }
96
97private:
101 Action entry() override
102 {
103 // see if we need to flush any stale requests
104 if (--abortCnt_ != 0)
105 {
106 return return_ok();
107 }
108
110 }
111
116 {
117 if (timer_.is_triggered())
118 {
119 // abort
120 return return_ok();
121 }
122
123 const struct tm *tm = server_->gmtime_recalculate();
124
125 int year = tm->tm_year + 1900;
126 if (year < 0)
127 {
128 year = 0;
129 }
130 if (year > 4095)
131 {
132 year = 4095;
133 }
134
135 uint64_t event_id =
137
138 writer_.WriteAsync(server_->node(), Defs::MTI_EVENT_REPORT,
139 WriteHelper::global(), eventid_to_buffer(event_id), this);
140
142 }
143
147 {
148 const struct tm *tm = server_->gmtime_get();
149
150 uint64_t event_id = BroadcastTimeDefs::date_to_event(
151 server_->event_base(), tm->tm_mon + 1, tm->tm_mday);
152
153 writer_.WriteAsync(server_->node(), Defs::MTI_EVENT_REPORT,
154 WriteHelper::global(), eventid_to_buffer(event_id), this);
155
156 return wait_and_return_ok();
157 }
158
162 uint8_t abortCnt_;
163
165};
166
167
171{
173 void reset()
174 {
175 }
176};
177
180 : public CallableFlow<BroadcastTimeServerTimeInput>
181{
182public:
186 : CallableFlow<BroadcastTimeServerTimeInput>(server->node()->iface())
187 , finish_(server)
188 , server_(server)
189 , writer_()
190 , timeRequired_(false)
191 , dateRollover_(false)
192 {
193 }
194
199
202 {
203 if (!timeRequired_)
204 {
205 // no time pending, make it pending
206 timeRequired_ = true;
208 }
209 }
210
211private:
214 Action entry() override
215 {
216 if (!server_->is_running())
217 {
218 // we shouldn't get here, but it means the clock is not running
219 return return_ok();
220 }
221
222 const struct tm *tm = server_->gmtime_recalculate();
223
224 if ((server_->get_rate_quarters() > 0 && tm->tm_hour == 0 &&
225 tm->tm_min == 0) ||
226 (server_->get_rate_quarters() < 0 && tm->tm_hour == 23 &&
227 tm->tm_min == 59))
228 {
229 // date rollover
230 dateRollover_ = true;
231
232 uint64_t event_id = server_->event_base();
234
235 writer_.WriteAsync(server_->node(), Defs::MTI_EVENT_REPORT,
236 WriteHelper::global(), eventid_to_buffer(event_id), this);
237
239 }
240 else
241 {
243 }
244 }
245
249 {
250 timeRequired_ = false;
251 const struct tm *tm = server_->gmtime_get();
252
253 uint64_t event_id = BroadcastTimeDefs::time_to_event(
254 server_->event_base(), tm->tm_hour, tm->tm_min);
255 writer_.WriteAsync(server_->node(), Defs::MTI_EVENT_REPORT,
256 WriteHelper::global(), eventid_to_buffer(event_id), this);
257
258 if (dateRollover_)
259 {
260 dateRollover_ = false;
262 }
263
264 return wait_and_return_ok();
265 }
266
270 uint8_t timeRequired_ : 1;
271 uint8_t dateRollover_ : 1;
272
274};
275
279{
281 void reset()
282 {
283 }
284};
285
288 : public CallableFlow<BroadcastTimeServerSyncInput>
289{
290public:
294 : CallableFlow<BroadcastTimeServerSyncInput>(server->node()->iface())
295 , server_(server)
296 , writer_()
297 , timer_(this)
298 , syncRequired_(false)
299#if defined(GTEST)
300 , shutdown_(false)
301#endif
302 {
303 }
304
309
312 {
313 if (!syncRequired_)
314 {
315 // no sync pending, make it pending
316 syncRequired_ = true;
317
318 // abort the current sync if sleeping
320
322 }
323 }
324
325#if defined(GTEST)
326 void shutdown()
327 {
328 shutdown_ = true;
329 request_sync();
330 }
331
332 bool is_shutdown()
333 {
334 return is_terminated();
335 }
336#endif
337
338private:
342 Action entry() override
343 {
344#if defined(GTEST)
345 if (shutdown_)
346 {
347 return StateFlowBase::exit();
348 }
349#endif
351
352 uint64_t event_id = server_->event_base();
353 event_id += server_->is_started() ?
356
357 syncRequired_ = false;
359 WriteHelper::global(), eventid_to_buffer(event_id), this);
360
362 }
363
367 {
368 uint64_t event_id = BroadcastTimeDefs::rate_to_event(
370
372 WriteHelper::global(), eventid_to_buffer(event_id), this);
373
375 }
376
380 {
381 const struct tm *tm = server_->gmtime_get();
382
383 int year = tm->tm_year + 1900;
384 if (year < 0)
385 {
386 year = 0;
387 }
388 if (year > 4095)
389 {
390 year = 4095;
391 }
392
393 uint64_t event_id =
395
397 WriteHelper::global(), eventid_to_buffer(event_id), this);
398
400 }
401
405 {
406 const struct tm *tm = server_->gmtime_get();
407
408 uint64_t event_id = BroadcastTimeDefs::date_to_event(
409 server_->event_base(), tm->tm_mon + 1, tm->tm_mday);
410
412 WriteHelper::global(), eventid_to_buffer(event_id), this);
413
415 }
416
420 {
421 const struct tm *tm = server_->gmtime_recalculate();
422
423 uint64_t event_id = BroadcastTimeDefs::time_to_event(
424 server_->event_base(), tm->tm_hour, tm->tm_min);
426 WriteHelper::global(), eventid_to_buffer(event_id), this);
427
429 }
430
434 {
435 if (server_->is_running())
436 {
437 const struct tm *tm = server_->gmtime_get();
438 //const struct tm *tm = server_->gmtime_recalculate();
439
440 // setup to send the next time report
441 time_t expires = server_->time();
442 if (server_->get_rate_quarters() > 0)
443 {
444 expires += 60 - tm->tm_sec;
445 }
446 else
447 {
448 // Note, we are adding 2 in order to account for some jitter
449 // in the RTOS timing. The result is that the next time report
450 // event might be sent at tm_sec == 57 to 59.
451 expires -= tm->tm_sec ? (tm->tm_sec + 2) : 2;
452 }
453
454 long long real_expires = 0;
455 bool result =
456 server_->real_nsec_until_fast_time_abs(expires, &real_expires);
457 HASSERT(result);
458 return sleep_and_call(&timer_, real_expires,
460 }
461 return return_ok();
462 }
463
467 {
468 if (!timer_.is_triggered())
469 {
470 server_->time_->request_time();
471 }
472
473 return return_ok();
474 }
475
479 uint8_t syncRequired_ : 1;
480#if defined(GTEST)
481 uint8_t shutdown_ : 1;
482#endif
483
485};
486
490{
493 void reset(uint16_t suffix)
494 {
495 suffix_ = suffix;
496 }
497
498 uint16_t suffix_;
499};
500
503 : public CallableFlow<BroadcastTimeServerSetInput>
504{
505public:
510 server->node()->iface())
511 , server_(server)
512 , writer_()
513 , timer_(this)
514 , requestCount_(0)
515 {
516 }
517
522
525 void request_set(uint16_t suffix)
526 {
527 if (requestCount_ != UINT8_MAX)
528 {
530
531 // waiting for a sync sequence to start, abort
533
535 }
536 }
537
538private:
541 Action entry() override
542 {
543 bool start_or_stop = false;
544 struct tm tm;
545 server_->gmtime_r(&tm);
546 time_t old_seconds = server_->time();
547 time_t new_seconds = 0;
548
549 uint16_t suffix = message()->data()->suffix_;
550
552 {
554 if (!server_->started_)
555 server_->started_ = true;
556 start_or_stop = true;
557 break;
559 server_->started_ = false;
560 start_or_stop = true;
561 break;
563 {
564 tm.tm_hour = BroadcastTimeDefs::event_to_hour(suffix);
565 tm.tm_min = BroadcastTimeDefs::event_to_min(suffix);
566 tm.tm_sec = server_->rate_ < 0 ? 59 : 0;
567 break;
568 }
570 {
571 tm.tm_mday = BroadcastTimeDefs::event_to_day(suffix);
572 tm.tm_mon = BroadcastTimeDefs::event_to_month(suffix) - 1;
573 break;
574 }
576 {
577 tm.tm_year = BroadcastTimeDefs::event_to_year(suffix) - 1900;
578 break;
579 }
581 {
583 break;
584 }
585 default:
586 // should never get there
588 return return_ok();
589 }
590
591 {
593 server_->seconds_ = mktime(&tm);
595 new_seconds = server_->seconds_;
596 }
597
598 server_->service_callbacks(old_seconds, new_seconds);
599
600 if (start_or_stop)
601 {
602 // start or stop events do not produce events of their own
604 }
605
606 uint64_t event_id = server_->event_base() + suffix - 0x8000;
607
608 writer_.WriteAsync(server_->node(), Defs::MTI_EVENT_REPORT,
609 WriteHelper::global(), eventid_to_buffer(event_id), this);
610
612 }
613
618 {
619 if (--requestCount_ == 0)
620 {
622 }
623 else
624 {
625 return return_ok();
626 }
627 }
628
632 {
633 if (!timer_.is_triggered())
634 {
635 // we have not received any more set events for 3 seconds, sync
636 server_->sync_->request_sync();
637 }
638 return return_ok();
639 }
640
645
647};
648
652{
653public:
658 server->node(), server,
660 std::placeholders::_1))
661 , server_(server)
662 {
663 memset(activeMinutes_, 0, sizeof(activeMinutes_));
664 }
665
670
674 void subscribe(int hour, int min)
675 {
676 if (hour <= 23 && hour >= 0 && min <= 59 && min >= 0)
677 {
678 AtomicHolder h(this);
679 if ((activeMinutes_[hour] & (0x1ULL << min)) == 0)
680 {
681 activeMinutes_[hour] |= 0x1ULL << min;
683 }
684 }
685 }
686
687private:
690 Action entry() override
691 {
693
695 }
696
700 {
701 server_->time_->request_time();
703 done->notify();
704 }
705
707 void update_notify() override
708 {
709 if (clock_->is_running())
710 {
714 }
715 }
716
721 time_t next_active_minute(time_t seconds, const struct tm *tm)
722 {
723 int hour = tm->tm_hour;
724 int min = tm->tm_min;
725
726 // we will target to produce a time event every four real minutes.
727 int rate_min_per_4_real_min = std::abs(clock_->get_rate_quarters());
728
729 // get the time_t value for the next whole minute
730 if (clock_->get_rate_quarters() > 0)
731 {
732 seconds += 60 - tm->tm_sec;
733 }
734 else
735 {
736 seconds -= tm->tm_sec + 1;
737 }
738
739 do
740 {
741 if (next_minute(&hour, &min))
742 {
743 // date rollover, always produce the date rollover event
744 break;
745 }
746 if (activeMinutes_[hour] & (0x1ULL << min))
747 {
748 break;
749 }
750 seconds += clock_->get_rate_quarters() > 0 ? 60 : -60;
751 }
752 while ((hour != tm->tm_hour || min != tm->tm_min) &&
753 --rate_min_per_4_real_min > 0);
754
755 return seconds;
756 }
757
762 bool next_minute(int *hour, int *min)
763 {
764 bool result = false;
765 if (clock_->get_rate_quarters() > 0)
766 {
767 if (++(*min) == 60)
768 {
769 *min = 0;
770 if (++(*hour) == 24)
771 {
772 *hour = 0;
773 result = true;
774 }
775 }
776 }
777 else if (clock_->get_rate_quarters() < 0)
778 {
779 if (--(*min) < 0)
780 {
781 *min = 59;
782 if (--(*hour) < 0)
783 {
784 *hour = 23;
785 result = true;
786 }
787 }
788 }
789 return result;
790 }
791
793 uint64_t activeMinutes_[24];
794
796};
797
798
799
800//
801// BroadcastTimeServer::BroadcastTimeServer()
802//
804 : BroadcastTime(node, clock_id)
805 , secondsRequested_(0)
806 , updateRequested_(false)
807#if defined (GTEST)
808 , shutdown_(false)
809#endif
810 , time_(new BroadcastTimeServerTime(this))
811 , sync_(new BroadcastTimeServerSync(this))
812 , set_(new BroadcastTimeServerSet(this))
813 , alarm_(new BroadcastTimeServerAlarm(this))
814{
815 EventRegistry::instance()->register_handler(
816 EventRegistryEntry(this, eventBase_), 16);
817}
818
819//
820// BroadcastTimeServer::~BroadcastTimeServer()
821//
823{
824 EventRegistry::instance()->unregister_handler(this);
825 delete alarm_;
826 delete set_;
827 delete sync_;
828 delete time_;
829}
830
831#if defined(GTEST)
832void BroadcastTimeServer::shutdown()
833{
834 shutdown_ = true;
835 sync_->shutdown();
836 alarm_->shutdown();
837}
838
839bool BroadcastTimeServer::is_shutdown()
840{
841 return is_terminated() && alarm_->is_shutdown() && sync_->is_shutdown();
842}
843#endif
844
845//
846// BroadcastTimeServer::handle_consumer_identified()
847//
849 const EventRegistryEntry &entry, EventReport *event,
850 BarrierNotifiable *done)
851{
852 done->notify();
853
856 {
857 int min = BroadcastTimeDefs::event_to_min(event->event);
858 int hour = BroadcastTimeDefs::event_to_hour(event->event);
859 if (hour != -1 && min != -1)
860 {
861 alarm_->subscribe(hour, min);
862 }
863 }
864}
865
872 const EventRegistryEntry &registry_entry, EventReport *event,
873 BarrierNotifiable *done)
874{
875 done->notify();
876 if (event->event == eventBase_ && event->mask == 0xFFFF)
877 {
878 // A new time client was identified, send a time sync.
879 sync_->request_sync();
880 }
881}
882
883//
884// BroadcastTimeServer::handle_event_report()
885//
887 EventReport *event,
888 BarrierNotifiable *done)
889{
890 AutoNotify an(done);
891
892 set_shortcut(event->event);
893}
894
895//
896// BroadcastTimeServer::set_shortcut
897//
899{
901 {
908 set_->request_set(event);
909 break;
911 if (is_terminated())
912 {
914 }
915 break;
916 default:
917 break;
918 }
919}
920
921//
922// BroadcastTimeServer::query_response()
923//
929
930} // namespace openlcb
int bind(int socket, const struct sockaddr *address, socklen_t address_len)
Bind a name to a socket.
Definition Socket.cxx:159
#define STATE(_fn)
Turns a function name into an argument to be supplied to functions expecting a state.
Definition StateFlow.hxx:61
See OSMutexLock in os/OS.hxx.
Definition Atomic.hxx:153
This class sends a notification in its destructor.
A BarrierNotifiable allows to create a number of child Notifiable and wait for all of them to finish.
void notify() override
Implementation of the barrier semantics.
Action return_ok()
Terminates the flow and returns the request buffer to the caller with an error code of OK (zero).
Action wait_and_return_ok()
Waits to be notified before moving onto the next state for termination.
static long long get_monotonic()
Get the monotonic time since the system started.
Definition OS.hxx:560
static EventRegistry * instance()
Definition Singleton.hxx:77
Return type for a state flow callback.
Use this timer class to deliver the timeout notification to a stateflow.
bool is_terminated()
Action exit()
Terminate current StateFlow activity.
void start_flow(Callback c)
Resets the flow to the specified state and starts it.
static void invoke_subflow_and_ignore_result(FlowInterface< Buffer< T > > *target_flow, Args &&... args)
Calls a helper flow to perform some actions.
Action wait_and_call(Callback c)
Wait for resource to become available before proceeding to next state.
Action sleep_and_call(::Timer *timer, long long timeout_nsec, Callback c)
Suspends execution of this control flow for a specified time.
struct tm * gmtime_r(struct tm *result)
Get the time as a standard struct tm.
Definition TimeBase.hxx:108
uint16_t started_
true if clock is started
Definition TimeBase.hxx:293
time_t seconds_
Clock time at the last time update.
Definition TimeBase.hxx:290
bool is_started()
Test of the clock is started (rate could still be 0).
Definition TimeBase.hxx:186
int16_t get_rate_quarters()
Report the clock rate as a 12-bit fixed point number (-512.00 to 511.75).
Definition TimeBase.hxx:170
bool is_running()
Test of the clock is running.
Definition TimeBase.hxx:178
long long timestamp_
OS time at the last time update.
Definition TimeBase.hxx:288
bool real_nsec_until_fast_time_abs(time_t fast_sec, long long *real_nsec)
Convert a fast time to absolute nsec until it will occur.
Definition TimeBase.hxx:249
time_t time()
Get the time as a value of seconds relative to the system epoch.
Definition TimeBase.hxx:87
int16_t rate_
effective clock rate
Definition TimeBase.hxx:291
bool is_triggered()
Definition Timer.hxx:273
void ensure_triggered()
Triggers the timer if it is not expired yet.
Definition Timer.hxx:249
Action call_immediately(Callback c)
Imediately call the next state upon return.
Basic alarm type that all other alarms are based off of.
void set(time_t time)
Start the alarm to expire at the given fast time.
BroadcastTime * clock_
clock that our alarm is based off of
virtual Action entry()
Entry point to state flow.
virtual void update_notify()
Called by the clock when time, rate, or running state has changed.
Specialization of the BroacastTimeAlarm to expire on the necessary clock minutes that must be produce...
uint64_t activeMinutes_[24]
active minutes to produce events on
BroadcastTimeServerAlarm(BroadcastTimeServer *server)
Constructor.
bool next_minute(int *hour, int *min)
Advance to the next hour/min based on rate setting.
void update_notify() override
Called when the clock time has changed.
time_t next_active_minute(time_t seconds, const struct tm *tm)
Get the next active minute that we will produce a time event on.
void expired_callback(BarrierNotifiable *done)
callback for when the alarm expires.
BroadcastTimeServer * server_
reference to our parent
Action entry() override
Entry point of the state machine.
void subscribe(int hour, int min)
Add a time event subscriber.
State machine for sending the date rollover finish (year and date events) sequence.
BroadcastTimeServer * server_
reference to our parent
uint8_t abortCnt_
request that the current processing be aborted
Action send_date_report()
Send the Event Report message appropriate for the date event ID.
BroadcastTimeServerDateRolloverFinish(BroadcastTimeServer *server)
Constuctor.
WriteHelper writer_
helper for sending event messages
void request_finish()
Request a date rollover finish.
Action entry() override
Wait the obligatory 3 seconds before sending the year/date report.
Action send_year_report()
Send the Event Report message appropriate for the year event ID.
State machine for sending the clock set sequence.
Action send_sync()
Request the sync sequence if timer has not been triggered early.
Action entry() override
Set a clock attribute and send the appropriate event report.
Action write_done()
The previous event write has completed.
BroadcastTimeServerSet(BroadcastTimeServer *server)
Constuctor.
WriteHelper writer_
helper for sending event messages
StateFlowTimer timer_
timer helper
uint8_t requestCount_
counter to know when there are no more requests
void request_set(uint16_t suffix)
Request a time parameter set.
BroadcastTimeServer * server_
reference to our parent
State machine for sending the clock sync sequence.
Action send_rate_report()
Send the Producer Identified message appropriate for the rate event ID.
WriteHelper writer_
helper for sending event messages
BroadcastTimeServerSync(BroadcastTimeServer *server)
Constuctor.
Action entry() override
Send the Producer Identified message appropriate for the start/stop event ID.
Action send_time_report_next()
Send the Event Report message appropriate for the time event ID.
BroadcastTimeServer * server_
reference to our parent
Action send_time_report_done()
If clock is running, sleep until next time report.
uint8_t syncRequired_
flag to keep track of multiple sync requests
Action send_year_report()
Send the Producer Identified message appropriate for the year event ID.
Action send_date_report()
Send the Producer Identified message appropriate for the date event ID.
Action send_time_report()
Send the Producer Identified message appropriate for the time event ID.
State machine for sending the clock time events.
Action entry() override
Send the date rollover event if appropriate.
BroadcastTimeServerDateRolloverFinish finish_
finsh the date rollover
BroadcastTimeServer * server_
reference to our parent
uint8_t timeRequired_
flag to keep track of multiple tme requests
BroadcastTimeServerTime(BroadcastTimeServer *server)
Constuctor.
Action send_time_report()
Send the appropriate time report event.
uint8_t dateRollover_
processing a date rollover
void request_time()
Request a time event.
WriteHelper writer_
helper for sending event messages
Implementation of a Broadcast Time Protocol server.
BroadcastTimeServer(Node *node, NodeID clock_id)
Constructor.
void handle_consumer_range_identified(const EventRegistryEntry &registry_entry, EventReport *event, BarrierNotifiable *done) override
Called on another node sending ConsumerRangeIdentified.
void handle_event_report(const EventRegistryEntry &entry, EventReport *event, BarrierNotifiable *done) override
Handle an incoming event report.
void handle_consumer_identified(const EventRegistryEntry &entry, EventReport *event, BarrierNotifiable *done) override
Handle an incoming consumer identified.
Action query_response()
Respond to a query by scheduling a sync.
Action entry()
Entry to state machine.
virtual void set_shortcut(uint64_t event) override
Try the possible set event shortcut.
Implementation of Broadcast Time Protocol.
const struct tm * gmtime_get()
Get the last calculated reprentation of time.
void service_callbacks(time_t old, time_t current)
Service all of the attached update subscribers.
Node * node()
Accessor method to get the Node reference.
EventId event_base()
Access method to get the (64-bit) Event ID base.
const struct tm * gmtime_recalculate()
Recalculate the struct tm representation of time.
EventId eventBase_
48-bit unique identifier for the clock instance
Structure used in registering event handlers.
Base class for NMRAnet nodes conforming to the asynchronous interface.
Definition Node.hxx:52
A statically allocated buffer for sending one message to the OpenLCB bus.
void WriteAsync(Node *node, Defs::MTI mti, NodeHandle dst, const payload_type &buffer, Notifiable *done)
Originates an NMRAnet message from a particular node.
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
Definition macros.h:138
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Removes default copy-constructor and assignment added by C++.
Definition macros.h:171
uint64_t NodeID
48-bit NMRAnet Node ID type
Payload eventid_to_buffer(uint64_t eventid)
Converts an Event ID to a Payload suitable to be sent as an event report.
Definition If.cxx:72
#define SEC_TO_NSEC(_sec)
Convert a second value to a nanosecond value.
Definition os.h:286
All callable flow request objects have to derive from this struct.
static uint64_t time_to_event(uint64_t event_base, int hours, int minutes)
Build an event from hours and minutes.
static int event_to_day(uint64_t event)
Get the day from the event.
static int event_to_month(uint64_t event)
Get the month from the event.
static uint64_t year_to_event(uint64_t event_base, int year)
Build an event from year.
static int event_to_min(uint64_t event)
Get the minutes from the event.
static EventType get_event_type(uint16_t suffix)
Get the EventTuype from the event suffix number.
static uint64_t rate_to_event(uint64_t event_base, int16_t rate)
Build an event from rate.
static int16_t event_to_rate(uint64_t event)
Get the rate from the event.
static uint64_t date_to_event(uint64_t event_base, int month, int day)
Build an event from month and day.
static int event_to_year(uint64_t event)
Get the year from the event.
static int event_to_hour(uint64_t event)
Get the hour from the event.
@ START_EVENT_SUFFIX
start clock event suffix value
@ DATE_ROLLOVER_EVENT_SUFFIX
rollover the date suffix value
@ STOP_EVENT_SUFFIX
stop clock event suffix value
Request structure used to send requests to the BroadcastTimeServerDateRolloverFinish object.
Request structure used to send requests to the BroadcastTimeServerSet object.
uint16_t suffix_
clock set event suffix
void reset(uint16_t suffix)
Setup "null" input.
Request structure used to send requests to the BroadcastTimeServerSync object.
Request structure used to send requests to the BroadcastTimeServerTime object.
@ MTI_PRODUCER_IDENTIFIED_VALID
producer broadcast, valid state
Shared notification structure that is assembled for each incoming event-related message,...
EventId mask
Specifies the mask in case the request is for an event range.
EventId event
The event ID from the incoming message.