F´ Flight Software - C/C++ Documentation
A framework for building embedded system applications to NASA flight quality standards.
Loading...
Searching...
No Matches
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>
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#include <type_traits>
24
25namespace Drv {
26
27
30 switch (errno_input) {
31 case 0:
33 break;
34 case EBADF:
36 break;
37 case EINVAL:
39 break;
40 case ENODEV:
42 break;
43 case ENOMEM:
45 break;
46 case EPERM:
48 break;
49 case ENXIO:
51 break;
52 // Cascades intended
53 case EFAULT:
54 case EWOULDBLOCK:
55 case EBUSY:
56 case EIO:
57 default:
59 break;
60 }
61 return status;
62}
63
66 switch (errno_input) {
67 case EBADF:
69 break;
70 case ENXIO:
72 break;
73 // Cascades intended
74 case EFAULT:
75 case EINVAL:
76 case EWOULDBLOCK:
77 case EBUSY:
78 case EIO:
79 default:
81 break;
82 }
83 return status;
84}
85
87 U32 flags = 0;
88 switch (configuration) {
90 flags = GPIOHANDLE_REQUEST_OUTPUT;
91 break;
92 // Cascade intended
97 flags = GPIOHANDLE_REQUEST_INPUT;
98 break;
99 default:
100 FW_ASSERT(0, static_cast<FwAssertArgType>(configuration));
101 break;
102 }
103 return flags;
104}
105
107 U32 flags = 0;
108 switch (configuration) {
110 flags = GPIOEVENT_REQUEST_RISING_EDGE;
111 break;
113 flags = GPIOEVENT_REQUEST_FALLING_EDGE;
114 break;
116 flags = GPIOEVENT_REQUEST_RISING_EDGE | GPIOEVENT_REQUEST_FALLING_EDGE;
117 break;
118 default:
119 FW_ASSERT(0, static_cast<FwAssertArgType>(configuration));
120 break;
121 }
122 return flags;
123}
124
125LinuxGpioDriver ::~LinuxGpioDriver() {
126 (void) ::close(this->m_fd);
127}
128
129// ----------------------------------------------------------------------
130// Handler implementations for user-defined typed input ports
131// ----------------------------------------------------------------------
132
133Os::File::Status LinuxGpioDriver ::setupLineHandle(const PlatformIntType chip_descriptor,
134 const U32 gpio,
135 const GpioConfiguration& configuration,
136 const Fw::Logic& default_state,
137 PlatformIntType& fd) {
139 // Set up the GPIO request
140 struct gpiohandle_request request;
141 (void) ::memset(&request, 0, sizeof request);
142 request.lineoffsets[0] = gpio;
143 Fw::StringUtils::string_copy(request.consumer_label, FW_OPTIONAL_NAME(this->getObjName()),
144 static_cast<FwSizeType>(sizeof request.consumer_label));
145 request.default_values[0] = (default_state == Fw::Logic::HIGH) ? 1 : 0;
146 request.fd = -1;
147 request.lines = 1;
148 request.flags = configuration_to_handler_flags(configuration);
149
150 errno = 0;
151 PlatformIntType return_value = ioctl(chip_descriptor, GPIO_GET_LINEHANDLE_IOCTL, &request);
152 fd = request.fd;
153 if (return_value != 0) {
154 status = errno_to_file_status(errno);
155 fd = -1;
156 }
157 return status;
158}
159
160Os::File::Status LinuxGpioDriver ::setupLineEvent(const PlatformIntType chip_descriptor,
161 const U32 gpio,
162 const GpioConfiguration& configuration,
163 PlatformIntType& fd) {
165 // Set up the GPIO request
166 struct gpioevent_request event;
167 (void) ::memset(&event, 0, sizeof event);
168 event.lineoffset = gpio;
169 Fw::StringUtils::string_copy(event.consumer_label, FW_OPTIONAL_NAME(this->getObjName()),
170 static_cast<FwSizeType>(sizeof event.consumer_label));
171 event.fd = -1;
172 event.handleflags = configuration_to_handler_flags(configuration);
173 event.eventflags = configuration_to_event_flags(configuration);
174 errno = 0;
175 PlatformIntType return_value = ioctl(chip_descriptor, GPIO_GET_LINEEVENT_IOCTL, &event);
176 fd = event.fd;
177 if (return_value != 0) {
178 status = errno_to_file_status(errno);
179 fd = -1;
180 }
181 return status;
182}
183
184Os::File::Status LinuxGpioDriver ::open(const char* device,
185 const U32 gpio,
186 const GpioConfiguration& configuration,
187 const Fw::Logic& default_state) {
189 Os::File chip_file;
190 FW_ASSERT(device != nullptr);
191 FW_ASSERT(configuration < MAX_GPIO_CONFIGURATION and configuration >= 0, static_cast<FwAssertArgType>(configuration));
192
193 // Open chip file and check for success
194 status = chip_file.open(device, Os::File::Mode::OPEN_WRITE);
195 if (status != Os::File::OP_OK) {
196 this->log_WARNING_HI_OpenChipError(Fw::String(device), Os::FileStatus(static_cast<Os::FileStatus::T>(status)));
197 return status;
198 }
199 // Read chip information and check for correctness
200 PlatformIntType chip_descriptor =
201 reinterpret_cast<Os::Posix::File::PosixFileHandle*>(chip_file.getHandle())->m_file_descriptor;
202 struct gpiochip_info chip_info;
203 (void) ::memset(&chip_info, 0, sizeof chip_info);
204 PlatformIntType return_value = ioctl(chip_descriptor, GPIO_GET_CHIPINFO_IOCTL, &chip_info);
205 if (return_value != 0) {
206 status = errno_to_file_status(errno);
207 this->log_WARNING_HI_OpenChipError(Fw::String(device), Os::FileStatus(static_cast<Os::FileStatus::T>(status)));
208 return status;
209 }
210 // Check if the GPIO line exists
211 if (gpio >= chip_info.lines) {
212 this->log_WARNING_HI_OpenPinError(Fw::String(device), gpio, Fw::String("Does Not Exist"),
213 Os::FileStatus(static_cast<Os::FileStatus::T>(status)));
214 return status;
215 }
216 Fw::String pin_message("Unknown");
217 struct gpioline_info pin_info;
218 (void) ::memset(&pin_info, 0, sizeof pin_info);
219 pin_info.line_offset = gpio;
220 return_value = ioctl(chip_descriptor, GPIO_GET_LINEINFO_IOCTL, &pin_info);
221 if (return_value == 0) {
222 const bool has_consumer = pin_info.consumer[0] != '\0';
223 pin_message.format("%s%s%s", pin_info.name, has_consumer ? " with current consumer " : "",
224 has_consumer ? pin_info.consumer : "");
225 }
226
227 // Set up pin and set file descriptor for it
228 PlatformIntType pin_fd = -1;
229 switch (configuration) {
230 // Cascade intended
231 case GPIO_OUTPUT:
232 case GPIO_INPUT:
233 status = this->setupLineHandle(chip_descriptor, gpio, configuration, default_state, pin_fd);
234 break;
235 // Cascade intended
236 case GPIO_INTERRUPT_RISING_EDGE:
237 case GPIO_INTERRUPT_FALLING_EDGE:
238 case GPIO_INTERRUPT_BOTH_RISING_AND_FALLING_EDGES:
239 status = this->setupLineEvent(chip_descriptor, gpio, configuration, pin_fd);
240 break;
241 default:
242 FW_ASSERT(0);
243 break;
244 }
245 // Final status check
246 if (status != Os::File::Status::OP_OK) {
247 this->log_WARNING_HI_OpenPinError(Fw::String(device), gpio, pin_message,
248 Os::FileStatus(static_cast<Os::FileStatus::T>(status)));
249 } else {
250 this->log_DIAGNOSTIC_OpenChip(Fw::String(chip_info.name), Fw::String(chip_info.label),
251 gpio, pin_message);
252 this->m_fd = pin_fd;
253 this->m_configuration = configuration;
254 }
255 return status;
256}
257
258Drv::GpioStatus LinuxGpioDriver ::gpioRead_handler(const NATIVE_INT_TYPE portNum, Fw::Logic& state) {
260 if (this->m_configuration == GpioConfiguration::GPIO_INPUT) {
261 struct gpiohandle_data values;
262 (void) ::memset(&values, 0, sizeof values);
263 PlatformIntType return_value = ioctl(this->m_fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &values);
264 if (return_value != 0) {
265 status = errno_to_gpio_status(errno);
266 } else {
267 state = values.values[0] ? Fw::Logic::HIGH : Fw::Logic::LOW;
268 status = Drv::GpioStatus::OP_OK;
269 }
270 }
271 return status;
272}
273
274Drv::GpioStatus LinuxGpioDriver ::gpioWrite_handler(const NATIVE_INT_TYPE portNum, const Fw::Logic& state) {
276 if (this->m_configuration == GpioConfiguration::GPIO_OUTPUT) {
277 struct gpiohandle_data values;
278 (void) ::memset(&values, 0, sizeof values);
279 values.values[0] = (state == Fw::Logic::HIGH) ? 1 : 0;
280 PlatformIntType return_value = ioctl(this->m_fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &values);
281 if (return_value != 0) {
282 status = errno_to_gpio_status(errno);
283 } else {
284 status = Drv::GpioStatus::OP_OK;
285 }
286 }
287 return status;
288}
289
290void LinuxGpioDriver ::pollLoop() {
291 // Ensure size of FwSizeType is large enough to fit the necessary ranges
292 // NOTE: casts to unsigned types for int and ssize_t are made to avoid sign-compare warning;
293 // in both cases the cast is safe because max() returns nonnegative value.
294 static_assert(GPIO_POLL_TIMEOUT < static_cast<unsigned int>(std::numeric_limits<int>::max()), "Poll timeout would overflow");
295 static_assert(sizeof(struct gpioevent_data) < std::numeric_limits<FwSizeType>::max(), "FwSizeType too small");
296 using unsigned_ssize_t = std::make_unsigned<ssize_t>::type;
297 static_assert(static_cast<unsigned_ssize_t>(std::numeric_limits<ssize_t>::max()) <= std::numeric_limits<FwSizeType>::max(), "FwSizeType too small");
298 // Setup poll information
299 pollfd file_descriptors[1];
300 // Loop forever
301 while (this->getRunning()) {
302 // Setup polling
303 (void) ::memset(file_descriptors, 0, sizeof file_descriptors);
304 file_descriptors[0].fd = this->m_fd;
305 file_descriptors[0].events = POLLIN; // Ask for read data available
306 // Poll for fd bing ready
307 PlatformIntType status = ::poll(file_descriptors, 1, static_cast<int>(GPIO_POLL_TIMEOUT));
308 // Check for some file descriptor to be ready
309 if (status > 0) {
310 struct gpioevent_data event_data;
311 FwSizeType read_bytes = static_cast<FwSizeType>(::read(this->m_fd, &event_data, sizeof event_data));
312 if (read_bytes == sizeof event_data) {
313 Os::RawTime timestamp;
314 timestamp.now();
315 this->gpioInterrupt_out(0, timestamp);
316 }
317 // A read error occurred
318 else {
319 this->log_WARNING_HI_InterruptReadError(static_cast<U32>(sizeof event_data),
320 static_cast<U32>(read_bytes));
321 }
322 }
323 // An error of some kind occurred
324 else if (status < 0) {
325 this->log_WARNING_HI_PollingError(static_cast<I32>(errno));
326 }
327 }
328}
329
330} // 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
#define FW_OPTIONAL_NAME(name)
Definition FpConfig.h:157
PlatformSizeType FwSizeType
Definition FpConfig.h:35
C++-compatible configuration header for fprime configuration.
@ INVALID_MODE
Operation not permitted with current configuration.
@ NOT_OPENED
Pin was never opened.
@ UNKNOWN_ERROR
An unknown error occurred.
@ OP_OK
Operation succeeded.
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.
@ LOW
Logic low state.
@ HIGH
Logic high state.
void format(const CHAR *formatString,...)
write formatted string to buffer
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
@ NO_SPACE
No space left.
Definition File.hpp:32
@ INVALID_ARGUMENT
Invalid argument passed in.
Definition File.hpp:39
@ INVALID_MODE
Mode for file access is invalid for current operation.
Definition File.hpp:38
@ NO_PERMISSION
No permission to read/write file.
Definition File.hpp:33
@ NOT_OPENED
file hasn't been opened yet
Definition File.hpp:35
@ OTHER_ERROR
A catch-all for other errors. Have to look in implementation-specific code.
Definition File.hpp:40
@ OP_OK
Operation was successful.
Definition File.hpp:30
@ DOESNT_EXIST
File doesn't exist (for read)
Definition File.hpp:31
@ OPEN_WRITE
Open file for writing.
Definition File.hpp:23
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