27 #include "hardware/GPIO_odb.h" 31 #include "modules/pifacedigital/PFGPIO_odb.h" 34 #include "pifacedigital.h" 40 #include <boost/iterator/transform_iterator.hpp> 41 #include <boost/uuid/uuid_io.hpp> 44 #include <odb/schema-catalog.hxx> 55 zmqpp::socket *module_manager_pipe,
56 const boost::property_tree::ptree &config,
58 :
BaseModule(ctx, module_manager_pipe, config, utils)
59 , bus_push_(ctx_,
zmqpp::socket_type::push)
60 , ws_helper_thread_(utils)
61 , degraded_mode_(false)
63 if (pifacedigital_open(0) == -1)
67 ERROR(
"Cannot open PifaceDigital device. Are you running on device with SPI " 68 "bus and have SPI linux kernel module enabled ?");
72 for (uint8_t hw_addr = 1; hw_addr < 4; ++hw_addr)
74 if (pifacedigital_open(hw_addr) == -1)
76 ERROR(
"Failed to initialize pifacedigital with hardware address" 81 int ret = pifacedigital_enable_interrupts();
82 ASSERT_LOG(ret == 0,
"Failed to enable interrupt on piface board");
85 bus_push_.connect(
"inproc://zmq-bus-pull");
91 std::string path_to_gpio =
92 "/sys/class/gpio/gpio" + std::to_string(GPIO_INTERRUPT_PIN) +
"/value";
93 interrupt_fd_ = open(path_to_gpio.c_str(), O_RDONLY | O_NONBLOCK);
95 pifacedigital_read_reg(0x11, 0);
100 zmqpp::poller::poll_pri | zmqpp::poller::poll_error);
116 [](
const PFDigitalPin &p) -> std::chrono::system_clock::time_point {
117 return p.next_update();
121 boost::make_transform_iterator(
gpios_.begin(), itr_transform),
122 boost::make_transform_iterator(
gpios_.end(), itr_transform));
124 for (
auto &gpio_pin :
gpios_)
126 if (gpio_pin.next_update() < std::chrono::system_clock::now())
139 std::array<char, 64> buffer{};
144 "Reading on interrupt_fd gave unexpected return value: " << ret);
147 "Lseeking on interrupt_fd gave unexpected return value: " << ret);
149 for (uint8_t hwaddr = 0; hwaddr < 4; ++hwaddr)
151 uint8_t states = pifacedigital_read_reg(0x11, hwaddr);
152 for (
int i = 0; i < 8; ++i)
154 if (((states >> i) & 0x01) == 0)
157 std::string gpio_name;
161 << std::string(
"S_INT:" + gpio_name));
170 for (
const auto &gpio :
gpios_)
173 gpio.hardware_address_ == hw_addr)
184 boost::property_tree::ptree module_config = cfg.get_child(
"module_config");
186 for (
auto &node : module_config.get_child(
"gpios"))
188 boost::property_tree::ptree gpio_cfg = node.second;
190 std::string gpio_name = gpio_cfg.get<std::string>(
"name");
191 int gpio_no = gpio_cfg.get<uint8_t>(
"no");
192 std::string gpio_direction = gpio_cfg.get<std::string>(
"direction");
193 bool gpio_value = gpio_cfg.get<
bool>(
"value",
false);
194 uint8_t hw_addr = gpio_cfg.get<uint8_t>(
"hardware_address", 0);
196 INFO(
"Creating GPIO " << gpio_name <<
", with no " << gpio_no
197 <<
". direction = " << gpio_direction
198 <<
"Hardware address: " << (
int)hw_addr);
203 gpio_value, hw_addr);
205 if (gpio_direction !=
"in" && gpio_direction !=
"out")
206 throw GpioException(
"Direction (" + gpio_direction +
") is invalid");
207 gpios_.push_back(std::move(pin));
208 utils_->config_checker().register_object(gpio_name,
215 bool use_db =
config_.get<
bool>(
"module_config.use_database",
false);
218 throw LEOSACException(
"We failed to open piface digital device and wont " 219 "enable database support. There is nothing to do but " 235 ASSERT_LOG(hwd_service,
"No hardware service but we have database.");
249 using namespace odb::core;
250 auto db =
utils_->database();
251 schema_version v = db->schema_version(
"module_pifacedigital");
252 schema_version cv(schema_catalog::current_version(*db,
"module_pifacedigital"));
255 transaction t(db->begin());
256 schema_catalog::create_schema(*db,
"module_pifacedigital");
261 INFO(
"PIFACEDIGITAL_GPIO Module performing database migration. Going from " 263 << v <<
" to version " << cv);
264 transaction t(db->begin());
265 schema_catalog::migrate(*db, cv,
"module_pifacedigital");
272 using Result = odb::result<PFGPIO>;
274 odb::transaction t(db->begin());
280 INFO(
"Not creating GPIO object because the module is running in degraded " 284 for (
const auto &gpio : result)
288 if (gpio.number() > std::numeric_limits<uint8_t>::max())
290 WARN(
"Cannot create GPIO " 292 <<
" because its number is too big: " << gpio.number());
296 INFO(
"Creating GPIO " 297 << gpio.name() <<
", with no " << gpio.number() <<
". direction = " 300 gpio.default_value(), gpio.hardware_address());
301 gpios_.push_back(std::move(pin));
302 utils_->config_checker().register_object(gpio.name(),
318 if (parameters_.degraded_mode)
320 "Cannot test Piface Digital GPIO when running in degraded mode.");
323 odb::transaction t(db->begin());
324 auto gpio = db->find<
PFGPIO>(gpio_id);
333 if (!core_utils_->config_checker().has_object(gpio->name(),
337 "",
"GPIO doesn't exist in the runtime configuration checker. " 338 "This probably means that you need to restart Leosac to load the " 339 "new configuration");
343 Hardware::FGPIO gpio_facade(core_utils_->zmqpp_context(), gpio->name());
346 for (
int i = 0; i < 8; ++i)
349 std::this_thread::sleep_for(std::chrono::milliseconds(750));
357 json j{{
"mode", mode}};
360 "pfdigital.is_degraded_mode");
362 ws_service.register_handler(
368 this->test_output_pin(gpio_id);
371 "pfdigital.test_output_pin");
void unregister_handler(const std::string &name)
Remove an handler by name.
virtual void run() override
Module's main loop.
A service object provided by the Websocket module.
bool register_handler(HandlerT &&handler, const std::string &type)
Register a handler for a websocket message.
A Facade to a GPIO object.
PFDigitalModule(zmqpp::context &ctx, zmqpp::socket *module_manager_pipe, const boost::property_tree::ptree &config, CoreUtilsPtr utils)
An exception class for general API error.
Some ~const parameter that are required to process websocket requests.
This is the header file for a generated source file, GitSHA1.cpp.
zmqpp::socket bus_push_
Socket to push event to the bus.
static json serialize(const PFGPIO &in, const SecurityContext &sc)
Piface Module GPIO descriptor.
static WebSockAPI::CRUDResourceHandlerUPtr instanciate(WebSockAPI::RequestContext)
void load_config_from_database()
ServiceRegistry & get_service_registry()
A function to retrieve the ServiceRegistry from pretty much anywhere.
CoreUtilsPtr utils_
Pointer to the core utils, which gives access to scheduler and others.
void handle_message()
The PFGpioModule will register this method so its called when a message is ready on the pin socket...
This is a implementation class.
void unregister_ws_handlers(WebSockAPI::Service &ws_service) override
WSHelperThread ws_helper_thread_
Support thread for processing websocket requests.
void start_running()
Effectively starts an helper thread and run its io_service.
bool is_running_
Boolean indicating whether the main loop should run or not.
A workaround permission that requires the user to be administrator.
Thin wrapper around boost::uuids::uuid.
Database aware Hardware Service.
#define LEOSAC_ENFORCE(cond,...)
Similar to enforce, except that it will throw a LEOSACException.
Base class for module implementation.
zmqpp::context & ctx_
A reference to the ZeroMQ context in case you need it to create additional socket.
Provides various database-related services to consumer.
Exception class for Gpio related errors.
#define ASSERT_LOG(cond, msg)
Provide ODB magic to be able to store an Leosac::Audit::EventType (FlagSet) object.
std::vector< PFDigitalPin > gpios_
GPIO vector.
void register_ws_handlers(WebSockAPI::Service &ws_service) override
Called when websocket handler registration is possible.
zmqpp::reactor reactor_
The reactor object we poll() on in the main loop.
void test_output_pin(const UUID &gpio_id)
Implements the "pfdigital.test_output_pin" API call.
std::shared_ptr< ServiceInterface > get_service() const
Retrieve the service instance implementing the ServiceInterface, or nullptr if no such service was re...
const ClientMessage & original_msg
The original, complete, client message object.
void process_xml_config(const boost::property_tree::ptree &cfg)
Process the XML configuration, preparing configured GPIO pin.
void handle_interrupt()
An interrupt was triggered.
A base class for Leosac specific exception.
std::shared_ptr< CoreUtils > CoreUtilsPtr
SecurityContext & security_ctx
bool toggle()
Toggle the GPIO value by sending a message to the backend GPIO impl.
odb::result< Tools::LogEntry > Result
boost::property_tree::ptree config_
The configuration tree passed to the start_module function.
bool degraded_mode_
True if we are running in "degraded" mode (ie, not on a device that support the PifaceDigital).
Holds valuable pointer to provide context to a request.
void enforce_permission(Action a, const ActionParam &ap) const
Similar to check_permission(), but throws is the permission is denied.
std::shared_ptr< odb::database > DBPtr
void setup_database()
Create / update database schema for the module.
bool get_input_pin_name(std::string &dest, int idx, uint8_t hw_addr)
Retrieve the (user-given) name of the pin and store it in dest.
void set_parameter(const ParameterT &p)
int interrupt_fd_
File descriptor of the PIN that triggers interrupts.
void unregister_serializer()
void process_config()
Process configuration.