github.com/jshiv/can-go@v0.2.1-0.20210224011015-069e90e90bdf/pkg/canjson/encode.go (about)

     1  package canjson
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"strconv"
     7  
     8  	"go.einride.tech/can"
     9  	"go.einride.tech/can/pkg/descriptor"
    10  	"go.einride.tech/can/pkg/generated"
    11  )
    12  
    13  // preAllocatedBytesPerSignal is an estimate of how many bytes each signal needs.
    14  const preAllocatedBytesPerSignal = 40
    15  
    16  // Marshal a CAN message to JSON.
    17  func Marshal(m generated.Message) ([]byte, error) {
    18  	f := m.Frame()
    19  	bytes := make([]byte, 0, len(m.Descriptor().Signals)*preAllocatedBytesPerSignal)
    20  	bytes = append(bytes, '{')
    21  	for i, s := range m.Descriptor().Signals {
    22  		s := s
    23  		bytes = append(bytes, '"')
    24  		bytes = append(bytes, s.Name...)
    25  		bytes = append(bytes, `":`...)
    26  		sig := &signal{}
    27  		sig.set(s, f)
    28  		jsonSig, err := json.Marshal(sig)
    29  		if err != nil {
    30  			return nil, fmt.Errorf("marshal json: %w", err)
    31  		}
    32  		bytes = append(bytes, jsonSig...)
    33  		if i < len(m.Descriptor().Signals)-1 {
    34  			bytes = append(bytes, ',')
    35  		}
    36  	}
    37  	bytes = append(bytes, '}')
    38  	return bytes, nil
    39  }
    40  
    41  type signal struct {
    42  	Raw         json.Number
    43  	Physical    json.Number
    44  	Unit        string `json:",omitempty"`
    45  	Description string `json:",omitempty"`
    46  }
    47  
    48  func (s *signal) set(desc *descriptor.Signal, f can.Frame) {
    49  	switch {
    50  	case desc.Length == 1: // bool
    51  		s.setBoolValue(desc.UnmarshalBool(f.Data), desc)
    52  	case desc.IsSigned: // signed
    53  		s.setSignedValue(desc.UnmarshalSigned(f.Data), desc)
    54  	default: // unsigned
    55  		s.setUnsignedValue(desc.UnmarshalUnsigned(f.Data), desc)
    56  	}
    57  }
    58  
    59  func (s *signal) setUnsignedValue(value uint64, desc *descriptor.Signal) {
    60  	s.Raw = uintToJSON(value)
    61  	s.Physical = floatToJSON(desc.ToPhysical(float64(value)))
    62  	s.Unit = desc.Unit
    63  	if value, ok := desc.ValueDescription(int(value)); ok {
    64  		s.Description = value
    65  	}
    66  }
    67  
    68  func (s *signal) setSignedValue(value int64, desc *descriptor.Signal) {
    69  	s.Raw = intToJSON(value)
    70  	s.Physical = floatToJSON(desc.ToPhysical(float64(value)))
    71  	s.Unit = desc.Unit
    72  	if value, ok := desc.ValueDescription(int(value)); ok {
    73  		s.Description = value
    74  	}
    75  }
    76  
    77  func (s *signal) setBoolValue(value bool, desc *descriptor.Signal) {
    78  	if value {
    79  		s.Raw = "1"
    80  		s.Physical = floatToJSON(desc.ToPhysical(1))
    81  	} else {
    82  		s.Raw = "0"
    83  		s.Physical = floatToJSON(desc.ToPhysical(0))
    84  	}
    85  	s.Unit = desc.Unit
    86  	intValue := 0
    87  	if value {
    88  		intValue = 1
    89  	}
    90  	if value, ok := desc.ValueDescription(intValue); ok {
    91  		s.Description = value
    92  	}
    93  }
    94  
    95  func floatToJSON(f float64) json.Number {
    96  	return json.Number(strconv.FormatFloat(f, 'f', -1, 64))
    97  }
    98  
    99  func intToJSON(i int64) json.Number {
   100  	return json.Number(strconv.Itoa(int(i)))
   101  }
   102  
   103  func uintToJSON(i uint64) json.Number {
   104  	return json.Number(strconv.Itoa(int(i)))
   105  }