Organizing device drivers

Hi devs,

on several occasions the question about how to merge similar device drivers occurred. That means covering different derivatives of a device with one device driver, to avoid code duplication. Compare discussions in these PRs:

https://github.com/RIOT-OS/RIOT/pull/5604 https://github.com/RIOT-OS/RIOT/pull/5484 https://github.com/RIOT-OS/RIOT/pull/5433

For the dht11/22 or at86rf212b/232/233 we already merged drivers by putting #ifdef around different code parts. This does not affect code readability as long as differences are small (which is not guaranteed). On the other hand, this approach prohibits to use both devices simultaneously. Furthermore, naming schemes might get confusing. E.g. merging "MPU6000", "MPU6050" and "MPU9150" might lead to "MPUXXX0". I've no idea about further and future version names.

For similar CPUs we maintain a "common" folder next to the dedicated CPU version. Different code parts were maintained separately in individual folders. The question is, if this approach is reasonable for pretty simple device drivers where multiple derivatives might exist.

Another solution would be to handle common and individual functions in one file (without #ifdef). This might bloat code size but allows usage of different versions in parallel. Also, it does not bloat the file structure. The problem about naming schemes is still present here.

I'd like to have a general principle for this. What is your opinion about the above described procedures? Are there other/better ideas?

Best Peter

Hi Perter, all,

> this approach prohibits to use both devices simultaneously. I think this is a blocking issue for merging akin device drivers. IMHO If this situation happens the drivers should be separated back, even if bloating/doubling the code.

> For similar CPUs we maintain a "common" folder ... Considering the mentioned "blocking issue" I would go for a "common" folder for solely collecting utility functions, i.e. functions not using global/static variables or buffers.

> Another solution would be to handle common and individual functions in one file (without #ifdef). ... You mean putting all required functions in each driver without considering similarities? At least this would be safe, since every driver then truly operates in defined bounds. But obviously this would most probably introduce a lot developing/debugging repetition.

Best regards, Martin

Hi Martin,

thanks for your feedback.

Hi Perter, all,

> this approach prohibits to use both devices simultaneously. I think this is a blocking issue for merging akin device drivers. IMHO If this situation happens the drivers should be separated back, even if bloating/doubling the code.

> For similar CPUs we maintain a "common" folder ... Considering the mentioned "blocking issue" I would go for a "common" folder for solely collecting utility functions, i.e. functions not using global/static variables or buffers.

> Another solution would be to handle common and individual functions in one file (without #ifdef). ... You mean putting all required functions in each driver without considering similarities?

That approach is about to maintain one folder/file for a shared implementation. That file consists of individual functions *and* shared functions. That prohibits from bloating the file structure and enables simultaneous usage but enlarges code size..

At least this would be safe, since every driver then truly operates in defined bounds. But obviously this would most probably introduce a lot developing/debugging repetition.

Best regards, Martin

Best Peter

Hi Peter, I think I prefer the common solution most, though we need to be careful how interaction between the common module and the actual driver would work. #ifdef different variants is as you said to use a mixture of radio devices (e.g a samr21-xpro with an OpenLabs RaspPi hat attached) and also is prone to produce more complicated code if things get out of hand, even if the local ifdef seems small (see the old sys/transceiver drivers [1]). The third I don’t like because of bloat, both code-size-wise and loc-wise.

Cheers, Martine

[1] https://github.com/RIOT-OS/RIOT/blob/89fa57c5a9188e5dbe292ba11997447e047b1c08/sys/transceiver/transceiver.c

Hi,

Another solution would be to handle common and individual functions in one file (without #ifdef). This might bloat code size but allows usage of different versions in parallel. Also, it does not bloat the file structure. The problem about naming schemes is still present here.

I prefer clear only this solution, with the difference to handle common and individual functions in one directory. The derivative functions can be controlled using C if statements, which should be optimized by the compiler and the modern linker should remove the unused functions. I pour a little oil into the fire: some developer overdo it with the macros and the driver (also other) sources look like "a macro-monster has puked on the display".

Regards,

Johann Fischer