/* Направляет в стандартный вывод данные полученные с параллельной 8-битной шины Raspberry Pi4. Собирать внутри папки WiringPi/examples командой make really-all. Использование: ./gpio-interrupt # только stdout ./gpio-interrupt /tmp/gpio.log # stdout + лог в файл ./gpio-interrupt - # только лог в stdout (stderr) Предварительные условия: - WiringPi должен быть собран из этой версии, в которую добавлена функция digitalReadPins() make && make install text - WiringPi должен быть установлен из того deb-пакета который получен из этой версии make debian && dpkg -i debian-template/WiringPi*.deb text */ #include #include #include #include #include #include #include #include #include /* жёлтый д0 красный такт чёрный д1 синий д2 зелёный д3 оранжевый - общий */ 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 */ struct fifo { char *buffer; /** Буфер FIFO */ size_t len; /** Длина буфера FIFO */ size_t wri; /** Указатель записи FIFO */ size_t rdi; /** Указатель чтения FIFO */ }; void fifo_reset(struct fifo* ff) { ff->wri = 0U; ff->rdi = 0U; } 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); } bool fifo_is_full(struct fifo *ff) { return ((ff->wri + 1U) % ff->len) == ff->rdi; } 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); } 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; void isr_handle(void) { char byte_read = 0x0f & digitalReadPins(pins, sizeof pins / sizeof pins[0]); fifo_try_write(&isr_ff, &byte_read, 1); } 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) { // Логировать в 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"); } // Инициализация FIFO if (!fifo_init(&isr_ff, fifo_buffer_len)) { perror("не выполнено fifo_init()\n"); exit(EXIT_FAILURE); } // Инициализация WiringPi if (wiringPiSetup() == -1) { perror("не выполнено wiringPiSetup()\n"); exit(EXIT_FAILURE); } // Настройка пина записи 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); } // Регистрация обработчика прерываний int rc = wiringPiISR(wr_pin, INT_EDGE_RISING, &isr_handle); if (rc != 0) { perror("не выполнено wiringPiISR()\n"); exit(EXIT_FAILURE); } fprintf(stderr, "GPIO pins initialized, waiting for interrupts...\n"); char buffer[out_buffer_len]; unsigned long total_bytes = 0; 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 задержка, если данных нет } } // Очистка (теоретически недостижимо, но для порядка) if (log_file && log_file != stderr) { fclose(log_file); } fifo_uninit(&isr_ff); return EXIT_SUCCESS; }