Files
gpio-reader/examples/gpio-interrupt.c
2026-05-06 12:52:14 +03:00

252 lines
7.1 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
Чтение данных с параллельной 8-битной шины Raspberry Pi 4
и вывод в stdout (для передачи, например, в Go-сервер).
Сборка (внутри WiringPi/examples):
make really-all
Использование:
./gpio-interrupt # только stdout
./gpio-interrupt /tmp/log # stdout + лог в файл
./gpio-interrupt - # лог в stderr
Требования:
- Используется модифицированный WiringPi с функцией digitalReadPins()
*/
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stddef.h>
#include <stdbool.h>
#include <time.h>
#include <sys/time.h>
#include <wiringPi.h>
/*
Подключение физические контакты на 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; // Пин сигнала записи (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;
size_t len;
size_t wri;
size_t rdi;
};
void fifo_reset(struct fifo* ff) {
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;
}
void fifo_uninit(struct fifo* ff) {
free(ff->buffer);
ff->buffer = NULL;
fifo_reset(ff);
}
size_t fifo_available(struct fifo *ff) {
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;
}
bool fifo_can_read(struct fifo *ff, size_t 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;
}
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;
}
// =======================================
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) {
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;
// Обработка аргументов
if (argc > 1) {
log_path = argv[1];
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");
exit(EXIT_FAILURE);
}
// WiringPi
if (wiringPiSetup() == -1) {
perror("Ошибка wiringPiSetup()");
exit(EXIT_FAILURE);
}
// Настройка WR
pinMode(wr_pin, INPUT);
pullUpDnControl(wr_pin, PUD_UP);
// Настройка шины данных
for (unsigned int i = 0; i < (sizeof pins / sizeof pins[0]); i++) {
unsigned int pin = pins[i];
// Используем подтяжку вниз (важно для стабильности)
pullUpDnControl(pin, PUD_DOWN);
pinMode(pin, INPUT);
}
// Прерывание по фронту
if (wiringPiISR(wr_pin, INT_EDGE_RISING, &isr_handle) != 0) {
perror("Ошибка wiringPiISR()");
exit(EXIT_FAILURE);
}
fprintf(stderr, "GPIO инициализированы, ожидание данных...\n");
fprintf(stderr, "Антидребезг: %ld мкс\n", debounce_us);
// Диагностика
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]));
}
char byte;
char log_buffer[out_buffer_len];
int log_index = 0;
unsigned long total_bytes = 0;
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;
}