package message import ( "bytes" "encoding/binary" "encoding/hex" "fmt" "github.com/snksoft/crc" "log/slog" "strconv" "sync" ) const ( TRAIN_BTM_ENDA = 0x75E1 TRAIN_BTM_ENDB = 0x75E2 ID_COMMAND_TYPE = 0xF8 //命令帧 REQT_TYPE = 0xE6 //请求帧 ) const ( COMMAND_TYPE = 0x90 //ID 命令帧 VOBC→BTM20 字节 REQUEST_TYPE = 0x91 //请求帧 VOBC→BTM34 字节 MESSAGE_TYPE = 0x92 //报文帧 BTM→VOBC 135 字节 FREE_MESSAGE_TYPE = 0x94 //空闲帧 BTM→VOBC 135 字节 ) var PACKAGE_HEAD = []byte{0xFF, 0xFE} var PACKAGE_END = []byte{0xFF, 0xFD} func BtmVobcDecode(packData []byte) (byte, []byte, error) { head := packData[:2] end := packData[len(packData)-2:] if !bytes.Equal(head, PACKAGE_HEAD) || !bytes.Equal(end, PACKAGE_END) { slog.Error("btm vobc 数据包头或包尾尾错误", hex.EncodeToString(packData)) return 0, nil, fmt.Errorf("btm vobc 数据包头或包尾尾错误") } data := packData[2 : len(packData)-2] command := data[0] if command != ID_COMMAND_TYPE && command != REQT_TYPE { slog.Error("btm vobc 解析未知命令帧", strconv.FormatInt(int64(command), 16), command) return 0, nil, fmt.Errorf("btm vobc 解析未知命令帧") } dataText := data[1:] if command == ID_COMMAND_TYPE { frameType := dataText[0] return frameType, dataText, nil } else if command == REQT_TYPE { newDatatext, _ := TranslateFromFFFE(dataText) rssp := &RsspRsd{} rsspErr := rssp.Decode(newDatatext) if rsspErr != nil { //slog.Error("解析请求帧rssp-i失败,元数据:", hex.EncodeToString(cfs), "错误信息:", rsspErr.Error()) return 0, nil, fmt.Errorf("解析请求帧rssp-i失败") } return rssp.Sad[0], rssp.Sad, nil } return 0, nil, fmt.Errorf("btm vobc 解析未知命令帧") } const ( WAIT_FF_C1 = 0x00 WAIT_FF_C2 = 0x01 WAIT_NO_FF = 0x02 WAIT_FF_POS = 0x03 ABNORMAL_STATE = 0x04 /*FFFE数据接收状态*/ COM_WAIT_START_FF = 0x00 COM_WAIT_START_FE = 0x01 COM_WAIT_STOP_FF = 0x02 COM_WAIT_STOP_FD = 0x03 ) /* func SourceDataDecode(packData []byte) []BaseBtmVobc { data, _ := TranslateFromFFFE(packData) buf := bytes.NewBuffer(data) } func parseData(buf *bytes.Buffer) { h1, _ := buf.ReadByte() h2, _ := buf.ReadByte() if bytes.Equal(PACKAGE_HEAD, []byte{h1, h2}) { t, _ := buf.ReadByte() var ft byte = 0 if t == ID_COMMAND_TYPE || t == REQT_TYPE { ft, _ = buf.ReadByte() if t == ID_COMMAND_TYPE { return parseIdFrame(ft, buf.Bytes()) } else if t == REQT_TYPE { } } else { } } } */ func parseIdFrame(frame byte, data []byte) BtmVobcIdCommand { buf := bytes.NewBuffer(data) dataLen, _ := buf.ReadByte() dsn, _ := buf.ReadByte() var btmId uint16 var vobcId uint16 var vobcLifeId uint32 var yuliu [5]byte var crc32 uint32 binary.Read(buf, binary.BigEndian, &btmId) binary.Read(buf, binary.BigEndian, &vobcId) binary.Read(buf, binary.BigEndian, &vobcLifeId) binary.Read(buf, binary.BigEndian, &yuliu) binary.Read(buf, binary.BigEndian, &crc32) return BtmVobcIdCommand{BaseBtmVobc: BaseBtmVobc{Frame: frame, FrameLen: dataLen, AutoIdFrame: dsn, Crc32: crc32}} } type BaseBtmVobc struct { Frame byte //帧类型 FrameLen byte //帧长定义为 TEXT+CRC32,ID 命令帧为 20 字节; AutoIdFrame byte // 无论何时传输数据,该数都在 1-255 范围内递增,在错误重传时也是递增的,255 之后是 1,不使用 0; Crc32 uint32 } func baseDecode(d []byte) (BaseBtmVobc, *bytes.Buffer) { buf := bytes.NewBuffer(d) frame, _ := buf.ReadByte() frameLen, _ := buf.ReadByte() autoIdFrame, _ := buf.ReadByte() crc32 := binary.BigEndian.Uint32(d[len(d)-4:]) return BaseBtmVobc{Frame: frame, FrameLen: frameLen, Crc32: crc32, AutoIdFrame: autoIdFrame}, buf } func baseEncode(source []byte) []byte { data := make([]byte, 0) crc32 := crc.CalculateCRC(crc.CRC32, source) newSource := binary.BigEndian.AppendUint32(source, uint32(crc32)) f2 := make([]byte, len(newSource)*2) lens := aa(newSource, f2) fffeData := f2[:lens] data = append(data, PACKAGE_HEAD...) data = append(data, fffeData...) data = append(data, PACKAGE_END...) return data } // ID 命令帧的正文 type BtmVobcIdCommand struct { BaseBtmVobc BtmId uint16 //VOBC 向 BTM 分配的 ID,暂定 0x75E1 或者0x75A2,其他无效; VobcId uint16 //暂定 0x5511,其他无效 VobcLifeNum uint32 //7~10 1~FFFFFFFF,0 不使用 yuliu []byte //11-15 预留字节 } func (b *BtmVobcIdCommand) Decode(data []byte) { base, buf := baseDecode(data) b.BaseBtmVobc = base var btmId uint16 var vobcId uint16 var lifeNum uint32 binary.Read(buf, binary.BigEndian, &btmId) binary.Read(buf, binary.BigEndian, &vobcId) binary.Read(buf, binary.BigEndian, &lifeNum) b.BtmId = btmId b.VobcId = vobcId b.VobcLifeNum = lifeNum } const ( REQ_FRAME_STATUS_OK = 0x06 REQ_FRAME_STATUS_ERROR = 0x15 REQ_FRAME_STATUS_BOOT = 0x00 REQ_PACKETS_TYPE_FREE = 0x05 REQ_PACKETS_TYPE_MSG = 0x0A REQ_PACKETS_TYPE_BOOT = 0x00 ) // 请求帧的正文 type BtmVobcReq struct { BaseBtmVobc FrameStatus byte //帧正确/不正确 06h:帧正确15h:不正确00h:开机状态填00 其它无效 MessageType byte // 空闲/报文数据 05h:空闲0Ah:报文数据00h:开机状态填00 其它无效 MessageSerial byte //报文序列号 1-255;开机时使用0 yuliu []byte //预留字节(10 字节) VobcLifeNum uint32 // VOBC 周期号 1~FFFFFFFF,0 不使用 TimeStamp []byte //年月日时分秒各占一个字节 Speed uint16 //速度 单位:cm/s VobcLifeWalkDistance uint16 //VOBC 周期走行距离 单位:cm } func (b *BtmVobcReq) Decode(data []byte) { base, buf := baseDecode(data) b.BaseBtmVobc = base b.FrameStatus, _ = buf.ReadByte() b.MessageType, _ = buf.ReadByte() b.MessageSerial, _ = buf.ReadByte() var tyuli = make([]byte, 10) buf.Read(tyuli) //b.yuliu = data[5:15] var lifeNum uint32 ts := make([]byte, 6) var speed uint16 var walkDis uint16 binary.Read(buf, binary.BigEndian, &lifeNum) buf.Read(ts) binary.Read(buf, binary.BigEndian, &speed) binary.Read(buf, binary.BigEndian, &walkDis) b.VobcLifeNum = lifeNum b.TimeStamp = ts b.Speed = speed b.VobcLifeWalkDistance = walkDis } var lock sync.Mutex const ( btm_status_ok = 0x00 btm_status_warn = 0x04 ) var mesage_yuliu = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0} //11~19 预留 var yuliu3 = []byte{0, 0, 0, 0, 0, 0} //8~13 保留 const ( BTM_STSTUS_NORMAL = 0x00 BTM_STSTUS_WARN = 0x04 ) // 报文帧的正文 type BtmVobcMessage struct { BaseBtmVobc FontTtl uint16 //前沿 TTL 时间 单位为 ms,溢出为0xffff,高字节在前;车体及应答器器地面环境理想情况下误差小于 5ms MsgSerial byte //报文序列号 1-255;不使用 0 BtmStatus byte //BTM 工作状态 00H-工作正常;04H-警告 BTM 有轻微故障(单套故障,整机能工作),向BDMS 汇报;FFH-BTM 故障,不能正常工作;在MMI进行故障提示并向ATS 汇报 Enter1 byte //1 通道好码率 0~100 Enter2 byte //2 通道好码率 0~100 DecodeTime uint16 //解码时间:从包络前沿到解码成功的时间,单位0.1ms。 yuliu []byte //11~19 预留 填 0 BackTtl uint16 //后沿 TTL 时间单位为 ms,溢出为0xffff,高字节在前;车体及应答器器地面环境理想情况下误差小于 5ms. BtmMsg []byte //22~125 应答器报文 ResponseTime byte //0~150,其他非法,单位0.1ms 误差小于 3ms VobcLifeNum uint32 //VOBC 周期号 1~FFFFFFFF,0 不使用。 } func (b *BtmVobcMessage) Encode() []byte { data := make([]byte, 0) buf := bytes.NewBuffer(data) binary.Write(buf, binary.BigEndian, byte(MESSAGE_TYPE)) binary.Write(buf, binary.BigEndian, byte(0x87)) //binary.Write(buf, binary.BigEndian, b.AutoIdFrame) binary.Write(buf, binary.BigEndian, b.AutoIdFrame) binary.Write(buf, binary.BigEndian, b.FontTtl) binary.Write(buf, binary.BigEndian, b.MsgSerial) binary.Write(buf, binary.BigEndian, b.BtmStatus) binary.Write(buf, binary.BigEndian, byte(100)) //b.Enter1 binary.Write(buf, binary.BigEndian, byte(100)) //b.Enter2 binary.Write(buf, binary.BigEndian, b.DecodeTime) binary.Write(buf, binary.BigEndian, mesage_yuliu) binary.Write(buf, binary.BigEndian, b.BackTtl) binary.Write(buf, binary.BigEndian, b.BtmMsg) binary.Write(buf, binary.BigEndian, b.ResponseTime) binary.Write(buf, binary.BigEndian, b.VobcLifeNum) return baseEncode(buf.Bytes()) } type BtmVobcMsgFree struct { BaseBtmVobc //yuliu1 byte //yuliu2 byte MsgSerial byte //1-255;开机时为0 BtmStatus byte //BTM 工作状态 00H-工作正常;04H-警告 BTM 有轻微故障(单套故障,整机能工作),向BDMS 汇报;FFH-BTM 故障,不能正常工作;在MMI 进行故障提示并向ATS 汇报 WorkTemperature byte //yuliu3 []byte //8~13 保留 填 0 //0-1 位 功放 1 电流状态 功放电流状态:“1”-欠流;“2”- 过流 ;“3”-正常(欠流和过流仅作为功放状态参考) //2-3 位 功放 1 电压状态 功放电压状态:“1”-欠压;“2”- 过压 ;“3”-正常(欠压和过压仅作为功放状态参考) //4-5 位 (预留) 功放 2 电流状态 功放电流状态:“1”-欠流;“2”- 过流 ;“3”-正常(欠流和过流仅作为功放状态参考) //6-7 位 功放 2 电压状 功放电压状态:“1”-欠压;“2”- 过压 ;“3”-正常(欠压和过压仅作为功放状态参考) //8-9 位 天线 1 状态 天线 1 状态:“1”-故障;“3”-正常。 //10-11 位 线缆 1 状态 线缆 1 状态:“1”-开路;“2”-短路;“3”-正常。 //12-13 位 (预留) 天线 2 状态 天线 2 状态:“1”-故障;“3”-正常。 //14-15 位 (预留) 线缆 2 状态 线缆 2 状态:“1”-开路;“2”-短路;“3”-正常。 Fun1 uint16 //第 14-15 字节(功放板、天线状态) //第 0 位 上行自检码检测通道 1 状态:“1”-正常;“0”-故障。(故障时,检查处理器板和接收板) //第 1 位 上行自检码检测通道 2 状态:“1”-正常;“0”-故障。(故障时,检查处理器板和接收板) //第 2 位 FSK 连接线状态通道 1状态:“1”-正常;“0”-故障。 //第 3 位 FSK 连接线状态通道 2状态:“1”-正常;“0”-故障。 //第 4-5 位 保留 保留 //第 6-7 位 接收板状态 状态:“0”-双通道故障;“1”-单通道故障;“3”-正常第 //8-15位保留 保留 Fun2 uint16 //第 16-17 字节(接收板状态) //第 0-1 位 通 道 1-24V 状态 状态:“1”-过压;“2”-欠压;“3”-正常;(欠压和过压仅作为电源板状态参考) //第 2-3 位 通 道 2-24V 状态 状态:“1”-过压;“2”-欠压;“3”-正常;(欠压和过压仅作为电源板状态参考) //第 4 位 通 道 1-23V 状态 状态:“1”-正常;“0”-故障。 //第 5 位 通 道 2-23V 状态 状态:“1”-正常;“0”-故障。 //第 6-13位保留 保留 //第 14-15位 电源板状态 电源板状态:“0”-故障;“1”-单通道故障;“2”-单通道故障;“3”- 正常。 Fun3 uint16 //第 18-19 字节(电源板状态) //第 0-1 位 板卡 ID 槽位号 “0”-1 号板卡;“1”-2 号板卡;“2”-3 号板卡;“3”-4 号板卡机箱正面从右往左顺序为处理器板1,2,3(预留),4(预留),同一个通信周期只有一个板卡报警 //第 2-3 位 工作温度状态 “0”-过高;“1”-温度报警;“2”-未知;“3”-正常。 //其他位保留 注:保留位全部为1 Fun4 uint16 //第 20-21 字节(处理器板) FreeMsg []byte //22~125 空闲数据 全填 00H RespTime byte //响应时间 0~150,其他非法,单位0.1ms VobcLifeNum uint32 //VOBC 周期号 1~FFFFFFFF,0 不使用。 } func (b *BtmVobcMsgFree) Encode() []byte { data := make([]byte, 0) buf := bytes.NewBuffer(data) binary.Write(buf, binary.BigEndian, byte(FREE_MESSAGE_TYPE)) binary.Write(buf, binary.BigEndian, byte(0x87)) binary.Write(buf, binary.BigEndian, b.AutoIdFrame) binary.Write(buf, binary.BigEndian, byte(0)) //保留 binary.Write(buf, binary.BigEndian, byte(0)) //保留 binary.Write(buf, binary.BigEndian, b.MsgSerial) binary.Write(buf, binary.BigEndian, b.BtmStatus) //binary.Write(buf, binary.BigEndian, b.WorkTemperature) binary.Write(buf, binary.BigEndian, byte(35)) binary.Write(buf, binary.BigEndian, yuliu3) binary.Write(buf, binary.BigEndian, b.Fun1) binary.Write(buf, binary.BigEndian, b.Fun2) binary.Write(buf, binary.BigEndian, b.Fun3) binary.Write(buf, binary.BigEndian, b.Fun4) binary.Write(buf, binary.BigEndian, b.FreeMsg) binary.Write(buf, binary.BigEndian, b.RespTime) binary.Write(buf, binary.BigEndian, b.VobcLifeNum) return baseEncode(buf.Bytes()) }