We have a battery manager implementation which uses a fuel gauge driver and a charger driver. Currently both of these drivers are hard-references to the fuel gauge and charger driver we currently support.
Now for new projects, another fuel gauge and another charger have been selected. We would like to keep the logic of the battery manager, but that the drivers can be chosen dynamically. The drivers all provide similar functionality for reading the important values and such.
The drivers are all part of our own library, we don't expect that we will have to support third party drivers. Also, we don't expect multiple fuel gauges or chargers to be present simultaneously.
Currently I see three options:
1. Give a filled-in API struct with function pointers to the Battery Manager
- Description: Initialize the Battery Manager with a struct of function pointers to e.g. the Fuel Gauge and Charger driver's their initialization and sensor reading functions
- Pros: Flexible
- Cons: The Battery Manager initialization caller has to know about the drivers
2. Let the Battery Manager find available fuel gauge and charger drivers from a shared list in which the fuel gauge and charger drivers register themselves
- Description: Setup a list that the is accessible by the drivers and the modules that use those drivers. The drivers register themselves in this list, the modules look for drivers that match their type
- Pros: The module initialization callers do not need to know about the drivers
- Cons: More programming overhead
3. Let the fuel gauge and charger drivers all implement the same interface (shared header) and let the Battery Manager just reference that
- Description: Have one .h file per driver type define the interface, and have drivers implement that interface so that the Battery Manager can just call e.g. FuelGauge_ReadVoltage() everywhere
- Pros: Easy to implement
- Cons: Feels hackish
I would very much appreciate your insights! Did I miss options? Did I miss pro's and/or cons? What would be the best choice?