Raspberry pi GPIO sysfs, fopen: разрешение отклонено

Я пытаюсь использовать GPIO Raspberry Pi через sysfs, используя язык C, но я продолжаю получать fopen: Permission denied при попытке изменить направление линии GPIO.
Проблема возникает при попытке открыть файл "/sys/class/gpio/gpio18/direction".

Примечания:

  • Если я запускаю программу во второй раз, она работает нормально.
  • Если я экспортирую линию GPIO вручную, а затем выполняю ее, она работает нормально.
  • Если я запускаю программу как root, она работает нормально.
  • Мой текущий пользователь является частью группы gpio и должен иметь все разрешения.

Обычно мне нужно вставить булавку, которую я хочу использовать в "/sys/class/gpio/export".
А затем мне нужно задать его направление (выход/ввод), написав 1 или 0 в "/sys/class/gpio/gpio18/direction".

Чтобы добиться этого программно, я использую следующий код

#include "io.h"
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>

int main(int argc, char const* argv[]) {
  // export line
  FILE* p_gpio_line;
  if ((p_gpio_line = fopen("/sys/class/gpio/export", "w")) == NULL) {
    printf("Cannot open export file.\n");
    perror("fopen");
    exit(1);
  }
  rewind(p_gpio_line);
  fwrite("18", sizeof(char), 2, p_gpio_line);
  fclose(p_gpio_line);

  // set direction
  FILE* p_gpio_direction;
  if ((p_gpio_direction = fopen("/sys/class/gpio/gpio18/direction", "r+")) == NULL) {
    printf("Cannot open direction file.\n");
    perror("fopen");
    exit(1);
  }
  return 0;
}

В первый раз, когда он выполняется, я получаю

Cannot open direction file.
fopen: Permission denied

Второй раз работает нормально, потому что линия GPIO экспортируется до выполнения программы (из первого исполнения)
Он также отлично работает, если я вручную экспортирую линию GPIO из терминала.

Не используйте perror(), если только сразу после неудачной функции. printf() может измениться errno, поэтому perror() сообщение не имеет смысла.

dimich 30.04.2023 02:44

Используйте libgpiod и его ресурсы, не используйте sysfs для GPIO.

0andriy 02.05.2023 17:13
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
93
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Мой комментарий о perror() остается в силе, но действительно в вашем примере fopen() возвращает EACCES («Отказано в доступе»).

Группа gpio и разрешения для /sys/class/gpio специфичны для дистрибутива Raspberry Pi. Они устанавливаются правилом udev в /etc/udev/rules.d/99-com.rules:

SUBSYSTEM= = "gpio", ACTION= = "add", PROGRAM = "/bin/sh -c 'chgrp -R gpio /sys%p && chmod -R g=u /sys%p'"

Правило Udev применяется асинхронно после появления файла direction. Вы пытаетесь открыть файл, пока разрешения еще не установлены.

Я бы предложил использовать интерфейс GPIO символьного устройства с libgpiod вместо устаревшего интерфейса sysfs.

Если вы все еще хотите использовать интерфейс sysfs, простое решение — повторять попытку fopen() до тех пор, пока она не увенчается успехом (или с ошибкой, отличной от EACCES, или тайм-аутом). Например:

// Open timeout, ms
#define DIR_OPEN_TIMEOUT_MS 3000
// Delay between retries, ms
#define DIR_POLL_DELAY_MS   100

...
    // set direction
    FILE* p_gpio_direction;
    unsigned int retries_left = DIR_OPEN_TIMEOUT_MS / DIR_POLL_DELAY_MS;
    while (1)
    {
        p_gpio_direction = fopen("/sys/class/gpio/gpio18/direction", "r+");

        if (p_gpio_direction)
            break;

        if ((errno != EACCES) || (retries_left-- == 0)) {
            printf("Cannot open direction file: %m\n");
            exit(1);
        }

        const struct timespec rqt = {
            .tv_sec  = DIR_POLL_DELAY_MS / 1000,
            .tv_nsec = 1000000L * (DIR_POLL_DELAY_MS % 1000)
        };
        if (nanosleep(&rqt, NULL) == -1)
            perror("nanosleep()");
    }
...

Это объясняет это, спасибо, один вопрос: если я хочу по-прежнему использовать sysfs, как я могу дождаться применения правила перед доступом к файлу direction?

First dev 30.04.2023 19:18

Это не лучшее направление для решения проблемы. Нам нужно включить libgpiod для GPIO, sysfs использовать нельзя.

0andriy 02.05.2023 17:12

Другие вопросы по теме