Leosac  0.8.0
Open Source Access Control
LibgpiodPin.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014-2022 Leosac
3 
4  This file is part of Leosac.
5 
6  Leosac is free software: you can redistribute it and/or modify
7  it under the terms of the GNU Affero General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  Leosac is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU Affero General Public License for more details.
15 
16  You should have received a copy of the GNU Affero General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include "LibgpiodPin.hpp"
21 #include <fcntl.h>
22 #include <tools/log.hpp>
23 #include <unistd.h>
24 
25 using namespace Leosac::Module::Libgpiod;
26 
27 LibgpiodPin::LibgpiodPin(zmqpp::context &ctx, const std::string &name, const std::string &gpio_device,
28  int gpio_offset, Direction direction, InterruptMode interrupt_mode,
29  bool initial_value, LibgpiodModule &module)
30  : sock_(ctx, zmqpp::socket_type::rep)
31  , name_(name)
32  , gpio_device_(gpio_device)
33  , gpio_offset_(gpio_offset)
34  , direction_(direction)
35  , initial_value_(initial_value)
36  , module_(module)
37  , next_update_time_(std::chrono::system_clock::time_point::max())
38  , gpiod_chip_(nullptr)
39  , gpiod_line_(nullptr)
40  , gpiod_fd_(-1)
41 {
42  sock_.bind("inproc://" + name);
43 
44  gpiod_chip_ = gpiod_chip_open_lookup(gpio_device_.c_str());
45  assert(gpiod_chip_ != nullptr);
46 
47  gpiod_line_ = gpiod_chip_get_line(gpiod_chip_, gpio_offset_);
48  assert(gpiod_line_ != nullptr);
49 
50  set_direction(direction);
51  set_interrupt(interrupt_mode);
52 }
53 
55 {
56  release();
57 }
58 
60 {
61  if (gpiod_line_ != nullptr)
62  {
63  gpiod_line_release(gpiod_line_);
64  }
65  if (gpiod_chip_ != nullptr)
66  {
67  gpiod_chip_close(gpiod_chip_);
68  }
69 }
70 
72 {
73  if (dir == Direction::In)
74  {
75  gpiod_line_request_input(gpiod_line_, module_.general_config()->consumer().c_str());
76  }
77  else
78  {
79  gpiod_line_request_output(gpiod_line_, module_.general_config()->consumer().c_str(), initial_value_);
80  }
81 }
82 
84 {
85  int ret;
87  ret = 0;
88  else if (mode == LibgpiodPin::InterruptMode::Both)
89  ret = gpiod_line_request_both_edges_events(gpiod_line_, module_.general_config()->consumer().c_str());
90  else if (mode == LibgpiodPin::InterruptMode::Falling)
91  ret = gpiod_line_request_falling_edge_events(gpiod_line_, module_.general_config()->consumer().c_str());
92  else if (mode == LibgpiodPin::InterruptMode::Rising)
93  ret = gpiod_line_request_rising_edge_events(gpiod_line_, module_.general_config()->consumer().c_str());
94  else
95  assert(0);
96 
97  ASSERT_LOG(ret >= 0, "Toggle failed on GPIO pin.");
98 }
99 
101 {
102  zmqpp::message_t msg;
103  std::string frame1;
104  sock_.receive(msg);
105 
106  msg >> frame1;
107  bool ok = false;
108  if (frame1 == "ON")
109  ok = turn_on(&msg);
110  else if (frame1 == "OFF")
111  ok = turn_off();
112  else if (frame1 == "TOGGLE")
113  ok = toggle();
114  sock_.send(ok ? "OK" : "KO");
115 
116  // publish new state.
117  module_.publish_on_bus(zmqpp::message() << ("S_" + name_)
118  << (read_value() ? "ON" : "OFF"));
119 }
120 
121 bool LibgpiodPin::turn_on(zmqpp::message *msg /* = nullptr */)
122 {
123  if (msg && msg->remaining() == 1)
124  {
125  // ASSERT_LOG(msg->parts() == 2 && msg->remaining() == 1, "Invalid internal
126  // message.");
127  // optional parameter is present
128  int64_t duration;
129  *msg >> duration;
131  std::chrono::system_clock::now() + std::chrono::milliseconds(duration);
132  }
133  else if (msg)
134  {
135  WARN("Called with unexpected number of arguments: " << msg->remaining());
136  }
137 
138  int ret = gpiod_line_set_value(gpiod_line_, 1);
139  return (ret == 1);
140 }
141 
143 {
144  int ret = gpiod_line_set_value(gpiod_line_, 0);
145  return (ret == 1);
146 }
147 
149 {
150  int ret = gpiod_line_set_value(gpiod_line_, read_value() ? 1 : 0);
151  ASSERT_LOG(ret >= 0, "Toggle failed on GPIO pin.");
152  return (ret == 1);
153 }
154 
156 {
157  int ret = gpiod_line_get_value(gpiod_line_);
158  ASSERT_LOG(ret >= 0, "Read failed on GPIO pin.");
159  return (ret == 1);
160 }
161 
163 {
164  gpiod_line_event gpiod_event;
165  int ret = gpiod_line_event_read_fd(gpiod_fd_, &gpiod_event);
166  ASSERT_LOG(ret >= 0, "Read failed on GPIO pin.");
167 
168  module_.publish_on_bus(zmqpp::message() << "S_INT:" + name_);
169 }
170 
171 void LibgpiodPin::register_sockets(zmqpp::reactor *reactor)
172 {
173  reactor->add(sock_, std::bind(&LibgpiodPin::handle_message, this));
174  if (direction_ == Direction::In)
175  {
176  gpiod_fd_ = gpiod_line_event_get_fd(gpiod_line_);
177  ASSERT_LOG(gpiod_fd_ >= 0, "Bad GPIO line or the line is not setup for event monitoring.");
178  reactor->add(gpiod_fd_, std::bind(&LibgpiodPin::handle_interrupt, this),
179  zmqpp::poller::poll_pri);
180  }
181 }
182 
183 std::chrono::system_clock::time_point LibgpiodPin::next_update() const
184 {
185  return next_update_time_;
186 }
187 
189 {
190  DEBUG("Turning off Libgpiod pin.");
191  turn_off();
192  next_update_time_ = std::chrono::system_clock::time_point::max();
193 }
Leosac::Module::Libgpiod::LibgpiodPin::set_direction
void set_direction(Direction dir)
Write direction to the direction file.
Definition: LibgpiodPin.cpp:71
Leosac::Module::Libgpiod::LibgpiodPin::handle_message
void handle_message()
The SysFsGpioModule will register this method so its called when a message is ready on the pin socket...
Definition: LibgpiodPin.cpp:100
WARN
@ WARN
Definition: log.hpp:33
zmqpp
Definition: CoreUtils.hpp:27
Leosac::Module::Libgpiod::LibgpiodPin::module_
LibgpiodModule & module_
Reference to the module.
Definition: LibgpiodPin.hpp:166
Leosac::Module::Libgpiod::LibgpiodPin::gpiod_fd_
int gpiod_fd_
Definition: LibgpiodPin.hpp:177
DEBUG
@ DEBUG
Definition: log.hpp:35
Leosac::Module::Libgpiod::LibgpiodPin::update
void update()
Update the PIN.
Definition: LibgpiodPin.cpp:188
ASSERT_LOG
#define ASSERT_LOG(cond, msg)
Definition: log.hpp:190
Leosac::Module::Libgpiod::LibgpiodPin::next_update
std::chrono::system_clock::time_point next_update() const
This method shall returns the time point at which we want to be updated.
Definition: LibgpiodPin.cpp:183
Leosac::Module::Libgpiod::LibgpiodPin::gpiod_line_
gpiod_line * gpiod_line_
Definition: LibgpiodPin.hpp:175
Leosac::Module::Libgpiod::LibgpiodPin::InterruptMode::None
@ None
Leosac::Module::Libgpiod::LibgpiodPin::release
void release()
Release Libgpiod resources.
Definition: LibgpiodPin.cpp:59
Leosac::Module::Libgpiod::LibgpiodModule::publish_on_bus
void publish_on_bus(zmqpp::message &msg)
Write the message eon the bus.
Definition: LibgpiodModule.cpp:116
Leosac::Module::Libgpiod::LibgpiodPin::turn_on
bool turn_on(zmqpp::message *msg=nullptr)
Write to sysfs to turn the gpio on.
Definition: LibgpiodPin.cpp:121
Leosac::Module::Libgpiod::LibgpiodModule
Handle GPIO management over libgpiod.
Definition: LibgpiodModule.hpp:49
Leosac::Module::Libgpiod::LibgpiodPin::toggle
bool toggle()
Read to sysfs and then write the opposite value.
Definition: LibgpiodPin.cpp:148
Leosac::Module::Libgpiod::LibgpiodPin::InterruptMode::Both
@ Both
Leosac::Module::Libgpiod::LibgpiodModule::general_config
std::shared_ptr< LibgpiodConfig > general_config() const
Retrieve the config object.
Definition: LibgpiodModule.cpp:127
Leosac::Hardware::GPIO::Direction
Direction
Definition: GPIO.hpp:44
Leosac::Module::Libgpiod::LibgpiodPin::next_update_time_
std::chrono::system_clock::time_point next_update_time_
Time point of next wished update.
Definition: LibgpiodPin.hpp:171
Leosac::Module::Libgpiod
Namespace for the module that implements GPIO support using the Linux Kernel libgpiod interface.
Definition: LibgpiodConfig.hpp:32
Leosac::Module::Libgpiod::LibgpiodPin::set_interrupt
void set_interrupt(InterruptMode mode)
Write interrupt mode to the edge file.
Definition: LibgpiodPin.cpp:83
Leosac::Module::Libgpiod::LibgpiodPin::LibgpiodPin
LibgpiodPin(zmqpp::context &ctx, const std::string &name, const std::string &gpio_device, int gpio_offset, Direction direction, InterruptMode interrupt_mode, bool initial_value, LibgpiodModule &module)
Definition: LibgpiodPin.cpp:27
Leosac::Module::Libgpiod::LibgpiodPin::InterruptMode::Falling
@ Falling
Leosac::Module::Libgpiod::LibgpiodPin::handle_interrupt
void handle_interrupt()
Interrupt happened for this GPIO ping.
Definition: LibgpiodPin.cpp:162
Leosac::Module::Libgpiod::LibgpiodPin::InterruptMode
InterruptMode
Definition: LibgpiodPin.hpp:47
Leosac::Module::Libgpiod::LibgpiodPin::~LibgpiodPin
~LibgpiodPin()
Definition: LibgpiodPin.cpp:54
Leosac::Module::Libgpiod::LibgpiodPin::gpiod_chip_
gpiod_chip * gpiod_chip_
Definition: LibgpiodPin.hpp:173
LibgpiodPin.hpp
Leosac::Module::Libgpiod::LibgpiodPin::InterruptMode::Rising
@ Rising
Leosac::Hardware::GPIO::Direction::In
@ In
log.hpp
Leosac::Module::Libgpiod::LibgpiodPin::register_sockets
void register_sockets(zmqpp::reactor *reactor)
Register own socket to the module's reactor.
Definition: LibgpiodPin.cpp:171
Leosac::Module::Libgpiod::LibgpiodPin::direction_
const Direction direction_
Direction of the PIN.
Definition: LibgpiodPin.hpp:156
Leosac::Module::Libgpiod::LibgpiodPin::turn_off
bool turn_off()
Write to sysfs to turn the gpio on.
Definition: LibgpiodPin.cpp:142
Leosac::Module::Libgpiod::LibgpiodPin::gpio_offset_
int gpio_offset_
Offset of the GPIO.
Definition: LibgpiodPin.hpp:151
Leosac::Module::Libgpiod::LibgpiodPin::gpio_device_
std::string gpio_device_
File descriptor of the GPIO in sysfs.
Definition: LibgpiodPin.hpp:146
Leosac::Module::Libgpiod::LibgpiodPin::read_value
bool read_value()
Read value from filesystem.
Definition: LibgpiodPin.cpp:155
Leosac::Module::Libgpiod::LibgpiodPin::name_
std::string name_
Definition: LibgpiodPin.hpp:141
Leosac::Module::Libgpiod::LibgpiodPin::initial_value_
const bool initial_value_
Initial value of the PIN.
Definition: LibgpiodPin.hpp:161
Leosac::Module::Libgpiod::LibgpiodPin::sock_
zmqpp::socket sock_
listen to command from other component.
Definition: LibgpiodPin.hpp:139