{{ define "packet" }} {{- $structName := camelCase .Name true}} {{- /* generate any bitfield structs */ -}} {{range .Data -}} {{ if .Bits -}} {{- $bfname := (printf "%s%s" $structName (camelCase .Name true)) }} type {{$bfname}} struct { {{- range $el := .Bits}} {{camelCase $el.Name true}} bool `json:"{{$el.Name}}"` {{- end}} } func (p *{{$bfname}}) MarshalByte() byte { var b byte {{- range $idx, $el := .Bits}} {{- $bitName := camelCase $el.Name true}} if p.{{$bitName}} { b |= 1 << {{$idx}} } {{- end}} return b } func (p *{{$bfname}}) UnmarshalByte(b byte) { {{- range $idx, $el := .Bits}} {{- $bitName := camelCase $el.Name true }} p.{{$bitName}} = (b & (1 << {{ $idx }})) != 0 {{- end}} } {{end}} {{- end}} // {{$structName}} is {{.Description}} type {{$structName}} struct { {{- range .Data}} {{- if .Units }} // {{.Conversion}} {{.Units}} {{- end }} {{ .ToStructMember $structName }} `json:"{{.Name}}"` {{- end}} {{- if .Repeat }} // Idx is the packet index. The accepted range is 0-{{.Repeat}} Idx uint32 `json:"idx"` {{- end }} } func (p *{{$structName}}) CanId() (can.CanID, error) { c := can.CanID{Extended: {{.Extended}}} {{- if .Repeat }} if p.Idx >= {{.Repeat}} { return c, &UnknownIdError{ {{ printf "0x%X" .Id }} } } c.Id = {{ printf "0x%X" .Id }} + p.Idx {{- else }} c.Id = {{ printf "0x%X" .Id }} {{- end }} return c, nil } func (p *{{$structName}}) Size() uint { return {{.CalcSize}} } func (p *{{$structName}}) MarshalPacket() ([]byte, error) { b := make([]byte, {{ .CalcSize }}) {{.MakeMarshal}} return b, nil } func (p *{{$structName}}) UnmarshalPacket(b []byte) error { {{.MakeUnmarshal}} return nil } func (p *{{$structName}}) String() string { return "{{ .Name }}" } {{ end }} {{- /* begin actual file template */ -}} // generated by gen_skylab.go at {{ Time }} DO NOT EDIT! package skylab import ( "errors" "encoding/binary" "github.com/kschamplin/gotelem/internal/can" "encoding/json" ) type SkylabId uint32 const ( {{- range .Packets }} {{camelCase .Name true}}Id SkylabId = {{.Id | printf "0x%X"}} {{- end}} ) var nameToIdMap = map[string]can.CanID{ } // list of every packet ID. can be used for O(1) checks. var idMap = map[can.CanID]bool{ {{ range $p := .Packets -}} {{ if $p.Repeat }} {{ range $idx := Nx (int $p.Id) $p.Repeat $p.Offset -}} { Id: {{ $idx | printf "0x%X"}}, Extended: {{$p.Extended}} }: true, {{ end }} {{- else }} { Id: {{ $p.Id | printf "0x%X" }}, Extended: {{$p.Extended}} }: true, {{- end}} {{- end}} } // FromCanFrame creates a Packet from a given CAN ID and data payload. // If the CAN ID is unknown, it will return an error. func FromCanFrame(f can.Frame) (Packet, error) { id := f.Id if !idMap[id] { return nil, &UnknownIdError{ id.Id } } switch id { {{- range $p := .Packets }} {{- if $p.Repeat }} case {{ $p | idToString -}}: var res = &{{camelCase $p.Name true}}{} res.UnmarshalPacket(f.Data) res.Idx = id.Id - {{$p.Id | printf "0x%X" }} return res, nil {{- else }} case {{ $p | idToString }}: var res = &{{camelCase $p.Name true}}{} res.UnmarshalPacket(f.Data) return res, nil {{- end}} {{- end}} } panic("This should never happen. CAN ID didn't match but was in ID map") } func FromJson (name string, raw []byte) (Packet, error) { switch name { {{- range $p := .Packets }} case "{{ $p.Name }}": var res = &{{camelCase $p.Name true}}{} err := json.Unmarshal(raw, res) return res, err {{- end }} } return nil, errors.New("unknown packet name") } {{range .Packets -}} {{template "packet" .}} {{- end}} // The json representation that was used to generate this data. // can be used to share the parsing data for i.e dynamic python gui. const SkylabDefinitions = `{{json . | printf "%s" }}`