From 7db86a1c70609e7e209135bddc00caa0a79d1f61 Mon Sep 17 00:00:00 2001
From: aler9 <46489434+aler9@users.noreply.github.com>
Date: Thu, 29 Feb 2024 23:10:41 +0100
Subject: [PATCH] support enum values in binary, hex and exponential format
(#93)
---
pkg/conversion/conversion.go | 83 ++++++++++++++++++-----
pkg/conversion/conversion_test.go | 109 +++++++++++++++++++++++++++++-
pkg/conversion/definition.go | 4 +-
3 files changed, 174 insertions(+), 22 deletions(-)
diff --git a/pkg/conversion/conversion.go b/pkg/conversion/conversion.go
index 896a519e1..77005d661 100644
--- a/pkg/conversion/conversion.go
+++ b/pkg/conversion/conversion.go
@@ -5,7 +5,6 @@ import (
"bytes"
"fmt"
"io"
- "math"
"net/http"
"net/url"
"os"
@@ -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 }}
@@ -90,7 +89,7 @@ import (
{{- range .Enum.Description }}
// {{ . }}
{{- end }}
-type {{ .Enum.Name }} uint32
+type {{ .Enum.Name }} uint64
const (
{{- $pn := .Enum.Name }}
@@ -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
}
@@ -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),
})
}
diff --git a/pkg/conversion/conversion_test.go b/pkg/conversion/conversion_test.go
index 1e62b39c6..5f02eaf1f 100644
--- a/pkg/conversion/conversion_test.go
+++ b/pkg/conversion/conversion_test.go
@@ -29,6 +29,14 @@ const testDialect = `
E
+
+
+
+
+
+
+
+
@@ -44,9 +52,10 @@ const testDialect = `
`
-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
@@ -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)
@@ -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))
}
diff --git a/pkg/conversion/definition.go b/pkg/conversion/definition.go
index 75750881d..4395cc700 100644
--- a/pkg/conversion/definition.go
+++ b/pkg/conversion/definition.go
@@ -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"`
@@ -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"`
}