/* Чтение данных с параллельной 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 #include #include #include #include #include #include #include #include /* Подключение физические контакты на 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; }