Merge branch 'refs/heads/main' into clean_beep
This commit is contained in:
155
pkg/card_reader/reader.go
Normal file
155
pkg/card_reader/reader.go
Normal file
@@ -0,0 +1,155 @@
|
||||
package card_reader
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/grid-x/modbus"
|
||||
"go.uber.org/zap"
|
||||
"io"
|
||||
"math"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Reader interface {
|
||||
io.Closer
|
||||
// SetSlave 设置读卡器的 UnitID
|
||||
SetSlave(byte)
|
||||
// WriteUnitId 写入读卡器的 UnitID
|
||||
WriteUnitId(uint16) error
|
||||
// Init 初始化读卡器配置
|
||||
Init() error
|
||||
// OnCardInfo 会在卡号信息发生变化时调用回调函数,直到上下文被取消,或者 Reader 被关闭。需要在 goroutine 中调用。
|
||||
OnCardInfo(context.Context, func(*CardInfo))
|
||||
GetCardInfo() *CardInfo
|
||||
}
|
||||
|
||||
type CardInfo struct {
|
||||
Type []byte
|
||||
ID string
|
||||
}
|
||||
|
||||
type reader struct {
|
||||
h modbus.ClientHandler
|
||||
c modbus.Client
|
||||
}
|
||||
|
||||
// WriteUnitId 写入读卡器的 UnitID
|
||||
func (r *reader) WriteUnitId(id uint16) error {
|
||||
v := id<<8 + 1
|
||||
zap.S().Infof("WriteRegister 40007 %#x", v)
|
||||
_, err := r.c.WriteSingleRegister(6, v)
|
||||
return err
|
||||
}
|
||||
|
||||
// Init 初始化读卡器配置
|
||||
func (r *reader) Init() error {
|
||||
// 配置读卡间隔时间为 50 毫秒
|
||||
_, err := r.c.WriteSingleRegister(8, 0x0511)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 由低到高输出 500 毫秒
|
||||
_, err = r.c.WriteSingleRegister(9, 0xF20A)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 读取后自动清空,高字节:00 不清空 01 清空
|
||||
_, err = r.c.WriteSingleRegister(10, 0x0103)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 自动读卡号,高字节高4位:0 读一次 1 连续读
|
||||
_, err = r.c.WriteSingleRegister(11, 0x0301)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetCardInfo 获取卡号信息
|
||||
func (r *reader) GetCardInfo() *CardInfo {
|
||||
// 读取状态寄存器确认是否信息已经准备好
|
||||
status, err := r.c.ReadHoldingRegisters(29, 1)
|
||||
if err != nil {
|
||||
zap.S().Errorln("ReadRegister 40030 error:", err)
|
||||
return nil
|
||||
} else if len(status) != 2 || status[1] == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 读取卡号长度
|
||||
cardLength, err := r.c.ReadHoldingRegisters(30, 1)
|
||||
if err != nil {
|
||||
zap.S().Errorln("ReadRegister 40031 error:", err)
|
||||
return nil
|
||||
}
|
||||
dataLength := cardLength[0]
|
||||
|
||||
// 读取卡类型
|
||||
cardType, err := r.c.ReadHoldingRegisters(31, 1)
|
||||
if err != nil {
|
||||
zap.S().Errorln("ReadRegister 40032 error:", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 读取卡号数据
|
||||
cardData, err := r.c.ReadHoldingRegisters(32, uint16(math.Round(float64(dataLength)/2)))
|
||||
if err != nil {
|
||||
zap.S().Errorln("ReadRegister 40033~ error:", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
s := make([]string, dataLength)
|
||||
for i := 0; i < int(dataLength); i++ {
|
||||
s[i] = fmt.Sprintf("%02X", cardData[i])
|
||||
}
|
||||
|
||||
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) SetSlave(unitID byte) {
|
||||
r.h.SetSlave(unitID)
|
||||
}
|
||||
|
||||
func (r *reader) Close() error {
|
||||
return r.h.Close()
|
||||
}
|
||||
|
||||
// NewReader 创建一个新的读卡器
|
||||
func NewReader(address string) (Reader, error) {
|
||||
// 配置串口客户端
|
||||
h := modbus.NewRTUClientHandler(address)
|
||||
h.SlaveID = 1
|
||||
h.BaudRate = 9600
|
||||
h.DataBits = 8
|
||||
h.Parity = "N"
|
||||
h.StopBits = 1
|
||||
|
||||
// 连接串口
|
||||
if err := h.Connect(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 创建 modbus 客户端
|
||||
c := modbus.NewClient(h)
|
||||
|
||||
return &reader{h, c}, nil
|
||||
}
|
||||
54
pkg/channel/channel.go
Normal file
54
pkg/channel/channel.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package channel
|
||||
|
||||
import "sync"
|
||||
|
||||
// Closed 可包含关闭状态的通道
|
||||
type Closed[T any] struct {
|
||||
ch chan T
|
||||
closed bool
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
func (s *Closed[T]) Close() {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if s.closed {
|
||||
return
|
||||
}
|
||||
|
||||
close(s.ch)
|
||||
s.closed = true
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Closed[T]) Data() <-chan T {
|
||||
return s.ch
|
||||
}
|
||||
|
||||
func (s *Closed[T]) Send(data T) bool {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
if s.closed {
|
||||
return false
|
||||
}
|
||||
|
||||
s.ch <- data
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *Closed[T]) isClosed() bool {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
return s.closed
|
||||
}
|
||||
|
||||
func NewClosed[T any]() *Closed[T] {
|
||||
return &Closed[T]{
|
||||
ch: make(chan T),
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package relay
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"go.bug.st/serial/enumerator"
|
||||
)
|
||||
|
||||
func PrintPorts() {
|
||||
ports, err := enumerator.GetDetailedPortsList()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if len(ports) == 0 {
|
||||
return
|
||||
}
|
||||
for _, port := range ports {
|
||||
fmt.Printf("Port: %s\n", port.Name)
|
||||
if port.Product != "" {
|
||||
fmt.Printf(" Product Name: %s\n", port.Product)
|
||||
}
|
||||
if port.IsUSB {
|
||||
fmt.Printf(" USB ID : %s:%s\n", port.VID, port.PID)
|
||||
fmt.Printf(" USB serial : %s\n", port.SerialNumber)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,46 +1,69 @@
|
||||
package relay
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"go.bug.st/serial"
|
||||
"github.com/grid-x/modbus"
|
||||
"io"
|
||||
)
|
||||
|
||||
type Device struct {
|
||||
port serial.Port
|
||||
type Relay interface {
|
||||
io.Closer
|
||||
// SetSlave 设置继电器的 UnitID
|
||||
SetSlave(byte)
|
||||
// On 打开继电器
|
||||
On(int) error
|
||||
// Off 关闭继电器
|
||||
Off(int) error
|
||||
// OnAll 打开所有继电器
|
||||
OnAll() error
|
||||
// OffAll 关闭所有继电器
|
||||
OffAll() error
|
||||
}
|
||||
|
||||
func (r *Device) Close() error {
|
||||
return r.port.Close()
|
||||
type device struct {
|
||||
h modbus.ClientHandler
|
||||
c modbus.Client
|
||||
}
|
||||
|
||||
func (r *Device) On(num int) error {
|
||||
_, err := io.WriteString(r.port, fmt.Sprintf("AT+OUT%v+1=ON\r\n", num))
|
||||
func (r *device) SetSlave(slaveID byte) {
|
||||
r.h.SetSlave(slaveID)
|
||||
}
|
||||
|
||||
func (r *device) Close() error {
|
||||
return r.h.Close()
|
||||
}
|
||||
|
||||
func (r *device) OnAll() error {
|
||||
_, err := r.c.WriteMultipleCoils(uint16(0), 16, []byte{0xFF, 0xFF})
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *Device) Off(num int) error {
|
||||
_, err := io.WriteString(r.port, fmt.Sprintf("AT+OUT%v+1=OFF\r\n", num))
|
||||
func (r *device) OffAll() error {
|
||||
_, err := r.c.WriteMultipleCoils(uint16(0), 16, []byte{0x00, 0x00})
|
||||
return err
|
||||
}
|
||||
|
||||
func New(portName string, reader func(msg string)) (*Device, error) {
|
||||
port, err := serial.Open(portName, &serial.Mode{
|
||||
BaudRate: 9600,
|
||||
DataBits: 8,
|
||||
})
|
||||
if err != nil {
|
||||
func (r *device) On(num int) error {
|
||||
_, err := r.c.WriteSingleCoil(uint16(num), 0xFF00)
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *device) Off(num int) error {
|
||||
_, err := r.c.WriteSingleCoil(uint16(num), 0x0000)
|
||||
return err
|
||||
}
|
||||
|
||||
func New(address string) (Relay, error) {
|
||||
h := modbus.NewRTUClientHandler(address)
|
||||
h.SlaveID = 1
|
||||
h.BaudRate = 9600
|
||||
h.DataBits = 8
|
||||
h.Parity = "N"
|
||||
h.StopBits = 1
|
||||
|
||||
if err := h.Connect(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
go func() {
|
||||
for {
|
||||
r := bufio.NewReader(port)
|
||||
line, _, _ := r.ReadLine()
|
||||
if reader != nil {
|
||||
reader(string(line))
|
||||
}
|
||||
}
|
||||
}()
|
||||
return &Device{port: port}, nil
|
||||
c := modbus.NewClient(h)
|
||||
|
||||
return &device{h, c}, nil
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@ func (tts *AliTTS) getToken() error {
|
||||
func (tts *AliTTS) Get(text string) (io.Reader, error) {
|
||||
param := nls.DefaultSpeechSynthesisParam()
|
||||
param.Volume = 100
|
||||
param.Voice = tts.Voice
|
||||
|
||||
err := tts.getToken()
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user