Compare commits

...

2 Commits

Author SHA1 Message Date
Erki
c994e63478 Initial implementation of app state machine 2022-07-17 18:20:45 +03:00
Erki
1c695fbaa8 Implement millis() function 2022-07-16 12:23:07 +03:00
9 changed files with 144 additions and 85 deletions

View File

@ -49,7 +49,7 @@ add_executable(skl_tunnel
radio/src/radio_gpio.c
radio/src/radio_hw_instance.cpp
app/src/app_logging.cpp
app/src/app_board.cpp
app/src/app_transparent_client.cpp
main.cpp
syscalls.c

View File

@ -1,15 +0,0 @@
//
// Created by erki on 28.06.22.
//
#ifndef SKL_TUNNEL_APP_LOGGING_HPP
#define SKL_TUNNEL_APP_LOGGING_HPP
namespace App::Logging
{
void setup();
}
#endif //SKL_TUNNEL_APP_LOGGING_HPP

View File

@ -36,8 +36,23 @@ private:
Utility::FunctionOwned<TransparentClient, void (radio::HwInstance*)> m_isr_cb_pointer;
std::optional<radio::Interrupts> m_pending_irqs = std::nullopt;
enum class AppState
{
STARTUP,
PASSIVE,
ACTIVE_RX,
ACTIVE_TX,
RX_FRAME_READY
};
AppState m_state = AppState::STARTUP;
void m_cbRadioIrqHandler(radio::HwInstance*);
void m_processInterrupts();
std::optional<AppState> m_hwInterruptToNewState();
void m_transitionToState(const AppState& new_state);
void m_processState();
void m_initiateTx();
bool m_txBufferIsReady();
};
}

View File

@ -5,10 +5,6 @@
#ifndef SKL_TUNNEL_SKULLC_SAMD21_HAL_HPP
#define SKL_TUNNEL_SKULLC_SAMD21_HAL_HPP
#include <array>
#include <cstdint>
#include <cassert>
#include <hal_delay.h>
#include <hal_io.h>
#include <hal_usart_async.h>
@ -16,6 +12,12 @@
#include <utility_function.hpp>
#include <utility_tag.hpp>
#include <array>
#include <cstdint>
#include <cassert>
#include "app_board.hpp"
namespace Peripherals
{
namespace Hal
@ -26,7 +28,14 @@ namespace Samd
struct StaticHal
{
static void initialize()
{ }
{
App::Board::setup();
}
static std::uint32_t getMillis()
{
return App::Board::systickGet();
}
static void delay(const std::uint32_t milliseconds)
{

View File

@ -2,15 +2,16 @@
// Created by erki on 15.07.22.
//
#include "driver_init.h"
#include "app_board.hpp"
#include "driver_init.h"
#include "skullc_samd21_hal.hpp"
#include <utility_logging.hpp>
#include <utility_asynclogger.hpp>
#include <utility_staticpointer.hpp>
#include "skullc_samd21_hal.hpp"
namespace Hal = Peripherals::Hal::Samd;
@ -46,7 +47,7 @@ void setup()
m_logger.setup(usart0);
Utility::setLogger(*m_logger);
SysTick_Config(1000);
SysTick_Config(F_CPU / 1000u);
}
std::uint32_t systickGet()

View File

@ -1,43 +0,0 @@
//
// Created by erki on 28.06.22.
//
#include "app_logging.hpp"
#include "driver_init.h"
#include <utility_logging.hpp>
#include <utility_asynclogger.hpp>
#include <utility_staticpointer.hpp>
#include "skullc_samd21_hal.hpp"
namespace Hal = Peripherals::Hal::Samd;
using Logger = Utility::AsyncLogger<Hal::SerialInterfaceAsync<usart_async_descriptor>, Hal::StaticHal, 5, 255>;
namespace
{
Utility::StaticPointer<Logger> m_logger;
void m_txCompleteCb(const usart_async_descriptor* const)
{
m_logger->txCompleteCallback();
}
}
namespace App::Logging
{
void setup()
{
Hal::SerialInterfaceAsync<usart_async_descriptor> usart0{&USART_0};
usart0.registerTxCallback(m_txCompleteCb);
m_logger.setup(usart0);
Utility::setLogger(*m_logger);
}
}

View File

@ -5,6 +5,10 @@
#include "radio_hw_instance.hpp"
#include "app_transparent_client.hpp"
#include "skullc_samd21_hal.hpp"
#include "utility_logging.hpp"
#include <utility_atomicscopeguard.hpp>
namespace App
{
@ -14,7 +18,7 @@ TransparentClient::TransparentClient(const RadioSettings& initial_settings)
, m_isr_cb_pointer(*this, &TransparentClient::m_cbRadioIrqHandler)
{
apply_settings(initial_settings);
m_radio->set_irq_handler(&m_isr_cb_pointer);
m_radio->set_current_state(radio::HwInstance::States::PLL_ON);
}
@ -30,8 +34,21 @@ void TransparentClient::apply_settings(const RadioSettings& settings)
void TransparentClient::process()
{
if (m_pending_irqs)
m_processInterrupts();
std::optional<AppState> new_state_request = std::nullopt;
{
Utility::AtomicScopeGuard<Peripherals::Hal::Samd::StaticHal> irq_guard;
if (m_pending_irqs)
new_state_request = m_hwInterruptToNewState();
}
if (!new_state_request && m_txBufferIsReady())
new_state_request = AppState::ACTIVE_TX;
if (new_state_request)
m_transitionToState(*new_state_request);
m_processState();
}
void TransparentClient::m_cbRadioIrqHandler(radio::HwInstance*)
@ -43,9 +60,86 @@ void TransparentClient::m_cbRadioIrqHandler(radio::HwInstance*)
m_pending_irqs = new_irqs;
}
void TransparentClient::m_processInterrupts()
std::optional<TransparentClient::AppState> TransparentClient::m_hwInterruptToNewState()
{
const radio::Interrupts current_irqs = *m_pending_irqs;
m_pending_irqs = std::nullopt;
SKULLC_LOG_DEBUG("APP: Processing IRQs: %d.", current_irqs);
const auto flag_is_set = [current_irqs](const radio::Interrupts& flag) -> bool
{
return std::underlying_type_t<radio::Interrupts>(current_irqs & flag);
};
switch (m_state)
{
case AppState::STARTUP:
if (flag_is_set(radio::Interrupts::PLL_LOCK))
return AppState::PASSIVE;
break;
case AppState::PASSIVE:
if (flag_is_set(radio::Interrupts::RX_START))
return AppState::ACTIVE_RX;
else if (flag_is_set(radio::Interrupts::AMI))
return AppState::RX_FRAME_READY;
break;
case AppState::ACTIVE_RX:
[[fallthrough]];
case AppState::ACTIVE_TX:
if (flag_is_set(radio::Interrupts::TRX_END))
return AppState::PASSIVE;
break;
default:
break;
}
return std::nullopt;
}
void TransparentClient::m_transitionToState(const AppState& new_state)
{
SKULLC_LOG_DEBUG("APP: Trans. to state. %d -> %d.", m_state, new_state);
switch (m_state)
{
case AppState::STARTUP:
if (new_state == AppState::PASSIVE)
m_radio->set_current_state(radio::HwInstance::States::RX_ON);
break;
case AppState::PASSIVE:
// new_state == AppState::ACTIVE_RX is a HW transition. State machine simply locks itself.
// new_state == AppState::RX_FRAME_READY is handled in process state.
if (new_state == AppState::ACTIVE_TX)
m_initiateTx();
break;
case AppState::ACTIVE_RX:
// new_state == AppState::PASSIVE is a HW transition. State machine simply unlocks itself.
break;
case AppState::ACTIVE_TX:
if (new_state == AppState::PASSIVE)
m_radio->set_current_state(radio::HwInstance::States::RX_ON);
break;
case AppState::RX_FRAME_READY:
break;
}
m_state = new_state;
}
void TransparentClient::m_processState()
{
return;
}
void TransparentClient::m_initiateTx()
{
return;
}
bool TransparentClient::m_txBufferIsReady()
{
return false;
}
}

View File

@ -6,7 +6,6 @@
#include <utility_function.hpp>
#include "radio_hw_instance.hpp"
#include "app_logging.hpp"
#include "skullc_samd21_hal.hpp"
#include "app_transparent_client.hpp"
@ -34,30 +33,28 @@ int main()
atmel_start_init();
Utility::Assert::setHandler(m_faultHandler);
Hal::StaticHal::initialize();
gpio_set_pin_level(OUT_LED_TX, false);
App::Logging::setup();
SKULLC_LOG_DEBUG("Begin.");
const App::RadioSettings settings;
m_app.setup(settings);
radio::HwInstance* radio_hw = radio::HwInstance::instance();
std::uint32_t counter = 0;
/* Replace with your application code */
while (true)
{
gpio_toggle_pin_level(OUT_LED_RX);
if (counter++ == 1000)
{
gpio_toggle_pin_level(OUT_LED_TX);
counter = 0;
}
gpio_toggle_pin_level(OUT_LED_TX);
int16_t radio_status = radio_hw->register_read(radio::Registers::TRX_STATUS);
radio_status &= 0x1F;
SKULLC_LOG_INFO("Status: %d", radio_status);
delay_ms(1000);
m_app->process();
Hal::StaticHal::delay(1);
}
}

View File

@ -150,6 +150,7 @@ bool HwInstance::set_current_state(const States& new_state)
register_write(Registers::TRX_STATE, std::uint8_t(new_state));
m_wait_can_transition();
SKULLC_LOG_DEBUG("HW: New state. %d -> %d.", m_current_state, new_state);
m_current_state = new_state;
return true;
}