mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-13 03:13:41 +00:00
0a41786a77
Signed-off-by: deadprogram <ron@hybridgroup.com>
381 lines
9.4 KiB
Go
381 lines
9.4 KiB
Go
package gps
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
func TestAppendChecksum(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
input []byte
|
|
expected []byte
|
|
}{
|
|
{
|
|
name: "simple message",
|
|
input: []byte{0xB5, 0x62, 0x06, 0x24, 0x00, 0x00},
|
|
expected: []byte{0xB5, 0x62, 0x06, 0x24, 0x00, 0x00, 0x2A, 0x84},
|
|
},
|
|
{
|
|
name: "CFG-NAV5 header only",
|
|
input: []byte{0xB5, 0x62, 0x06, 0x24, 0x24, 0x00},
|
|
expected: []byte{0xB5, 0x62, 0x06, 0x24, 0x24, 0x00, 0x4E, 0xCC},
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
result := appendChecksum(tc.input)
|
|
|
|
if len(result) != len(tc.expected) {
|
|
t.Errorf("expected length %d, got %d", len(tc.expected), len(result))
|
|
return
|
|
}
|
|
|
|
// Check checksum bytes (last two bytes)
|
|
ckA := result[len(result)-2]
|
|
ckB := result[len(result)-1]
|
|
expectedCkA := tc.expected[len(tc.expected)-2]
|
|
expectedCkB := tc.expected[len(tc.expected)-1]
|
|
|
|
if ckA != expectedCkA || ckB != expectedCkB {
|
|
t.Errorf("expected checksum 0x%02X 0x%02X, got 0x%02X 0x%02X",
|
|
expectedCkA, expectedCkB, ckA, ckB)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAppendChecksumPreservesOriginal(t *testing.T) {
|
|
input := []byte{0xB5, 0x62, 0x06, 0x24, 0x00, 0x00}
|
|
original := make([]byte, len(input))
|
|
copy(original, input)
|
|
|
|
result := appendChecksum(input)
|
|
|
|
// Verify original bytes are preserved
|
|
for i := range input {
|
|
if result[i] != original[i] {
|
|
t.Errorf("byte %d changed: expected 0x%02X, got 0x%02X", i, original[i], result[i])
|
|
}
|
|
}
|
|
|
|
// Verify two bytes were appended
|
|
if len(result) != len(input)+2 {
|
|
t.Errorf("expected length %d, got %d", len(input)+2, len(result))
|
|
}
|
|
}
|
|
|
|
func TestFlightModeCmdConfig(t *testing.T) {
|
|
// Verify FlightModeCmd has expected values
|
|
if FlightModeCmd.DynModel != 6 {
|
|
t.Errorf("expected DynModel 6 (airborne <1g), got %d", FlightModeCmd.DynModel)
|
|
}
|
|
|
|
if FlightModeCmd.FixMode != 3 {
|
|
t.Errorf("expected FixMode 3 (auto 2D/3D), got %d", FlightModeCmd.FixMode)
|
|
}
|
|
|
|
expectedMask := CfgNav5Dyn | CfgNav5MinEl | CfgNav5PosFixMode
|
|
if FlightModeCmd.Mask != expectedMask {
|
|
t.Errorf("expected Mask 0x%04X, got 0x%04X", expectedMask, FlightModeCmd.Mask)
|
|
}
|
|
|
|
if FlightModeCmd.MinElev_deg != 5 {
|
|
t.Errorf("expected MinElev_deg 5, got %d", FlightModeCmd.MinElev_deg)
|
|
}
|
|
}
|
|
|
|
func TestGNSSDisableCmdConfig(t *testing.T) {
|
|
// Verify GNSSDisableCmd has expected structure
|
|
if GNSSDisableCmd.MsgVer != 0 {
|
|
t.Errorf("expected MsgVer 0, got %d", GNSSDisableCmd.MsgVer)
|
|
}
|
|
|
|
if GNSSDisableCmd.NumTrkChHw != 0x20 {
|
|
t.Errorf("expected NumTrkChHw 0x20, got 0x%02X", GNSSDisableCmd.NumTrkChHw)
|
|
}
|
|
|
|
if len(GNSSDisableCmd.ConfigBlocks) != 5 {
|
|
t.Errorf("expected 5 config blocks, got %d", len(GNSSDisableCmd.ConfigBlocks))
|
|
return
|
|
}
|
|
|
|
// Verify GPS is enabled
|
|
gpsBlock := GNSSDisableCmd.ConfigBlocks[0]
|
|
if gpsBlock.GnssId != 0 {
|
|
t.Errorf("expected first block GnssId 0 (GPS), got %d", gpsBlock.GnssId)
|
|
}
|
|
if gpsBlock.Flags&CfgGnssEnable == 0 {
|
|
t.Error("expected GPS to be enabled")
|
|
}
|
|
|
|
// Verify other GNSS are disabled
|
|
for i := 1; i < len(GNSSDisableCmd.ConfigBlocks); i++ {
|
|
block := GNSSDisableCmd.ConfigBlocks[i]
|
|
if block.Flags&CfgGnssEnable != 0 {
|
|
t.Errorf("expected block %d (GnssId %d) to be disabled", i, block.GnssId)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFlightModeCmdWrite(t *testing.T) {
|
|
buf := make([]byte, 64)
|
|
n, err := FlightModeCmd.Write(buf)
|
|
|
|
if err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
|
|
if n != 42 {
|
|
t.Errorf("expected 42 bytes, got %d", n)
|
|
}
|
|
|
|
// Verify sync chars
|
|
if buf[0] != 0xB5 || buf[1] != 0x62 {
|
|
t.Errorf("expected sync 0xB5 0x62, got 0x%02X 0x%02X", buf[0], buf[1])
|
|
}
|
|
|
|
// Verify class/id
|
|
if buf[2] != 0x06 || buf[3] != 0x24 {
|
|
t.Errorf("expected class/id 0x06 0x24, got 0x%02X 0x%02X", buf[2], buf[3])
|
|
}
|
|
|
|
// Verify DynModel at offset 8
|
|
if buf[8] != 6 {
|
|
t.Errorf("expected DynModel 6, got %d", buf[8])
|
|
}
|
|
}
|
|
|
|
func TestGNSSDisableCmdWrite(t *testing.T) {
|
|
buf := make([]byte, 64)
|
|
n, err := GNSSDisableCmd.Write(buf)
|
|
|
|
if err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
|
|
// 6 header + 4 payload header + 5*8 blocks = 50 bytes
|
|
expectedLen := 6 + 4 + 5*8
|
|
if n != expectedLen {
|
|
t.Errorf("expected %d bytes, got %d", expectedLen, n)
|
|
}
|
|
|
|
// Verify sync chars
|
|
if buf[0] != 0xB5 || buf[1] != 0x62 {
|
|
t.Errorf("expected sync 0xB5 0x62, got 0x%02X 0x%02X", buf[0], buf[1])
|
|
}
|
|
|
|
// Verify class/id
|
|
if buf[2] != 0x06 || buf[3] != 0x3E {
|
|
t.Errorf("expected class/id 0x06 0x3E, got 0x%02X 0x%02X", buf[2], buf[3])
|
|
}
|
|
|
|
// Verify number of blocks
|
|
if buf[9] != 5 {
|
|
t.Errorf("expected 5 blocks, got %d", buf[9])
|
|
}
|
|
}
|
|
|
|
func TestChecksumCalculation(t *testing.T) {
|
|
// Test with known UBX message and expected checksum
|
|
// This is a minimal CFG-NAV5 poll message
|
|
msg := []byte{0xB5, 0x62, 0x06, 0x24, 0x00, 0x00}
|
|
|
|
result := appendChecksum(msg)
|
|
|
|
// Verify checksum by recalculating
|
|
var ckA, ckB byte
|
|
for i := 2; i < len(msg); i++ {
|
|
ckA += msg[i]
|
|
ckB += ckA
|
|
}
|
|
|
|
if result[6] != ckA || result[7] != ckB {
|
|
t.Errorf("checksum mismatch: expected 0x%02X 0x%02X, got 0x%02X 0x%02X",
|
|
ckA, ckB, result[6], result[7])
|
|
}
|
|
}
|
|
|
|
func TestMessageRateCmdConfigs(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
cmd CfgMsg1
|
|
msgClass byte
|
|
msgID byte
|
|
rate byte
|
|
}{
|
|
{"GGA", MessageRateGGACmd, 0xF0, 0x00, 1},
|
|
{"GLL", MessageRateGLLCmd, 0xF0, 0x01, 0},
|
|
{"GSA", MessageRateGSACmd, 0xF0, 0x02, 1},
|
|
{"GSV", MessageRateGSVCmd, 0xF0, 0x03, 1},
|
|
{"RMC", MessageRateRMCCmd, 0xF0, 0x04, 1},
|
|
{"VTG", MessageRateVTGCmd, 0xF0, 0x05, 0},
|
|
{"ZDA", MessageRateZDACmd, 0xF0, 0x08, 0},
|
|
{"TXT", MessageRateTXTCmd, 0xF0, 0x41, 0},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
if tc.cmd.MsgClass != tc.msgClass {
|
|
t.Errorf("expected MsgClass 0x%02X, got 0x%02X", tc.msgClass, tc.cmd.MsgClass)
|
|
}
|
|
if tc.cmd.MsgID != tc.msgID {
|
|
t.Errorf("expected MsgID 0x%02X, got 0x%02X", tc.msgID, tc.cmd.MsgID)
|
|
}
|
|
if tc.cmd.Rate != tc.rate {
|
|
t.Errorf("expected Rate %d, got %d", tc.rate, tc.cmd.Rate)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCfgMsg1Write(t *testing.T) {
|
|
cmd := CfgMsg1{
|
|
MsgClass: 0xF0,
|
|
MsgID: 0x00,
|
|
Rate: 1,
|
|
}
|
|
|
|
buf := make([]byte, 16)
|
|
n, err := cmd.Write(buf)
|
|
|
|
if err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
|
|
if n != 9 {
|
|
t.Errorf("expected 9 bytes, got %d", n)
|
|
}
|
|
|
|
// Verify sync chars
|
|
if buf[0] != 0xB5 || buf[1] != 0x62 {
|
|
t.Errorf("expected sync 0xB5 0x62, got 0x%02X 0x%02X", buf[0], buf[1])
|
|
}
|
|
|
|
// Verify class/id (0x06 0x01 for CFG-MSG)
|
|
if buf[2] != 0x06 || buf[3] != 0x01 {
|
|
t.Errorf("expected class/id 0x06 0x01, got 0x%02X 0x%02X", buf[2], buf[3])
|
|
}
|
|
|
|
// Verify length (3 bytes payload)
|
|
if buf[4] != 3 || buf[5] != 0 {
|
|
t.Errorf("expected length 3, got %d", uint16(buf[4])|uint16(buf[5])<<8)
|
|
}
|
|
|
|
// Verify payload
|
|
if buf[6] != 0xF0 {
|
|
t.Errorf("expected MsgClass 0xF0, got 0x%02X", buf[6])
|
|
}
|
|
if buf[7] != 0x00 {
|
|
t.Errorf("expected MsgID 0x00, got 0x%02X", buf[7])
|
|
}
|
|
if buf[8] != 1 {
|
|
t.Errorf("expected Rate 1, got %d", buf[8])
|
|
}
|
|
}
|
|
|
|
func TestCfgMsg1ClassID(t *testing.T) {
|
|
cmd := CfgMsg1{}
|
|
if got := cmd.classID(); got != 0x0106 {
|
|
t.Errorf("expected 0x0106, got 0x%04x", got)
|
|
}
|
|
}
|
|
|
|
func TestMinimalMessageRatesConfig(t *testing.T) {
|
|
// Verify the minimal config has correct rates set
|
|
// GGA and RMC should be enabled (rate=1), others disabled (rate=0)
|
|
expectedRates := map[byte]byte{
|
|
0x00: 1, // GGA - enabled
|
|
0x01: 0, // GLL - disabled
|
|
0x02: 1, // GSA - enabled
|
|
0x03: 1, // GSV - enabled
|
|
0x04: 1, // RMC - enabled
|
|
0x05: 0, // VTG - disabled
|
|
0x08: 0, // ZDA - disabled
|
|
0x41: 0, // TXT - disabled
|
|
}
|
|
|
|
commands := []CfgMsg1{
|
|
MessageRateGGACmd,
|
|
MessageRateGLLCmd,
|
|
MessageRateGSACmd,
|
|
MessageRateGSVCmd,
|
|
MessageRateRMCCmd,
|
|
MessageRateVTGCmd,
|
|
MessageRateZDACmd,
|
|
MessageRateTXTCmd,
|
|
}
|
|
|
|
for _, cmd := range commands {
|
|
expectedRate, ok := expectedRates[cmd.MsgID]
|
|
if !ok {
|
|
t.Errorf("unexpected MsgID 0x%02X", cmd.MsgID)
|
|
continue
|
|
}
|
|
if cmd.Rate != expectedRate {
|
|
t.Errorf("MsgID 0x%02X: expected rate %d, got %d", cmd.MsgID, expectedRate, cmd.Rate)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAllMessageRatesWriteCorrectBytes(t *testing.T) {
|
|
// Test that each message rate command writes the correct bytes
|
|
commands := []CfgMsg1{
|
|
MessageRateGGACmd,
|
|
MessageRateGLLCmd,
|
|
MessageRateGSACmd,
|
|
MessageRateGSVCmd,
|
|
MessageRateRMCCmd,
|
|
MessageRateVTGCmd,
|
|
MessageRateZDACmd,
|
|
MessageRateTXTCmd,
|
|
}
|
|
|
|
for _, cmd := range commands {
|
|
buf := make([]byte, 16)
|
|
n, err := cmd.Write(buf)
|
|
|
|
if err != nil {
|
|
t.Errorf("MsgID 0x%02X: unexpected error: %v", cmd.MsgID, err)
|
|
continue
|
|
}
|
|
|
|
if n != 9 {
|
|
t.Errorf("MsgID 0x%02X: expected 9 bytes, got %d", cmd.MsgID, n)
|
|
}
|
|
|
|
// Verify MsgClass in payload
|
|
if buf[6] != 0xF0 {
|
|
t.Errorf("MsgID 0x%02X: expected MsgClass 0xF0, got 0x%02X", cmd.MsgID, buf[6])
|
|
}
|
|
|
|
// Verify MsgID in payload
|
|
if buf[7] != cmd.MsgID {
|
|
t.Errorf("expected MsgID 0x%02X in payload, got 0x%02X", cmd.MsgID, buf[7])
|
|
}
|
|
|
|
// Verify Rate in payload
|
|
if buf[8] != cmd.Rate {
|
|
t.Errorf("MsgID 0x%02X: expected Rate %d, got %d", cmd.MsgID, cmd.Rate, buf[8])
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSetMessageRatesAllEnabledModifiesRate(t *testing.T) {
|
|
// Verify that when we copy a command and set Rate=1, it works correctly
|
|
cmd := MessageRateGLLCmd // This one is disabled by default
|
|
if cmd.Rate != 0 {
|
|
t.Errorf("expected GLL default rate 0, got %d", cmd.Rate)
|
|
}
|
|
|
|
// Simulate what SetMessageRatesAllEnabled does
|
|
cmd.Rate = 1
|
|
|
|
buf := make([]byte, 16)
|
|
_, _ = cmd.Write(buf)
|
|
|
|
if buf[8] != 1 {
|
|
t.Errorf("expected Rate 1 in buffer, got %d", buf[8])
|
|
}
|
|
}
|