remove exceptions from operation subsystem
This commit is contained in:
parent
df5458a43a
commit
1fa8cd8e47
@ -81,7 +81,7 @@ BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 140
|
||||
ColumnLimit: 16666660
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
#include "message_type_id.hpp"
|
||||
#include <proto/gpio.pb.h>
|
||||
#include <proto/operation.pb.h>
|
||||
#include <proto/temperature.pb.h>
|
||||
|
||||
struct Error {
|
||||
@ -35,18 +36,26 @@ ERR(wouldblock, EWOULDBLOCK);
|
||||
|
||||
} // namespace zephyr::gpio
|
||||
|
||||
|
||||
namespace rims::gpio {
|
||||
ERR_CATEGORY(rims_gpio, gpio_receiver_tag);
|
||||
ERR(bad_id, gpio_Error_BadId);
|
||||
ERR(ioerror, gpio_Error_BadId);
|
||||
} // namespace rims::gpio
|
||||
|
||||
namespace rims::temperature{
|
||||
namespace rims::temperature {
|
||||
ERR_CATEGORY(rims_temperature, temperature_receiver_tag);
|
||||
ERR(unknownChannel, temperature_Error_UnknownChannel);
|
||||
ERR(sensorDisconnected, temperature_Error_TemperatureSensorDisconnected);
|
||||
ERR(sensorBroken, temperature_Error_TemperatureSensorBroken);
|
||||
ERR(hwError, 100);
|
||||
ERR(calibrationError, 101);
|
||||
}
|
||||
} // namespace rims::temperature
|
||||
|
||||
namespace rims::op {
|
||||
ERR_CATEGORY(rims_op, operation_receiver_tag);
|
||||
ERR(max_number_of_channels, op_Error_MaxNumberOfChannels);
|
||||
ERR(channel_used_multiple_times, op_Error_ControlChannelUsedMultipleTimes);
|
||||
ERR(channel_not_found, op_Error_ChannelNotFound);
|
||||
ERR(control_channel_disabled, op_Error_ControlChannelDisabled);
|
||||
ERR(mode_does_not_accept_target_temperature, op_Error_ModeDoesNotHandleTargetTemperatureMessage);
|
||||
} // namespace rims::op
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#include "operation.hpp"
|
||||
#include "common.hpp"
|
||||
#include "error.hpp"
|
||||
#include "inplace_vector.hpp"
|
||||
#include "log.hpp"
|
||||
#include "messenger.hpp"
|
||||
@ -18,42 +19,6 @@
|
||||
|
||||
namespace rims {
|
||||
|
||||
namespace op {
|
||||
|
||||
struct error : std::exception {
|
||||
op_Error _err;
|
||||
error() : _err{op_Error_UnknownError} {
|
||||
}
|
||||
error(op_Error e) : _err{e} {
|
||||
}
|
||||
};
|
||||
|
||||
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
|
||||
|
||||
template <typename T>
|
||||
concept HasSetTargetTemperature = requires(T t, const op_TargetTemperature &temp) {
|
||||
{ t.setTargetTemperature(temp) } -> std::same_as<void>;
|
||||
@ -80,11 +45,11 @@ fifo_queue<op_EgressMessage, 2> operationEgressQueue{operationEggress};
|
||||
constexpr auto op_factory = handler_factory<op_IngressMessage, op_EgressMessage, op::error>{};
|
||||
|
||||
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>(),
|
||||
op_factory.make_handler_expected<op_ActiveChannelsRequest, &OperationOrchestrator::handle_activeChannelsRequest>(),
|
||||
op_factory.make_handler_expected<op_InitializeChannelRequest, &OperationOrchestrator::handle_initializeChannelRequest>(),
|
||||
op_factory.make_handler_expected<op_DeinitializeChannelRequest, &OperationOrchestrator::handle_deinitializeChannelRequest>(),
|
||||
op_factory.make_handler_expected<op_ModeRequest, &OperationOrchestrator::handle_modeRequest>(),
|
||||
op_factory.make_handler_expected<op_TargetTemperatureRequest, &OperationOrchestrator::handle_targetTemperatureRequest>(),
|
||||
};
|
||||
|
||||
OperationOrchestrator::OperationOrchestrator() {
|
||||
@ -131,26 +96,28 @@ void OperationOrchestrator::event_operationMessageArrived() {
|
||||
});
|
||||
}
|
||||
|
||||
void OperationOrchestrator::handle_activeChannelsRequest(const ActiveChannelsRequest &req, ActiveChannelsResponse &resp) const {
|
||||
std::expected<void, op::error> OperationOrchestrator::handle_activeChannelsRequest(const ActiveChannelsRequest &req, ActiveChannelsResponse &resp) const {
|
||||
ULOG_INFO("active channels request handler");
|
||||
resp.data_count = _channels.size();
|
||||
for (auto i = 0; i < resp.data_count; i++) {
|
||||
resp.data[i].channel = _channels.at(i).id();
|
||||
resp.data[i].ctrl_channel_ids_count = _channels.at(i).copyControlChannels(resp.data[i].ctrl_channel_ids);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void OperationOrchestrator::handle_initializeChannelRequest(const InitializeChannelRequest &req, InitializeChannelResponse &resp) {
|
||||
std::expected<void, op::error>
|
||||
OperationOrchestrator::handle_initializeChannelRequest(const InitializeChannelRequest &req, InitializeChannelResponse &resp) {
|
||||
ULOG_INFO("channel init request handler");
|
||||
|
||||
if (_channels.full()) throw op::max_number_of_channels{};
|
||||
|
||||
CHECK(freeSlot());
|
||||
|
||||
// check if any of needed channels are already controlld by somebody else
|
||||
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{};
|
||||
return std::unexpected{op::channel_used_multiple_times{}};
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -160,42 +127,48 @@ void OperationOrchestrator::handle_initializeChannelRequest(const InitializeChan
|
||||
channels.push_back(req.ctrl_channels[i]);
|
||||
}
|
||||
|
||||
auto find_id = [&]() {
|
||||
auto find_id = [&]() -> std::expected<uint8_t, op::error> {
|
||||
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{};
|
||||
return std::unexpected{op::max_number_of_channels{}};
|
||||
};
|
||||
|
||||
// create OperationChannel for channels and id
|
||||
const auto &newChannel = _channels.emplace_back(std::span{channels.begin(), channels.end()}, find_id());
|
||||
auto activatedChannels = TRY(OperationChannel::check_channels(std::span{channels}));
|
||||
auto id = TRY(find_id());
|
||||
const auto &newChannel = _channels.emplace_back(activatedChannels, id);
|
||||
|
||||
|
||||
resp.has_data = true;
|
||||
resp.data.channel = newChannel.id();
|
||||
resp.data.ctrl_channel_ids_count = newChannel.copyControlChannels(resp.data.ctrl_channel_ids);
|
||||
return {};
|
||||
}
|
||||
|
||||
void OperationOrchestrator::handle_deinitializeChannelRequest(const DeinitializeChannelRequest &req, DeinitializeChannelResponse &resp) {
|
||||
std::expected<void, op::error> 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{};
|
||||
return std::unexpected{ op::channel_not_found{}};
|
||||
}
|
||||
|
||||
_channels.erase(found);
|
||||
return {};
|
||||
}
|
||||
|
||||
void OperationOrchestrator::handle_modeRequest(const ModeRequest &request, ModeResponse &resp) {
|
||||
std::expected<void, op::error> OperationOrchestrator::handle_modeRequest(const ModeRequest &request, ModeResponse &resp) {
|
||||
ULOG_INFO("mode request handler");
|
||||
if (not channelExists(request.channel_id)) throw op::channel_not_found{};
|
||||
CHECK(channelValid(request.channel_id));
|
||||
|
||||
if (request.has_data) {
|
||||
setMode(request.channel_id, request.data);
|
||||
}
|
||||
|
||||
resp.data.mode = mode(request.channel_id);
|
||||
return{};
|
||||
}
|
||||
|
||||
TemperatureSlopeMode::TemperatureSlopeMode(PowerControl &pc, PIDController &pid, const op_TemperatureSlopeConfig &config)
|
||||
@ -265,25 +238,28 @@ void ConstantTemperatureMode::update() {
|
||||
_powerControl.get().setPower(outputPower);
|
||||
}
|
||||
|
||||
void OperationOrchestrator::handle_targetTemperatureRequest(const TargetTemperatureRequest &req, TargetTemperatureResponse &resp) {
|
||||
std::expected<void, op::error>
|
||||
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);
|
||||
CHECK(channelValid(req.channel_id));
|
||||
CHECK(TRY(find(req.channel_id)).get().handle_targetTemperatureRequest(req, resp));
|
||||
return {};
|
||||
}
|
||||
|
||||
void OperationChannel::handle_targetTemperatureRequest(const TargetTemperatureRequest &req, TargetTemperatureResponse &resp) {
|
||||
std::expected<void, op::error> OperationChannel::handle_targetTemperatureRequest(const TargetTemperatureRequest &req, TargetTemperatureResponse &resp) {
|
||||
ULOG_INFO("target temperature request handler");
|
||||
if (req.has_target_temperature) {
|
||||
std::visit(
|
||||
[&](auto &obj) {
|
||||
CHECK(std::visit(
|
||||
[&](auto &obj) -> std::expected<void, op::error> {
|
||||
if constexpr (HasSetTargetTemperature<decltype(obj)>) {
|
||||
obj.setTargetTemperature(req.target_temperature);
|
||||
return {};
|
||||
} else {
|
||||
throw op::mode_does_not_accept_target_temperature{};
|
||||
return std::unexpected{op::mode_does_not_accept_target_temperature{}};
|
||||
}
|
||||
},
|
||||
_mode
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
std::visit(
|
||||
@ -297,10 +273,11 @@ void OperationChannel::handle_targetTemperatureRequest(const TargetTemperatureRe
|
||||
},
|
||||
_mode
|
||||
);
|
||||
return {};
|
||||
}
|
||||
|
||||
void OperationOrchestrator::setMode(uint8_t ch, const op_ModeData &data) {
|
||||
if (not channelExists(ch)) throw op::channel_not_found{};
|
||||
CHECK_ASSERT(channelValid(ch));
|
||||
|
||||
ULOG_INFO("channel %d mode change to %d", ch, data.mode);
|
||||
_channels.at(ch).setMode(data.mode, optcref(data.has_mode_config, data.mode_config));
|
||||
@ -336,8 +313,9 @@ void OperationChannel::setMode(Mode mode, std::optional<cref<op_ModeConfig>> con
|
||||
}
|
||||
|
||||
op_Mode OperationOrchestrator::mode(uint8_t ch) const noexcept {
|
||||
if (not channelExists(ch)) return op_Mode_Disabled;
|
||||
else return find(ch).mode();
|
||||
/// TODO should return some other status on disabled channel
|
||||
if (not channelValid(ch)) return op_Mode_Disabled;
|
||||
else return find(ch).value().get().mode();
|
||||
}
|
||||
|
||||
Mode OperationChannel::mode() const noexcept {
|
||||
@ -351,40 +329,30 @@ Mode OperationChannel::mode() const noexcept {
|
||||
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(std::span<uint8_t> channels) : _control_channels{channels.begin(), channels.end()} {
|
||||
ULOG_DEBUG("PowerControl start");
|
||||
|
||||
std::expected<void, op::error> PowerControl::check_channels(std::span<uint8_t> _control_channels) {
|
||||
for (const auto ch : _control_channels) {
|
||||
ctrl_PowerControlAlgorithmRequest plar = ctrl_PowerControlAlgorithmRequest_init_zero;
|
||||
plar.channel_id = ch;
|
||||
auto resp = MessengerThread::ipc_request(plar);
|
||||
|
||||
if (not resp.has_value()) {
|
||||
ULOG_ERROR("Something went really bad ;( during PowerControlAlgorithm check");
|
||||
throw op::error{};
|
||||
}
|
||||
|
||||
if (resp->has_error) {
|
||||
ULOG_WARNING("ctrl returned error:%d", resp->error);
|
||||
throw op::error{};
|
||||
}
|
||||
|
||||
assert(resp.has_value()); // internal error, should not occour ever
|
||||
|
||||
if (resp->data.alg == ctrl_PowerControlAlgorithm_NoModulation) {
|
||||
ULOG_WARNING("ctrl channel %d disabled", ch);
|
||||
throw op::control_channel_disabled{};
|
||||
return std::unexpected{op::control_channel_disabled{}};
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
PowerControl::PowerControl(std::span<uint8_t> channels) : _control_channels{channels.begin(), channels.end()} {
|
||||
ULOG_DEBUG("PowerControl start");
|
||||
}
|
||||
|
||||
void PowerControl::setPower(float percent) {
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
/* Kernel event for notifying other threads */
|
||||
#include "common.hpp"
|
||||
#include "error.hpp"
|
||||
#include "fifo_queue.hpp"
|
||||
|
||||
#include "inplace_vector.hpp"
|
||||
@ -15,6 +16,7 @@
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <expected>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
@ -70,7 +72,7 @@ class ModeStrategy {
|
||||
return {};
|
||||
}
|
||||
|
||||
virtual ~ModeStrategy() {
|
||||
virtual ~ModeStrategy(){
|
||||
/// todo set channel power to 0 at exit
|
||||
};
|
||||
|
||||
@ -80,6 +82,7 @@ class ModeStrategy {
|
||||
|
||||
class PowerControl {
|
||||
public:
|
||||
static std::expected<void, op::error> check_channels(std::span<uint8_t> channels);
|
||||
PowerControl(std::span<uint8_t> channels);
|
||||
|
||||
void setPower(float percent);
|
||||
@ -161,12 +164,27 @@ class OperationChannel {
|
||||
ConstantTemperatureMode,
|
||||
TemperatureSlopeMode>;
|
||||
|
||||
struct ChannelsActivated {
|
||||
std::span<uint8_t> channels;
|
||||
ChannelsActivated() = delete;
|
||||
explicit ChannelsActivated(std::span<uint8_t> channels) : channels{channels} {
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
void setMode(Mode mode, std::optional<cref<op_ModeConfig>> config);
|
||||
Mode mode() const noexcept;
|
||||
|
||||
public:
|
||||
OperationChannel(std::span<uint8_t> control_channels, uint8_t id) : _pc{control_channels}, _ownId{id} {
|
||||
NDIS static std::expected<ChannelsActivated, op::error> check_channels(std::span<uint8_t> channels) noexcept {
|
||||
if (auto status = PowerControl::check_channels(channels); status.has_value()) {
|
||||
return ChannelsActivated{channels};
|
||||
} else {
|
||||
return std::unexpected{status.error()};
|
||||
}
|
||||
}
|
||||
|
||||
OperationChannel(ChannelsActivated control_channels, uint8_t id) : _pc{control_channels.channels}, _ownId{id} {
|
||||
}
|
||||
~OperationChannel() {
|
||||
}
|
||||
@ -193,7 +211,7 @@ class OperationChannel {
|
||||
std::visit([](auto &mode) { mode.update(); }, _mode);
|
||||
}
|
||||
|
||||
void handle_targetTemperatureRequest(const TargetTemperatureRequest &request, TargetTemperatureResponse &resp);
|
||||
NDIS std::expected<void, op::error> handle_targetTemperatureRequest(const TargetTemperatureRequest &request, TargetTemperatureResponse &resp);
|
||||
|
||||
private:
|
||||
WorkMode _mode;
|
||||
@ -211,12 +229,12 @@ class OperationOrchestrator {
|
||||
OperationOrchestrator();
|
||||
void loop();
|
||||
|
||||
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);
|
||||
NDIS std::expected<void, op::error> handle_activeChannelsRequest(const ActiveChannelsRequest &req, ActiveChannelsResponse &resp) const;
|
||||
NDIS std::expected<void, op::error> handle_initializeChannelRequest(const InitializeChannelRequest &req, InitializeChannelResponse &resp);
|
||||
NDIS std::expected<void, op::error> handle_deinitializeChannelRequest(const DeinitializeChannelRequest &req, DeinitializeChannelResponse &resp);
|
||||
|
||||
void handle_modeRequest(const ModeRequest &request, ModeResponse &resp);
|
||||
void handle_targetTemperatureRequest(const TargetTemperatureRequest &request, TargetTemperatureResponse &resp);
|
||||
NDIS std::expected<void, op::error> handle_modeRequest(const ModeRequest &request, ModeResponse &resp);
|
||||
NDIS std::expected<void, op::error> handle_targetTemperatureRequest(const TargetTemperatureRequest &request, TargetTemperatureResponse &resp);
|
||||
|
||||
private:
|
||||
void event_tick();
|
||||
@ -225,14 +243,33 @@ class OperationOrchestrator {
|
||||
void setMode(uint8_t ch, const op_ModeData &mode);
|
||||
op_Mode mode(uint8_t ch) const noexcept;
|
||||
|
||||
bool channelExists(uint8_t ch) const;
|
||||
|
||||
OperationChannel &find(uint8_t ch) {
|
||||
NDIS std::expected<void, op::error> channelValid(uint8_t ch) const {
|
||||
auto found = std::find_if(_channels.begin(), _channels.end(), [&](const OperationChannel &opch) { return opch.id() == ch; });
|
||||
if (found != _channels.end()) return std::unexpected{op::channel_not_found{}};
|
||||
return {};
|
||||
}
|
||||
|
||||
NDIS std::expected<void, op::error> freeSlot() const {
|
||||
if (_channels.full()) return std::unexpected{op::max_number_of_channels{}};
|
||||
return {};
|
||||
}
|
||||
|
||||
NDIS std::expected<std::reference_wrapper<OperationChannel>, op::error> find(uint8_t ch) {
|
||||
auto found = std::find_if(_channels.begin(), _channels.end(), [&](const OperationChannel &opch) { return opch.id() == ch; });
|
||||
|
||||
if (found == _channels.end()) {
|
||||
return std::unexpected{op::channel_not_found{}};
|
||||
}
|
||||
|
||||
return *found;
|
||||
}
|
||||
const OperationChannel &find(uint8_t ch) const {
|
||||
NDIS std::expected<std::reference_wrapper<const OperationChannel>, op::error> find(uint8_t ch) const {
|
||||
auto found = std::find_if(_channels.begin(), _channels.end(), [&](const OperationChannel &opch) { return opch.id() == ch; });
|
||||
|
||||
if (found == _channels.end()) {
|
||||
return std::unexpected{op::channel_not_found{}};
|
||||
}
|
||||
|
||||
return *found;
|
||||
}
|
||||
|
||||
@ -246,7 +283,7 @@ class OperationOrchestrator {
|
||||
|
||||
class OperationThread : public ZephyrThread {
|
||||
public:
|
||||
OperationThread(TStackBase &stack) : ZephyrThread(stack, 5, 0, "Operation") {};
|
||||
OperationThread(TStackBase &stack) : ZephyrThread(stack, 5, 0, "Operation"){};
|
||||
|
||||
void threadMain() override;
|
||||
};
|
||||
|
||||
@ -19,6 +19,8 @@
|
||||
#error "Unsupported compiler: TRY macro only supported for GCC and Clang"
|
||||
#endif
|
||||
|
||||
#define NDIS [[nodiscard]]
|
||||
|
||||
#define TRY(failable) \
|
||||
({ \
|
||||
auto result = (failable); \
|
||||
|
||||
Loading…
Reference in New Issue
Block a user