diff --git a/go.mod b/go.mod index 8786da3..114267f 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( ) require ( - github.com/aliyun/alibaba-cloud-sdk-go v1.63.52 // indirect + github.com/aliyun/alibaba-cloud-sdk-go v1.63.53 // indirect github.com/creack/goselect v0.1.2 // indirect github.com/ebitengine/oto/v3 v3.3.1 // indirect github.com/ebitengine/purego v0.8.1 // indirect diff --git a/go.sum b/go.sum index d2128b9..88d1877 100644 --- a/go.sum +++ b/go.sum @@ -5,6 +5,8 @@ github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3 github.com/aliyun/alibaba-cloud-sdk-go v1.61.1376/go.mod h1:9CMdKNL3ynIGPpfTcdwTvIm8SGuAZYYC4jFVSSvE1YQ= github.com/aliyun/alibaba-cloud-sdk-go v1.63.52 h1:2qZQ6tiGuBqtaXd0rgsct29WxFzYyUKywg113mMP7QE= github.com/aliyun/alibaba-cloud-sdk-go v1.63.52/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ= +github.com/aliyun/alibaba-cloud-sdk-go v1.63.53 h1:I93ILTm5ytF4e5+lEQXSXcydS26D9eVyJ4H6z3rJqMA= +github.com/aliyun/alibaba-cloud-sdk-go v1.63.53/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ= github.com/aliyun/alibabacloud-nls-go-sdk v1.1.1 h1:LjItoNZuu5xHlsByFo+kr3nGa4LRIESCGWhfurayxBg= github.com/aliyun/alibabacloud-nls-go-sdk v1.1.1/go.mod h1:4BDMUKpEaP/Ct79w0ozR0nbnEj49g1k3mrgX/IKG5I4= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= diff --git a/internal/routes/play.go b/internal/routes/play.go index 120b3a0..2993603 100644 --- a/internal/routes/play.go +++ b/internal/routes/play.go @@ -20,7 +20,7 @@ func switchPoint(point int) leaf.HandlerFunc { return play.OnlyVideo case 4: // 4号点位(发卡机) - return play.NewPushCard() + return play.PushCard() default: return play.Default } diff --git a/internal/routes/play/card_device/device.go b/internal/routes/play/card_device/device.go new file mode 100644 index 0000000..84f4f4d --- /dev/null +++ b/internal/routes/play/card_device/device.go @@ -0,0 +1,161 @@ +package card_device + +import ( + "fmt" + "github.com/warthog618/go-gpiocdev" + "go.uber.org/zap" + "strings" + "time" +) + +type Device struct { + chip *gpiocdev.Chip // GPIO 设备 + inLines *gpiocdev.Lines // 输入针脚 + pushLine *gpiocdev.Line // 发卡针脚 + pullLine *gpiocdev.Line // 回收针脚 + resetLine *gpiocdev.Line // 重置针脚 + status map[inGpioLine]int // 状态 +} + +// statusEventHandler 状态事件处理 +func (d *Device) statusEventHandler(evt gpiocdev.LineEvent) { + offset := inGpioLine(evt.Offset) + eType := evt.Type + + t := false + defer func() { + if t { + zap.S().Infof("状态: %s-%d", offset, d.status[offset]) + } + }() + + if v, ok := d.status[offset]; ok { + if eType == gpiocdev.LineEventFallingEdge { + if v == 0 { + return + } else { + t = true + d.status[offset] = 0 + } + } else if eType == gpiocdev.LineEventRisingEdge { + if v == 1 { + return + } else { + t = true + d.status[offset] = 1 + } + } + } +} + +// initStatus 读取初始状态 +func (d *Device) initStatus() error { + offsets := d.inLines.Offsets() + status := make([]int, len(offsets), len(offsets)) + err := d.inLines.Values(status) + if err != nil { + return err + } + for i := 0; i < len(status); i++ { + d.status[inGpioLine(offsets[i])] = status[i] + } + + sv := make([]string, len(offsets)) + for _, g := range allInGpio() { + sv = append(sv, fmt.Sprintf("%s-%d", g, d.status[g])) + } + strings.Join(sv, " ") + zap.S().Infof("初始状态: %s", strings.Join(sv, " ")) + return nil +} + +// Close 关闭设备 +func (d *Device) Close() error { + d.resetLine.Close() + d.pullLine.Close() + d.pushLine.Close() + + d.inLines.Close() + d.chip.Close() + + return nil +} + +// PushCard 发卡 +func (d *Device) PushCard() { + d.pushLine.SetValue(1) + defer d.pushLine.SetValue(0) + + time.Sleep(500 * time.Millisecond) +} + +// PullCard 回收卡 +func (d *Device) PullCard() { + d.pullLine.SetValue(1) + defer d.pullLine.SetValue(0) + + time.Sleep(500 * time.Millisecond) +} + +// Reset 重置 +func (d *Device) Reset() { + d.resetLine.SetValue(1) + defer d.resetLine.SetValue(0) + + time.Sleep(500 * time.Millisecond) +} + +func New(name string) (*Device, error) { + chip, err := gpiocdev.NewChip(name, gpiocdev.AsActiveLow) + if err != nil { + return nil, fmt.Errorf("打开 GPIO 设备失败: %w", err) + } + + d := &Device{ + chip: chip, + status: make(map[inGpioLine]int), + } + + // 初始化输入针脚并监听针脚 + inLines, err := chip.RequestLines( + allInGpioInt(), + gpiocdev.AsInput, // 请求引脚作为输入 + gpiocdev.WithPullUp, // 使用上拉电阻 + gpiocdev.WithRealtimeEventClock, // 使用实时时钟 + gpiocdev.WithBothEdges, // 监听上升沿和下降沿 + gpiocdev.WithEventHandler(d.statusEventHandler), + ) + if err != nil { + return nil, fmt.Errorf("请求输入引脚失败: %w", err) + } + d.inLines = inLines + + // 读取初始状态 + err = d.initStatus() + if err != nil { + return nil, fmt.Errorf("读取初始状态失败: %w", err) + } + + // 初始化发卡引脚 + push, err := chip.RequestLine(int(PushLine), gpiocdev.AsOutput()) + if err != nil { + return nil, fmt.Errorf("请求引脚 %d 作为发卡失败: %w", PushLine, err) + } + d.pushLine = push + + // 初始化回收引脚 + pull, err := chip.RequestLine(int(PullLine), gpiocdev.AsOutput()) + if err != nil { + return nil, fmt.Errorf("请求引脚 %d 作为回收失败: %w", PullLine, err) + } + d.pullLine = pull + + // 初始化重置引脚 + reset, err := chip.RequestLine(int(ResetLine), gpiocdev.AsOutput()) + if err != nil { + return nil, fmt.Errorf("请求引脚 %d 作为重置失败: %w", ResetLine, err) + } + d.resetLine = reset + + return d, nil +} diff --git a/internal/routes/play/card_device/in_gpio.go b/internal/routes/play/card_device/in_gpio.go new file mode 100644 index 0000000..94cfa8f --- /dev/null +++ b/internal/routes/play/card_device/in_gpio.go @@ -0,0 +1,38 @@ +package card_device + +import ( + "fmt" + "github.com/warthog618/go-gpiocdev/device/rpi" +) + +type inGpioLine int + +const ( + OutOKLine inGpioLine = rpi.GPIO6 + LowerLine inGpioLine = rpi.GPIO13 + ErrorLine inGpioLine = rpi.GPIO19 + EmptyLine inGpioLine = rpi.GPIO26 +) + +func (g inGpioLine) String() string { + switch g { + case OutOKLine: + return "OutOKLine" + case LowerLine: + return "LowerLine" + case ErrorLine: + return "ErrorLine" + case EmptyLine: + return "EmptyLine" + default: + return fmt.Sprint(int(g)) + } +} + +func allInGpio() []inGpioLine { + return []inGpioLine{OutOKLine, LowerLine, ErrorLine, EmptyLine} +} + +func allInGpioInt() []int { + return []int{int(OutOKLine), int(LowerLine), int(ErrorLine), int(EmptyLine)} +} diff --git a/internal/routes/play/card_device/out_gpio.go b/internal/routes/play/card_device/out_gpio.go new file mode 100644 index 0000000..23eca6a --- /dev/null +++ b/internal/routes/play/card_device/out_gpio.go @@ -0,0 +1,35 @@ +package card_device + +import ( + "fmt" + "github.com/warthog618/go-gpiocdev/device/rpi" +) + +type outGpioLine int + +const ( + PushLine outGpioLine = rpi.GPIO11 + ResetLine outGpioLine = rpi.GPIO22 + PullLine outGpioLine = rpi.GPIO27 +) + +func (g outGpioLine) String() string { + switch g { + case PushLine: + return "PushLine" + case ResetLine: + return "ResetLine" + case PullLine: + return "PullLine" + default: + return fmt.Sprint(int(g)) + } +} + +func allOutGpio() []outGpioLine { + return []outGpioLine{PushLine, ResetLine, PullLine} +} + +func allOutGpioInt() []int { + return []int{int(PushLine), int(ResetLine), int(PullLine)} +} diff --git a/internal/routes/play/push_card.go b/internal/routes/play/push_card.go index b726d23..a63316f 100644 --- a/internal/routes/play/push_card.go +++ b/internal/routes/play/push_card.go @@ -1,115 +1,24 @@ package play import ( - "fmt" "game-driver/internal/middleware" + "game-driver/internal/routes/play/card_device" "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) +func PushCard() leaf.HandlerFunc { + device, err := card_device.New("gpiochip0") if err != nil { - zap.S().Panicln("打开 GPIO 设备失败:", err) + zap.S().Panicln("初始化发卡器失败: ", 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() + device.Close() }() return func(c *leaf.Context) { @@ -135,13 +44,7 @@ func NewPushCard() leaf.HandlerFunc { select { case <-a: case <-time.After(action * time.Second): - // 将输出引脚设置为活动,发卡信号 - payout.SetValue(1) - // 恢复为未活动,停止发卡信号 - defer payout.SetValue(0) - - // 信号持续 500ms - time.Sleep(500 * time.Millisecond) + device.PushCard() } }() diff --git a/logger/logger.go b/logger/logger.go index bbad675..55ec51e 100644 --- a/logger/logger.go +++ b/logger/logger.go @@ -8,6 +8,11 @@ import ( "os" ) +func DefaultLogger() { + logger, _ := zap.NewDevelopment() + zap.ReplaceGlobals(logger) +} + func InitLogger() { // 解析日志级别 level, err := zapcore.ParseLevel(config.C.Log.Level)