Skip to content

Commit

Permalink
support enum values in binary, hex and exponential format (#93)
Browse files Browse the repository at this point in the history
  • Loading branch information
aler9 committed Feb 29, 2024
1 parent ab19a1b commit 7db86a1
Show file tree
Hide file tree
Showing 3 changed files with 174 additions and 22 deletions.
83 changes: 65 additions & 18 deletions pkg/conversion/conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"bytes"
"fmt"
"io"
"math"
"net/http"
"net/url"
"os"
Expand Down Expand Up @@ -68,13 +67,13 @@ import (
type {{ .Enum.Name }} = {{ .Enum.DefName }}.{{ .Enum.Name }}
const (
{{- $en := .Enum }}
{{- range .Enum.Values }}
{{- range .Description }}
{{- $en := .Enum }}
{{- range .Enum.Values }}
{{- range .Description }}
// {{ . }}
{{- end }}
{{- end }}
{{ .Name }} {{ $en.Name }} = {{ $en.DefName }}.{{ .Name }}
{{- end }}
{{- end }}
)
{{- else }}
Expand All @@ -90,7 +89,7 @@ import (
{{- range .Enum.Description }}
// {{ . }}
{{- end }}
type {{ .Enum.Name }} uint32
type {{ .Enum.Name }} uint64
const (
{{- $pn := .Enum.Name }}
Expand Down Expand Up @@ -264,8 +263,24 @@ func parseDescription(in string) []string {
return lines
}

func uintPow(base, exp uint64) uint64 {
result := uint64(1)
for {
if exp&1 == 1 {
result *= base
}
exp >>= 1
if exp == 0 {
break
}
base *= base
}

return result
}

type outEnumValue struct {
Value uint32
Value uint64
Name string
Description []string
}
Expand Down Expand Up @@ -357,19 +372,51 @@ func processDefinition(
Bitmask: enum.Bitmask,
}

for _, val := range enum.Values {
tmp, err := strconv.ParseInt(val.Value, 10, 64)
if err != nil {
return nil, err
}
if tmp < 0 || tmp > int64(math.Pow(2, 32)) {
return nil, fmt.Errorf("enum values that overflow an uint32 are not supported")
for _, entry := range enum.Entries {
var v uint64

switch {
case strings.HasPrefix(entry.Value, "0b"):
tmp, err := strconv.ParseUint(entry.Value[2:], 2, 64)
if err != nil {
return nil, err
}
v = tmp

case strings.HasPrefix(entry.Value, "0x"):
tmp, err := strconv.ParseUint(entry.Value[2:], 16, 64)
if err != nil {
return nil, err
}
v = tmp

case strings.Contains(entry.Value, "**"):
parts := strings.SplitN(entry.Value, "**", 2)

x, err := strconv.ParseUint(parts[0], 10, 64)
if err != nil {
return nil, err
}

y, err := strconv.ParseUint(parts[1], 10, 64)
if err != nil {
return nil, err
}

v = uintPow(x, y)

default:
tmp, err := strconv.ParseUint(entry.Value, 10, 64)
if err != nil {
return nil, err
}
v = tmp
}

oute.Values = append(oute.Values, &outEnumValue{
Value: uint32(tmp),
Name: val.Name,
Description: parseDescription(val.Description),
Value: v,
Name: entry.Name,
Description: parseDescription(entry.Description),
})
}

Expand Down
109 changes: 107 additions & 2 deletions pkg/conversion/conversion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ const testDialect = `<?xml version="1.0"?>
<entry value="4" name="E">
<description>E</description>
</entry>
<entry value="1" name="BIT0" />
<entry value="2**4" name="BIT4" />
<entry value="0b000100000000" name="BIT8" />
<entry value="0x10000" name="BIT16" />
<entry value="0b1000000000000000000000000000000000000000000000000000000000000" name="BIT60" />
<entry value="2305843009213693952" name="BIT61" />
<entry value="2**62" name="BIT62" />
<entry value="0x8000000000000000" name="BIT63" />
</enum>
</enums>
<messages>
Expand All @@ -44,9 +52,10 @@ const testDialect = `<?xml version="1.0"?>
</mavlink>
`

var testDialectGo = `//autogenerated:yes
var testMessageGo = `//autogenerated:yes
//nolint:revive,misspell,govet,lll
package testdialect
// Detected anomaly info measured by onboard sensors and actuators.
type MessageAMessage struct {
// a test uint8
Expand All @@ -65,6 +74,98 @@ func (*MessageAMessage) GetID() uint32 {
}
`

var testEnumGo = `//autogenerated:yes
//nolint:revive,misspell,govet,lll,dupl,gocritic
package testdialect
import (
"strconv"
"fmt"
)
// Detected Anomaly Types.
type A_TYPE uint64
const (
// A.
A A_TYPE = 0
// B.
B A_TYPE = 1
// C.
C A_TYPE = 2
// D.
D A_TYPE = 3
// E
E A_TYPE = 4
BIT0 A_TYPE = 1
BIT4 A_TYPE = 16
BIT8 A_TYPE = 256
BIT16 A_TYPE = 65536
BIT60 A_TYPE = 1152921504606846976
BIT61 A_TYPE = 2305843009213693952
BIT62 A_TYPE = 4611686018427387904
BIT63 A_TYPE = 9223372036854775808
)
var labels_A_TYPE = map[A_TYPE]string{
A: "A",
B: "B",
C: "C",
D: "D",
E: "E",
BIT0: "BIT0",
BIT4: "BIT4",
BIT8: "BIT8",
BIT16: "BIT16",
BIT60: "BIT60",
BIT61: "BIT61",
BIT62: "BIT62",
BIT63: "BIT63",
}
var values_A_TYPE = map[string]A_TYPE{
"A": A,
"B": B,
"C": C,
"D": D,
"E": E,
"BIT0": BIT0,
"BIT4": BIT4,
"BIT8": BIT8,
"BIT16": BIT16,
"BIT60": BIT60,
"BIT61": BIT61,
"BIT62": BIT62,
"BIT63": BIT63,
}
// MarshalText implements the encoding.TextMarshaler interface.
func (e A_TYPE) MarshalText() ([]byte, error) {
if name, ok := labels_A_TYPE[e]; ok {
return []byte(name), nil
}
return []byte(strconv.Itoa(int(e))), nil
}
// UnmarshalText implements the encoding.TextUnmarshaler interface.
func (e *A_TYPE) UnmarshalText(text []byte) error {
if value, ok := values_A_TYPE[string(text)]; ok {
*e = value
} else if value, err := strconv.Atoi(string(text)); err == nil {
*e = A_TYPE(value)
} else {
return fmt.Errorf("invalid label '%s'", text)
}
return nil
}
// String implements the fmt.Stringer interface.
func (e A_TYPE) String() string {
val, _ := e.MarshalText()
return string(val)
}
`

func TestConversion(t *testing.T) {
dir, err := os.MkdirTemp("", "gomavlib")
require.NoError(t, err)
Expand All @@ -80,5 +181,9 @@ func TestConversion(t *testing.T) {

buf, err := os.ReadFile("testdialect/message_a_message.go")
require.NoError(t, err)
require.Equal(t, testDialectGo, string(buf))
require.Equal(t, testMessageGo, string(buf))

buf, err = os.ReadFile("testdialect/enum_a_type.go")
require.NoError(t, err)
require.Equal(t, testEnumGo, string(buf))
}
4 changes: 2 additions & 2 deletions pkg/conversion/definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"strconv"
)

type definitionEnumValue struct {
type definitionEnumEntry struct {
Value string `xml:"value,attr"`
Name string `xml:"name,attr"`
Description string `xml:"description"`
Expand All @@ -14,7 +14,7 @@ type definitionEnumValue struct {
type definitionEnum struct {
Name string `xml:"name,attr"`
Description string `xml:"description"`
Values []*definitionEnumValue `xml:"entry"`
Entries []*definitionEnumEntry `xml:"entry"`
Bitmask bool `xml:"bitmask,attr"`
}

Expand Down

0 comments on commit 7db86a1

Please sign in to comment.