chore: upload current project state
This commit is contained in:
@@ -0,0 +1,234 @@
|
||||
package gpio_monitor
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"FireLeave_tool/logger"
|
||||
"FireLeave_tool/reporter"
|
||||
)
|
||||
|
||||
const (
|
||||
// ButtonGPIO GPIO引脚编号
|
||||
ButtonGPIO = 111
|
||||
// DebounceTime 去抖动时间
|
||||
DebounceTime = 200 * time.Millisecond
|
||||
)
|
||||
|
||||
// GPIOButtonMonitor GPIO按钮监视器
|
||||
type GPIOButtonMonitor struct {
|
||||
gpioPin int
|
||||
isRunning bool
|
||||
lastState bool
|
||||
lastChange time.Time
|
||||
lastAlertTime time.Time
|
||||
cooldownTime time.Duration
|
||||
cooldownActive bool
|
||||
}
|
||||
|
||||
// NewGPIOButtonMonitor 创建GPIO按钮监视器
|
||||
func NewGPIOButtonMonitor(gpioPin int) *GPIOButtonMonitor {
|
||||
return &GPIOButtonMonitor{
|
||||
gpioPin: gpioPin,
|
||||
isRunning: false,
|
||||
lastState: false,
|
||||
lastChange: time.Now(),
|
||||
lastAlertTime: time.Now().Add(-6 * time.Second), // 初始化为6秒前,确保第一次可以触发
|
||||
cooldownTime: 5 * time.Second, // 5秒冷却时间
|
||||
cooldownActive: false, // 冷却期状态
|
||||
}
|
||||
}
|
||||
|
||||
// InitGPIO 初始化GPIO
|
||||
func (m *GPIOButtonMonitor) InitGPIO() error {
|
||||
gpioPath := fmt.Sprintf("/sys/class/gpio/gpio%d", m.gpioPin)
|
||||
|
||||
// 检查GPIO是否已导出
|
||||
if _, err := os.Stat(gpioPath); os.IsNotExist(err) {
|
||||
// 导出GPIO
|
||||
if err := os.WriteFile("/sys/class/gpio/export", []byte(strconv.Itoa(m.gpioPin)), 0666); err != nil {
|
||||
return fmt.Errorf("failed to export GPIO %d: %v", m.gpioPin, err)
|
||||
}
|
||||
// 等待导出完成
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
}
|
||||
|
||||
// 检查并设置方向为输入
|
||||
directionPath := fmt.Sprintf("%s/direction", gpioPath)
|
||||
directionBytes, err := os.ReadFile(directionPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read GPIO direction: %v", err)
|
||||
}
|
||||
|
||||
direction := string(directionBytes)
|
||||
if direction != "in\n" && direction != "in" {
|
||||
if err := os.WriteFile(directionPath, []byte("in"), 0666); err != nil {
|
||||
return fmt.Errorf("failed to set GPIO direction to in: %v", err)
|
||||
}
|
||||
// 等待设置完成
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
|
||||
if log := logger.GlobalLoggerManager.GetLogger("gpio"); log != nil {
|
||||
log.Printf("GPIO %d initialized successfully as input", m.gpioPin)
|
||||
} else if log := logger.GlobalLoggerManager.GetLogger("reporter"); log != nil {
|
||||
log.Printf("GPIO %d initialized successfully as input", m.gpioPin)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadGPIOValue 读取GPIO值
|
||||
func (m *GPIOButtonMonitor) ReadGPIOValue() (bool, error) {
|
||||
valuePath := fmt.Sprintf("/sys/class/gpio/gpio%d/value", m.gpioPin)
|
||||
valueBytes, err := os.ReadFile(valuePath)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to read GPIO value: %v", err)
|
||||
}
|
||||
|
||||
value := string(valueBytes)
|
||||
return value == "1\n" || value == "1", nil
|
||||
}
|
||||
|
||||
// Start 启动GPIO监控
|
||||
func (m *GPIOButtonMonitor) Start(ctx context.Context) error {
|
||||
// 初始化GPIO
|
||||
if err := m.InitGPIO(); err != nil {
|
||||
return fmt.Errorf("failed to initialize GPIO: %v", err)
|
||||
}
|
||||
|
||||
m.isRunning = true
|
||||
if log := logger.GlobalLoggerManager.GetLogger("gpio"); log != nil {
|
||||
log.Printf("Started monitoring GPIO %d for button alerts", m.gpioPin)
|
||||
} else if log := logger.GlobalLoggerManager.GetLogger("reporter"); log != nil {
|
||||
log.Printf("Started monitoring GPIO %d for button alerts", m.gpioPin)
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
m.isRunning = false
|
||||
if log := logger.GlobalLoggerManager.GetLogger("gpio"); log != nil {
|
||||
log.Printf("Stopped monitoring GPIO %d", m.gpioPin)
|
||||
} else if log := logger.GlobalLoggerManager.GetLogger("reporter"); log != nil {
|
||||
log.Printf("Stopped monitoring GPIO %d", m.gpioPin)
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
// 读取GPIO值
|
||||
currentState, err := m.ReadGPIOValue()
|
||||
if err != nil {
|
||||
if log := logger.GlobalLoggerManager.GetLogger("gpio"); log != nil {
|
||||
log.Printf("Error reading GPIO %d value: %v", m.gpioPin, err)
|
||||
} else if log := logger.GlobalLoggerManager.GetLogger("reporter"); log != nil {
|
||||
log.Printf("Error reading GPIO %d value: %v", m.gpioPin, err)
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
|
||||
// 检查状态是否变化
|
||||
if currentState != m.lastState {
|
||||
// 记录状态变化
|
||||
if log := logger.GlobalLoggerManager.GetLogger("gpio"); log != nil {
|
||||
log.Printf("GPIO %d state changed: %t → %t", m.gpioPin, m.lastState, currentState)
|
||||
} else if log := logger.GlobalLoggerManager.GetLogger("reporter"); log != nil {
|
||||
log.Printf("GPIO %d state changed: %t → %t", m.gpioPin, m.lastState, currentState)
|
||||
}
|
||||
|
||||
// 状态变化时更新lastChange
|
||||
m.lastChange = time.Now()
|
||||
|
||||
// 立即更新lastState,避免重复触发状态变化日志
|
||||
m.lastState = currentState
|
||||
|
||||
// 只输出true状态
|
||||
if currentState {
|
||||
if log := logger.GlobalLoggerManager.GetLogger("gpio"); log != nil {
|
||||
log.Printf("GPIO %d current state: %t", m.gpioPin, currentState)
|
||||
} else if log := logger.GlobalLoggerManager.GetLogger("reporter"); log != nil {
|
||||
log.Printf("GPIO %d current state: %t", m.gpioPin, currentState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查冷却期状态
|
||||
if time.Since(m.lastAlertTime) < m.cooldownTime {
|
||||
if !m.cooldownActive {
|
||||
m.cooldownActive = true
|
||||
// 只记录一次冷却期开始
|
||||
}
|
||||
} else {
|
||||
if m.cooldownActive {
|
||||
// 只记录一次冷却期结束
|
||||
if log := logger.GlobalLoggerManager.GetLogger("gpio"); log != nil {
|
||||
log.Printf("GPIO %d cooldown period ended", m.gpioPin)
|
||||
} else if log := logger.GlobalLoggerManager.GetLogger("reporter"); log != nil {
|
||||
log.Printf("GPIO %d cooldown period ended", m.gpioPin)
|
||||
}
|
||||
m.cooldownActive = false
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否稳定,且当前状态为true(高电平)
|
||||
if currentState && time.Since(m.lastChange) > DebounceTime {
|
||||
// 检查冷却期
|
||||
if time.Since(m.lastAlertTime) >= m.cooldownTime {
|
||||
// 检测到稳定的高电平,切换事件周期
|
||||
if log := logger.GlobalLoggerManager.GetLogger("gpio"); log != nil {
|
||||
log.Printf("GPIO %d detected stable high level after debounce, switching event cycle...", m.gpioPin)
|
||||
} else if log := logger.GlobalLoggerManager.GetLogger("reporter"); log != nil {
|
||||
log.Printf("GPIO %d detected stable high level after debounce, switching event cycle...", m.gpioPin)
|
||||
}
|
||||
|
||||
// 切换事件周期
|
||||
var targetCycle reporter.EventCycle
|
||||
switch reporter.GetCurrentEventCycle() {
|
||||
case reporter.EventCycleFireLeave:
|
||||
targetCycle = reporter.EventCycleFireCheck
|
||||
case reporter.EventCycleFireCheck:
|
||||
targetCycle = reporter.EventCycleFireLeave
|
||||
default:
|
||||
targetCycle = reporter.EventCycleFireCheck
|
||||
}
|
||||
|
||||
if err := reporter.SwitchEventCycle(targetCycle); err != nil {
|
||||
if log := logger.GlobalLoggerManager.GetLogger("gpio"); log != nil {
|
||||
log.Printf("Failed to switch event cycle: %v", err)
|
||||
} else if log := logger.GlobalLoggerManager.GetLogger("reporter"); log != nil {
|
||||
log.Printf("Failed to switch event cycle: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 更新lastAlertTime,开始冷却期
|
||||
m.lastAlertTime = time.Now()
|
||||
if log := logger.GlobalLoggerManager.GetLogger("gpio"); log != nil {
|
||||
log.Printf("GPIO %d alert sent, cooldown period started (5s)", m.gpioPin)
|
||||
} else if log := logger.GlobalLoggerManager.GetLogger("reporter"); log != nil {
|
||||
log.Printf("GPIO %d alert sent, cooldown period started (5s)", m.gpioPin)
|
||||
}
|
||||
|
||||
// 重置lastChange,避免重复触发
|
||||
m.lastChange = time.Now()
|
||||
}
|
||||
}
|
||||
|
||||
// 增加休眠时间,减少CPU占用和日志频率
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsRunning 检查监视器是否正在运行
|
||||
func (m *GPIOButtonMonitor) IsRunning() bool {
|
||||
return m.isRunning
|
||||
}
|
||||
Reference in New Issue
Block a user