F´ Flight Software - C/C++ Documentation  devel
A framework for building embedded system applications to NASA flight quality standards.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
LinuxGpioDriver.cpp
Go to the documentation of this file.
1 // ======================================================================
2 // \title LinuxGpioDriverImpl.cpp
3 // \author tcanham
4 // \brief cpp file for LinuxGpioDriver component implementation class
5 //
6 // \copyright
7 // Copyright 2009-2015, by the California Institute of Technology.
8 // ALL RIGHTS RESERVED. United States Government Sponsorship
9 // acknowledged.
10 //
11 // ======================================================================
13 #include <FpConfig.hpp>
14 #include <Fw/Types/String.hpp>
15 #include <Fw/Types/StringUtils.hpp>
16 #include <Os/Posix/File.hpp>
17 
18 #include <linux/gpio.h>
19 #include <poll.h>
20 #include <sys/ioctl.h>
21 #include <unistd.h>
22 #include <cerrno>
23 
24 namespace Drv {
25 
26 
29  switch (errno_input) {
30  case 0:
31  status = Os::File::Status::OP_OK;
32  break;
33  case EBADF:
34  status = Os::File::Status::NOT_OPENED;
35  break;
36  case EINVAL:
37  status = Os::File::Status::INVALID_ARGUMENT;
38  break;
39  case ENODEV:
40  status = Os::File::Status::DOESNT_EXIST;
41  break;
42  case ENOMEM:
44  break;
45  case EPERM:
46  status = Os::File::Status::NO_PERMISSION;
47  break;
48  case ENXIO:
49  status = Os::File::Status::INVALID_MODE;
50  break;
51  // Cascades intended
52  case EFAULT:
53  case EWOULDBLOCK:
54  case EBUSY:
55  case EIO:
56  default:
58  break;
59  }
60  return status;
61 }
62 
64  Drv::GpioStatus status = Drv::GpioStatus::T::UNKNOWN_ERROR;
65  switch (errno_input) {
66  case EBADF:
67  status = Drv::GpioStatus::T::NOT_OPENED;
68  break;
69  case ENXIO:
71  break;
72  // Cascades intended
73  case EFAULT:
74  case EINVAL:
75  case EWOULDBLOCK:
76  case EBUSY:
77  case EIO:
78  default:
79  status = Drv::GpioStatus::T::UNKNOWN_ERROR;
80  break;
81  }
82  return status;
83 }
84 
86  U32 flags = 0;
87  switch (configuration) {
89  flags = GPIOHANDLE_REQUEST_OUTPUT;
90  break;
91  // Cascade intended
96  flags = GPIOHANDLE_REQUEST_INPUT;
97  break;
98  default:
99  FW_ASSERT(0, static_cast<FwAssertArgType>(configuration));
100  break;
101  }
102  return flags;
103 }
104 
106  U32 flags = 0;
107  switch (configuration) {
109  flags = GPIOEVENT_REQUEST_RISING_EDGE;
110  break;
112  flags = GPIOEVENT_REQUEST_FALLING_EDGE;
113  break;
115  flags = GPIOEVENT_REQUEST_RISING_EDGE | GPIOEVENT_REQUEST_FALLING_EDGE;
116  break;
117  default:
118  FW_ASSERT(0, static_cast<FwAssertArgType>(configuration));
119  break;
120  }
121  return flags;
122 }
123 
125  (void) ::close(this->m_fd);
126 }
127 
128 // ----------------------------------------------------------------------
129 // Handler implementations for user-defined typed input ports
130 // ----------------------------------------------------------------------
131 
132 Os::File::Status LinuxGpioDriver ::setupLineHandle(const PlatformIntType chip_descriptor,
133  const U32 gpio,
134  const GpioConfiguration& configuration,
135  const Fw::Logic& default_state,
136  PlatformIntType& fd) {
138  // Set up the GPIO request
139  struct gpiohandle_request request;
140  (void) ::memset(&request, 0, sizeof request);
141  request.lineoffsets[0] = gpio;
142  Fw::StringUtils::string_copy(request.consumer_label, this->getObjName(),
143  static_cast<FwSizeType>(sizeof request.consumer_label));
144  request.default_values[0] = (default_state == Fw::Logic::HIGH) ? 1 : 0;
145  request.fd = -1;
146  request.lines = 1;
147  request.flags = configuration_to_handler_flags(configuration);
148 
149  errno = 0;
150  PlatformIntType return_value = ioctl(chip_descriptor, GPIO_GET_LINEHANDLE_IOCTL, &request);
151  fd = request.fd;
152  if (return_value != 0) {
153  status = errno_to_file_status(errno);
154  fd = -1;
155  }
156  return status;
157 }
158 
159 Os::File::Status LinuxGpioDriver ::setupLineEvent(const PlatformIntType chip_descriptor,
160  const U32 gpio,
161  const GpioConfiguration& configuration,
162  PlatformIntType& fd) {
164  // Set up the GPIO request
165  struct gpioevent_request event;
166  (void) ::memset(&event, 0, sizeof event);
167  event.lineoffset = gpio;
168  Fw::StringUtils::string_copy(event.consumer_label, this->getObjName(),
169  static_cast<FwSizeType>(sizeof event.consumer_label));
170  event.fd = -1;
171  event.handleflags = configuration_to_handler_flags(configuration);
172  event.eventflags = configuration_to_event_flags(configuration);
173  errno = 0;
174  PlatformIntType return_value = ioctl(chip_descriptor, GPIO_GET_LINEEVENT_IOCTL, &event);
175  fd = event.fd;
176  if (return_value != 0) {
177  status = errno_to_file_status(errno);
178  fd = -1;
179  }
180  return status;
181 }
182 
184  const U32 gpio,
185  const GpioConfiguration& configuration,
186  const Fw::Logic& default_state) {
188  Os::File chip_file;
189  FW_ASSERT(device != nullptr);
190  FW_ASSERT(configuration < MAX_GPIO_CONFIGURATION and configuration >= 0, static_cast<FwAssertArgType>(configuration));
191 
192  // Open chip file and check for success
193  status = chip_file.open(device, Os::File::Mode::OPEN_WRITE);
194  if (status != Os::File::OP_OK) {
195  this->log_WARNING_HI_OpenChipError(Fw::String(device), Os::FileStatus(static_cast<Os::FileStatus::T>(status)));
196  return status;
197  }
198  // Read chip information and check for correctness
199  PlatformIntType chip_descriptor =
200  reinterpret_cast<Os::Posix::File::PosixFileHandle*>(chip_file.getHandle())->m_file_descriptor;
201  struct gpiochip_info chip_info;
202  (void) ::memset(&chip_info, 0, sizeof chip_info);
203  PlatformIntType return_value = ioctl(chip_descriptor, GPIO_GET_CHIPINFO_IOCTL, &chip_info);
204  if (return_value != 0) {
205  status = errno_to_file_status(errno);
206  this->log_WARNING_HI_OpenChipError(Fw::String(device), Os::FileStatus(static_cast<Os::FileStatus::T>(status)));
207  return status;
208  }
209  // Check if the GPIO line exists
210  if (gpio >= chip_info.lines) {
211  this->log_WARNING_HI_OpenPinError(Fw::String(device), gpio, Fw::String("Does Not Exist"),
212  Os::FileStatus(static_cast<Os::FileStatus::T>(status)));
213  return status;
214  }
215  Fw::String pin_message("Unknown");
216  struct gpioline_info pin_info;
217  (void) ::memset(&pin_info, 0, sizeof pin_info);
218  pin_info.line_offset = gpio;
219  return_value = ioctl(chip_descriptor, GPIO_GET_LINEINFO_IOCTL, &pin_info);
220  if (return_value == 0) {
221  const bool has_consumer = pin_info.consumer[0] != '\0';
222  pin_message.format("%s%s%s", pin_info.name, has_consumer ? " with current consumer " : "",
223  has_consumer ? pin_info.consumer : "");
224  }
225 
226  // Set up pin and set file descriptor for it
227  PlatformIntType pin_fd = -1;
228  switch (configuration) {
229  // Cascade intended
230  case GPIO_OUTPUT:
231  case GPIO_INPUT:
232  status = this->setupLineHandle(chip_descriptor, gpio, configuration, default_state, pin_fd);
233  break;
234  // Cascade intended
238  status = this->setupLineEvent(chip_descriptor, gpio, configuration, pin_fd);
239  break;
240  default:
241  FW_ASSERT(0);
242  break;
243  }
244  // Final status check
245  if (status != Os::File::Status::OP_OK) {
246  this->log_WARNING_HI_OpenPinError(Fw::String(device), gpio, pin_message,
247  Os::FileStatus(static_cast<Os::FileStatus::T>(status)));
248  } else {
249  this->log_DIAGNOSTIC_OpenChip(Fw::String(chip_info.name), Fw::String(chip_info.label),
250  gpio, pin_message);
251  this->m_fd = pin_fd;
252  this->m_configuration = configuration;
253  }
254  return status;
255 }
256 
257 Drv::GpioStatus LinuxGpioDriver ::gpioRead_handler(const NATIVE_INT_TYPE portNum, Fw::Logic& state) {
259  if (this->m_configuration == GpioConfiguration::GPIO_INPUT) {
260  struct gpiohandle_data values;
261  (void) ::memset(&values, 0, sizeof values);
262  PlatformIntType return_value = ioctl(this->m_fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &values);
263  if (return_value != 0) {
264  status = errno_to_gpio_status(errno);
265  } else {
266  state = values.values[0] ? Fw::Logic::HIGH : Fw::Logic::LOW;
267  status = Drv::GpioStatus::OP_OK;
268  }
269  }
270  return status;
271 }
272 
273 Drv::GpioStatus LinuxGpioDriver ::gpioWrite_handler(const NATIVE_INT_TYPE portNum, const Fw::Logic& state) {
275  if (this->m_configuration == GpioConfiguration::GPIO_OUTPUT) {
276  struct gpiohandle_data values;
277  (void) ::memset(&values, 0, sizeof values);
278  values.values[0] = (state == Fw::Logic::HIGH) ? 1 : 0;
279  PlatformIntType return_value = ioctl(this->m_fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &values);
280  if (return_value != 0) {
281  status = errno_to_gpio_status(errno);
282  } else {
283  status = Drv::GpioStatus::OP_OK;
284  }
285  }
286  return status;
287 }
288 
289 void LinuxGpioDriver ::pollLoop() {
290  static_assert(GPIO_POLL_TIMEOUT < std::numeric_limits<int>::max(), "Poll timeout would overflow");
291  static_assert(sizeof(struct gpioevent_data) < std::numeric_limits<FwSizeType>::max(), "FwSizeType too small");
292  static_assert(std::numeric_limits<ssize_t>::max() <= std::numeric_limits<FwSizeType>::max(), "FwSizeType too small");
293  // Setup poll information
294  pollfd file_descriptors[1];
295  // Loop forever
296  while (this->getRunning()) {
297  // Setup polling
298  (void) ::memset(file_descriptors, 0, sizeof file_descriptors);
299  file_descriptors[0].fd = this->m_fd;
300  file_descriptors[0].events = POLLIN; // Ask for read data available
301  // Poll for fd bing ready
302  PlatformIntType status = ::poll(file_descriptors, 1, static_cast<int>(GPIO_POLL_TIMEOUT));
303  // Check for some file descriptor to be ready
304  if (status > 0) {
305  struct gpioevent_data event_data;
306  FwSizeType read_bytes = static_cast<FwSizeType>(::read(this->m_fd, &event_data, sizeof event_data));
307  if (read_bytes == sizeof event_data) {
308  Os::RawTime timestamp;
309  timestamp.now();
310  this->gpioInterrupt_out(0, timestamp);
311  }
312  // A read error occurred
313  else {
314  this->log_WARNING_HI_InterruptReadError(static_cast<U32>(sizeof event_data),
315  static_cast<U32>(read_bytes));
316  }
317  }
318  // An error of some kind occurred
319  else if (status < 0) {
320  this->log_WARNING_HI_PollingError(static_cast<I32>(errno));
321  }
322  }
323 }
324 
325 } // end namespace Drv
#define FW_ASSERT(...)
Definition: Assert.hpp:14
PlatformIntType NATIVE_INT_TYPE
Definition: BasicTypes.h:55
int PlatformIntType
DefaultTypes.hpp provides fallback defaults for the platform types.
PlatformAssertArgType FwAssertArgType
Definition: FpConfig.h:39
PlatformSizeType FwSizeType
Definition: FpConfig.h:35
C++-compatible configuration header for fprime configuration.
@ INVALID_MODE
Operation not permitted with current configuration.
@ OP_OK
Operation succeeded.
void log_DIAGNOSTIC_OpenChip(const Fw::StringBase &chip, const Fw::StringBase &chipLabel, U32 pin, const Fw::StringBase &pinMessage)
Log event OpenChip.
void log_WARNING_HI_OpenPinError(const Fw::StringBase &chip, U32 pin, const Fw::StringBase &pinMessage, Os::FileStatus status)
Log event OpenPinError.
void log_WARNING_HI_OpenChipError(const Fw::StringBase &chip, Os::FileStatus status)
Log event OpenChipError.
void log_WARNING_HI_InterruptReadError(U32 expected, U32 got)
Log event InterruptReadError.
void log_WARNING_HI_PollingError(I32 error_number)
Log event PollingError.
void gpioInterrupt_out(FwIndexType portNum, Os::RawTime &cycleStart)
Invoke output port gpioInterrupt.
static constexpr FwSizeType GPIO_POLL_TIMEOUT
Os::File::Status open(const char *device, const U32 gpio, const GpioConfiguration &configuration, const Fw::Logic &default_state=Fw::Logic::LOW)
open a GPIO pin for use in the system
GpioConfiguration
configure the GPIO pin
@ GPIO_INPUT
Input GPIO pin for direct reading.
@ GPIO_INTERRUPT_FALLING_EDGE
Input GPIO pin triggers interrupt port on falling edge.
@ GPIO_INTERRUPT_BOTH_RISING_AND_FALLING_EDGES
Input GPIO pin triggers interrupt port on both edges.
@ GPIO_INTERRUPT_RISING_EDGE
Input GPIO pin triggers interrupt port on rising edge.
@ GPIO_OUTPUT
Output GPIO pin for direct writing.
Logic states.
Definition: LogicEnumAc.hpp:19
@ LOW
Logic low state.
Definition: LogicEnumAc.hpp:33
@ HIGH
Logic high state.
Definition: LogicEnumAc.hpp:35
void format(const CHAR *formatString,...)
write formatted string to buffer
Definition: StringBase.cpp:56
FileHandle * getHandle() override
returns the raw file handle
Definition: File.cpp:184
Os::FileInterface::Status open(const char *path, Mode mode)
open file with supplied path and mode
Definition: File.cpp:45
@ OP_OK
Operation was successful.
Definition: File.hpp:30
FPP shadow-enum representing Os::File::Status.
T
The raw enum type.
Status now() override
Get the current time.
Definition: RawTime.cpp:36
U32 configuration_to_event_flags(Drv::LinuxGpioDriver::GpioConfiguration configuration)
Drv::GpioStatus errno_to_gpio_status(PlatformIntType errno_input)
U32 configuration_to_handler_flags(Drv::LinuxGpioDriver::GpioConfiguration configuration)
Os::File::Status errno_to_file_status(PlatformIntType errno_input)
char * string_copy(char *destination, const char *source, FwSizeType num)
copy string with null-termination guaranteed
Definition: StringUtils.cpp:6
@ OP_OK
Operation succeeded.
Definition: Os.hpp:26
@ OTHER_ERROR
A catch-all for other errors. Have to look in implementation-specific code.
@ NO_SPACE
No space left on the device for writing.