发卡关卡的读卡流程完成
This commit is contained in:
21
config.yml
21
config.yml
@@ -1,7 +1,7 @@
|
|||||||
location: wushan
|
location: wushan
|
||||||
point: 5
|
point: 5
|
||||||
relay: COM7
|
relay: COM7
|
||||||
maxTimeout: 60 # 单位 s
|
maxTimeout: 60 # 单位 s,必须大于 0
|
||||||
log:
|
log:
|
||||||
level: debug
|
level: debug
|
||||||
file:
|
file:
|
||||||
@@ -20,12 +20,13 @@ aliyun:
|
|||||||
voice: zhifeng_emo
|
voice: zhifeng_emo
|
||||||
game:
|
game:
|
||||||
url: rtu:///dev/ttyUSB0 # 点位 5 的串口地址
|
url: rtu:///dev/ttyUSB0 # 点位 5 的串口地址
|
||||||
# cardGroups: # 点位 4 的发卡器配置
|
# pushGroups: # 点位 4 的发卡器配置
|
||||||
# - name: gpiochip0
|
# - name: gpiochip0
|
||||||
# outOK: 6
|
# outOK: 6
|
||||||
# lower: 13
|
# lower: 13
|
||||||
# error: 19
|
# error: 19
|
||||||
# empty: 26
|
# empty: 26
|
||||||
# push: 11
|
# push: 11
|
||||||
# reset: 22
|
# reset: 22
|
||||||
# pull: 27
|
# pull: 27
|
||||||
|
# readUrl: rtu:///dev/ttyUSB0 # 点位 4 的读卡器配置
|
||||||
@@ -3,5 +3,6 @@ package game
|
|||||||
import "game-driver/internal/routes/play/card_pusher"
|
import "game-driver/internal/routes/play/card_pusher"
|
||||||
|
|
||||||
type ConfigPush struct {
|
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 (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"game-driver/config/game"
|
"game-driver/config/game"
|
||||||
"game-driver/internal/middleware"
|
"game-driver/internal/middleware"
|
||||||
"game-driver/internal/routes/play/card_pusher"
|
"game-driver/internal/routes/play/card_pusher"
|
||||||
"game-driver/internal/schema"
|
"game-driver/internal/schema"
|
||||||
"game-driver/leaf"
|
"game-driver/leaf"
|
||||||
|
"game-driver/pkg/card_reader"
|
||||||
"game-driver/pkg/utils"
|
"game-driver/pkg/utils"
|
||||||
"github.com/eclipse/paho.golang/paho"
|
"github.com/eclipse/paho.golang/paho"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -26,11 +30,35 @@ type ResponseBody struct {
|
|||||||
func PushCard(ctx context.Context) leaf.HandlerFunc {
|
func PushCard(ctx context.Context) leaf.HandlerFunc {
|
||||||
g := (game.G).(game.ConfigPush)
|
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)
|
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)
|
gv, _ := json.Marshal(group)
|
||||||
zap.S().Info("发卡器指针:", string(gv))
|
zap.S().Info("发卡器指针:", string(gv))
|
||||||
|
|
||||||
|
// 初始化发卡器
|
||||||
device, err := card_pusher.New(group)
|
device, err := card_pusher.New(group)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
zap.S().Panicln("初始化发卡器失败: ", err)
|
zap.S().Panicln("初始化发卡器失败: ", err)
|
||||||
@@ -84,6 +112,13 @@ func PushCard(ctx context.Context) leaf.HandlerFunc {
|
|||||||
// 延迟1秒获取结果并发送消息
|
// 延迟1秒获取结果并发送消息
|
||||||
time.AfterFunc(time.Second, func() {
|
time.AfterFunc(time.Second, func() {
|
||||||
if body.num != 0 {
|
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()
|
body.OutOk += devices[body.num-1].GetOutOk()
|
||||||
}
|
}
|
||||||
publishBody(ctx, c.Properties.ResponseTopic, body)
|
publishBody(ctx, c.Properties.ResponseTopic, body)
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ func WaitCard(ctx context.Context) leaf.HandlerFunc {
|
|||||||
wait.Add(1)
|
wait.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
defer wait.Done()
|
defer wait.Done()
|
||||||
reader.OnCardInfo(cc, func(info card_reader.CardInfo) {
|
reader.OnCardInfo(cc, func(info *card_reader.CardInfo) {
|
||||||
cardInfo.Send(info.ID)
|
cardInfo.Send(info.ID)
|
||||||
})
|
})
|
||||||
}()
|
}()
|
||||||
|
|||||||
@@ -14,9 +14,13 @@ import (
|
|||||||
type Reader interface {
|
type Reader interface {
|
||||||
io.Closer
|
io.Closer
|
||||||
SetUnitID(uint8)
|
SetUnitID(uint8)
|
||||||
|
// WriteUnitId 写入读卡器的 UnitID
|
||||||
|
WriteUnitId(uint16) error
|
||||||
|
// Init 初始化读卡器配置
|
||||||
Init() error
|
Init() error
|
||||||
// OnCardInfo 会在卡号信息发生变化时调用回调函数,直到上下文被取消,或者 Reader 被关闭。需要在 goroutine 中调用。
|
// OnCardInfo 会在卡号信息发生变化时调用回调函数,直到上下文被取消,或者 Reader 被关闭。需要在 goroutine 中调用。
|
||||||
OnCardInfo(context.Context, func(CardInfo))
|
OnCardInfo(context.Context, func(*CardInfo))
|
||||||
|
GetCardInfo() *CardInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
type CardInfo struct {
|
type CardInfo struct {
|
||||||
@@ -28,6 +32,14 @@ type reader struct {
|
|||||||
c *modbus.Client
|
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 {
|
func (r *reader) Init() error {
|
||||||
// 配置读卡间隔时间为 50 毫秒
|
// 配置读卡间隔时间为 50 毫秒
|
||||||
err := r.c.WriteRegister(8, 0x0511)
|
err := r.c.WriteRegister(8, 0x0511)
|
||||||
@@ -52,57 +64,64 @@ func (r *reader) Init() error {
|
|||||||
return nil
|
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 {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return
|
return
|
||||||
case <-time.After(100 * time.Millisecond):
|
case <-time.After(100 * time.Millisecond):
|
||||||
{
|
info := r.GetCardInfo()
|
||||||
// 读取状态寄存器确认是否信息已经准备好
|
if info != nil {
|
||||||
status, err := r.c.ReadRegister(29, modbus.HoldingRegister)
|
f(info)
|
||||||
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, ""),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user