* changed signum for offset calculation * added error handling if a non-existent signal is to be removed from a message
116 lines
4.1 KiB
Python
116 lines
4.1 KiB
Python
# -*- coding: UTF-8 -*-
|
|
|
|
'''
|
|
Created on 06.07.2012
|
|
|
|
@author: Christian Sültrop
|
|
'''
|
|
|
|
import array
|
|
import sys
|
|
|
|
class CanMessage(object):
|
|
|
|
'''
|
|
A CAN message.
|
|
A CAN message is represented by an ID, a Length in bytes, a CycleTime in ms, an array of Signals, and Data.
|
|
|
|
When calling the composeData() method, the data from all Signals is copied into the Data array of the message,
|
|
with respect to the signal begin and length definitions from the CanSignal objects in Signals.
|
|
'''
|
|
|
|
|
|
def __init__(self, MessageId, MessageLength, MessageCycleTime, Label):
|
|
'''
|
|
Create a new CanMessage object.
|
|
|
|
@param MessageId: The CAN ID. Valid range 0x00 to 0x7ff.
|
|
@param MessageLength: The message length in bytes.
|
|
@param messageCycleTime: Cycle time in ms.
|
|
'''
|
|
|
|
# Instance variables
|
|
self.Signals = {}
|
|
self.Data = array.array('B')
|
|
|
|
# check message length for validity
|
|
if MessageLength > 8:
|
|
sys.exit('Invalid message MessageLength')
|
|
|
|
# check message ID for validity
|
|
if (MessageId < 0x000) or (MessageId > 0x7ff):
|
|
sys.exit('Invalid MessageId')
|
|
|
|
# assign the parameters
|
|
self.Length = MessageLength
|
|
self.Id = MessageId
|
|
self.CycleTime = MessageCycleTime
|
|
self.Label = Label
|
|
|
|
# create an initial array of message data
|
|
for i in range(0, self.Length):
|
|
self.Data.append(0x00)
|
|
|
|
|
|
def addSignal(self, CanSignal):
|
|
'''
|
|
Add a Signal of type CanSignal to the list of signals.
|
|
|
|
@param CanSignal: The signal to add to the list of signals.
|
|
'''
|
|
|
|
self.Signals.update({CanSignal.Label: CanSignal})
|
|
|
|
def removeSignal(self, CanSignalLabel):
|
|
try:
|
|
self.Signals.pop(CanSignalLabel)
|
|
except:
|
|
pass
|
|
|
|
|
|
def clearSignals(self):
|
|
self.Signals = {}
|
|
|
|
def composeData(self):
|
|
'''
|
|
Takes the CanSignals from the list in self.Signals and copies
|
|
the data that is stored in their Data fields into the Data field
|
|
of the CanMessage object. The position where to copy the data
|
|
is defined in the Begin and Length fields of the CanSignal objects.
|
|
'''
|
|
|
|
for sigKey in self.Signals:
|
|
sig = self.Signals[sigKey]
|
|
srcBegin = 0 # reading the source data (from the Signal definition) always starts at the first bit
|
|
tgtBegin = sig.Begin # where the source data goes is defined in the Begin field of the CanSignal object
|
|
|
|
srcByteNo = (srcBegin/8) # will be 0 if srcBegin == 0
|
|
srcBitNo = (srcBegin%8) # will be 0 if srcBegin == 0
|
|
|
|
tgtByteNo = (tgtBegin/8) # get the byte and bit numbers
|
|
tgtBitNo = (tgtBegin%8) # for the target (the CanMessage object) array
|
|
|
|
for i in range(0, sig.Length):
|
|
# copy the source data bits to the target
|
|
# OR # get srcBitNo from srcByteNo and shift it to tgtBitNo
|
|
if tgtByteNo >= self.Length:
|
|
sys.exit('Signal does not fit into message!')
|
|
|
|
tmp = sig.Data[srcByteNo]
|
|
tmp = tmp >> srcBitNo
|
|
tmp = tmp & 0x01
|
|
if tmp == 1: # the bit shall be set
|
|
self.Data[tgtByteNo] |= (1 << tgtBitNo)
|
|
else: # the bit shall be cleared
|
|
self.Data[tgtByteNo] &= ~(1 << tgtBitNo)
|
|
|
|
# increment the counters
|
|
srcBitNo += 1
|
|
if srcBitNo >= 8: # on bit counter overflow, increment the byte counter and reset the bit counter
|
|
srcBitNo = 0
|
|
srcByteNo += 1
|
|
|
|
tgtBitNo += 1
|
|
if tgtBitNo >= 8:
|
|
tgtBitNo = 0
|
|
tgtByteNo += 1
|