Hi All,

We use this approach exhaustively (for drivers and practically everything
else) with the same result.
The struct does not even need to be declared as a const struct if it is
used in a way that implies such, though it is definitely more elegant to
declare it so.

Though I do have a preference for binding prerequisite functions as a part
of the interface, rather than hiding them in the body of the code with
macros.
As a disclaimer, I haven't actually checked the result of this particular
style of binding, which in our application does use a dereference to access
the function pointer. I will have a shot at that later on.
Our decision was that effective modularity was more critical than
performance for our driver elements (at least until we experience a
performance issue).

ie.
`
//Initialise the radio device
extern int8_t SI446x_init(struct si446x_s *device,
                          transfer_data_function spi_transfer_function,
                          set_pin_function set_sdn,
                          get_pin_function get_cts,
                          get_pin_function get_irq,
                          get_pin_function get_cca);
`
Where for the purposes of this example the above are defined so:
`
typedef int8_t (*transfer_data_function)(void* context, uint8_t *data,
uint8_t size);
typedef int8_t (*set_pin_function)(void* context, uint8_t value);
typedef int8_t (*get_pin_function)(void* context);
`

This means that any dependencies are explicitly defined in the interface,
rather than hidden in the source code.
It also means that instantiating multiple devices and linking them to
different underlying communication channels becomes possible, and you can
do some quite neat testing based on that.

In my opinion this is a cleaner abstraction, and leads to clearer parallel
composition (or wiring) of modules, rather than the oft used vertical
composition.
I had a bit of a wild rant about this recently, and there is a /very/ draft
set of slides if anyone is interested.

Hope some of this is valuable,

Ryan

On 19 February 2015 at 05:28, ROUSSEL Kévin <kevin.rous...@inria.fr> wrote:

> Hello,
>
> I began to use function pointers in the 'radio_driver.h' when trying to
> create a unified model for radio drivers. I guess it went over later to the
> whole netdev effort.
>
> My idea then was to have a "fast", predictable call chain from the MAC
> layer to the physical radio transceiver functions: most MAC protocols
> expect to run with precise delays, and a mechanism relying on message
> between threads (like 'transceiver') did not fit that need.
> The model of driver as structs containing function pointers is the one
> used in Contiki: it seemed quite a natural way to handle the problem to
> me... In their code, the needed drivers are aliased as 'NETSTACK_xxx'
> macros, then functions are called by invoking 'NETSTACK_xxx.func()'.
> I've never seen advanced dereferencing (->) nor object-oriented like
> constructs in that context.
>
> As P. Nikander said, since you are supposed to know your hardware at
> compile time, these pointers are actually constants that should be resolved
> at compile (linking) time -- even with GCC. Theoretically, it should be
> translated by standard indirect calls at the assembler level. Could you
> tell us more about your previous experiments? It seems quite strange to me
> that such a mechanism (that seems simple to me) could impose speed and
> debugging penalties.
>
> The other question is how could we implement the network stack? Using a
> mechanism like 'transceiver', that relies on message-passing between
> threads, implies that there is no predictable delay for executing network
> functions (one has to wait for the scheduler to switch to the thread(s)
> that execute(s) the feature(s) you want to use). At some levels -- like
> between MAC and PHY -- this can be a huge disadvantage.
>
> Is there a better way to obtain deterministic/direct API calls than using
> the "struct of function pointers" scheme ?...
>
> Regards,
>
>
>
> Le 18/02/2015 11:38, Oleg Hahm a écrit :
>
>> Dear remodeling IoTlers!
>>
>> Ludwig just made me aware that Joakim's PR for NVRAM [1] introduces
>> function
>> pointers as part of the device driver struct. This made me remember that
>> there
>> were already similar function pointers introduced as part of netdev.
>>
>> As I was always opposed to use function pointers in that way, I could not
>> recall what was the reason to use them for netdev. I don't like this
>> pseudo
>> object oriented C style (dev->write() and the like) because we made bad
>> experiences with it at my former company. While writing the whole HAL for
>> our
>> firmware there using function pointers this way, made programming pretty
>> convenient, it turned out to become problematic speed-wise and was a
>> nightmare
>> to debug.
>>
>> Hence, I would like to trigger a fundamental discussion on this topic.
>> Does
>> anyone has a particular opinion on the topic why function pointer based
>> device drivers should be a good or a bad idea? And can anyone explain to
>> me
>> the need of function pointers for netdev?
>>
>> Cheers,
>> Oleg
>>
>> [1] https://github.com/RIOT-OS/RIOT/pull/2353
>>
>>
>>
>> _______________________________________________
>> devel mailing list
>> devel@riot-os.org
>> http://lists.riot-os.org/mailman/listinfo/devel
>>
>>
> --
>
>
>      Kévin Roussel
>      Doctorant, projet LAR
>      Équipe MADYNES, INRIA Nancy Grand-Est / LORIA
>      Tél. : +33 3 54 95 86 27
>      kevin.rous...@inria.fr
>
>
> _______________________________________________
> devel mailing list
> devel@riot-os.org
> http://lists.riot-os.org/mailman/listinfo/devel
>
_______________________________________________
devel mailing list
devel@riot-os.org
http://lists.riot-os.org/mailman/listinfo/devel

Reply via email to