I tried to start a thread
Suppose you have a complex dashboard with tenth of LEDs, gauges, values, labels and so on. It could be a full-futured high-resolution TFT display. The values shown on the dashboard come from remote controllers connected through a bus. I think it's a very common scenario in my systems.
When I design the firmware of the dashboard controller, I always have many doubts on the design better to choose: refresh-based or event-based?
Refresh-based is very simple: every 20ms, 100ms, 500ms or 1s a refresh function is called. This function redraws *everything* on the dashboard based on the current values collected on the bus. The thing I don't like with this approach is that it could be time consuming. If the values change slowly, most probably only 1-5 values really change since the last refresh. Why do I redraw everything? I could improve this by defining a variable with the old displayed value for each graphical element:
bool ledX_displayed; if (ledX_displayed != ledX_currentvalue()) { ledX_displayed = ledX_currentvalue(); ledX_refresh(); }
However this method uses a double RAM space (current values and displayed values) and the code isn't so clear.
Another approach is event-based. IMHO, it is very attractive and elegant, because it remembers state-machines. The drawing operations are performed only when necessary.
int X, Y, ...; void bus_rx(const char *msg, size_t msglen) { int new_value; ... new_value = /* X value */ if (X != new_value) { X = new_value; event_handler(X_CHANGED); } ... } void event_handler(enum EVENT_TYPE evtype) { if (X_CHANGED == evtype) ledX_refresh(); else ... }
The event X_CHANGED is triggered by the bus task: when a new value for X is received, it is compared with the current value and, if it is different, the event is triggered (a callback is called).
Even this design patter have some drawbacks. IMHO it is dangerous and error-prone, because you could ignore a certain sequence of events that brings to a wrong state (you will have a wrong value displayed on the dashboard). The startup must be designed with great care. Should a "virtual startup event" be triggered during initialization for each value, so the current/init value is correctly displayed? How to distinguish a "virtual startup event" from a "normal event"? It's important, if I have to make soma actions only if a "normal event" occurs.
What is you preferred method?