package play import ( "fmt" "game-driver/internal/middleware" "game-driver/internal/schema" "game-driver/leaf" "game-driver/pkg/utils" "github.com/warthog618/go-gpiocdev" "github.com/warthog618/go-gpiocdev/device/rpi" "go.uber.org/zap" "sync" "time" ) var gpios = []int{rpi.GPIO6, rpi.GPIO13, rpi.GPIO19, rpi.GPIO26} type label int func (t label) String() string { switch t { case rpi.GPIO6: return "OutOK" case rpi.GPIO13: return "Lower" case rpi.GPIO19: return "Error" case rpi.GPIO26: return "Empty" default: return fmt.Sprint(int(t)) } } type statusData map[int]int func (data statusData) Init(offsets []int, values []int) { for i := 0; i < len(offsets); i++ { data[offsets[i]] = values[i] } zap.S().Infof( "初始状态: %s-%d %s-%d %s-%d %s-%d", label(rpi.GPIO6), data[rpi.GPIO6], label(rpi.GPIO13), data[rpi.GPIO13], label(rpi.GPIO19), data[rpi.GPIO19], label(rpi.GPIO26), data[rpi.GPIO26], ) } func (data statusData) Change(offset int, value gpiocdev.LineEventType) { if v, ok := data[offset]; ok { if value == gpiocdev.LineEventFallingEdge { if v == 0 { return } else { zap.S().Infof("%s: 0", label(offset)) data[offset] = 0 } } else if value == gpiocdev.LineEventRisingEdge { if v == 1 { return } else { zap.S().Infof("%s: 1", label(offset)) data[offset] = 1 } } } } func NewPushCard() leaf.HandlerFunc { chip, err := gpiocdev.NewChip("gpiochip0", gpiocdev.AsActiveLow) if err != nil { zap.S().Panicln("打开 GPIO 设备失败:", err) } go func() { <-utils.GlobalMqttClient.Done() chip.Close() }() status := make(statusData) lines, err := chip.RequestLines( gpios, gpiocdev.AsInput, // 请求引脚作为输入 gpiocdev.WithPullUp, // 使用上拉电阻 gpiocdev.WithRealtimeEventClock, // 使用实时时钟 gpiocdev.WithBothEdges, // 监听上升沿和下降沿 gpiocdev.WithEventHandler(func(evt gpiocdev.LineEvent) { status.Change(evt.Offset, evt.Type) }), ) if err != nil { zap.S().Panicln("请求引脚作为输入信号失败:", err) } go func() { <-utils.GlobalMqttClient.Done() lines.Close() }() // 读取引脚初始状态 rr := make([]int, len(gpios), len(gpios)) lines.Values(rr) status.Init(gpios, rr) // 初始化发卡引脚 payout, err := chip.RequestLine(rpi.GPIO11, gpiocdev.AsOutput(0)) if err != nil { zap.S().Panicf("请求引脚 %d 作为 PayOut 失败: %s\n", rpi.GPIO11, err) } go func() { <-utils.GlobalMqttClient.Done() payout.Close() }() return func(c *leaf.Context) { payload := leaf.Value[*schema.PlayModal](c, middleware.PayloadJSONKey) var action time.Duration if a, ok := payload.Game["action"]; ok { action = time.Duration(a.(float64)) } // 等待组 var wait sync.WaitGroup defer wait.Wait() // 结束信号通道 a := make(chan struct{}) // 发送结束信号 defer close(a) wait.Add(1) go func() { defer wait.Done() select { case <-a: case <-time.After(action * time.Second): // 将输出引脚设置为活动,发卡信号 payout.SetValue(1) // 恢复为未活动,停止发卡信号 defer payout.SetValue(0) // 信号持续 500ms time.Sleep(500 * time.Millisecond) } }() // 执行等待信号 Default(c) } }