From 25cb34f6f5d475b1a121cf979d441bffd2c9297b Mon Sep 17 00:00:00 2001 From: mapleafgo Date: Tue, 10 Dec 2024 17:40:59 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=91=E5=8D=A1=E5=85=B3=E5=8D=A1=E7=9A=84?= =?UTF-8?q?=E8=AF=BB=E5=8D=A1=E6=B5=81=E7=A8=8B=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config.yml | 21 +++--- config/game/push_card.go | 3 +- demo/modbus2/main.go | 41 +++++++++++ internal/routes/play/push_card.go | 37 +++++++++- internal/routes/play/wait_card.go | 2 +- pkg/card_reader/reader.go | 113 +++++++++++++++++------------- 6 files changed, 157 insertions(+), 60 deletions(-) create mode 100644 demo/modbus2/main.go diff --git a/config.yml b/config.yml index 1bccaa0..816634b 100755 --- a/config.yml +++ b/config.yml @@ -1,7 +1,7 @@ location: wushan point: 5 relay: COM7 -maxTimeout: 60 # 单位 s +maxTimeout: 60 # 单位 s,必须大于 0 log: level: debug file: @@ -20,12 +20,13 @@ aliyun: voice: zhifeng_emo game: url: rtu:///dev/ttyUSB0 # 点位 5 的串口地址 -# cardGroups: # 点位 4 的发卡器配置 -# - name: gpiochip0 -# outOK: 6 -# lower: 13 -# error: 19 -# empty: 26 -# push: 11 -# reset: 22 -# pull: 27 + # pushGroups: # 点位 4 的发卡器配置 + # - name: gpiochip0 + # outOK: 6 + # lower: 13 + # error: 19 + # empty: 26 + # push: 11 + # reset: 22 + # pull: 27 + # readUrl: rtu:///dev/ttyUSB0 # 点位 4 的读卡器配置 \ No newline at end of file diff --git a/config/game/push_card.go b/config/game/push_card.go index 1ad86f9..b08e5ff 100644 --- a/config/game/push_card.go +++ b/config/game/push_card.go @@ -3,5 +3,6 @@ package game import "game-driver/internal/routes/play/card_pusher" type ConfigPush struct { - CardGroups []*card_pusher.LineGroup + PushGroups []*card_pusher.LineGroup + ReadURL string } diff --git a/demo/modbus2/main.go b/demo/modbus2/main.go new file mode 100644 index 0000000..0a96409 --- /dev/null +++ b/demo/modbus2/main.go @@ -0,0 +1,41 @@ +package main + +import ( + "context" + "fmt" + "game-driver/logger" + "game-driver/pkg/card_reader" + "go.uber.org/zap" + "os" + "os/signal" + "syscall" +) + +func main() { + logger.DefaultLogger() + defer logger.Sync() + + reader, err := card_reader.NewReader("rtu:///dev/ttyUSB0") + if err != nil { + zap.S().Panicln(err) + } + defer reader.Close() + + err = reader.Init() + if err != nil { + zap.S().Panicln(err) + } + + ctx, cancel := context.WithCancel(context.Background()) + go reader.OnCardInfo(ctx, func(info *card_reader.CardInfo) { + zap.S().Infow("Card info", "Type", fmt.Sprintf("%#x", info.Type), "ID", info.ID) + }) + + sig := make(chan os.Signal, 1) + signal.Notify(sig, os.Interrupt, syscall.SIGTERM) + + <-sig + zap.S().Infoln("接收到关闭命令 - 正在关闭程序") + cancel() + zap.S().Infoln("关闭完成") +} diff --git a/internal/routes/play/push_card.go b/internal/routes/play/push_card.go index 30b5ea3..87696ee 100644 --- a/internal/routes/play/push_card.go +++ b/internal/routes/play/push_card.go @@ -3,14 +3,18 @@ package play import ( "context" "encoding/json" + "errors" "game-driver/config/game" "game-driver/internal/middleware" "game-driver/internal/routes/play/card_pusher" "game-driver/internal/schema" "game-driver/leaf" + "game-driver/pkg/card_reader" "game-driver/pkg/utils" "github.com/eclipse/paho.golang/paho" "go.uber.org/zap" + "io/fs" + "os" "sync" "time" ) @@ -26,11 +30,35 @@ type ResponseBody struct { func PushCard(ctx context.Context) leaf.HandlerFunc { g := (game.G).(game.ConfigPush) + // 开始初始化读卡器 + reader, err := card_reader.NewReader(g.ReadURL) + if err != nil { + if errors.Is(err, fs.ErrNotExist) { + zap.S().Errorf("读卡器串口文件不存在: %s", g.ReadURL) + os.Exit(1) + } + zap.S().Panicf("读卡器串口连接失败 [%T]: %q", err, err) + } + go func() { + <-ctx.Done() + _ = reader.Close() + }() + + // 开始初始化发卡器 devices := make([]*card_pusher.Device, 0) - for _, group := range g.CardGroups { + for i, group := range g.PushGroups { + // 对读卡器初始化配置 + reader.SetUnitID(uint8(i + 1)) + err = reader.Init() + if err != nil { + zap.S().Panicln("读卡器初始配置失败", err) + } + + // 解析发卡器配置 gv, _ := json.Marshal(group) zap.S().Info("发卡器指针:", string(gv)) + // 初始化发卡器 device, err := card_pusher.New(group) if err != nil { zap.S().Panicln("初始化发卡器失败: ", err) @@ -84,6 +112,13 @@ func PushCard(ctx context.Context) leaf.HandlerFunc { // 延迟1秒获取结果并发送消息 time.AfterFunc(time.Second, func() { if body.num != 0 { + // 若卡片就位,读取卡片信息 + if devices[body.num-1].GetOutOk() == 1 { + reader.SetUnitID(uint8(body.num)) + if info := reader.GetCardInfo(); info != nil { + body.CardId = info.ID + } + } body.OutOk += devices[body.num-1].GetOutOk() } publishBody(ctx, c.Properties.ResponseTopic, body) diff --git a/internal/routes/play/wait_card.go b/internal/routes/play/wait_card.go index 31aedee..69df178 100644 --- a/internal/routes/play/wait_card.go +++ b/internal/routes/play/wait_card.go @@ -85,7 +85,7 @@ func WaitCard(ctx context.Context) leaf.HandlerFunc { wait.Add(1) go func() { defer wait.Done() - reader.OnCardInfo(cc, func(info card_reader.CardInfo) { + reader.OnCardInfo(cc, func(info *card_reader.CardInfo) { cardInfo.Send(info.ID) }) }() diff --git a/pkg/card_reader/reader.go b/pkg/card_reader/reader.go index 793d839..4b543be 100644 --- a/pkg/card_reader/reader.go +++ b/pkg/card_reader/reader.go @@ -14,9 +14,13 @@ import ( type Reader interface { io.Closer SetUnitID(uint8) + // WriteUnitId 写入读卡器的 UnitID + WriteUnitId(uint16) error + // Init 初始化读卡器配置 Init() error // OnCardInfo 会在卡号信息发生变化时调用回调函数,直到上下文被取消,或者 Reader 被关闭。需要在 goroutine 中调用。 - OnCardInfo(context.Context, func(CardInfo)) + OnCardInfo(context.Context, func(*CardInfo)) + GetCardInfo() *CardInfo } type CardInfo struct { @@ -28,6 +32,14 @@ type reader struct { c *modbus.Client } +// WriteUnitId 写入读卡器的 UnitID +func (r *reader) WriteUnitId(id uint16) error { + v := id<<8 + 1 + zap.S().Infof("WriteRegister 40007 %#x", v) + return r.c.WriteRegister(6, v) +} + +// Init 初始化读卡器配置 func (r *reader) Init() error { // 配置读卡间隔时间为 50 毫秒 err := r.c.WriteRegister(8, 0x0511) @@ -52,57 +64,64 @@ func (r *reader) Init() error { return nil } -func (r *reader) OnCardInfo(ctx context.Context, f func(info CardInfo)) { +// GetCardInfo 获取卡号信息 +func (r *reader) GetCardInfo() *CardInfo { + // 读取状态寄存器确认是否信息已经准备好 + status, err := r.c.ReadRegister(29, modbus.HoldingRegister) + if err != nil { + zap.S().Errorln("ReadRegister 40030 error:", err) + return nil + } else if status == 0x0000 { + return nil + } + + // 读取卡号长度 + cardLength, err := r.c.ReadRegister(30, modbus.HoldingRegister) + if err != nil { + zap.S().Errorln("ReadRegister 40031 error:", err) + return nil + } + dataLength := cardLength >> 8 + + // 读取卡类型 + cardType, err := r.c.ReadRegister(31, modbus.HoldingRegister) + if err != nil { + zap.S().Errorln("ReadRegister 40032 error:", err) + return nil + } + + // 读取卡号数据 + cardData, err := r.c.ReadRegisters(32, uint16(math.Round(float64(dataLength)/2)), modbus.HoldingRegister) + if err != nil { + zap.S().Errorln("ReadRegister 40033~ error:", err) + return nil + } + + s := make([]string, dataLength) + for i := 0; i < int(dataLength); i++ { + if i%2 == 0 { + s[i] = fmt.Sprintf("%02X", cardData[i/2]>>8) + } else { + s[i] = fmt.Sprintf("%02X", cardData[i/2]&0xFF) + } + } + + return &CardInfo{ + Type: cardType, + ID: strings.Join(s, ""), + } +} + +// OnCardInfo 会在卡号信息发生变化时调用回调函数,直到上下文被取消,或者 Reader 被关闭。需要在 goroutine 中调用。 +func (r *reader) OnCardInfo(ctx context.Context, f func(info *CardInfo)) { for { select { case <-ctx.Done(): return case <-time.After(100 * time.Millisecond): - { - // 读取状态寄存器确认是否信息已经准备好 - status, err := r.c.ReadRegister(29, modbus.HoldingRegister) - if err != nil { - zap.S().Errorln("ReadRegister 40030 error:", err) - break - } else if status == 0x0000 { - break - } - - // 读取卡号长度 - cardLength, err := r.c.ReadRegister(30, modbus.HoldingRegister) - if err != nil { - zap.S().Errorln("ReadRegister 40031 error:", err) - break - } - dataLength := cardLength >> 8 - - // 读取卡类型 - cardType, err := r.c.ReadRegister(31, modbus.HoldingRegister) - if err != nil { - zap.S().Errorln("ReadRegister 40032 error:", err) - break - } - - // 读取卡号数据 - cardData, err := r.c.ReadRegisters(32, uint16(math.Round(float64(dataLength)/2)), modbus.HoldingRegister) - if err != nil { - zap.S().Errorln("ReadRegister 40033~ error:", err) - break - } - - s := make([]string, dataLength) - for i := 0; i < int(dataLength); i++ { - if i%2 == 0 { - s[i] = fmt.Sprintf("%02X", cardData[i/2]>>8) - } else { - s[i] = fmt.Sprintf("%02X", cardData[i/2]&0xFF) - } - } - - f(CardInfo{ - Type: cardType, - ID: strings.Join(s, ""), - }) + info := r.GetCardInfo() + if info != nil { + f(info) } } }