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 }