Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
ConfiguredConsumer.hxx
Go to the documentation of this file.
1
36#ifndef _OPENLCB_CONFIGUREDCONSUMER_HXX_
37#define _OPENLCB_CONFIGUREDCONSUMER_HXX_
38
44
45namespace openlcb
46{
47
49CDI_GROUP(ConsumerConfig);
52 Name("Description"), Description("User name of this output."));
55 event_on, EventConfigEntry, //
56 Name("Event On"),
57 Description("Receiving this event ID will turn the output on."));
60 event_off, EventConfigEntry, //
61 Name("Event Off"),
62 Description("Receiving this event ID will turn the output off."));
64
66CDI_GROUP(PulseConsumerConfig);
69 Name("Description"), Description("User name of this output."));
72 event, EventConfigEntry, //
73 Name("Event"),
74 Description(
75 "Receiving this event ID will generate a pulse on the output."));
78 duration, Uint8ConfigEntry, Default(3), //
79 Name("Pulse duration"),
80 Description("Length of the pulse to output (unit of 30 msec)."));
82
88{
89public:
90 using Impl = GPIOBit;
91
92 ConfiguredConsumer(Node *node, const ConsumerConfig &cfg, const Gpio *gpio)
93 : impl_(node, 0, 0, gpio)
94 , consumer_(&impl_)
95 , cfg_(cfg)
96 {
98 }
99
100 template <class HW>
101 ConfiguredConsumer(Node *node, const ConsumerConfig &cfg, const HW &, const Gpio* g = HW::instance(), decltype(HW::instance)* = 0)
102 : impl_(node, 0, 0, g)
103 , consumer_(&impl_)
104 , cfg_(cfg)
105 {
107 }
108
109 UpdateAction apply_configuration(int fd, bool initial_load,
111 {
112 AutoNotify n(done);
113 EventId cfg_event_on = cfg_.event_on().read(fd);
114 EventId cfg_event_off = cfg_.event_off().read(fd);
115 if (cfg_event_off != impl_.event_off() ||
116 cfg_event_on != impl_.event_on())
117 {
118 auto saved_gpio = impl_.gpio_;
119 auto saved_node = impl_.node();
120 // Need to reinitialize the consumer. We do this with in-place
121 // destruction and construction.
122 consumer_.~BitEventConsumer();
123 impl_.Impl::~Impl();
124 new (&impl_)
125 Impl(saved_node, cfg_event_on, cfg_event_off, saved_gpio);
126 new (&consumer_) BitEventConsumer(&impl_);
127 return REINIT_NEEDED; // Causes events identify.
128 }
129 return UPDATED;
130 }
131
133 {
134 cfg_.description().write(fd, "");
135 }
136
137private:
138 Impl impl_;
139 BitEventConsumer consumer_;
140 const ConsumerConfig cfg_;
141};
142
148 private SimpleEventHandler,
149 public Polling
150{
151public:
152 template <class HW>
153 ConfiguredPulseConsumer(Node *node, const PulseConsumerConfig &cfg,
154 const HW &, const Gpio* g = HW::instance())
155 : node_(node)
156 , gpio_(g)
157 , cfg_(cfg)
158 {
160 }
161
162 ConfiguredPulseConsumer(Node *node, const PulseConsumerConfig &cfg,
163 const Gpio *gpio)
164 : node_(node)
165 , gpio_(gpio)
166 , cfg_(cfg)
167 {
169 }
170
172 {
175 }
176
177 UpdateAction apply_configuration(int fd, bool initial_load,
179 {
180 AutoNotify n(done);
181 EventId cfg_event_on = cfg_.event().read(fd);
182 pulseLength_ = cfg_.duration().read(fd);
183 if (cfg_event_on == event_)
184 return UPDATED; // nothing to do
185 if (!initial_load)
186 {
188 }
189 event_ = cfg_event_on;
190 do_register();
191 return REINIT_NEEDED; // Causes events identify.
192 }
193
195 {
196 cfg_.description().write(fd, "");
197 CDI_FACTORY_RESET(cfg_.duration);
198 }
199
200private:
203 {
204 EventRegistry::instance()->register_handler(
205 EventRegistryEntry(this, event_), 0);
206 }
207
211 {
212 EventRegistry::instance()->unregister_handler(this);
213 }
214
215 // Implementations for the event handler functions.
216
217 void handle_identify_global(const EventRegistryEntry &registry_entry,
218 EventReport *event, BarrierNotifiable *done)
220 {
221 if (event->dst_node && event->dst_node != node_)
222 {
223 return done->notify();
224 }
225 SendConsumerIdentified(event, done);
226 }
227
228 void SendConsumerIdentified(EventReport *event, BarrierNotifiable *done)
229 {
231 if (!pulseRemaining_)
232 {
233 mti++; // INVALID
234 }
235 event->event_write_helper<3>()->WriteAsync(
236 node_, mti, WriteHelper::global(), eventid_to_buffer(event_), done);
237 }
238
241 {
242 if (event->event != event_)
243 {
244 return done->notify();
245 }
246 SendConsumerIdentified(event, done);
247 }
248
249 void handle_event_report(const EventRegistryEntry &registry_entry,
251 {
252 if (event->event == event_)
253 {
254 pulseRemaining_ = pulseLength_;
255 }
256 done->notify();
257 }
258
259 // Polling interface
261 {
262 if (pulseRemaining_ > 0)
263 {
264 gpio_->set();
265 --pulseRemaining_;
266 }
267 else
268 {
269 gpio_->clr();
270 }
271 done->notify();
272 }
273
274 Node *node_; //< virtual node to export the consumer on
275 const Gpio *gpio_; //< hardware output pin to drive
276 EventId event_{0}; //< Event ID to listen for
277 const PulseConsumerConfig cfg_; //< offset to the config in EEPROM
278 uint8_t pulseLength_{1}; //< length of pulse (in polling count)
279 uint8_t pulseRemaining_{0}; //< remaining polling count to keep pulse on
280};
281
282} // namespace openlcb
283
284#endif // _OPENLCB_CONFIGUREDCONSUMER_HXX_
#define CDI_GROUP(GroupName, ARGS...)
Starts a CDI group.
#define CDI_GROUP_ENTRY(NAME, TYPE, ARGS...)
Adds an entry to a CDI group.
#define CDI_FACTORY_RESET(PATH)
Performs factory reset on a CDI variable.
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.
UpdateAction
Specifies what additional steps are needed to apply the new configuration.
@ REINIT_NEEDED
Need to perform application-level reinitialization.
@ UPDATED
No additional step is necessary.
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 clr() const =0
Clears the GPIO output pin to low.
virtual void set() const =0
Sets the GPIO output pin to high.
An object that can schedule itself on an executor to run.
static ConfigUpdateService * instance()
Definition Singleton.hxx:77
Event handler for a single-bit consumer, e.g.
uint64_t event_on()
returns the event ID for representing the state transition OFF->ON.
uint64_t event_off()
returns the event ID for representing the state transition ON->OFF.
OpenLCB Consumer class integrating a simple CDI-based configuration for two event IDs,...
UpdateAction apply_configuration(int fd, bool initial_load, BarrierNotifiable *done) OVERRIDE
Notifies the component that there is new configuration available for loading.
void factory_reset(int fd) OVERRIDE
Clears configuration file and resets the configuration settings to factory value.
OpenLCB Consumer class integrating a simple CDI-based configuration for a single event IDs,...
void handle_identify_global(const EventRegistryEntry &registry_entry, EventReport *event, BarrierNotifiable *done) OVERRIDE
Called on the need of sending out identification messages.
void handle_identify_consumer(const EventRegistryEntry &registry_entry, EventReport *event, BarrierNotifiable *done) OVERRIDE
Called on another node sending IdentifyConsumer.
void do_unregister()
Removed registration of this event handler from the global event registry.
void factory_reset(int fd) OVERRIDE
Clears configuration file and resets the configuration settings to factory value.
void poll_33hz(WriteHelper *helper, Notifiable *done) OVERRIDE
This function will be called approximately 33 times per second by the refresh loop.
UpdateAction apply_configuration(int fd, bool initial_load, BarrierNotifiable *done) OVERRIDE
Notifies the component that there is new configuration available for loading.
void handle_event_report(const EventRegistryEntry &registry_entry, EventReport *event, BarrierNotifiable *done) OVERRIDE
Called on incoming EventReport messages.
void do_register()
Registers the event handler with the global event registry.
Implementation class for event ID configuration entries.
Structure used in registering event handlers.
Simple implementation of the BitEventInterface for going through GPIO ports.
Node * node() OVERRIDE
returns the OpenLCB virtual node from which to send the respective events when the bit changes.
Base class for NMRAnet nodes conforming to the asynchronous interface.
Definition Node.hxx:52
Implementation class for numeric configuration entries, templated by the integer type.
Abstract base class for components that need repeated execution (with a specified frequency,...
SimpleEventHandler ignores all non-essential callbacks.
Implementation class for string configuration entries.
A statically allocated buffer for sending one message to the OpenLCB bus.
#define OVERRIDE
Function attribute for virtual functions declaring that this funciton is overriding a funciton that s...
Definition macros.h:180
CDI_GROUP_END()
Signals termination of the group.
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.