mirror of
https://github.com/jwetzell/psn-go.git
synced 2026-08-28 10:29:15 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 65947914b3 | |||
| 1bf0c7c0f0 | |||
| 8c2a580b75 | |||
| f8fde1a796 | |||
| 610344e706 | |||
| 0e03f68a59 | |||
| 0877357b78 | |||
| 6bc6fb3668 | |||
| 0c297d606d | |||
| f5b944579d | |||
| ea184a936d |
@@ -0,0 +1,48 @@
|
|||||||
|
name: "Test Decoders"
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, reopened, synchronize]
|
||||||
|
paths:
|
||||||
|
- 'internal/decoders/**'
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'main'
|
||||||
|
paths:
|
||||||
|
- 'internal/decoders/**'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test_decoders:
|
||||||
|
name: "test decoders"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Go
|
||||||
|
uses: actions/setup-go@v4
|
||||||
|
with:
|
||||||
|
go-version: ^1.23
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: go test -cover -coverprofile=decoders_coverage.txt ./internal/decoders/...
|
||||||
|
|
||||||
|
- name: Archive code coverage results
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: decoders-code-coverage
|
||||||
|
path: decoders_coverage.txt # Make sure to use the same file name you chose for the "-coverprofile" in the "Test" step
|
||||||
|
|
||||||
|
code_coverage:
|
||||||
|
name: "Code coverage report"
|
||||||
|
if: github.event_name == 'pull_request' # Do not run when workflow is triggered by push to main branch
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: test_decoders
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
actions: read
|
||||||
|
pull-requests: write
|
||||||
|
steps:
|
||||||
|
- uses: fgrosse/go-coverage-report@v1.1.1 # Consider using a Git revision for maximum security
|
||||||
|
with:
|
||||||
|
coverage-artifact-name: "decoders-code-coverage" # can be omitted if you used this default value
|
||||||
|
coverage-file-name: "decoders_coverage.txt" # can be omitted if you used this default value
|
||||||
+5
-3
@@ -1,5 +1,7 @@
|
|||||||
package psn
|
package psn
|
||||||
|
|
||||||
var PACKET_HEADER_SIZE = 16
|
const (
|
||||||
var MAX_UDP_PACKET_SIZE = 1500
|
PACKET_HEADER_SIZE = 16
|
||||||
var CHUNK_HEADER_SIZE = 4
|
MAX_UDP_PACKET_SIZE = 1500
|
||||||
|
CHUNK_HEADER_SIZE = 4
|
||||||
|
)
|
||||||
|
|||||||
+18
-5
@@ -1,6 +1,8 @@
|
|||||||
package psn
|
package psn
|
||||||
|
|
||||||
import "github.com/jwetzell/psn-go/internal/decoders"
|
import (
|
||||||
|
"github.com/jwetzell/psn-go/internal/decoders"
|
||||||
|
)
|
||||||
|
|
||||||
type Decoder struct {
|
type Decoder struct {
|
||||||
lastInfoPacketHeader *decoders.PacketHeaderChunk
|
lastInfoPacketHeader *decoders.PacketHeaderChunk
|
||||||
@@ -48,11 +50,18 @@ func (d *Decoder) updateData(framePackets []decoders.DataPacketChunk) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Decoder) Decode(bytes []byte) {
|
func (d *Decoder) Decode(bytes []byte) error {
|
||||||
chunk := decoders.DecodeChunk(bytes)
|
chunk, err := decoders.DecodeChunk(bytes)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if chunk.Header.Id == 0x6756 {
|
if chunk.Header.Id == 0x6756 {
|
||||||
infoPacket := decoders.DecodeInfoPacketChunk(bytes)
|
infoPacket, err := decoders.DecodeInfoPacketChunk(bytes)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
currentInfoPacketHeader := infoPacket.Data.PacketHeader
|
currentInfoPacketHeader := infoPacket.Data.PacketHeader
|
||||||
|
|
||||||
_, ok := d.infoPacketFrames[currentInfoPacketHeader.Data.FrameId]
|
_, ok := d.infoPacketFrames[currentInfoPacketHeader.Data.FrameId]
|
||||||
@@ -67,7 +76,10 @@ func (d *Decoder) Decode(bytes []byte) {
|
|||||||
delete(d.infoPacketFrames, currentInfoPacketHeader.Data.FrameId)
|
delete(d.infoPacketFrames, currentInfoPacketHeader.Data.FrameId)
|
||||||
}
|
}
|
||||||
} else if chunk.Header.Id == 0x6755 {
|
} else if chunk.Header.Id == 0x6755 {
|
||||||
dataPacket := decoders.DecodeDataPacketChunk(bytes)
|
dataPacket, err := decoders.DecodeDataPacketChunk(bytes)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
currentInfoPacketHeader := dataPacket.Data.PacketHeader
|
currentInfoPacketHeader := dataPacket.Data.PacketHeader
|
||||||
|
|
||||||
_, ok := d.dataPacketFrames[currentInfoPacketHeader.Data.FrameId]
|
_, ok := d.dataPacketFrames[currentInfoPacketHeader.Data.FrameId]
|
||||||
@@ -82,4 +94,5 @@ func (d *Decoder) Decode(bytes []byte) {
|
|||||||
delete(d.dataPacketFrames, currentInfoPacketHeader.Data.FrameId)
|
delete(d.dataPacketFrames, currentInfoPacketHeader.Data.FrameId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ func (e *Encoder) GetInfoPackets(timestamp uint64, trackers []Tracker) [][]byte
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) GetDataPackets(timestamp uint64, trackers []Tracker) [][]byte {
|
func (e *Encoder) GetDataPackets(timestamp uint64, trackers []Tracker) [][]byte {
|
||||||
|
|
||||||
trackerChunks := [][]byte{}
|
trackerChunks := [][]byte{}
|
||||||
|
|
||||||
for _, tracker := range trackers {
|
for _, tracker := range trackers {
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ func getNTrackers(n int) []psn.Tracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
testSizes := []int{1, 10, 100, 1000}
|
testSizes := []int{1, 10, 100, 1000}
|
||||||
encoder := psn.Encoder{
|
encoder := psn.Encoder{
|
||||||
SystemName: "test encoder",
|
SystemName: "test encoder",
|
||||||
@@ -39,7 +38,6 @@ func main() {
|
|||||||
benchmark(trackerCount, iterations, encoder, *decoder)
|
benchmark(trackerCount, iterations, encoder, *decoder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type BenchmarkResults struct {
|
type BenchmarkResults struct {
|
||||||
|
|||||||
+19
-8
@@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
"github.com/jwetzell/psn-go"
|
"github.com/jwetzell/psn-go"
|
||||||
)
|
)
|
||||||
@@ -10,18 +11,28 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
decoder := psn.NewDecoder()
|
decoder := psn.NewDecoder()
|
||||||
|
|
||||||
infoPacketBytes := []byte{0x56, 0x67, 0x34, 0x80, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x01,
|
infoPacketBytes := []byte{
|
||||||
|
0x56, 0x67, 0x34, 0x80, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x01,
|
||||||
0x01, 0x01, 0x00, 0x0b, 0x00, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x4e, 0x61, 0x6d, 0x65, 0x02, 0x00, 0x11,
|
0x01, 0x01, 0x00, 0x0b, 0x00, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x4e, 0x61, 0x6d, 0x65, 0x02, 0x00, 0x11,
|
||||||
0x80, 0x01, 0x00, 0x0d, 0x80, 0x00, 0x00, 0x09, 0x00, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x65, 0x72, 0x20, 0x31}
|
0x80, 0x01, 0x00, 0x0d, 0x80, 0x00, 0x00, 0x09, 0x00, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x65, 0x72, 0x20, 0x31,
|
||||||
|
}
|
||||||
|
|
||||||
dataPacketBytes := []byte{0x55, 0x67, 0x28, 0x80, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x01,
|
dataPacketBytes := []byte{
|
||||||
|
0x55, 0x67, 0x28, 0x80, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x01,
|
||||||
0x01, 0x01, 0x00, 0x14, 0x80, 0x01, 0x00, 0x10, 0x80, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00,
|
0x01, 0x01, 0x00, 0x14, 0x80, 0x01, 0x00, 0x10, 0x80, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00,
|
||||||
0x80, 0x3f, 0x00, 0x00, 0x80, 0x3f}
|
0x80, 0x3f, 0x00, 0x00, 0x80, 0x3f,
|
||||||
|
}
|
||||||
|
|
||||||
decoder.Decode(infoPacketBytes)
|
err := decoder.Decode(infoPacketBytes)
|
||||||
decoder.Decode(dataPacketBytes)
|
if err != nil {
|
||||||
|
slog.Error("error decoding", "err", err)
|
||||||
|
}
|
||||||
|
err = decoder.Decode(dataPacketBytes)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("error decoding", "err", err)
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Printf("decoded: %+v\n", decoder.SystemName)
|
fmt.Printf("decoded system name: %s\n", decoder.SystemName)
|
||||||
|
|
||||||
trackers, err := json.MarshalIndent(decoder.Trackers, "", " ")
|
trackers, err := json.MarshalIndent(decoder.Trackers, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -29,5 +40,5 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(string(trackers))
|
fmt.Printf("decoded trackers: \n%s\n", string(trackers))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
encoder := psn.Encoder{
|
encoder := psn.Encoder{
|
||||||
SystemName: "Server Name",
|
SystemName: "Server Name",
|
||||||
VersionHigh: 2,
|
VersionHigh: 2,
|
||||||
@@ -41,5 +40,4 @@ func main() {
|
|||||||
fmt.Printf("%v\n", infoPacket)
|
fmt.Printf("%v\n", infoPacket)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -11,14 +12,13 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
addr, err := net.ResolveUDPAddr("udp", "236.10.10.10:56565")
|
addr, err := net.ResolveUDPAddr("udp", "236.10.10.10:56565")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error %v\n", err)
|
slog.Error("error making UDP address", "err", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := net.ListenMulticastUDP("udp", nil, addr)
|
client, err := net.ListenMulticastUDP("udp", nil, addr)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error %v\n", err)
|
slog.Error("error listening to UDP", "err", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer client.Close()
|
defer client.Close()
|
||||||
@@ -31,13 +31,15 @@ func main() {
|
|||||||
buffer := make([]byte, 2048)
|
buffer := make([]byte, 2048)
|
||||||
|
|
||||||
length, _, err := client.ReadFromUDP(buffer)
|
length, _, err := client.ReadFromUDP(buffer)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error %v", err)
|
slog.Error("error reading from UDP", "err", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if length > 0 {
|
if length > 0 {
|
||||||
decoder.Decode(buffer)
|
err := decoder.Decode(buffer)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("error decoding", "err", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if time.Now().UnixMilli()-lastPrintMillis > 1000 {
|
if time.Now().UnixMilli()-lastPrintMillis > 1000 {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"math"
|
"math"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
@@ -11,7 +12,6 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
client, err := net.Dial("udp", "236.10.10.10:56565")
|
client, err := net.Dial("udp", "236.10.10.10:56565")
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error %v\n", err)
|
fmt.Printf("Error %v\n", err)
|
||||||
return
|
return
|
||||||
@@ -46,7 +46,7 @@ func main() {
|
|||||||
|
|
||||||
for {
|
for {
|
||||||
if (time.Now().UnixMilli() - lastInfoMillis) > 500 {
|
if (time.Now().UnixMilli() - lastInfoMillis) > 500 {
|
||||||
fmt.Println("Sending Info Packets")
|
slog.Info("Sending Info Packets")
|
||||||
infoPackets := encoder.GetInfoPackets(uint64(timestamp), trackers)
|
infoPackets := encoder.GetInfoPackets(uint64(timestamp), trackers)
|
||||||
for _, infoPacket := range infoPackets {
|
for _, infoPacket := range infoPackets {
|
||||||
client.Write(infoPacket)
|
client.Write(infoPacket)
|
||||||
@@ -71,7 +71,7 @@ func main() {
|
|||||||
trackers[index].SetTimestamp(uint64(timestamp))
|
trackers[index].SetTimestamp(uint64(timestamp))
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Sending Data Packets")
|
slog.Info("Sending Data Packets")
|
||||||
dataPackets := encoder.GetDataPackets(uint64(timestamp), trackers)
|
dataPackets := encoder.GetDataPackets(uint64(timestamp), trackers)
|
||||||
for _, DataPacket := range dataPackets {
|
for _, DataPacket := range dataPackets {
|
||||||
client.Write(DataPacket)
|
client.Write(DataPacket)
|
||||||
@@ -81,5 +81,4 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package decoders
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ChunkHeader struct {
|
type ChunkHeader struct {
|
||||||
@@ -11,11 +12,16 @@ type ChunkHeader struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Chunk struct {
|
type Chunk struct {
|
||||||
Header ChunkHeader
|
|
||||||
ChunkData []byte
|
ChunkData []byte
|
||||||
|
Header ChunkHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecodeChunk(bytes []byte) (Chunk, error) {
|
||||||
|
|
||||||
|
if len(bytes) < 4 {
|
||||||
|
return Chunk{}, errors.New("chunk must be at least 4 bytes")
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodeChunk(bytes []byte) Chunk {
|
|
||||||
id := binary.LittleEndian.Uint16(bytes[0:2])
|
id := binary.LittleEndian.Uint16(bytes[0:2])
|
||||||
lengthAndFlag := binary.LittleEndian.Uint16(bytes[2:4])
|
lengthAndFlag := binary.LittleEndian.Uint16(bytes[2:4])
|
||||||
|
|
||||||
@@ -38,6 +44,5 @@ func DecodeChunk(bytes []byte) Chunk {
|
|||||||
return Chunk{
|
return Chunk{
|
||||||
Header: header,
|
Header: header,
|
||||||
ChunkData: chunk_data,
|
ChunkData: chunk_data,
|
||||||
}
|
}, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ package decoders
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestChunkDecoding(t *testing.T) {
|
func TestGoodChunkDecoding(t *testing.T) {
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
description string
|
description string
|
||||||
bytes []byte
|
bytes []byte
|
||||||
@@ -15,41 +15,54 @@ func TestChunkDecoding(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
description: "info packet",
|
description: "info packet",
|
||||||
bytes: []byte{0x56, 0x67, 0x34, 0x80, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x01,
|
bytes: []byte{
|
||||||
|
0x56, 0x67, 0x34, 0x80, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x01,
|
||||||
0x01, 0x01, 0x00, 0x0b, 0x00, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x4e, 0x61, 0x6d, 0x65, 0x02, 0x00, 0x11,
|
0x01, 0x01, 0x00, 0x0b, 0x00, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x4e, 0x61, 0x6d, 0x65, 0x02, 0x00, 0x11,
|
||||||
0x80, 0x01, 0x00, 0x0d, 0x80, 0x00, 0x00, 0x09, 0x00, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x65, 0x72, 0x20, 0x31},
|
0x80, 0x01, 0x00, 0x0d, 0x80, 0x00, 0x00, 0x09, 0x00, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x65, 0x72, 0x20, 0x31,
|
||||||
|
},
|
||||||
expected: Chunk{
|
expected: Chunk{
|
||||||
Header: ChunkHeader{
|
Header: ChunkHeader{
|
||||||
Id: uint16(26454),
|
Id: uint16(26454),
|
||||||
DataLen: uint16(52),
|
DataLen: uint16(52),
|
||||||
HasSubchunks: true,
|
HasSubchunks: true,
|
||||||
},
|
},
|
||||||
ChunkData: []byte{0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x01,
|
ChunkData: []byte{
|
||||||
|
0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x01,
|
||||||
0x01, 0x01, 0x00, 0x0b, 0x00, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x4e, 0x61, 0x6d, 0x65, 0x02, 0x00, 0x11,
|
0x01, 0x01, 0x00, 0x0b, 0x00, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x4e, 0x61, 0x6d, 0x65, 0x02, 0x00, 0x11,
|
||||||
0x80, 0x01, 0x00, 0x0d, 0x80, 0x00, 0x00, 0x09, 0x00, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x65, 0x72, 0x20, 0x31},
|
0x80, 0x01, 0x00, 0x0d, 0x80, 0x00, 0x00, 0x09, 0x00, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x65, 0x72, 0x20, 0x31,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "data packet",
|
description: "data packet",
|
||||||
bytes: []byte{0x55, 0x67, 0x28, 0x80, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x01,
|
bytes: []byte{
|
||||||
|
0x55, 0x67, 0x28, 0x80, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x01,
|
||||||
0x01, 0x01, 0x00, 0x14, 0x80, 0x01, 0x00, 0x10, 0x80, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00,
|
0x01, 0x01, 0x00, 0x14, 0x80, 0x01, 0x00, 0x10, 0x80, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00,
|
||||||
0x80, 0x3f, 0x00, 0x00, 0x80, 0x3f},
|
0x80, 0x3f, 0x00, 0x00, 0x80, 0x3f,
|
||||||
|
},
|
||||||
expected: Chunk{
|
expected: Chunk{
|
||||||
Header: ChunkHeader{
|
Header: ChunkHeader{
|
||||||
Id: uint16(26453),
|
Id: uint16(26453),
|
||||||
DataLen: uint16(40),
|
DataLen: uint16(40),
|
||||||
HasSubchunks: true,
|
HasSubchunks: true,
|
||||||
},
|
},
|
||||||
ChunkData: []byte{0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x01,
|
ChunkData: []byte{
|
||||||
|
0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x01,
|
||||||
0x01, 0x01, 0x00, 0x14, 0x80, 0x01, 0x00, 0x10, 0x80, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00,
|
0x01, 0x01, 0x00, 0x14, 0x80, 0x01, 0x00, 0x10, 0x80, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00,
|
||||||
0x80, 0x3f, 0x00, 0x00, 0x80, 0x3f},
|
0x80, 0x3f, 0x00, 0x00, 0x80, 0x3f,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
|
|
||||||
actual := DecodeChunk(testCase.bytes)
|
actual, err := DecodeChunk(testCase.bytes)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Test '%s' failed to decode chunk properly", testCase.description)
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(actual, testCase.expected) {
|
if !reflect.DeepEqual(actual, testCase.expected) {
|
||||||
t.Errorf("Test '%s' failed to decode chunk properly", testCase.description)
|
t.Errorf("Test '%s' failed to decode chunk properly", testCase.description)
|
||||||
@@ -58,3 +71,33 @@ func TestChunkDecoding(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBadChunkDecoding(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
description string
|
||||||
|
bytes []byte
|
||||||
|
errorShouldContain string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
description: "empty packet",
|
||||||
|
bytes: []byte{},
|
||||||
|
errorShouldContain: "must be at least 4 bytes",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
|
||||||
|
_, err := DecodeChunk(testCase.bytes)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Test '%s' should have failed fail to decode chunk properly", testCase.description)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(err.Error(), testCase.errorShouldContain) {
|
||||||
|
t.Errorf("Test '%s' did not return the correct error", testCase.description)
|
||||||
|
fmt.Printf("expected: %v\n", testCase.errorShouldContain)
|
||||||
|
fmt.Printf("actual: %v\n", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,29 +11,39 @@ type DataPacketChunkData struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DataPacketChunk struct {
|
type DataPacketChunk struct {
|
||||||
Chunk Chunk
|
|
||||||
Data DataPacketChunkData
|
Data DataPacketChunkData
|
||||||
|
Chunk Chunk
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecodeDataPacketChunk(bytes []byte) (DataPacketChunk, error) {
|
||||||
|
chunk, err := DecodeChunk(bytes)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return DataPacketChunk{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodeDataPacketChunk(bytes []byte) DataPacketChunk {
|
|
||||||
chunk := DecodeChunk(bytes)
|
|
||||||
data := DataPacketChunkData{}
|
data := DataPacketChunkData{}
|
||||||
|
|
||||||
if chunk.Header.HasSubchunks && chunk.ChunkData != nil && chunk.Header.DataLen > 0 {
|
if chunk.Header.HasSubchunks && chunk.ChunkData != nil && chunk.Header.DataLen > 0 {
|
||||||
offset := 0
|
offset := 0
|
||||||
|
|
||||||
for offset < int(chunk.Header.DataLen) {
|
for offset < int(chunk.Header.DataLen) {
|
||||||
|
|
||||||
switch id := binary.LittleEndian.Uint16(chunk.ChunkData[offset : offset+2]); id {
|
switch id := binary.LittleEndian.Uint16(chunk.ChunkData[offset : offset+2]); id {
|
||||||
case 0:
|
case 0x0000:
|
||||||
packet_header := DecodePacketHeaderChunk(chunk.ChunkData[offset:])
|
packet_header, err := DecodePacketHeaderChunk(chunk.ChunkData[offset:])
|
||||||
|
if err != nil {
|
||||||
|
return DataPacketChunk{}, err
|
||||||
|
}
|
||||||
data.PacketHeader = &packet_header
|
data.PacketHeader = &packet_header
|
||||||
offset += 4
|
offset += 4
|
||||||
if packet_header.Chunk.Header.DataLen > 0 {
|
if packet_header.Chunk.Header.DataLen > 0 {
|
||||||
offset = offset + int(packet_header.Chunk.Header.DataLen)
|
offset = offset + int(packet_header.Chunk.Header.DataLen)
|
||||||
}
|
}
|
||||||
case 1:
|
case 0x0001:
|
||||||
tracker_list := DecodeDataTrackerListChunk(chunk.ChunkData[offset:])
|
tracker_list, err := DecodeDataTrackerListChunk(chunk.ChunkData[offset:])
|
||||||
|
if err != nil {
|
||||||
|
return DataPacketChunk{}, err
|
||||||
|
}
|
||||||
data.TrackerList = &tracker_list
|
data.TrackerList = &tracker_list
|
||||||
offset += 4
|
offset += 4
|
||||||
if tracker_list.Chunk.Header.DataLen > 0 {
|
if tracker_list.Chunk.Header.DataLen > 0 {
|
||||||
@@ -49,5 +59,6 @@ func DecodeDataPacketChunk(bytes []byte) DataPacketChunk {
|
|||||||
return DataPacketChunk{
|
return DataPacketChunk{
|
||||||
Chunk: chunk,
|
Chunk: chunk,
|
||||||
Data: data,
|
Data: data,
|
||||||
}
|
},
|
||||||
|
nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,64 +16,89 @@ type DataTrackerChunkData struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DataTrackerChunk struct {
|
type DataTrackerChunk struct {
|
||||||
Chunk Chunk
|
|
||||||
Data DataTrackerChunkData
|
Data DataTrackerChunkData
|
||||||
|
Chunk Chunk
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecodeDataTrackerChunk(bytes []byte) (DataTrackerChunk, error) {
|
||||||
|
chunk, err := DecodeChunk(bytes)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return DataTrackerChunk{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodeDataTrackerChunk(bytes []byte) DataTrackerChunk {
|
|
||||||
chunk := DecodeChunk(bytes)
|
|
||||||
data := DataTrackerChunkData{}
|
data := DataTrackerChunkData{}
|
||||||
|
|
||||||
if chunk.Header.HasSubchunks && chunk.ChunkData != nil && chunk.Header.DataLen > 0 {
|
if chunk.Header.HasSubchunks && chunk.ChunkData != nil && chunk.Header.DataLen > 0 {
|
||||||
offset := 0
|
offset := 0
|
||||||
|
|
||||||
for offset < int(chunk.Header.DataLen) {
|
for offset < int(chunk.Header.DataLen) {
|
||||||
|
|
||||||
switch id := binary.LittleEndian.Uint16(chunk.ChunkData[offset : offset+2]); id {
|
switch id := binary.LittleEndian.Uint16(chunk.ChunkData[offset : offset+2]); id {
|
||||||
case 0:
|
case 0x0000:
|
||||||
pos := DecodeDataTrackerXYZChunk(chunk.ChunkData[offset:])
|
pos, err := DecodeDataTrackerXYZChunk(chunk.ChunkData[offset:])
|
||||||
|
if err != nil {
|
||||||
|
return DataTrackerChunk{}, err
|
||||||
|
}
|
||||||
data.Pos = &pos
|
data.Pos = &pos
|
||||||
offset += 4
|
offset += 4
|
||||||
if data.Pos.Chunk.Header.DataLen > 0 {
|
if data.Pos.Chunk.Header.DataLen > 0 {
|
||||||
offset = offset + int(data.Pos.Chunk.Header.DataLen)
|
offset = offset + int(data.Pos.Chunk.Header.DataLen)
|
||||||
}
|
}
|
||||||
case 1:
|
case 0x0001:
|
||||||
speed := DecodeDataTrackerXYZChunk(chunk.ChunkData[offset:])
|
speed, err := DecodeDataTrackerXYZChunk(chunk.ChunkData[offset:])
|
||||||
|
if err != nil {
|
||||||
|
return DataTrackerChunk{}, err
|
||||||
|
}
|
||||||
data.Speed = &speed
|
data.Speed = &speed
|
||||||
offset += 4
|
offset += 4
|
||||||
if data.Speed.Chunk.Header.DataLen > 0 {
|
if data.Speed.Chunk.Header.DataLen > 0 {
|
||||||
offset = offset + int(data.Speed.Chunk.Header.DataLen)
|
offset = offset + int(data.Speed.Chunk.Header.DataLen)
|
||||||
}
|
}
|
||||||
case 2:
|
case 0x0002:
|
||||||
ori := DecodeDataTrackerXYZChunk(chunk.ChunkData[offset:])
|
ori, err := DecodeDataTrackerXYZChunk(chunk.ChunkData[offset:])
|
||||||
|
if err != nil {
|
||||||
|
return DataTrackerChunk{}, err
|
||||||
|
}
|
||||||
data.Ori = &ori
|
data.Ori = &ori
|
||||||
offset += 4
|
offset += 4
|
||||||
if data.Ori.Chunk.Header.DataLen > 0 {
|
if data.Ori.Chunk.Header.DataLen > 0 {
|
||||||
offset = offset + int(data.Ori.Chunk.Header.DataLen)
|
offset = offset + int(data.Ori.Chunk.Header.DataLen)
|
||||||
}
|
}
|
||||||
case 3:
|
case 0x0003:
|
||||||
status := DecodeDataTrackerStatusChunk(chunk.ChunkData[offset:])
|
status, err := DecodeDataTrackerStatusChunk(chunk.ChunkData[offset:])
|
||||||
|
if err != nil {
|
||||||
|
return DataTrackerChunk{}, err
|
||||||
|
}
|
||||||
data.Status = &status
|
data.Status = &status
|
||||||
offset += 4
|
offset += 4
|
||||||
if data.Status.Chunk.Header.DataLen > 0 {
|
if data.Status.Chunk.Header.DataLen > 0 {
|
||||||
offset = offset + int(data.Status.Chunk.Header.DataLen)
|
offset = offset + int(data.Status.Chunk.Header.DataLen)
|
||||||
}
|
}
|
||||||
case 4:
|
case 0x0004:
|
||||||
accel := DecodeDataTrackerXYZChunk(chunk.ChunkData[offset:])
|
accel, err := DecodeDataTrackerXYZChunk(chunk.ChunkData[offset:])
|
||||||
|
if err != nil {
|
||||||
|
return DataTrackerChunk{}, err
|
||||||
|
}
|
||||||
data.Accel = &accel
|
data.Accel = &accel
|
||||||
offset += 4
|
offset += 4
|
||||||
if data.Accel.Chunk.Header.DataLen > 0 {
|
if data.Accel.Chunk.Header.DataLen > 0 {
|
||||||
offset = offset + int(data.Accel.Chunk.Header.DataLen)
|
offset = offset + int(data.Accel.Chunk.Header.DataLen)
|
||||||
}
|
}
|
||||||
case 5:
|
case 0x0005:
|
||||||
trgtpos := DecodeDataTrackerXYZChunk(chunk.ChunkData[offset:])
|
trgtpos, err := DecodeDataTrackerXYZChunk(chunk.ChunkData[offset:])
|
||||||
|
if err != nil {
|
||||||
|
return DataTrackerChunk{}, err
|
||||||
|
}
|
||||||
data.TrgtPos = &trgtpos
|
data.TrgtPos = &trgtpos
|
||||||
offset += 4
|
offset += 4
|
||||||
if data.TrgtPos.Chunk.Header.DataLen > 0 {
|
if data.TrgtPos.Chunk.Header.DataLen > 0 {
|
||||||
offset = offset + int(data.TrgtPos.Chunk.Header.DataLen)
|
offset = offset + int(data.TrgtPos.Chunk.Header.DataLen)
|
||||||
}
|
}
|
||||||
case 6:
|
case 0x0006:
|
||||||
timestamp := DecodeDataTrackerTimestampChunk(chunk.ChunkData[offset:])
|
timestamp, err := DecodeDataTrackerTimestampChunk(chunk.ChunkData[offset:])
|
||||||
|
if err != nil {
|
||||||
|
return DataTrackerChunk{}, err
|
||||||
|
}
|
||||||
data.Timestamp = ×tamp
|
data.Timestamp = ×tamp
|
||||||
offset += 4
|
offset += 4
|
||||||
if data.Timestamp.Chunk.Header.DataLen > 0 {
|
if data.Timestamp.Chunk.Header.DataLen > 0 {
|
||||||
@@ -89,5 +114,6 @@ func DecodeDataTrackerChunk(bytes []byte) DataTrackerChunk {
|
|||||||
return DataTrackerChunk{
|
return DataTrackerChunk{
|
||||||
Chunk: chunk,
|
Chunk: chunk,
|
||||||
Data: data,
|
Data: data,
|
||||||
}
|
},
|
||||||
|
nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,14 +8,21 @@ type DataTrackerListChunk struct {
|
|||||||
Data DataTrackerListChunkData
|
Data DataTrackerListChunkData
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodeDataTrackerListChunk(bytes []byte) DataTrackerListChunk {
|
func DecodeDataTrackerListChunk(bytes []byte) (DataTrackerListChunk, error) {
|
||||||
chunk := DecodeChunk(bytes)
|
chunk, err := DecodeChunk(bytes)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return DataTrackerListChunk{}, err
|
||||||
|
}
|
||||||
|
|
||||||
trackers := []DataTrackerChunk{}
|
trackers := []DataTrackerChunk{}
|
||||||
if chunk.Header.HasSubchunks && chunk.Header.DataLen > 0 {
|
if chunk.Header.HasSubchunks && chunk.Header.DataLen > 0 {
|
||||||
offset := 0
|
offset := 0
|
||||||
for offset < int(chunk.Header.DataLen) {
|
for offset < int(chunk.Header.DataLen) {
|
||||||
trackerChunk := DecodeDataTrackerChunk(chunk.ChunkData[offset:])
|
trackerChunk, err := DecodeDataTrackerChunk(chunk.ChunkData[offset:])
|
||||||
|
if err != nil {
|
||||||
|
return DataTrackerListChunk{}, err
|
||||||
|
}
|
||||||
offset += 4
|
offset += 4
|
||||||
if trackerChunk.Chunk.Header.DataLen > 0 {
|
if trackerChunk.Chunk.Header.DataLen > 0 {
|
||||||
offset += int(trackerChunk.Chunk.Header.DataLen)
|
offset += int(trackerChunk.Chunk.Header.DataLen)
|
||||||
@@ -31,6 +38,6 @@ func DecodeDataTrackerListChunk(bytes []byte) DataTrackerListChunk {
|
|||||||
return DataTrackerListChunk{
|
return DataTrackerListChunk{
|
||||||
Chunk: chunk,
|
Chunk: chunk,
|
||||||
Data: data,
|
Data: data,
|
||||||
}
|
},
|
||||||
|
nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package decoders
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
"math"
|
"math"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -14,8 +15,16 @@ type DataTrackerStatusChunk struct {
|
|||||||
Data DataTrackerStatusChunkData
|
Data DataTrackerStatusChunkData
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodeDataTrackerStatusChunk(bytes []byte) DataTrackerStatusChunk {
|
func DecodeDataTrackerStatusChunk(bytes []byte) (DataTrackerStatusChunk, error) {
|
||||||
chunk := DecodeChunk(bytes)
|
chunk, err := DecodeChunk(bytes)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return DataTrackerStatusChunk{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(chunk.ChunkData) < 4 {
|
||||||
|
return DataTrackerStatusChunk{}, errors.New("DATA_TRACKER_STATUS chunk must be at least 4 bytes")
|
||||||
|
}
|
||||||
|
|
||||||
statusBits := binary.LittleEndian.Uint32(chunk.ChunkData[0:4])
|
statusBits := binary.LittleEndian.Uint32(chunk.ChunkData[0:4])
|
||||||
|
|
||||||
@@ -26,6 +35,6 @@ func DecodeDataTrackerStatusChunk(bytes []byte) DataTrackerStatusChunk {
|
|||||||
return DataTrackerStatusChunk{
|
return DataTrackerStatusChunk{
|
||||||
Chunk: chunk,
|
Chunk: chunk,
|
||||||
Data: data,
|
Data: data,
|
||||||
}
|
},
|
||||||
|
nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package decoders
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DataTrackerTimestampChunkData struct {
|
type DataTrackerTimestampChunkData struct {
|
||||||
@@ -13,8 +14,16 @@ type DataTrackerTimestampChunk struct {
|
|||||||
Data DataTrackerTimestampChunkData
|
Data DataTrackerTimestampChunkData
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodeDataTrackerTimestampChunk(bytes []byte) DataTrackerTimestampChunk {
|
func DecodeDataTrackerTimestampChunk(bytes []byte) (DataTrackerTimestampChunk, error) {
|
||||||
chunk := DecodeChunk(bytes)
|
chunk, err := DecodeChunk(bytes)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return DataTrackerTimestampChunk{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(chunk.ChunkData) < 8 {
|
||||||
|
return DataTrackerTimestampChunk{}, errors.New("DATA_TRACKER_TIMESTAMP chunk must be at least 8 bytes")
|
||||||
|
}
|
||||||
|
|
||||||
timestamp := binary.LittleEndian.Uint64(chunk.ChunkData[0:8])
|
timestamp := binary.LittleEndian.Uint64(chunk.ChunkData[0:8])
|
||||||
|
|
||||||
@@ -25,6 +34,6 @@ func DecodeDataTrackerTimestampChunk(bytes []byte) DataTrackerTimestampChunk {
|
|||||||
return DataTrackerTimestampChunk{
|
return DataTrackerTimestampChunk{
|
||||||
Chunk: chunk,
|
Chunk: chunk,
|
||||||
Data: data,
|
Data: data,
|
||||||
}
|
},
|
||||||
|
nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package decoders
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
"math"
|
"math"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -16,8 +17,16 @@ type DataTrackerXYZChunk struct {
|
|||||||
Data DataTrackerXYZChunkData
|
Data DataTrackerXYZChunkData
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodeDataTrackerXYZChunk(bytes []byte) DataTrackerXYZChunk {
|
func DecodeDataTrackerXYZChunk(bytes []byte) (DataTrackerXYZChunk, error) {
|
||||||
chunk := DecodeChunk(bytes)
|
chunk, err := DecodeChunk(bytes)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return DataTrackerXYZChunk{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(chunk.ChunkData) < 12 {
|
||||||
|
return DataTrackerXYZChunk{}, errors.New("DATA_TRACKER_XYZ chunk must be at least 12 bytes")
|
||||||
|
}
|
||||||
|
|
||||||
xBits := binary.LittleEndian.Uint32(chunk.ChunkData[0:4])
|
xBits := binary.LittleEndian.Uint32(chunk.ChunkData[0:4])
|
||||||
yBits := binary.LittleEndian.Uint32(chunk.ChunkData[4:8])
|
yBits := binary.LittleEndian.Uint32(chunk.ChunkData[4:8])
|
||||||
@@ -32,6 +41,5 @@ func DecodeDataTrackerXYZChunk(bytes []byte) DataTrackerXYZChunk {
|
|||||||
return DataTrackerXYZChunk{
|
return DataTrackerXYZChunk{
|
||||||
Chunk: chunk,
|
Chunk: chunk,
|
||||||
Data: data,
|
Data: data,
|
||||||
}
|
}, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,36 +12,47 @@ type InfoPacketChunkData struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type InfoPacketChunk struct {
|
type InfoPacketChunk struct {
|
||||||
Chunk Chunk
|
|
||||||
Data InfoPacketChunkData
|
Data InfoPacketChunkData
|
||||||
|
Chunk Chunk
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodeInfoPacketChunk(bytes []byte) InfoPacketChunk {
|
func DecodeInfoPacketChunk(bytes []byte) (InfoPacketChunk, error) {
|
||||||
chunk := DecodeChunk(bytes)
|
chunk, err := DecodeChunk(bytes)
|
||||||
|
if err != nil {
|
||||||
|
return InfoPacketChunk{}, err
|
||||||
|
}
|
||||||
data := InfoPacketChunkData{}
|
data := InfoPacketChunkData{}
|
||||||
|
|
||||||
if chunk.Header.HasSubchunks && chunk.ChunkData != nil && chunk.Header.DataLen > 0 {
|
if chunk.Header.HasSubchunks && chunk.ChunkData != nil && chunk.Header.DataLen > 0 {
|
||||||
offset := 0
|
offset := 0
|
||||||
|
|
||||||
for offset < int(chunk.Header.DataLen) {
|
for offset < int(chunk.Header.DataLen) {
|
||||||
|
|
||||||
switch id := binary.LittleEndian.Uint16(chunk.ChunkData[offset : offset+2]); id {
|
switch id := binary.LittleEndian.Uint16(chunk.ChunkData[offset : offset+2]); id {
|
||||||
case 0:
|
case 0x0000:
|
||||||
packet_header := DecodePacketHeaderChunk(chunk.ChunkData[offset:])
|
packet_header, err := DecodePacketHeaderChunk(chunk.ChunkData[offset:])
|
||||||
|
if err != nil {
|
||||||
|
return InfoPacketChunk{}, err
|
||||||
|
}
|
||||||
data.PacketHeader = &packet_header
|
data.PacketHeader = &packet_header
|
||||||
offset += 4
|
offset += 4
|
||||||
if packet_header.Chunk.Header.DataLen > 0 {
|
if packet_header.Chunk.Header.DataLen > 0 {
|
||||||
offset = offset + int(packet_header.Chunk.Header.DataLen)
|
offset = offset + int(packet_header.Chunk.Header.DataLen)
|
||||||
}
|
}
|
||||||
case 1:
|
case 0x0001:
|
||||||
system_name := DecodeInfoSystemNameChunk(chunk.ChunkData[offset:])
|
system_name, err := DecodeInfoSystemNameChunk(chunk.ChunkData[offset:])
|
||||||
|
if err != nil {
|
||||||
|
return InfoPacketChunk{}, err
|
||||||
|
}
|
||||||
data.SystemName = &system_name
|
data.SystemName = &system_name
|
||||||
offset += 4
|
offset += 4
|
||||||
if system_name.Chunk.Header.DataLen > 0 {
|
if system_name.Chunk.Header.DataLen > 0 {
|
||||||
offset = offset + int(system_name.Chunk.Header.DataLen)
|
offset = offset + int(system_name.Chunk.Header.DataLen)
|
||||||
}
|
}
|
||||||
case 2:
|
case 0x0002:
|
||||||
tracker_list := DecodeInfoTrackerListChunk(chunk.ChunkData[offset:])
|
tracker_list, err := DecodeInfoTrackerListChunk(chunk.ChunkData[offset:])
|
||||||
|
if err != nil {
|
||||||
|
return InfoPacketChunk{}, err
|
||||||
|
}
|
||||||
data.TrackerList = &tracker_list
|
data.TrackerList = &tracker_list
|
||||||
offset += 4
|
offset += 4
|
||||||
if tracker_list.Chunk.Header.DataLen > 0 {
|
if tracker_list.Chunk.Header.DataLen > 0 {
|
||||||
@@ -57,5 +68,6 @@ func DecodeInfoPacketChunk(bytes []byte) InfoPacketChunk {
|
|||||||
return InfoPacketChunk{
|
return InfoPacketChunk{
|
||||||
Chunk: chunk,
|
Chunk: chunk,
|
||||||
Data: data,
|
Data: data,
|
||||||
}
|
},
|
||||||
|
nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,21 +5,23 @@ type InfoSystemNameChunkData struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type InfoSystemNameChunk struct {
|
type InfoSystemNameChunk struct {
|
||||||
Chunk Chunk
|
|
||||||
Data InfoSystemNameChunkData
|
Data InfoSystemNameChunkData
|
||||||
|
Chunk Chunk
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodeInfoSystemNameChunk(bytes []byte) InfoSystemNameChunk {
|
func DecodeInfoSystemNameChunk(bytes []byte) (InfoSystemNameChunk, error) {
|
||||||
chunk := DecodeChunk(bytes)
|
chunk, err := DecodeChunk(bytes)
|
||||||
system_name := string(chunk.ChunkData[0:chunk.Header.DataLen])
|
if err != nil {
|
||||||
|
return InfoSystemNameChunk{}, err
|
||||||
|
}
|
||||||
|
data := InfoSystemNameChunkData{}
|
||||||
|
|
||||||
data := InfoSystemNameChunkData{
|
if chunk.Header.DataLen > 0 {
|
||||||
SystemName: system_name,
|
data.SystemName = string(chunk.ChunkData[0:chunk.Header.DataLen])
|
||||||
}
|
}
|
||||||
|
|
||||||
return InfoSystemNameChunk{
|
return InfoSystemNameChunk{
|
||||||
Chunk: chunk,
|
Chunk: chunk,
|
||||||
Data: data,
|
Data: data,
|
||||||
}
|
}, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,22 +10,27 @@ type InfoTrackerChunkData struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type InfoTrackerChunk struct {
|
type InfoTrackerChunk struct {
|
||||||
Chunk Chunk
|
|
||||||
Data InfoTrackerChunkData
|
Data InfoTrackerChunkData
|
||||||
|
Chunk Chunk
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodeInfoTrackerChunk(bytes []byte) InfoTrackerChunk {
|
func DecodeInfoTrackerChunk(bytes []byte) (InfoTrackerChunk, error) {
|
||||||
chunk := DecodeChunk(bytes)
|
chunk, err := DecodeChunk(bytes)
|
||||||
|
if err != nil {
|
||||||
|
return InfoTrackerChunk{}, err
|
||||||
|
}
|
||||||
data := InfoTrackerChunkData{}
|
data := InfoTrackerChunkData{}
|
||||||
|
|
||||||
if chunk.Header.HasSubchunks && chunk.ChunkData != nil && chunk.Header.DataLen > 0 {
|
if chunk.Header.HasSubchunks && chunk.ChunkData != nil && chunk.Header.DataLen > 0 {
|
||||||
offset := 0
|
offset := 0
|
||||||
|
|
||||||
for offset < int(chunk.Header.DataLen) {
|
for offset < int(chunk.Header.DataLen) {
|
||||||
|
|
||||||
switch id := binary.LittleEndian.Uint16(chunk.ChunkData[offset : offset+2]); id {
|
switch id := binary.LittleEndian.Uint16(chunk.ChunkData[offset : offset+2]); id {
|
||||||
case 0:
|
case 0x0000:
|
||||||
tracker_name := DecodeInfoTrackerNameChunk(chunk.ChunkData[offset:])
|
tracker_name, err := DecodeInfoTrackerNameChunk(chunk.ChunkData[offset:])
|
||||||
|
if err != nil {
|
||||||
|
return InfoTrackerChunk{}, err
|
||||||
|
}
|
||||||
data.TrackerName = &tracker_name
|
data.TrackerName = &tracker_name
|
||||||
offset += 4
|
offset += 4
|
||||||
if tracker_name.Chunk.Header.DataLen > 0 {
|
if tracker_name.Chunk.Header.DataLen > 0 {
|
||||||
@@ -40,5 +45,6 @@ func DecodeInfoTrackerChunk(bytes []byte) InfoTrackerChunk {
|
|||||||
return InfoTrackerChunk{
|
return InfoTrackerChunk{
|
||||||
Chunk: chunk,
|
Chunk: chunk,
|
||||||
Data: data,
|
Data: data,
|
||||||
}
|
},
|
||||||
|
nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,14 +9,20 @@ type InfoTrackerListChunk struct {
|
|||||||
Data InfoTrackerListChunkData
|
Data InfoTrackerListChunkData
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodeInfoTrackerListChunk(bytes []byte) InfoTrackerListChunk {
|
func DecodeInfoTrackerListChunk(bytes []byte) (InfoTrackerListChunk, error) {
|
||||||
chunk := DecodeChunk(bytes)
|
chunk, err := DecodeChunk(bytes)
|
||||||
|
if err != nil {
|
||||||
|
return InfoTrackerListChunk{}, err
|
||||||
|
}
|
||||||
|
|
||||||
trackers := []InfoTrackerChunk{}
|
trackers := []InfoTrackerChunk{}
|
||||||
if chunk.Header.HasSubchunks && chunk.Header.DataLen > 0 {
|
if chunk.Header.HasSubchunks && chunk.Header.DataLen > 0 {
|
||||||
offset := 0
|
offset := 0
|
||||||
for offset < int(chunk.Header.DataLen) {
|
for offset < int(chunk.Header.DataLen) {
|
||||||
trackerChunk := DecodeInfoTrackerChunk(chunk.ChunkData[offset:])
|
trackerChunk, err := DecodeInfoTrackerChunk(chunk.ChunkData[offset:])
|
||||||
|
if err != nil {
|
||||||
|
return InfoTrackerListChunk{}, err
|
||||||
|
}
|
||||||
offset += 4
|
offset += 4
|
||||||
if trackerChunk.Chunk.Header.DataLen > 0 {
|
if trackerChunk.Chunk.Header.DataLen > 0 {
|
||||||
offset += int(trackerChunk.Chunk.Header.DataLen)
|
offset += int(trackerChunk.Chunk.Header.DataLen)
|
||||||
@@ -32,6 +38,6 @@ func DecodeInfoTrackerListChunk(bytes []byte) InfoTrackerListChunk {
|
|||||||
return InfoTrackerListChunk{
|
return InfoTrackerListChunk{
|
||||||
Chunk: chunk,
|
Chunk: chunk,
|
||||||
Data: data,
|
Data: data,
|
||||||
}
|
},
|
||||||
|
nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,22 +5,26 @@ type InfoTrackerNameChunkData struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type InfoTrackerNameChunk struct {
|
type InfoTrackerNameChunk struct {
|
||||||
Chunk Chunk
|
|
||||||
Data InfoTrackerNameChunkData
|
Data InfoTrackerNameChunkData
|
||||||
|
Chunk Chunk
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodeInfoTrackerNameChunk(bytes []byte) InfoTrackerNameChunk {
|
func DecodeInfoTrackerNameChunk(bytes []byte) (InfoTrackerNameChunk, error) {
|
||||||
chunk := DecodeChunk(bytes)
|
chunk, err := DecodeChunk(bytes)
|
||||||
|
|
||||||
tracker_name := string(chunk.ChunkData[0:chunk.Header.DataLen])
|
if err != nil {
|
||||||
|
return InfoTrackerNameChunk{}, err
|
||||||
|
}
|
||||||
|
|
||||||
data := InfoTrackerNameChunkData{
|
data := InfoTrackerNameChunkData{}
|
||||||
TrackerName: tracker_name,
|
|
||||||
|
if chunk.Header.DataLen > 0 {
|
||||||
|
data.TrackerName = string(chunk.ChunkData[0:chunk.Header.DataLen])
|
||||||
}
|
}
|
||||||
|
|
||||||
return InfoTrackerNameChunk{
|
return InfoTrackerNameChunk{
|
||||||
Chunk: chunk,
|
Chunk: chunk,
|
||||||
Data: data,
|
Data: data,
|
||||||
}
|
},
|
||||||
|
nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,11 @@ type PacketHeaderChunk struct {
|
|||||||
Data PacketHeaderChunkData
|
Data PacketHeaderChunkData
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodePacketHeaderChunk(bytes []byte) PacketHeaderChunk {
|
func DecodePacketHeaderChunk(bytes []byte) (PacketHeaderChunk, error) {
|
||||||
chunk := DecodeChunk(bytes)
|
chunk, err := DecodeChunk(bytes)
|
||||||
|
if err != nil {
|
||||||
|
return PacketHeaderChunk{}, err
|
||||||
|
}
|
||||||
|
|
||||||
packet_timestamp := binary.LittleEndian.Uint64(chunk.ChunkData[0:8])
|
packet_timestamp := binary.LittleEndian.Uint64(chunk.ChunkData[0:8])
|
||||||
version_high := chunk.ChunkData[8]
|
version_high := chunk.ChunkData[8]
|
||||||
@@ -35,6 +38,6 @@ func DecodePacketHeaderChunk(bytes []byte) PacketHeaderChunk {
|
|||||||
return PacketHeaderChunk{
|
return PacketHeaderChunk{
|
||||||
Chunk: chunk,
|
Chunk: chunk,
|
||||||
Data: data,
|
Data: data,
|
||||||
}
|
},
|
||||||
|
nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package encoders
|
|||||||
import "encoding/binary"
|
import "encoding/binary"
|
||||||
|
|
||||||
func EncodeChunk(id uint16, chunkData []byte, hasSubchunks bool) []byte {
|
func EncodeChunk(id uint16, chunkData []byte, hasSubchunks bool) []byte {
|
||||||
|
|
||||||
header := []byte{}
|
header := []byte{}
|
||||||
|
|
||||||
header = binary.LittleEndian.AppendUint16(header, id)
|
header = binary.LittleEndian.AppendUint16(header, id)
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package encoders
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/jwetzell/psn-go/internal/decoders"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestChunkEncoding(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
description string
|
||||||
|
expected []byte
|
||||||
|
chunk decoders.Chunk
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
description: "info packet",
|
||||||
|
expected: []byte{
|
||||||
|
0x56, 0x67, 0x34, 0x80, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x01,
|
||||||
|
0x01, 0x01, 0x00, 0x0b, 0x00, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x4e, 0x61, 0x6d, 0x65, 0x02, 0x00, 0x11,
|
||||||
|
0x80, 0x01, 0x00, 0x0d, 0x80, 0x00, 0x00, 0x09, 0x00, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x65, 0x72, 0x20, 0x31,
|
||||||
|
},
|
||||||
|
chunk: decoders.Chunk{
|
||||||
|
Header: decoders.ChunkHeader{
|
||||||
|
Id: uint16(26454),
|
||||||
|
DataLen: uint16(52),
|
||||||
|
HasSubchunks: true,
|
||||||
|
},
|
||||||
|
ChunkData: []byte{
|
||||||
|
0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x01,
|
||||||
|
0x01, 0x01, 0x00, 0x0b, 0x00, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x4e, 0x61, 0x6d, 0x65, 0x02, 0x00, 0x11,
|
||||||
|
0x80, 0x01, 0x00, 0x0d, 0x80, 0x00, 0x00, 0x09, 0x00, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x65, 0x72, 0x20, 0x31,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "data packet",
|
||||||
|
expected: []byte{
|
||||||
|
0x55, 0x67, 0x28, 0x80, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x01,
|
||||||
|
0x01, 0x01, 0x00, 0x14, 0x80, 0x01, 0x00, 0x10, 0x80, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00,
|
||||||
|
0x80, 0x3f, 0x00, 0x00, 0x80, 0x3f,
|
||||||
|
},
|
||||||
|
chunk: decoders.Chunk{
|
||||||
|
Header: decoders.ChunkHeader{
|
||||||
|
Id: uint16(26453),
|
||||||
|
DataLen: uint16(40),
|
||||||
|
HasSubchunks: true,
|
||||||
|
},
|
||||||
|
ChunkData: []byte{
|
||||||
|
0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x01,
|
||||||
|
0x01, 0x01, 0x00, 0x14, 0x80, 0x01, 0x00, 0x10, 0x80, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00,
|
||||||
|
0x80, 0x3f, 0x00, 0x00, 0x80, 0x3f,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
|
||||||
|
actual := EncodeChunk(testCase.chunk.Header.Id, testCase.chunk.ChunkData, testCase.chunk.Header.HasSubchunks)
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(actual, testCase.expected) {
|
||||||
|
t.Errorf("Test '%s' failed to encode chunk properly", testCase.description)
|
||||||
|
fmt.Printf("expected: %v\n", testCase.expected)
|
||||||
|
fmt.Printf("actual: %v\n", actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -12,8 +12,6 @@ type XYZData struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Tracker struct {
|
type Tracker struct {
|
||||||
Id uint16
|
|
||||||
Name string
|
|
||||||
Pos *XYZData
|
Pos *XYZData
|
||||||
Speed *XYZData
|
Speed *XYZData
|
||||||
Ori *XYZData
|
Ori *XYZData
|
||||||
@@ -21,6 +19,8 @@ type Tracker struct {
|
|||||||
Accel *XYZData
|
Accel *XYZData
|
||||||
TrgtPos *XYZData
|
TrgtPos *XYZData
|
||||||
Timestamp *uint64
|
Timestamp *uint64
|
||||||
|
Name string
|
||||||
|
Id uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tracker) SetPos(x float32, y float32, z float32) {
|
func (t *Tracker) SetPos(x float32, y float32, z float32) {
|
||||||
|
|||||||
Reference in New Issue
Block a user