Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
MultiConfiguredConsumer.hxx
Go to the documentation of this file.
1
36#ifndef _OPENLCB_MULTICONFIGUREDCONSUMER_HXX_
37#define _OPENLCB_MULTICONFIGUREDCONSUMER_HXX_
38
42
43namespace openlcb
44{
45
52 private SimpleEventHandler
53{
54public:
55 typedef ConsumerConfig config_entry_type;
56
73 template <unsigned N>
74 __attribute__((noinline)) MultiConfiguredConsumer(Node *node,
75 const Gpio *const *pins, unsigned size,
77 : node_(node)
78 , pins_(pins)
79 , size_(N)
80 , offset_(config)
81 {
82 // Mismatched sizing of the GPIO array from the configuration array.
83 HASSERT(size == N);
85 }
86
88 {
89 do_unregister();
91 }
92
93 UpdateAction apply_configuration(int fd, bool initial_load,
95 {
96 AutoNotify n(done);
97
98 if (!initial_load)
99 {
100 // There is no way to figure out what the previously registered
101 // eventid values were for the individual pins. Therefore we always
102 // unregister everything and register them anew. It also causes us
103 // to identify all. This is not a problem since apply_configuration
104 // is coming from a user action.
105 do_unregister();
106 }
107 RepeatedGroup<config_entry_type, UINT_MAX> grp_ref(offset_.offset());
108 for (unsigned i = 0; i < size_; ++i)
109 {
110 const config_entry_type cfg_ref(grp_ref.entry(i));
111 EventId cfg_event_on = cfg_ref.event_on().read(fd);
112 EventId cfg_event_off = cfg_ref.event_off().read(fd);
113 EventRegistry::instance()->register_handler(
114 EventRegistryEntry(this, cfg_event_off, i * 2), 0);
115 EventRegistry::instance()->register_handler(
116 EventRegistryEntry(this, cfg_event_on, i * 2 + 1), 0);
117 }
118 return REINIT_NEEDED; // Causes events identify.
119 }
120
121 void factory_reset(int fd) OVERRIDE
122 {
123 RepeatedGroup<config_entry_type, UINT_MAX> grp_ref(offset_.offset());
124 for (unsigned i = 0; i < size_; ++i)
125 {
126 grp_ref.entry(i).description().write(fd, "");
127 }
128 }
129
133 void factory_reset_names(int fd, const char *basename)
134 {
135 RepeatedGroup<config_entry_type, UINT_MAX> grp_ref(offset_.offset());
136 for (unsigned i = 0; i < size_; ++i)
137 {
138 string v(basename);
139 v.push_back(' ');
140 char buf[10];
141 unsigned_integer_to_buffer(i+1, buf);
142 v += buf;
143 grp_ref.entry(i).description().write(fd, v);
144 }
145 }
146
147 // Implementations for the event handler functions.
148
149 void handle_identify_global(const EventRegistryEntry &registry_entry,
150 EventReport *event, BarrierNotifiable *done)
152 {
153 if (event->dst_node && event->dst_node != node_)
154 {
155 return done->notify();
156 }
157 SendConsumerIdentified(registry_entry, event, done);
158 }
159
160 void handle_identify_consumer(const EventRegistryEntry &registry_entry,
161 EventReport *event, BarrierNotifiable *done)
163 {
164 if (event->event != registry_entry.event)
165 {
166 return done->notify();
167 }
168 SendConsumerIdentified(registry_entry, event, done);
169 }
170
171 void handle_event_report(const EventRegistryEntry &registry_entry,
173 {
174 if (event->event != registry_entry.event)
175 {
176 return done->notify();
177 }
178 const Gpio *pin = pins_[registry_entry.user_arg >> 1];
179 const bool is_on = (registry_entry.user_arg & 1);
180 pin->write(is_on);
181 done->notify();
182 }
183
184private:
187 void SendConsumerIdentified(const EventRegistryEntry &registry_entry,
188 EventReport *event, BarrierNotifiable *done)
189 {
191 unsigned b1 = pins_[registry_entry.user_arg >> 1]->is_set() ? 1 : 0;
192 unsigned b2 = registry_entry.user_arg & 1; // on or off event?
193 if (b1 ^ b2)
194 {
195 mti++; // INVALID
196 }
197 event->event_write_helper<3>()->WriteAsync(node_, mti,
198 WriteHelper::global(), eventid_to_buffer(registry_entry.event),
199 done);
200 }
201
204 void do_unregister()
205 {
206 EventRegistry::instance()->unregister_handler(this);
207 }
208
209 Node *node_; //< virtual node to export the consumer on
210 const Gpio *const *pins_; //< array of all GPIO pins to use
211 size_t size_; //< number of GPIO pins to export
212 ConfigReference offset_; //< Offset in the configuration space for our
213 // configs.
214};
215
216} // namespace openlcb
217
218#endif // _OPENLCB_MULTICONFIGUREDCONSUMER_HXX_
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.
Abstract class for components that need to receive configuration from EEPROM.
virtual void factory_reset(int fd)=0
Clears configuration file and resets the configuration settings to factory value.
UpdateAction
Specifies what additional steps are needed to apply the new configuration.
@ REINIT_NEEDED
Need to perform application-level reinitialization.
virtual UpdateAction apply_configuration(int fd, bool initial_load, BarrierNotifiable *done)=0
Notifies the component that there is new configuration available for loading.
virtual void register_update_listener(ConfigUpdateListener *listener)=0
Adds a config update listener to be called upon configuration updates.
virtual void unregister_update_listener(ConfigUpdateListener *listener)=0
Removes a config update listener.
OS-independent abstraction for GPIO.
Definition Gpio.hxx:43
virtual void write(Value new_state) const =0
Writes a GPIO output pin (set or clear to a specific state).
static ConfigUpdateService * instance()
Definition Singleton.hxx:77
Class representing a particular location in the configuration space.
virtual void handle_identify_global(const EventRegistryEntry &registry_entry, EventReport *event, BarrierNotifiable *done)=0
Called on the need of sending out identification messages.
virtual void handle_event_report(const EventRegistryEntry &registry_entry, EventReport *event, BarrierNotifiable *done)=0
Called on incoming EventReport messages.
virtual void handle_identify_consumer(const EventRegistryEntry &registry_entry, EventReport *event, BarrierNotifiable *done)=0
Called on another node sending IdentifyConsumer.
Structure used in registering event handlers.
uint32_t user_arg
Opaque user argument.
EventId event
Stores the event ID or beginning of range for which to register the given handler.
Version of the ConfiguredConsumer class that can handle many GPIO pins with two events each.
Base class for NMRAnet nodes conforming to the asynchronous interface.
Definition Node.hxx:52
Defines a repeated group of a given type and a given number of repeats.
SimpleEventHandler ignores all non-essential callbacks.
#define OVERRIDE
Function attribute for virtual functions declaring that this funciton is overriding a funciton that s...
Definition macros.h:180
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
Definition macros.h:138
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_CONSUMER_IDENTIFIED_VALID
consumer broadcast, valid state
Shared notification structure that is assembled for each incoming event-related 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...