Files
lab-rv32i-freertos-integration/include/freertos/isr_drivers.hpp
T

279 lines
6.3 KiB
C++

#ifndef FREERTOS_ISR_DRIVERS_HPP
#define FREERTOS_ISR_DRIVERS_HPP
#include <cstddef>
#include <cstdint>
#include <type_traits>
extern "C"
{
#include "FreeRTOS.h"
#include "queue.h"
#include "task.h"
}
namespace freertos
{
class IsrContext final
{
public:
void merge_wake_request( BaseType_t local_request ) noexcept
{
if( local_request != pdFALSE )
{
higher_priority_task_woken_ = pdTRUE;
}
}
[[nodiscard]] bool wake_requested() const noexcept
{
return higher_priority_task_woken_ != pdFALSE;
}
[[nodiscard]] std::uint32_t yield_calls() const noexcept
{
return yield_calls_;
}
[[nodiscard]] bool yield_if_needed() noexcept
{
++yield_calls_;
bool const requested = wake_requested();
portYIELD_FROM_ISR( higher_priority_task_woken_ );
return requested;
}
private:
BaseType_t higher_priority_task_woken_{ pdFALSE };
std::uint32_t yield_calls_{ 0U };
};
enum class IsrSendResult
{
queued,
dropped_newest
};
template< typename T, std::size_t Capacity >
class StaticIsrQueue final
{
static_assert( Capacity > 0U );
static_assert( std::is_trivially_copyable_v< T > );
public:
StaticIsrQueue( StaticQueue_t & control, std::uint8_t * bytes ) noexcept
: handle_( xQueueCreateStatic( static_cast< UBaseType_t >( Capacity ),
static_cast< UBaseType_t >( sizeof( T ) ),
bytes,
&control ) )
{
}
StaticIsrQueue( const StaticIsrQueue & ) = delete;
StaticIsrQueue & operator=( const StaticIsrQueue & ) = delete;
[[nodiscard]] bool valid() const noexcept
{
return handle_ != nullptr;
}
[[nodiscard]] IsrSendResult send_from_isr( const T & item,
IsrContext & context ) noexcept
{
BaseType_t local_wake = pdFALSE;
BaseType_t const result = xQueueSendFromISR( handle_, &item, &local_wake );
context.merge_wake_request( local_wake );
return result == pdPASS ? IsrSendResult::queued
: IsrSendResult::dropped_newest;
}
[[nodiscard]] bool receive( T & item, TickType_t timeout ) noexcept
{
return xQueueReceive( handle_, &item, timeout ) == pdPASS;
}
private:
QueueHandle_t handle_;
};
class TaskNotificationRef final
{
public:
explicit constexpr TaskNotificationRef( TaskHandle_t task ) noexcept
: task_( task )
{
}
[[nodiscard]] bool give_from_isr( IsrContext & context ) const noexcept
{
BaseType_t local_wake = pdFALSE;
vTaskNotifyGiveFromISR( task_, &local_wake );
context.merge_wake_request( local_wake );
return true;
}
private:
TaskHandle_t task_;
};
struct UartRegisters
{
volatile std::uint32_t status;
volatile std::uint32_t rx_data[ 2 ];
volatile std::uint32_t rx_count;
volatile std::uint32_t control;
};
class UartTaskView final
{
public:
explicit constexpr UartTaskView( UartRegisters & registers ) noexcept
: registers_( &registers )
{
}
void enable_rx_irq() const noexcept { registers_->control = 1U; }
void inject_rx_pair_for_test( std::uint8_t first,
std::uint8_t second ) const noexcept
{
registers_->rx_data[ 0 ] = first;
registers_->rx_data[ 1 ] = second;
registers_->rx_count = 2U;
registers_->status = 1U;
}
private:
UartRegisters * registers_;
};
class UartIsrView final
{
public:
explicit constexpr UartIsrView( UartRegisters & registers ) noexcept
: registers_( &registers )
{
}
[[nodiscard]] bool rx_ready_from_isr() const noexcept
{
return ( registers_->status & 1U ) != 0U &&
registers_->rx_count != 0U;
}
[[nodiscard]] std::uint8_t read_rx_from_isr() const noexcept
{
configASSERT( rx_ready_from_isr() );
std::uint8_t const byte =
static_cast< std::uint8_t >( registers_->rx_data[ 0 ] );
registers_->rx_data[ 0 ] = registers_->rx_data[ 1 ];
--registers_->rx_count;
if( registers_->rx_count == 0U )
{
registers_->status = 0U;
}
return byte;
}
private:
UartRegisters * registers_;
};
class Uart final
{
public:
explicit constexpr Uart( UartRegisters & registers ) noexcept
: registers_( &registers ) {}
[[nodiscard]] UartTaskView task_view() const noexcept
{
return UartTaskView{ *registers_ };
}
[[nodiscard]] UartIsrView isr_view() const noexcept
{
return UartIsrView{ *registers_ };
}
private:
UartRegisters * registers_;
};
struct GpioRegisters
{
volatile std::uint32_t direction;
volatile std::uint32_t data;
volatile std::uint32_t edge_status;
};
class GpioTaskView final
{
public:
explicit constexpr GpioTaskView( GpioRegisters & registers ) noexcept
: registers_( &registers ) {}
void configure_output( std::uint32_t mask ) const noexcept
{
registers_->direction |= mask;
}
void write_output( std::uint32_t mask, bool high ) const noexcept
{
if( high ) { registers_->data |= mask; }
else { registers_->data &= ~mask; }
}
void inject_edge_for_test( std::uint32_t mask ) const noexcept
{
registers_->edge_status |= mask;
}
private:
GpioRegisters * registers_;
};
class GpioIsrView final
{
public:
explicit constexpr GpioIsrView( GpioRegisters & registers ) noexcept
: registers_( &registers ) {}
[[nodiscard]] bool edge_pending_from_isr( std::uint32_t mask ) const noexcept
{
return ( registers_->edge_status & mask ) != 0U;
}
void clear_edge_from_isr( std::uint32_t mask ) const noexcept
{
registers_->edge_status &= ~mask;
}
private:
GpioRegisters * registers_;
};
class GpioPin final
{
public:
explicit constexpr GpioPin( GpioRegisters & registers ) noexcept
: registers_( &registers ) {}
[[nodiscard]] GpioTaskView task_view() const noexcept
{
return GpioTaskView{ *registers_ };
}
[[nodiscard]] GpioIsrView isr_view() const noexcept
{
return GpioIsrView{ *registers_ };
}
private:
GpioRegisters * registers_;
};
} // namespace freertos
#endif