Files
gpio-reader/examples/gpio-interrupt.c

281 lines
8.4 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
Сборка (внутри WiringPi/examples):
make really-all
Требования:
Используется модифицированный WiringPi с функцией digitalReadPins()
Режимы:
fill - заполняет паузы последним байтом (высокий CPU, непрерывный поток)
sleep - спит при отсутствии данных (низкий CPU, только реальные данные)
*/
#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 <getopt.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; // Размер ПППУ в байтах
// Режимы работы
typedef enum {
MODE_FILL, // Заполнение пауз последним байтом (оригинальное поведение)
MODE_SLEEP // Сон при отсутствии данных (энергоэффективный)
} run_mode_t;
// Глобальные настройки
static run_mode_t run_mode = MODE_SLEEP; // По умолчанию энергоэффективный режим
static bool debug_mode = false;
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;
// Антидребезг
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;
if (now_us - last_time_us < debounce_us) return;
last_time_us = now_us;
interrupts_processed++;
char byte_read = 0xff & digitalReadPins(pins, sizeof pins / sizeof pins[0]);
fifo_try_write(&isr_ff, &byte_read, 1);
}
// Режим 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[]) {
parse_arguments(argc, argv);
if (!fifo_init(&isr_ff, fifo_buffer_len)) {
perror("fifo_init()");
exit(EXIT_FAILURE);
}
if (wiringPiSetup() == -1) {
perror("wiringPiSetup()");
exit(EXIT_FAILURE);
}
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);
}
if (run_mode == MODE_FILL) {
run_mode_fill();
} else {
run_mode_sleep();
}
fifo_uninit(&isr_ff);
return EXIT_SUCCESS;
}