github.com/jshiv/can-go@v0.2.1-0.20210224011015-069e90e90bdf/pkg/descriptor/signal.go (about) 1 package descriptor 2 3 import ( 4 "math" 5 6 "go.einride.tech/can" 7 ) 8 9 // Signal describes a CAN signal. 10 type Signal struct { 11 // Description of the signal. 12 Name string 13 // Start bit. 14 Start uint16 15 // Length in bits. 16 Length uint16 17 // IsBigEndian is true if the signal is big-endian. 18 IsBigEndian bool 19 // IsSigned is true if the signal uses raw signed values. 20 IsSigned bool 21 // IsMultiplexer is true if the signal is the multiplexor of a multiplexed message. 22 IsMultiplexer bool 23 // IsMultiplexed is true if the signal is multiplexed. 24 IsMultiplexed bool 25 // MultiplexerValue is the value of the multiplexer when this signal is present. 26 MultiplexerValue uint 27 // Offset for real-world transform. 28 Offset float64 29 // Scale for real-world transform. 30 Scale float64 31 // Min real-world value. 32 Min float64 33 // Max real-world value. 34 Max float64 35 // Unit of the signal. 36 Unit string 37 // Description of the signal. 38 Description string 39 // ValueDescriptions of the signal. 40 ValueDescriptions []*ValueDescription 41 // ReceiverNodes is the list of names of the nodes receiving the signal. 42 ReceiverNodes []string 43 // DefaultValue of the signal. 44 DefaultValue int 45 } 46 47 // ValueDescription returns the value description for the provided value. 48 func (s *Signal) ValueDescription(value int) (string, bool) { 49 for _, vd := range s.ValueDescriptions { 50 if vd.Value == value { 51 return vd.Description, true 52 } 53 } 54 return "", false 55 } 56 57 // ToPhysical converts a raw signal value to its physical value. 58 func (s *Signal) ToPhysical(value float64) float64 { 59 result := value 60 result *= s.Scale 61 result += s.Offset 62 if s.Min != 0 || s.Max != 0 { 63 result = math.Max(math.Min(result, s.Max), s.Min) 64 } 65 return result 66 } 67 68 // FromPhysical converts a physical signal value to its raw value. 69 func (s *Signal) FromPhysical(physical float64) float64 { 70 result := physical 71 if s.Min != 0 || s.Max != 0 { 72 result = math.Max(math.Min(result, s.Max), s.Min) 73 } 74 result -= s.Offset 75 result /= s.Scale 76 // perform saturated cast 77 if s.IsSigned { 78 result = math.Max(float64(s.MinSigned()), math.Min(float64(s.MaxSigned()), result)) 79 } else { 80 result = math.Max(0, math.Min(float64(s.MaxUnsigned()), result)) 81 } 82 return result 83 } 84 85 // UnmarshalPhysical returns the physical value of the signal in the provided CAN frame. 86 func (s *Signal) UnmarshalPhysical(d can.Data) float64 { 87 switch { 88 case s.Length == 1: 89 if d.Bit(s.Start) { 90 return 1 91 } 92 return 0 93 case s.IsSigned: 94 var value int64 95 if s.IsBigEndian { 96 value = d.SignedBitsBigEndian(s.Start, s.Length) 97 } else { 98 value = d.SignedBitsLittleEndian(s.Start, s.Length) 99 } 100 return s.ToPhysical(float64(value)) 101 default: 102 var value uint64 103 if s.IsBigEndian { 104 value = d.UnsignedBitsBigEndian(s.Start, s.Length) 105 } else { 106 value = d.UnsignedBitsLittleEndian(s.Start, s.Length) 107 } 108 return s.ToPhysical(float64(value)) 109 } 110 } 111 112 // UnmarshalUnsigned returns the unsigned value of the signal in the provided CAN frame. 113 func (s *Signal) UnmarshalUnsigned(d can.Data) uint64 { 114 if s.IsBigEndian { 115 return d.UnsignedBitsBigEndian(s.Start, s.Length) 116 } 117 return d.UnsignedBitsLittleEndian(s.Start, s.Length) 118 } 119 120 // UnmarshalValueDescription returns the value description of the signal in the provided CAN data. 121 func (s *Signal) UnmarshalValueDescription(d can.Data) (string, bool) { 122 if len(s.ValueDescriptions) == 0 { 123 return "", false 124 } 125 var intValue int 126 if s.IsSigned { 127 intValue = int(s.UnmarshalSigned(d)) 128 } else { 129 intValue = int(s.UnmarshalUnsigned(d)) 130 } 131 return s.ValueDescription(intValue) 132 } 133 134 // UnmarshalSigned returns the signed value of the signal in the provided CAN frame. 135 func (s *Signal) UnmarshalSigned(d can.Data) int64 { 136 if s.IsBigEndian { 137 return d.SignedBitsBigEndian(s.Start, s.Length) 138 } 139 return d.SignedBitsLittleEndian(s.Start, s.Length) 140 } 141 142 // UnmarshalBool returns the bool value of the signal in the provided CAN frame. 143 func (s *Signal) UnmarshalBool(d can.Data) bool { 144 return d.Bit(s.Start) 145 } 146 147 // MarshalUnsigned sets the unsigned value of the signal in the provided CAN frame. 148 func (s *Signal) MarshalUnsigned(d *can.Data, value uint64) { 149 if s.IsBigEndian { 150 d.SetUnsignedBitsBigEndian(s.Start, s.Length, value) 151 } else { 152 d.SetUnsignedBitsLittleEndian(s.Start, s.Length, value) 153 } 154 } 155 156 // MarshalSigned sets the signed value of the signal in the provided CAN frame. 157 func (s *Signal) MarshalSigned(d *can.Data, value int64) { 158 if s.IsBigEndian { 159 d.SetSignedBitsBigEndian(s.Start, s.Length, value) 160 } else { 161 d.SetSignedBitsLittleEndian(s.Start, s.Length, value) 162 } 163 } 164 165 // MarshalBool sets the bool value of the signal in the provided CAN frame. 166 func (s *Signal) MarshalBool(d *can.Data, value bool) { 167 d.SetBit(s.Start, value) 168 } 169 170 // MaxUnsigned returns the maximum unsigned value representable by the signal. 171 func (s *Signal) MaxUnsigned() uint64 { 172 return (2 << (s.Length - 1)) - 1 173 } 174 175 // MinSigned returns the minimum signed value representable by the signal. 176 func (s *Signal) MinSigned() int64 { 177 return (2 << (s.Length - 1) / 2) * -1 178 } 179 180 // MaxSigned returns the maximum signed value representable by the signal. 181 func (s *Signal) MaxSigned() int64 { 182 return (2 << (s.Length - 1) / 2) - 1 183 } 184 185 // SaturatedCastSigned performs a saturated cast of an int64 to the value domain of the signal. 186 func (s *Signal) SaturatedCastSigned(value int64) int64 { 187 min := s.MinSigned() 188 max := s.MaxSigned() 189 switch { 190 case value < min: 191 return min 192 case value > max: 193 return max 194 default: 195 return value 196 } 197 } 198 199 // SaturatedCastUnsigned performs a saturated cast of a uint64 to the value domain of the signal. 200 func (s *Signal) SaturatedCastUnsigned(value uint64) uint64 { 201 max := s.MaxUnsigned() 202 if value > max { 203 return max 204 } 205 return value 206 }