QSocketNotifier and libgpiod on Raspberry Pi
-
Hi,
I am using libgpiod and Qt 6.8.3 on my Raspberry Pi to access the GPIO pins and would like to use a QSocketNotifier to get informed whenever the signal an a given GPIO pin changes.
In the constructor of my Sampler object I have got this code:
m_gpioChip = gpiod_chip_open_by_name("gpiochip0"); m_retrace = gpiod_chip_get_line(m_gpioChip, 26); gpiod_line_request_falling_edge_events(m_retrace, "display"); m_fdRetrace = gpiod_line_event_get_fd(m_retrace); m_notifier = new QSocketNotifier(m_fdRetrace, QSocketNotifier::Read, this); connect(m_notifier, &QSocketNotifier::activated, this, &Sampler::onRetrace);The signature of onRetrace is
void Sampler::onRetrace(QSocketDescriptor socket, QSocketNotifier::Type type)and corresponds to what I have found in the documentatin.
However, on Retrace gets never called. I have also tried the QSocketNotifier::Exception type and different pins but this does not change anything.
My question is: is this kind of use of QSocketNotifier possible at all or have I made a mistake in my code? The poll() function works, but would like to avoid using it because it blocks the worker thread.Thanks,
Ralf
-
Hi,
I haven't used that library yet but I am wondering: does it implement the events supported by QSocketNotifier ? From a brief look at their example I am not sure about that.
Depending on your needs using a QThread and poll might be the easier route. -
Hi,
I haven't used that library yet but I am wondering: does it implement the events supported by QSocketNotifier ? From a brief look at their example I am not sure about that.
Depending on your needs using a QThread and poll might be the easier route. -
Would it be possible for you to provide a minimal compilable example using QSocketNotifier so other people may explore this issue ?
-
Would it be possible for you to provide a minimal compilable example using QSocketNotifier so other people may explore this issue ?
Hi,
I have set up a Raspberry Pi with the most recent OS (Trixie) that comes with libgpiod version 2.2.1. This version seems to work. I have created a test class "GpioWatcher". The signal "activated" is sent when an event at the pin occurs. I know that it is just a hack and not good code and there are certainly better ways to do it but it was just to test if QSocketNotifier works with this version of the library.
class GpioWatcher : public QObject { Q_OBJECT public: enum class Edge { Rising, Falling, Both }; explicit GpioWatcher(const QString& chipPath, uint lineOffset, Edge edge, QObject* parent = nullptr); ~GpioWatcher(); private slots: void handleGpioEvent(); private: void setupGpio(const QString& chipPath, uint lineOffset, Edge edge); private: struct gpiod_chip* m_chip; struct gpiod_line_request* m_request; gpiod_edge_event_buffer* m_eventBuffer; QSocketNotifier* m_notifier; signals: void activated(); };GpioWatcher::GpioWatcher(const QString& chipPath, uint lineOffset, Edge edge, QObject* parent) : QObject{parent} , m_chip{nullptr} , m_request{nullptr} , m_eventBuffer{nullptr} , m_notifier{nullptr} { setupGpio(chipPath, lineOffset, edge); m_eventBuffer = gpiod_edge_event_buffer_new(4); if (!m_eventBuffer) { throw std::runtime_error("Failed to create edge event buffer"); } int fd = gpiod_line_request_get_fd(m_request); m_notifier = new QSocketNotifier(fd, QSocketNotifier::Read, this); connect(m_notifier, &QSocketNotifier::activated, this, &GpioWatcher::handleGpioEvent); } GpioWatcher::~GpioWatcher() { if (m_notifier) { m_notifier->setEnabled(false); } if (m_eventBuffer) { gpiod_edge_event_buffer_free(m_eventBuffer); } if (m_request) { gpiod_line_request_release(m_request); } if (m_chip) { gpiod_chip_close(m_chip); } } void GpioWatcher::setupGpio(const QString& chipPath, uint lineOffset, Edge edge) { m_chip = gpiod_chip_open(chipPath.toUtf8().constData()); if (!m_chip) { throw std::runtime_error("Failed to open GPIO chip"); } gpiod_line_settings* lineSettings = gpiod_line_settings_new(); gpiod_line_config* lineConfig = gpiod_line_config_new(); gpiod_request_config* requestConfig = gpiod_request_config_new(); gpiod_request_config_set_consumer(requestConfig, "GpioWatcher"); gpiod_line_settings_set_direction( lineSettings, GPIOD_LINE_DIRECTION_INPUT ); gpiod_line_edge edgeType; switch (edge) { case Edge::Rising: edgeType = GPIOD_LINE_EDGE_RISING; break; case Edge::Falling: edgeType = GPIOD_LINE_EDGE_FALLING; break; case Edge::Both: default: edgeType = GPIOD_LINE_EDGE_BOTH; break; } gpiod_line_settings_set_edge_detection(lineSettings, edgeType); gpiod_line_config_add_line_settings( lineConfig, &lineOffset, 1, lineSettings ); m_request = gpiod_chip_request_lines( m_chip, requestConfig, lineConfig ); gpiod_line_settings_free(lineSettings); gpiod_line_config_free(lineConfig); gpiod_request_config_free(requestConfig); if (!m_request) { throw std::runtime_error("Failed to request GPIO line"); } } void GpioWatcher::handleGpioEvent() { const int count = gpiod_line_request_read_edge_events( m_request, m_eventBuffer, gpiod_edge_event_buffer_get_capacity(m_eventBuffer) ); if (count < 0) { return; } for (int i = 0; i < count; ++i) { const gpiod_edge_event* event = gpiod_edge_event_buffer_get_event(m_eventBuffer, i); Q_UNUSED(event); emit activated(); } } -
Excellent ! Thanks for the feedback !
Since you have it working now, please mark the thread as solved using the "Topic Tools" button or the three dotted menu beside the answer you deem correct so other forum users may know a solution has been found :-)
-
D DL5EU has marked this topic as solved