diff --git a/plugins/gpio/GPIODriver.cpp b/plugins/gpio/GPIODriver.cpp index 2d12aec1c0..4d19e116fa 100644 --- a/plugins/gpio/GPIODriver.cpp +++ b/plugins/gpio/GPIODriver.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -43,6 +44,7 @@ namespace gpio { const char GPIODriver::GPIO_BASE_DIR[] = "/sys/class/gpio/gpio"; using ola::thread::MutexLocker; +using std::find; using std::string; using std::vector; @@ -122,7 +124,9 @@ bool GPIODriver::SetupGPIO() { * echo N > /sys/class/gpio/export * That requires root access. */ - const string direction("out"); + const string normal_direction("low"); + const string inverted_direction("high"); + const string* direction = nullptr; bool failed = false; vector::const_iterator iter = m_options.gpio_pins.begin(); for (; iter != m_options.gpio_pins.end(); ++iter) { @@ -134,7 +138,12 @@ bool GPIODriver::SetupGPIO() { break; } - GPIOPin pin = {pin_fd, UNDEFINED, false}; + // Check if pin is in the inverted pin list + bool inverted = (find(m_options.gpio_inverted_pins.begin(), + m_options.gpio_inverted_pins.end(), + (*iter)) != m_options.gpio_inverted_pins.end()); + + GPIOPin pin = {pin_fd, UNDEFINED, false, inverted}; // Set dir str.str(""); @@ -144,9 +153,19 @@ bool GPIODriver::SetupGPIO() { failed = true; break; } - if (write(fd, direction.c_str(), direction.size()) < 0) { - OLA_WARN << "Failed to enable output on " << str.str() << " : " - << strerror(errno); + // Assign correct initial state + if (inverted) { + direction = &inverted_direction; + } else { + direction = &normal_direction; + } + + OLA_DEBUG << "Configuring GPIO pin " << static_cast(*iter) + << " with " << (inverted ? "inverted" : "normal") << " logic"; + if (write(fd, direction->c_str(), direction->size()) < 0) { + OLA_WARN << "Failed to enable output on " << str.str() + << " with " << (inverted ? "inverted" : "normal") << " logic" + << " : " << strerror(errno); failed = true; } close(fd); @@ -191,7 +210,14 @@ bool GPIODriver::UpdateGPIOPins(const DmxBuffer &dmx) { // Change the pin state if required. if (action != NO_CHANGE) { - char data = (action == TURN_ON ? '1' : '0'); + char data; + bool state = (action == TURN_ON); + // Handle inverted logic appropriately + if (m_gpio_pins[i].inverted) { + state = !state; + } + // Convert to char and write to sysfs + data = (state ? '1' : '0'); if (write(m_gpio_pins[i].fd, &data, sizeof(data)) < 0) { OLA_WARN << "Failed to toggle GPIO pin " << i << ", fd " << static_cast(m_gpio_pins[i].fd) << ": " diff --git a/plugins/gpio/GPIODriver.h b/plugins/gpio/GPIODriver.h index 6906ad87ad..f6f5c257ce 100644 --- a/plugins/gpio/GPIODriver.h +++ b/plugins/gpio/GPIODriver.h @@ -49,6 +49,11 @@ class GPIODriver : private ola::thread::Thread { */ std::vector gpio_pins; + /** + * @brief A list of gpio_pins which use inverted logic. + */ + std::vector gpio_inverted_pins; + /** * @brief The DMX512 start address of the first pin */ @@ -108,6 +113,7 @@ class GPIODriver : private ola::thread::Thread { int fd; GPIOState state; bool last_value; + bool inverted; }; typedef std::vector GPIOPins; diff --git a/plugins/gpio/GPIOPlugin.cpp b/plugins/gpio/GPIOPlugin.cpp index 5d9bbfb8d3..a166f5d12a 100644 --- a/plugins/gpio/GPIOPlugin.cpp +++ b/plugins/gpio/GPIOPlugin.cpp @@ -20,6 +20,7 @@ #include "plugins/gpio/GPIOPlugin.h" +#include #include #include #include @@ -35,10 +36,12 @@ namespace plugin { namespace gpio { using std::auto_ptr; +using std::find; using std::string; using std::vector; const char GPIOPlugin::GPIO_PINS_KEY[] = "gpio_pins"; +const char GPIOPlugin::GPIO_PINS_INVERTED_KEY[] = "gpio_pins_inverted"; const char GPIOPlugin::GPIO_SLOT_OFFSET_KEY[] = "gpio_slot_offset"; const char GPIOPlugin::GPIO_TURN_OFF_KEY[] = "gpio_turn_off"; const char GPIOPlugin::GPIO_TURN_ON_KEY[] = "gpio_turn_on"; @@ -87,6 +90,28 @@ bool GPIOPlugin::StartHook() { options.gpio_pins.push_back(pin); } + pin_list.clear(); + StringSplit(m_preferences->GetValue(GPIO_PINS_INVERTED_KEY), &pin_list, ","); + iter = pin_list.begin(); + for (; iter != pin_list.end(); ++iter) { + if (iter->empty()) { + continue; + } + + uint16_t pin; + if (!StringToInt(*iter, &pin)) { + OLA_WARN << "Invalid value for GPIO pin to invert: " << *iter; + return false; + } + + if (find(pin_list.begin(), pin_list.end(), (*iter)) == pin_list.end()) { + OLA_WARN << "Inverted pin " << (*iter) << " not found in GPIO pin list"; + return false; + } + + options.gpio_inverted_pins.push_back(pin); + } + if (options.gpio_pins.empty()) { return true; } @@ -124,6 +149,9 @@ bool GPIOPlugin::SetDefaultPreferences() { save |= m_preferences->SetDefaultValue(GPIO_PINS_KEY, StringValidator(), ""); + save |= m_preferences->SetDefaultValue(GPIO_PINS_INVERTED_KEY, + StringValidator(), + ""); save |= m_preferences->SetDefaultValue(GPIO_SLOT_OFFSET_KEY, UIntValidator(1, DMX_UNIVERSE_SIZE), "1"); diff --git a/plugins/gpio/GPIOPlugin.h b/plugins/gpio/GPIOPlugin.h index b66ea568e5..06267a6819 100644 --- a/plugins/gpio/GPIOPlugin.h +++ b/plugins/gpio/GPIOPlugin.h @@ -55,6 +55,7 @@ class GPIOPlugin: public ola::Plugin { bool SetDefaultPreferences(); static const char GPIO_PINS_KEY[]; + static const char GPIO_PINS_INVERTED_KEY[]; static const char GPIO_SLOT_OFFSET_KEY[]; static const char GPIO_TURN_OFF_KEY[]; static const char GPIO_TURN_ON_KEY[]; diff --git a/plugins/gpio/README.md b/plugins/gpio/README.md index de7da02a82..e1e18c2391 100644 --- a/plugins/gpio/README.md +++ b/plugins/gpio/README.md @@ -11,6 +11,9 @@ The offset (start address) of the GPIO pins is configurable. `gpio_pins = [int]` The list of GPIO pins to control, each pin is mapped to a DMX512 slot. +`gpio_pins_inverted = [int]` +The list of GPIO pins listed under `gpio_pins` which use inverted logic. + `gpio_slot_offset = ` The DMX512 slot for the first pin. Slots are indexed from 1.