Skip to content

Commit

Permalink
feat: 添加0x9101和0x1005指令等
Browse files Browse the repository at this point in the history
  • Loading branch information
cuteLittleDevil committed Oct 31, 2024
1 parent bff24d1 commit 3f6dce1
Show file tree
Hide file tree
Showing 9 changed files with 248 additions and 12 deletions.
87 changes: 87 additions & 0 deletions protocol/model/p_0x9101.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package model

import (
"encoding/binary"
"fmt"
"github.com/cuteLittleDevil/go-jt808/protocol"
"github.com/cuteLittleDevil/go-jt808/protocol/jt808"
"github.com/cuteLittleDevil/go-jt808/protocol/utils"
"github.com/cuteLittleDevil/go-jt808/shared/consts"
"strings"
)

type P0x9101 struct {
BaseHandle
// ServerIPLen 视频服务器IP地址长度
ServerIPLen byte `json:"serverIPLen"`
// ServerIPAddr 视频服务器IP地址
ServerIPAddr string `json:"serverIPAddr"`
// TcpPort 视频服务器TCP端口号,不使用TCP协议传输时保持默认值0即可(TCP和UDP二选一,当TCP和UDP均非默认值时一般以TCP为准)
TcpPort uint16 `json:"tcpPort"`
// UdpPort 视频服务器UDP端口号,不使用UDP协议传输时保持默认值0即可(TCP和UDP二选一,当TCP和UDP均非默认值时一般以TCP为准)
UdpPort uint16 `json:"udpPort"`
// ChannelNo 逻辑通道号
ChannelNo byte `json:"channelNo"`
// DataType 数据类型 0-音视频 1-视频 2-双向对讲 3-监听 4-中心广播 5-透传
DataType byte `json:"dataType"`
// StreamType 码流类型 0-主码流 1-子码流
StreamType byte `json:"streamType"`
}

func (p *P0x9101) Protocol() consts.JT808CommandType {
return consts.P9101RealTimeAudioVideoRequest
}

func (p *P0x9101) ReplyProtocol() consts.JT808CommandType {
return consts.T0001GeneralRespond
}

func (p *P0x9101) Parse(jtMsg *jt808.JTMessage) error {
body := jtMsg.Body
if len(body) < 1 {
return protocol.ErrBodyLengthInconsistency
}
p.ServerIPLen = body[0]
if len(body) != 1+int(p.ServerIPLen)+7 {
return protocol.ErrBodyLengthInconsistency
}
n := int(p.ServerIPLen)
p.ServerIPAddr = string(body[1 : n+1])
p.TcpPort = binary.BigEndian.Uint16(body[n+1:])
p.UdpPort = binary.BigEndian.Uint16(body[n+3:])
p.ChannelNo = body[n+5]
p.DataType = body[n+6]
p.StreamType = body[n+7]
return nil
}

func (p *P0x9101) Encode() []byte {
data := make([]byte, 0, 25)
data = append(data, p.ServerIPLen)
data = append(data, utils.String2FillingBytes(p.ServerIPAddr, len(p.ServerIPAddr))...)
data = append(data, byte(p.TcpPort>>8), byte(p.TcpPort))
data = append(data, byte(p.UdpPort>>8), byte(p.UdpPort))
data = append(data, p.ChannelNo)
data = append(data, p.DataType)
data = append(data, p.StreamType)
return data
}

func (p *P0x9101) ReplyBody(_ *jt808.JTMessage) ([]byte, error) {
return nil, nil
}

func (p *P0x9101) String() string {
return strings.Join([]string{
"数据体对象:{",
fmt.Sprintf("\t%s:[%x]", p.Protocol(), p.Encode()),
fmt.Sprintf("\t[%02x] 服务器IP地址长度:[%d]", p.ServerIPLen, p.ServerIPLen),
fmt.Sprintf("\t[%x] 服务器IP地址:[%s]", p.ServerIPAddr, p.ServerIPAddr),
fmt.Sprintf("\t[%04x] 服务器视频通道监听端口号(TCP):[%d]", p.TcpPort, p.TcpPort),
fmt.Sprintf("\t[%04x] 服务器视频通道监听端口号(UDP):[%d]", p.UdpPort, p.UdpPort),
fmt.Sprintf("\t[%02x] 逻辑通道号:[%d]", p.ChannelNo, p.ChannelNo),
fmt.Sprintf("\t[%02x] 数据类型:[%d]", p.DataType, p.DataType),
fmt.Sprintf("\t[%02x] 码流类型:[%d]", p.StreamType, p.StreamType),
"}",
}, "\n")
}
31 changes: 31 additions & 0 deletions protocol/model/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,37 @@ func TestParse(t *testing.T) {
TerminalSupportedMaxNumberOfVideoPhysicalChannels: 8,
},
},
{
name: "P0x9101 平台-实时音视频传输请求",
args: args{
msg: "7e9101001712345678901200010f3132332e3132332e3132332e313233030440c60c0100a17e",
Handler: &P0x9101{},
bodyLens: []int{0, 2},
},
fields: &P0x9101{
ServerIPLen: 15,
ServerIPAddr: "123.123.123.123",
TcpPort: 772,
UdpPort: 16582,
ChannelNo: 12,
DataType: 1,
StreamType: 0,
},
},
{
name: "T0x1005 终端-上传乘客流量",
args: args{
msg: "7E100500101234567890120001241001000000241002001001000200138D7E",
Handler: &T0x1005{},
bodyLens: []int{15},
},
fields: &T0x1005{
StartTime: "2024-10-01 00:00:00",
EndTime: "2024-10-02 00:10:01",
BoardNumber: 2,
AlightNumber: 19,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
12 changes: 12 additions & 0 deletions protocol/model/protocol_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,18 @@ func TestReplyProtocol(t *testing.T) {
wantProtocol: consts.T1003UploadAudioVideoAttr,
wantReplyProtocol: 0,
},
{
name: "P0x9101 平台-实时音视频传输请求",
args: &P0x9101{},
wantProtocol: consts.P9101RealTimeAudioVideoRequest,
wantReplyProtocol: consts.T0001GeneralRespond,
},
{
name: "T0x1005 终端-上传乘客流量",
args: &T0x1005{},
wantProtocol: consts.T1005UploadPassengerFlow,
wantReplyProtocol: 0,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
37 changes: 33 additions & 4 deletions protocol/model/reply_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,16 @@ func TestReply(t *testing.T) {
result2013: "7e0000000012345678901200008a7e",
},
},
{
name: "P0x9101 平台-实时音视频传输请求",
args: args{
Handler: &P0x9101{},
msg2013: "7e9101001712345678901200010f3132332e3132332e3132332e313233030440c60c0100a17e",
},
want: want{
result2013: "7e0001000012345678901200008b7e",
},
},
}
checkReplyInfo := func(t *testing.T, msg string, handler Handler, expectedResult string) {
if msg == "" {
Expand Down Expand Up @@ -180,9 +190,28 @@ func TestT0x0102Reply(t *testing.T) {
}
}

func TestP0x8104ReplyBody(t *testing.T) {
handler := &P0x8104{}
if _, err := handler.ReplyBody(nil); err != nil {
t.Errorf("P0x8104 ReplyBody = [%x]", err)
func TestReplyBody(t *testing.T) {
type Handler interface {
ReplyBody(_ *jt808.JTMessage) ([]byte, error)
}
tests := []struct {
name string
args Handler
}{
{
name: "P0x8104 平台-查询终端参数",
args: &P0x8104{},
},
{
name: "T0x1005 终端-上传乘客流量",
args: &T0x1005{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got, _ := tt.args.ReplyBody(nil); got != nil {
t.Errorf("ReplyBody() got = %s\n want nil", got)
}
})
}
}
8 changes: 1 addition & 7 deletions protocol/model/t_0x0200_location_item.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,13 +173,7 @@ func (tl *T0x0200LocationItem) encode() []byte {
binary.BigEndian.PutUint16(data[16:18], tl.Altitude)
binary.BigEndian.PutUint16(data[18:20], tl.Speed)
binary.BigEndian.PutUint16(data[20:22], tl.Direction)
bcdTime := strings.ReplaceAll(tl.DateTime, "-", "")
bcdTime = strings.ReplaceAll(bcdTime, ":", "")
bcdTime = strings.ReplaceAll(bcdTime, " ", "")
if len(bcdTime) == 14 {
bcdTime = bcdTime[2:]
}
data = append(data, utils.Time2BCD(bcdTime)...)
data = append(data, utils.Time2BCD(tl.DateTime)...)
return data
}

Expand Down
1 change: 0 additions & 1 deletion protocol/model/t_0x1003.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ func (t *T0x1003) Parse(jtMsg *jt808.JTMessage) error {
if len(body) != 10 {
return protocol.ErrBodyLengthInconsistency
}
binary.BigEndian.Uint16(body[:2])
t.EnterAudioEncoding = body[0]
t.EnterAudioChannelsNumber = body[1]
t.EnterAudioSampleRate = body[2]
Expand Down
70 changes: 70 additions & 0 deletions protocol/model/t_0x1005.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package model

import (
"encoding/binary"
"fmt"
"github.com/cuteLittleDevil/go-jt808/protocol"
"github.com/cuteLittleDevil/go-jt808/protocol/jt808"
"github.com/cuteLittleDevil/go-jt808/protocol/utils"
"github.com/cuteLittleDevil/go-jt808/shared/consts"
"strings"
)

type T0x1005 struct {
BaseHandle
// StartTime 开始时间 BCD[6] CMT+8时区(上海时区)
StartTime string `json:"startTime"`
// EndTime 结束时间 BCD[6] CMT+8时区(上海时区)
EndTime string `json:"endTime"`
// BoardNumber 上车人数 从起始时间到结束时间的上车人数
BoardNumber uint16 `json:"boardNumber"`
// AlightNumber 下车人数 从起始时间到结束时间的上车人数
AlightNumber uint16 `json:"alightNumber"`
}

func (t *T0x1005) Protocol() consts.JT808CommandType {
return consts.T1005UploadPassengerFlow
}

func (t *T0x1005) ReplyProtocol() consts.JT808CommandType {
return 0
}

func (t *T0x1005) Parse(jtMsg *jt808.JTMessage) error {
body := jtMsg.Body
if len(body) != 16 {
return protocol.ErrBodyLengthInconsistency
}
t.StartTime = utils.BCD2Time(body[:6])
t.EndTime = utils.BCD2Time(body[6:12])
t.BoardNumber = binary.BigEndian.Uint16(body[12:14])
t.AlightNumber = binary.BigEndian.Uint16(body[14:16])
return nil
}

func (t *T0x1005) Encode() []byte {
data := make([]byte, 20)
startBcdTime := utils.Time2BCD(t.StartTime)
copy(data[0:6], startBcdTime)
endBcdTime := utils.Time2BCD(t.EndTime)
copy(data[6:12], endBcdTime)
binary.BigEndian.PutUint16(data[12:14], t.BoardNumber)
binary.BigEndian.PutUint16(data[14:16], t.AlightNumber)
return data
}

func (t *T0x1005) ReplyBody(_ *jt808.JTMessage) ([]byte, error) {
return nil, nil
}

func (t *T0x1005) String() string {
return strings.Join([]string{
"数据体对象:{",
fmt.Sprintf("\t%s:[%x]", t.Protocol(), t.Encode()),
fmt.Sprintf("\t[%x] 开始时间:[%s]", utils.Time2BCD(t.StartTime), t.StartTime),
fmt.Sprintf("\t[%x] 结束时间:[%s]", utils.Time2BCD(t.EndTime), t.EndTime),
fmt.Sprintf("\t[%04x] 上车人数:[%d]", t.BoardNumber, t.BoardNumber),
fmt.Sprintf("\t[%04x] 下车人数:[%d]", t.AlightNumber, t.AlightNumber),
"}",
}, "\n")
}
9 changes: 9 additions & 0 deletions protocol/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/transform"
"io"
"strings"
)

func Bcd2Dec(data []byte) string {
Expand All @@ -19,6 +20,14 @@ func Bcd2Dec(data []byte) string {
}

func Time2BCD(time string) []byte {
if strings.Contains(time, ":") {
time = strings.ReplaceAll(time, "-", "")
time = strings.ReplaceAll(time, ":", "")
time = strings.ReplaceAll(time, " ", "")
if len(time) == 14 {
time = time[2:]
}
}
if len(time)%2 != 0 {
time = "0" + time
}
Expand Down
5 changes: 5 additions & 0 deletions protocol/utils/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ func TestBCD2Time(t *testing.T) {
args: "241001000000",
want: "2024-10-01 00:00:00",
},
{
name: "默认时间格式的",
args: "2024-10-01 00:00:00",
want: "2024-10-01 00:00:00",
},
{
name: "7位的时间",
args: "20241001000000",
Expand Down

0 comments on commit 3f6dce1

Please sign in to comment.