github.com/blueinnovationsgroup/can-go@v0.0.0-20230518195432-d0567cda0028/frame_json.go (about)

     1  package can
     2  
     3  import (
     4  	"encoding/hex"
     5  	"encoding/json"
     6  	"fmt"
     7  	"strconv"
     8  )
     9  
    10  type jsonFrame struct {
    11  	ID       uint32  `json:"id"`
    12  	Data     *string `json:"data"`
    13  	Length   *uint8  `json:"length"`
    14  	Extended *bool   `json:"extended"`
    15  	Remote   *bool   `json:"remote"`
    16  }
    17  
    18  // JSON returns the JSON-encoding of f, using hex-encoding for the data.
    19  //
    20  // Examples:
    21  //
    22  //	{"id":32,"data":"0102030405060708"}
    23  //	{"id":32,"extended":true,"remote":true,"length":4}
    24  func (f Frame) JSON() string {
    25  	switch {
    26  	case f.IsRemote && f.IsExtended:
    27  		return `{"id":` + strconv.Itoa(int(f.ID)) +
    28  			`,"extended":true,"remote":true,"length":` +
    29  			strconv.Itoa(int(f.Length)) + `}`
    30  	case f.IsRemote:
    31  		return `{"id":` + strconv.Itoa(int(f.ID)) +
    32  			`,"remote":true,"length":` +
    33  			strconv.Itoa(int(f.Length)) + `}`
    34  	case f.IsExtended && f.Length == 0:
    35  		return `{"id":` + strconv.Itoa(int(f.ID)) + `,"extended":true}`
    36  	case f.IsExtended:
    37  		return `{"id":` + strconv.Itoa(int(f.ID)) +
    38  			`,"data":"` + hex.EncodeToString(f.Data[:f.Length]) + `"` +
    39  			`,"extended":true}`
    40  	case f.Length == 0:
    41  		return `{"id":` + strconv.Itoa(int(f.ID)) + `}`
    42  	default:
    43  		return `{"id":` + strconv.Itoa(int(f.ID)) +
    44  			`,"data":"` + hex.EncodeToString(f.Data[:f.Length]) + `"}`
    45  	}
    46  }
    47  
    48  // MarshalJSON returns the JSON-encoding of f, using hex-encoding for the data.
    49  //
    50  // See JSON for an example of the JSON schema.
    51  func (f Frame) MarshalJSON() ([]byte, error) {
    52  	return []byte(f.JSON()), nil
    53  }
    54  
    55  // UnmarshalJSON sets *f using the provided JSON-encoded values.
    56  //
    57  // See MarshalJSON for an example of the expected JSON schema.
    58  //
    59  // The result should be checked with Validate to guard against invalid JSON data.
    60  func (f *Frame) UnmarshalJSON(jsonData []byte) error {
    61  	jf := jsonFrame{}
    62  	if err := json.Unmarshal(jsonData, &jf); err != nil {
    63  		return err
    64  	}
    65  	if jf.Data != nil {
    66  		data, err := hex.DecodeString(*jf.Data)
    67  		if err != nil {
    68  			return fmt.Errorf("failed to hex-decode CAN data: %v: %w", string(jsonData), err)
    69  		}
    70  		f.Data = Data{}
    71  		copy(f.Data[:], data)
    72  		f.Length = uint8(len(data))
    73  	} else {
    74  		f.Data = Data{}
    75  		f.Length = 0
    76  	}
    77  	f.ID = jf.ID
    78  	if jf.Remote != nil {
    79  		f.IsRemote = *jf.Remote
    80  	} else {
    81  		f.IsRemote = false
    82  	}
    83  	if f.IsRemote {
    84  		if jf.Length == nil {
    85  			return fmt.Errorf("missing length field for remote JSON frame: %v", string(jsonData))
    86  		}
    87  		f.Length = *jf.Length
    88  	}
    89  	if jf.Extended != nil {
    90  		f.IsExtended = *jf.Extended
    91  	} else {
    92  		f.IsExtended = false
    93  	}
    94  	return nil
    95  }