diff --git a/rims_app/.clang-format b/rims_app/.clang-format index 194499b1653..62cbf0fba6c 100755 --- a/rims_app/.clang-format +++ b/rims_app/.clang-format @@ -81,7 +81,7 @@ BreakBeforeTernaryOperators: true BreakConstructorInitializers: BeforeColon BreakInheritanceList: BeforeColon BreakStringLiterals: true -ColumnLimit: 140 +ColumnLimit: 16666660 CommentPragmas: '^ IWYU pragma:' CompactNamespaces: false ConstructorInitializerIndentWidth: 4 diff --git a/rims_app/src/error.hpp b/rims_app/src/error.hpp index cea5f4925b1..e676795bc11 100644 --- a/rims_app/src/error.hpp +++ b/rims_app/src/error.hpp @@ -4,6 +4,7 @@ #include "message_type_id.hpp" #include +#include #include 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 diff --git a/rims_app/src/operation.cpp b/rims_app/src/operation.cpp index 9c465f03328..03504c1419c 100644 --- a/rims_app/src/operation.cpp +++ b/rims_app/src/operation.cpp @@ -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 concept HasSetTargetTemperature = requires(T t, const op_TargetTemperature &temp) { { t.setTargetTemperature(temp) } -> std::same_as; @@ -80,11 +45,11 @@ fifo_queue operationEgressQueue{operationEggress}; constexpr auto op_factory = handler_factory{}; constexpr std::array op_handlers = { - op_factory.make_handler(), - op_factory.make_handler(), - op_factory.make_handler(), - op_factory.make_handler(), - op_factory.make_handler(), + op_factory.make_handler_expected(), + op_factory.make_handler_expected(), + op_factory.make_handler_expected(), + op_factory.make_handler_expected(), + op_factory.make_handler_expected(), }; OperationOrchestrator::OperationOrchestrator() { @@ -131,26 +96,28 @@ void OperationOrchestrator::event_operationMessageArrived() { }); } -void OperationOrchestrator::handle_activeChannelsRequest(const ActiveChannelsRequest &req, ActiveChannelsResponse &resp) const { +std::expected 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 +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 { 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 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 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 +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 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 { if constexpr (HasSetTargetTemperature) { 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> 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 channels) : _control_channels{channels.begin(), channels.end()} { - ULOG_DEBUG("PowerControl start"); - +std::expected PowerControl::check_channels(std::span _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 channels) : _control_channels{channels.begin(), channels.end()} { + ULOG_DEBUG("PowerControl start"); } void PowerControl::setPower(float percent) { diff --git a/rims_app/src/operation.hpp b/rims_app/src/operation.hpp index 73aba25df6c..ee2f3357f6c 100644 --- a/rims_app/src/operation.hpp +++ b/rims_app/src/operation.hpp @@ -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 #include #include +#include #include #include #include @@ -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 check_channels(std::span channels); PowerControl(std::span channels); void setPower(float percent); @@ -161,12 +164,27 @@ class OperationChannel { ConstantTemperatureMode, TemperatureSlopeMode>; + struct ChannelsActivated { + std::span channels; + ChannelsActivated() = delete; + explicit ChannelsActivated(std::span channels) : channels{channels} { + } + }; + public: void setMode(Mode mode, std::optional> config); Mode mode() const noexcept; public: - OperationChannel(std::span control_channels, uint8_t id) : _pc{control_channels}, _ownId{id} { + NDIS static std::expected check_channels(std::span 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 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 handle_activeChannelsRequest(const ActiveChannelsRequest &req, ActiveChannelsResponse &resp) const; + NDIS std::expected handle_initializeChannelRequest(const InitializeChannelRequest &req, InitializeChannelResponse &resp); + NDIS std::expected 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 handle_modeRequest(const ModeRequest &request, ModeResponse &resp); + NDIS std::expected 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 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 freeSlot() const { + if (_channels.full()) return std::unexpected{op::max_number_of_channels{}}; + return {}; + } + + NDIS std::expected, 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, 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; }; diff --git a/rims_app/src/zephyr.hpp b/rims_app/src/zephyr.hpp index f0b8e3c0476..cb657139e66 100644 --- a/rims_app/src/zephyr.hpp +++ b/rims_app/src/zephyr.hpp @@ -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); \