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 aa(src []byte, dest []byte) uint16 { var ( SrcPos, TgtPos, Pos1, Pos2, iii, Gap uint16 Got1stFF uint8 ) srouceLen := uint16(len(src)) for SrcPos = 0; SrcPos < srouceLen; SrcPos++ { if Got1stFF == 1 { if src[SrcPos] == 0xff { //Got2ndFF = 1 Pos2 = SrcPos dest[TgtPos] = byte(Pos2 - Pos1) TgtPos++ for iii = Pos1 + 1; iii < Pos2; iii++ { dest[TgtPos] = src[iii] TgtPos++ } Got1stFF = 0 //Got2ndFF = 0 Pos1 = 0 Pos2 = 0 Gap = 0 } else { /*已遇到前一个FF,且当前遇到非FF*/ Gap++ if 252 == Gap { Got1stFF = 0 Gap = 0 dest[TgtPos] = 0 TgtPos++ for iii = Pos1 + 1; iii <= SrcPos; iii++ { dest[TgtPos] = src[iii] TgtPos++ } } } } else { /*尚未遇到前一个FF*/ dest[TgtPos] = src[SrcPos] TgtPos++ if 0xFF == src[SrcPos] { /*遇到前一个FF*/ Got1stFF = 1 Pos1 = SrcPos Gap = 0 } } } if 1 == Got1stFF { dest[TgtPos] = 0 TgtPos++ for iii = Pos1 + 1; iii < srouceLen; iii++ { dest[TgtPos] = src[iii] TgtPos++ } } return TgtPos } func TranslateFromFFFE(pSrc []byte) ([]byte, uint16) { var ( srcPos, tgtPos, nonFFCount, nextFFPos uint16 char uint8 state int ) if len(pSrc) == 0 { return nil, 0 // 入参错误 } pTgt := make([]byte, len(pSrc)) // 预分配与输入等长的缓冲区 tgtPos = 0 state = WAIT_FF_C1 nonFFCount = 0 for srcPos = 0; srcPos < uint16(len(pSrc)); srcPos++ { char = pSrc[srcPos] switch state { case WAIT_FF_C1: if char == 0xFF { pTgt[tgtPos] = char tgtPos++ state = WAIT_FF_C2 } else { pTgt[tgtPos] = char tgtPos++ } case WAIT_FF_C2: if char == 0xFD || char == 0xFE || char == 0xFF { state = ABNORMAL_STATE } else { if char == 0 { state = WAIT_NO_FF } else if char == 1 { pTgt[tgtPos] = 0xFF tgtPos++ state = WAIT_FF_C1 } else { nextFFPos = srcPos + uint16(char) - 1 state = WAIT_FF_POS } } case WAIT_NO_FF: nonFFCount++ if char == 0xFF && nonFFCount < 252 { state = ABNORMAL_STATE } else { pTgt[tgtPos] = char tgtPos++ if nonFFCount == 252 { nonFFCount = 0 state = WAIT_FF_C1 } } case WAIT_FF_POS: if char == 0xFF { state = ABNORMAL_STATE } else { pTgt[tgtPos] = char tgtPos++ if srcPos == nextFFPos { pTgt[tgtPos] = 0xFF tgtPos++ state = WAIT_FF_C1 } } default: state = ABNORMAL_STATE } if state == ABNORMAL_STATE { tgtPos = 0 break } } // 退出时的状态判断 if state == WAIT_FF_C2 || state == WAIT_FF_POS { tgtPos = 0 } return pTgt[:tgtPos], tgtPos } // TranslateToFFFE 对给定的字节切片进行FFFE转义处理 func TranslateToFFFE(src []byte) ([]byte, error) { if src == nil { return nil, fmt.Errorf("source data is nil") } var tgt []byte var pos1, pos2 int var gap int var got1stFF bool for i, b := range src { if got1stFF { if b == 0xFF { // 已遇到前一个FF,且当前又遇到FF got1stFF = false pos2 = i if gap > 252 { // 间隙过大,特殊处理 tgt = append(tgt, 0) tgt = append(tgt, src[pos1+1:pos2]...) } else { // 写入间隙长度 tgt = append(tgt, byte(gap)) // 写入间隙中的字节 tgt = append(tgt, src[pos1+1:pos2]...) } } else { // 已遇到前一个FF,且当前遇到非FF,增加gap计数 gap++ } } else { // 尚未遇到前一个FF tgt = append(tgt, b) if b == 0xFF { // 遇到前一个FF got1stFF = true pos1 = i gap = 0 } } } // 如果在数据末尾遇到了FF且没有第二个FF if got1stFF { if gap > 252 { tgt = append(tgt, 0) tgt = append(tgt, src[pos1+1:]...) } else { tgt = append(tgt, 0) tgt = append(tgt, src[pos1+1:len(src)]...) } } return tgt, nil } // TranslateToFFFE 将数据进行FFFE转义处理(不加头FFFE及尾FFFD)。 func TranslateToFFFE2(pSrc []byte) []byte { var ( srcPos, tgtPos, pos1, pos2, iii uint16 gap uint16 got1stFF bool ) if pSrc == nil { return nil // 入口参数错误 } pTgt := make([]byte, 0, len(pSrc)*2) // 预分配空间以应对最坏情况 for srcPos = 0; srcPos < uint16(len(pSrc)); srcPos++ { if got1stFF { if pSrc[srcPos] == 0xFF { // 已遇到前一个FF,且当前又遇到FF pos2 = srcPos pTgt = append(pTgt, byte(pos2-pos1)) tgtPos++ for iii = pos1 + 1; iii < pos2; iii++ { pTgt = append(pTgt, pSrc[iii]) tgtPos++ } got1stFF = false pos1, pos2, gap = 0, 0, 0 } else { // 已遇到前一个FF,且当前遇到非FF gap++ if gap == 252 { got1stFF, gap = false, 0 pTgt = append(pTgt, 0) tgtPos++ for iii = pos1 + 1; iii <= srcPos; iii++ { pTgt = append(pTgt, pSrc[iii]) tgtPos++ } } } } else { // 尚未遇到前一个FF pTgt = append(pTgt, pSrc[srcPos]) tgtPos++ if pSrc[srcPos] == 0xFF { // 遇到前一个FF got1stFF = true pos1 = srcPos gap = 0 } } } // 已经遇到了前一个FF, 且源数据已到了末尾仍未遇到后一个FF if got1stFF { pTgt = append(pTgt, 0) tgtPos++ for iii = pos1 + 1; iii < uint16(len(pSrc)); iii++ { pTgt = append(pTgt, pSrc[iii]) tgtPos++ } } // 截取实际使用的部分返回 return pTgt[:tgtPos] } func TranslateToFFFE3(pSrc []uint8, SrcLen uint16) ([]byte, uint16) { var ( SrcPos, TgtPos, Pos1, Pos2, iii uint16 Gap uint16 Got1stFF uint8 pTgt []uint8 ) if pSrc == nil { fmt.Println("入口参数错误") return nil, 0 } pTgt = make([]uint8, 0, SrcLen*2) // 预分配足够的空间以避免频繁扩容 TgtPos = 0 for SrcPos = 0; SrcPos < SrcLen; SrcPos++ { if Got1stFF == 1 { if pSrc[SrcPos] == 0xFF { // 已遇到前一个FF,且当前又遇到FF //Got2ndFF = 1 Pos2 = SrcPos pTgt = append(pTgt, uint8(Pos2-Pos1-1)) TgtPos++ for iii = Pos1 + 1; iii < Pos2; iii++ { pTgt = append(pTgt, pSrc[iii]) TgtPos++ } Got1stFF = 0 //Got2ndFF = 0 Pos1 = 0 Pos2 = 0 Gap = 0 } else { // 已遇到前一个FF,且当前遇到非FF Gap++ if Gap == 252 { Got1stFF = 0 Gap = 0 pTgt = append(pTgt, 0) TgtPos++ for iii = Pos1 + 1; iii <= SrcPos; iii++ { pTgt = append(pTgt, pSrc[iii]) TgtPos++ } } } } else { // 尚未遇到前一个FF pTgt = append(pTgt, pSrc[SrcPos]) TgtPos++ if pSrc[SrcPos] == 0xFF { // 遇到前一个FF Got1stFF = 1 Pos1 = SrcPos Gap = 0 } } } // 已经遇到了前一个FF, 且源数据已到了末尾仍未遇到后一个FF if Got1stFF == 1 { pTgt = append(pTgt, 0) TgtPos++ for iii = Pos1 + 1; iii < SrcLen; iii++ { pTgt = append(pTgt, pSrc[iii]) TgtPos++ } } return pTgt, TgtPos } 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)) //fffeData, _ := TranslateToFFFE(newSource) //fffeData := TranslateToFFFE2(newSource) //fffeData := FFFEEncode(newSource) //fffeData, _ := TranslateToFFFE3(newSource, uint16(len(newSource))) /*f2 := make([]byte, len(newSource)*2) lens, _ := TranslateToFFFE4(newSource, f2) fffeData := f2[:lens]*/ 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 } func TranslateToFFFE4(pSrc []byte, pTgt []byte) (int, error) { if pSrc == nil || pTgt == nil { return 0, fmt.Errorf("pSrc or pTgt is nil") } srcLen := len(pSrc) tgtLen := 0 pos1 := -1 // 前一个FF的位置 gap := 0 // 两个FF之间的字节数 for i, b := range pSrc { if pos1 != -1 { if b == 0xFF { // 遇到了第二个FF pTgt[tgtLen] = byte(i - pos1 - 1) // 减1是因为不包括第一个FF tgtLen++ // 复制pos1和当前位置之间的数据 copy(pTgt[tgtLen:tgtLen+gap], pSrc[pos1+1:i]) tgtLen += gap // 重置状态 pos1 = -1 gap = 0 } else { // 计数两个FF之间的字节数 gap++ if gap == 252 { // 如果gap超过252,则写入一个0并复制数据 pTgt[tgtLen] = 0 tgtLen++ copy(pTgt[tgtLen:tgtLen+gap], pSrc[pos1+1:i]) tgtLen += gap // 重置状态 pos1 = -1 gap = 0 } } } else { // 尚未遇到前一个FF pTgt[tgtLen] = b tgtLen++ if b == 0xFF { // 遇到了第一个FF pos1 = i } } } // 如果数据以FF结尾,但没有第二个FF if pos1 != -1 { pTgt[tgtLen] = 0 tgtLen++ // 复制pos1之后的数据 copy(pTgt[tgtLen:tgtLen+srcLen-pos1-1], pSrc[pos1+1:]) tgtLen += srcLen - pos1 - 1 } return tgtLen, nil } // 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 } const ( a = 0x06 b = 0x15 ) 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 MESSAGE_AUTO_ID byte = 1 var MESSAGE_SERIAL byte = 1 var lock sync.Mutex func getAutoId() byte { defer lock.Unlock() lock.Lock() if MESSAGE_AUTO_ID <= 0 { MESSAGE_AUTO_ID = 1 } else if MESSAGE_AUTO_ID > 255 { MESSAGE_AUTO_ID = 1 } MESSAGE_AUTO_ID += 1 return MESSAGE_AUTO_ID } func GetAutoMessageId() byte { defer lock.Unlock() lock.Lock() if MESSAGE_SERIAL <= 0 { MESSAGE_SERIAL = 1 } else if MESSAGE_SERIAL > 255 { MESSAGE_SERIAL = 1 } MESSAGE_SERIAL += 1 return MESSAGE_SERIAL } const ( btm_status_ok = 0x00 btm_status_warn = 0x04 ) var mesage_yuliu = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0} 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, getAutoId()) 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()) } var yuliu3 = []byte{0, 0, 0, 0, 0, 0} 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, getAutoId()) //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()) }