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  }