доработка в кабинете

This commit is contained in:
Maxim
2026-05-06 12:52:14 +03:00
parent 655a8dd474
commit c863f5bf20

View File

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