# How is a New Device Added?

> One question that will go a long way to help me understand the new flow is what has to happen to add a new instrument on an available UART?

## Implement Drivers Against Abstract Interfaces, Not Implementations

When you add new device drivers, you need to make sure their constructors take in _references to a base class interface for the underlying communication protocol_. For example, if using a UART, you should include `UART_Interface.hpp` and have the constructor take in a reference to the base class:

```cpp
GPSUBlox(UART& uart) : GPS("GPSUBlox"), uart_(uart)
```

Your driver will then be developed against the generic interface for the specific communication/control protocol.

## Declaring Instances

All of the declarations and mappings currently happen in `bsp.cpp`. This way, you have one location that declares all of your resource assignments. This makes it easy to review and change in one single place, rather than scouring the system for the different mappings.

You will need to create the necessary declarations required by the underlying device prior to declaring your new driver instance.

For example, the `GPSUBlox` class talks over UART. To hook it up to an STM32 UART with DMA support, you first need to declare the necessary dependents for the UART class (DMA channels and a timer). The DMA declaration selects the DMA instance and channels that will be used by the UART device. Check and make sure that you are not declaring something with conflicting channels (that's why all the device allocations happen in one place).

```cpp
auto uart1Timer = timer_mgr.allocate();
STM32DMA gps1UART_DMA_tx(STM32DMA::device::dma1, STM32DMA::channel::CH1);
STM32DMA gps1UART_DMA_rx(STM32DMA::device::dma1, STM32DMA::channel::CH0);
```

The STM32 UART driver takes in a configuration structure, so that needs to be declared:

```cpp
STM32UART::DMA::config gps1UARTConfig{.baudrate = 9600,
										  .tx_channel = gps1UART_DMA_tx,
										  .rx_channel = gps1UART_DMA_rx,
										  .timeout_timer = uart1Timer};
```

And then the UART itself can be declared:

```cpp
STM32UART::DMA gps1UART(STM32UART::devices::usart1, gps1UARTConfig);
```

At this point, it is wise to check `_bsp_private.hpp` and make sure that the pins for the UART are correctly defined. This is most important if you are using a new UART for the first time.

Now that you have the dependent device declared, you can create an instance of your driver, supplying the UART driver as a constructor parameter.

```cpp
GPS1 gps1(gps1UART);
```

If you wanted to switch which UART a device was attached to, all you would need to change would be the "STM32UART::devices::usart1" parameter passed to the UART driver constructor to select the desired device. (e.g., `STM32UART::devices::uart4`)

For completeness - if you needed to change from a DMA-driven driver to an interrupt-driven driver (e.g., some device has a higher priority claim on DMA channels), that would end up being a different declaration, like this:

```cpp
STM32UART::Interrupt gps1UART(STM32UART::devices::usart1);
```

The GPS driver would not need to make any changes on its part to adapt to the new setting, since all it knows about is the abstract UART interface.
