96 lines
2.4 KiB
Go
96 lines
2.4 KiB
Go
package can
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"fmt"
|
|
"strconv"
|
|
)
|
|
|
|
type jsonFrame struct {
|
|
ID uint32 `json:"id"`
|
|
Data *string `json:"data"`
|
|
Length *uint16 `json:"length"`
|
|
Extended *bool `json:"extended"`
|
|
Remote *bool `json:"remote"`
|
|
}
|
|
|
|
// JSON returns the JSON-encoding of f, using hex-encoding for the data.
|
|
//
|
|
// Examples:
|
|
//
|
|
// {"id":32,"data":"0102030405060708"}
|
|
// {"id":32,"extended":true,"remote":true,"length":4}
|
|
func (f Frame) JSON() string {
|
|
switch {
|
|
case f.IsRemote && f.IsExtended:
|
|
return `{"id":` + strconv.Itoa(int(f.ID)) +
|
|
`,"extended":true,"remote":true,"length":` +
|
|
strconv.Itoa(int(f.Length)) + `}`
|
|
case f.IsRemote:
|
|
return `{"id":` + strconv.Itoa(int(f.ID)) +
|
|
`,"remote":true,"length":` +
|
|
strconv.Itoa(int(f.Length)) + `}`
|
|
case f.IsExtended && f.Length == 0:
|
|
return `{"id":` + strconv.Itoa(int(f.ID)) + `,"extended":true}`
|
|
case f.IsExtended:
|
|
return `{"id":` + strconv.Itoa(int(f.ID)) +
|
|
`,"data":"` + hex.EncodeToString(f.Data[:f.Length]) + `"` +
|
|
`,"extended":true}`
|
|
case f.Length == 0:
|
|
return `{"id":` + strconv.Itoa(int(f.ID)) + `}`
|
|
default:
|
|
return `{"id":` + strconv.Itoa(int(f.ID)) +
|
|
`,"data":"` + hex.EncodeToString(f.Data[:f.Length]) + `"}`
|
|
}
|
|
}
|
|
|
|
// MarshalJSON returns the JSON-encoding of f, using hex-encoding for the data.
|
|
//
|
|
// See JSON for an example of the JSON schema.
|
|
func (f Frame) MarshalJSON() ([]byte, error) {
|
|
return []byte(f.JSON()), nil
|
|
}
|
|
|
|
// UnmarshalJSON sets *f using the provided JSON-encoded values.
|
|
//
|
|
// See MarshalJSON for an example of the expected JSON schema.
|
|
//
|
|
// The result should be checked with Validate to guard against invalid JSON data.
|
|
func (f *Frame) UnmarshalJSON(jsonData []byte) error {
|
|
jf := jsonFrame{}
|
|
if err := json.Unmarshal(jsonData, &jf); err != nil {
|
|
return err
|
|
}
|
|
if jf.Data != nil {
|
|
data, err := hex.DecodeString(*jf.Data)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to hex-decode CAN data: %v: %w", string(jsonData), err)
|
|
}
|
|
f.Data = Data{}
|
|
copy(f.Data[:], data)
|
|
f.Length = uint16(len(data))
|
|
} else {
|
|
f.Data = Data{}
|
|
f.Length = 0
|
|
}
|
|
f.ID = jf.ID
|
|
if jf.Remote != nil {
|
|
f.IsRemote = *jf.Remote
|
|
} else {
|
|
f.IsRemote = false
|
|
}
|
|
if f.IsRemote {
|
|
if jf.Length == nil {
|
|
return fmt.Errorf("missing length field for remote JSON frame: %v", string(jsonData))
|
|
}
|
|
f.Length = *jf.Length
|
|
}
|
|
if jf.Extended != nil {
|
|
f.IsExtended = *jf.Extended
|
|
} else {
|
|
f.IsExtended = false
|
|
}
|
|
return nil
|
|
}
|