Compare commits

...

3 Commits

Author SHA1 Message Date
Maxim
83959e3da8 доработка с двумя режимами 2026-06-09 15:45:31 +03:00
Maxim
79c711a486 wip 2026-06-09 13:44:52 +03:00
Maxim
bf23cf5ca4 версия без принтов 2026-06-09 13:37:59 +03:00

View File

@@ -1,17 +1,14 @@
/*
Чтение данных с параллельной 8-битной шины Raspberry Pi 4
и вывод в stdout (для передачи, например, в Go-сервер).
и вывод в stdout
Сборка (внутри WiringPi/examples):
make really-all
Использование:
./gpio-interrupt # только stdout
./gpio-interrupt /tmp/log # stdout + лог в файл
./gpio-interrupt - # лог в stderr
Требования:
- Используется модифицированный WiringPi с функцией digitalReadPins()
Используется модифицированный WiringPi с функцией digitalReadPins()
Режимы:
fill - заполняет паузы последним байтом (высокий CPU, непрерывный поток)
sleep - спит при отсутствии данных (низкий CPU, только реальные данные)
*/
#include <stdlib.h>
@@ -22,6 +19,7 @@
#include <stdbool.h>
#include <time.h>
#include <sys/time.h>
#include <getopt.h>
#include <wiringPi.h>
/*
@@ -34,7 +32,7 @@
35 - D5
33 - D6
31 - D7
36 - такт
36 - Запись
14 - GND
*/
@@ -42,9 +40,18 @@ 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 буфера
const size_t fifo_buffer_len = 4096U; // Размер ПППУ в байтах
// Режимы работы
typedef enum {
MODE_FILL, // Заполнение пауз последним байтом (оригинальное поведение)
MODE_SLEEP // Сон при отсутствии данных (энергоэффективный)
} run_mode_t;
// Глобальные настройки
static run_mode_t run_mode = MODE_SLEEP; // По умолчанию энергоэффективный режим
static bool debug_mode = false;
// ================= FIFO =================
struct fifo {
char *buffer;
@@ -89,7 +96,6 @@ bool fifo_can_read(struct fifo *ff, size_t 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;
@@ -98,155 +104,178 @@ bool fifo_try_read(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))
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 unsigned long long last_time_us = 0;
static const long debounce_us = 5000; // 5 мс
// Диагностика
static unsigned long total_bytes = 0;
static unsigned long interrupts_processed = 0;
static unsigned long loop_iterations = 0;
// Обработчик прерывания
void isr_handle(void) {
unsigned long long now_us;
struct timeval now;
gettimeofday(&now, NULL);
now_us = now.tv_sec * 1000000LL + now.tv_usec;
long diff = (now.tv_sec - last_isr_time.tv_sec) * 1000000L +
(now.tv_usec - last_isr_time.tv_usec);
if (now_us - last_time_us < debounce_us) return;
last_time_us = now_us;
if (diff < debounce_us) {
return; // игнорируем дребезг
}
last_isr_time = now;
// Читать 8 бит
interrupts_processed++;
char byte_read = 0xff & digitalReadPins(pins, sizeof pins / sizeof pins[0]);
fifo_try_write(&isr_ff, &byte_read, 1);
}
// ================= MAIN =================
// Режим 1: Заполнение пауз последним байтом
void run_mode_fill(void) {
char byte;
char byte_prev = 0;
while (true) {
if (fifo_try_read(&isr_ff, &byte, 1)) {
fwrite(&byte, 1, 1, stdout);
byte_prev = byte;
total_bytes++;
} else {
fwrite(&byte_prev, 1, 1, stdout);
}
fflush(stdout);
loop_iterations++;
if (debug_mode && (loop_iterations % 1000000 == 0)) {
fprintf(stderr, "[DEBUG] Mode=fill, iterations=%lu, bytes=%lu\n",
loop_iterations, total_bytes);
}
}
}
// Режим 2: Сон при отсутствии данных (с минимальной диагностикой)
void run_mode_sleep(void) {
char byte;
int first_bytes_shown = 0;
// Минимальная диагностика при запуске
fprintf(stderr, "GPIO Monitor: waiting for data on WR pin %d...\n", wr_pin);
fflush(stderr);
while (true) {
if (fifo_try_read(&isr_ff, &byte, 1)) {
fwrite(&byte, 1, 1, stdout);
fflush(stdout);
total_bytes++;
loop_iterations = 0;
// Показать первые 10 байт в stderr
if (first_bytes_shown < 10) {
if (first_bytes_shown == 0) {
fprintf(stderr, "First bytes: ");
}
fprintf(stderr, "0x%02x ", (unsigned char)byte);
first_bytes_shown++;
if (first_bytes_shown == 10) {
fprintf(stderr, "\n");
fflush(stderr);
}
}
} else {
usleep(1000);
loop_iterations++;
}
if (debug_mode && (loop_iterations > 0) && (loop_iterations % 10000 == 0)) {
fprintf(stderr, "[DEBUG] Mode=sleep, idle loops=%lu, bytes=%lu\n",
loop_iterations, total_bytes);
}
}
}
// Парсинг аргументов командной строки
void parse_arguments(int argc, char *argv[]) {
static struct option long_options[] = {
{"mode", required_argument, 0, 'm'},
{"debug", no_argument, 0, 'd'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}
};
int opt;
int option_index = 0;
while ((opt = getopt_long(argc, argv, "m:dh", long_options, &option_index)) != -1) {
switch (opt) {
case 'm':
if (strcmp(optarg, "fill") == 0) {
run_mode = MODE_FILL;
} else if (strcmp(optarg, "sleep") == 0) {
run_mode = MODE_SLEEP;
} else {
fprintf(stderr, "Неизвестный режим: %s\n", optarg);
fprintf(stderr, "Доступные режимы: fill, sleep\n");
exit(EXIT_FAILURE);
}
break;
case 'd':
debug_mode = true;
break;
case 'h':
printf("Использование: %s [OPTIONS]\n\n", argv[0]);
printf("Опции:\n");
printf(" -m, --mode=MODE Режим работы: fill или sleep\n");
printf(" fill - заполнение пауз последним байтом\n");
printf(" sleep - сон при отсутствии данных (по умолчанию)\n");
printf(" -d, --debug Включить диагностику в stderr\n");
printf(" -h, --help Показать эту справку\n");
exit(EXIT_SUCCESS);
break;
default:
fprintf(stderr, "Используйте --help для справки\n");
exit(EXIT_FAILURE);
}
}
}
int main(int argc, char *argv[]) {
FILE *log_file = NULL;
const char *log_path = NULL;
parse_arguments(argc, argv);
// Обработка аргументов
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");
perror("fifo_init()");
exit(EXIT_FAILURE);
}
// WiringPi
if (wiringPiSetup() == -1) {
perror("Ошибка wiringPiSetup()");
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()");
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]));
if (run_mode == MODE_FILL) {
run_mode_fill();
} else {
run_mode_sleep();
}
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;
}