diff --git a/examples/gpio-interrupt.c b/examples/gpio-interrupt.c index 099ae69..de9c698 100644 --- a/examples/gpio-interrupt.c +++ b/examples/gpio-interrupt.c @@ -1,21 +1,17 @@ -/* Направляет в стандартный вывод данные полученные с - параллельной 8-битной шины Raspberry Pi4. Собирать внутри папки WiringPi/examples - командой make really-all. - +/* + Чтение данных с параллельной 8-битной шины Raspberry Pi 4 + и вывод в stdout (для передачи, например, в Go-сервер). + + Сборка (внутри WiringPi/examples): + make really-all + Использование: - ./gpio-interrupt # только stdout - ./gpio-interrupt /tmp/gpio.log # stdout + лог в файл - ./gpio-interrupt - # только лог в stdout (stderr) - - Предварительные условия: - - WiringPi должен быть собран из этой версии, в которую добавлена функция digitalReadPins() -make && make install + ./gpio-interrupt # только stdout + ./gpio-interrupt /tmp/log # stdout + лог в файл + ./gpio-interrupt - # лог в stderr -text -- WiringPi должен быть установлен из того deb-пакета который получен из этой версии -make debian && dpkg -i debian-template/WiringPi*.deb - -text + Требования: + - Используется модифицированный WiringPi с функцией digitalReadPins() */ #include @@ -29,185 +25,228 @@ text #include /* -жёлтый д0 -красный такт -чёрный д1 -синий д2 -зелёный д3 -оранжевый - общий + Подключение физические контакты на Raspberry pi4: + 29 - D0 + 7 - D1 + 22 - D2 + 18 - D3 + 37 - D4 + 35 - D5 + 33 - D6 + 31 - D7 + 36 - такт + 14 - GND */ -unsigned int wr_pin = 27; /** Вывод для сигнала записи */ -unsigned int pins[] = { 21, 7, 6, 5, 25, 24, 23, 22 }; /** Выводы для данных */ -const size_t out_buffer_len = 32U; /** Размер выходного буфера */ -const size_t fifo_buffer_len = 4096U; /** Размер буфера FIFO */ +unsigned int wr_pin = 27; // Пин сигнала записи (WR) +unsigned int pins[] = { 21, 7, 6, 5, 25, 24, 23, 22 }; // 8-битная шина данных (wPi) + +const size_t out_buffer_len = 32U; // Размер логируемого пакета +const size_t fifo_buffer_len = 4096U; // Размер FIFO буфера + +// ================= FIFO ================= struct fifo { -char *buffer; /** Буфер FIFO */ -size_t len; /** Длина буфера FIFO */ -size_t wri; /** Указатель записи FIFO */ -size_t rdi; /** Указатель чтения FIFO */ + char *buffer; + size_t len; + size_t wri; + size_t rdi; }; void fifo_reset(struct fifo* ff) { -ff->wri = 0U; -ff->rdi = 0U; + ff->wri = 0; + ff->rdi = 0; } bool fifo_init(struct fifo* ff, size_t len) { -ff->buffer = malloc(len); -ff->len = len; -fifo_reset(ff); -return ff->buffer != NULL; + ff->buffer = malloc(len); + ff->len = len; + fifo_reset(ff); + return ff->buffer != NULL; } void fifo_uninit(struct fifo* ff) { -free(ff->buffer); -ff->buffer = NULL; -fifo_reset(ff); -} - -bool fifo_is_full(struct fifo *ff) { -return ((ff->wri + 1U) % ff->len) == ff->rdi; + free(ff->buffer); + ff->buffer = NULL; + fifo_reset(ff); } size_t fifo_available(struct fifo *ff) { -bool v = ff->wri >= ff->rdi; -return (ff->wri - ff->rdi) * v + (ff->wri + ff->len - ff->rdi) * (!v); + if (ff->wri >= ff->rdi) + return ff->wri - ff->rdi; + else + return ff->wri + ff->len - ff->rdi; } bool fifo_can_write(struct fifo *ff, size_t len) { -return (ff->len - fifo_available(ff)) > len; + return (ff->len - fifo_available(ff)) > len; } bool fifo_can_read(struct fifo *ff, size_t len) { -return fifo_available(ff) >= len; + return fifo_available(ff) >= len; } bool fifo_try_read(struct fifo *ff, char* buffer, size_t len) { -if (!fifo_can_read(ff, len)) { -return false; -} -memcpy(buffer, &ff->buffer[ff->rdi], len); -ff->rdi = (ff->rdi + len) % ff->len; -return true; + if (!fifo_can_read(ff, len)) + return false; + + memcpy(buffer, &ff->buffer[ff->rdi], len); + ff->rdi = (ff->rdi + len) % ff->len; + return true; } bool fifo_try_write(struct fifo *ff, char* buffer, size_t len) { -if (!fifo_can_write(ff, len)) { -return false; -} -memcpy(&ff->buffer[ff->wri], buffer, len); -ff->wri = (ff->wri + len) % ff->len; -return true; + if (!fifo_can_write(ff, len)) + return false; + + memcpy(&ff->buffer[ff->wri], buffer, len); + ff->wri = (ff->wri + len) % ff->len; + return true; } +// ======================================= + static struct fifo isr_ff; +// Защита от дребезга (debounce) +static volatile struct timeval last_isr_time = {0, 0}; +static const long debounce_us = 5000; // 5 мс + +// Обработчик прерывания void isr_handle(void) { -char byte_read = 0x0f & digitalReadPins(pins, sizeof pins / sizeof pins[0]); -fifo_try_write(&isr_ff, &byte_read, 1); + struct timeval now; + gettimeofday(&now, NULL); + + long diff = (now.tv_sec - last_isr_time.tv_sec) * 1000000L + + (now.tv_usec - last_isr_time.tv_usec); + + if (diff < debounce_us) { + return; // игнорируем дребезг + } + + last_isr_time = now; + + // Читать 8 бит + char byte_read = 0xff & digitalReadPins(pins, sizeof pins / sizeof pins[0]); + + fifo_try_write(&isr_ff, &byte_read, 1); } +// ================= MAIN ================= + int main(int argc, char *argv[]) { -FILE *log_file = NULL; -const char *log_path = NULL; + FILE *log_file = NULL; + const char *log_path = NULL; -// Обработка аргументов командной строки -if (argc > 1) { -log_path = argv[1]; + // Обработка аргументов + if (argc > 1) { + log_path = argv[1]; -if (strcmp(log_path, "-") == 0) { - // Логировать в stderr (чтобы не мешать stdout) - log_file = stderr; - fprintf(stderr, "=== GPIO Monitor started (logging to stderr) ===\n"); -} else { - // Открываем файл для логирования - log_file = fopen(log_path, "a"); - if (!log_file) { - perror("Ошибка открытия лог-файла"); - exit(EXIT_FAILURE); - } - fprintf(stderr, "=== GPIO Monitor started (logging to %s) ===\n", log_path); - fprintf(log_file, "\n=== Session started: %ld ===\n", (long)time(NULL)); - fflush(log_file); -} -} else { -fprintf(stderr, "=== GPIO Monitor started (stdout only) ===\n"); -} + if (strcmp(log_path, "-") == 0) { + log_file = stderr; + fprintf(stderr, "=== Запуск GPIO-монитора (лог в stderr) ===\n"); + } else { + log_file = fopen(log_path, "a"); + if (!log_file) { + perror("Ошибка открытия лог-файла"); + exit(EXIT_FAILURE); + } + fprintf(stderr, "=== Запуск GPIO-монитора (лог в %s) ===\n", log_path); + fprintf(log_file, "\n=== Новая сессия: %ld ===\n", (long)time(NULL)); + fflush(log_file); + } + } else { + fprintf(stderr, "=== Запуск GPIO-монитора (только stdout) ===\n"); + } -// Инициализация FIFO -if (!fifo_init(&isr_ff, fifo_buffer_len)) { -perror("не выполнено fifo_init()\n"); -exit(EXIT_FAILURE); -} + // FIFO + if (!fifo_init(&isr_ff, fifo_buffer_len)) { + perror("Ошибка инициализации FIFO"); + exit(EXIT_FAILURE); + } -// Инициализация WiringPi -if (wiringPiSetup() == -1) { -perror("не выполнено wiringPiSetup()\n"); -exit(EXIT_FAILURE); -} + // WiringPi + if (wiringPiSetup() == -1) { + perror("Ошибка wiringPiSetup()"); + exit(EXIT_FAILURE); + } -// Настройка пина записи -pinMode(wr_pin, INPUT); -pullUpDnControl(wr_pin, PUD_UP); + // Настройка WR + pinMode(wr_pin, INPUT); + pullUpDnControl(wr_pin, PUD_UP); -// Настройка шины данных 8 бит -for (unsigned int i = 0; i < (sizeof pins / sizeof pins[0]); i++) { -unsigned int pin = pins[i]; -pinMode(pin, INPUT); -pullUpDnControl(pin, PUD_UP); -} + // Настройка шины данных + for (unsigned int i = 0; i < (sizeof pins / sizeof pins[0]); i++) { + unsigned int pin = pins[i]; -// Регистрация обработчика прерываний -int rc = wiringPiISR(wr_pin, INT_EDGE_RISING, &isr_handle); -if (rc != 0) { -perror("не выполнено wiringPiISR()\n"); -exit(EXIT_FAILURE); -} + // Используем подтяжку вниз (важно для стабильности) + pullUpDnControl(pin, PUD_DOWN); + pinMode(pin, INPUT); + } -fprintf(stderr, "GPIO pins initialized, waiting for interrupts...\n"); + // Прерывание по фронту + if (wiringPiISR(wr_pin, INT_EDGE_RISING, &isr_handle) != 0) { + perror("Ошибка wiringPiISR()"); + exit(EXIT_FAILURE); + } -char buffer[out_buffer_len]; -unsigned long total_bytes = 0; + fprintf(stderr, "GPIO инициализированы, ожидание данных...\n"); + fprintf(stderr, "Антидребезг: %ld мкс\n", debounce_us); -while (true) { -bool is_read = fifo_try_read(&isr_ff, buffer, sizeof buffer); -if (is_read) { - total_bytes += sizeof buffer; - - // Логирование в файл или stderr - if (log_file) { - fprintf(log_file, "--- Packet #%lu (%zu bytes) ---\n", - total_bytes / sizeof buffer, sizeof buffer); - for (int i = 0; i < sizeof buffer; i++) { - fprintf(log_file, " [%02d] = 0x%02x (%3d)\n", - i, (unsigned char)buffer[i], (unsigned char)buffer[i]); - } - fflush(log_file); - - // Краткая сводка на экран - fprintf(stderr, "."); // Прогресс-индикатор - if (total_bytes % (32 * 10) == 0) { - fprintf(stderr, " [%lu bytes]\n", total_bytes); - } - fflush(stderr); - } - - // Бинарные данные в stdout для Go-сервера - fwrite(buffer, 1U, sizeof buffer, stdout); - fflush(stdout); - -} else { - usleep(10000); // 10ms задержка, если данных нет -} -} + // Диагностика + fprintf(stderr, "Начальные состояния пинов:\n"); + for (unsigned int i = 0; i < (sizeof pins / sizeof pins[0]); i++) { + fprintf(stderr, " пин %d = %d\n", pins[i], digitalRead(pins[i])); + } -// Очистка (теоретически недостижимо, но для порядка) -if (log_file && log_file != stderr) { -fclose(log_file); -} -fifo_uninit(&isr_ff); + char byte; + char log_buffer[out_buffer_len]; + int log_index = 0; + unsigned long total_bytes = 0; -return EXIT_SUCCESS; -} + while (true) { + if (fifo_try_read(&isr_ff, &byte, 1)) { + log_buffer[log_index++] = byte; + total_bytes++; + + // Вывод в stdout (побайтно) + fwrite(&byte, 1, 1, stdout); + fflush(stdout); + + // Логирование блоками + if (log_index >= (int)out_buffer_len && log_file) { + fprintf(log_file, "--- Пакет #%lu (%zu байт) ---\n", + total_bytes / out_buffer_len, out_buffer_len); + + for (int i = 0; i < (int)out_buffer_len; i++) { + fprintf(log_file, " [%02d] = 0x%02x (%3d)\n", + i, + (unsigned char)log_buffer[i], + (unsigned char)log_buffer[i]); + } + + fflush(log_file); + + // Индикатор прогресса + fprintf(stderr, "."); + if (total_bytes % (32 * 10) == 0) { + fprintf(stderr, " [%lu байт]\n", total_bytes); + } + fflush(stderr); + + log_index = 0; + } + + } else { + usleep(10000); + } + } + + // Очистка (теоретически недостижимо, но для порядка) + if (log_file && log_file != stderr) { + fclose(log_file); + } + + fifo_uninit(&isr_ff); + return EXIT_SUCCESS; +} \ No newline at end of file