Skip to content

Commit 90a3150

Browse files
committed
Add support for inverted (active low) logic in GPIO plugin
1 parent f69e4a6 commit 90a3150

5 files changed

Lines changed: 67 additions & 4 deletions

File tree

plugins/gpio/GPIODriver.cpp

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <sys/types.h>
2929
#include <unistd.h>
3030

31+
#include <algorithm>
3132
#include <sstream>
3233
#include <string>
3334
#include <vector>
@@ -43,6 +44,7 @@ namespace gpio {
4344
const char GPIODriver::GPIO_BASE_DIR[] = "/sys/class/gpio/gpio";
4445

4546
using ola::thread::MutexLocker;
47+
using std::find;
4648
using std::string;
4749
using std::vector;
4850

@@ -121,7 +123,9 @@ bool GPIODriver::SetupGPIO() {
121123
* echo N > /sys/class/gpio/export
122124
* That requires root access.
123125
*/
124-
const string direction("out");
126+
const string normal_direction("low");
127+
const string inverted_direction("high");
128+
const string* direction = nullptr;
125129
bool failed = false;
126130
vector<uint16_t>::const_iterator iter = m_options.gpio_pins.begin();
127131
for (; iter != m_options.gpio_pins.end(); ++iter) {
@@ -133,7 +137,12 @@ bool GPIODriver::SetupGPIO() {
133137
break;
134138
}
135139

136-
GPIOPin pin = {pin_fd, UNDEFINED, false};
140+
// Check if pin is in the inverted pin list
141+
bool inverted = (find(m_options.gpio_inverted_pins.begin(),
142+
m_options.gpio_inverted_pins.end(),
143+
(*iter)) != m_options.gpio_inverted_pins.end());
144+
145+
GPIOPin pin = {pin_fd, UNDEFINED, false, inverted};
137146

138147
// Set dir
139148
str.str("");
@@ -143,7 +152,16 @@ bool GPIODriver::SetupGPIO() {
143152
failed = true;
144153
break;
145154
}
146-
if (write(fd, direction.c_str(), direction.size()) < 0) {
155+
// Assign correct initial state
156+
if (inverted) {
157+
direction = &inverted_direction;
158+
} else {
159+
direction = &normal_direction;
160+
}
161+
162+
OLA_DEBUG << "Configuring GPIO pin " << static_cast<int>(*iter)
163+
<< " with " << ( inverted ? "inverted" : "normal" ) << " logic";
164+
if (write(fd, direction->c_str(), direction->size()) < 0) {
147165
OLA_WARN << "Failed to enable output on " << str.str() << " : "
148166
<< strerror(errno);
149167
failed = true;
@@ -190,7 +208,14 @@ bool GPIODriver::UpdateGPIOPins(const DmxBuffer &dmx) {
190208

191209
// Change the pin state if required.
192210
if (action != NO_CHANGE) {
193-
char data = (action == TURN_ON ? '1' : '0');
211+
char data;
212+
bool state = (action == TURN_ON);
213+
// Handle inverted logic appropriately
214+
if (m_gpio_pins[i].inverted) {
215+
state = !state;
216+
}
217+
// Convert to char and write to sysfs
218+
data = (state ? '0' : '1');
194219
if (write(m_gpio_pins[i].fd, &data, sizeof(data)) < 0) {
195220
OLA_WARN << "Failed to toggle GPIO pin " << i << ", fd "
196221
<< static_cast<int>(m_gpio_pins[i].fd) << ": "

plugins/gpio/GPIODriver.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ class GPIODriver : private ola::thread::Thread {
4949
*/
5050
std::vector<uint16_t> gpio_pins;
5151

52+
/**
53+
* @brief A list of gpio_pins which use inverted logic.
54+
*/
55+
std::vector<uint16_t> gpio_inverted_pins;
56+
5257
/**
5358
* @brief The DMX512 start address of the first pin
5459
*/
@@ -108,6 +113,7 @@ class GPIODriver : private ola::thread::Thread {
108113
int fd;
109114
GPIOState state;
110115
bool last_value;
116+
bool inverted;
111117
};
112118

113119
typedef std::vector<GPIOPin> GPIOPins;

plugins/gpio/GPIOPlugin.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
#include "plugins/gpio/GPIOPlugin.h"
2222

23+
#include <algorithm>
2324
#include <memory>
2425
#include <string>
2526
#include <vector>
@@ -35,10 +36,12 @@ namespace plugin {
3536
namespace gpio {
3637

3738
using std::auto_ptr;
39+
using std::find;
3840
using std::string;
3941
using std::vector;
4042

4143
const char GPIOPlugin::GPIO_PINS_KEY[] = "gpio_pins";
44+
const char GPIOPlugin::GPIO_PINS_INVERTED_KEY[] = "gpio_pins_inverted";
4245
const char GPIOPlugin::GPIO_SLOT_OFFSET_KEY[] = "gpio_slot_offset";
4346
const char GPIOPlugin::GPIO_TURN_OFF_KEY[] = "gpio_turn_off";
4447
const char GPIOPlugin::GPIO_TURN_ON_KEY[] = "gpio_turn_on";
@@ -87,6 +90,28 @@ bool GPIOPlugin::StartHook() {
8790
options.gpio_pins.push_back(pin);
8891
}
8992

93+
pin_list.clear();
94+
StringSplit(m_preferences->GetValue(GPIO_PINS_INVERTED_KEY), &pin_list, ",");
95+
iter = pin_list.begin();
96+
for (; iter != pin_list.end(); ++iter) {
97+
if (iter->empty()) {
98+
continue;
99+
}
100+
101+
uint16_t pin;
102+
if (!StringToInt(*iter, &pin)) {
103+
OLA_WARN << "Invalid value for GPIO pin to invert: " << *iter;
104+
return false;
105+
}
106+
107+
if (find(pin_list.begin(), pin_list.end(), (*iter)) == pin_list.end()) {
108+
OLA_WARN << "Inverted pin " << (*iter) << " not found in GPIO pin list";
109+
return false;
110+
}
111+
112+
options.gpio_inverted_pins.push_back(pin);
113+
}
114+
90115
if (options.gpio_pins.empty()) {
91116
return true;
92117
}
@@ -124,6 +149,9 @@ bool GPIOPlugin::SetDefaultPreferences() {
124149
save |= m_preferences->SetDefaultValue(GPIO_PINS_KEY,
125150
StringValidator(),
126151
"");
152+
save |= m_preferences->SetDefaultValue(GPIO_PINS_INVERTED_KEY,
153+
StringValidator(),
154+
"");
127155
save |= m_preferences->SetDefaultValue(GPIO_SLOT_OFFSET_KEY,
128156
UIntValidator(1, DMX_UNIVERSE_SIZE),
129157
"1");

plugins/gpio/GPIOPlugin.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ class GPIOPlugin: public ola::Plugin {
5555
bool SetDefaultPreferences();
5656

5757
static const char GPIO_PINS_KEY[];
58+
static const char GPIO_PINS_INVERTED_KEY[];
5859
static const char GPIO_SLOT_OFFSET_KEY[];
5960
static const char GPIO_TURN_OFF_KEY[];
6061
static const char GPIO_TURN_ON_KEY[];

plugins/gpio/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ The offset (start address) of the GPIO pins is configurable.
1111
`gpio_pins = [int]`
1212
The list of GPIO pins to control, each pin is mapped to a DMX512 slot.
1313

14+
`gpio_pins_inverted = [int]`
15+
The list of GPIO pins listed under `gpio_pins` which use inverted logic.
16+
1417
`gpio_slot_offset = <int>`
1518
The DMX512 slot for the first pin. Slots are indexed from 1.
1619

0 commit comments

Comments
 (0)