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> 18 namespace duds {
namespace hardware {
namespace interface {
namespace linux {
26 gpiohandle_request &req,
27 const std::string &consumer
29 memset(&req, 0,
sizeof(gpiohandle_request));
30 strcpy(req.consumer_label, consumer.c_str());
38 static void AddOffset(gpiohandle_request &req, std::uint32_t offset) {
41 assert(req.lines < GPIOHANDLES_MAX);
43 for (
int idx = req.lines - 1; idx >= 0; --idx) {
44 assert(req.lineoffsets[idx] != offset);
47 req.lineoffsets[req.lines++] = offset;
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) {
74 static bool RemoveOffset(gpiohandle_request &req, std::uint32_t offset) {
78 for (
int idx = req.lines - 1; idx >= 0; --idx) {
79 if (req.lineoffsets[idx] == offset) {
81 req.lineoffsets[idx] = req.lineoffsets[req.lines - 1];
83 req.default_values[idx] = req.default_values[req.lines - 1];
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)) {
124 boost::errinfo_errno(res)
128 if (ioctl(req.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &result) < 0) {
131 boost::errinfo_errno(res)
151 static void SetOutput(
int chipFd, gpiohandle_request &req) {
152 assert(req.flags & GPIOHANDLE_REQUEST_OUTPUT);
153 assert(req.lines > 0);
156 if (ioctl(chipFd, GPIO_GET_LINEHANDLE_IOCTL, &req) < 0) {
159 boost::errinfo_errno(res)
166 if (ioctl(req.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &(req.default_values)) < 0) {
169 boost::errinfo_errno(res)
188 virtual void inputOffset(
int chipFd, std::uint32_t offset) = 0;
195 virtual void outputOffset(
int chipFd, std::uint32_t offset,
bool state) = 0;
206 gpiohandle_data &result,
207 std::uint32_t *&offsets,
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;
252 req.lineoffsets[0] = offset;
260 assert(offset == req.lineoffsets[0]);
261 req.flags = GPIOHANDLE_REQUEST_INPUT;
263 if (ioctl(chipFd, GPIO_GET_LINEHANDLE_IOCTL, &req) < 0) {
266 boost::errinfo_errno(res)
270 virtual void outputOffset(
int chipFd, std::uint32_t offset,
bool state) {
272 assert(offset == req.lineoffsets[0]);
273 req.flags = GPIOHANDLE_REQUEST_OUTPUT;
275 req.default_values[0] = state;
276 if (ioctl(chipFd, GPIO_GET_LINEHANDLE_IOCTL, &req) < 0) {
279 boost::errinfo_errno(res)
285 gpiohandle_data &result,
286 std::uint32_t *&offsets,
290 offsets = req.lineoffsets;
296 virtual void write(
int chipFd, std::uint32_t offset,
bool state) {
298 assert(offset == req.lineoffsets[0]);
300 if (req.fd && (state == (req.default_values[0] > 0))) {
304 if (req.flags != GPIOHANDLE_REQUEST_OUTPUT) {
305 req.flags = GPIOHANDLE_REQUEST_OUTPUT;
308 req.default_values[0] = state;
313 assert(offset == req.lineoffsets[0]);
314 gpiohandle_data result;
316 if (req.flags != GPIOHANDLE_REQUEST_INPUT) {
317 req.flags = GPIOHANDLE_REQUEST_INPUT;
321 return result.values[0];
325 assert(offset == req.lineoffsets[0]);
326 req.default_values[0] = state;
348 inReq.flags = GPIOHANDLE_REQUEST_INPUT;
349 outReq.flags = GPIOHANDLE_REQUEST_OUTPUT;
356 outReq.default_values[outReq.lines - 1] = state;
371 lastOutputState(state);
379 if (ioctl(chipFd, GPIO_GET_LINEHANDLE_IOCTL, &inReq) < 0) {
382 boost::errinfo_errno(res)
386 virtual void outputOffset(
int chipFd, std::uint32_t offset,
bool state) {
392 lastOutputState(state);
393 if (ioctl(chipFd, GPIO_GET_LINEHANDLE_IOCTL, &outReq) < 0) {
396 boost::errinfo_errno(res)
402 gpiohandle_data &result,
403 std::uint32_t *&offsets,
407 offsets = inReq.lineoffsets;
408 length = inReq.lines;
415 virtual void write(
int chipFd, std::uint32_t offset,
bool state) {
419 if (outReq.fd && (state == (outReq.default_values[idx] > 0))) {
422 outReq.default_values[idx] = state;
426 gpiohandle_data result;
430 return result.values[idx] > 0;
441 lastOutputState(state);
443 outReq.default_values[idx] = state;
451 const std::string &path,
452 unsigned int firstid,
453 const std::string &username
455 chipFd = open(path.c_str(), 0);
458 boost::errinfo_file_name(path)
462 if (ioctl(
chipFd, GPIO_GET_CHIPINFO_IOCTL, &cinfo) < 0) {
467 boost::errinfo_file_name(path) << boost::errinfo_errno(res)
471 pins.resize(cinfo.lines);
472 for (std::uint32_t pidx = 0; pidx < cinfo.lines; ++pidx) {
478 const std::vector<unsigned int> &ids,
479 const std::string &path,
480 unsigned int firstid,
481 const std::string &username
484 chipFd = open(path.c_str(), 0);
487 boost::errinfo_file_name(path)
491 if (ioctl(
chipFd, GPIO_GET_CHIPINFO_IOCTL, &cinfo) < 0) {
496 boost::errinfo_file_name(path) << boost::errinfo_errno(res)
500 std::vector<unsigned int>::const_iterator iter = ids.begin();
501 for (
unsigned int pid = 0; iter != ids.end(); ++iter, ++pid) {
508 const std::string &
name,
509 const std::string &defaultPath,
516 if (forceDefault || port.
typeval.empty()) {
522 std::vector<unsigned int> gpios;
523 unsigned int next = 0;
524 gpios.reserve(port.
pins.size());
525 for (
auto const &pin : port.
pidIndex()) {
527 if ((pin.pid + port.
idOffset) != pin.gid) {
533 if (pin.pid > next) {
535 gpios.insert(gpios.end(), pin.pid - next, -1);
538 gpios.push_back(pin.pid);
541 std::shared_ptr<GpioDevPort> sp = std::make_shared<GpioDevPort>(
549 pe << boost::errinfo_file_name(path);
563 pins[pid].markNonexistent();
568 memset(&linfo, 0,
sizeof(linfo));
569 linfo.line_offset =
offset;
571 if (ioctl(
chipFd, GPIO_GET_LINEINFO_IOCTL, &linfo) < 0) {
576 boost::errinfo_errno(res) << boost::errinfo_file_name(
devpath)
580 if (linfo.flags & GPIOLINE_FLAG_KERNEL) {
582 pins[pid].markNonexistent();
585 if (linfo.flags & GPIOLINE_FLAG_IS_OUT) {
590 if (linfo.flags & GPIOLINE_FLAG_OPEN_DRAIN) {
592 }
else if (linfo.flags & GPIOLINE_FLAG_OPEN_SOURCE) {
598 pins[pid].conf.minOutputCurrent =
pins[pid].conf.maxOutputCurrent = 0;
602 pins[pid].cap.capabilities =
610 pins[pid].cap.maxOutputCurrent = 0;
698 const std::vector<unsigned int> &pvec,
702 gpiohandle_data result;
703 std::uint32_t *offsets;
706 assert(length >= pvec.size());
708 for (
int idx = 0; idx < length; ++idx) {
709 pins[offsets[idx]].conf.options.setTo(
711 result.values[idx] > 0
715 std::vector<bool> outv(pvec.size());
717 for (
const unsigned int &gid : pvec) {
723 pe << boost::errinfo_file_name(
devpath);
749 const std::vector<unsigned int> &pvec,
750 const std::vector<bool> &state,
756 std::vector<unsigned int>::const_iterator piter = pvec.begin();
757 std::vector<bool>::const_iterator siter = state.begin();
759 for (; piter != pvec.end(); ++piter, ++siter) {
774 pe << boost::errinfo_file_name(
devpath);
BitFlags setTo(const BitFlags &bf, bool val)
Make all bits in bf set or clear based on the value of val.
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'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'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.
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...
virtual ~SingleGpioRequest()
boost::error_info< struct Info_PinId, unsigned int > PinErrorId
The pin global ID involved in the error.
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...
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.
An error was reported from a GPIOHANDLE_SET_LINE_VALUES_IOCTL operation.
static void InitGpioHandleReq(gpiohandle_request &req, const std::string &consumer)
Initializes a gpiohandle_request structure.
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.
boost::error_info< struct Info_PinPortId, unsigned int > PinErrorPortId
The port (hardware) specific pin ID involved in the error.
void lastOutputState(bool state)
const PinConfiguration::Pins::index< index_pid >::type & pidIndex() const
Convenience function that provides the pin local ID index for the port'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.
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.
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.
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.
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.
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.
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...
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...