diff --git a/README.rst b/README.rst
index a7943b6..c4649c7 100644
--- a/README.rst
+++ b/README.rst
@@ -16,7 +16,7 @@ Web resources
Features
--------
* Sends and receives CAN frames.
-* Handles parsing of CAN signals from CAN frames.
+* Handles parsing of CAN signals from CAN frames (can optionally match labels).
..
@@ -58,7 +58,7 @@ Known limitations
-----------------
* Not all CAN functionality is implemented. 'Error frames' and 'remote request frames' are not
handled, and CAN multiplex signals are not supported.
-* Not all features of the KCD file format are implemented, for example 'Labels'.
+* Not all features of the KCD file format are implemented, for example 'LabelGroups'.
* It is assumed that each CAN signal name only is available in a single CAN frame ID.
diff --git a/can4python/canbus.py b/can4python/canbus.py
index 739ce38..70e2b74 100644
--- a/can4python/canbus.py
+++ b/can4python/canbus.py
@@ -3,14 +3,14 @@
# Author: Jonas Berg
# Copyright (c) 2015, Semcon Sweden AB
# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without modification, are permitted
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
# provided that the following conditions are met:
# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
# following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
# the following disclaimer in the documentation and/or other materials provided with the distribution.
-# 3. Neither the name of the Semcon Sweden AB nor the names of its contributors may be used to endorse or
+# 3. Neither the name of the Semcon Sweden AB nor the names of its contributors may be used to endorse or
# promote products derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
@@ -23,7 +23,7 @@
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
+#
import logging
@@ -156,7 +156,7 @@ def init_reception(self):
frame_id_list = [x.frame_id for x in self._input_framedefinition_storage]
self.caninterface.set_receive_filters(frame_id_list)
- def recv_next_signals(self):
+ def recv_next_signals(self, match_labels=False):
"""Receive one CAN frame, and unpack it to signal values.
Returns:
@@ -170,7 +170,7 @@ def recv_next_signals(self):
"""
frame = self.caninterface.recv_next_frame()
- return frame.unpack(self._configuration.framedefinitions)
+ return frame.unpack(self._configuration.framedefinitions, match_labels=match_labels)
def recv_next_frame(self):
"""Receive one CAN frame. Returns a :class:`.CanFrame` object.
@@ -195,7 +195,7 @@ def stop_reception(self):
def send_signals(self, *args, **kwargs):
"""Send CAN signals in frames.
-
+
Args:
signals_to_send (dict): The signal values to send_frame. The keys are the signalnames (*str*),
and the items are the values (*numerical* or *None*). If the value is *None* the default value is used.
@@ -209,7 +209,7 @@ def send_signals(self, *args, **kwargs):
Raises:
CanException: When failing to set signal value etc. See :exc:`.CanException`.
-
+
"""
if args:
if isinstance(args[0], dict):
@@ -296,15 +296,15 @@ def stop(self):
def get_descriptive_ascii_art(self):
"""Display an overview of the :class:`.CanBus` object with frame definitions and signal definitions.
-
+
Returns:
A multi-line string.
"""
text = repr(self) + "\n"
text += " " + self._configuration.get_descriptive_ascii_art()
- return text
-
+ return text
+
def write_configuration(self, filename):
"""Write configuration to file.
diff --git a/can4python/canframe.py b/can4python/canframe.py
index 51ef1d7..fb1cad5 100644
--- a/can4python/canframe.py
+++ b/can4python/canframe.py
@@ -3,14 +3,14 @@
# Author: Jonas Berg
# Copyright (c) 2015, Semcon Sweden AB
# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without modification, are permitted
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
# provided that the following conditions are met:
# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
# following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
# the following disclaimer in the documentation and/or other materials provided with the distribution.
-# 3. Neither the name of the Semcon Sweden AB nor the names of its contributors may be used to endorse or
+# 3. Neither the name of the Semcon Sweden AB nor the names of its contributors may be used to endorse or
# promote products derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
@@ -23,7 +23,7 @@
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
+#
import struct
@@ -193,11 +193,11 @@ def get_signalvalue(self, signaldefinition):
def set_signalvalue(self, signaldefinition, physical_value=None):
"""
Set a signal physical_value in the frame.
-
+
Args:
signaldefinition (:class:`.CanSignalDefinition` object): The definition of the signal
physical_value (numerical): The physical_value (numerical) of the signal.
-
+
If the physical_value not is given, the default physical_value for the *signaldefinition* is used.
Raises:
@@ -269,18 +269,24 @@ def set_signalvalue(self, signaldefinition, physical_value=None):
self.frame_data = utilities.int_to_can_bytes(dlc, dataint)
- def unpack(self, frame_definitions):
+ def unpack(self, frame_definitions, match_labels=False):
"""Unpack the CAN frame, and return all signal values.
-
+
Args:
frame_definitions (dict): The keys are frame_id (int) and
the items are :class:`.CanFrameDefinition` objects.
+ match_labels (bool): Whether labels in the :class:`.CanSignalDefinition`
+ should be matched to the signal values.
Raises:
CanException: For wrong DLC. See :exc:`.CanException`.
Returns:
- A dictionary of signal values. The keys are the signalname (str) and the items are the values (numerical).
+ A dictionary of signal values. The keys are the signalname (str) and the items are the values (numerical),
+ or - if match_labels is True and there is at least one label in the signal definion -
+ tuples of (value, label).
+ If there is a label for at least one value, but none for the current value, an empty string will be written
+ as label.
If the frame not is described in the 'frame_definitions', an empty dictionary is returned.
"""
@@ -288,16 +294,22 @@ def unpack(self, frame_definitions):
fr_def = frame_definitions[self.frame_id]
except KeyError:
return {}
-
+
if len(self.frame_data) != fr_def.dlc:
raise exceptions.CanException('The received frame has wrong length: {}, Def: {}'.format(self, fr_def))
-
+
outputdict = {}
for sigdef in fr_def.signaldefinitions:
val = self.get_signalvalue(sigdef)
- outputdict[sigdef.signalname] = val
+ if match_labels and sigdef.labels:
+ try:
+ outputdict[sigdef.signalname] = (val, sigdef.labels[val])
+ except KeyError:
+ outputdict[sigdef.signalname] = (val, "")
+ else:
+ outputdict[sigdef.signalname] = val
return outputdict
-
+
def get_rawframe(self):
"""Returns a 16 bytes long 'bytes' object."""
dlc = len(self.frame_data)
diff --git a/can4python/cansignal.py b/can4python/cansignal.py
index faebc5c..c439847 100644
--- a/can4python/cansignal.py
+++ b/can4python/cansignal.py
@@ -3,14 +3,14 @@
# Author: Jonas Berg
# Copyright (c) 2015, Semcon Sweden AB
# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without modification, are permitted
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
# provided that the following conditions are met:
# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
# following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
# the following disclaimer in the documentation and/or other materials provided with the distribution.
-# 3. Neither the name of the Semcon Sweden AB nor the names of its contributors may be used to endorse or
+# 3. Neither the name of the Semcon Sweden AB nor the names of its contributors may be used to endorse or
# promote products derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
@@ -23,7 +23,7 @@
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
+#
from . import constants
from . import utilities
@@ -32,11 +32,11 @@
SYMBOL_LEAST_SIGNIFICANT_BIT = "L"
SYMBOL_MOST_SIGNIFICANT_BIT = "M"
SYMBOL_OTHER_VALID_BIT = "X"
-
-
+
+
class CanSignalDefinition():
"""A class for describing a CAN signal definition (not the value of the signal).
-
+
Attributes:
signalname (str): Signal name
unit (str): Unit for the value. Defaults to ``''``.
@@ -66,9 +66,9 @@ class CanSignalDefinition():
* In the first byte the least significant bit (rightmost, value 1) is named ``0``,
and the most significant bit (leftmost, value 128) is named ``7``.
* In next byte, the least significant bit is named ``8`` etc.
-
+
This results in this bit numbering for the CAN frame::
-
+
7,6,5,4,3,2,1,0 15,14,13,12,11,10,9,8 23,22,21,20,19,18,17,16 31,30,29,28,27,26,25,24 etc.
Byte0 Byte1 Byte2 Byte3
@@ -100,7 +100,7 @@ class CanSignalDefinition():
"""
def __init__(self, signalname, startbit, numberofbits, scalingfactor=1, valueoffset=0, defaultvalue=None,
unit="", comment="", minvalue=None, maxvalue=None,
- endianness=constants.LITTLE_ENDIAN, signaltype=constants.CAN_SIGNALTYPE_UNSIGNED):
+ endianness=constants.LITTLE_ENDIAN, signaltype=constants.CAN_SIGNALTYPE_UNSIGNED, labels={}):
# Properties #
self.endianness = endianness
@@ -111,6 +111,7 @@ def __init__(self, signalname, startbit, numberofbits, scalingfactor=1, valueoff
self.valueoffset = valueoffset
self.minvalue = minvalue
self.maxvalue = maxvalue
+ self.labels = labels
if defaultvalue is None:
defaultvalue = valueoffset
@@ -286,9 +287,26 @@ def numberofbits(self, value):
value))
self._numberofbits = value
+ @property
+ def labels(self):
+ """
+ *dict* Descriptive names for specific values.
+
+ """
+ return self._labels
+
+ @labels.setter
+ def labels(self, value):
+ try:
+ value = {int(k): v for k,v in value.items()}
+ except (ValueError, TypeError, AttributeError) as _:
+ raise exceptions.CanException("Labels must be assigned as a dictionary with numeric keys. Given: {}".format(value))
+
+ self._labels = value
+
def __repr__(self):
text = "Signal {!r} Startbit {}, bits {} (min DLC {}) {} endian, {}, scalingfactor {:1.2g}, unit: {}\n".format(
- self.signalname, self.startbit, self.numberofbits,
+ self.signalname, self.startbit, self.numberofbits,
self.get_minimum_dlc(), self.endianness, self.signaltype, self.scalingfactor, self.unit)
text += " valoffset {:3.1f} (range {:1.1g} to {:1.1g}) min {}, max {}, default {:3.1f}.\n".format(
self.valueoffset,
@@ -306,27 +324,30 @@ def __repr__(self):
commentstring = "{} ...".format(self.comment[0:MAX_COMMENT_LENGTH].replace('\n', ' ').replace('\r', ''))
text += " {} ".format(commentstring)
return text
-
+
def get_descriptive_ascii_art(self):
"""Create a visual indication how the signal is located in the frame_definition.
-
+
Returns:
A multi-line string.
-
+
"""
tempstring, stopbit = self._get_overview_string()
-
- text = " {!r}\n".format(self)
+
+ text = " {!r}".format(self)
+ if len(self.labels) > 0:
+ text += " Labels: {}\n".format(self.labels)
+ text += "\n"
text += " Startbit normal bit numbering, least significant bit: {}\n".format(self.startbit)
text += " Startbit normal bit numbering, most significant bit: {}\n".format(stopbit)
text += " Startbit backward bit numbering, least significant bit: {}\n\n".format(
utilities.calculate_backward_bitnumber(self.startbit))
text += utilities.generate_bit_byte_overview(tempstring, number_of_indent_spaces=9, show_reverse_bitnumbering=True)
return text
-
+
def get_maximum_possible_value(self):
"""Get the largest value that technically could be sent with this signal.
-
+
The largest integer we can store is ``2**numberofbits - 1``.
Also the :attr:`scalingfactor`, :attr:`valueoffset` and the :attr:`signaltype` affect the result.
diff --git a/can4python/filehandler_kcd.py b/can4python/filehandler_kcd.py
index 4d28c95..fe1915b 100644
--- a/can4python/filehandler_kcd.py
+++ b/can4python/filehandler_kcd.py
@@ -131,6 +131,9 @@ def read(filename, busname=None):
unit = ""
minvalue = maxvalue = None
signaltype = constants.CAN_SIGNALTYPE_UNSIGNED
+
+ labels = {}
+
for val in signal.findall('kayak:Value', constants.KCD_XML_NAMESPACE):
scalingfactor = float(val.get('slope', 1))
valueoffset = float(val.get('intercept', 0))
@@ -150,10 +153,14 @@ def read(filename, busname=None):
if notes.text is not None:
signalcomment += notes.text
+ for labelset in signal.findall('kayak:LabelSet', constants.KCD_XML_NAMESPACE):
+ for label in labelset.findall('kayak:Label', constants.KCD_XML_NAMESPACE):
+ labels[label.get('value')] = label.get('name')
+
s = cansignal.CanSignalDefinition(signalname, startbit, numberofbits, scalingfactor, valueoffset,
unit=unit, comment=signalcomment,
minvalue=minvalue, maxvalue=maxvalue,
- endianness=endianness, signaltype=signaltype)
+ endianness=endianness, signaltype=signaltype, labels=labels)
f.signaldefinitions.append(s)
config.framedefinitions[f.frame_id] = f
@@ -224,6 +231,12 @@ def write(config, filename):
if len(valueattributes):
ElementTree.SubElement(s_subtree, "Value", attrib=valueattributes)
+ if len(s.labels):
+ labelset_subtree = ElementTree.SubElement(s_subtree, "LabelSet")
+ for k, v in s.labels.items():
+ ElementTree.SubElement(labelset_subtree, "Label", attrib={"value": str(k),
+ "name": v})
+
# Producers
if f.producer_ids:
p_subtree = ElementTree.SubElement(m_subtree, "Producer")
diff --git a/tests/test_canbus.py b/tests/test_canbus.py
index 525afb6..b783863 100755
--- a/tests/test_canbus.py
+++ b/tests/test_canbus.py
@@ -384,6 +384,15 @@ def testReceiveRaw(self):
shell=False, stderr=subprocess.STDOUT)
result = self.canbus_raw.recv_next_signals()
self.assertEqual(len(result), 4)
+ self.assertEqual(result['testsignal11'], 0)
+
+ # with label matching
+ time.sleep(0.1)
+ self.simulated_can_process = subprocess.Popen(["cansend", VIRTUAL_CAN_BUS_NAME, canstring],
+ shell=False, stderr=subprocess.STDOUT)
+ result = self.canbus_raw.recv_next_signals(match_labels=True)
+ self.assertEqual(len(result), 4)
+ self.assertEqual(result['testsignal11'], (0, "no"))
def testReceiveBcmAndStop(self):
self.canbus_bcm.init_reception()
diff --git a/tests/test_canframe.py b/tests/test_canframe.py
index 69b1e7c..f2620f0 100755
--- a/tests/test_canframe.py
+++ b/tests/test_canframe.py
@@ -20,11 +20,13 @@
class TestCanFrame(unittest.TestCase):
-
def setUp(self):
self.frame = canframe.CanFrame(1, b'\x00\x02\x00\x08\x00\x00\x00\xff')
self.testsig1 = cansignal.CanSignalDefinition('testsignal1', 56, 1) # Least significant bit in last byte
+ self.testsig1_with_one_label = cansignal.CanSignalDefinition('testsignal1', 56, 1, labels={0: "off"})
+ self.testsig1_with_labels = cansignal.CanSignalDefinition('testsignal1', 56, 1, labels={0: "off", "1": "on"})
+
self.testsig2 = cansignal.CanSignalDefinition('testsignal2', 8, 16, endianness='big') # Two leftmost bytes
self.testsig3 = cansignal.CanSignalDefinition('testsignal3', 24, 16, endianness='little',
maxvalue=1200) # Two center bytes
@@ -46,20 +48,20 @@ def testConstructor(self):
self.assertEqual(frame2.frame_id, 0x1FFFFFFF)
self.assertEqual(frame2.frame_data, b'\x02\x03')
self.assertEqual(frame2.frame_format, 'extended')
-
- def testConstructorNamedArguments(self):
+
+ def testConstructorNamedArguments(self):
frame = canframe.CanFrame(frame_id=3, frame_data=b'\x04', frame_format='extended')
self.assertEqual(frame.frame_id, 3)
self.assertEqual(frame.frame_data, b'\x04')
self.assertEqual(frame.frame_format, 'extended')
-
- def testConstructorFromEmptyBytes(self):
+
+ def testConstructorFromEmptyBytes(self):
frame = canframe.CanFrame.from_empty_bytes(5, 6, 'extended')
self.assertEqual(frame.frame_id, 5)
self.assertEqual(frame.frame_data, b'\x00\x00\x00\x00\x00\x00')
self.assertEqual(frame.frame_format, 'extended')
-
- def testConstructorFromRawframes(self):
+
+ def testConstructorFromRawframes(self):
frame1 = canframe.CanFrame.from_rawframe(b'\x07\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
self.assertEqual(frame1.frame_id, 7)
self.assertEqual(frame1.frame_format, 'standard')
@@ -146,7 +148,7 @@ def testFramedataSetWrongValue(self):
self.assertRaises(exceptions.CanException, setattr, self.frame, 'frame_data', "7")
self.assertRaises(exceptions.CanException, setattr, self.frame, 'frame_data', "\x01")
- def testSignalvalueSet(self):
+ def testSignalvalueSet(self):
self.frame.set_signalvalue(self.testsig1)
self.frame.set_signalvalue(self.testsig1, 0)
self.frame.set_signalvalue(self.testsig1, 1)
@@ -157,7 +159,7 @@ def testSignalvalueSet(self):
self.frame.set_signalvalue(self.testsig3, 1000)
self.frame.set_signalvalue(self.testsig3, 0)
self.assertEqual(self.frame.frame_data, b'\x00\x00\x00\x00\x00\x00\x00\xfe')
-
+
self.frame.set_signalvalue(self.testsig1, 1)
self.frame.set_signalvalue(self.testsig2, 16)
self.frame.set_signalvalue(self.testsig3, 512)
@@ -250,7 +252,6 @@ def testSignalvalueSetTooShortFrame(self):
self.frame.frame_data = b'\00'
self.assertRaises(exceptions.CanException, self.frame.set_signalvalue, self.testsig1)
-
def testSignalvalueGetSetMin(self):
self.testsig3.minvalue = 0
self.frame.set_signalvalue(self.testsig3, 0)
@@ -303,6 +304,32 @@ def testUnpack(self):
self.assertEqual(result['testsignal3'], 8)
self.assertEqual(result['testsignal4'], 0)
+ def testUnpackOneLabel(self):
+ # label only for one possible value
+ frame_def = self.frame_def
+ frame_def.signaldefinitions.remove(self.testsig1)
+ frame_def.signaldefinitions.append(self.testsig1_with_one_label)
+
+ result = self.frame.unpack({self.frame_def.frame_id: frame_def}, match_labels=True)
+ self.assertEqual(len(result), 4)
+ self.assertEqual(result['testsignal1'], (1, ""))
+ self.assertEqual(result['testsignal2'], 2)
+ self.assertEqual(result['testsignal3'], 8)
+ self.assertEqual(result['testsignal4'], 0)
+
+ def testUnpackTwoLabels(self):
+ # labels for all two possible values
+ frame_def = self.frame_def
+ frame_def.signaldefinitions.remove(self.testsig1)
+ frame_def.signaldefinitions.append(self.testsig1_with_labels)
+
+ result = self.frame.unpack({self.frame_def.frame_id: frame_def}, match_labels=True)
+ self.assertEqual(len(result), 4)
+ self.assertEqual(result['testsignal1'], (1, "on"))
+ self.assertEqual(result['testsignal2'], 2)
+ self.assertEqual(result['testsignal3'], 8)
+ self.assertEqual(result['testsignal4'], 0)
+
def testUnpackWrongFrameId(self):
self.frame.frame_id = 2
frame_defs = {self.frame_def.frame_id: self.frame_def}
@@ -326,15 +353,13 @@ def testLen(self):
def testGetDescriptiveAsciiArt(self):
result = self.frame.get_descriptive_ascii_art()
print('\n\n' + result) # Check the output manually
-
+
if __name__ == '__main__':
-
- # Run all tests #
+ # Run all tests #
unittest.main()
-
- # Run a single test #
+
+ # Run a single test #
# suite = unittest.TestSuite()
# suite.addTest(TestCanFrame("testGetDescriptiveAsciiArt"))
# unittest.TextTestRunner(verbosity=2).run(suite)
-
diff --git a/tests/test_caninterface_raw.py b/tests/test_caninterface_raw.py
index a9b6ab5..7f8c823 100755
--- a/tests/test_caninterface_raw.py
+++ b/tests/test_caninterface_raw.py
@@ -39,14 +39,14 @@ def enable_virtual_can_bus():
except subprocess.CalledProcessError:
pass
try:
- subprocess.check_output(["ifconfig", VIRTUAL_CAN_BUS_NAME, "up"])
+ subprocess.check_output(["ip", "link", "set", "up", VIRTUAL_CAN_BUS_NAME])
except subprocess.CalledProcessError:
raise exceptions.CanException("Could not enable {}. Are you sure you are running as sudo?".format(
VIRTUAL_CAN_BUS_NAME))
def disable_virtual_can_bus():
- subprocess.check_output(["ifconfig", VIRTUAL_CAN_BUS_NAME, "down"])
+ subprocess.check_output(["ip", "link", "set", "down", VIRTUAL_CAN_BUS_NAME])
class TestSocketCanRawInterface(unittest.TestCase):
@@ -89,15 +89,15 @@ def testConstructor(self):
self.assertEqual(a.interfacename, VIRTUAL_CAN_BUS_NAME)
a.close()
self.assertEqual(a.interfacename, VIRTUAL_CAN_BUS_NAME)
-
+
b = caninterface_raw.SocketCanRawInterface(VIRTUAL_CAN_BUS_NAME, timeout=1.0)
self.assertEqual(b.interfacename, VIRTUAL_CAN_BUS_NAME)
b.close()
-
+
c = caninterface_raw.SocketCanRawInterface(VIRTUAL_CAN_BUS_NAME, timeout=1.0)
self.assertEqual(c.interfacename, VIRTUAL_CAN_BUS_NAME)
c.close()
-
+
d = caninterface_raw.SocketCanRawInterface(VIRTUAL_CAN_BUS_NAME, timeout=1.0)
self.assertEqual(d.interfacename, VIRTUAL_CAN_BUS_NAME)
d.close()
@@ -113,13 +113,13 @@ def testConstructorWrongType(self):
def testConstructorSeveralInterfaces(self):
a = caninterface_raw.SocketCanRawInterface(VIRTUAL_CAN_BUS_NAME, timeout=1.0)
self.assertEqual(a.interfacename, VIRTUAL_CAN_BUS_NAME)
-
+
b = caninterface_raw.SocketCanRawInterface(VIRTUAL_CAN_BUS_NAME, timeout=1.0)
self.assertEqual(b.interfacename, VIRTUAL_CAN_BUS_NAME)
-
+
c = caninterface_raw.SocketCanRawInterface(VIRTUAL_CAN_BUS_NAME, timeout=1.0)
self.assertEqual(c.interfacename, VIRTUAL_CAN_BUS_NAME)
-
+
a.close()
b.close()
c.close()
@@ -202,11 +202,11 @@ def testTooFewTooManyFiltersDefined(self):
self.interface.set_receive_filters([])
self.interface.set_receive_filters(list(range(200)))
-if __name__ == '__main__':
-
- # Run all tests #
+if __name__ == '__main__':
+
+ # Run all tests #
unittest.main()
-
+
# Run a single test #
# suite = unittest.TestSuite()
# suite.addTest(TestSocketCanInterfaceRaw("testConstructor"))
diff --git a/tests/test_cansignal.py b/tests/test_cansignal.py
index 3b3384b..cd7f52f 100755
--- a/tests/test_cansignal.py
+++ b/tests/test_cansignal.py
@@ -35,7 +35,8 @@ def testConstructor(self):
self.assertEqual(sig.minvalue, None)
self.assertEqual(sig.maxvalue, None)
self.assertEqual(sig.defaultvalue, 0)
-
+ self.assertEqual(sig.labels, {})
+
sig = cansignal.CanSignalDefinition('testsignal2', 7, 1, endianness='big') # Most significant bit in first byte
self.assertEqual(sig.signalname, 'testsignal2')
self.assertEqual(sig.startbit, 7)
@@ -46,9 +47,10 @@ def testConstructor(self):
self.assertEqual(sig.signaltype, 'unsigned')
self.assertEqual(sig.minvalue, None)
self.assertEqual(sig.maxvalue, None)
- self.assertEqual(sig.defaultvalue, 0)
-
- sig = cansignal.CanSignalDefinition('testsignal3', 56, 1, defaultvalue=1) # Least significant bit in last byte
+ self.assertEqual(sig.defaultvalue, 0)
+ self.assertEqual(sig.labels, {})
+
+ sig = cansignal.CanSignalDefinition('testsignal3', 56, 1, defaultvalue=1, labels={0: "on", '1': "off"}) # Least significant bit in last byte
self.assertEqual(sig.signalname, 'testsignal3')
self.assertEqual(sig.startbit, 56)
self.assertEqual(sig.numberofbits, 1)
@@ -59,6 +61,7 @@ def testConstructor(self):
self.assertEqual(sig.minvalue, None)
self.assertEqual(sig.maxvalue, None)
self.assertEqual(sig.defaultvalue, 1)
+ self.assertEqual(sig.labels, {0: "on", 1: "off"})
def testConstructorWrongValues(self):
self.assertRaises(exceptions.CanException, cansignal.CanSignalDefinition, 'testsignal', 63, 1, scalingfactor=-1)
@@ -86,6 +89,11 @@ def testConstructorWrongValues(self):
self.assertRaises(exceptions.CanException, cansignal.CanSignalDefinition,
'testsignal', 56, 1, endianness=None)
+ self.assertRaises(exceptions.CanException, cansignal.CanSignalDefinition,
+ 'testsignal', 56, 1, labels=[])
+ self.assertRaises(exceptions.CanException, cansignal.CanSignalDefinition,
+ 'testsignal', 56, 1, labels={1: "correct", "str": "wrong"})
+
def testProperties(self):
self.assertEqual(self.signal.signalname, 'testsignal')
self.assertEqual(self.signal.startbit, 56)
@@ -96,6 +104,7 @@ def testProperties(self):
self.assertEqual(self.signal.signaltype, constants.CAN_SIGNALTYPE_UNSIGNED)
self.assertEqual(self.signal.maxvalue, None)
self.assertEqual(self.signal.minvalue, None)
+ self.assertEqual(self.signal.labels, {})
self.signal.signalname = 'testsignal2'
self.signal.startbit = 55
@@ -109,6 +118,7 @@ def testProperties(self):
self.signal.signaltype = constants.CAN_SIGNALTYPE_SIGNED
self.signal.unit = 'm/s'
self.signal.comment = "ABC"
+ self.signal.labels = {'3': "somename"}
self.assertEqual(self.signal.signalname, 'testsignal2')
self.assertEqual(self.signal.startbit, 55)
@@ -122,6 +132,7 @@ def testProperties(self):
self.assertEqual(self.signal.signaltype, constants.CAN_SIGNALTYPE_SIGNED)
self.assertEqual(self.signal.unit, 'm/s')
self.assertEqual(self.signal.comment, "ABC")
+ self.assertEqual(self.signal.labels, {3: "somename"})
def testPropertiesWrongValues(self):
self.assertRaises(exceptions.CanException, setattr, self.signal, 'startbit', -1)
@@ -149,6 +160,8 @@ def testPropertiesWrongValues(self):
self.assertRaises(exceptions.CanException, setattr, self.signal, 'scalingfactor', None)
self.assertRaises(exceptions.CanException, setattr, self.signal, 'valueoffset', 'ABC')
self.assertRaises(exceptions.CanException, setattr, self.signal, 'valueoffset', None)
+ self.assertRaises(exceptions.CanException, setattr, self.signal, 'labels', [])
+ self.assertRaises(exceptions.CanException, setattr, self.signal, 'labels', {"str": 3})
sig = cansignal.CanSignalDefinition('testsignal', 56, 1, endianness='big')
sig.signaltype = constants.CAN_SIGNALTYPE_SINGLE
@@ -171,7 +184,7 @@ def testGetDescriptiveAsciiArt(self):
sig = cansignal.CanSignalDefinition('testsignalA', 56, 1)
print(sig.get_descriptive_ascii_art())
- sig = cansignal.CanSignalDefinition('testsignalB', 54, 4)
+ sig = cansignal.CanSignalDefinition('testsignalB', 54, 4, labels={0: "disabled"})
print(sig.get_descriptive_ascii_art())
sig = cansignal.CanSignalDefinition('testsignalC', 54, 2, endianness='big')
diff --git a/tests/test_configuration.py b/tests/test_configuration.py
index 1918ced..e4fa8e3 100755
--- a/tests/test_configuration.py
+++ b/tests/test_configuration.py
@@ -34,7 +34,8 @@
fr_def1.signaldefinitions.append(testsig2)
fr_def1.signaldefinitions.append(testsig3)
fr_def1.signaldefinitions.append(testsig4)
-testsig11 = cansignal.CanSignalDefinition('testsignal11', 56, 1) # Least significant bit in last byte
+testsig11 = cansignal.CanSignalDefinition('testsignal11', 56, 1,
+ labels={0: "no", 1: "yes"}) # Least significant bit in last byte
testsig12 = cansignal.CanSignalDefinition('testsignal12', 8, 16, endianness='big') # Two leftmost bytes
testsig13 = cansignal.CanSignalDefinition('testsignal13', 24, 16, endianness='little') # Two center bytes
testsig14 = cansignal.CanSignalDefinition('testsignal14', 59, 4, endianness='big', signaltype='signed')
@@ -49,10 +50,10 @@
TESTCONFIG1.add_framedefinition(fr_def1)
TESTCONFIG1.add_framedefinition(fr_def2)
TESTCONFIG1.busname = "bus1"
-TESTCONFIG1.ego_node_ids = ["1", "33", "45A", "A",]
+TESTCONFIG1.ego_node_ids = ["1", "33", "45A", "A", ]
-class TestConfiguration(unittest.TestCase):
+class TestConfiguration(unittest.TestCase):
def setUp(self):
self.config = copy.deepcopy(TESTCONFIG1)
@@ -73,7 +74,7 @@ def testConstructor(self):
fr_def = canframe_definition.CanFrameDefinition(1, 'testframedef')
sig1 = cansignal.CanSignalDefinition('testsignal', 56, 1) # Least significant bit in last byte
fr_def.signaldefinitions.append(sig1)
- config = configuration.Configuration({1:fr_def}, "DEF")
+ config = configuration.Configuration({1: fr_def}, "DEF")
self.assertEqual(config.framedefinitions[1], fr_def)
self.assertEqual(config.busname, "DEF")
@@ -136,7 +137,7 @@ def testSetReceiveOnChangeOnlyFromSignalnamesWrongValues(self):
self.config.set_receive_on_change_only_from_signalnames, ["nonexistingsignal"])
self.assertRaises(exceptions.CanException, self.config.set_receive_on_change_only_from_signalnames, "ABC")
self.assertRaises(exceptions.CanException, self.config.set_receive_on_change_only_from_signalnames, 123)
-
+
def testGetDescriptiveAsciiArt(self):
result = self.config.get_descriptive_ascii_art()
print('\n\n' + result) # Check the output manually
@@ -148,5 +149,6 @@ def testAddFramedefinition(self):
self.assertEqual(config.framedefinitions[1], fr_def)
self.assertEqual(config.busname, None)
+
if __name__ == '__main__':
unittest.main()
diff --git a/tests/test_filehandler_kcd.py b/tests/test_filehandler_kcd.py
index a535fde..6e2c04f 100755
--- a/tests/test_filehandler_kcd.py
+++ b/tests/test_filehandler_kcd.py
@@ -165,6 +165,10 @@ def testSaveLoadedConfigurationToFile(self):
filehandler_kcd.FilehandlerKcd.write(config, self.OUTPUT_FILENAME_2)
self.assertTrue(os.path.exists(self.OUTPUT_FILENAME_2))
+ # Read rewritten file
+ config2 = filehandler_kcd.FilehandlerKcd.read(self.OUTPUT_FILENAME_2, None)
+ self.assertEqual(config.get_descriptive_ascii_art(), config2.get_descriptive_ascii_art())
+
# TODO: Check manually that the input and output files are similar
def testWriteKcdFileNoBusnameGiven(self):
diff --git a/tests/testfile_input.kcd b/tests/testfile_input.kcd
index 66dadb0..26b7ff0 100644
--- a/tests/testfile_input.kcd
+++ b/tests/testfile_input.kcd
@@ -26,7 +26,12 @@
-
+
+
+
+
+
+