package protocol import ( "bytes" "encoding/binary" "fmt" "github.com/valyala/bytebufferpool" "golang.org/x/text/encoding/simplifiedchinese" "golang.org/x/text/transform" "io/ioutil" promodel "server/model/common/devices" "strconv" "time" ) // 认证登录 (这里设置了默认心跳时间为60s) func (x AuthDataPack) AuthLogin() *bytebufferpool.ByteBuffer { buf := bytebufferpool.Get() x.Head = []byte{0xFE, 0x5C, 0x4B, 0x89} x.Len = []byte{0x2A, 0x00, 0x00, 0x00} x.Type = 0x62 x.Id = []byte{0x00, 0x00, 0x00, 0x00} x.DataLen = []byte{0x17, 0x00, 0x00, 0x00} x.Result = 0x31 x.Separator1 = 0x23 x.Separator2 = 0x23 x.HeartBeat = []byte{0x30, 0x36, 0x30} //默认060, 60秒发一次心跳 x.EndSeparator = 0x23 x.End = []byte{0xFF, 0xFF} buf.Write(x.Head) buf.Write(x.Len) buf.WriteByte(x.Type) buf.Write(x.Id) buf.Write(x.DataLen) buf.WriteByte(x.Result) buf.WriteByte(x.Separator1) slice := GetNowDate() TmpData := make([]byte, len(slice)) for i, s := range slice { TmpData[i] = byte(s) + 0x30 } x.Time = TmpData buf.Write(x.Time) buf.WriteByte(x.Separator2) buf.Write(x.HeartBeat) buf.WriteByte(x.EndSeparator) buf.Write(x.End) //fmt.Println("TmpData: ", hex.EncodeToString(buf.Bytes())) //fmt.Println("TmpData: ", buf.Bytes()) return buf } // 开关屏幕 func (x SwitchDataPack) SwitchScreens() *bytebufferpool.ByteBuffer { buf := bytebufferpool.Get() x.Head = []byte{0xFE, 0x5C, 0x4B, 0x89} x.Len = []byte{0x13, 0x00, 0x00, 0x00} x.Id = []byte{0x00, 0x00, 0x00, 0x00} x.Reserve = []byte{0x00, 0x00, 0x00, 0x00} x.End = []byte{0xFF, 0xFF} buf.Write(x.Head) buf.Write(x.Len) buf.WriteByte(x.Type) buf.Write(x.Id) buf.Write(x.Reserve) buf.Write(x.End) return buf } // 发送内码文字 func (x InternalCodeDataPack) SendInternalCode(content []promodel.InternalCodeContent) *bytebufferpool.ByteBuffer { buf := bytebufferpool.Get() x.Head = []byte{0xFE, 0x5C, 0x4B, 0x89} x.Type = 0x31 x.Id = []byte{0x00, 0x00, 0x00, 0x00} //封装控制指令内容 for i, codeContent := range content { //拼接素材ID 000000001 UidStr := fmt.Sprintf("%09d", i+1) //给每一项加0x30 uidByte := EachItemAdd(UidStr) //将内容转GB2312编码格式 gbk, contentLen, _ := Utf8ToGbk([]byte(codeContent.Text)) //获取素材内容长度 contentLenBytes := GetBytesArrYes(contentLen+10, 4) ICD := InternalCodeData{ MaterialId: uidByte, //素材ID CharacterColor: codeContent.Color, //字符颜色 TextSize: codeContent.Size, //字体大小 ControlCode2: []byte{byte(i + 1), 0x00}, //控制码2 MaterialContentLen: contentLenBytes, //素材内容长度 MaterialContent: gbk, //素材内容 } ContentBuf := ICD.AppendInternalCodeContent() x.Data = append(x.Data, ContentBuf.Bytes()...) } x.Len = GetBytesArrYes(uint8(len(x.Data))+22, 4) x.DataLen = GetBytesArrYes(uint8(len(x.Data))+3, 4) x.EndSign = []byte{0x2D, 0x31, 0x2C} x.End = []byte{0xFF, 0xFF} buf.Write(x.Head) buf.Write(x.Len) buf.WriteByte(x.Type) buf.Write(x.Id) buf.Write(x.DataLen) buf.Write(x.Data) buf.Write(x.EndSign) buf.Write(x.End) return buf } func (x InternalCodeData) AppendInternalCodeContent() *bytebufferpool.ByteBuffer { buf := bytebufferpool.Get() x.Separator = 0x2C x.DisplayMode = 0x09 x.DisplaySpeed = 0x01 x.StopTime = 0xFF // 静止显示 x.PlayingPeriod = []byte{0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x39, 0x39, 0x31, 0x32, 0x33, 0x31} x.MaterialAttribLen = []byte{0x13, 0x00, 0x00, 0x00} x.MaterialStartFlag = []byte{0x55, 0xAA} x.ReservedWord1 = 0x00 x.TextRotation = 0x01 x.MaterialAttrib = 0x37 x.MaterialStorageMode = 0x32 x.MaterialUpdateMode = 0x31 x.TextStartSign = 0x31 x.ScreenColor = 0x32 x.PictureCodeMode = 0x31 x.ReservedWord2 = []byte{0x00, 0x00} x.Width = []byte{0x0C, 0x00} //宽:96/8=12 也就是0x0C x.Height = []byte{0x18, 0x00} //高:24 也就是0x18 x.ReservedWord3 = 0x00 x.ControlCode1 = []byte{0xFF, 0x00} x.ControlCode3 = []byte{0x01, 0x00, 0x01, 0x00} x.ReservedWord4 = []byte{0x00, 0x00} buf.Write(x.MaterialId) buf.WriteByte(x.Separator) buf.WriteByte(x.DisplayMode) buf.WriteByte(x.DisplaySpeed) buf.WriteByte(x.StopTime) buf.Write(x.PlayingPeriod) buf.Write(x.MaterialAttribLen) buf.Write(x.MaterialStartFlag) buf.WriteByte(x.ReservedWord1) buf.WriteByte(x.TextRotation) buf.WriteByte(x.MaterialAttrib) buf.WriteByte(x.MaterialStorageMode) buf.WriteByte(x.MaterialUpdateMode) buf.WriteByte(x.TextStartSign) buf.WriteByte(x.ScreenColor) buf.WriteByte(x.PictureCodeMode) buf.Write(x.ReservedWord2) buf.Write(x.Width) buf.Write(x.Height) buf.WriteByte(x.CharacterColor) buf.WriteByte(x.TextSize) buf.WriteByte(x.ReservedWord3) buf.Write(x.MaterialContentLen) buf.Write(x.MaterialContent) buf.Write(x.ControlCode1) buf.Write(x.ControlCode2) buf.Write(x.ControlCode3) buf.Write(x.ReservedWord4) return buf } // 远程喊话 func (x VoiceBroadDataPack) VoiceBroad(broad string) *bytebufferpool.ByteBuffer { buf := bytebufferpool.Get() x.Head = []byte{0xFE, 0x5C, 0x4B, 0x89} x.Type = 0x68 x.ForwardPort = 0x02 //转发端口 x.Id = []byte{0x00, 0x00, 0x00} x.End = []byte{0xFF, 0xFF} //将语音内容字符串转字节数组,并获取其长度供给内容长度使用 gbk, contentLen, _ := Utf8ToGbk([]byte(broad)) contentLenBytes := GetBytesArrNo(contentLen+2, 2) data := VoiceBroadData{ BroadContentLen: contentLenBytes, BroadContent: gbk, } contentByte := data.AppendVoiceBroadContent() x.Data = contentByte.Bytes() //帧头到保留字刚好是控制指令长度 x.DataLen = GetBytesArrYes(uint8(len(x.Data)), 4) x.Len = GetBytesArrYes(uint8(len(x.Data)+19), 4) buf.Write(x.Head) buf.Write(x.Len) buf.WriteByte(x.Type) buf.WriteByte(x.ForwardPort) buf.Write(x.Id) buf.Write(x.DataLen) buf.Write(x.Data) buf.Write(x.End) return buf } func (x VoiceBroadData) AppendVoiceBroadContent() *bytebufferpool.ByteBuffer { buf := bytebufferpool.Get() x.FrameHeader = 0xFD x.BroadWord = 0x01 x.BroadEncodeFormat = []byte{0x00} //编码格式 /*0x5B, 0x6D, 0x35, 0x32, 0x5D, //男2声 0x5B, 0x73, 0x35, 0x5D, //中语速 0x5B, 0x76, 0x31, 0x30, 0x5D*/ //高音量 x.ReservedWord = []byte{0x00, 0x00} buf.WriteByte(x.FrameHeader) buf.Write(x.BroadContentLen) buf.WriteByte(x.BroadWord) buf.Write(x.BroadEncodeFormat) buf.Write(x.BroadContent) buf.Write(x.ReservedWord) return buf } // 调节亮度 func (x SetBrightnessDataPack) SetBrightness(brightLevel byte) *bytebufferpool.ByteBuffer { buf := bytebufferpool.Get() x.Head = []byte{0xFE, 0x5C, 0x4B, 0x89} x.Len = []byte{0x17, 0x00, 0x00, 0x00} x.Type = 0x76 x.Id = []byte{0x00, 0x00, 0x00, 0x00} x.DataLen = []byte{0x04, 0x00, 0x00, 0x00} data := SetBrightnessData{ControlPriority: 0x02, ControlPriorityInverse: 0xFD, BrightnessLevel: brightLevel, BrightnessLevelInverse: ^brightLevel, //取反码 } buffer := data.AppendSetBrightnessContent() x.Data = buffer.Bytes() x.End = []byte{0xFF, 0xFF} buf.Write(x.Head) buf.Write(x.Len) buf.WriteByte(x.Type) buf.Write(x.Id) buf.Write(x.DataLen) buf.Write(x.Data) buf.Write(x.End) return buf } func (x SetBrightnessData) AppendSetBrightnessContent() *bytebufferpool.ByteBuffer { buf := bytebufferpool.Get() buf.WriteByte(x.ControlPriority) buf.WriteByte(x.ControlPriorityInverse) buf.WriteByte(x.BrightnessLevel) buf.WriteByte(x.BrightnessLevelInverse) return buf } func GetNowDate() (dateSlice [16]int) { now := time.Now() year, month, day := now.Date() hour, minute, second := now.Clock() weekday := int(now.Weekday()) // 0表示星期天,1表示星期一,依此类推 if weekday == 0 { weekday = 7 // 将星期天设为07 } // 格式化 Y := fmt.Sprintf("%d", year) M := fmt.Sprintf("%02d", month) // 将月份转换为两位数字 D := fmt.Sprintf("%02d", day) // 将日期转换为两位数字 H := fmt.Sprintf("%02d", hour) // 将小时转换为两位数字 Min := fmt.Sprintf("%02d", minute) // 将分钟转换为两位数字 S := fmt.Sprintf("%02d", second) // 将秒数转换为两位数字 W := fmt.Sprintf("%02d", weekday) // 将星期几转换为两位数字 dateStr := Y + M + D + W + H + Min + S for i, _ := range dateStr { num, _ := strconv.Atoi(string(dateStr[i])) dateSlice[i] = num } return dateSlice } func Utf8ToGbk(s []byte) ([]byte, uint8, error) { reader := transform.NewReader(bytes.NewReader(s), simplifiedchinese.GBK.NewEncoder()) d, e := ioutil.ReadAll(reader) u := uint8(len(d)) if e != nil { return nil, u, e } return d, u, nil } // 传入数字字符串给每一项加0x30 func EachItemAdd(strArr string) []byte { var byteArr = make([]byte, len(strArr)) for i, _ := range strArr { num, _ := strconv.Atoi(string(strArr[i])) byteArr[i] = byte(num) + 0x30 } return byteArr } // 获取字节数组(低字节在前,高字节在后,要倒转) func GetBytesArrYes(param uint8, ByteLen int) []byte { byteArray := make([]byte, ByteLen) // 将输入的整数转换为字节并存储在字节数组中 if ByteLen >= 4 { binary.BigEndian.PutUint32(byteArray[ByteLen-4:], uint32(param)) } else { for i := 0; i < ByteLen; i++ { byteArray[ByteLen-1-i] = byte(param >> (8 * i)) // 右移并放置到正确位置 } } return Rotate(byteArray) } // 获取字节数组(低字节在后,高字节在前,不需要倒转) func GetBytesArrNo(param uint8, ByteLen int) []byte { byteArray := make([]byte, ByteLen) // 将输入的整数转换为字节并存储在字节数组中 if ByteLen >= 4 { binary.BigEndian.PutUint32(byteArray[ByteLen-4:], uint32(param)) } else { for i := 0; i < ByteLen; i++ { byteArray[ByteLen-1-i] = byte(param >> (8 * i)) // 右移并放置到正确位置 } } return byteArray } // 低位字节在前,高位字节在后 func Rotate(ss []byte) []byte { ret := make([]byte, len(ss)) copy(ret, ss) left, rigth := 0, 0 if len(ret)%2 == 0 { left = len(ret)/2 - 1 rigth = len(ret) / 2 } else { left = len(ret)/2 - 1 rigth = len(ret)/2 + 1 } for ; left >= 0 || rigth <= len(ret)-1; left, rigth = left-1, rigth+1 { ret[left], ret[rigth] = ret[rigth], ret[left] } return ret }