123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612 |
- package cabinet_pkg
- import (
- "dy-admin/internal/pcmserver/bus/cabinet_pkg/dataProto"
- "dy-admin/internal/pcmserver/bus/model"
- "dy-admin/internal/pcmserver/global"
- "dy-admin/internal/pcmserver/pkg/code"
- "dy-admin/pkg/log"
- "dy-admin/pkg/rescode"
- "encoding/hex"
- "fmt"
- "go.uber.org/zap"
- "strings"
- "time"
- )
- // AddCabinet 添加柜子
- // info 柜子基础信息
- // cabinetConnectChan 柜子连接状态
- // gridStatusChan 柜子所有格子状态回传通道
- func AddCabinet(cabinetInfo model.Cabinet, cabinetConnectChan chan<- *dataProto.CabinetConnect,
- gridStatusChan chan<- *dataProto.GridStatsProto, openStatusChan chan<- *dataProto.GridLockStatusProto) error {
- if cabinets == nil {
- return fmt.Errorf("cabinets is nil")
- }
- cb := newCabinet(cabinetInfo, cabinetConnectChan, gridStatusChan, openStatusChan)
- cabinets.setCabinet(cabinetInfo.ID, cb)
- return nil
- }
- // DelCabinet 删除柜子
- func DelCabinet(cabinetId int) error {
- if cabinets == nil {
- return fmt.Errorf("cabinets is nil")
- }
- cab, exists := cabinets.getCabinet(cabinetId)
- if !exists {
- return nil
- }
- if cab != nil {
- if cab.conn != nil {
- err := cab.conn.Close()
- if err != nil {
- return err
- }
- }
- }
- cabinets.deleteCabinet(cabinetId)
- return nil
- }
- func cabinetPreCheck(cabinetId int) (*cabinet, error) {
- if cabinets == nil {
- return nil, fmt.Errorf("cabinets is nil")
- }
- cab, ok := cabinets.getCabinet(cabinetId)
- if !ok {
- err := fmt.Errorf("cabinetID %d not found", cabinetId)
- return nil, rescode.RegisterErrorWithCause(err, code.ErrCodeMap[code.ErrCabinetMemNotFoundCode])
- }
- if !cab.memInfo.IsConnect {
- err := fmt.Errorf("cabinetID %d not connected", cabinetId)
- return nil, rescode.RegisterErrorWithCause(err, code.ErrCodeMap[code.ErrCabinetNotConnectCode])
- }
- return cab, nil
- }
- func SetCabinetNumber(cabinetId int) error {
- cab, err := cabinetPreCheck(cabinetId)
- if err != nil {
- return err
- }
- ccp := &dataProto.CabinetConfigProto{
- PkgLength: dataProto.PkgLengthCabinetConfig,
- StartSymbol: dataProto.StartSymbolCabinetConfig,
- Cmd: dataProto.CmdCabinetConfig,
- CabinetNumber: cab.memInfo.CabinetNum,
- CabinetGridCount: cab.memInfo.GridCount,
- CRCCode: 0x1DC0,
- }
- encodeBytes, err := dataProto.CabinetConfigProtoEncode(ccp)
- if err != nil {
- return rescode.RegisterErrorWithCause(err, code.ErrCodeMap[code.ErrCabinetDeviceCode])
- }
- tcpServer.WriteData(cab.conn, encodeBytes)
- // 记录下发设置柜子编号指令
- deviceLogChan <- &MsgLog{
- CabinetID: cabinetId,
- MsgType: model.MsgTypeSend,
- MsgName: "设置柜子编号指令",
- Message: encodeBytes,
- }
- err = waitCabinetConfigResponse(cab.responseChannels.cabinetConfigResChannel, cab.memInfo.CabinetNum, 10)
- if err != nil {
- return rescode.RegisterErrorWithCause(err, code.ErrCodeMap[code.ErrCabinetTimeoutCode])
- }
- return nil
- }
- // EnableOpenDoor 允许开门
- func EnableOpenDoor(cabinetId int, uptMem bool) error {
- cab, err := cabinetPreCheck(cabinetId)
- if err != nil {
- return err
- }
- if !IsHumanization() {
- // 强制管理 下发允许开门指令
- controlProto := &dataProto.DoorControlProto{
- PkgLength: dataProto.PkgLengthDoorControl,
- StartSymbol: dataProto.StartSymbolDoorControl,
- CabinetNumber: cab.memInfo.CabinetNum,
- Cmd: dataProto.CmdDoorControlEnable,
- }
- controlProtoBytes, err := dataProto.DoorControlProtoEncode(controlProto)
- if err != nil {
- tips := fmt.Sprintf("cabinetId:%d", cabinetId)
- return rescode.RegisterErrorWithMessage(err, tips, code.ErrCodeMap[code.ErrCabinetDeviceCode])
- }
- //发送
- tcpServer.WriteData(cab.conn, controlProtoBytes)
- // 记录下发允许开门指令
- deviceLogChan <- &MsgLog{
- CabinetID: cabinetId,
- MsgType: model.MsgTypeSend,
- MsgName: "允许开门指令",
- Message: controlProtoBytes,
- }
- err = waitDoorControlResponse(cab.responseChannels.doorControlResChannel, dataProto.CmdDoorControlEnable, 10)
- if err != nil {
- tips := fmt.Sprintf("cabinetId:%d", cabinetId)
- return rescode.RegisterErrorWithMessage(err, tips, code.ErrCodeMap[code.ErrCabinetTimeoutCode])
- }
- }
- //更新内存柜子信息未允许开启状态
- if uptMem {
- cab.memInfo.IsAllowOpen = true
- }
- // 发送获取柜子所有消息的指令
- go func() {
- // 柜子要求.发送禁止柜门后1分钟后再获取状态。
- time.Sleep(time.Second * 60)
- err = GetCabinetStatus(cabinetId)
- if err != nil {
- log.Error("获取柜门信息失败", zap.Error(err))
- }
- }()
- return nil
- }
- // DisableOpenDoor 禁止打开所有柜门
- func DisableOpenDoor(cabinetId int) error {
- cab, err := cabinetPreCheck(cabinetId)
- if err != nil {
- return err
- }
- if !IsHumanization() {
- // 强制管理
- controlProto := &dataProto.DoorControlProto{
- PkgLength: dataProto.PkgLengthDoorControl,
- StartSymbol: dataProto.StartSymbolDoorControl,
- CabinetNumber: cab.memInfo.CabinetNum,
- Cmd: dataProto.CmdDoorControlDisable,
- }
- controlProtoBytes, err := dataProto.DoorControlProtoEncode(controlProto)
- if err != nil {
- tips := fmt.Sprintf("cabinetId:%d", cabinetId)
- return rescode.RegisterErrorWithMessage(err, tips, code.ErrCodeMap[code.ErrCabinetDeviceCode])
- }
- //发送
- tcpServer.WriteData(cab.conn, controlProtoBytes)
- // 记录下发禁止开门指令
- deviceLogChan <- &MsgLog{
- CabinetID: cabinetId,
- MsgType: model.MsgTypeSend,
- MsgName: "禁止开门指令",
- Message: controlProtoBytes,
- }
- err = waitDoorControlResponse(cab.responseChannels.doorControlResChannel, dataProto.CmdDoorControlDisable, 10)
- if err != nil {
- tips := fmt.Sprintf("cabinetId:%d", cabinetId)
- return rescode.RegisterErrorWithMessage(err, tips, code.ErrCodeMap[code.ErrCabinetTimeoutCode])
- }
- }
- //更新内存柜子信息未允许开启状态
- cab.memInfo.IsAllowOpen = false
- // 发送获取柜子所有消息的指令
- go func() {
- // 柜子要求.发送禁止柜门后1分钟后再获取状态。
- time.Sleep(time.Second * 60)
- err = GetCabinetStatus(cabinetId)
- if err != nil {
- log.Error("获取柜门信息失败", zap.Error(err))
- }
- }()
- return nil
- }
- func EnableGrid(cabinetId int, gridNum uint16) error {
- cab, err := cabinetPreCheck(cabinetId)
- if err != nil {
- return err
- }
- controlProto := &dataProto.GridControlProto{
- PkgLength: dataProto.PkgLengthGridControl,
- StartSymbol: dataProto.StartSymbolGridControl,
- CabinetNumber: cab.memInfo.CabinetNum,
- GridNumber: gridNum,
- Cmd: dataProto.CmdGridControlEnable,
- }
- controlProtoBytes, err := dataProto.GridControlProtoEncode(controlProto)
- if err != nil {
- return rescode.RegisterErrorWithCause(err, code.ErrCodeMap[code.ErrCabinetDeviceCode])
- }
- // 记录下发允许打开格子指令
- deviceLogChan <- &MsgLog{
- CabinetID: cabinetId,
- MsgType: model.MsgTypeSend,
- MsgName: fmt.Sprintf("允许打开%d号格子指令", gridNum),
- Message: controlProtoBytes,
- }
- //发送
- tcpServer.WriteData(cab.conn, controlProtoBytes)
- err = waitGridControlResponse(cab.responseChannels.gridControlResChannel, dataProto.CmdGridControlEnable, 10)
- if err != nil {
- return rescode.RegisterErrorWithCause(err, code.ErrCodeMap[code.ErrCabinetTimeoutCode])
- }
- return nil
- }
- func DisableGrid(cabinetId int, gridNum uint16) error {
- cab, err := cabinetPreCheck(cabinetId)
- if err != nil {
- return err
- }
- controlProto := &dataProto.GridControlProto{
- PkgLength: dataProto.PkgLengthGridControl,
- StartSymbol: dataProto.StartSymbolGridControl,
- CabinetNumber: cab.memInfo.CabinetNum,
- GridNumber: gridNum,
- Cmd: dataProto.CmdGridControlDisable,
- }
- controlProtoBytes, err := dataProto.GridControlProtoEncode(controlProto)
- if err != nil {
- return rescode.RegisterErrorWithCause(err, code.ErrCodeMap[code.ErrCabinetDeviceCode])
- }
- //发送
- tcpServer.WriteData(cab.conn, controlProtoBytes)
- // 记录下发禁止打开格子指令
- deviceLogChan <- &MsgLog{
- CabinetID: cabinetId,
- MsgType: model.MsgTypeSend,
- MsgName: fmt.Sprintf("禁止打开%d号格子指令", gridNum),
- Message: controlProtoBytes,
- }
- err = waitGridControlResponse(cab.responseChannels.gridControlResChannel, dataProto.CmdGridControlDisable, 10)
- if err != nil {
- return rescode.RegisterErrorWithCause(err, code.ErrCodeMap[code.ErrCabinetTimeoutCode])
- }
- return nil
- }
- // OpenDoor 打开指定柜门
- func OpenDoor(cabinetId int, gridID uint16) error {
- cab, err := cabinetPreCheck(cabinetId)
- if err != nil {
- return err
- }
- // 平台可以在禁止时开门
- //if !cab.cabinetInfo.IsAllowOpen {
- // return fmt.Errorf("此时禁止打开箱门")
- //}
- openDoor := &dataProto.OpenGridProto{
- PkgLength: dataProto.PkgLengthOpenGrid,
- StartSymbol: dataProto.StartSymbolOpenGrid,
- Cmd: dataProto.CmdOpenGrid,
- CabinetNumber: cab.memInfo.CabinetNum,
- GridNumber: gridID,
- }
- //编码
- openDoorBytes, err := dataProto.OpenGridProtoEncode(openDoor)
- if err != nil {
- return rescode.RegisterErrorWithCause(err, code.ErrCodeMap[code.ErrCabinetDeviceCode])
- }
- //发送
- tcpServer.WriteData(cab.conn, openDoorBytes)
- // 记录下发打开格子指令
- deviceLogChan <- &MsgLog{
- CabinetID: cabinetId,
- MsgType: model.MsgTypeSend,
- MsgName: fmt.Sprintf("打开%d号格子指令", gridID),
- Message: openDoorBytes,
- }
- // 开箱门操作不等待开门结果。 统一由开门状态通道获取箱门的状态。
- log.Info("开门命令下发成功", zap.String("cabinetIP", cab.memInfo.CabinetIP), zap.Uint16("number", cab.memInfo.CabinetNum))
- return nil
- }
- // GetCabinetStatus 手动获取柜门所有箱门的状态
- func GetCabinetStatus(cabinetId int) error {
- cab, err := cabinetPreCheck(cabinetId)
- if err != nil {
- return err
- }
- getReq := &dataProto.GetCabinetReq{
- PkgLength: dataProto.PkgLengthGetCabinetReq,
- StartSymbol: dataProto.StartSymbolGetCabinetReq,
- Cmd: dataProto.CmdGetCabinetReq,
- CabinetNumber: cab.memInfo.CabinetNum,
- }
- //编码
- openDoorBytes, err := dataProto.GetCabinetReqEncode(getReq)
- if err != nil {
- return rescode.RegisterErrorWithCause(err, code.ErrCodeMap[code.ErrCabinetDeviceCode])
- }
- //发送
- tcpServer.WriteData(cab.conn, openDoorBytes)
- // 记录下发获取所有柜门状态指令
- deviceLogChan <- &MsgLog{
- CabinetID: cabinetId,
- MsgType: model.MsgTypeSend,
- MsgName: "获取指定柜子所有格子状态指令",
- Message: openDoorBytes,
- }
- //手动获取箱门状态响应全部由服务层管道读取后统一处理
- log.Info("获取柜子信息命令下发成功", zap.String("cabinetIP", cab.memInfo.CabinetIP), zap.Uint16("number", cab.memInfo.CabinetNum))
- return nil
- }
- // SendCabinetDoorStatus 发送柜门此时是否允许开
- func SendCabinetDoorStatus(cabinetId int) error {
- if cabinets == nil {
- return fmt.Errorf("cabinets is nil")
- }
- cab, ok := cabinets.getCabinet(cabinetId)
- if !ok {
- return fmt.Errorf("cabinetId %d not found", cabinetId)
- }
- var doorControlCmd uint8
- if cab.memInfo.IsAllowOpen {
- doorControlCmd = dataProto.CmdDoorControlEnable
- } else {
- doorControlCmd = dataProto.CmdDoorControlDisable
- }
- dcp := &dataProto.DoorControlProto{
- PkgLength: dataProto.PkgLengthDoorControl,
- StartSymbol: dataProto.StartSymbolDoorControl,
- CabinetNumber: cab.memInfo.CabinetNum,
- Cmd: doorControlCmd,
- }
- protoBytes, err := dataProto.DoorControlProtoEncode(dcp)
- if err != nil {
- return rescode.RegisterErrorWithCause(err, code.ErrCodeMap[code.ErrCabinetDeviceCode])
- }
- tcpServer.WriteData(cab.conn, protoBytes)
- if cab.memInfo.IsAllowOpen {
- // 记录下发允许开门指令
- deviceLogChan <- &MsgLog{
- CabinetID: cabinetId,
- MsgType: model.MsgTypeSend,
- MsgName: "允许开门指令",
- Message: protoBytes,
- }
- } else {
- // 记录下发禁止开门指令
- deviceLogChan <- &MsgLog{
- CabinetID: cabinetId,
- MsgType: model.MsgTypeSend,
- MsgName: "禁止开门指令",
- Message: protoBytes,
- }
- }
- // 不是页面发起的 不能在这里同步等待
- go func() {
- err = waitDoorControlResponse(cab.responseChannels.doorControlResChannel, doorControlCmd, 10)
- if err != nil {
- log.Error("waitDoorControlResponse err", zap.Error(err))
- }
- }()
- return nil
- }
- func SendPing(cabinetId int) error {
- if cabinets == nil {
- return fmt.Errorf("cabinets is nil")
- }
- cab, ok := cabinets.getCabinet(cabinetId)
- if !ok {
- return fmt.Errorf("cabinetId %d not found", cabinetId)
- }
- pingBytes, err := hex.DecodeString(dataProto.PingHex)
- if err != nil {
- return rescode.RegisterErrorWithCause(err, code.ErrCodeMap[code.ErrCabinetDeviceCode])
- }
- tcpServer.WriteData(cab.conn, pingBytes)
- //deviceLogChan <- &MsgLog{
- // CabinetID: cabinetId,
- // MsgType: model.MsgTypeSend,
- // MsgName: "ping",
- // Message: pingBytes,
- //}
- // 等待响应
- if err := waitPongResponse(cab.responseChannels.pongResChannel, 10); err != nil {
- return err
- }
- return nil
- }
- func waitPongResponse(resChan chan []byte, waitSecond int) error {
- ticker := time.NewTicker(time.Second * time.Duration(waitSecond))
- for {
- select {
- case <-ticker.C:
- return fmt.Errorf("wait pong time out")
- case pongBytes := <-resChan:
- if strings.ToUpper(hex.EncodeToString(pongBytes)) == dataProto.PongHex {
- return nil
- }
- }
- }
- }
- func waitCabinetConfigResponse(resChan chan *dataProto.CabinetConfigProto, number uint16, waitSecond int) error {
- ticker := time.NewTicker(time.Second * time.Duration(waitSecond))
- for {
- select {
- case <-ticker.C:
- return fmt.Errorf("wait CabinetConfig response time out")
- case resProto := <-resChan:
- log.Info("waitResponse", zap.Any("resProto", resProto))
- if resProto.CabinetNumber == number {
- return nil
- } else {
- log.Warnf("set number is %d,but response number is %d,not matched", number, resProto.CabinetNumber)
- continue
- }
- }
- }
- }
- func waitDoorControlResponse(resChan chan *dataProto.DoorControlProto, cmd uint8, waitSecond int) error {
- ticker := time.NewTicker(time.Second * time.Duration(waitSecond))
- for {
- select {
- case <-ticker.C:
- return fmt.Errorf("wait DoorControl response time out")
- case resProto := <-resChan:
- log.Info("doorControlResChannel out")
- if resProto.Cmd == cmd {
- return nil
- } else {
- log.Warnf("set cmd %d,but response cmd is %d,not matched", cmd, resProto.Cmd)
- continue
- }
- }
- }
- }
- func waitGridControlResponse(resChan chan *dataProto.GridControlProto, cmd uint8, waitSecond int) error {
- ticker := time.NewTicker(time.Second * time.Duration(waitSecond))
- for {
- select {
- case <-ticker.C:
- return fmt.Errorf("waitGridControlResponse wait response time out")
- case resProto := <-resChan:
- if resProto == nil {
- return fmt.Errorf("res proto is nil")
- }
- log.Info("gridControlResChannel out")
- if resProto.Cmd == cmd {
- return nil
- } else {
- log.Warnf("set cmd %d,but response cmd is %d,not matched", cmd, resProto.Cmd)
- continue
- }
- }
- }
- }
- func waitOpenDoorResponse(resChan chan *dataProto.GridLockStatusProto, cabinetNum uint16, gridNum uint16, waitSecond int) error {
- ticker := time.NewTicker(time.Second * time.Duration(waitSecond))
- for {
- select {
- case <-ticker.C:
- return fmt.Errorf("wait response time out")
- case resProto := <-resChan:
- log.Info("waitResponse", zap.Any("resProto", resProto))
- if resProto.CabinetNumber != cabinetNum {
- return fmt.Errorf("set cabinet number is %d,but response number is %d,not matched", cabinetNum, resProto.CabinetNumber)
- }
- if resProto.GridNumber != gridNum {
- return fmt.Errorf("set gird number is %d,but response number is %d,not matched", gridNum, resProto.GridNumber)
- }
- if resProto.LockStatus == dataProto.OpenGridLockBroken {
- return fmt.Errorf("开启失败,锁故障")
- }
- if resProto.LockStatus == dataProto.OpenGridLockOpen {
- return nil
- }
- }
- }
- }
- func sendCabinetNum(cabinetId int) error {
- err := SetCabinetNumber(cabinetId)
- if err != nil {
- return err
- }
- return nil
- }
- func sendCabinetDoorControl(cabinetId int) error {
- cab, ok := cabinets.getCabinet(cabinetId)
- if !ok {
- return fmt.Errorf("sendCabinetNum err,remoteId %d not found", cabinetId)
- }
- if cab.memInfo.IsAllowOpen {
- if err := EnableOpenDoor(cabinetId, true); err != nil {
- return err
- }
- } else {
- if err := DisableOpenDoor(cabinetId); err != nil {
- return err
- }
- }
- return nil
- }
- func sendGetCabinetStatus(cabinetId int) error {
- return GetCabinetStatus(cabinetId)
- }
- func sendVacation(cabinetId int) error {
- cab, ok := cabinets.getCabinet(cabinetId)
- if !ok {
- return fmt.Errorf("sendCabinetNum err,remoteId %d not found", cabinetId)
- }
- // 获取当前柜子的所有请假人员
- var staffs []model.Staff
- err := global.DB.Model(&model.Staff{}).Where("cabinet_id = ?", cab.memInfo.CabinetID).Where("vacation_state = ?", 2).Find(&staffs).Error
- if err != nil {
- return err
- }
- for _, staff := range staffs {
- // 下发请假指令
- err = EnableGrid(cabinetId, uint16(staff.GridDeviceID))
- if err != nil {
- return err
- }
- // 每个人间隔1毫秒 张总要求
- time.Sleep(time.Microsecond)
- }
- return nil
- }
|