As pointed out in the comments yesterday, “nodes” in a WSN should to be more parametrized. With ports, it’s very easy to mix and match different sensors – creating nodes which are not all the same should be equally easy.
I’ve touched on a related topic before in a post titled Modular nodes.
Ideally, you want to write interface code for say a PIR motion sensor once, and then re-use it in different nodes. Same for an SHT11 temperature/humidity sensor, an IR send/receive sensor, a barometer, door switches, an OOK receiver, and so on – the list is bound to grow considerably over time.
Even “more ideally” (heh), you probably would like someone else to already have written that interface code, so you can just fill in the parameters and incorporate it into your own room-or-other node.
In fact, the whole (modular!) Plugs & Ports concept of JeeNodes is yearning for this type of modularity to be carried through to the software.
To achieve such modularity all the way through, several questions need to be answered:
- are these interface code “snippets” always very small and self-contained, or do they need additional C/C++ source files?
- can interfaces depend on other interfaces / is a class hierarchy the best way to modularize such dependencies and derivations?
- can we have multiple instances of the same interface in a single node? (answer: yes, for example multiple door-open sensors, attached to different I/O pins)
- how do we deal with a mix of interfaces which use different timing periods for readout?
- how do we compose packets to send, if the information types vary?
One way to implement this modularity, is what I’ve been doing in the Ports library until now: define and implement C++ classes for each interface, and then create (static) instances of each interface needed in a particular node.
This is an extract of the Ports.h library header file:
It works – and I think it’s a decent start – but it doesn’t go far enough:
Many configuration parameters are variables (and data members inside C++ objects), even though they are essentially contant (the port number, an I2C device ID, I/O pin choices, etc). This eats up scarce RAM space, and prevents the compiler from fully optimizing the code. The “heavy” solution to this is C++ templates, as I’ve written about in three – older – posts. Trouble is: C++ templates are “viral”, once you start on that path, everything tends to become a template. Not my idea of simplicity…
I want to figure out what a good set of reporting periods is, to minimize the number of packets sent, for example. This task comes back with every type of node, so having some automated tool to help with that effort would be useful.
There can be severe resource constraints in low-power nodes. I’d like to see what the RAM and EEPROM (and FLASH) usage is when choosing a specific mix of interfaces. I’d also like to find out whether the interrupts can co-exist and still service everything sufficiently quickly. And I’d like to get estimates for battery life. None of this is impossible, even if unnecessary for a first implementation.
Implementing pin-change interrupt handlers is not easy to fit into C++ as run-time mechanism, even though for any given interface mix it is very simple to generate the interrupt handler code for it.
The result of a choice of interfaces is not just a sketch – it also implies specific packet structures, as used for getting data across. And indirectly, it also means there has to be something node-specific at the central node (not necessarily in that receiving node, it could be code that runs on an attached PC).
If the number of interfaces grows considerably, and if more people were to start implementing such interfaces, then the management and versioning of all these interface definitions (code, data, docs) needs to be addressed.
What this points to IMO, is the need for a “configurator” or “wizard” type tool, which knows about a large number of interfaces, and which produces a sketch when given a bunch of configuration choices. An even more convenient tool would let me manage my entire collection of nodes, so I can make most configuration choices once, and then manage all node definitions together. It’d let me add and update interfaces and nodes as needed, over time:
What comes out is still a C/C++ coded sketch, since that’s what needs to be uploaded to the node.
What should also come out (not included in the above diagram), are one or more packet structure definitions, as well as the code (or data definitions) needed to decode those packets again.
With this approach, you can pick the hardware needed for a specific node, enter your choices into the configurator, and be done with it. Upload the sketch it generated, turn the node on, and launch the central server with the information it needs to understand the new incoming data packets. For other nodes, or to make changes, simply rinse and repeat…
I haven’t decided yet whether I’ll actually go for this. It’s fairly ambitious, even for a simple first implementation. But it sure would scratch an itch of mine…