The reason that I wanted to use function pointers in the NVRAM
interface is to avoid having to resort to macros or defining wrapper
functions in the board directory for my specific board's NVRAM
hardware. As I see it I have three choices for implementing a board
specific configuration of NVRAM:

 - Macros for the board's functions such as:
    board.h:
    #define NVRAM_READ(addr, len) nvram_spi_read(MYBOARD_NVRAM_SPI,
MYBOARD_NVRAM_CS, addr, len)
    #define ....

 - board-specific wrapper functions:
    board.c:
    int nvram_read(addr, len) {
        return nvram_spi_read(MYBOARD_NVRAM_SPI, MYBOARD_NVRAM_CS, addr, len)
    }
    ....

- Function pointers:
    board.c:
    inside board_init():
    nvram_spi_init(&fram, &spi_params, memsize);

I decided on function pointers for the ease of use and the clear
interface abstraction.

BR,
Joakim Gebart
www.eistec.se


On Wed, Feb 18, 2015 at 11:16 PM, Oleg Hahm <oliver.h...@inria.fr> wrote:
> Hi Kévin!
>
>> 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.
>
> Yes, I remember that, but why can't this be implemented in a similar way we
> did for most of the peripheral drivers like SPI? Instead of calling a function
> pointer, we simply pass a struct describing the low-level device (driver) that
> should be used.
>
>> 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.
>
> I completely agree on the point that we need to have direct function calls for
> MAC protocols (see also http://arxiv.org/abs/1502.01968).
>
>> 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 think it is indeed one of the two natural solutions - the other one would be
> MACROing everything. I made experiences with both versions while developing on
> firmware for older sensor board platforms. And both had their drawbacks. Thus,
> when I started to work on what now is known as RIOT, I wanted to avoid Macros
> and a function pointer based abstraction layer model as much as possible. Of
> course, there are cases where either the one or the other will be the best
> solution, but I think we have to make sure to check if there are no
> alternative solutions that might work better on the long run.
>
>> 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.
>
> You name it: If everything is known at link time, then there is also always a
> way around function pointers. As I've written in the previous mail: I'd rather
> tell the compiler (or linker) how to do the stuff in an efficient way than
> hoping for the toolchain being smarter than me.
>
>> 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.
>
> I cannot disclose any code here, because it was proprietary code for my old
> company, but the problem was a layered one. We had a highly abstracted driver
> model, similar to Linux' one with char and block devices, abstracted serial
> line devices and the like. Thus, an application or any high level code
> accessing low-level drivers would be de-referenced multiple times. This made
> it incredible hard to debug (because you had to follow all the pointer
> de-referencing) and made it almost impossible to hold some strict deadlines
> for TDMA on our old MSP430F1612.
>
>> 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.
>
> I think we can live with the overhead of IPC calls on all layers except the
> MAC protocol. However, even message-passing has a predictable delay in RIOT -
> just the concrete numbers might be to high for some low latency MAC protocols.
> But again, I'm definitely not arguing against function calls for these tasks,
> just wondering if function pointers are the smartest solution here. (And I'm
> not saying that they're not...)
>
> Cheers,
> Oleg
> --
> printk("CPU[%d]: Giving pardon to imprisoned penguins\n", smp_processor_id());
>         linux-2.4.8/arch/sparc64/kernel/smp.c
>
> _______________________________________________
> 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