Initial implementation of app state machine

This commit is contained in:
Erki 2022-07-17 18:20:45 +03:00
parent 1c695fbaa8
commit c994e63478
4 changed files with 124 additions and 16 deletions

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,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

@ -42,21 +42,19 @@ int main()
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);
SKULLC_LOG_INFO("Millis: %u", Hal::StaticHal::getMillis());
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;
}