Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
EventHandlerTemplates.cxx
Go to the documentation of this file.
1
35#define _DEFAULT_SOURCE
36#include <unistd.h>
37
38#include "utils/logging.h"
41
42#ifdef __linux__
43//#define DESCRIBE_VAR
44#endif
45
46#ifdef DESCRIBE_VAR
47extern int debug_variables;
48int debug_variables = 0;
49#include <string>
50namespace openlcb
51{
52extern const string &GetNameForEvent(uint64_t);
53
54__attribute__((weak)) const string &GetNameForEvent(uint64_t)
55{
56 static string empty;
57 return empty;
58}
59}
60#endif
61
62namespace openlcb
63{
64
65BitRangeEventPC::BitRangeEventPC(Node *node, uint64_t event_base,
66 uint32_t *backing_store, unsigned size)
67 : event_base_(event_base)
68 , node_(node)
69 , data_(backing_store)
70 , size_(size)
71{
72 unsigned mask = EventRegistry::align_mask(&event_base, size * 2);
73 EventRegistry::instance()->register_handler(
74 EventRegistryEntry(this, event_base), mask);
75}
76
77BitRangeEventPC::~BitRangeEventPC()
78{
79 EventRegistry::instance()->unregister_handler(this);
80}
81
82void BitRangeEventPC::GetBitAndMask(unsigned bit, uint32_t **data,
83 uint32_t *mask) const
84{
85 *data = nullptr;
86 if (bit >= size_)
87 return;
88 *data = data_ + (bit >> 5);
89 *mask = 1 << (bit & 31);
90}
91
92bool BitRangeEventPC::Get(unsigned bit) const
93{
94 HASSERT(bit < size_);
95 uint32_t *ofs;
96 uint32_t mask;
97 GetBitAndMask(bit, &ofs, &mask);
98 if (!ofs)
99 return false;
100 return (*ofs) & mask;
101}
102
103void BitRangeEventPC::Set(unsigned bit, bool new_value, WriteHelper *writer,
104 BarrierNotifiable *done)
105{
106 HASSERT(bit < size_);
107 uint32_t *ofs;
108 uint32_t mask;
109 GetBitAndMask(bit, &ofs, &mask);
110 bool old_value = new_value;
111 HASSERT(ofs);
112 if (ofs)
113 old_value = (*ofs) & mask;
114 if (old_value != new_value)
115 {
116#ifdef DESCRIBE_VAR
117 if (debug_variables)
118 {
119 fprintf(stderr, "BitRange: OUT bit %x (%s) to %d\n", bit,
120 GetNameForEvent(event_base_ + (bit * 2)).c_str(),
121 new_value);
122 }
123#else
124 LOG(VERBOSE, "BitRange: set bit %x to %d", bit, new_value);
125#endif
126 if (new_value)
127 {
128 *ofs |= mask;
129 }
130 else
131 {
132 *ofs &= ~mask;
133 }
134 uint64_t event = event_base_ + bit * 2;
135 if (!new_value)
136 event++;
137 writer->WriteAsync(node_, Defs::MTI_EVENT_REPORT, WriteHelper::global(),
138 eventid_to_buffer(event), done);
139#ifndef TARGET_LPC11Cxx
140 if (!done)
141 {
142 // We wait for the sent-out event to come back. Otherwise there is a
143 // race
144 // condition where the automata processing could have gone further,
145 // but
146 // the "set" message will arrive.
147 while (EventService::instance->event_processing_pending())
148 {
149 usleep(100);
150 }
151 }
152#endif
153 }
154 else
155 {
156#ifdef DESCRIBE_VAR
157 if (debug_variables > 2)
158 {
159 fprintf(stderr, "BitRange: out bit %x (%s) to %d\n", bit,
160 GetNameForEvent(event_base_ + (bit * 2)).c_str(),
161 new_value);
162 }
163#endif
164 if (done)
165 done->notify();
166 }
167}
168
170 BarrierNotifiable *done)
171{
172 done->notify();
173 if (event->event < event_base_)
174 return;
175 uint64_t d = (event->event - event_base_);
176 bool new_value = !(d & 1);
177 d >>= 1;
178 if (d >= size_)
179 return;
180 int bit = d;
181#ifdef DESCRIBE_VAR
182 if (debug_variables)
183 {
184 fprintf(stderr, "BitRange: IN bit %x (%s) to %d\n", bit,
185 GetNameForEvent(event_base_ + (2 * bit)).c_str(), new_value);
186 }
187#else
188 LOG(VERBOSE, "BitRange: evt bit %x to %d", bit, new_value);
189#endif
190
191 uint32_t *ofs = nullptr;
192 uint32_t mask = 0;
193 GetBitAndMask(bit, &ofs, &mask);
194 if (new_value)
195 {
196 *ofs |= mask;
197 }
198 else
199 {
200 *ofs &= ~mask;
201 }
202}
203
205 BarrierNotifiable *done)
206{
207 HandleIdentifyBase(Defs::MTI_PRODUCER_IDENTIFIED_VALID, event, done);
208}
209
211 BarrierNotifiable *done)
212{
213 HandleIdentifyBase(Defs::MTI_CONSUMER_IDENTIFIED_VALID, event, done);
214}
215void BitRangeEventPC::HandleIdentifyBase(Defs::MTI mti_valid,
216 EventReport *event,
217 BarrierNotifiable *done)
218{
219 if (event->event < event_base_)
220 return done->notify();
221 uint64_t d = (event->event - event_base_);
222 bool new_value = !(d & 1);
223 d >>= 1;
224 if (d >= size_)
225 return done->notify();
226 uint32_t *ofs = nullptr;
227 uint32_t mask = 0;
228 GetBitAndMask(d, &ofs, &mask);
229 Defs::MTI mti = mti_valid;
230 bool old_value = *ofs & mask;
231 if (old_value != new_value)
232 {
233 mti++; // mti INVALID
234 }
235
236 event->event_write_helper<1>()->WriteAsync(node_, mti,
237 WriteHelper::global(), eventid_to_buffer(event->event), done);
238}
239
240uint64_t EncodeRange(uint64_t begin, unsigned size)
241{
242 // We assemble a valid event range identifier that covers our block.
243 uint64_t end = begin + size - 1;
244 uint64_t shift = 1;
245 while ((begin + shift) < end)
246 {
247 begin &= ~shift;
248 shift <<= 1;
249 }
250 if (begin & shift)
251 {
252 // last real bit is 1 => range ends with zero.
253 return begin;
254 }
255 else
256 {
257 // last real bit is zero. Set all lower bits to 1.
258 begin |= shift - 1;
259 return begin;
260 }
261}
262
264 BarrierNotifiable *done)
265{
266 if (event->dst_node && event->dst_node != node_)
267 {
268 return done->notify();
269 }
270 uint64_t range = EncodeRange(event_base_, size_ * 2);
271 event->event_write_helper<1>()->WriteAsync(node_,
272 Defs::MTI_PRODUCER_IDENTIFIED_RANGE, WriteHelper::global(),
273 eventid_to_buffer(range), done->new_child());
274 event->event_write_helper<2>()->WriteAsync(node_,
275 Defs::MTI_CONSUMER_IDENTIFIED_RANGE, WriteHelper::global(),
276 eventid_to_buffer(range), done->new_child());
277 done->maybe_done();
278}
279
281 BarrierNotifiable *done)
282{
283 uint64_t range = EncodeRange(event_base_, size_ * 2);
285 WriteHelper::global(), eventid_to_buffer(range), done);
286}
287
289 EventReport *event,
290 BarrierNotifiable *done)
291{
292 if (event->dst_node && event->dst_node != node_)
293 {
294 return done->notify();
295 }
296 uint64_t range = EncodeRange(event_base_, size_ * 2);
297 event->event_write_helper<1>()->WriteAsync(node_,
298 Defs::MTI_PRODUCER_IDENTIFIED_RANGE, WriteHelper::global(),
299 eventid_to_buffer(range), done->new_child());
300 done->maybe_done();
301}
302
303ByteRangeEventC::ByteRangeEventC(Node *node, uint64_t event_base,
304 uint8_t *backing_store, unsigned size)
305 : event_base_(event_base)
306 , node_(node)
307 , data_(backing_store)
308 , size_(size)
309{
310 unsigned mask = EventRegistry::align_mask(&event_base, size * 256);
311 EventRegistry::instance()->register_handler(
312 EventRegistryEntry(this, event_base), mask);
313}
314
315ByteRangeEventC::~ByteRangeEventC()
316{
317 EventRegistry::instance()->unregister_handler(this);
318}
319
321 BarrierNotifiable *done)
322{
323 done->notify();
324 uint8_t *storage;
325 uint8_t value;
326 if (!DecodeEventId(event->event, &storage, &value))
327 return;
328#ifdef DESCRIBE_VAR
329 if (debug_variables)
330 {
331 fprintf(stderr, "ByteRange: IN byte %" PRIxPTR " to %d\n", storage - data_,
332 value);
333 }
334#else
335 LOG(VERBOSE, "ByteRange: evt %x to %d", (unsigned)(storage - data_), value);
336#endif
337 *storage = value;
338 notify_changed(storage - data_);
339}
340
341bool ByteRangeEventC::DecodeEventId(uint64_t event, uint8_t **storage,
342 uint8_t *value)
343{
344 *storage = nullptr;
345 *value = 0;
346 if (event < event_base_)
347 return false;
348 event -= event_base_;
349 *value = event & 0xff;
350 event >>= 8;
351 if (event >= size_)
352 return false;
353 *storage = data_ + event;
354 return true;
355}
356
358 BarrierNotifiable *done)
359{
360 uint8_t *storage;
361 uint8_t value;
362 if (!DecodeEventId(event->event, &storage, &value))
363 {
364 return done->notify();
365 }
367 if (*storage != value)
368 {
369 mti++; // mti INVALID
370 }
371 event->event_write_helper<1>()->WriteAsync(node_, mti,
372 WriteHelper::global(), eventid_to_buffer(event->event), done);
373}
374
376 BarrierNotifiable *done)
377{
378 if (event->dst_node && event->dst_node != node_)
379 {
380 return done->notify();
381 }
382 uint64_t range = EncodeRange(event_base_, size_ * 256);
383 event->event_write_helper<1>()->WriteAsync(node_,
384 Defs::MTI_CONSUMER_IDENTIFIED_RANGE, WriteHelper::global(),
385 eventid_to_buffer(range), done->new_child());
386 done->maybe_done();
387}
388
390 BarrierNotifiable *done)
391{
392 uint64_t range = EncodeRange(event_base_, size_ * 256);
394 WriteHelper::global(), eventid_to_buffer(range), done);
395}
396
397ByteRangeEventP::ByteRangeEventP(Node *node, uint64_t event_base,
398 uint8_t *backing_store, unsigned size)
399 : ByteRangeEventC(node, event_base, backing_store, size)
400{
401}
402
404 BarrierNotifiable *done)
405{
406 // Nothing to do for producers.
407 done->notify();
408}
410 BarrierNotifiable *done)
411{
412 // Nothing to do for producers.
413 done->notify();
414}
415
416uint64_t ByteRangeEventP::CurrentEventId(unsigned byte)
417{
418 return event_base_ + (byte << 8) + data_[byte];
419}
420
422 BarrierNotifiable *done)
423{
424 uint8_t *storage;
425 uint8_t value;
426 if (!DecodeEventId(event->event, &storage, &value))
427 {
428 return done->notify();
429 }
431 if (*storage != value)
432 {
433 mti++; // mti INVALID
434 // We also send off the currently valid value.
435 Update(
436 storage - data_, event->event_write_helper<2>(), done->new_child());
437 }
438 event->event_write_helper<1>()->WriteAsync(node_, mti,
439 WriteHelper::global(), eventid_to_buffer(event->event),
440 done->new_child());
441 done->maybe_done();
442}
444 BarrierNotifiable *done)
445{
446 if (event->dst_node && event->dst_node != node_)
447 {
448 return done->notify();
449 }
450 uint64_t range = EncodeRange(event_base_, size_ * 256);
451 event->event_write_helper<1>()->WriteAsync(node_,
452 Defs::MTI_PRODUCER_IDENTIFIED_RANGE, WriteHelper::global(),
453 eventid_to_buffer(range), done);
454}
455
457 BarrierNotifiable *done)
458{
459 uint64_t range = EncodeRange(event_base_, size_ * 256);
461 WriteHelper::global(), eventid_to_buffer(range), done);
462}
463
464void ByteRangeEventP::Update(unsigned byte, WriteHelper *writer,
465 BarrierNotifiable *done)
466{
467 // @TODO(balazs.racz): Should we use producer identified valid or event
468 // report here?
469 writer->WriteAsync(node_, Defs::MTI_EVENT_REPORT, WriteHelper::global(),
470 eventid_to_buffer(CurrentEventId(byte)), done);
471}
472
473// Responses to possible queries.
475 BarrierNotifiable *done)
476{
477 uint8_t *storage;
478 uint8_t value;
479 if (!DecodeEventId(event->event, &storage, &value))
480 {
481 return done->notify();
482 }
483 Update(storage - data_, event->event_write_helper<1>(), done);
484}
485
487 BarrierNotifiable *done)
488{
491 if (event->event + event->mask < event_base_)
492 {
493 return done->notify();
494 }
495 if (event->event >= event_base_ + size_ * 256)
496 {
497 return done->notify();
498 }
499 unsigned start_offset = 0;
500 unsigned end_offset = 0;
501 uint8_t *storage;
502 uint8_t value;
503 if (!DecodeEventId(event->event, &storage, &value))
504 {
505 start_offset = 0;
506 }
507 else
508 {
509 start_offset = storage - data_;
510 }
511 if (!DecodeEventId(event->event + event->mask, &storage, &value))
512 {
513 end_offset = size_;
514 }
515 else
516 {
517 end_offset = storage - data_ + 1;
518 }
519 unsigned cur = start_offset;
520 if (cur < end_offset)
521 {
522 Update(cur++, event->event_write_helper<1>(), done->new_child());
523 }
524 if (cur < end_offset)
525 {
526 Update(cur++, event->event_write_helper<2>(), done->new_child());
527 }
528 if (cur < end_offset)
529 {
530 Update(cur++, event->event_write_helper<3>(), done->new_child());
531 }
532 if (cur < end_offset)
533 {
534 Update(cur++, event->event_write_helper<4>(), done->new_child());
535 }
536 // This will crash if more than four packets are to be produced. The above
537 // code should be replaced by a background iteration in that case.
538 HASSERT(cur >= end_offset);
539 done->maybe_done();
540}
541
542BitEventHandler::BitEventHandler(BitEventInterface *bit) : bit_(bit)
543{
544}
545
546void BitEventHandler::register_handler(uint64_t event_on, uint64_t event_off)
547{
548 if ((event_on ^ event_off) == 1ULL)
549 {
550 // Register once for two eventids.
551 uint64_t id = event_on & (~1ULL);
552 unsigned user_data = 0;
553 if (event_on & 1) {
554 user_data |= BOTH_OFF_IS_ZERO;
555 } else {
556 user_data |= BOTH_ON_IS_ZERO;
557 }
558 EventRegistry::instance()->register_handler(
559 EventRegistryEntry(this, id, user_data), 1);
560 }
561 else
562 {
563 EventRegistry::instance()->register_handler(
564 EventRegistryEntry(this, event_on, EVENT_ON), 0);
565 EventRegistry::instance()->register_handler(
566 EventRegistryEntry(this, event_off, EVENT_OFF), 0);
567 }
568}
569
571{
572 EventRegistry::instance()->unregister_handler(this);
573}
574
576 EventReport *event, BarrierNotifiable *done)
577{
578 EventState state = bit_->get_current_state();
580 event->event_write_helper<1>()->WriteAsync(bit_->node(), mti,
581 WriteHelper::global(), eventid_to_buffer(bit_->event_on()),
582 done->new_child());
584 event->event_write_helper<2>()->WriteAsync(bit_->node(), mti,
585 WriteHelper::global(), eventid_to_buffer(bit_->event_off()),
586 done->new_child());
587}
588
590 EventReport *event, BarrierNotifiable *done)
591{
592 EventState state = bit_->get_current_state();
594 event->event_write_helper<3>()->WriteAsync(bit_->node(), mti,
595 WriteHelper::global(), eventid_to_buffer(bit_->event_on()),
596 done->new_child());
598 event->event_write_helper<4>()->WriteAsync(bit_->node(), mti,
599 WriteHelper::global(), eventid_to_buffer(bit_->event_off()),
600 done->new_child());
601}
602
604{
605 EventState value = bit_->get_requested_state();
606 uint64_t event;
607 if (value == EventState::VALID) {
608 event = bit_->event_on();
609 } else if (value == EventState::INVALID) {
610 event = bit_->event_off();
611 } else {
612 DIE("Requested sending event report for a bit event that is in unknown "
613 "state.");
614 }
615 writer->WriteAsync(bit_->node(), Defs::MTI_EVENT_REPORT,
616 WriteHelper::global(), eventid_to_buffer(event), done);
617}
618
620 BarrierNotifiable *done)
621{
622 if (event->src_node.id == bit_->node()->node_id())
623 {
624 // We don't respond to queries from our own node. This is not nice, but
625 // we
626 // want to avoid to answering our own Query command.
627 done->notify();
628 return;
629 }
630 EventState active;
631 if (event->event == bit_->event_on())
632 {
633 active = bit_->get_current_state();
634 }
635 else if (event->event == bit_->event_off())
636 {
637 active = invert_event_state(bit_->get_current_state());
638 }
639 else
640 {
641 done->notify();
642 return;
643 }
644 mti = mti + active;
645 event->event_write_helper<1>()->WriteAsync(bit_->node(), mti,
646 WriteHelper::global(), eventid_to_buffer(event->event), done);
647}
648
650 BarrierNotifiable *done)
651{
652 done->notify();
653 bool value;
654 if (event->state == EventState::VALID)
655 {
656 value = true;
657 }
658 else if (event->state == EventState::INVALID)
659 {
660 value = false;
661 }
662 else
663 {
664 return; // nothing to learn from this message.
665 }
666 if (event->event == bit_->event_on())
667 {
668 bit_->set_state(value);
669 }
670 else if (event->event == bit_->event_off())
671 {
672 bit_->set_state(!value);
673 }
674 else
675 {
676 return; // uninteresting event id.
677 }
678}
679
681{
683 WriteHelper::global(),
684 eventid_to_buffer(bit_->event_on()), done);
685}
686
688 BarrierNotifiable *done)
689{
690 if (event->event == bit_->event_on())
691 {
692 bit_->set_state(true);
693 }
694 else if (event->event == bit_->event_off())
695 {
696 bit_->set_state(false);
697 }
698 done->notify();
699}
700
702{
704 WriteHelper::global(),
705 eventid_to_buffer(bit_->event_on()), done);
706}
707
709 BarrierNotifiable *done)
710{
711 if (event->dst_node && event->dst_node != bit_->node())
712 {
713 return done->notify();
714 }
715 SendProducerIdentified(event, done);
716 done->maybe_done();
717}
718
724
730
736
738 BarrierNotifiable *done)
739{
740 if (event->dst_node && event->dst_node != bit_->node())
741 {
742 return done->notify();
743 }
744 SendConsumerIdentified(event, done);
745 done->maybe_done();
746}
747
749{
751 WriteHelper::global(),
752 eventid_to_buffer(bit_->event_on()), done);
753}
754
756 BarrierNotifiable *done)
757{
758 if (event->dst_node && event->dst_node != bit_->node())
759 {
760 return done->notify();
761 }
762 SendProducerIdentified(event, done);
763 SendConsumerIdentified(event, done);
764 done->maybe_done();
765}
766
768 BarrierNotifiable *done)
769{
770 done->notify();
771 bool value;
772 if (event->state == EventState::VALID)
773 {
774 value = true;
775 }
776 else if (event->state == EventState::INVALID)
777 {
778 value = false;
779 }
780 else
781 {
782 return; // nothing to learn from this message.
783 }
784 if (event->event == bit_->event_on())
785 {
786 bit_->set_state(value);
787 }
788 else if (event->event == bit_->event_off())
789 {
790 bit_->set_state(!value);
791 }
792 else
793 {
794 return; // uninteresting event id.
795 }
796}
797
798
799}; /* namespace openlcb */
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.
void maybe_done()
When there are no more child tasks to add, call maybe_done().
BarrierNotifiable * new_child()
Call this for each child task.
An object that can schedule itself on an executor to run.
static EventRegistry * instance()
Definition Singleton.hxx:77
void handle_identify_global(const EventRegistryEntry &entry, EventReport *event, BarrierNotifiable *done) override
Called on the need of sending out identification messages.
void handle_event_report(const EventRegistryEntry &entry, EventReport *event, BarrierNotifiable *done) override
Called on incoming EventReport messages.
void handle_identify_consumer(const EventRegistryEntry &entry, EventReport *event, BarrierNotifiable *done) override
Called on another node sending IdentifyConsumer.
void SendQuery(WriteHelper *writer, BarrierNotifiable *done)
Queries producers and acquires the current state of the bit.
void handle_producer_identified(const EventRegistryEntry &entry, EventReport *event, BarrierNotifiable *done) override
Called on another node sending ProducerIdentified for this event.
void SendConsumerIdentified(EventReport *event, BarrierNotifiable *done)
Sends off two packets using event_write_helper{3,4} of ConsumerIdentified for handling a global ident...
void unregister_handler()
Removes this event handler from the global event manager.
void register_handler(uint64_t event_on, uint64_t event_off)
Registers this event handler with the global event manager.
void SendEventReport(WriteHelper *writer, Notifiable *done)
Requests the event associated with the current value of the bit to be produced (unconditionally): sen...
void SendProducerIdentified(EventReport *event, BarrierNotifiable *done)
Sends off two packets using event_write_helper{1,2} of ProducerIdentified for handling a global ident...
void HandlePCIdentify(Defs::MTI mti_valid, EventReport *event, BarrierNotifiable *done)
Checks if the event in the report is something we are interested in, and if so, sends off a {Producer...
@ BOTH_ON_IS_ZERO
This registration is for two events, and the lower numbered is the event on.
@ EVENT_ON
This registration is for a single event_on.
@ EVENT_OFF
This registration is for a single event_off.
@ BOTH_OFF_IS_ZERO
This registration is for two events, and the lower numbered is the event off.
Represents a bit of state using two events.
uint64_t event_on()
returns the event ID for representing the state transition OFF->ON.
virtual void set_state(bool new_value)=0
Updates the hardware for the new event state.
virtual EventState get_requested_state()
Get the requested state.
uint64_t event_off()
returns the event ID for representing the state transition ON->OFF.
virtual Node * node()=0
returns the OpenLCB virtual node from which to send the respective events when the bit changes.
virtual EventState get_current_state()=0
returns the current hardware state: true for ON, false for OFF.
void handle_identify_global(const EventRegistryEntry &entry, EventReport *event, BarrierNotifiable *done) override
Called on the need of sending out identification messages.
void SendQueryConsumer(WriteHelper *writer, BarrierNotifiable *done)
Queries consumer and acquires the current state of the bit.
void handle_identify_producer(const EventRegistryEntry &entry, EventReport *event, BarrierNotifiable *done) override
Called on another node sending IdentifyProducer.
void handle_consumer_identified(const EventRegistryEntry &entry, EventReport *event, BarrierNotifiable *done) override
Called on another node sending ConsumerIdentified for this event.
void SendQuery(WriteHelper *writer, BarrierNotifiable *done)
Queries consumers and acquires the current state of the bit.
void handle_identify_producer(const EventRegistryEntry &entry, EventReport *event, BarrierNotifiable *done) override
Called on another node sending IdentifyProducer.
void handle_identify_global(const EventRegistryEntry &entry, EventReport *event, BarrierNotifiable *done) override
Called on the need of sending out identification messages.
void handle_identify_producer(const EventRegistryEntry &entry, EventReport *event, BarrierNotifiable *done) override
Called on another node sending IdentifyProducer.
void handle_identify_consumer(const EventRegistryEntry &entry, EventReport *event, BarrierNotifiable *done) override
Called on another node sending IdentifyConsumer.
void handle_identify_global(const EventRegistryEntry &entry, EventReport *event, BarrierNotifiable *done) override
Called on the need of sending out identification messages.
BitRangeEventPC(Node *node, uint64_t event_base, uint32_t *backing_store, unsigned size)
Creates a new bit range listener.
bool Get(unsigned bit) const
void SendIdentified(WriteHelper *writer, BarrierNotifiable *done)
Sends out a ProducerRangeIdentified.
void handle_event_report(const EventRegistryEntry &entry, EventReport *event, BarrierNotifiable *done) override
Called on incoming EventReport messages.
void Set(unsigned bit, bool new_value, WriteHelper *writer, BarrierNotifiable *done)
Requests the event associated with the current value of the bit to be produced (unconditionally).
void handle_identify_global(const EventRegistryEntry &entry, EventReport *event, BarrierNotifiable *done) override
Called on the need of sending out identification messages.
Consumer event handler for a sequence of bytes represented by a dense block of consecutive event IDs.
void handle_event_report(const EventRegistryEntry &entry, EventReport *event, BarrierNotifiable *done) override
Called on incoming EventReport messages.
void handle_identify_consumer(const EventRegistryEntry &entry, EventReport *event, BarrierNotifiable *done) override
Called on another node sending IdentifyConsumer.
bool DecodeEventId(uint64_t event_id, uint8_t **data, uint8_t *value)
takes an event ID and checks if we are responsible for it.
void handle_identify_global(const EventRegistryEntry &entry, EventReport *event, BarrierNotifiable *done) override
Called on the need of sending out identification messages.
void SendIdentified(WriteHelper *writer, BarrierNotifiable *done)
Sends out a ConsumerRangeIdentified.
ByteRangeEventC(Node *node, uint64_t event_base, uint8_t *backing_store, unsigned size)
Creates a new byte range listener.
virtual void notify_changed(unsigned offset)
This function is called by the handler when a data value overwrite event arrives.
void handle_identify_consumer(const EventRegistryEntry &entry, EventReport *event, BarrierNotifiable *done) override
Called on another node sending IdentifyConsumer.
void handle_identify_global(const EventRegistryEntry &entry, EventReport *event, BarrierNotifiable *done) override
Called on the need of sending out identification messages.
void Update(unsigned byte, WriteHelper *writer, BarrierNotifiable *done)
Requests the event associated with the current value of a specific byte to be produced (unconditional...
ByteRangeEventP(Node *node, uint64_t event_base, uint8_t *backing_store, unsigned size)
Creates a new byte range producer.
uint64_t CurrentEventId(unsigned byte)
Creates the eventid of the currently valid value of a given byte.
void SendIdentified(WriteHelper *writer, BarrierNotifiable *done)
Sends out a ProducerRangeIdentified.
void handle_identify_producer(const EventRegistryEntry &entry, EventReport *event, BarrierNotifiable *done) override
Called on another node sending IdentifyProducer.
void handle_consumer_identified(const EventRegistryEntry &entry, EventReport *event, BarrierNotifiable *done) override
Called on another node sending ConsumerIdentified for this event.
void handle_event_report(const EventRegistryEntry &entry, EventReport *event, BarrierNotifiable *done) override
Called on incoming EventReport messages.
void handle_consumer_range_identified(const EventRegistryEntry &entry, EventReport *event, BarrierNotifiable *done) override
Called on another node sending ConsumerRangeIdentified.
Structure used in registering event handlers.
static unsigned align_mask(EventId *event, unsigned size)
Computes the alignment mask for registering an event range.
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 LOG(level, message...)
Conditionally write a message to the logging output.
Definition logging.h:99
static const int VERBOSE
Loglevel that is usually not printed, reporting debugging information.
Definition logging.h:59
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
Definition macros.h:138
#define DIE(MSG)
Unconditionally terminates the current process with a message.
Definition macros.h:143
uint64_t EncodeRange(uint64_t begin, unsigned size)
Creates a single encoded event range from the beginning of the range and the number fo events to cove...
EventState invert_event_state(EventState state)
Returns the inverted event state, switching valid and invalid, but not changing unknown and reserved.
EventState
Allowed states of producers and consumers.
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
MTI
Known Message type indicators.
@ MTI_PRODUCER_IDENTIFY
query about producers
@ MTI_PRODUCER_IDENTIFIED_RANGE
producer broadcast about a range of producers
@ MTI_PRODUCER_IDENTIFIED_VALID
producer broadcast, valid state
@ MTI_CONSUMER_IDENTIFY
query about consumers
@ MTI_CONSUMER_IDENTIFIED_VALID
consumer broadcast, valid state
@ MTI_CONSUMER_IDENTIFIED_RANGE
consumer broadcast about a range of consumers
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.
EventState state
For producer/consumer identified messages, specifies the state of the producer/consumer as the sender...
NodeHandle src_node
Information about the sender of the incoming event-related OpenLCB message.
EventId event
The event ID from the incoming message.
Node * dst_node
nullptr for global messages; points to the specific virtual node for addressed events identify messag...
WriteHelper * event_write_helper()
These allow event handlers to produce up to four messages per invocation.
NodeID id
48-bit NMRAnet Node ID