Files
game-driver/pkg/card_reader/reader.go

157 lines
3.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package card_reader
import (
"context"
"fmt"
"github.com/munnik/modbus"
"go.uber.org/zap"
"io"
"math"
"strings"
"time"
)
type Reader interface {
io.Closer
SetUnitID(uint8)
// WriteUnitId 写入读卡器的 UnitID
WriteUnitId(uint16) error
// Init 初始化读卡器配置
Init() error
// OnCardInfo 会在卡号信息发生变化时调用回调函数,直到上下文被取消,或者 Reader 被关闭。需要在 goroutine 中调用。
OnCardInfo(context.Context, func(*CardInfo))
GetCardInfo() *CardInfo
}
type CardInfo struct {
Type uint16
ID string
}
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)
if err != nil {
return err
}
// 由低到高输出 500 毫秒
err = r.c.WriteRegister(9, 0xF20A)
if err != nil {
return err
}
// 读取后自动清空高字节00 不清空 01 清空
err = r.c.WriteRegister(10, 0x0103)
if err != nil {
return err
}
// 自动读卡号高字节高4位0 读一次 1 连续读
err = r.c.WriteRegister(11, 0x0301)
if err != nil {
return err
}
return nil
}
// 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):
info := r.GetCardInfo()
if info != nil {
f(info)
}
}
}
}
func (r *reader) SetUnitID(unitID uint8) {
_ = r.c.SetUnitID(unitID)
}
func (r *reader) Close() error {
return r.c.Close()
}
// NewReader 创建一个新的读卡器
func NewReader(URL string) (Reader, error) {
// 配置串口客户端
c, _ := modbus.NewClient(&modbus.Configuration{
URL: URL,
Speed: 9600,
DataBits: 8,
Timeout: 2 * time.Second,
Logger: zap.NewStdLog(zap.L()),
})
// 打开串口连接
err := c.Open()
if err != nil {
return nil, err
}
return &reader{c}, nil
}