DUDS
Distributed Update of Data from Something
GpioDevPort.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) 2018 Jeff Jackowski
9  */
10 #include <boost/exception/errinfo_file_name.hpp>
11 #include <boost/exception/errinfo_errno.hpp>
14 #include <linux/gpio.h>
15 #include <sys/ioctl.h>
16 #include <fcntl.h>
17 
18 namespace duds { namespace hardware { namespace interface { namespace linux {
19 
25 static void InitGpioHandleReq(
26  gpiohandle_request &req,
27  const std::string &consumer
28 ) {
29  memset(&req, 0, sizeof(gpiohandle_request));
30  strcpy(req.consumer_label, consumer.c_str());
31 }
32 
38 static void AddOffset(gpiohandle_request &req, std::uint32_t offset) {
39  #ifndef NDEBUG
40  // check limit on number of lines
41  assert(req.lines < GPIOHANDLES_MAX);
42  // ensure the offset is not already present
43  for (int idx = req.lines - 1; idx >= 0; --idx) {
44  assert(req.lineoffsets[idx] != offset);
45  }
46  #endif
47  req.lineoffsets[req.lines++] = offset;
48 }
49 
58 static int FindOffset(gpiohandle_request &req, std::uint32_t offset) {
59  for (int idx = req.lines - 1; idx >= 0; --idx) {
60  if (req.lineoffsets[idx] == offset) {
61  return idx;
62  }
63  }
64  return -1;
65 }
66 
74 static bool RemoveOffset(gpiohandle_request &req, std::uint32_t offset) {
75  // non-empty request?
76  if (req.lines) {
77  // search for offset
78  for (int idx = req.lines - 1; idx >= 0; --idx) {
79  if (req.lineoffsets[idx] == offset) {
80  // move last offset into spot of offset to remove
81  req.lineoffsets[idx] = req.lineoffsets[req.lines - 1];
82  // also move output state value
83  req.default_values[idx] = req.default_values[req.lines - 1];
84  // remove last
85  --req.lines;
86  return true;
87  }
88  }
89  }
90  return false;
91 }
92 
98 static void CloseIfOpen(gpiohandle_request &req) {
99  if (req.fd) {
100  close(req.fd);
101  req.fd = 0;
102  }
103 }
104 
118 static void GetInput(int chipFd, gpiohandle_data &result, gpiohandle_request &req) {
119  assert(req.flags & GPIOHANDLE_REQUEST_INPUT);
120  assert(req.lines > 0);
121  if (!req.fd && (ioctl(chipFd, GPIO_GET_LINEHANDLE_IOCTL, &req) < 0)) {
122  int res = errno;
124  boost::errinfo_errno(res)
125  );
126  }
127  assert(req.fd);
128  if (ioctl(req.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &result) < 0) {
129  int res = errno;
131  boost::errinfo_errno(res)
132  );
133  }
134 }
135 
151 static void SetOutput(int chipFd, gpiohandle_request &req) {
152  assert(req.flags & GPIOHANDLE_REQUEST_OUTPUT);
153  assert(req.lines > 0);
154  if (!req.fd) {
155  // obtain new line handle only when it didn't already exist
156  if (ioctl(chipFd, GPIO_GET_LINEHANDLE_IOCTL, &req) < 0) {
157  int res = errno;
159  boost::errinfo_errno(res)
160  );
161  }
162  // else, the above ioctl function succeeded and the output is now set
163  } else {
164  // already have line handle
165  assert(req.fd);
166  if (ioctl(req.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &(req.default_values)) < 0) {
167  int res = errno;
169  boost::errinfo_errno(res)
170  );
171  }
172  }
173 }
174 
175 
180 class GpioRequest {
181 public:
182  virtual ~GpioRequest() { };
188  virtual void inputOffset(int chipFd, std::uint32_t offset) = 0;
195  virtual void outputOffset(int chipFd, std::uint32_t offset, bool state) = 0;
204  virtual void read(
205  int chipFd,
206  gpiohandle_data &result,
207  std::uint32_t *&offsets,
208  int &length
209  ) = 0;
214  virtual void write(int chipFd) = 0;
222  virtual void write(int chipFd, std::uint32_t offset, bool state) = 0;
229  virtual bool inputState(int chipFd, std::uint32_t offset) = 0;
236  virtual void outputState(std::uint32_t offset, bool state) = 0;
237 };
238 
248  gpiohandle_request req;
249 public:
250  SingleGpioRequest(const std::string &consumer, std::uint32_t offset) {
251  InitGpioHandleReq(req, consumer);
252  req.lineoffsets[0] = offset;
253  req.lines = 1;
254  }
255  virtual ~SingleGpioRequest() {
256  CloseIfOpen(req);
257  }
258  virtual void inputOffset(int chipFd, std::uint32_t offset) {
259  // offset must not change
260  assert(offset == req.lineoffsets[0]);
261  req.flags = GPIOHANDLE_REQUEST_INPUT;
262  CloseIfOpen(req);
263  if (ioctl(chipFd, GPIO_GET_LINEHANDLE_IOCTL, &req) < 0) {
264  int res = errno;
266  boost::errinfo_errno(res)
267  );
268  }
269  }
270  virtual void outputOffset(int chipFd, std::uint32_t offset, bool state) {
271  // offset must not change
272  assert(offset == req.lineoffsets[0]);
273  req.flags = GPIOHANDLE_REQUEST_OUTPUT;
274  CloseIfOpen(req);
275  req.default_values[0] = state;
276  if (ioctl(chipFd, GPIO_GET_LINEHANDLE_IOCTL, &req) < 0) {
277  int res = errno;
279  boost::errinfo_errno(res)
280  );
281  }
282  }
283  virtual void read(
284  int chipFd,
285  gpiohandle_data &result,
286  std::uint32_t *&offsets,
287  int &length
288  ) {
289  GetInput(chipFd, result, req);
290  offsets = req.lineoffsets;
291  length = 1;
292  }
293  virtual void write(int chipFd) {
294  SetOutput(chipFd, req);
295  }
296  virtual void write(int chipFd, std::uint32_t offset, bool state) {
297  // offset must not change
298  assert(offset == req.lineoffsets[0]);
299  // early exit: already outputing the requested state
300  if (req.fd && (state == (req.default_values[0] > 0))) {
301  return;
302  }
303  // might not yet be an output
304  if (req.flags != GPIOHANDLE_REQUEST_OUTPUT) {
305  req.flags = GPIOHANDLE_REQUEST_OUTPUT;
306  CloseIfOpen(req);
307  }
308  req.default_values[0] = state;
309  SetOutput(chipFd, req);
310  }
311  virtual bool inputState(int chipFd, std::uint32_t offset) {
312  // offset must not change
313  assert(offset == req.lineoffsets[0]);
314  gpiohandle_data result;
315  // might not yet be an input
316  if (req.flags != GPIOHANDLE_REQUEST_INPUT) {
317  req.flags = GPIOHANDLE_REQUEST_INPUT;
318  CloseIfOpen(req);
319  }
320  GetInput(chipFd, result, req);
321  return result.values[0];
322  }
323  virtual void outputState(std::uint32_t offset, bool state) {
324  // offset must not change
325  assert(offset == req.lineoffsets[0]);
326  req.default_values[0] = state;
327  }
328 };
329 
335 class IoGpioRequest : public GpioRequest {
339  gpiohandle_request inReq;
343  gpiohandle_request outReq;
344 public:
345  IoGpioRequest(const std::string &consumer) {
346  InitGpioHandleReq(inReq, consumer);
347  InitGpioHandleReq(outReq, consumer);
348  inReq.flags = GPIOHANDLE_REQUEST_INPUT;
349  outReq.flags = GPIOHANDLE_REQUEST_OUTPUT;
350  }
351  virtual ~IoGpioRequest() {
352  CloseIfOpen(inReq);
353  CloseIfOpen(outReq);
354  }
355  void lastOutputState(bool state) {
356  outReq.default_values[outReq.lines - 1] = state;
357  }
362  void addInputOffset(std::uint32_t offset) {
363  AddOffset(inReq, offset);
364  }
369  void addOutputOffset(std::uint32_t offset, bool state) {
370  AddOffset(outReq, offset);
371  lastOutputState(state);
372  }
373  virtual void inputOffset(int chipFd, std::uint32_t offset) {
374  bool rem = RemoveOffset(outReq, offset);
375  assert(rem);
376  CloseIfOpen(outReq);
377  AddOffset(inReq, offset);
378  CloseIfOpen(inReq);
379  if (ioctl(chipFd, GPIO_GET_LINEHANDLE_IOCTL, &inReq) < 0) {
380  int res = errno;
382  boost::errinfo_errno(res)
383  );
384  }
385  }
386  virtual void outputOffset(int chipFd, std::uint32_t offset, bool state) {
387  bool rem = RemoveOffset(inReq, offset);
388  assert(rem);
389  CloseIfOpen(inReq);
390  AddOffset(outReq, offset);
391  CloseIfOpen(outReq);
392  lastOutputState(state);
393  if (ioctl(chipFd, GPIO_GET_LINEHANDLE_IOCTL, &outReq) < 0) {
394  int res = errno;
396  boost::errinfo_errno(res)
397  );
398  }
399  }
400  virtual void read(
401  int chipFd,
402  gpiohandle_data &result,
403  std::uint32_t *&offsets,
404  int &length
405  ) {
406  GetInput(chipFd, result, inReq);
407  offsets = inReq.lineoffsets;
408  length = inReq.lines;
409  }
410  virtual void write(int chipFd) {
411  if (outReq.lines) {
412  SetOutput(chipFd, outReq);
413  }
414  }
415  virtual void write(int chipFd, std::uint32_t offset, bool state) {
416  int idx = FindOffset(outReq, offset);
417  assert(idx >= 0);
418  // early exit: already outputing the requested state
419  if (outReq.fd && (state == (outReq.default_values[idx] > 0))) {
420  return;
421  }
422  outReq.default_values[idx] = state;
423  SetOutput(chipFd, outReq);
424  }
425  virtual bool inputState(int chipFd, std::uint32_t offset) {
426  gpiohandle_data result;
427  GetInput(chipFd, result, inReq);
428  int idx = FindOffset(inReq, offset);
429  assert(idx >= 0);
430  return result.values[idx] > 0;
431  }
432  virtual void outputState(std::uint32_t offset, bool state) {
433  int idx = FindOffset(outReq, offset);
434  if (idx < 0) {
435  bool rem = RemoveOffset(inReq, offset);
436  // the pin must already be in a request object
437  assert(rem);
438  CloseIfOpen(inReq);
439  AddOffset(outReq, offset);
440  CloseIfOpen(outReq);
441  lastOutputState(state);
442  } else {
443  outReq.default_values[idx] = state;
444  }
445  }
446 };
447 
448 // ---------------------------------------------------------------------------
449 
451  const std::string &path,
452  unsigned int firstid,
453  const std::string &username
454 ) : DigitalPortIndependentPins(0, firstid), consumer(username), devpath(path) {
455  chipFd = open(path.c_str(), 0);
456  if (chipFd < 0) {
458  boost::errinfo_file_name(path)
459  );
460  }
461  gpiochip_info cinfo;
462  if (ioctl(chipFd, GPIO_GET_CHIPINFO_IOCTL, &cinfo) < 0) {
463  int res = errno;
464  close(chipFd);
465  // could improve error reporting, but may not really matter
467  boost::errinfo_file_name(path) << boost::errinfo_errno(res)
468  );
469  }
470  name = cinfo.name;
471  pins.resize(cinfo.lines);
472  for (std::uint32_t pidx = 0; pidx < cinfo.lines; ++pidx) {
473  initPin(pidx, pidx);
474  }
475 }
476 
478  const std::vector<unsigned int> &ids,
479  const std::string &path,
480  unsigned int firstid,
481  const std::string &username
482 ) : DigitalPortIndependentPins(ids.size(), firstid), consumer(username),
483 devpath(path) {
484  chipFd = open(path.c_str(), 0);
485  if (chipFd < 0) {
487  boost::errinfo_file_name(path)
488  );
489  }
490  gpiochip_info cinfo;
491  if (ioctl(chipFd, GPIO_GET_CHIPINFO_IOCTL, &cinfo) < 0) {
492  int res = errno;
493  close(chipFd);
494  // could improve error reporting, but may not really matter
496  boost::errinfo_file_name(path) << boost::errinfo_errno(res)
497  );
498  }
499  name = cinfo.name;
500  std::vector<unsigned int>::const_iterator iter = ids.begin();
501  for (unsigned int pid = 0; iter != ids.end(); ++iter, ++pid) {
502  initPin(*iter, pid);
503  }
504 }
505 
506 std::shared_ptr<GpioDevPort> GpioDevPort::makeConfiguredPort(
507  PinConfiguration &pc,
508  const std::string &name,
509  const std::string &defaultPath,
510  bool forceDefault
511 ) {
512  // find the port's config object
513  const PinConfiguration::Port &port = pc.port(name);
514  // work out device file path
515  std::string path;
516  if (forceDefault || port.typeval.empty()) {
517  path = defaultPath;
518  } else {
519  path = port.typeval;
520  }
521  // enumerate the pins
522  std::vector<unsigned int> gpios;
523  unsigned int next = 0;
524  gpios.reserve(port.pins.size());
525  for (auto const &pin : port.pidIndex()) {
526  // pin IDs cannot be assigned arbitrary values
527  if ((pin.pid + port.idOffset) != pin.gid) {
529  PortPinId(pin.gid)
530  );
531  }
532  // need empty spots?
533  if (pin.pid > next) {
534  // add unavailable pins
535  gpios.insert(gpios.end(), pin.pid - next, -1);
536  }
537  // add available pin
538  gpios.push_back(pin.pid);
539  next = pin.pid + 1;
540  }
541  std::shared_ptr<GpioDevPort> sp = std::make_shared<GpioDevPort>(
542  gpios,
543  path,
544  port.idOffset
545  );
546  try {
547  pc.attachPort(sp, name);
548  } catch (PinError &pe) {
549  pe << boost::errinfo_file_name(path);
550  throw;
551  }
552  return sp;
553 }
554 
556  shutdown();
557  close(chipFd);
558 }
559 
560 void GpioDevPort::initPin(std::uint32_t offset, unsigned int pid) {
561  if (offset == -1) {
562  // line cannot be used
563  pins[pid].markNonexistent();
564  return;
565  }
566  // prepare data for inquiry to kernel
567  gpioline_info linfo;
568  memset(&linfo, 0, sizeof(linfo)); // all examples do this; needed?
569  linfo.line_offset = offset;
570  // request data from the kernel; check for error
571  if (ioctl(chipFd, GPIO_GET_LINEINFO_IOCTL, &linfo) < 0) {
572  int res = errno;
573  close(chipFd);
575  PinErrorId(globalId(offset)) << PinErrorPortId(offset) <<
576  boost::errinfo_errno(res) << boost::errinfo_file_name(devpath)
577  );
578  }
579  // used by kernel?
580  if (linfo.flags & GPIOLINE_FLAG_KERNEL) {
581  // line cannot be used
582  pins[pid].markNonexistent();
583  } else {
584  // set configuration to match reported status
585  if (linfo.flags & GPIOLINE_FLAG_IS_OUT) {
586  pins[pid].conf.options = DigitalPinConfig::DirOutput;
587  } else {
588  pins[pid].conf.options = DigitalPinConfig::DirInput;
589  }
590  if (linfo.flags & GPIOLINE_FLAG_OPEN_DRAIN) {
591  pins[pid].conf.options |= DigitalPinConfig::OutputDriveLow;
592  } else if (linfo.flags & GPIOLINE_FLAG_OPEN_SOURCE) {
593  pins[pid].conf.options |= DigitalPinConfig::OutputDriveHigh;
594  } else if (pins[pid].conf.options & DigitalPinConfig::DirOutput) {
595  pins[pid].conf.options |= DigitalPinConfig::OutputPushPull;
596  }
597  // no data on output currents
598  pins[pid].conf.minOutputCurrent = pins[pid].conf.maxOutputCurrent = 0;
599  // Unfortunately, the kernel reports on the current status of the line
600  // and not the line's capabilities. Report the line can do what the
601  // kernel supports, and hope this doesn't cause trouble.
602  pins[pid].cap.capabilities =
605  DigitalPinCap::EventEdgeFalling | // theses are not yet supported
606  DigitalPinCap::EventEdgeRising |
607  DigitalPinCap::EventEdgeChange |
608  DigitalPinCap::InterruptOnEvent */;
609  // no data on output currents
610  pins[pid].cap.maxOutputCurrent = 0;
611  }
612 }
613 
615  return true;
616 }
617 
620 }
621 
623  // create the request objects
625  // fill stuff?
626 
627  for (auto pid : acc.localIds()) {
628  const PinEntry &pe = pins[pid];
630  //AddOffset(hreq->inReq, pid);
631  igr->addInputOffset(pid);
632  } else if (pe.conf.options & DigitalPinConfig::DirOutput) {
633  //AddOffset(hreq->outReq, pid);
634  igr->addOutputOffset(
635  pid,
637  );
638  }
640  }
641  portData(acc).pointer = igr;
642 }
643 
644 void GpioDevPort::retiredAccess(const DigitalPinAccess &acc) noexcept {
645  SingleGpioRequest *sgr;
646  portDataPtr(acc, &sgr);
647  delete sgr;
648 }
649 
651  IoGpioRequest *igr;
652  portDataPtr(acc, &igr);
653  delete igr;
654 }
655 
657  unsigned int lid,
658  const DigitalPinConfig &cfg,
660 ) try {
661  GpioRequest *gr = (GpioRequest*)pdata->pointer;
662  DigitalPinConfig &dpc = pins[lid].conf;
663  // change in config?
664  if (
665  (dpc.options & DigitalPinConfig::DirMask) !=
667  ) {
668  if (cfg & DigitalPinConfig::DirInput) {
669  gr->inputOffset(chipFd, lid);
670  } else if (cfg & DigitalPinConfig::DirOutput) {
671  gr->outputOffset(
672  chipFd,
673  lid,
674  dpc.options & DigitalPinConfig::OutputState
675  );
676  }
677  }
678 } catch (PinError &pe) {
679  pe << PinErrorId(globalId(lid)) << boost::errinfo_file_name(devpath);
680  throw;
681 }
682 
684  unsigned int gid,
686 ) try {
687  GpioRequest *gr = (GpioRequest*)pdata->pointer;
688  int lid = localId(gid);
689  bool res = gr->inputState(chipFd, lid);
690  pins[lid].conf.options.setTo(DigitalPinConfig::InputState, res);
691  return res;
692 } catch (PinError &pe) {
693  pe << PinErrorId(gid) << boost::errinfo_file_name(devpath);
694  throw;
695 }
696 
697 std::vector<bool> GpioDevPort::inputImpl(
698  const std::vector<unsigned int> &pvec,
700 ) try {
701  GpioRequest *gr = (GpioRequest*)pdata->pointer;
702  gpiohandle_data result;
703  std::uint32_t *offsets;
704  int length;
705  gr->read(chipFd, result, offsets, length);
706  assert(length >= pvec.size());
707  // record input states
708  for (int idx = 0; idx < length; ++idx) {
709  pins[offsets[idx]].conf.options.setTo(
711  result.values[idx] > 0
712  );
713  }
714  // return input states
715  std::vector<bool> outv(pvec.size());
716  int idx = 0;
717  for (const unsigned int &gid : pvec) {
718  outv[idx++] =
719  (pins[localId(gid)].conf.options & DigitalPinConfig::InputState) > 0;
720  }
721  return outv;
722 } catch (PinError &pe) {
723  pe << boost::errinfo_file_name(devpath);
724  throw;
725 }
726 
728  unsigned int lid,
729  bool state,
731 ) try {
732  // find the pin configuration
733  DigitalPinConfig &dpc = pins[lid].conf;
734  // get the request object to make modifications
735  GpioRequest *gr = (GpioRequest*)pdata->pointer;
736  // is output?
738  // set output state
739  gr->write(chipFd, lid, state);
740  }
741  // store new state; no change if error above
743 } catch (PinError &pe) {
744  pe << PinErrorId(globalId(lid)) << boost::errinfo_file_name(devpath);
745  throw;
746 }
747 
749  const std::vector<unsigned int> &pvec,
750  const std::vector<bool> &state,
752 ) try {
753  // get the request object to make modifications
754  GpioRequest *gr = (GpioRequest*)pdata->pointer;
755  // loop through all pins to alter
756  std::vector<unsigned int>::const_iterator piter = pvec.begin();
757  std::vector<bool>::const_iterator siter = state.begin();
758  int outs = 0;
759  for (; piter != pvec.end(); ++piter, ++siter) {
760  // configured for output? might be changing state ahead of config change
761  if (pins[*piter].conf.options & DigitalPinConfig::DirOutput) {
762  // configure the port data; no output happens yet
763  gr->outputState(*piter, *siter);
764  ++outs;
765  }
766  // store new state
767  pins[*piter].conf.options.setTo(DigitalPinConfig::OutputState, *siter);
768  }
769  // send output if already in output state
770  if (outs) {
771  gr->write(chipFd);
772  }
773 } catch (PinError &pe) {
774  pe << boost::errinfo_file_name(devpath);
775  throw;
776 }
777 
778 } } } } // namespaces
BitFlags setTo(const BitFlags &bf, bool val)
Make all bits in bf set or clear based on the value of val.
Definition: BitFlags.hpp:267
unsigned int localId() const
Returns the local pin ID of the accessed pin.
virtual void outputOffset(int chipFd, std::uint32_t offset, bool state)
Configures the pin at the given offset as an output.
GpioDevPort(const std::string &path="/dev/gpiochip0", unsigned int firstid=0, const std::string &username="DUDS")
Make a GpioDevPort object with all the pins available to the device.
gpiohandle_request outReq
Output request.
A required DigitalPort object was not supplied.
boost::error_info< struct Info_PortPinId, unsigned int > PortPinId
The global ID of a pin from a configuration that is involved in the error.
static constexpr Flags Input
Input operation is supported.
static constexpr Flags DirMask
A bit mask for all direction flags.
Provides access to multiple pins on a DigitalPort.
unsigned int offset() const
Returns the offset for the port&#39;s pins.
unsigned int idOffset
The pin ID offset for the port; used to translate between global and port pin IDs.
virtual void write(int chipFd)=0
Configures pins as outputs and sets their output states.
static constexpr Flags DirInput
Configure the pin for input.
virtual void configurePort(unsigned int localPinId, const DigitalPinConfig &cfg, DigitalPinAccessBase::PortData *pdata)
Changes the hardware configuration for a single pin.
virtual void inputOffset(int chipFd, std::uint32_t offset)
Configures the pin at the given offset as an input.
static DigitalPinAccessBase::PortData & portData(const DigitalPinAccessBase &acc)
Returns a reference to the port specific data in the given DigitalPinAccessBase object.
virtual void write(int chipFd)
Configures pins as outputs and sets their output states.
Implements using a single gpiohandle_request object for working with a single pin.
Defines the configuration for a digital general purpose I/O 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.
std::string devpath
The path of the device file; retained only for error reporting purposes.
virtual void outputState(std::uint32_t offset, bool state)
Sets the output state of a single pin in advance of making the output request to the port...
SingleGpioRequest(const std::string &consumer, std::uint32_t offset)
A given pin ID cannot be used with the port, such as an ID that is less than the port&#39;s ID offset...
virtual void madeAccess(DigitalPinAccess &acc)
Called after a new access object is made to allow a port implementation to take further action...
virtual bool simultaneousOperations() const
Simultaneous operations are supported; returns true.
DigitalPinConfig conf
The configuration for the pin.
Definition: DigitalPort.hpp:78
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.
static void portDataPtr(const DigitalPinAccessBase &acc, T **ptr)
Provides a pointer to type T stored in the port specific data of the given DigitalPinAccessBase objec...
boost::error_info< struct Info_PinId, unsigned int > PinErrorId
The pin global ID involved in the error.
Definition: PinErrors.hpp:97
std::string consumer
The consumer name given to the kernel when requesting the use of GPIO lines.
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...
std::string typeval
A hint as to what DigitalPort implementation should be used.
void addInputOffset(std::uint32_t offset)
Adds an offset for input use.
virtual void outputState(std::uint32_t offset, bool state)
Sets the output state of a single pin in advance of making the output request to the port...
virtual void write(int chipFd)
Configures pins as outputs and sets their output states.
Implements using two gpiohandle_requests object for working with multiple pins.
virtual bool inputImpl(unsigned int gid, DigitalPinAccessBase::PortData *pdata)
Reads input from the given pin.
virtual void outputState(std::uint32_t offset, bool state)=0
Sets the output state of a single pin in advance of making the output request to the port...
static void GetInput(int chipFd, gpiohandle_data &result, gpiohandle_request &req)
Requests input states from the kernel.
The provided DigitalPort object lacks a required 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.
static constexpr Flags OutputDriveLow
Configure the pin to be able to drive the output low.
void initPin(std::uint32_t offset, unsigned int pid)
Initializes a PinEntry with data on a GPIO line.
virtual void read(int chipFd, gpiohandle_data &result, std::uint32_t *&offsets, int &length)
Read from all input pins.
static constexpr Flags OutputDriveHigh
Configure the pin to be able to drive the output high.
void shutdown()
Waits for access to all pins so that any user of access objects may finish with their operation...
Definition: DigitalPort.cpp:20
virtual void write(int chipFd, std::uint32_t offset, bool state)
Sets the output state of a single output pin.
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.
IoGpioRequest(const std::string &consumer)
unsigned int size() const
The maximum number of pins on the port.
virtual bool inputState(int chipFd, std::uint32_t offset)
Reads the input state of the indicated pin.
gpiohandle_request req
The request object.
Provides access to a single pin on a DigitalPort.
int chipFd
File descriptor for GPIO chip device file.
void * pointer
A pointer available for use by DigitalPort implementations to manage additional implementation specif...
std::string name
The reported name of the GPIO chip device.
Definition: GpioDevPort.hpp:96
An error was reported from a GPIOHANDLE_SET_LINE_VALUES_IOCTL operation.
Definition: GpioDevPort.hpp:47
static void InitGpioHandleReq(gpiohandle_request &req, const std::string &consumer)
Initializes a gpiohandle_request structure.
Definition: GpioDevPort.cpp:25
virtual void read(int chipFd, gpiohandle_data &result, std::uint32_t *&offsets, int &length)=0
Read from all input pins.
void addOutputOffset(std::uint32_t offset, bool state)
Adds an offset for output use and sets the initial output state.
An error was reported from a GPIOHANDLE_GET_LINE_VALUES_IOCTL operation.
Definition: GpioDevPort.hpp:42
boost::error_info< struct Info_PinPortId, unsigned int > PinErrorPortId
The port (hardware) specific pin ID involved in the error.
Definition: PinErrors.hpp:107
const PinConfiguration::Pins::index< index_pid >::type & pidIndex() const
Convenience function that provides the pin local ID index for the port&#39;s pins.
An abstraction for using gpiohandle_request object(s).
static std::shared_ptr< GpioDevPort > makeConfiguredPort(PinConfiguration &pc, const std::string &name="default", const std::string &defaultPath="/dev/gpiochip0", bool forceDefault=false)
Make a GpioDevPort object according to the given configuration, and attach to the configuration...
static void AddOffset(gpiohandle_request &req, std::uint32_t offset)
Adds a GPIO line offset to a gpiohandle_request object.
Definition: GpioDevPort.cpp:38
static constexpr Flags OutputPushPull
The output can drive the line either low or high.
gpiohandle_request inReq
Input request.
virtual void read(int chipFd, gpiohandle_data &result, std::uint32_t *&offsets, int &length)
Read from all input pins.
static int FindOffset(gpiohandle_request &req, std::uint32_t offset)
Finds the array index that corresponds to the given offset.
Definition: GpioDevPort.cpp:58
virtual void inputOffset(int chipFd, std::uint32_t offset)
Configures the pin at the given offset as an input.
static bool RemoveOffset(gpiohandle_request &req, std::uint32_t offset)
Removes a GPIO line offset from a gpiohandle_request object.
Definition: GpioDevPort.cpp:74
static constexpr Flags DirOutput
Configure the pin for output.
virtual void inputOffset(int chipFd, std::uint32_t offset)=0
Configures the pin at the given offset as an input.
static void SetOutput(int chipFd, gpiohandle_request &req)
Sets the output states for all the pins in the request object.
Flags options
The control options requested for a digital pin.
static constexpr Flags OutputState
The set output state for the pin.
virtual void write(int chipFd, std::uint32_t offset, bool state)
Sets the output state of a single output pin.
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
const std::vector< unsigned int > & localIds() const
Provides access to the internal vector of local pin IDs.
virtual void outputImpl(unsigned int lid, bool state, DigitalPinAccessBase::PortData *pdata)
Changes the output state of the given pin.
PinVector pins
Data on each pin handled by the port.
An error was reported from a GPIO_GET_LINEHANDLE_IOCTL operation.
Definition: GpioDevPort.hpp:37
virtual void outputOffset(int chipFd, std::uint32_t offset, bool state)
Configures the pin at the given offset as an output.
Data stored for each pin controlled by the port.
Definition: DigitalPort.hpp:66
virtual void outputOffset(int chipFd, std::uint32_t offset, bool state)=0
Configures the pin at the given offset as an output.
#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
virtual bool inputState(int chipFd, std::uint32_t offset)=0
Reads the input state of the indicated pin.
virtual void retiredAccess(const DigitalPinAccess &acc) noexcept
Called just before an access object is retired to allow a port implementation to take further action...
static constexpr Flags InputState
The last known input state from the pin.
virtual bool inputState(int chipFd, std::uint32_t offset)
Reads the input state of the indicated pin.
static void CloseIfOpen(gpiohandle_request &req)
Closes the file descriptor in the request object if it appears to have a file, and then sets the desc...
Definition: GpioDevPort.cpp:98