Leosac  0.8.0
Open Source Access Control
SysFSGPIOPin.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014-2016 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 "SysFSGPIOPin.hpp"
21 #include "tools/unixfs.hpp"
22 #include <fcntl.h>
23 #include <tools/log.hpp>
24 #include <unistd.h>
25 
26 using namespace Leosac::Module::SysFsGpio;
28 
29 SysFsGpioPin::SysFsGpioPin(zmqpp::context &ctx, const std::string &name, int gpio_no,
30  Direction direction, InterruptMode interrupt_mode,
31  bool initial_value, SysFsGpioModule &module)
32  : gpio_no_(gpio_no)
33  , sock_(ctx, zmqpp::socket_type::rep)
34  , name_(name)
35  , direction_(direction)
36  , initial_value_(initial_value)
37  , module_(module)
38  , path_cfg_(module.general_config())
39  , next_update_time_(std::chrono::system_clock::time_point::max())
40 {
41  sock_.bind("inproc://" + name);
42 
43  set_direction(direction);
44  set_interrupt(interrupt_mode);
45  std::string full_path = path_cfg_.value_path(gpio_no);
46 
47  if (direction == Direction::Out)
48  {
49  if (initial_value_)
50  turn_on();
51  else
52  turn_off();
53  }
54 
55  file_fd_ = open(full_path.c_str(), O_RDONLY | O_NONBLOCK);
56  assert(file_fd_ != -1);
57 }
58 
60 {
62  {
63  try
64  {
65  if (initial_value_)
66  turn_on();
67  else
68  turn_off();
69  }
70  catch(FsException &e)
71  {
72  ERROR("Error while resetting gpio state: " << e.what());
73  }
74  }
75 
76  if (file_fd_ != -1 && ::close(file_fd_) != 0)
77  {
78  ERROR("fail to close fd " << file_fd_);
79  }
80  try
81  {
82  UnixFs::writeSysFsValue(module_.general_config().unexport_path(), gpio_no_);
83  }
84  catch (FsException &e)
85  {
86  ERROR("Error while unexporting GPIO: " << e.what());
87  }
88 }
89 
91 {
92  std::string direction = dir == Direction::In ? "in" : "out";
93  UnixFs::writeSysFsValue(path_cfg_.direction_path(gpio_no_), direction);
94 }
95 
97 {
98  std::string value;
100  value = "none";
101  else if (mode == SysFsGpioPin::InterruptMode::Both)
102  value = "both";
103  else if (mode == SysFsGpioPin::InterruptMode::Falling)
104  value = "falling";
105  else if (mode == SysFsGpioPin::InterruptMode::Rising)
106  value = "rising";
107  else
108  assert(0);
109  UnixFs::writeSysFsValue(path_cfg_.edge_path(gpio_no_), value);
110 }
111 
113 {
114  zmqpp::message_t msg;
115  std::string frame1;
116  sock_.receive(msg);
117 
118  msg >> frame1;
119  bool ok = false;
120  if (frame1 == "ON")
121  ok = turn_on(&msg);
122  else if (frame1 == "OFF")
123  ok = turn_off();
124  else if (frame1 == "TOGGLE")
125  ok = toggle();
126  sock_.send(ok ? "OK" : "KO");
127 
128  // publish new state.
129  module_.publish_on_bus(zmqpp::message() << ("S_" + name_)
130  << (read_value() ? "ON" : "OFF"));
131 }
132 
133 bool SysFsGpioPin::turn_on(zmqpp::message *msg /* = nullptr */)
134 {
135  if (msg && msg->remaining() == 1)
136  {
137  // ASSERT_LOG(msg->parts() == 2 && msg->remaining() == 1, "Invalid internal
138  // message.");
139  // optional parameter is present
140  int64_t duration;
141  *msg >> duration;
143  std::chrono::system_clock::now() + std::chrono::milliseconds(duration);
144  }
145  else if (msg)
146  {
147  WARN("Called with unexpected number of arguments: " << msg->remaining());
148  }
149 
150  UnixFs::writeSysFsValue(path_cfg_.value_path(gpio_no_), 1);
151  return true;
152 }
153 
155 {
156  UnixFs::writeSysFsValue(path_cfg_.value_path(gpio_no_), 0);
157  return true;
158 }
159 
161 {
162  int v = UnixFs::readSysFsValue<int>(path_cfg_.value_path(gpio_no_));
163  UnixFs::writeSysFsValue(path_cfg_.value_path(gpio_no_), v == 1 ? 0 : 1);
164  return true;
165 }
166 
168 {
169  return UnixFs::readSysFsValue<bool>(path_cfg_.value_path(gpio_no_));
170 }
171 
173 {
174  std::array<char, 64> buffer;
175  ssize_t ret;
176 
177  // flush interrupt by reading.
178  // if we fail we cant recover, this means hardware failure.
179  ret = ::read(file_fd_, &buffer[0], buffer.size());
180  ASSERT_LOG(ret >= 0, "Read failed on GPIO pin.");
181  ret = ::lseek(file_fd_, 0, SEEK_SET);
182  ASSERT_LOG(ret >= 0, "Lseek failed on GPIO pin.");
183 
184  module_.publish_on_bus(zmqpp::message() << "S_INT:" + name_);
185 }
186 
187 void SysFsGpioPin::register_sockets(zmqpp::reactor *reactor)
188 {
189  reactor->add(sock_, std::bind(&SysFsGpioPin::handle_message, this));
190  if (direction_ == Direction::In)
191  reactor->add(file_fd_, std::bind(&SysFsGpioPin::handle_interrupt, this),
192  zmqpp::poller::poll_pri);
193 }
194 
195 std::chrono::system_clock::time_point SysFsGpioPin::next_update() const
196 {
197  return next_update_time_;
198 }
199 
201 {
202  DEBUG("Turning off SysFsGPIO pin.");
203  turn_off();
204  next_update_time_ = std::chrono::system_clock::time_point::max();
205 }
Leosac::Module::SysFsGpio::SysFsGpioPin::update
void update()
Update the PIN.
Definition: SysFSGPIOPin.cpp:200
Leosac::Module::SysFsGpio::SysFsGpioConfig::direction_path
std::string direction_path(int pin_no) const
Compute the absolute path the "direction" file for pin_no.
Definition: SysFsGpioConfig.cpp:93
LEOSACException::what
virtual const char * what() const noexcept final
Definition: leosacexception.hpp:53
Leosac::Module::SysFsGpio::SysFsGpioPin::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: SysFSGPIOPin.cpp:195
Leosac::Module::SysFsGpio::SysFsGpioPin::SysFsGpioPin
SysFsGpioPin(zmqpp::context &ctx, const std::string &name, int gpio_no, Direction direction, InterruptMode interrupt_mode, bool initial_value, SysFsGpioModule &module)
Definition: SysFSGPIOPin.cpp:29
WARN
@ WARN
Definition: log.hpp:33
Leosac::Module::SysFsGpio::SysFsGpioPin::handle_interrupt
void handle_interrupt()
Interrupt happened for this GPIO ping.
Definition: SysFSGPIOPin.cpp:172
zmqpp
Definition: CoreUtils.hpp:27
ERROR
@ ERROR
Definition: log.hpp:32
DEBUG
@ DEBUG
Definition: log.hpp:35
Leosac::Hardware::GPIO::Direction::Out
@ Out
Leosac::Module::SysFsGpio::SysFsGpioPin::set_direction
void set_direction(Direction dir)
Write direction to the direction file.
Definition: SysFSGPIOPin.cpp:90
ASSERT_LOG
#define ASSERT_LOG(cond, msg)
Definition: log.hpp:190
Leosac::Module::SysFsGpio::SysFsGpioPin::initial_value_
const bool initial_value_
Initial value of the PIN.
Definition: SysFSGPIOPin.hpp:155
Leosac::Module::SysFsGpio::SysFsGpioModule::publish_on_bus
void publish_on_bus(zmqpp::message &msg)
Write the message eon the bus.
Definition: SysFsGpioModule.cpp:122
Leosac::Module::SysFsGpio::SysFsGpioPin::read_value
bool read_value()
Read value from filesystem.
Definition: SysFSGPIOPin.cpp:167
Leosac::Module::SysFsGpio::SysFsGpioPin::InterruptMode::Both
@ Both
Leosac::Module::SysFsGpio::SysFsGpioPin::toggle
bool toggle()
Read to sysfs and then write the opposite value.
Definition: SysFSGPIOPin.cpp:160
Leosac::Module::SysFsGpio::SysFsGpioPin::InterruptMode::Rising
@ Rising
unixfs.hpp
unix filesystem helper functions
Leosac::Module::SysFsGpio::SysFsGpioPin::InterruptMode::None
@ None
Leosac::Module::SysFsGpio::SysFsGpioConfig::value_path
std::string value_path(int pin_no) const
Compute the absolute path the "value" file for pin_no.
Definition: SysFsGpioConfig.cpp:73
Leosac::Module::SysFsGpio::SysFsGpioPin::name_
std::string name_
Definition: SysFSGPIOPin.hpp:145
Leosac::Module::SysFsGpio::SysFsGpioModule::general_config
const SysFsGpioConfig & general_config() const
Retrieve a reference to the config object.
Definition: SysFsGpioModule.cpp:133
SysFSGPIOPin.hpp
Leosac::Module::SysFsGpio::SysFsGpioPin::sock_
zmqpp::socket sock_
listen to command from other component.
Definition: SysFSGPIOPin.hpp:143
Leosac::Module::SysFsGpio::SysFsGpioPin::handle_message
void handle_message()
The SysFsGpioModule will register this method so its called when a message is ready on the pin socket...
Definition: SysFSGPIOPin.cpp:112
Leosac::Module::SysFsGpio
Namespace for the module that implements GPIO support using the Linux Kernel sysfs interface.
Definition: SysFsGpioConfig.hpp:32
Leosac::Hardware::GPIO::Direction
Direction
Definition: GPIO.hpp:44
Leosac::Module::SysFsGpio::SysFsGpioPin::set_interrupt
void set_interrupt(InterruptMode mode)
Write interrupt mode to the edge file.
Definition: SysFSGPIOPin.cpp:96
Leosac::Module::SysFsGpio::SysFsGpioPin::next_update_time_
std::chrono::system_clock::time_point next_update_time_
Time point of next wished update.
Definition: SysFSGPIOPin.hpp:167
FsException
Definition: fsexception.hpp:33
Leosac::Module::SysFsGpio::SysFsGpioConfig::edge_path
std::string edge_path(int pin_no) const
Compute the absolute path the "edge" file for pin_no.
Definition: SysFsGpioConfig.cpp:83
Leosac::Module::SysFsGpio::SysFsGpioPin::InterruptMode
InterruptMode
Definition: SysFSGPIOPin.hpp:46
Leosac::Module::SysFsGpio::SysFsGpioPin::turn_on
bool turn_on(zmqpp::message *msg=nullptr)
Write to sysfs to turn the gpio on.
Definition: SysFSGPIOPin.cpp:133
Leosac::Tools::UnixFs
Definition: unixfs.hpp:39
Leosac::Module::SysFsGpio::SysFsGpioPin::InterruptMode::Falling
@ Falling
Leosac::Module::SysFsGpio::SysFsGpioPin::gpio_no_
int gpio_no_
Number of the GPIO.
Definition: SysFSGPIOPin.hpp:138
Leosac::Module::SysFsGpio::SysFsGpioPin::~SysFsGpioPin
~SysFsGpioPin()
Definition: SysFSGPIOPin.cpp:59
Leosac::Module::SysFsGpio::SysFsGpioPin::turn_off
bool turn_off()
Write to sysfs to turn the gpio on.
Definition: SysFSGPIOPin.cpp:154
Leosac::Hardware::GPIO::Direction::In
@ In
log.hpp
Leosac::Module::SysFsGpio::SysFsGpioModule
Handle GPIO management over sysfs.
Definition: SysFsGpioModule.hpp:49
Leosac::Module::SysFsGpio::SysFsGpioPin::register_sockets
void register_sockets(zmqpp::reactor *reactor)
Register own socket to the module's reactor.
Definition: SysFSGPIOPin.cpp:187
Leosac::Module::SysFsGpio::SysFsGpioPin::file_fd_
int file_fd_
File descriptor of the GPIO in sysfs.
Definition: SysFSGPIOPin.hpp:133
Leosac::Module::SysFsGpio::SysFsGpioPin::path_cfg_
const SysFsGpioConfig & path_cfg_
Definition: SysFSGPIOPin.hpp:162
Leosac::Module::SysFsGpio::SysFsGpioPin::module_
SysFsGpioModule & module_
Reference to the module.
Definition: SysFSGPIOPin.hpp:160
Leosac::Module::SysFsGpio::SysFsGpioPin::direction_
const Direction direction_
Direction of the PIN.
Definition: SysFSGPIOPin.hpp:150
Leosac::Module::SysFsGpio::SysFsGpioConfig::unexport_path
const std::string & unexport_path() const
Returns the absolute path to the "unexport" sysfs file.
Definition: SysFsGpioConfig.cpp:68