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() {
|
||||
|
||||
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,
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,13 @@ func main() {
|
||||
if err != nil {
|
||||
slog.Error("error reading from UDP", "err", err)
|
||||
} 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 {
|
||||
slog.Error("error decoding", "err", err)
|
||||
}
|
||||
|
||||
@@ -18,40 +18,37 @@ type FreeDPosition struct {
|
||||
Focus int32
|
||||
}
|
||||
|
||||
func Encode(message FreeDPosition) []byte {
|
||||
bytes := []byte{}
|
||||
func Encode(message FreeDPosition) [29]byte {
|
||||
var bytes [29]byte
|
||||
|
||||
bytes = append(bytes, 0xd1)
|
||||
bytes = append(bytes, message.ID)
|
||||
bytes[0] = 0xd1
|
||||
bytes[1] = message.ID
|
||||
|
||||
bytes = append(bytes, rotationToFreeDUnits(message.Pan)...)
|
||||
bytes = append(bytes, rotationToFreeDUnits(message.Tilt)...)
|
||||
bytes = append(bytes, rotationToFreeDUnits(message.Roll)...)
|
||||
copy(bytes[2:5], rotationToFreeDUnits(message.Pan))
|
||||
copy(bytes[5:8], rotationToFreeDUnits(message.Tilt))
|
||||
copy(bytes[8:11], rotationToFreeDUnits(message.Roll))
|
||||
|
||||
bytes = append(bytes, positionToFreeDUnits(message.PosX)...)
|
||||
bytes = append(bytes, positionToFreeDUnits(message.PosY)...)
|
||||
bytes = append(bytes, positionToFreeDUnits(message.PosZ)...)
|
||||
copy(bytes[11:14], positionToFreeDUnits(message.PosX))
|
||||
copy(bytes[14:17], positionToFreeDUnits(message.PosY))
|
||||
copy(bytes[17:20], positionToFreeDUnits(message.PosZ))
|
||||
|
||||
bytes = append(bytes, uint8(math.Trunc(float64(message.Zoom/65536))))
|
||||
bytes = append(bytes, uint8(int64(message.Zoom/256)%256))
|
||||
bytes = append(bytes, uint8(int32(message.Zoom)%256))
|
||||
bytes[20] = uint8(math.Trunc(float64(message.Zoom / 65536)))
|
||||
bytes[21] = uint8(int64(message.Zoom/256) % 256)
|
||||
bytes[22] = uint8(int32(message.Zoom) % 256)
|
||||
|
||||
bytes = append(bytes, uint8(math.Trunc(float64(message.Focus/65536))))
|
||||
bytes = append(bytes, uint8(int64(message.Focus/256)%256))
|
||||
bytes = append(bytes, uint8(int32(message.Focus)%256))
|
||||
bytes[23] = uint8(math.Trunc(float64(message.Focus / 65536)))
|
||||
bytes[24] = uint8(int64(message.Focus/256) % 256)
|
||||
bytes[25] = uint8(int32(message.Focus) % 256)
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
func Decode(bytes []byte) (FreeDPosition, error) {
|
||||
if len(bytes) != 29 {
|
||||
return FreeDPosition{}, errors.New("FreeD packet must be 29 bytes long")
|
||||
}
|
||||
|
||||
func Decode(bytes [29]byte) (FreeDPosition, error) {
|
||||
if bytes[0] != 0xd1 {
|
||||
return FreeDPosition{}, errors.New("only FreeD position messages are currently supported")
|
||||
}
|
||||
|
||||
+45
-5
@@ -9,12 +9,12 @@ import (
|
||||
func TestMessageDecoding(t *testing.T) {
|
||||
testCases := []struct {
|
||||
description string
|
||||
bytes []byte
|
||||
bytes [29]byte
|
||||
expected FreeDPosition
|
||||
}{
|
||||
{
|
||||
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,
|
||||
},
|
||||
expected: FreeDPosition{
|
||||
@@ -48,15 +48,15 @@ func TestMessageDecoding(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMessageEncoding(t *testing.T) {
|
||||
func TestGoodMessageEncoding(t *testing.T) {
|
||||
testCases := []struct {
|
||||
description string
|
||||
expected []byte
|
||||
expected [29]byte
|
||||
message FreeDPosition
|
||||
}{
|
||||
{
|
||||
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,
|
||||
},
|
||||
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