mirror of
https://github.com/jwetzell/free-d-go.git
synced 2026-09-06 14:28:58 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cf2d3a2ae0 | |||
| acb6708b80 | |||
| e8b3869048 | |||
| 64814b9e05 |
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 Joel Wetzell
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
messageBytes := []byte{0xd1, 0x01, 0x5a, 0x00, 0x00, 0x2d, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x7f, 0xff, 0x40, 0x7f, 0xff, 0x80, 0x7f, 0xff,
|
messageBytes := [29]byte{0xd1, 0x01, 0x5a, 0x00, 0x00, 0x2d, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x7f, 0xff, 0x40, 0x7f, 0xff, 0x80, 0x7f, 0xff,
|
||||||
0xc0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00, 0x00, 50,
|
0xc0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00, 0x00, 50,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,13 @@ func main() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("error reading from UDP", "err", err)
|
slog.Error("error reading from UDP", "err", err)
|
||||||
} else if length > 0 {
|
} else if length > 0 {
|
||||||
message, err := freeD.Decode(buffer[0:length])
|
if length != 29 {
|
||||||
|
slog.Warn("received UDP packet with unexpected length", "length", length)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var messageBytes [29]byte
|
||||||
|
copy(messageBytes[:], buffer[0:length])
|
||||||
|
message, err := freeD.Decode(messageBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("error decoding", "err", err)
|
slog.Error("error decoding", "err", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,40 +18,37 @@ type FreeDPosition struct {
|
|||||||
Focus int32
|
Focus int32
|
||||||
}
|
}
|
||||||
|
|
||||||
func Encode(message FreeDPosition) []byte {
|
func Encode(message FreeDPosition) [29]byte {
|
||||||
bytes := []byte{}
|
var bytes [29]byte
|
||||||
|
|
||||||
bytes = append(bytes, 0xd1)
|
bytes[0] = 0xd1
|
||||||
bytes = append(bytes, message.ID)
|
bytes[1] = message.ID
|
||||||
|
|
||||||
bytes = append(bytes, rotationToFreeDUnits(message.Pan)...)
|
copy(bytes[2:5], rotationToFreeDUnits(message.Pan))
|
||||||
bytes = append(bytes, rotationToFreeDUnits(message.Tilt)...)
|
copy(bytes[5:8], rotationToFreeDUnits(message.Tilt))
|
||||||
bytes = append(bytes, rotationToFreeDUnits(message.Roll)...)
|
copy(bytes[8:11], rotationToFreeDUnits(message.Roll))
|
||||||
|
|
||||||
bytes = append(bytes, positionToFreeDUnits(message.PosX)...)
|
copy(bytes[11:14], positionToFreeDUnits(message.PosX))
|
||||||
bytes = append(bytes, positionToFreeDUnits(message.PosY)...)
|
copy(bytes[14:17], positionToFreeDUnits(message.PosY))
|
||||||
bytes = append(bytes, positionToFreeDUnits(message.PosZ)...)
|
copy(bytes[17:20], positionToFreeDUnits(message.PosZ))
|
||||||
|
|
||||||
bytes = append(bytes, uint8(math.Trunc(float64(message.Zoom/65536))))
|
bytes[20] = uint8(math.Trunc(float64(message.Zoom / 65536)))
|
||||||
bytes = append(bytes, uint8(int64(message.Zoom/256)%256))
|
bytes[21] = uint8(int64(message.Zoom/256) % 256)
|
||||||
bytes = append(bytes, uint8(int32(message.Zoom)%256))
|
bytes[22] = uint8(int32(message.Zoom) % 256)
|
||||||
|
|
||||||
bytes = append(bytes, uint8(math.Trunc(float64(message.Focus/65536))))
|
bytes[23] = uint8(math.Trunc(float64(message.Focus / 65536)))
|
||||||
bytes = append(bytes, uint8(int64(message.Focus/256)%256))
|
bytes[24] = uint8(int64(message.Focus/256) % 256)
|
||||||
bytes = append(bytes, uint8(int32(message.Focus)%256))
|
bytes[25] = uint8(int32(message.Focus) % 256)
|
||||||
|
|
||||||
// spare area?
|
// spare area?
|
||||||
bytes = append(bytes, 0, 0)
|
bytes[26] = 0
|
||||||
|
bytes[27] = 0
|
||||||
|
|
||||||
bytes = append(bytes, checksum(bytes[0:28]))
|
bytes[28] = checksum(bytes[0:28])
|
||||||
return bytes
|
return bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
func Decode(bytes []byte) (FreeDPosition, error) {
|
func Decode(bytes [29]byte) (FreeDPosition, error) {
|
||||||
if len(bytes) != 29 {
|
|
||||||
return FreeDPosition{}, errors.New("FreeD packet must be 29 bytes long")
|
|
||||||
}
|
|
||||||
|
|
||||||
if bytes[0] != 0xd1 {
|
if bytes[0] != 0xd1 {
|
||||||
return FreeDPosition{}, errors.New("only FreeD position messages are currently supported")
|
return FreeDPosition{}, errors.New("only FreeD position messages are currently supported")
|
||||||
}
|
}
|
||||||
|
|||||||
+45
-5
@@ -9,12 +9,12 @@ import (
|
|||||||
func TestMessageDecoding(t *testing.T) {
|
func TestMessageDecoding(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
description string
|
description string
|
||||||
bytes []byte
|
bytes [29]byte
|
||||||
expected FreeDPosition
|
expected FreeDPosition
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
description: "simple position message",
|
description: "simple position message",
|
||||||
bytes: []byte{0xd1, 0x01, 0x5a, 0x00, 0x00, 0x2d, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x7f, 0xff, 0x40, 0x7f, 0xff, 0x80, 0x7f, 0xff,
|
bytes: [29]byte{0xd1, 0x01, 0x5a, 0x00, 0x00, 0x2d, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x7f, 0xff, 0x40, 0x7f, 0xff, 0x80, 0x7f, 0xff,
|
||||||
0xc0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00, 0x00, 50,
|
0xc0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00, 0x00, 50,
|
||||||
},
|
},
|
||||||
expected: FreeDPosition{
|
expected: FreeDPosition{
|
||||||
@@ -48,15 +48,15 @@ func TestMessageDecoding(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMessageEncoding(t *testing.T) {
|
func TestGoodMessageEncoding(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
description string
|
description string
|
||||||
expected []byte
|
expected [29]byte
|
||||||
message FreeDPosition
|
message FreeDPosition
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
description: "simple position message",
|
description: "simple position message",
|
||||||
expected: []byte{0xd1, 0x01, 0x5a, 0x00, 0x00, 0x2d, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x7f, 0xff, 0x40, 0x7f, 0xff, 0x80, 0x7f, 0xff,
|
expected: [29]byte{0xd1, 0x01, 0x5a, 0x00, 0x00, 0x2d, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x7f, 0xff, 0x40, 0x7f, 0xff, 0x80, 0x7f, 0xff,
|
||||||
0xc0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00, 0x00, 50,
|
0xc0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00, 0x00, 50,
|
||||||
},
|
},
|
||||||
message: FreeDPosition{
|
message: FreeDPosition{
|
||||||
@@ -84,3 +84,43 @@ func TestMessageEncoding(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkMessageDecoding(b *testing.B) {
|
||||||
|
data := [29]byte{0xd1, 0x01, 0x5a, 0x00, 0x00, 0x2d, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x7f, 0xff, 0x40, 0x7f, 0xff, 0x80, 0x7f, 0xff,
|
||||||
|
0xc0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00, 0x00, 50,
|
||||||
|
}
|
||||||
|
for b.Loop() {
|
||||||
|
Decode(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMessageEncoding(b *testing.B) {
|
||||||
|
message := FreeDPosition{
|
||||||
|
ID: 1,
|
||||||
|
Pan: 180,
|
||||||
|
Tilt: 90,
|
||||||
|
Roll: -180,
|
||||||
|
PosX: 131069,
|
||||||
|
PosY: 131070,
|
||||||
|
PosZ: 131071,
|
||||||
|
Zoom: 66051,
|
||||||
|
Focus: 263430,
|
||||||
|
}
|
||||||
|
for b.Loop() {
|
||||||
|
Encode(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func FuzzMessageDecoding(f *testing.F) {
|
||||||
|
f.Add([]byte{0xd1, 0x01, 0x5a, 0x00, 0x00, 0x2d, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x7f, 0xff, 0x40, 0x7f, 0xff, 0x80, 0x7f, 0xff,
|
||||||
|
0xc0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00, 0x00, 50,
|
||||||
|
})
|
||||||
|
f.Fuzz(func(t *testing.T, data []byte) {
|
||||||
|
if len(data) != 29 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var dataArray [29]byte
|
||||||
|
copy(dataArray[:], data)
|
||||||
|
Decode(dataArray)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user