CANLibrary/CANLibrary/CanMessage.py
Christian Sültrop c35e26f025 Bugfixes
* changed signum for offset calculation
* added error handling if a non-existent signal is to be removed from a message
2012-07-26 11:07:00 +02:00

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