add Chapter 15 - runtime observer implementation
This commit is contained in:
18
Chapter15/observer/hal/adc/inc/adc.hpp
Normal file
18
Chapter15/observer/hal/adc/inc/adc.hpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <expected>
|
||||
|
||||
#include <units.hpp>
|
||||
|
||||
namespace hal
|
||||
{
|
||||
class adc {
|
||||
public:
|
||||
enum class error {
|
||||
timeout
|
||||
};
|
||||
|
||||
virtual void init() = 0;
|
||||
virtual std::expected<units::voltage, adc::error> get_reading() = 0;
|
||||
};
|
||||
};
|
||||
22
Chapter15/observer/hal/adc/inc/adc_stm32.hpp
Normal file
22
Chapter15/observer/hal/adc/inc/adc_stm32.hpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <adc.hpp>
|
||||
#include <units.hpp>
|
||||
|
||||
#include <stm32f0xx_hal.h>
|
||||
#include <stm32f072xb.h>
|
||||
|
||||
namespace hal
|
||||
{
|
||||
|
||||
class adc_stm32 : public adc{
|
||||
public:
|
||||
adc_stm32(units::voltage ref_voltage) : ref_voltage_(ref_voltage) {}
|
||||
|
||||
void init() override;
|
||||
std::expected<units::voltage, adc::error> get_reading() override;
|
||||
private:
|
||||
ADC_HandleTypeDef adc_handle_;
|
||||
units::voltage ref_voltage_;
|
||||
};
|
||||
};
|
||||
47
Chapter15/observer/hal/adc/src/adc_stm32.cpp
Normal file
47
Chapter15/observer/hal/adc/src/adc_stm32.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
#include <adc_stm32.hpp>
|
||||
|
||||
void hal::adc_stm32::init() {
|
||||
ADC_ChannelConfTypeDef sConfig = {0};
|
||||
|
||||
/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
|
||||
*/
|
||||
adc_handle_.Instance = ADC1;
|
||||
adc_handle_.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
|
||||
adc_handle_.Init.Resolution = ADC_RESOLUTION_12B;
|
||||
adc_handle_.Init.DataAlign = ADC_DATAALIGN_RIGHT;
|
||||
adc_handle_.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
|
||||
adc_handle_.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
|
||||
adc_handle_.Init.LowPowerAutoWait = DISABLE;
|
||||
adc_handle_.Init.LowPowerAutoPowerOff = DISABLE;
|
||||
adc_handle_.Init.ContinuousConvMode = DISABLE;
|
||||
adc_handle_.Init.DiscontinuousConvMode = DISABLE;
|
||||
adc_handle_.Init.ExternalTrigConv = ADC_SOFTWARE_START;
|
||||
adc_handle_.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
|
||||
adc_handle_.Init.DMAContinuousRequests = DISABLE;
|
||||
adc_handle_.Init.Overrun = ADC_OVR_DATA_PRESERVED;
|
||||
if (HAL_ADC_Init(&adc_handle_) != HAL_OK)
|
||||
{
|
||||
//Error_Handler();
|
||||
}
|
||||
|
||||
/** Configure for the selected ADC regular channel to be converted.
|
||||
*/
|
||||
sConfig.Channel = ADC_CHANNEL_0;
|
||||
sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
|
||||
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
|
||||
if (HAL_ADC_ConfigChannel(&adc_handle_, &sConfig) != HAL_OK)
|
||||
{
|
||||
//Error_Handler();
|
||||
}
|
||||
}
|
||||
|
||||
std::expected<units::voltage, hal::adc::error> hal::adc_stm32::get_reading() {
|
||||
HAL_ADC_Start(&adc_handle_);
|
||||
if(HAL_ADC_PollForConversion(&adc_handle_, 1000) != HAL_OK) {
|
||||
return std::unexpected(hal::adc::error::timeout);
|
||||
}
|
||||
|
||||
auto adc_val = HAL_ADC_GetValue(&adc_handle_);
|
||||
|
||||
return ref_voltage_ * adc_val / 4096.f;
|
||||
}
|
||||
19
Chapter15/observer/hal/gpio/inc/gpio.hpp
Normal file
19
Chapter15/observer/hal/gpio/inc/gpio.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
|
||||
namespace hal
|
||||
{
|
||||
class gpio
|
||||
{
|
||||
public:
|
||||
gpio(const std::function<void()> & on_press = nullptr);
|
||||
void execute_interrupt_handler() const;
|
||||
|
||||
[[nodiscard]] virtual bool is_interrupt_generated() const = 0;
|
||||
virtual void clear_interrupt_flag() const = 0;
|
||||
private:
|
||||
std::function<void()> on_press_;
|
||||
};
|
||||
}; // namespace hal
|
||||
19
Chapter15/observer/hal/gpio/inc/gpio_interrupt_manager.hpp
Normal file
19
Chapter15/observer/hal/gpio/inc/gpio_interrupt_manager.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
#include <gpio.hpp>
|
||||
|
||||
namespace hal {
|
||||
|
||||
struct gpio_interrupt_manager {
|
||||
static void register_interrupt_handler(gpio * pin);
|
||||
|
||||
static void execute_interrupt_handlers();
|
||||
|
||||
static constexpr std::size_t c_gpio_handlers_num = 16;
|
||||
static inline std::array<gpio*, c_gpio_handlers_num> gpio_handlers{};
|
||||
static inline std::size_t w_idx = 0;
|
||||
};
|
||||
};
|
||||
70
Chapter15/observer/hal/gpio/inc/gpio_stm32.hpp
Normal file
70
Chapter15/observer/hal/gpio/inc/gpio_stm32.hpp
Normal file
@@ -0,0 +1,70 @@
|
||||
#include <gpio.hpp>
|
||||
|
||||
#include <stm32f072xb.h>
|
||||
|
||||
namespace hal {
|
||||
|
||||
enum class pin : uint16_t {
|
||||
p_invalid = 0,
|
||||
p0 = 0x0001U,
|
||||
p1 = 0x0002U,
|
||||
p2 = 0x0004U,
|
||||
p3 = 0x0008U,
|
||||
p4 = 0x0010U,
|
||||
p5 = 0x0020U,
|
||||
p6 = 0x0040U,
|
||||
p7 = 0x0080U,
|
||||
p8 = 0x0100U,
|
||||
p9 = 0x0200U,
|
||||
p10 = 0x0400U,
|
||||
p11 = 0x0800U,
|
||||
p12 = 0x1000U,
|
||||
p13 = 0x2000U,
|
||||
p14 = 0x4000U,
|
||||
p15 = 0x8000U,
|
||||
all = 0xFFFFU
|
||||
};
|
||||
|
||||
struct port_a {
|
||||
static constexpr uint8_t c_pin_num = 16;
|
||||
static inline GPIO_TypeDef * port = reinterpret_cast<GPIO_TypeDef*>(GPIOA);
|
||||
static void init_clock () {
|
||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Port>
|
||||
class gpio_stm32 : public gpio {
|
||||
public:
|
||||
gpio_stm32(pin the_pin, const std::function<void()> & on_press = nullptr)
|
||||
: gpio(on_press), the_pin_(the_pin) {
|
||||
Port::init_clock();
|
||||
|
||||
GPIO_InitTypeDef GPIO_InitStruct { static_cast<uint16_t>(the_pin),
|
||||
GPIO_MODE_IT_RISING,
|
||||
GPIO_NOPULL,
|
||||
GPIO_SPEED_FREQ_LOW,
|
||||
0 };
|
||||
HAL_GPIO_Init(Port::port, &GPIO_InitStruct);
|
||||
|
||||
if(on_press) {
|
||||
enable_interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] bool is_interrupt_generated() const override {
|
||||
return __HAL_GPIO_EXTI_GET_IT(static_cast<uint16_t>(the_pin_));
|
||||
}
|
||||
void clear_interrupt_flag() const override {
|
||||
__HAL_GPIO_EXTI_CLEAR_IT(static_cast<uint16_t>(the_pin_));
|
||||
}
|
||||
private:
|
||||
pin the_pin_ = pin::p_invalid;
|
||||
|
||||
void enable_interrupt() {
|
||||
// TODO: check EXTI line macro according to pin used
|
||||
HAL_NVIC_SetPriority(EXTI4_15_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(EXTI4_15_IRQn);
|
||||
}
|
||||
};
|
||||
};
|
||||
21
Chapter15/observer/hal/gpio/src/gpio.cpp
Normal file
21
Chapter15/observer/hal/gpio/src/gpio.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#include <gpio.hpp>
|
||||
#include <gpio_interrupt_manager.hpp>
|
||||
|
||||
namespace hal {
|
||||
|
||||
gpio::gpio(const std::function<void()> & on_press) {
|
||||
on_press_ = on_press;
|
||||
gpio_interrupt_manager::register_interrupt_handler(this);
|
||||
}
|
||||
|
||||
void gpio::execute_interrupt_handler () const {
|
||||
if(is_interrupt_generated())
|
||||
{
|
||||
clear_interrupt_flag();
|
||||
if(on_press_) {
|
||||
on_press_();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
17
Chapter15/observer/hal/gpio/src/gpio_interrupt_manager.cpp
Normal file
17
Chapter15/observer/hal/gpio/src/gpio_interrupt_manager.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#include <gpio_interrupt_manager.hpp>
|
||||
|
||||
namespace hal {
|
||||
|
||||
void gpio_interrupt_manager::register_interrupt_handler(gpio * pin) {
|
||||
gpio_handlers.at(w_idx++) = pin;
|
||||
}
|
||||
|
||||
void gpio_interrupt_manager::execute_interrupt_handlers() {
|
||||
for(std::size_t i = 0; i < w_idx; i++) {
|
||||
gpio_handlers[i]->execute_interrupt_handler();
|
||||
}
|
||||
}
|
||||
extern "C" void EXTI4_15_IRQHandler(void) {
|
||||
gpio_interrupt_manager::execute_interrupt_handlers();
|
||||
}
|
||||
};
|
||||
33
Chapter15/observer/hal/inc/hal.hpp
Normal file
33
Chapter15/observer/hal/inc/hal.hpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <stm32f0xx_hal.h>
|
||||
|
||||
namespace hal
|
||||
{
|
||||
inline void init()
|
||||
{
|
||||
HAL_Init();
|
||||
}
|
||||
|
||||
inline std::uint32_t get_pc()
|
||||
{
|
||||
std::uint32_t pc;
|
||||
__asm volatile ("mov %0, pc" : "=r" (pc) );
|
||||
return pc;
|
||||
}
|
||||
|
||||
struct time
|
||||
{
|
||||
static std::uint32_t get_ms()
|
||||
{
|
||||
return HAL_GetTick();
|
||||
}
|
||||
|
||||
static void delay_ms(uint32_t delay)
|
||||
{
|
||||
HAL_Delay(delay);
|
||||
}
|
||||
};
|
||||
}; // namespace hal
|
||||
21
Chapter15/observer/hal/uart/inc/stm32f0xx_hal_uart.hpp
Normal file
21
Chapter15/observer/hal/uart/inc/stm32f0xx_hal_uart.hpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <stm32f0xx_hal.h>
|
||||
#include <stm32f072xb.h>
|
||||
|
||||
namespace hal::stm32{
|
||||
struct uart {
|
||||
uart() = delete;
|
||||
|
||||
static inline HAL_StatusTypeDef init(UART_HandleTypeDef *huart) {
|
||||
return HAL_UART_Init(huart);
|
||||
}
|
||||
|
||||
static inline HAL_StatusTypeDef transmit(UART_HandleTypeDef *huart,
|
||||
uint8_t *pData,
|
||||
uint16_t Size,
|
||||
uint32_t Timeout) {
|
||||
return HAL_UART_Transmit(huart, pData, Size, Timeout);
|
||||
}
|
||||
};
|
||||
};
|
||||
14
Chapter15/observer/hal/uart/inc/uart.hpp
Normal file
14
Chapter15/observer/hal/uart/inc/uart.hpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <span>
|
||||
|
||||
namespace hal
|
||||
{
|
||||
class uart
|
||||
{
|
||||
public:
|
||||
virtual void init(std::uint32_t baudrate) = 0;
|
||||
virtual void write(std::span<const char> data) = 0;
|
||||
};
|
||||
}; // namespace hal
|
||||
46
Chapter15/observer/hal/uart/inc/uart_stm32.hpp
Normal file
46
Chapter15/observer/hal/uart/inc/uart_stm32.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <span>
|
||||
#include <cstdint>
|
||||
|
||||
#include <uart.hpp>
|
||||
|
||||
#include <stm32f0xx_hal_uart.hpp>
|
||||
|
||||
namespace hal
|
||||
{
|
||||
template <typename HalUart>
|
||||
class uart_stm32 : public uart
|
||||
{
|
||||
public:
|
||||
uart_stm32(USART_TypeDef *inst) : instance_(inst) {}
|
||||
|
||||
void init(std::uint32_t baudrate = c_baudrate_default) override {
|
||||
huart_.Instance = instance_;
|
||||
huart_.Init.BaudRate = baudrate;
|
||||
huart_.Init.WordLength = UART_WORDLENGTH_8B;
|
||||
huart_.Init.StopBits = UART_STOPBITS_1;
|
||||
huart_.Init.Parity = UART_PARITY_NONE;
|
||||
huart_.Init.Mode = UART_MODE_TX_RX;
|
||||
huart_.Init.HwFlowCtl = UART_HWCONTROL_NONE;
|
||||
huart_.Init.OverSampling = UART_OVERSAMPLING_16;
|
||||
huart_.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
|
||||
huart_.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
|
||||
// TODO: add GPIO initialization for real hardware
|
||||
huart_.MspInitCallback = nullptr;
|
||||
HalUart::init(&huart_);
|
||||
}
|
||||
void write(std::span<const char> data) override {
|
||||
// we must cast away costness due to ST HAL's API
|
||||
char * data_ptr = const_cast<char *>(data.data());
|
||||
HalUart::transmit(&huart_, reinterpret_cast<uint8_t *>(data_ptr), data.size(),
|
||||
HAL_MAX_DELAY);
|
||||
}
|
||||
|
||||
private:
|
||||
UART_HandleTypeDef huart_;
|
||||
USART_TypeDef *instance_;
|
||||
std::uint32_t baudrate_;
|
||||
static constexpr std::uint32_t c_baudrate_default = 115200;
|
||||
};
|
||||
}; // namespace hal
|
||||
34
Chapter15/observer/hal/uart/src/uart_stm32.cpp
Normal file
34
Chapter15/observer/hal/uart/src/uart_stm32.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#include <uart_stm32.hpp>
|
||||
|
||||
template <typename HalUart>
|
||||
hal::uart_stm32<HalUart>::uart_stm32(USART_TypeDef *inst)
|
||||
: instance_(inst)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename HalUart>
|
||||
void hal::uart_stm32<HalUart>::init(std::uint32_t baudrate)
|
||||
{
|
||||
huart_.Instance = instance_;
|
||||
huart_.Init.BaudRate = baudrate;
|
||||
huart_.Init.WordLength = UART_WORDLENGTH_8B;
|
||||
huart_.Init.StopBits = UART_STOPBITS_1;
|
||||
huart_.Init.Parity = UART_PARITY_NONE;
|
||||
huart_.Init.Mode = UART_MODE_TX_RX;
|
||||
huart_.Init.HwFlowCtl = UART_HWCONTROL_NONE;
|
||||
huart_.Init.OverSampling = UART_OVERSAMPLING_16;
|
||||
huart_.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
|
||||
huart_.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
|
||||
// TODO: add GPIO initialization for real hardware
|
||||
huart_.MspInitCallback = nullptr;
|
||||
HalUart::init(&huart_);
|
||||
}
|
||||
|
||||
template <typename HalUart>
|
||||
void hal::uart_stm32<HalUart>::write(std::span<const char> data)
|
||||
{
|
||||
// we must cast away costness due to ST HAL's API
|
||||
char * data_ptr = const_cast<char *>(data.data());
|
||||
HalUart::transmit(&huart_, reinterpret_cast<uint8_t *>(data_ptr), data.size(),
|
||||
HAL_MAX_DELAY);
|
||||
}
|
||||
Reference in New Issue
Block a user