Skip to content

Commit

Permalink
types: add multipurpose-io-mode
Browse files Browse the repository at this point in the history
  • Loading branch information
johnlettman committed Jul 16, 2024
1 parent e3b9eec commit 9ec7ed6
Show file tree
Hide file tree
Showing 2 changed files with 240 additions and 0 deletions.
129 changes: 129 additions & 0 deletions types/multipurpose-io-mode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package types

import (
"github.com/johnlettman/oyster/util"
)

// MultipurposeIOMode controls the functionality of the multipurpose I/O port on the
// Ouster sensor, particularly with respect to the SYNC_PULSE_OUT signal. Its
// configuration parameters include:
//
// - MultipurposeOff:
// No SYNC_PULSE_OUT signal is output.
// - MultipurposeInputNMEAUART:
// The port is reconfigured as an input.
// - MultipurposeOutputFromInternalOscillator:
// SYNC_PULSE_OUT synchronized with the internal clock.
// - MultipurposeOutputFromSyncPulseIn:
// SYNC_PULSE_OUT synchronized with provided SYNC_PULSE_IN.
// - MultipurposeOutputFromPTP1588:
// SYNC_PULSE_OUT synchronized with an external PTP IEEE 1588 master.
// - MultipurposeOutputFromEncoderAngle:
// SYNC_PULSE_OUT at a user-defined rate in an integer number of degrees.
//
// Note:
//
// - When the mode is MultipurposeOutputFromInternalOscillator, MultipurposeOutputFromSyncPulseIn,
// or MultipurposeOutputFromPTP1588, ConfigurationParameters.SyncPulseOutFrequency can define the output rate
// (defaults to 1 Hz).
// - When the sensor is in MultipurposeOutputFromEncoderAngle mode, ConfigurationParameters.SyncPulseOutAngle
// defines the output pulse rate.
// - In all modes, ConfigurationParameters.SyncPulseOutPulseWidth defines the output pulse width.
//
// For additional information, refer to [Ouster docs: multipurpose_io_mode] and
// [Ouster docs: External Trigger Clock Source]
//
// [Ouster docs: External Trigger Clock Source]: https://static.ouster.dev/sensor-docs/image_route1/image_route3/time_sync/time-sync.html#external-trigger-clock-source
// [Ouster docs: multipurpose_io_mode]: https://static.ouster.dev/sensor-docs/image_route1/image_route2/common_sections/API/sensor_configuration_description.html#multipurpose-io-mode
type MultipurposeIOMode uint8

const (
MultipurposeOff MultipurposeIOMode = iota // Do not output a SYNC_PULSE_OUT signal.

// MultipurposeInputNMEAUART reconfigures the MULTIPURPOSE_IO port as an input.
// See [Ouster docs: Setting Ouster Sensors Time Source] for more information.
//
// [Ouster docs: Setting Ouster Sensors Time Source]: https://static.ouster.dev/sensor-docs/image_route1/image_route3/time_sync/time-sync.html#setting-sensor-time
MultipurposeInputNMEAUART

MultipurposeOutputFromInternalOscillator // Output a SYNC_PULSE_OUT signal synchronized with the internal clock.
MultipurposeOutputFromSyncPulseIn // Output a SYNC_PULSE_OUT signal synchronized with a SYNC_PULSE_IN provided to the unit.
MultipurposeOutputFromPTP1588 // Output a SYNC_PULSE_OUT signal synchronized with an external PTP IEEE 1588 master.
MultipurposeOutputFromEncoderAngle // Output a SYNC_PULSE_OUT signal with a user defined rate in an integer number of degrees.
)

// multipurposeIOModeTextKV maps MultipurposeIOMode values to their text representations.
var multipurposeIOModeTextKV = map[MultipurposeIOMode]string{
MultipurposeOff: "OFF",
MultipurposeInputNMEAUART: "INPUT_NMEA_UART",
MultipurposeOutputFromInternalOscillator: "OUTPUT_FROM_INTERNAL_OSC",
MultipurposeOutputFromSyncPulseIn: "OUTPUT_FROM_SYNC_PULSE_IN",
MultipurposeOutputFromPTP1588: "OUTPUT_FROM_PTP_1588",
MultipurposeOutputFromEncoderAngle: "OUTPUT_FROM_ENCODER_ANGLE",
}

// multipurposeIOModeTextKV maps MultipurposeIOMode values to their string representations.
var multipurposeIOModeStringKV = map[MultipurposeIOMode]string{
MultipurposeOff: "off",
MultipurposeInputNMEAUART: "input from NMEA UART",
MultipurposeOutputFromInternalOscillator: "output from Internal Oscillator",
MultipurposeOutputFromSyncPulseIn: "output from Sync Pulse in",
MultipurposeOutputFromPTP1588: "output from PTP 1588",
MultipurposeOutputFromEncoderAngle: "output from encoder angle",
}

// multipurposeIOModeTextKV maps MultipurposeIOMode values to their Go syntax representations.
var multipurposeIOModeGoStringKV = map[MultipurposeIOMode]string{
MultipurposeOff: "MultipurposeOff",
MultipurposeInputNMEAUART: "MultipurposeInputNMEAUART",
MultipurposeOutputFromInternalOscillator: "MultipurposeOutputFromInternalOscillator",
MultipurposeOutputFromSyncPulseIn: "MultipurposeOutputFromSyncPulseIn",
MultipurposeOutputFromPTP1588: "MultipurposeOutputFromPTP1588",
MultipurposeOutputFromEncoderAngle: "MultipurposeOutputFromEncoderAngle",
}

// multipurposeIOModeTextVK maps string representations to MultipurposeIOMode values.
var multipurposeIOModeTextVK = util.ReverseMap(multipurposeIOModeTextKV)

// String returns the string representation of a MultipurposeIOMode value.
func (m MultipurposeIOMode) String() string {
if s, ok := multipurposeIOModeStringKV[m]; ok {
return s
}

return multipurposeIOModeStringKV[MultipurposeOff]
}

// GoString returns the Go syntax representation of a MultipurposeIOMode value.
func (m MultipurposeIOMode) GoString() string {
if s, ok := multipurposeIOModeGoStringKV[m]; ok {
return s
}

return multipurposeIOModeGoStringKV[MultipurposeOff]
}

// MarshalText returns the text representation of a MultipurposeIOMode value.
func (m MultipurposeIOMode) MarshalText() ([]byte, error) {
if text, ok := multipurposeIOModeTextKV[m]; ok {
return []byte(text), nil
}

return []byte(multipurposeIOModeTextKV[MultipurposeOff]), nil
}

// UnmarshalText updates the value of the MultipurposeIOMode receiver based on the input text.
// - If the input text matches a valid mapping in the multipurposeIOModeTextVK map,
// the receiver is updated to the corresponding MultipurposeIOMode value.
// - If the input text does not match any valid mapping, the receiver is set to MultipurposeOff.
//
// This method does not return an error.
func (m *MultipurposeIOMode) UnmarshalText(text []byte) error {
if mode, ok := multipurposeIOModeTextVK[string(text)]; ok {
*m = mode
} else {
*m = MultipurposeOff
}

return nil
}
111 changes: 111 additions & 0 deletions types/multipurpose-io-mode_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package types

import (
"github.com/brianvoe/gofakeit/v7"
"github.com/stretchr/testify/assert"
"math"
"testing"
)

func TestMultipurposeIOMode_String(t *testing.T) {
type TestCase struct {
name string
mode MultipurposeIOMode
want string
}

cases := []TestCase{
{"MultipurposeOff", MultipurposeOff, "off"},
{"MultipurposeInputNMEAUART", MultipurposeInputNMEAUART, "input from NMEA UART"},
{"MultipurposeOutputFromInternalOscillator", MultipurposeOutputFromInternalOscillator, "output from Internal Oscillator"},
{"MultipurposeOutputFromSyncPulseIn", MultipurposeOutputFromSyncPulseIn, "output from Sync Pulse in"},
{"MultipurposeOutputFromPTP1588", MultipurposeOutputFromPTP1588, "output from PTP 1588"},
{"MultipurposeOutputFromEncoderAngle", MultipurposeOutputFromEncoderAngle, "output from encoder angle"},
{"unknown value", math.MaxUint8, "off"},
}

for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
got := c.mode.String()
assert.Equal(t, c.want, got, "it should return the correct representation")
})
}
}

func TestMultipurposeIOMode_GoString(t *testing.T) {
type TestCase struct {
name string
mode MultipurposeIOMode
want string
}

cases := []TestCase{
{"MultipurposeOff", MultipurposeOff, "MultipurposeOff"},
{"MultipurposeInputNMEAUART", MultipurposeInputNMEAUART, "MultipurposeInputNMEAUART"},
{"MultipurposeOutputFromInternalOscillator", MultipurposeOutputFromInternalOscillator, "MultipurposeOutputFromInternalOscillator"},
{"MultipurposeOutputFromSyncPulseIn", MultipurposeOutputFromSyncPulseIn, "MultipurposeOutputFromSyncPulseIn"},
{"MultipurposeOutputFromPTP1588", MultipurposeOutputFromPTP1588, "MultipurposeOutputFromPTP1588"},
{"MultipurposeOutputFromEncoderAngle", MultipurposeOutputFromEncoderAngle, "MultipurposeOutputFromEncoderAngle"},
{"unknown value", math.MaxUint8, "MultipurposeOff"},
}

for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
got := c.mode.GoString()
assert.Equal(t, c.want, got, "it should return the correct representation")
})
}
}

func TestMultipurposeIOMode_MarshalText(t *testing.T) {
type TestCase struct {
name string
mode MultipurposeIOMode
want string
}

cases := []TestCase{
{"MultipurposeOff", MultipurposeOff, "OFF"},
{"MultipurposeInputNMEAUART", MultipurposeInputNMEAUART, "INPUT_NMEA_UART"},
{"MultipurposeOutputFromInternalOscillator", MultipurposeOutputFromInternalOscillator, "OUTPUT_FROM_INTERNAL_OSC"},
{"MultipurposeOutputFromSyncPulseIn", MultipurposeOutputFromSyncPulseIn, "OUTPUT_FROM_SYNC_PULSE_IN"},
{"MultipurposeOutputFromPTP1588", MultipurposeOutputFromPTP1588, "OUTPUT_FROM_PTP_1588"},
{"MultipurposeOutputFromEncoderAngle", MultipurposeOutputFromEncoderAngle, "OUTPUT_FROM_ENCODER_ANGLE"},
{"unknown value", math.MaxUint8, "OFF"},
}

for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
got, err := c.mode.MarshalText()
assert.NoError(t, err, "it should not error")
assert.Equal(t, []byte(c.want), got, "it should return the correct representation")
})
}
}

func TestMultipurposeIOMode_UnmarshalText(t *testing.T) {
type TestCase struct {
name string
text string
want MultipurposeIOMode
}

cases := []TestCase{
{"MultipurposeOff", "OFF", MultipurposeOff},
{"MultipurposeInputNMEAUART", "INPUT_NMEA_UART", MultipurposeInputNMEAUART},
{"MultipurposeOutputFromInternalOscillator", "OUTPUT_FROM_INTERNAL_OSC", MultipurposeOutputFromInternalOscillator},
{"MultipurposeOutputFromSyncPulseIn", "OUTPUT_FROM_SYNC_PULSE_IN", MultipurposeOutputFromSyncPulseIn},
{"MultipurposeOutputFromPTP1588", "OUTPUT_FROM_PTP_1588", MultipurposeOutputFromPTP1588},
{"MultipurposeOutputFromEncoderAngle", "OUTPUT_FROM_ENCODER_ANGLE", MultipurposeOutputFromEncoderAngle},
{"unknown text", gofakeit.LoremIpsumSentence(4), MultipurposeOff},
}

for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
var m MultipurposeIOMode
err := m.UnmarshalText([]byte(c.text))
assert.NoError(t, err, "it should not error")
assert.Equal(t, c.want, m, "it should return the correct representation")
})
}
}

0 comments on commit 9ec7ed6

Please sign in to comment.