DUDS
Distributed Update of Data from Something
SysFsPort.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the DUDS project. It is subject to the BSD-style
3  * license terms in the LICENSE file found in the top-level directory of this
4  * distribution and at https://github.com/jjackowski/duds/blob/master/LICENSE.
5  * No part of DUDS, including this file, may be copied, modified, propagated,
6  * or distributed except according to the terms contained in the LICENSE file.
7  *
8  * Copyright (C) 2017 Jeff Jackowski
9  */
10 #include <boost/exception/errinfo_file_name.hpp>
11 #include <sstream>
14 
15 namespace duds { namespace hardware { namespace interface { namespace linux {
16 
17 static const char *prefix = "/sys/class/gpio/gpio";
18 
19 SysFsPort::SysFsPort(const std::vector<unsigned int> &ids, unsigned int firstid) :
20 DigitalPortIndependentPins(ids.size(), firstid), fspins(ids.size()) {
21  PinVector::iterator piter = pins.begin();
22  FsPinVector::iterator fiter = fspins.begin();
23  std::vector<unsigned int>::const_iterator iiter = ids.cbegin();
24  for (; piter != pins.end(); ++firstid, ++iiter, ++fiter, ++piter) {
25  // check for an empty spot
26  if (*iiter == -1) {
27  piter->markNonexistent();
28  } else {
29  // attempt to access the resources
30  try {
31  fiter->open(piter->conf, piter->cap, *iiter);
32  } catch (PinError &pe) {
33  pe << PinErrorId(firstid);
34  throw;
35  }
36  }
37  }
38 }
39 
40 std::shared_ptr<SysFsPort> SysFsPort::makeConfiguredPort(
41  PinConfiguration &pc,
42  const std::string &name
43 ) {
44  // find the port's config object
45  const PinConfiguration::Port &port = pc.port(name);
46  // enumerate the pins
47  std::vector<unsigned int> gpios;
48  unsigned int next = port.idOffset;
49  gpios.reserve(port.pins.size());
50  for (auto const &pin : port.gidIndex()) {
51  // need empty spots?
52  if (pin.gid > next) {
53  // add unavailable pins
54  gpios.insert(gpios.end(), pin.gid - next, -1);
55  }
56  // add available pin
57  gpios.push_back(pin.pid);
58  next = pin.gid + 1;
59  }
60  std::shared_ptr<SysFsPort> sp = std::make_shared<SysFsPort>(
61  gpios,
62  port.idOffset
63  );
64  pc.attachPort(sp, name);
65  return sp;
66 }
67 
69  shutdown();
70  // more stuff here?
71 }
72 
74  return false;
75 }
76 
78  unsigned int localPinId,
79  const DigitalPinConfig &cfg,
81 ) {
82  // only configure existing pins
85  if (pins[localPinId]) {
87  try {
88  // change direction
89  fspins[localPinId].setDirection(cfg & DigitalPinConfig::DirOutput);
90  } catch (PinError &pe) {
91  pe << PinErrorId(globalId(localPinId));
92  throw;
93  }
94  }
95 }
96 
98 try {
99  return fspins[localId(gid)].read();
100 } catch (PinError &pe) {
101  pe << PinErrorId(gid);
102  throw;
103 }
104 
106  unsigned int lid,
107  bool state,
109 ) try {
110  fspins[lid].write(state);
111 } catch (PinError &pe) {
112  pe << PinErrorId(globalId(lid));
113  throw;
114 }
115 
117  DigitalPinConfig &conf, // uninitialized
118  DigitalPinCap &cap, // uninitialized
119  unsigned int pin
120 ) {
121  fsid = pin;
123  // initialize the configuration and capability values to clear / nonexistent
125  cap = NonexistentDigitalPin;
126  std::ostringstream fname;
127  fname << prefix << pin << "/value";
128  value.open(fname.str().c_str());
129  bool noOutput = false;
130  if (!value.is_open()) {
131  // allow for input only
132  value.open(fname.str().c_str(), std::ios_base::in);
133  if (!value.is_open()) {
135  boost::errinfo_file_name(fname.str())
136  );
137  }
138  // cannot change the value; still good for input
139  noOutput = true;
140  } else {
141  // obtain current pin value
142  curoutval = reqoutval = read();
143  }
144  // unwrite "value"
145  fname.seekp(-5, std::ios_base::cur);
146  fname << "direction";
147  std::string dir;
148  direction.open(fname.str().c_str());
149  if (!direction.is_open()) {
150  // allow for no direction writes
151  direction.open(fname.str().c_str(), std::ios_base::in);
152  if (!direction.is_open()) {
153  value.close();
155  boost::errinfo_file_name(fname.str())
156  );
157  }
158  // read current direction
159  direction >> dir;
160  // no longer needed
161  direction.close();
162  } else {
163  // read current direction
164  direction >> dir;
165  }
166  // parse direction for initial setting & caps
167  if (dir == "in") { // currently input
168  isoutput = false;
169  // stuck on input?
170  if (!direction.is_open()) {
171  noOutput = true;
172  }
175  } else if (dir == "out") { // currently output
176  isoutput = true;
177  // stuck on output?
178  if (!direction.is_open()) {
179  // check for non-writable value file
180  if (noOutput) {
181  // useless pin; an output that cannot be changed
182  value.close();
184  PinErrorPortId(pin)
185  );
186  }
187  } else {
188  // can input
190  }
193  } else {
194  // unexpected value
196  }
197  // I don't like double negatives, but I'm not changing the logic to fix it.
198  if (!noOutput) {
199  // add output flag
201  }
202 }
203 
205  // only change direction; do not set direction to what it already is
206  if (output != isoutput) {
207  if (output) {
208  direction << "out" << std::endl;
209  } else {
210  direction << "in" << std::endl;
211  }
212  if (direction.fail()) {
214  PinErrorPortId(fsid)
215  );
216  } else if (output) {
217  // assure the logic to avoid unneeded changes will see the next
218  // write as a change
219  curoutval = !reqoutval;
220  write(reqoutval);
221  }
222  isoutput = output;
223  }
224 }
225 
227  value.seekg(0);
228  char v;
229  value >> v;
230  if (value.fail()) {
232  PinErrorPortId(fsid)
233  );
234  }
235  return v == '1';
236 }
237 
239  // record this as the requested output value; used when switching from
240  // input to output
241  reqoutval = w;
242  // Changing the output results in an error if the pin is configured
243  // as an input; the filesystem interface does not allow for specifying
244  // a value to output ahead of switching to output.
245  // Don't continue if the request is the same as the current output.
246  if (isoutput && (w != curoutval)) {
247  char v = '0';
248  if (w) {
249  ++v;
250  }
251  value << v << std::endl;
252  if (value.fail()) {
254  PinErrorPortId(fsid)
255  );
256  }
257  // record this as the current output
258  curoutval = w;
259  }
260 }
261 
262 } } } } // namespaces
void write(bool state)
Changes the output value of the pin.
Definition: SysFsPort.cpp:238
const PinConfiguration::Pins::index< index_gid >::type & gidIndex() const
Convenience function that provides the pin global ID index for the port&#39;s pins.
static constexpr Flags Input
Input operation is supported.
unsigned int idOffset
The pin ID offset for the port; used to translate between global and port pin IDs.
An I/O error prevented the operation on the pin from succeeding.
Definition: PinErrors.hpp:33
static constexpr Flags DirInput
Configure the pin for input.
Defines the configuration for a digital general purpose I/O pin.
constexpr DigitalPinCap NonexistentDigitalPin
The capabilities of a non-existent pin.
Holds configuration data for a single digital port.
unsigned int localId(unsigned int globalId) const
Returns the local ID for a pin given the global ID.
The requested operation is not supported by the specific pin.
Definition: PinErrors.hpp:38
unsigned int globalId(unsigned int localId) const
Returns the global ID for a pin given the local ID.
Pins pins
The pins described by the configuration file.
boost::error_info< struct Info_PinId, unsigned int > PinErrorId
The pin global ID involved in the error.
Definition: PinErrors.hpp:97
void open(DigitalPinConfig &conf, DigitalPinCap &cap, unsigned int pin)
Opens the value and direction files for the pin.
Definition: SysFsPort.cpp:116
static constexpr Flags OutputPushPull
Configure the pin to drive output both high and low.
A type for holding arbitrary port-specific data within a DigitalPinAccess or DigitalPinSetAccess obje...
virtual void configurePort(unsigned int localPinId, const DigitalPinConfig &cfg, DigitalPinAccessBase::PortData *)
Changes the hardware configuration for a single pin.
Definition: SysFsPort.cpp:77
Flags capabilities
The capabilities of a digital pin.
void attachPort(const std::shared_ptr< DigitalPort > &dp, const std::string &name="default")
Attaches the given DigitalPort to the named port in the configuration.
bool read()
Reads from the value file of the pin and returns the result.
Definition: SysFsPort.cpp:226
FsPinVector fspins
Internal pin objects for each pin that will be made available through this port object.
Definition: SysFsPort.hpp:143
void shutdown()
Waits for access to all pins so that any user of access objects may finish with their operation...
Definition: DigitalPort.cpp:20
Parses configuration data for DigitalPort, DigitalPin, DigitalPinSet, ChipSelectManager, and ChipSelect objects.
const Port & port(const std::string &name="default") const
Finds the configuration data for the named DigitalPort.
boost::error_info< struct Info_PinPortId, unsigned int > PinErrorPortId
The port (hardware) specific pin ID involved in the error.
Definition: PinErrors.hpp:107
void output(unsigned int gid, bool state, DigitalPinAccessBase::PortData *pdata)
Does error checking in advance of calling outputImpl(unsigned int, bool) to change the output of the ...
static constexpr Flags OutputPushPull
The output can drive the line either low or high.
virtual bool simultaneousOperations() const
The sysfs interface does not support simultaneous operations; returns false.
Definition: SysFsPort.cpp:73
virtual void outputImpl(unsigned int lid, bool state, DigitalPinAccessBase::PortData *)
Changes the output state of the given pin.
Definition: SysFsPort.cpp:105
static constexpr Flags DirOutput
Configure the pin for output.
Defines the capabilites of a digital general purpose I/O pin.
void setDirection(bool output)
Changes the pin&#39;s direction between input and output.
Definition: SysFsPort.cpp:204
Flags options
The control options requested for a digital pin.
static std::shared_ptr< SysFsPort > makeConfiguredPort(PinConfiguration &pc, const std::string &name="default")
Make a SysFsPort object according to the given configuration, and attach to the configuration.
Definition: SysFsPort.cpp:40
A partial DigitalPort implementation for ports where the configuration of each pin is independent of ...
Base exception type for all errors about pins.
Definition: PinErrors.hpp:26
static const char * prefix
Definition: SysFsPort.cpp:17
PinVector pins
Data on each pin handled by the port.
virtual bool inputImpl(unsigned int gid, DigitalPinAccessBase::PortData *)
Reads input from the given pin.
Definition: SysFsPort.cpp:97
Construction option for initializing all fields to defaul values.
SysFsPort(const std::vector< unsigned int > &ids, unsigned int firstid)
Make a SysFsPort object with the given pins.
Definition: SysFsPort.cpp:19
#define DUDS_THROW_EXCEPTION(x)
Works like BOOST_THROW_EXCEPTION, but includes a stack trace if DUDS_ERRORS_VERBOSE is defined...
Definition: Errors.hpp:48