mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-05 23:43:41 +00:00
Suggestions by pato for GPS UBX support (#831)
* apply suggestions by pato * whoopsie on inverted condition
This commit is contained in:
committed by
Ron Evans
parent
1513808425
commit
b390e3225a
+1
-3
@@ -31,19 +31,18 @@ const (
|
||||
|
||||
// Device wraps a connection to a GPS device.
|
||||
type Device struct {
|
||||
buffer []byte
|
||||
bufIdx int
|
||||
sentence strings.Builder
|
||||
uart drivers.UART
|
||||
bus drivers.I2C
|
||||
address uint16
|
||||
buffer [bufferSize]byte
|
||||
}
|
||||
|
||||
// NewUART creates a new UART GPS connection. The UART must already be configured.
|
||||
func NewUART(uart drivers.UART) Device {
|
||||
return Device{
|
||||
uart: uart,
|
||||
buffer: make([]byte, bufferSize),
|
||||
bufIdx: bufferSize,
|
||||
sentence: strings.Builder{},
|
||||
}
|
||||
@@ -60,7 +59,6 @@ func NewI2CWithAddress(bus drivers.I2C, i2cAddress uint16) Device {
|
||||
return Device{
|
||||
bus: bus,
|
||||
address: i2cAddress,
|
||||
buffer: make([]byte, bufferSize),
|
||||
bufIdx: bufferSize,
|
||||
sentence: strings.Builder{},
|
||||
}
|
||||
|
||||
+45
-57
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
// FlightModeCmd is a UBX-CFG-NAV5 command to set the GPS into
|
||||
// flight mode (airborne <1g)
|
||||
var FlightModeCmd = CfgNav5{
|
||||
var flightModeCmd = CfgNav5{
|
||||
Mask: CfgNav5Dyn | CfgNav5MinEl | CfgNav5PosFixMode,
|
||||
DynModel: DynModeAirborne1g, // Airborne with <1g acceleration
|
||||
FixMode: FixModeAuto, // Auto 2D/3D
|
||||
@@ -28,59 +28,56 @@ var FlightModeCmd = CfgNav5{
|
||||
}
|
||||
|
||||
// SetFlightMode sends UBX-CFG-NAV5 command to set GPS into flight mode
|
||||
func SetFlightMode(d Device) (err error) {
|
||||
if _, err = FlightModeCmd.Write(d.buffer[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
err = SendCommand(d, d.buffer[:])
|
||||
return err
|
||||
func (d *Device) SetFlightMode() (err error) {
|
||||
flightModeCmd.Put42Bytes(d.buffer[:])
|
||||
return d.SendCommand(d.buffer[:42])
|
||||
}
|
||||
|
||||
var (
|
||||
// GGA (time, lat/lng, altitude)
|
||||
MessageRateGGACmd = CfgMsg1{
|
||||
messageRateGGACmd = CfgMsg1{
|
||||
MsgClass: 0xF0,
|
||||
MsgID: 0x00,
|
||||
Rate: 1, // Every position fix
|
||||
}
|
||||
// GLL (time, lat/lng)
|
||||
MessageRateGLLCmd = CfgMsg1{
|
||||
messageRateGLLCmd = CfgMsg1{
|
||||
MsgClass: 0xF0,
|
||||
MsgID: 0x01,
|
||||
Rate: 0, // Disabled
|
||||
}
|
||||
// GSA (satellite id list)
|
||||
MessageRateGSACmd = CfgMsg1{
|
||||
messageRateGSACmd = CfgMsg1{
|
||||
MsgClass: 0xF0,
|
||||
MsgID: 0x02,
|
||||
Rate: 1, // Every position fix
|
||||
}
|
||||
// GSV (satellite locations)
|
||||
MessageRateGSVCmd = CfgMsg1{
|
||||
messageRateGSVCmd = CfgMsg1{
|
||||
MsgClass: 0xF0,
|
||||
MsgID: 0x03,
|
||||
Rate: 1, // Every position fix
|
||||
}
|
||||
// RMC (time, lat/lng, speed, course)
|
||||
MessageRateRMCCmd = CfgMsg1{
|
||||
messageRateRMCCmd = CfgMsg1{
|
||||
MsgClass: 0xF0,
|
||||
MsgID: 0x04,
|
||||
Rate: 1, // Every position fix
|
||||
}
|
||||
// VTG (speed, course)
|
||||
MessageRateVTGCmd = CfgMsg1{
|
||||
messageRateVTGCmd = CfgMsg1{
|
||||
MsgClass: 0xF0,
|
||||
MsgID: 0x05,
|
||||
Rate: 0, // Disabled
|
||||
}
|
||||
// ZDA (time, timezone)
|
||||
MessageRateZDACmd = CfgMsg1{
|
||||
messageRateZDACmd = CfgMsg1{
|
||||
MsgClass: 0xF0,
|
||||
MsgID: 0x08,
|
||||
Rate: 0, // Disabled
|
||||
}
|
||||
// TXT (text transmission)
|
||||
MessageRateTXTCmd = CfgMsg1{
|
||||
messageRateTXTCmd = CfgMsg1{
|
||||
MsgClass: 0xF0,
|
||||
MsgID: 0x41,
|
||||
Rate: 0, // Disabled
|
||||
@@ -88,63 +85,53 @@ var (
|
||||
)
|
||||
|
||||
// SetMessageRatesMinimal configures the GPS to output a minimal set of NMEA sentences
|
||||
func SetMessageRatesMinimal(d Device) (err error) {
|
||||
func SetMessageRatesMinimal(d *Device) (err error) {
|
||||
commands := []CfgMsg1{
|
||||
MessageRateGSACmd,
|
||||
MessageRateGGACmd,
|
||||
MessageRateGLLCmd,
|
||||
MessageRateGSVCmd,
|
||||
MessageRateRMCCmd,
|
||||
MessageRateVTGCmd,
|
||||
MessageRateZDACmd,
|
||||
MessageRateTXTCmd,
|
||||
messageRateGSACmd,
|
||||
messageRateGGACmd,
|
||||
messageRateGLLCmd,
|
||||
messageRateGSVCmd,
|
||||
messageRateRMCCmd,
|
||||
messageRateVTGCmd,
|
||||
messageRateZDACmd,
|
||||
messageRateTXTCmd,
|
||||
}
|
||||
|
||||
for _, cmd := range commands {
|
||||
if _, err = cmd.Write(d.buffer[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = SendCommand(d, d.buffer[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return setCfg1s(d, commands)
|
||||
}
|
||||
|
||||
// SetMessageRatesAllEnabled configures the GPS to output all NMEA sentences
|
||||
func SetMessageRatesAllEnabled(d Device) (err error) {
|
||||
func SetMessageRatesAllEnabled(d *Device) (err error) {
|
||||
commands := []CfgMsg1{
|
||||
MessageRateGSACmd,
|
||||
MessageRateGGACmd,
|
||||
MessageRateGLLCmd,
|
||||
MessageRateGSVCmd,
|
||||
MessageRateRMCCmd,
|
||||
MessageRateVTGCmd,
|
||||
MessageRateZDACmd,
|
||||
MessageRateTXTCmd,
|
||||
messageRateGSACmd,
|
||||
messageRateGGACmd,
|
||||
messageRateGLLCmd,
|
||||
messageRateGSVCmd,
|
||||
messageRateRMCCmd,
|
||||
messageRateVTGCmd,
|
||||
messageRateZDACmd,
|
||||
messageRateTXTCmd,
|
||||
}
|
||||
return setCfg1s(d, commands)
|
||||
}
|
||||
|
||||
func setCfg1s(d *Device, commands []CfgMsg1) (err error) {
|
||||
var buf [9]byte
|
||||
for _, cmd := range commands {
|
||||
cmd.Rate = 1 // Enable all messages at 1 Hz
|
||||
if _, err = cmd.Write(d.buffer[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = SendCommand(d, d.buffer[:]); err != nil {
|
||||
cmd.Put9Bytes(buf[:9])
|
||||
if err = d.SendCommand(buf[:9]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GNSSDisableCmd is a UBX-CFG-GNSS command to disable all GNSS but GPS
|
||||
// gnssDisableCmd is a UBX-CFG-GNSS command to disable all GNSS but GPS
|
||||
// Needed for MAX8's, not needed for MAX7
|
||||
var GNSSDisableCmd = CfgGnss{
|
||||
var gnssDisableCmd = CfgGnss{
|
||||
MsgVer: 0x00,
|
||||
NumTrkChHw: 0x20, // 32 channels
|
||||
NumTrkChUse: 0x20,
|
||||
ConfigBlocks: []*CfgGnssConfigBlocksType{
|
||||
ConfigBlocks: []CfgGnssConfigBlocksType{
|
||||
{GnssId: 0, ResTrkCh: 8, MaxTrkCh: 16, Flags: CfgGnssEnable | 0x010000}, // GPS enabled
|
||||
{GnssId: 1, ResTrkCh: 1, MaxTrkCh: 3, Flags: 0x010000}, // SBAS disabled
|
||||
{GnssId: 3, ResTrkCh: 8, MaxTrkCh: 16, Flags: 0x010000}, // BeiDou disabled
|
||||
@@ -154,15 +141,16 @@ var GNSSDisableCmd = CfgGnss{
|
||||
}
|
||||
|
||||
// SetGNSSDisable sends UBX-CFG-GNSS command to disable all GNSS but GPS
|
||||
func SetGNSSDisable(d Device) (err error) {
|
||||
if _, err = GNSSDisableCmd.Write(d.buffer[:]); err != nil {
|
||||
func (d *Device) SetGNSSDisable() (err error) {
|
||||
err = gnssDisableCmd.Put(d.buffer[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return SendCommand(d, d.buffer[:])
|
||||
return d.SendCommand(d.buffer[:])
|
||||
}
|
||||
|
||||
// SendCommand sends a UBX command and waits for ACK/NAK response
|
||||
func SendCommand(d Device, command []byte) error {
|
||||
func (d *Device) SendCommand(command []byte) error {
|
||||
// Calculate and append checksum
|
||||
checksummed := appendChecksum(command)
|
||||
d.WriteBytes(checksummed)
|
||||
|
||||
+52
-79
@@ -67,41 +67,41 @@ func TestAppendChecksumPreservesOriginal(t *testing.T) {
|
||||
|
||||
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.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)
|
||||
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.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)
|
||||
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.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 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))
|
||||
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]
|
||||
gpsBlock := gnssDisableCmd.ConfigBlocks[0]
|
||||
if gpsBlock.GnssId != 0 {
|
||||
t.Errorf("expected first block GnssId 0 (GPS), got %d", gpsBlock.GnssId)
|
||||
}
|
||||
@@ -110,8 +110,8 @@ func TestGNSSDisableCmdConfig(t *testing.T) {
|
||||
}
|
||||
|
||||
// Verify other GNSS are disabled
|
||||
for i := 1; i < len(GNSSDisableCmd.ConfigBlocks); i++ {
|
||||
block := GNSSDisableCmd.ConfigBlocks[i]
|
||||
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)
|
||||
}
|
||||
@@ -120,15 +120,7 @@ func TestGNSSDisableCmdConfig(t *testing.T) {
|
||||
|
||||
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)
|
||||
}
|
||||
flightModeCmd.Put42Bytes(buf)
|
||||
|
||||
// Verify sync chars
|
||||
if buf[0] != 0xB5 || buf[1] != 0x62 {
|
||||
@@ -148,16 +140,16 @@ func TestFlightModeCmdWrite(t *testing.T) {
|
||||
|
||||
func TestGNSSDisableCmdWrite(t *testing.T) {
|
||||
buf := make([]byte, 64)
|
||||
n, err := GNSSDisableCmd.Write(buf)
|
||||
|
||||
err := gnssDisableCmd.Put(buf)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
t.Errorf("unexpected error, likely buffer too short for data: %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)
|
||||
const expectedLen = 6 + 4 + 5*8
|
||||
sz := gnssDisableCmd.Size()
|
||||
if sz != expectedLen {
|
||||
t.Errorf("expected %d bytes, got %d", expectedLen, sz)
|
||||
}
|
||||
|
||||
// Verify sync chars
|
||||
@@ -204,14 +196,14 @@ func TestMessageRateCmdConfigs(t *testing.T) {
|
||||
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},
|
||||
{"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 {
|
||||
@@ -237,16 +229,7 @@ func TestCfgMsg1Write(t *testing.T) {
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
cmd.Put9Bytes(buf)
|
||||
// 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])
|
||||
@@ -296,14 +279,14 @@ func TestMinimalMessageRatesConfig(t *testing.T) {
|
||||
}
|
||||
|
||||
commands := []CfgMsg1{
|
||||
MessageRateGGACmd,
|
||||
MessageRateGLLCmd,
|
||||
MessageRateGSACmd,
|
||||
MessageRateGSVCmd,
|
||||
MessageRateRMCCmd,
|
||||
MessageRateVTGCmd,
|
||||
MessageRateZDACmd,
|
||||
MessageRateTXTCmd,
|
||||
messageRateGGACmd,
|
||||
messageRateGLLCmd,
|
||||
messageRateGSACmd,
|
||||
messageRateGSVCmd,
|
||||
messageRateRMCCmd,
|
||||
messageRateVTGCmd,
|
||||
messageRateZDACmd,
|
||||
messageRateTXTCmd,
|
||||
}
|
||||
|
||||
for _, cmd := range commands {
|
||||
@@ -321,28 +304,19 @@ func TestMinimalMessageRatesConfig(t *testing.T) {
|
||||
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,
|
||||
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)
|
||||
}
|
||||
cmd.Put9Bytes(buf)
|
||||
|
||||
// Verify MsgClass in payload
|
||||
if buf[6] != 0xF0 {
|
||||
@@ -363,7 +337,7 @@ func TestAllMessageRatesWriteCorrectBytes(t *testing.T) {
|
||||
|
||||
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
|
||||
cmd := messageRateGLLCmd // This one is disabled by default
|
||||
if cmd.Rate != 0 {
|
||||
t.Errorf("expected GLL default rate 0, got %d", cmd.Rate)
|
||||
}
|
||||
@@ -372,8 +346,7 @@ func TestSetMessageRatesAllEnabledModifiesRate(t *testing.T) {
|
||||
cmd.Rate = 1
|
||||
|
||||
buf := make([]byte, 16)
|
||||
_, _ = cmd.Write(buf)
|
||||
|
||||
cmd.Put9Bytes(buf)
|
||||
if buf[8] != 1 {
|
||||
t.Errorf("expected Rate 1 in buffer, got %d", buf[8])
|
||||
}
|
||||
|
||||
+37
-17
@@ -1,5 +1,7 @@
|
||||
package gps
|
||||
|
||||
import "io"
|
||||
|
||||
// UBX message classes
|
||||
const (
|
||||
ubxClassACK = 0x05
|
||||
@@ -69,6 +71,8 @@ func (CfgNav5) classID() uint16 { return 0x2406 }
|
||||
|
||||
type CfgNav5Mask uint16
|
||||
|
||||
var _ io.WriterTo = CfgNav5{} // compile time guarantee of interface implementation.
|
||||
|
||||
const (
|
||||
CfgNav5Dyn CfgNav5Mask = 0x1 // Apply dynamic model settings
|
||||
CfgNav5MinEl CfgNav5Mask = 0x2 // Apply minimum elevation settings
|
||||
@@ -82,8 +86,23 @@ const (
|
||||
CfgNav5Utc CfgNav5Mask = 0x400 // Apply UTC settings (not supported in protocol versions less than 16).
|
||||
)
|
||||
|
||||
func (cfg CfgNav5) Append(dst []byte) []byte {
|
||||
var buf [42]byte
|
||||
cfg.Put42Bytes(buf[:])
|
||||
dst = append(dst, buf[:]...)
|
||||
return dst
|
||||
}
|
||||
|
||||
func (cfg CfgNav5) WriteTo(w io.Writer) (int64, error) {
|
||||
var buf [42]byte
|
||||
cfg.Put42Bytes(buf[:])
|
||||
n, err := w.Write(buf[:])
|
||||
return int64(n), err
|
||||
}
|
||||
|
||||
// Write CfgNav5 message to buffer
|
||||
func (cfg CfgNav5) Write(buf []byte) (int, error) {
|
||||
func (cfg CfgNav5) Put42Bytes(buf []byte) {
|
||||
_ = buf[41]
|
||||
copy(buf, []byte{0xb5, 0x62, byte(cfg.classID()), byte(cfg.classID() >> 8), 36, 0})
|
||||
|
||||
buf[6] = byte(cfg.Mask)
|
||||
@@ -117,8 +136,6 @@ func (cfg CfgNav5) Write(buf []byte) (int, error) {
|
||||
buf[35] = byte(cfg.StaticHoldMaxDist_m >> 8)
|
||||
buf[36] = cfg.UtcStandard
|
||||
copy(buf[37:42], cfg.Reserved2[:])
|
||||
|
||||
return 42, nil
|
||||
}
|
||||
|
||||
// Message ubx-cfg-msg
|
||||
@@ -134,14 +151,11 @@ type CfgMsg1 struct {
|
||||
|
||||
func (CfgMsg1) classID() uint16 { return 0x0106 }
|
||||
|
||||
func (cfg CfgMsg1) Write(buf []byte) (int, error) {
|
||||
func (cfg CfgMsg1) Put9Bytes(buf []byte) {
|
||||
copy(buf, []byte{0xb5, 0x62, byte(cfg.classID()), byte(cfg.classID() >> 8), 3, 0})
|
||||
|
||||
buf[6] = cfg.MsgClass
|
||||
buf[7] = cfg.MsgID
|
||||
buf[8] = cfg.Rate
|
||||
|
||||
return 9, nil
|
||||
}
|
||||
|
||||
// Message ubx-cfg-gnss
|
||||
@@ -150,11 +164,11 @@ func (cfg CfgMsg1) Write(buf []byte) (int, error) {
|
||||
// Class/Id 0x06 0x3e (4 + N*8 bytes)
|
||||
// Gets or sets the GNSS system channel sharing configuration. If the receiver is sent a valid new configuration, it will respond with a UBX-ACK- ACK message and immediately change to the new configuration. Otherwise the receiver will reject the request, by issuing a UBX-ACK-NAK and continuing operation with the previous configuration. Configuration requirements: It is necessary for at least one major GNSS to be enabled, after applying the new configuration to the current one. It is also required that at least 4 tracking channels are available to each enabled major GNSS, i.e. maxTrkCh must have a minimum value of 4 for each enabled major GNSS. The number of tracking channels in use must not exceed the number of tracking channels available in hardware, and the sum of all reserved tracking channels needs to be less than or equal to the number of tracking channels in use. Notes: To avoid cross-correlation issues, it is recommended that GPS and QZSS are always both enabled or both disabled. Polling this message returns the configuration of all supported GNSS, whether enabled or not; it may also include GNSS unsupported by the particular product, but in such cases the enable flag will always be unset. See section GNSS Configuration for a discussion of the use of this message. See section Satellite Numbering for a description of the GNSS IDs available. Configuration specific to the GNSS system can be done via other messages (e. g. UBX-CFG-SBAS).
|
||||
type CfgGnss struct {
|
||||
MsgVer byte // Message version (0x00 for this version)
|
||||
NumTrkChHw byte // Number of tracking channels available in hardware (read only)
|
||||
NumTrkChUse byte // (Read only in protocol versions greater than 23) Number of tracking channels to use. Must be > 0, <= numTrkChHw. If 0xFF, then number of tracking channels to use will be set to numTrkChHw.
|
||||
NumConfigBlocks byte `len:"ConfigBlocks"` // Number of configuration blocks following
|
||||
ConfigBlocks []*CfgGnssConfigBlocksType // len: NumConfigBlocks
|
||||
MsgVer byte // Message version (0x00 for this version)
|
||||
NumTrkChHw byte // Number of tracking channels available in hardware (read only)
|
||||
NumTrkChUse byte // (Read only in protocol versions greater than 23) Number of tracking channels to use. Must be > 0, <= numTrkChHw. If 0xFF, then number of tracking channels to use will be set to numTrkChHw.
|
||||
NumConfigBlocks byte `len:"ConfigBlocks"` // Number of configuration blocks following
|
||||
ConfigBlocks []CfgGnssConfigBlocksType // len: NumConfigBlocks
|
||||
}
|
||||
|
||||
func (CfgGnss) classID() uint16 { return 0x3e06 }
|
||||
@@ -175,14 +189,16 @@ const (
|
||||
)
|
||||
|
||||
// Write CfgGnss message to buffer
|
||||
func (cfg CfgGnss) Write(buf []byte) (int, error) {
|
||||
func (cfg CfgGnss) Put(buf []byte) error {
|
||||
sz := cfg.Size()
|
||||
if sz > len(buf) {
|
||||
return io.ErrShortBuffer
|
||||
}
|
||||
copy(buf, []byte{0xb5, 0x62, byte(cfg.classID()), byte(cfg.classID() >> 8), 4 + byte(len(cfg.ConfigBlocks))*8, 0})
|
||||
|
||||
buf[6] = cfg.MsgVer
|
||||
buf[7] = cfg.NumTrkChHw
|
||||
buf[8] = cfg.NumTrkChUse
|
||||
buf[9] = byte(len(cfg.ConfigBlocks))
|
||||
|
||||
offset := 10
|
||||
for _, block := range cfg.ConfigBlocks {
|
||||
buf[offset] = block.GnssId
|
||||
@@ -195,6 +211,10 @@ func (cfg CfgGnss) Write(buf []byte) (int, error) {
|
||||
buf[offset+7] = byte(block.Flags >> 24)
|
||||
offset += 8
|
||||
}
|
||||
|
||||
return offset, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// Size returns length of CfgGnss in bytes when sent over the wire.
|
||||
func (cfg CfgGnss) Size() int {
|
||||
return 10 + 8*len(cfg.ConfigBlocks)
|
||||
}
|
||||
|
||||
+10
-20
@@ -35,14 +35,7 @@ func TestCfgNav5Write(t *testing.T) {
|
||||
}
|
||||
|
||||
buf := make([]byte, 64)
|
||||
n, err := cfg.Write(buf)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if n != 42 {
|
||||
t.Errorf("expected 42 bytes written, got %d", n)
|
||||
}
|
||||
cfg.Put42Bytes(buf)
|
||||
|
||||
// Check sync chars
|
||||
if buf[0] != 0xb5 || buf[1] != 0x62 {
|
||||
@@ -113,7 +106,7 @@ func TestCfgGnssWrite(t *testing.T) {
|
||||
MsgVer: 0,
|
||||
NumTrkChHw: 32,
|
||||
NumTrkChUse: 32,
|
||||
ConfigBlocks: []*CfgGnssConfigBlocksType{
|
||||
ConfigBlocks: []CfgGnssConfigBlocksType{
|
||||
{GnssId: 0, ResTrkCh: 8, MaxTrkCh: 16, Flags: CfgGnssEnable | 0x010000},
|
||||
},
|
||||
},
|
||||
@@ -126,7 +119,7 @@ func TestCfgGnssWrite(t *testing.T) {
|
||||
MsgVer: 0,
|
||||
NumTrkChHw: 32,
|
||||
NumTrkChUse: 32,
|
||||
ConfigBlocks: []*CfgGnssConfigBlocksType{
|
||||
ConfigBlocks: []CfgGnssConfigBlocksType{
|
||||
{GnssId: 0, ResTrkCh: 8, MaxTrkCh: 16, Flags: CfgGnssEnable | 0x010000},
|
||||
{GnssId: 6, ResTrkCh: 8, MaxTrkCh: 14, Flags: CfgGnssEnable | 0x010000},
|
||||
},
|
||||
@@ -139,15 +132,10 @@ func TestCfgGnssWrite(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
buf := make([]byte, 64)
|
||||
n, err := tc.cfg.Write(buf)
|
||||
|
||||
err := tc.cfg.Put(buf)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
t.Errorf("unexpected error, data too long?: %v", err)
|
||||
}
|
||||
if n != tc.expectedLen {
|
||||
t.Errorf("expected %d bytes written, got %d", tc.expectedLen, n)
|
||||
}
|
||||
|
||||
// Check sync chars
|
||||
if buf[0] != 0xb5 || buf[1] != 0x62 {
|
||||
t.Errorf("expected sync chars 0xb5 0x62, got 0x%02x 0x%02x", buf[0], buf[1])
|
||||
@@ -171,14 +159,16 @@ func TestCfgGnssWriteBlockContent(t *testing.T) {
|
||||
MsgVer: 0,
|
||||
NumTrkChHw: 32,
|
||||
NumTrkChUse: 32,
|
||||
ConfigBlocks: []*CfgGnssConfigBlocksType{
|
||||
ConfigBlocks: []CfgGnssConfigBlocksType{
|
||||
{GnssId: 0, ResTrkCh: 8, MaxTrkCh: 16, Reserved1: 0, Flags: CfgGnssEnable | 0x010000},
|
||||
},
|
||||
}
|
||||
|
||||
buf := make([]byte, 64)
|
||||
_, _ = cfg.Write(buf)
|
||||
|
||||
err := cfg.Put(buf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Check first block at offset 10
|
||||
if buf[10] != 0 {
|
||||
t.Errorf("expected GnssId 0, got %d", buf[10])
|
||||
|
||||
Reference in New Issue
Block a user