Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sensor ctrl2 #309

Closed
wants to merge 86 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
848fe86
copy from old branch
jbbjarnason Oct 13, 2023
02eabfa
wip adding explicit discharge timer
jbbjarnason Oct 15, 2023
ff2fa04
pivot point, test another dependency injection technique
jbbjarnason Oct 16, 2023
e3f2492
state machine tests doing good things
jbbjarnason Oct 16, 2023
30ccb64
simplifications
jbbjarnason Oct 16, 2023
55f3107
format
jbbjarnason Oct 16, 2023
bfb6e83
add todo
jbbjarnason Oct 16, 2023
edd937d
add todo
jbbjarnason Oct 16, 2023
b5ea6cd
run speed in config
jbbjarnason Oct 16, 2023
10bf140
make sonar happy
jbbjarnason Oct 16, 2023
80e4984
Committing clang-format changes
jbbjarnason Oct 16, 2023
7251809
stop wip
jbbjarnason Oct 16, 2023
01fd02e
stop probably working, need to test and integrate to process
jbbjarnason Oct 16, 2023
fe70357
so the item of the statemachine is not stored in memory, need to reth…
jbbjarnason Oct 16, 2023
0cde401
make it compile
jbbjarnason Oct 17, 2023
ec44ac7
working on stopping mechanism
jbbjarnason Oct 18, 2023
635cdef
wip
jbbjarnason Oct 19, 2023
4c31492
history is working
jbbjarnason Oct 19, 2023
199d690
format
jbbjarnason Oct 19, 2023
82263a9
reorder
jbbjarnason Oct 19, 2023
a0c1d4c
wip
jbbjarnason Oct 19, 2023
92e7b8f
small progress
jbbjarnason Oct 20, 2023
45dbf9c
make state machine support inputting item at the same time it is outp…
jbbjarnason Oct 23, 2023
a50fef3
integrating newer impl of statemachine to business logic
jbbjarnason Oct 23, 2023
8676c80
enter_discharging_allow_input allows upstream input
jbbjarnason Oct 23, 2023
efd83a0
poll sensor slot while entering discharging state
jbbjarnason Oct 23, 2023
68a94df
enter_discharging&enter_discharging_allow_input poll if sensor is alr…
jbbjarnason Oct 23, 2023
73afdc1
timout of awaiting sensor
jbbjarnason Oct 23, 2023
96a3567
beautiful tests
jbbjarnason Oct 23, 2023
da36873
skeleton for integration tests
jbbjarnason Oct 30, 2023
5192643
finish integrating operation mode to sensor control
jbbjarnason Oct 30, 2023
8d7e710
failing test, need to finish
jbbjarnason Oct 30, 2023
e0f0e53
progress
jbbjarnason Oct 31, 2023
fd2d8e8
fix integration of dbus for sml
jbbjarnason Nov 10, 2023
9a01cda
minor fixes while manual testing
jbbjarnason Nov 10, 2023
581b191
add names to events and format
jbbjarnason Nov 10, 2023
da393c6
run motor the first time it is started, from start of process
jbbjarnason Nov 10, 2023
22443dc
add devcontainer and stuff
jbbjarnason Nov 10, 2023
bcf1cbd
remove queued item on sensor timeout
jbbjarnason Nov 15, 2023
c1107d7
forgot to set discharge active output
jbbjarnason Nov 15, 2023
3a23734
run on discharge config flag
jbbjarnason Nov 16, 2023
e0b8a69
add op enable executable
jbbjarnason Nov 16, 2023
9c383c2
using dbus system bus
jbbjarnason Nov 16, 2023
3cd5b46
fix includes
jbbjarnason Nov 17, 2023
f83a970
separate sm state for uncontrolled discharge
jbbjarnason Nov 17, 2023
0d89f21
format
jbbjarnason Nov 17, 2023
fb47bf0
poll sensor in various places
jbbjarnason Nov 20, 2023
1a2ebfa
add idle signal
jbbjarnason Nov 20, 2023
0872fb0
add todos
jbbjarnason Nov 20, 2023
c38793d
first time handling
jbbjarnason Nov 20, 2023
f131ba3
start to divert
jbbjarnason Nov 20, 2023
a66d8b3
Creating the base for track control
jbbjarnason Nov 20, 2023
13745df
fix after rebase
jbbjarnason Nov 20, 2023
b3f8e4c
this is getting big
jbbjarnason Nov 20, 2023
dd2232a
hmm I would like this getting going faster
jbbjarnason Nov 21, 2023
0fc0ffa
missing config param in glaze
jbbjarnason Nov 21, 2023
536d900
add initial state
magni-mar Nov 21, 2023
f1b7020
get name used
jbbjarnason Nov 21, 2023
2deb610
queue one item more
jbbjarnason Nov 21, 2023
08c8068
implement simple and logic gate
jbbjarnason Nov 21, 2023
9042518
may discharge new state filter
jbbjarnason Nov 21, 2023
00a6359
Revert "may discharge new state filter"
jbbjarnason Nov 22, 2023
1350a76
pulse discharge allowance
jbbjarnason Nov 22, 2023
bf22a4a
minor compilation errors
jbbjarnason Nov 22, 2023
95f2bdc
add logging
jbbjarnason Nov 22, 2023
a52a1ba
Handle if stopping system and removing tub then start system again
jbbjarnason Nov 23, 2023
e0a3618
Reversed the logic
jbbjarnason Nov 23, 2023
067b223
propagate event when it was already in queue
jbbjarnason Nov 23, 2023
22cbe2d
hacky way to turn off discharge active
jbbjarnason Nov 23, 2023
e2ee0d5
remove superflous logging
jbbjarnason Nov 23, 2023
f93731f
discharge active is active in uncontrolled discharge
jbbjarnason Nov 23, 2023
4a49bd6
damn how did this happen
jbbjarnason Nov 23, 2023
f49b808
add minimum discharge configurable time and allow item removal config
jbbjarnason Nov 24, 2023
63fea77
small tweaks after manual testing
jbbjarnason Nov 24, 2023
78fc7b7
not allow item removal restores state to awaiting sensor
jbbjarnason Nov 24, 2023
f96a516
fix check of using discharge delay
jbbjarnason Nov 24, 2023
12494f9
fix name
jbbjarnason Nov 24, 2023
a4fbbf5
using uuid instead of boolean between sensor controls
jbbjarnason Nov 24, 2023
377cbb8
fix compile error
jbbjarnason Nov 24, 2023
4063351
incremental fixes
jbbjarnason Nov 24, 2023
de2c917
add logs
jbbjarnason Nov 24, 2023
31c3b2e
remove moving of item when entering awaiting discharge
jbbjarnason Nov 24, 2023
a9fceb0
empty uuid is not equivalent
jbbjarnason Nov 24, 2023
217d1b9
create new item if sensor is set
jbbjarnason Nov 24, 2023
a3a60ed
reset current item when leaving allow input
jbbjarnason Nov 24, 2023
c101fc6
:art: Committing clang-format changes
magni-mar Dec 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "cpp",
"containerUser": "root",
"image": "ghcr.io/skaginn3x/skaginn3x/framework/tfc-toolchain:sha-6cd5f4c"
}
6 changes: 5 additions & 1 deletion exes/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
add_subdirectory(and)
add_subdirectory(ethercat)
add_subdirectory(button)
add_subdirectory(gpio)
add_subdirectory(operations)
add_subdirectory(tfcctl)
add_subdirectory(ipc-ruler)
add_subdirectory(signal_source)
add_subdirectory(mqtt-bridge)
add_subdirectory(sensor-control)
add_subdirectory(mqtt-bridge)
add_subdirectory(op_enable)
add_subdirectory(track-control)
17 changes: 17 additions & 0 deletions exes/and/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@

add_executable(and and.cpp)

find_package(fmt CONFIG REQUIRED)
find_package(glaze CONFIG REQUIRED)

target_link_libraries(and
PUBLIC
tfc::base
tfc::ipc
tfc::confman
tfc::logger
tfc::operation_mode
fmt::fmt
glaze::glaze
)

51 changes: 51 additions & 0 deletions exes/and/and.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include <memory>

#include <boost/asio.hpp>
#include <sdbusplus/asio/connection.hpp>

#include <tfc/dbus/sd_bus.hpp>
#include <tfc/ipc.hpp>
#include <tfc/progbase.hpp>

namespace asio = boost::asio;

auto main(int argc, char const* const* const argv) -> int {
tfc::base::init(argc, argv);

asio::io_context ctx{};
auto dbus{ std::make_shared<sdbusplus::asio::connection>(ctx, tfc::dbus::sd_bus_open_system()) };
dbus->request_name(tfc::dbus::make_dbus_process_name().c_str());

bool in_1_value{ false };
bool in_2_value{ false };

tfc::ipc::signal<tfc::ipc::details::type_bool, tfc::ipc_ruler::ipc_manager_client> out{ ctx, dbus, "out",
"Output of AND gate" };

auto set_signal{ [&out, &in_1_value, &in_2_value]() {
out.async_send(in_1_value && in_2_value, [](std::error_code err, std::size_t) {
if (err) {
fmt::print("Async send error: {}", err.message());
}
});
} };

tfc::ipc::slot<tfc::ipc::details::type_bool, tfc::ipc_ruler::ipc_manager_client> in_1{
ctx, dbus, "in_1", "Input 1 of AND gate",
[&in_1_value, &set_signal]([[maybe_unused]] bool new_value) {
in_1_value = new_value;
set_signal();
}
};
tfc::ipc::slot<tfc::ipc::details::type_bool, tfc::ipc_ruler::ipc_manager_client> in_2{
ctx, dbus, "in_2", "Input 2 of AND gate",
[&in_2_value, &set_signal]([[maybe_unused]] bool new_value) {
in_2_value = new_value;
set_signal();
}
};

ctx.run();

return EXIT_SUCCESS;
}
16 changes: 16 additions & 0 deletions exes/op_enable/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

add_executable(op_enable main.cpp)

find_package(fmt CONFIG REQUIRED)
find_package(glaze CONFIG REQUIRED)

target_link_libraries(op_enable
PUBLIC
tfc::base
tfc::ipc
tfc::confman
tfc::logger
tfc::operation_mode
fmt::fmt
glaze::glaze
)
69 changes: 69 additions & 0 deletions exes/op_enable/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include <cstddef>
#include <cstdlib>
#include <memory>
#include <system_error>

#include <boost/asio.hpp>
#include <sdbusplus/asio/connection.hpp>

#include <tfc/dbus/sd_bus.hpp>
#include <tfc/dbus/string_maker.hpp>
#include <tfc/ipc.hpp>
#include <tfc/logger.hpp>
#include <tfc/operation_mode.hpp>
#include <tfc/operation_mode/common.hpp>
#include <tfc/progbase.hpp>

namespace asio = boost::asio;

auto main(int argc, char const* const* const argv) -> int {
tfc::base::init(argc, argv);

asio::io_context ctx{};
auto dbus{ std::make_shared<sdbusplus::asio::connection>(ctx, tfc::dbus::sd_bus_open_system()) };
dbus->request_name(tfc::dbus::make_dbus_process_name().c_str());
tfc::logger::logger logger{ "actuator" };
bool running{ false };

tfc::ipc::signal<tfc::ipc::details::type_bool, tfc::ipc_ruler::ipc_manager_client> sig{
ctx, dbus, "out", "Pneumatic actuator or other output to activate only while operation running"
};
tfc::ipc::slot<tfc::ipc::details::type_bool, tfc::ipc_ruler::ipc_manager_client> slot{
ctx, dbus, "in", "Sensor or other input to propagate to output while operation running",
[&running, &sig, &logger]([[maybe_unused]] bool new_value) {
if (running) {
sig.async_send(new_value, [&logger](std::error_code err, std::size_t) {
if (err) {
logger.error("Failed to send signal: {}", err.message());
}
});
}
}
};

tfc::operation::interface operations {
ctx, "operations"
};
operations.on_enter(tfc::operation::mode_e::running,
[&running, &sig, &slot, &logger](tfc::operation::mode_e, tfc::operation::mode_e) {
running = true;
sig.async_send(slot.value().value_or(false), [&logger](std::error_code err, std::size_t) {
if (err) {
logger.error("Failed to send signal: {}", err.message());
}
});
});
operations.on_leave(tfc::operation::mode_e::running,
[&running, &sig, &logger](tfc::operation::mode_e, tfc::operation::mode_e) {
running = false;
sig.async_send(false, [&logger](std::error_code err, std::size_t) {
if (err) {
logger.error("Failed to send signal: {}", err.message());
}
});
});

ctx.run();

return EXIT_SUCCESS;
}
36 changes: 36 additions & 0 deletions exes/sensor-control/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@

find_package(Boost REQUIRED)
#find_package(tfc CONFIG REQUIRED)
find_package(fmt CONFIG REQUIRED)
find_package(ut CONFIG REQUIRED)
find_package(glaze CONFIG REQUIRED)
find_path(BEXT_SML_INCLUDE_DIRS "boost/sml.hpp")

add_library(sensor_ctrl src/sensor_control.cpp)
add_library(tfc::sensor_ctrl ALIAS sensor_ctrl)
add_executable(sensor_control src/main.cpp)

target_link_libraries(sensor_ctrl
PUBLIC
tfc::base
tfc::ipc
tfc::confman
tfc::logger
tfc::operation_mode
tfc::dbus_util
Boost::boost
fmt::fmt
glaze::glaze
)
target_link_libraries(sensor_control
PUBLIC
tfc::sensor_ctrl
)

target_include_directories(sensor_ctrl
PUBLIC
${CMAKE_CURRENT_LIST_DIR}/inc
${BEXT_SML_INCLUDE_DIRS}
)

add_subdirectory(tests)
174 changes: 174 additions & 0 deletions exes/sensor-control/inc/sensor_control.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
#pragma once

#include <functional>
#include <optional>

#include <mp-units/quantity.h>
#include <mp-units/unit.h>
#include <boost/asio/steady_timer.hpp>
#include <boost/sml.hpp>

#include <tfc/dbus/sml_interface.hpp>
#include <tfc/dbus/string_maker.hpp>
#include <tfc/ipc.hpp>
#include <tfc/ipc/details/type_description.hpp>
#include <tfc/ipc/item.hpp>
#include <tfc/logger.hpp>
#include <tfc/operation_mode.hpp>
#include <tfc/utils/asio_fwd.hpp>
#include <tfc/utils/units_glaze_meta.hpp>

#include "state_machine.hpp"

namespace tfc {

namespace asio = boost::asio;

template <template <typename, typename manager_client_t = ipc_ruler::ipc_manager_client&> typename signal_t = ipc::signal,
template <typename, typename manager_client_t = ipc_ruler::ipc_manager_client&> typename slot_t = ipc::slot,
template <typename, typename...> typename sml_t = boost::sml::sm>
class sensor_control {
public:
explicit sensor_control(asio::io_context& ctx, std::string_view log_key);
explicit sensor_control(asio::io_context& ctx) : sensor_control(ctx, "sensor_control") {}

struct sensor_control_config {
std::optional<std::chrono::milliseconds> discharge_timeout{ std::nullopt };
std::chrono::milliseconds minimum_discharge_duration{ std::chrono::seconds{ 1 } };
std::chrono::milliseconds await_sensor_timeout{ std::chrono::minutes{ 1 } };
mp_units::quantity<mp_units::percent, double> run_speed{ 0.0 * mp_units::percent };
bool run_on_discharge{ true };
bool allow_item_removal{ false };
struct glaze {
using type = sensor_control_config;
static constexpr std::string_view name{ "tfc::sensor_control" };
// clang-format off
static constexpr auto value{ glz::object(
"discharge delay", &type::discharge_timeout, "Delay after falling edge of sensor to keep output of discharge active high.",
"minimum discharge duration", &type::minimum_discharge_duration, "Minumum discharge duration, set with relation to item length and conveyor speed.",
"await sensor timeout", &type::await_sensor_timeout, "Timeout for awaiting sensor input.",
"run speed", &type::run_speed, json::schema{ .description="Speed of the motor when running.", .minimum=0.0, .maximum=100.0 },
"run on discharge", &type::run_on_discharge, "Run the motor when discharging an item.",
"allow item removal", &type::allow_item_removal, "Allow removing item while awaiting discharge"
) };
// clang-format on
};
};

void enter_stopped() {}
void leave_stopped() {}
void enter_running() {}
void leave_running() {}
void enter_idle();
void leave_idle();
void enter_awaiting_discharge();
void leave_awaiting_discharge();
void enter_awaiting_sensor();
void leave_awaiting_sensor();
void enter_discharging();
void leave_discharging();
void enter_uncontrolled_discharge();
void leave_uncontrolled_discharge();
void enter_discharge_delayed();
void leave_discharge_delayed();
void enter_discharging_allow_input();
void leave_discharging_allow_input();

auto config_run_on_discharge() const noexcept -> bool { return config_.value().run_on_discharge; }

// accessors for testing purposes
[[nodiscard]] auto motor_signal() const noexcept -> auto const& { return motor_percentage_; }
[[nodiscard]] auto discharge_signal() const noexcept -> auto const& { return request_discharge_; }
[[nodiscard]] auto discharge_allowance_signal() const noexcept -> auto const& { return discharge_allowance_; }
[[nodiscard]] auto discharge_request_slot() const noexcept -> auto const& { return discharge_request_; }
[[nodiscard]] auto may_discharge_slot() const noexcept -> auto const& { return may_discharge_; }
[[nodiscard]] auto sensor_slot() const noexcept -> auto const& { return sensor_; }
[[nodiscard]] auto state_machine() const noexcept -> auto const& { return sm_; }
[[nodiscard]] auto queued_item() const noexcept -> auto const& { return queued_item_; }
[[nodiscard]] auto config() noexcept -> auto& { return config_; }

void on_sensor(bool new_value);
void on_discharge_request(std::string const& new_value);
void on_may_discharge(std::string const& new_value);
void set_queued_item(ipc::item::item&&);

void await_sensor_timer_cb(std::error_code const&);
void discharge_timer_cb(std::error_code const&);
[[nodiscard]] auto using_discharge_delay() const noexcept -> bool { return config_->discharge_timeout.has_value(); }
[[nodiscard]] auto allow_item_removal() const noexcept -> bool { return config_->allow_item_removal; }
[[nodiscard]] auto min_discharge_duration_elapsed() const noexcept -> bool { return !min_discharge_timer_is_on_; }

void on_running();
void on_running_leave();

private:
void stop_motor();
void start_motor();
void pulse_discharge_allowance(ipc::item::item& itm);
void start_min_discharge_timer();

using bool_signal_t = signal_t<ipc::details::type_bool>;
using double_signal_t = signal_t<ipc::details::type_double>;
using json_signal_t = signal_t<ipc::details::type_json>;
using string_signal_t = signal_t<ipc::details::type_string>;
using bool_slot_t = slot_t<ipc::details::type_bool>;
using json_slot_t = slot_t<ipc::details::type_json>;
using string_slot_t = slot_t<ipc::details::type_string>;

asio::io_context& ctx_;
std::string_view log_key_;
ipc_ruler::ipc_manager_client ipc_client_{ ctx_ };
bool_slot_t sensor_{ ctx_, ipc_client_, "sensor",
"Sensor input at the end of my conveyor, item will stop here and wait for discharge",
std::bind_front(&sensor_control::on_sensor, this) };
json_signal_t request_discharge_{ ctx_, ipc_client_, "request_discharge", "Ask for release of item downstream" };
json_slot_t discharge_request_{ ctx_, ipc_client_, "discharge_request", "Get discharge request from upstream",
std::bind_front(&sensor_control::on_discharge_request, this) };
bool_signal_t idle_{ ctx_, ipc_client_, "idle", "Indication of not doing anything" };
string_signal_t discharge_allowance_{ ctx_, ipc_client_, "discharge_allowance_uuid",
"Let upstream know that the uuid can discharge onto me" };
bool_signal_t discharge_active_{ ctx_, ipc_client_, "discharge_active", "Discharging item to downstream" };
string_slot_t may_discharge_{ ctx_, ipc_client_, "may_discharge_uuid", "Get acknowledgement of discharging item with uuid",
std::bind_front(&sensor_control::on_may_discharge, this) };
double_signal_t motor_percentage_{ ctx_, ipc_client_, "motor_percentage", "Motor freq output, stopped when inactive." };

std::optional<ipc::item::item> queued_item_{ std::nullopt };
std::optional<ipc::item::item> current_item_{ std::nullopt };

logger::logger logger_{ log_key_ };

using state_machine_t =
sml_t<sensor::control::state_machine_operation_mode<sensor_control>, boost::sml::logger<tfc::dbus::sml::interface>>;

std::shared_ptr<sdbusplus::asio::dbus_interface> dbus_interface_{ std::make_shared<sdbusplus::asio::dbus_interface>(
ipc_client_.connection(),
std::string{ tfc::dbus::sml::tags::path },
tfc::dbus::make_dbus_name("SensorControl")) };

dbus::sml::interface sml_interface_ {
dbus_interface_, fmt::format("sm.{}", log_key_)
};
std::shared_ptr<state_machine_t> sm_{ std::make_shared<state_machine_t>(*this, sml_interface_) };

asio::steady_timer await_sensor_timer_{ ctx_ };
asio::steady_timer min_discharge_timer_{ ctx_ };
bool min_discharge_timer_is_on_{ false };
std::optional<asio::steady_timer> discharge_timer_{ std::nullopt };

confman::config<sensor_control_config> config_{ ctx_, "sensor_control",
sensor_control_config{ .discharge_timeout = std::nullopt,
.minimum_discharge_duration =
std::chrono::seconds{ 1 },
.await_sensor_timeout = std::chrono::minutes{ 1 },
.run_speed = 100.0 * mp_units::percent,
.run_on_discharge = true,
.allow_item_removal = false } };
operation::interface operation_mode_ {
ctx_, "operation_mode"
};
bool first_time_{ true };
};

extern template class sensor_control<>;

} // namespace tfc
Loading