Add messages to operation endpoint

This commit is contained in:
Bartosz Wieczorek 2025-05-28 10:52:40 +02:00
parent 207501a894
commit a9b36770dc
7 changed files with 511 additions and 103 deletions

View File

@ -13,6 +13,11 @@ enum Error {
NoError = 0;
UsedPowerChannelNotActive = 1;
MaxNumberOfChannels = 2;
ControlChannelUsedMultipleTimes = 3;
ChannelNotFound = 4;
ControlChannelDisabled = 5;
ModeDoesNotHandleTargetTemperatureMessage = 6;
UnknownError = 32;
}
@ -36,6 +41,31 @@ enum Mode {
// AutoTune = 7;
}
message ConstantTemperatureConfig
{
// What temperature source we need to talk to
uint32 temperature_channel_id = 1;
}
message TemperatureSlopeConfig
{
// What temperature source we need to talk to
uint32 temperature_channel_id = 1;
// Desired temperature slope in °C per minute
// defaults to 1°C per minute
float slope = 2;
}
message ModeConfig
{
oneof config
{
ConstantTemperatureConfig constant_temperature = 1;
TemperatureSlopeConfig temperature_slope = 2;
}
}
message ActiveChannelsRequest
{
}
@ -84,17 +114,35 @@ message DeinitializeChannelResponse
optional Error error = 254;
}
// read or change the current mode in which the controller works
message ModeRequest
{
// The ID of the operation channel
uint32 channel_id = 1; // one of
// The ID of the operation channel, this channel needs to be activated beforehand
uint32 channel_id = 1;
optional Mode mode = 2;
// optional configuration for selected mode, value ignored when mode is not set
optional ModeConfig mode_config = 3;
}
message ModeResponse
{
uint32 channel_id = 1;
Mode mode = 2;
ModeConfig mode_config = 3;
optional Error error = 254;
}
message TargetTemperatureRequest
{
uint32 channel_id = 1;
optional float target_temperature = 2;
}
message TargetTemperatureResponse
{
uint32 channel_id = 1;
optional float target_temperature = 2;
optional Error error = 254;
}
@ -114,6 +162,7 @@ message IngressMessage
DeinitializeChannelRequest deinitialize_channel_request = 3;
ModeRequest mode_request = 4;
TargetTemperatureRequest target_temperature_request = 5;
}
};
@ -127,5 +176,6 @@ message EgressMessage
DeinitializeChannelResponse deinitialize_channel_response = 3;
ModeResponse mode_response = 4;
TargetTemperatureResponse target_temperature_response = 5;
}
};

View File

@ -32,7 +32,7 @@ extern "C" unsigned int sleep(unsigned int seconds) {
using namespace rims;
static K_THREAD_STACK_DEFINE(k_messengerStack, 1500);
static K_THREAD_STACK_DEFINE(k_messengerStack, 2000);
TStack messengerStack{k_messengerStack, K_THREAD_STACK_SIZEOF(k_messengerStack)};
static K_THREAD_STACK_DEFINE(k_uartStack, 1300);

View File

@ -1,9 +1,17 @@
#include "operation.hpp"
#include "inplace_vector.hpp"
#include "log.hpp"
#include "operation_pb_helpers.hpp"
#include "messenger.hpp"
#include "pid.hpp"
#include "proto/ctrl.pb.h"
#include "proto/operation.pb.h"
#include "zephyr.hpp"
#include <algorithm>
#include <chrono>
#include <cstdint>
#include <exception>
#include <span>
#include <thread>
#include <variant>
namespace rims {
@ -18,6 +26,29 @@ struct error : std::exception {
}
};
struct max_number_of_channels : error {
max_number_of_channels() : error{op_Error_MaxNumberOfChannels} {
}
};
struct channel_used_multiple_times : error {
channel_used_multiple_times() : error{op_Error_ControlChannelUsedMultipleTimes} {
}
};
struct channel_not_found : error {
channel_not_found() : error{op_Error_ChannelNotFound} {
}
};
struct control_channel_disabled : error {
control_channel_disabled() : error{op_Error_ControlChannelDisabled} {
}
};
struct mode_does_not_accept_target_temperature : error {
mode_does_not_accept_target_temperature() : error{op_Error_ModeDoesNotHandleTargetTemperatureMessage} {
}
};
} // namespace op
K_FIFO_DEFINE(operationIngress);
@ -28,20 +59,21 @@ fifo_queue<op_EgressMessage, 2> operationEgressQueue{operationEggress};
constexpr auto op_factory = handler_factory<op_IngressMessage, op_EgressMessage, op::error>{};
constexpr auto op_modeHandler = op_factory.make_handler<op_ModeRequest, &OperationOrchestrator::handler_modeRequest>();
constexpr std::array<handler, 5> op_handlers = {
op_factory.make_handler<op_ActiveChannelsRequest, &OperationOrchestrator::handle_activeChannelsRequest>(),
op_factory.make_handler<op_InitializeChannelRequest, &OperationOrchestrator::handle_initializeChannelRequest>(),
op_factory.make_handler<op_DeinitializeChannelRequest, &OperationOrchestrator::handle_deinitializeChannelRequest>(),
op_factory.make_handler<op_ModeRequest, &OperationOrchestrator::handle_modeRequest>(),
op_factory.make_handler<op_TargetTemperatureRequest, &OperationOrchestrator::handle_targetTemperatureRequest>(),
};
OperationOrchestrator::OperationOrchestrator()
: //
_mode{DisabledMode{}, DisabledMode{}}, _pc{} {
OperationOrchestrator::OperationOrchestrator() {
ULOG_DEBUG("OperationOrchestrator start");
_tickTimer.start();
zephyr::event_pool::k_init(_events[0], _tickSem);
operationIngressQueue.k_event_init(_events[1]);
/// TODO change
setMode(0, op_Mode::op_Mode_ConstantTemperature);
_tickTimer.start();
}
void OperationOrchestrator::loop() {
@ -60,10 +92,10 @@ void OperationOrchestrator::loop() {
void OperationOrchestrator::event_tick() {
zephyr::semaphore::k_sem_take_now(_tickSem);
ULOG_INFO("PID update thread");
std::get<ConstantTemperatureMode>(_mode[0]).update();
for (auto &channel : _channels) {
channel.update();
}
}
void OperationOrchestrator::event_operationMessageArrived() {
@ -71,16 +103,70 @@ void OperationOrchestrator::event_operationMessageArrived() {
ULOG_INFO("operation request message handler");
operationEgressQueue.try_produce([&](op_EgressMessage &resp) {
ULOG_INFO("operation response message handler");
op_modeHandler.execute(this, req, resp);
for (const auto &handler : op_handlers) {
if (handler.execute(this, req, resp)) break;
}
return true;
});
});
}
void OperationOrchestrator::handler_modeRequest(const ModeRequest &request, ModeResponse &resp) {
void OperationOrchestrator::handle_activeChannelsRequest(const ActiveChannelsRequest &req, ActiveChannelsResponse &resp) const {
ULOG_INFO("active channels request handler");
resp.channels_count = _channels.size();
for (auto i = 0; i < resp.channels_count; i++) {
resp.channels[i] = _channels.at(i).id();
}
}
void OperationOrchestrator::handle_initializeChannelRequest(const InitializeChannelRequest &req, InitializeChannelResponse &resp) {
ULOG_INFO("channel init request handler");
if (_channels.full()) throw op::max_number_of_channels{};
for (auto i = 0; i < req.ctrl_channels_count; i++) {
const auto ch = req.ctrl_channels[i];
for (const auto &opchannel : _channels) {
if (opchannel.usesControlChannel(ch)) {
throw op::channel_used_multiple_times{};
}
}
}
beman::inplace_vector<uint8_t, sizeof(InitializeChannelRequest::ctrl_channels)> channels;
for (auto i = 0; i < req.ctrl_channels_count; i++) {
channels.push_back(req.ctrl_channels[i]);
}
auto find_id = [&]() {
for (uint8_t id = 0; id < 255; ++id) {
bool used = std::any_of(_channels.begin(), _channels.end(), [id](const OperationChannel &ch) { return ch.id() == id; });
if (!used) return id;
}
throw op::max_number_of_channels{};
};
_channels.emplace_back(std::span{channels.begin(), channels.end()}, find_id());
}
void OperationOrchestrator::handle_deinitializeChannelRequest(const DeinitializeChannelRequest &req, DeinitializeChannelResponse &resp) {
auto found = std::find_if(_channels.begin(), _channels.end(), [&](const OperationChannel &ch) { return ch.id() == req.channel_id; });
if (found == _channels.end()) {
ULOG_WARNING("channel %d not found", req.channel_id);
throw op::channel_not_found{};
}
resp.channel_id = found->id();
resp.ctrl_channel_ids_count = found->copyControlChannels(resp.ctrl_channel_ids);
_channels.erase(found);
}
void OperationOrchestrator::handle_modeRequest(const ModeRequest &request, ModeResponse &resp) {
ULOG_INFO("mode request handler");
/// TODO
// checkChannel(request.channel_id);
if (not channelExists(request.channel_id)) throw op::channel_not_found{};
if (request.has_mode) {
setMode(request.channel_id, request.mode);
}
@ -88,60 +174,200 @@ void OperationOrchestrator::handler_modeRequest(const ModeRequest &request, Mode
resp.mode = mode(request.channel_id);
}
TemperatureSlopeMode::TemperatureSlopeMode(PowerControl &pc, PIDController &pid, const op_TemperatureSlopeConfig &config)
: _powerControl{pc}, _pid{pid}, _tempChannel{static_cast<uint8_t>(config.temperature_channel_id)}, _slope{config.slope} {
}
void TemperatureSlopeMode::update() {
float currentTemperature = temp(_tempChannel);
// Use simple hysteresis to reduce mode-switch jitter
constexpr float hysteresis = 0.25f;
const bool closeToSetpoint = std::abs(targetTemperature() - currentTemperature) <= hysteresis;
auto useConstantTemperatureAlg = [&]() {
if (_heating) {
_pid.get().reset();
_heating = false;
}
const float outputPower = _pid.get().update(targetTemperature(), currentTemperature);
_powerControl.get().setPower(outputPower);
};
auto useConstantSlope = [&]() {
if (!_heating) {
_pid.get().reset();
_heating = true;
}
const float dt = 1.0f; // 1s guaranteed by RTOS
const float dT = currentTemperature - _lastTemperature;
const float measuredSlope = (dT / dt) * 60.0f; // °C/min
const float outputPower = _pid.get().update(_slope, measuredSlope);
_powerControl.get().setPower(outputPower);
};
if (closeToSetpoint) {
useConstantTemperatureAlg();
} else {
useConstantSlope();
}
_lastTemperature = currentTemperature;
}
ConstantTemperatureMode::ConstantTemperatureMode(PowerControl &pc, PIDController &pid, const op_ConstantTemperatureConfig &config)
: _powerControl{pc}, _pid{pid}, _tempChannel{static_cast<uint8_t>(config.temperature_channel_id)} {
gpio_GpioRequest gpio = gpio_GpioRequest_init_zero;
gpio.gpio = gpio_GPIO_GPIO_pin_2;
gpio.has_state = false;
auto resp = MessengerThread::ipc_request(gpio);
if (resp->state != true) {
gpio.has_state = true;
gpio.state = true;
MessengerThread::ipc_request(gpio);
ULOG_INFO("Pump turned on");
std::this_thread::sleep_for(std::chrono::seconds{1});
}
}
void ConstantTemperatureMode::update() {
auto currentTemperature = temp(_tempChannel);
float outputPower = _pid.get().update(targetTemperature(), currentTemperature);
_powerControl.get().setPower(outputPower);
}
template <typename T>
concept HasSetTargetTemperature = requires(T t, float temp) {
{ t.setTargetTemperature(temp) } -> std::same_as<void>;
};
template <typename T>
concept HasTargetTemperature = requires(T t) {
{ t.targetTemperature() } -> std::convertible_to<float>;
};
void OperationOrchestrator::handle_targetTemperatureRequest(const TargetTemperatureRequest &req, TargetTemperatureResponse &resp) {
ULOG_INFO("target temperature request handler");
if (not channelExists(req.channel_id)) throw op::channel_not_found{};
find(req.channel_id).handle_targetTemperatureRequest(req, resp);
}
void OperationChannel::handle_targetTemperatureRequest(const TargetTemperatureRequest &req, TargetTemperatureResponse &resp) {
ULOG_INFO("target temperature request handler");
if (req.has_target_temperature) {
std::visit(
[&](auto &obj) {
if constexpr (HasSetTargetTemperature<decltype(obj)>) {
obj.setTargetTemperature(req.target_temperature);
} else {
throw op::mode_does_not_accept_target_temperature{};
}
},
_mode
);
}
resp.has_target_temperature = true;
resp.target_temperature = std::visit(
[&](auto &obj) -> float {
if constexpr (HasTargetTemperature<decltype(obj)>) {
return obj.targetTemperature();
} else {
throw op::mode_does_not_accept_target_temperature{};
}
},
_mode
);
}
void OperationOrchestrator::setMode(uint8_t ch, op_Mode mode) {
ULOG_INFO("channel %d mode change to %d", ch, mode);
/// TODO check channel
if (not channelExists(ch)) throw op::channel_not_found{};
}
void OperationChannel::setMode(Mode mode, const std::optional<op_ModeConfig> &config) {
switch (mode) {
case op_Mode_Disabled:
_mode.at(ch).emplace<DisabledMode>();
case op_Mode_Disabled: {
_mode.emplace<DisabledMode>();
break;
case op_Mode_ConstantTemperature:
_mode.at(ch).emplace<ConstantTemperatureMode>(_pc, _pid);
}
case op_Mode_ConstantTemperature: {
constexpr auto defaultConfig = op_ModeConfig{
.which_config = op_ModeConfig_constant_temperature_tag, //
.config = {.constant_temperature = {op_ConstantTemperatureConfig{.temperature_channel_id = 0}}}
};
_mode.emplace<ConstantTemperatureMode>(_pc, _pid, config.value_or(defaultConfig).config.constant_temperature);
break;
case op_Mode_TemperatureSlope:
_mode.at(ch).emplace<TemperatureSlopeMode>();
}
case op_Mode_TemperatureSlope: {
constexpr auto defaultConfig = op_ModeConfig{
.which_config = op_ModeConfig_temperature_slope_tag, //
.config = {.temperature_slope = {op_TemperatureSlopeConfig{.temperature_channel_id = 0, .slope = 1.0f}}}
};
_mode.emplace<TemperatureSlopeMode>(_pc, _pid, config.value_or(defaultConfig).config.temperature_slope);
break;
}
default:
break;
}
}
op_Mode OperationOrchestrator::mode(uint8_t ch) const noexcept {
/// TODO check channel
if (std::holds_alternative<ConstantTemperatureMode>(_mode.at(ch))) {
if (not channelExists(ch)) return op_Mode_Disabled;
else return find(ch).mode();
}
Mode OperationChannel::mode() const noexcept {
if (std::holds_alternative<ConstantTemperatureMode>(_mode)) {
return op_Mode_ConstantTemperature;
}
if (std::holds_alternative<TemperatureSlopeMode>(_mode.at(ch))) {
if (std::holds_alternative<TemperatureSlopeMode>(_mode)) {
return op_Mode_TemperatureSlope;
}
return op_Mode_Disabled;
}
bool OperationOrchestrator::channelExists(uint8_t ch) const {
auto found = std::find_if(_channels.begin(), _channels.end(), [&](const OperationChannel &opch) { return opch.id() == ch; });
return found != _channels.end();
}
void OperationThread::threadMain() {
ULOG_DEBUG("OperationThread start");
OperationOrchestrator thread{};
thread.loop();
}
PowerControl::PowerControl() {
PowerControl::PowerControl(std::span<uint8_t> channels) : _control_channels{channels.begin(), channels.end()} {
ULOG_DEBUG("PowerControl start");
ctrl_PowerControlAlgorithmRequest plar = ctrl_PowerControlAlgorithmRequest_init_zero;
plar.alg = ctrl_PowerControlAlgorithm::ctrl_PowerControlAlgorithm_GroupModulation;
plar.has_alg = true;
plar.channel_id = 0;
MessengerThread::ipc_request(plar);
for (const auto ch : _control_channels) {
ctrl_PowerControlAlgorithmRequest plar = ctrl_PowerControlAlgorithmRequest_init_zero;
plar.channel_id = ch;
auto resp = MessengerThread::ipc_request(plar);
plar.channel_id = 1;
MessengerThread::ipc_request(plar);
if (not resp.has_value()) {
ULOG_ERROR("Something went really bad ;( during PowerControlAlgorithm check");
throw op::error{};
}
gpio_GpioRequest gpio = gpio_GpioRequest_init_zero;
gpio.gpio = gpio_GPIO_GPIO_pin_2;
gpio.has_state = true;
gpio.state = false;
MessengerThread::ipc_request(gpio);
ULOG_INFO("GPIO SET");
if (resp->has_error) {
ULOG_WARNING("ctrl returned error:%d", resp->error);
throw op::error{};
}
if (resp->alg == ctrl_PowerControlAlgorithm_NoModulation) {
ULOG_WARNING("ctrl channel %d disabled", resp->channel_id);
throw op::control_channel_disabled{};
}
}
}
void PowerControl::setPower(float percent) {

View File

@ -4,13 +4,19 @@
#include "common.hpp"
#include "fifo_queue.hpp"
#include "inplace_vector.hpp"
#include "log.hpp"
#include "messenger.hpp"
#include "operation_pb_helpers.hpp"
#include "pid.hpp"
#include "proto/operation.pb.h"
#include <algorithm>
#include <array>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <span>
#include <variant>
namespace rims {
@ -21,77 +27,185 @@ namespace rims {
extern fifo_queue<op_IngressMessage, 2> operationIngressQueue;
extern fifo_queue<op_EgressMessage, 2> operationEgressQueue;
using ModeRequest = op_ModeRequest;
using ModeResponse = op_ModeResponse;
using Mode = op_Mode;
using ActiveChannelsRequest = op_ActiveChannelsRequest;
using ActiveChannelsResponse = op_ActiveChannelsResponse;
using InitializeChannelRequest = op_InitializeChannelRequest;
using InitializeChannelResponse = op_InitializeChannelResponse;
using DeinitializeChannelRequest = op_DeinitializeChannelRequest;
using DeinitializeChannelResponse = op_DeinitializeChannelResponse;
using ModeRequest = op_ModeRequest;
using ModeResponse = op_ModeResponse;
using TargetTemperatureRequest = op_TargetTemperatureRequest;
using TargetTemperatureResponse = op_TargetTemperatureResponse;
class ModeStrategy {
public:
ModeStrategy() {
}
void setTargetTemperature(float temp) {
_setpoint = temp;
}
float targetTemperature() const {
return _setpoint;
}
float temp(uint8_t ch) const {
temperature_GetTemperatureRequest req = {};
req.channel_id = ch;
auto response = MessengerThread::ipc_request(req);
if (response.has_value()) {
if (response.has_value() and not response->has_error) {
return response.value().temperature_current.temp_c;
}
ULOG_WARNING("GotTemp ch:%d, error", ch);
return 0; /// TODO better error handling?
return 0;
}
virtual ~ModeStrategy() {
virtual ~ModeStrategy(){
/// todo set channel power to 0 at exit
};
private:
float _setpoint{30};
};
class PowerControl {
public:
PowerControl();
PowerControl(std::span<uint8_t> channels);
void setPower(float percent);
};
class DisabledMode : public ModeStrategy {};
class ConstantTemperatureMode : public ModeStrategy {
public:
ConstantTemperatureMode(PowerControl &pc, PIDController &pid) : _powerControl{pc}, _pid{pid} {
/// TODO check power control algorithm, should not be disabled
/// TODO check pump GPIO state, should be enabled
bool usesChannel(uint8_t ch) const {
return std::find(_control_channels.begin(), _control_channels.end(), ch) != _control_channels.end();
}
void update() {
auto currentTemperature = temp(0);
float outputPower = _pid.update(_setpoint, currentTemperature);
_powerControl.setPower(outputPower);
int copyControlChannels(uint32_t *ch) const {
for (std::size_t i = 0; i < _control_channels.size(); i++) {
ch[i] = _control_channels.at(i);
}
return _control_channels.size();
}
private:
float _setpoint{30};
PowerControl &_powerControl;
PIDController &_pid;
beman::inplace_vector<uint8_t, 16> _control_channels;
};
class TemperatureSlopeMode : public ModeStrategy {};
class DisabledMode : public ModeStrategy {
public:
void update() {
}
};
class ConstantTemperatureMode : public ModeStrategy {
public:
ConstantTemperatureMode(PowerControl &pc, PIDController &pid, const op_ConstantTemperatureConfig &config);
// Disallow copy
ConstantTemperatureMode(const ConstantTemperatureMode &) = delete;
ConstantTemperatureMode &operator=(const ConstantTemperatureMode &) = delete;
// Allow move
ConstantTemperatureMode(ConstantTemperatureMode &&) = default;
ConstantTemperatureMode &operator=(ConstantTemperatureMode &&) = default;
void update();
private:
/// reference wrapper allows this class to be movable
std::reference_wrapper<PowerControl> _powerControl;
std::reference_wrapper<PIDController> _pid;
uint8_t _tempChannel;
};
class TemperatureSlopeMode : public ModeStrategy {
public:
TemperatureSlopeMode(PowerControl &pc, PIDController &pid, const op_TemperatureSlopeConfig &config);
// Disallow copy
TemperatureSlopeMode(const TemperatureSlopeMode &) = delete;
TemperatureSlopeMode &operator=(const TemperatureSlopeMode &) = delete;
// Allow move
TemperatureSlopeMode(TemperatureSlopeMode &&) = default;
TemperatureSlopeMode &operator=(TemperatureSlopeMode &&) = default;
void update();
private:
/// reference wrapper allows this class to be movable
float _lastTemperature;
std::reference_wrapper<PowerControl> _powerControl;
std::reference_wrapper<PIDController> _pid;
uint8_t _tempChannel{0};
float _slope{1.0f};
bool _heating{false};
};
/*
* global operation of the device, it listens to temperature changes, and listens to user requests
* This class represents a 'virtual' channel,
*/
class OperationOrchestrator {
using Mode = std::variant< //
class OperationChannel {
using WorkMode = std::variant< //
DisabledMode,
ConstantTemperatureMode,
TemperatureSlopeMode>;
public:
void setMode(Mode mode, const std::optional<op_ModeConfig> &config);
Mode mode() const noexcept;
public:
OperationChannel(std::span<uint8_t> control_channels, uint8_t id) : _pc{control_channels}, _ownId{id} {
}
// Disallow copy
OperationChannel(const OperationChannel &) = delete;
OperationChannel &operator=(const OperationChannel &) = delete;
// Allow move
OperationChannel(OperationChannel &&) = default;
OperationChannel &operator=(OperationChannel &&) = default;
bool usesControlChannel(uint8_t ch) const {
return _pc.usesChannel(ch);
}
int copyControlChannels(uint32_t *ch) const {
return _pc.copyControlChannels(ch);
}
uint8_t id() const {
return _ownId;
}
void update() {
std::visit([](auto &mode) { mode.update(); }, _mode);
}
void handle_targetTemperatureRequest(const TargetTemperatureRequest &request, TargetTemperatureResponse &resp);
private:
WorkMode _mode;
PIDController _pid{2.0f, 0.5f, 0.1f, 1.0f};
PowerControl _pc;
uint8_t _ownId;
};
/*
* global operation of the device, it listens to temperature changes, and listens to user requests
*/
class OperationOrchestrator {
public:
OperationOrchestrator();
void loop();
void handler_modeRequest(const ModeRequest &request, ModeResponse &resp);
void handle_activeChannelsRequest(const ActiveChannelsRequest &req, ActiveChannelsResponse &resp) const;
void handle_initializeChannelRequest(const InitializeChannelRequest &req, InitializeChannelResponse &resp);
void handle_deinitializeChannelRequest(const DeinitializeChannelRequest &req, DeinitializeChannelResponse &resp);
void handle_modeRequest(const ModeRequest &request, ModeResponse &resp);
void handle_targetTemperatureRequest(const TargetTemperatureRequest &request, TargetTemperatureResponse &resp);
private:
void event_tick();
@ -100,20 +214,28 @@ class OperationOrchestrator {
void setMode(uint8_t ch, op_Mode mode);
op_Mode mode(uint8_t ch) const noexcept;
std::array<Mode, 2> _mode; /// TODO set maximum number of channels to max channels
bool channelExists(uint8_t ch) const;
OperationChannel &find(uint8_t ch) {
auto found = std::find_if(_channels.begin(), _channels.end(), [&](const OperationChannel &opch) { return opch.id() == ch; });
return *found;
}
const OperationChannel &find(uint8_t ch) const {
auto found = std::find_if(_channels.begin(), _channels.end(), [&](const OperationChannel &opch) { return opch.id() == ch; });
return *found;
}
std::array<k_poll_event, 2> _events;
zephyr::semaphore::sem _tickSem{0, 1};
RecurringSemaphoreTimer _tickTimer{_tickSem, std::chrono::seconds{1}};
/// TODO This should go to a separate class, one for each controlled channel
PIDController _pid{2.0f, 0.5f, 0.1f, 1.0f};
PowerControl _pc;
beman::inplace_vector<OperationChannel, 2> _channels; /// only 2 channels supported ATM
};
class OperationThread : public ZephyrThread {
public:
OperationThread(TStackBase &stack) : ZephyrThread(stack, 5, 0, "Operation") {};
OperationThread(TStackBase &stack) : ZephyrThread(stack, 5, 0, "Operation"){};
void threadMain() override;
};

View File

@ -6,61 +6,71 @@
namespace rims {
template <> constexpr int tag<op_ModeRequest>() {
return op_IngressMessage_mode_request_tag;
template <> constexpr int tag<op_ActiveChannelsRequest>() {
return op_IngressMessage_active_channels_request_tag;
}
template <> constexpr int tag<op_InitializeChannelRequest>() {
return op_IngressMessage_initialize_channel_request_tag;
}
template <> constexpr int tag<op_ActiveChannelsRequest>() {
return op_IngressMessage_active_channels_request_tag;
}
template <> constexpr int tag<op_DeinitializeChannelRequest>() {
return op_IngressMessage_deinitialize_channel_request_tag;
}
template <> constexpr int tag<op_ModeRequest>() {
return op_IngressMessage_mode_request_tag;
}
template <> constexpr int tag<op_TargetTemperatureRequest>() {
return op_IngressMessage_target_temperature_request_tag;
}
template <> constexpr int tag<op_ModeResponse>() {
return op_EgressMessage_mode_response_tag;
template <> constexpr int tag<op_ActiveChannelsResponse>() {
return op_EgressMessage_active_channels_response_tag;
}
template <> constexpr int tag<op_InitializeChannelResponse>() {
return op_EgressMessage_initialize_channel_response_tag;
}
template <> constexpr int tag<op_ActiveChannelsResponse>() {
return op_EgressMessage_active_channels_response_tag;
}
template <> constexpr int tag<op_DeinitializeChannelResponse>() {
return op_EgressMessage_deinitialize_channel_response_tag;
}
template <> constexpr int tag<op_ModeResponse>() {
return op_EgressMessage_mode_response_tag;
}
template <> constexpr int tag<op_TargetTemperatureResponse>() {
return op_EgressMessage_target_temperature_response_tag;
}
// Ingress and egress message categorization for operation package
template <typename MsgT>
constexpr bool is_op_ingress_msg_v = is_any_of_v<
MsgT, //
op_ModeRequest,
op_InitializeChannelRequest,
op_ActiveChannelsRequest,
op_DeinitializeChannelRequest>;
op_InitializeChannelRequest,
op_DeinitializeChannelRequest,
op_ModeRequest,
op_TargetTemperatureRequest>;
template <typename MsgT>
constexpr bool is_op_egress_msg_v = is_any_of_v<
MsgT, //
op_ModeResponse,
op_InitializeChannelResponse,
op_ActiveChannelsResponse,
op_DeinitializeChannelResponse>;
op_InitializeChannelResponse,
op_DeinitializeChannelResponse,
op_ModeResponse,
op_TargetTemperatureResponse>;
// ResponseSelector specializations
template <> struct ResponseSelector<op_ModeRequest> {
using response_t = op_ModeResponse;
template <> struct ResponseSelector<op_ActiveChannelsRequest> {
using response_t = op_ActiveChannelsResponse;
};
template <> struct ResponseSelector<op_InitializeChannelRequest> {
using response_t = op_InitializeChannelResponse;
};
template <> struct ResponseSelector<op_ActiveChannelsRequest> {
using response_t = op_ActiveChannelsResponse;
};
template <> struct ResponseSelector<op_DeinitializeChannelRequest> {
using response_t = op_DeinitializeChannelResponse;
};
template <> struct ResponseSelector<op_ModeRequest> {
using response_t = op_ModeResponse;
};
template <> struct ResponseSelector<op_TargetTemperatureRequest> {
using response_t = op_TargetTemperatureResponse;
};
} // namespace rims

View File

@ -52,7 +52,7 @@ fifo_queue<temperature_EgressMessage, 2> temperatureEgressQueue{temperatureEggr
constexpr auto temperature_factory = handler_factory<temperature_IngressMessage, temperature_EgressMessage, temp::error>{};
constexpr std::array<handler, 5> temp_modeHandlers = {
constexpr std::array<handler, 5> temp_handlers = {
temperature_factory.make_handler<GetTemperatureRequest, &TemperatureSamplerOrchestrator::handle_getTemperatureRequest>(),
temperature_factory.make_handler<GetActiveChannelsRequest, &TemperatureSamplerOrchestrator::handle_activeChannelsRequest>(),
temperature_factory.make_handler<SamplerConfigRequest, &TemperatureSamplerOrchestrator::handle_samplerConfigRequest>(),
@ -110,7 +110,7 @@ TemperatureSampler::TemperatureSampler(uint8_t channel) : _temperature{0.05}, _c
void TemperatureSampler::calibration() {
/// ~1ms
constexpr auto stabilizationTime = std::chrono::microseconds{2000};
constexpr auto stabilizationTime = std::chrono::microseconds{1000};
ULOG_TRACE("cas ch:%d start", _channel);
select_rmin();
@ -339,7 +339,7 @@ void TemperatureSamplerOrchestrator::event_messageArrived() {
ULOG_DEBUG("Producing temperature_EgressMessage response");
auto ok = temperatureIngressQueue.try_consume([&](temperature_IngressMessage &req) {
ULOG_DEBUG("Consuming temperature_IngressMessage request");
for (const auto &handler : temp_modeHandlers) {
for (const auto &handler : temp_handlers) {
if (handler.execute(this, req, resp)) break;
}
});

View File

@ -19,8 +19,8 @@ class uart_rx_buffer_overflow;
class uart_rx_not_ready_error;
class AsyncUART {
using rx_buffer_t = beman::inplace_vector<uint8_t, 256>;
using tx_buffer_t = RingBuffer<uint8_t, 256>;
using rx_buffer_t = beman::inplace_vector<uint8_t, 250>;
using tx_buffer_t = RingBuffer<uint8_t, 350>;
public:
AsyncUART();