lundi 9 septembre 2019

how to encapsulate ble / ip / ... devices with a common interface in C

I'm writing a library to send data from embedded device to PC using BLE / IP / ..., this library mainly focuses on packet segmentation(< MTU), CRC, etc.

Now I want to hide the details of BLE / IP / ..., with a common interface type data_transfer_instance_t, how can I finish this using linux driver's fashion?



More specifically, there are 2 kind of device to be supported now, BLE and IP, I'll take BLE as example in the following below.

BLE has a implementation struct ble_driver_t, and some method associated with, e.g.,

  • ble_driver_init(ble_driver_t* ble_driver)
  • ble_driver_send_data(ble_driver_t* ble_driver, const BYTE* data, UINT16 data_len)
  • ...

The library mainly deals with data_transfer_instance_t,

typedef struct _data_transfer_instance_t {
    void (*init)();
    bool (*send_data)(const BYTE* data, UINT16 data_len);
    ...
} data_transfer_instance_t;

using a management struct data_transfer_service_t,

typedef struct _data_transfer_service_t {
    data_transfer_instance_t* data_transfer_inst;
    ...
} data_transfer_service_t;

and some related methods:

  • data_transfer_service_init(data_transfer_service_t* data_transfer_service_t)
  • data_transfer_service_send_data(data_transfer_service_t* data_transfer_service, const BYTE* data, UINT16 data_len)
  • ...

Problem is here, how can I connect a data_transfer_instance_t instance with a ble_driver_t instance???

For now, I use a wrapper function,

ble_data_transfer_wrapper_init(data_transfer_instance_t* data_transfer_instance, ble_driver_t* ble_driver),

but since data_transfer_instance_t is a pure interface without any internal state, I have 2 choices:

  • store input ble_driver in a static global variable in its implementation file, but this prevents me to construct 2 or more data_transfer_instance_t instances with 2 or more ble_driver_t device instances
  • add a self reference pointer to data_transfer_instance_t's interface, e.g.,
    typedef struct _data_transfer_instance_t {
        void (*init)(data_transfer_instance_t* data_transfer_instance);
        bool (*send_data)(data_transfer_instance_t* data_transfer_instance, const BYTE* data, UINT16 data_len);
        ...
    } data_transfer_instance_t;
    
    
    then I have to write my code like p_data_transfer_inst->func(p_data_transfer_inst, ...), which seems annoying and redundant

Can anybody give me some advice on how to implement or even refactor my code in linux driver' style?

Aucun commentaire:

Enregistrer un commentaire