发卡关卡的读卡流程完成
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
location: wushan
|
||||
point: 5
|
||||
relay: COM7
|
||||
maxTimeout: 60 # 单位 s
|
||||
maxTimeout: 60 # 单位 s,必须大于 0
|
||||
log:
|
||||
level: debug
|
||||
file:
|
||||
@@ -20,7 +20,7 @@ aliyun:
|
||||
voice: zhifeng_emo
|
||||
game:
|
||||
url: rtu:///dev/ttyUSB0 # 点位 5 的串口地址
|
||||
# cardGroups: # 点位 4 的发卡器配置
|
||||
# pushGroups: # 点位 4 的发卡器配置
|
||||
# - name: gpiochip0
|
||||
# outOK: 6
|
||||
# lower: 13
|
||||
@@ -29,3 +29,4 @@ game:
|
||||
# push: 11
|
||||
# reset: 22
|
||||
# pull: 27
|
||||
# readUrl: rtu:///dev/ttyUSB0 # 点位 4 的读卡器配置
|
||||
@@ -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
|
||||
}
|
||||
|
||||
41
demo/modbus2/main.go
Normal file
41
demo/modbus2/main.go
Normal file
@@ -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("关闭完成")
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}()
|
||||
|
||||
@@ -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,27 +64,22 @@ func (r *reader) Init() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *reader) OnCardInfo(ctx context.Context, f func(info CardInfo)) {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
{
|
||||
// GetCardInfo 获取卡号信息
|
||||
func (r *reader) GetCardInfo() *CardInfo {
|
||||
// 读取状态寄存器确认是否信息已经准备好
|
||||
status, err := r.c.ReadRegister(29, modbus.HoldingRegister)
|
||||
if err != nil {
|
||||
zap.S().Errorln("ReadRegister 40030 error:", err)
|
||||
break
|
||||
return nil
|
||||
} else if status == 0x0000 {
|
||||
break
|
||||
return nil
|
||||
}
|
||||
|
||||
// 读取卡号长度
|
||||
cardLength, err := r.c.ReadRegister(30, modbus.HoldingRegister)
|
||||
if err != nil {
|
||||
zap.S().Errorln("ReadRegister 40031 error:", err)
|
||||
break
|
||||
return nil
|
||||
}
|
||||
dataLength := cardLength >> 8
|
||||
|
||||
@@ -80,14 +87,14 @@ func (r *reader) OnCardInfo(ctx context.Context, f func(info CardInfo)) {
|
||||
cardType, err := r.c.ReadRegister(31, modbus.HoldingRegister)
|
||||
if err != nil {
|
||||
zap.S().Errorln("ReadRegister 40032 error:", err)
|
||||
break
|
||||
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)
|
||||
break
|
||||
return nil
|
||||
}
|
||||
|
||||
s := make([]string, dataLength)
|
||||
@@ -99,10 +106,22 @@ func (r *reader) OnCardInfo(ctx context.Context, f func(info CardInfo)) {
|
||||
}
|
||||
}
|
||||
|
||||
f(CardInfo{
|
||||
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):
|
||||
info := r.GetCardInfo()
|
||||
if info != nil {
|
||||
f(info)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user