When working on embedded devices (read: microcontrollers), you often write a driver for a peripheral such as an UART (aka. serial port). This driver may just be a thin HAL, locking the peripheral (to make it thread safe) and wrapping the calls to a C library (provided by the manufacturer of the microcontroller).
Further, a microcontroller often has multiple peripherals (physical interfaces) of the same type, i.e., UART0, UART1, UART2, etc.
That's how I'd represent them in C++:
#include <stdint.h>
class DevUart {
public:
enum class interfaces_t {
UART0 = 0,
UART1 = 1,
UART2 = 2,
UART3 = 3,
UART4 = 4
};
DevUart(interfaces_t interface) : Interface{interface} {
switch(interface) {
case interfaces_t::UART0:
HardwareRegister = (void *)0xE0001000;
break;
/* for UART1, etc. ... */
}
}
void sendByte(uint8_t data) {
/* lock Interface, send data, unlock Interface, etc. */ }
private:
interfaces_t Interface;
void * HardwareRegister;
};
To guarantee that the same driver instance is using a given peripheral, I use the following singleton:
class DevUartSingleton {
public:
static DevUart & Instance(DevUart::interfaces_t interface) {
static DevUart S{interface};
return S;
}
DevUartSingleton() = delete;
~DevUartSingleton() = delete;
};
However, this singleton only supports for a single driver instance in the system, e.g., UART2:
DevUart & uart_driverC = DevUartSingleton::Instance(DevUart::interfaces_t::UART2);
If I wanted to also instantiate a driver for, e.g., UART0, I'd need a different solution.
Thus I'm looking for a solution to allow for creating multiple instances of that driver, but no more than a single driver for each physical interface. In other words, I'm looking for a singleton that returns different drivers for different interfaces but the same driver for the same interface. So that you can use the different peripherals, while guaranteeing that there will only ever be one driver instance that is representing the physical interface. I hope that makes sense to you.