Доработка сборки проекта

This commit is contained in:
Maxim
2026-05-01 09:58:02 +03:00
parent 39f945fc31
commit e06f0ae0c6
4 changed files with 300 additions and 10 deletions

105
README.md
View File

@@ -1,16 +1,101 @@
# GPIO Monitor Server # GPIO Monitor Dashboard for Raspberry Pi
Сервер для мониторинга GPIO на Raspberry Pi. Реалтайм мониторинг параллельной GPIO-шины Raspberry Pi через C + Go + Web Dashboard.
## Структура проекта Проект читает входящие сигналы с GPIO-пинов Raspberry Pi по прерыванию, передаёт данные через FIFO pipe в Go-сервер и отображает всё в браузере в реальном времени.
- `cmd/server/` - точка входа приложения
- `internal/` - внутренняя логика ---
- `web/` - веб-интерфейс
- `scripts/` - вспомогательные скрипты # Возможности
✅ Захват данных по GPIO interrupt
✅ Работа через WiringPi
✅ FIFO pipe между C и Go
✅ Высокоскоростной RingBuffer
✅ HTTP API
✅ Web Dashboard
✅ Работа через Wi-Fi Access Point Raspberry Pi
✅ Подходит для ПК и мобильных устройств
---
# Архитектура
```text
GPIO BUS (8 bit)
gpio-interrupt.c
↓ stdout
systemd socket FIFO (/tmp/gpio_pipe)
Go Server
HTTP API (:8080)
Dashboard (Browser)
# Структура проекта
.
├── cmd/server/main.go # Go HTTP сервер
├── internal/adapter/ # RingBuffer
├── web/
│ ├── index.html
│ ├── dashboard.html
│ ├── css/style.css
│ ├── js/app.js
│ └── favicon.png
├── scripts/
├── start-server.sh
└── README.md
# GPIO pin
WR/STROBE = GPIO27
DATA BUS:
D0 = GPIO21
D1 = GPIO7
D2 = GPIO6
D3 = GPIO5
D4 = GPIO25
D5 = GPIO24
D6 = GPIO23
D7 = GPIO22
# Установка
sudo apt update
sudo apt install golang git build-essential
# Сборка
## Сборка
go build -o gpio-monitor-server ./cmd/server go build -o gpio-monitor-server ./cmd/server
## Запуск # Запуск сервера
./gpio-monitor-server
./start-server.sh
sudo systemctl start monitor-gpio.service
# Dashboard
Открывать на http://192.168.77.1:8080
# API
GET /api/health
GET /api/history
# Wi-Fi режим Raspberry Pi
SSID: fix_me
IP: 192.168.77.1
Подключение: ssh user@192.168.77.1
# License
MIT

177
scripts/imi_wire.py Executable file
View File

@@ -0,0 +1,177 @@
#!/usr/bin/env python3
"""
Имитатор параллельной шины для gpio-interrupt (Raspberry Pi 4)
"""
import gpiod
import time
import argparse
import sys
import signal
from gpiod.line import Direction, Value
class ParallelBusImitator:
"""Имитатор 7-битной параллельной шины данных"""
# Временные константы (секунды)
DATA_SETUP_TIME = 0.000005
STROBE_WIDTH = 0.000005
HOLD_TIME = 0.000005
WR_PIN = 12 # BCM12
DATA_PINS_MAPPING = [
(21, 18, "D0 (LSB)"),
(7, 27, "D1"),
(6, 22, "D2"),
(5, 23, "D3"),
(25, 17, "D4"),
(24, 20, "D5"),
(23, 21, "D6"),
(22, None, "D7 (не подключён)"),
]
def __init__(self, use_mask=True, chip_path='/dev/gpiochip0'):
self.use_mask = use_mask
self.counter = 0
self.active_pins = []
for wpi, bcm, desc in self.DATA_PINS_MAPPING:
if bcm is not None:
self.active_pins.append((wpi, bcm, desc))
self.data_pins_bcm = [bcm for _, bcm, _ in self.active_pins]
self.all_pins = self.data_pins_bcm + [self.WR_PIN]
try:
self.chip = gpiod.Chip(chip_path)
self.lines = self.chip.request_lines(
{
p: gpiod.LineSettings(
direction=Direction.OUTPUT,
output_value=Value.INACTIVE
)
for p in self.all_pins
},
consumer="par-bus-imitator"
)
except PermissionError:
print("Нет прав доступа к GPIO. Используйте sudo.")
sys.exit(1)
except Exception as e:
print(f"Ошибка GPIO: {e}")
sys.exit(1)
bit_width = 4 if use_mask else len(self.data_pins_bcm)
print(f"✓ Имитатор шины ({bit_width}-бит режим)")
print("Нажмите Ctrl+C для остановки\n")
def send_byte(self, value):
"""Отправка одного байта"""
if self.use_mask:
value &= 0x0F
else:
value &= 0x7F
out = {}
for bit_pos, bcm_pin in enumerate(self.data_pins_bcm):
bit = (value >> bit_pos) & 1
out[bcm_pin] = Value.ACTIVE if bit else Value.INACTIVE
self.lines.set_values(out)
time.sleep(self.DATA_SETUP_TIME)
self.lines.set_value(self.WR_PIN, Value.ACTIVE)
time.sleep(self.STROBE_WIDTH)
self.lines.set_value(self.WR_PIN, Value.INACTIVE)
time.sleep(self.HOLD_TIME)
self.counter += 1
self.show_status(value)
def show_status(self, value):
"""Красивый статус без спама"""
bits = 4 if self.use_mask else 7
bin_val = format(value, f'0{bits}b')
msg = (
f"\r▶ Передача: "
f"HEX=0x{value:02X} | "
f"BIN={bin_val} | "
f"Пакетов: {self.counter}"
)
print(msg, end='', flush=True)
def send_sequence(self, values, delay=0.2):
for val in values:
self.send_byte(val)
time.sleep(delay)
def cleanup(self):
if hasattr(self, 'lines'):
self.lines.release()
if hasattr(self, 'chip'):
self.chip.close()
def handle_signal(signum, frame):
print("\nЗавершение работы...")
sys.exit(0)
def main():
signal.signal(signal.SIGINT, handle_signal)
signal.signal(signal.SIGTERM, handle_signal)
parser = argparse.ArgumentParser(
description='Имитатор параллельной шины'
)
parser.add_argument('--no-mask', action='store_true',
help='7-битный режим')
parser.add_argument('--test',
choices=['default', 'counter', 'pattern'],
default='default')
parser.add_argument('--delay', type=float, default=0.2)
parser.add_argument('--single', type=str)
parser.add_argument('--chip', default='/dev/gpiochip0')
args = parser.parse_args()
imitator = ParallelBusImitator(
use_mask=not args.no_mask,
chip_path=args.chip
)
try:
if args.single:
val = int(args.single, 16)
imitator.send_byte(val)
print()
return
if args.test == 'default':
test_data = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40]
elif args.test == 'counter':
test_data = list(range(128))
else:
test_data = [0x00, 0x01, 0x03, 0x07, 0x0F, 0x55, 0x2A]
while True:
imitator.send_sequence(test_data, args.delay)
except KeyboardInterrupt:
print("\nОстановка...")
except Exception as e:
print(f"\nОшибка: {e}")
finally:
imitator.cleanup()
print("✓ GPIO освобождены")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,16 @@
[Unit]
Description=GPIO Interrupt Capture Service
Requires=monitor-gpio.socket
After=monitor-gpio.socket
[Service]
Type=simple
User=root
WorkingDirectory=/home/user/WiringPi/examples
ExecStart=/home/user/WiringPi/examples/gpio-interrupt -
StandardOutput=socket
StandardError=journal
Restart=always
RestartSec=2

View File

@@ -0,0 +1,12 @@
[Unit]
Description=GPIO FIFO Pipe
[Socket]
ListenFIFO=/tmp/gpio_pipe
SocketMode=0666
SocketUser=user
SocketGroup=user
RemoveOnStop=yes
[Install]
WantedBy=sockets.target