CAN bus support
CAN (Controller Area Network) bus is a standard for communication between microcontrollers and other devices without a central bus controller. It was designed for use in the automotive industry, but it is increasingly adopted in other areas as well.
Overview
Squish 6.7 and later allow testing CAN messages sent and received by a device running an application. To facilitate this, the test setup must include a PC with the supported CAN hardware attached and connected to the same CAN bus as the tested system, and with the corresponding driver package installed.
Diagram of a Squish CAN bus test setup
Device vendor | Driver name | Used with |
---|---|---|
Generic | socketcan | Devices using standard SocketCAN interface. Only available on Linux. |
SYS TEC electronic | systeccan | Devices using SYS TEC CAN interface. Only available on Windows. |
PEAK-System | peakcan | Devices using PEAK CAN interface. |
MHS Elektronik | tinycan | Devices using MHS CAN interface. |
Vector Informatik | vectorcan | Devices using Vector CAN interface. Only available on Windows. |
CAN bus types are available only in the application context created with the ApplicationContext startCAN(options).
ApplicationContext startCAN(options)
ApplicationContext startCAN(options, host)
ApplicationContext startCAN(options, host, port)
ApplicationContext startCAN(options, host, port, timeoutSecs)
Creates, activates and returns a new application context which provides types and utilities related to CAN bus. All access to CAN objects need to be done while that context is active.
The first argument is a dictionary which allows specifying additional options for the new context. Currently the only supported key is schema
. If provided, the associated value should be a valid CAN frame schema.
Optionally, as seconds and third parameters a host
and port
can be specified. If these parameters are used, instead of connecting to the default host and port (as specified in the Squish IDE's settings or on squishrunner's command line), a connection to the squishserver on the specified host and listening to the specified port will be established.
The fourth parameter, timeoutSecs
(an integer number of seconds) can also be specified. This tells Squish how long it should be prepared to wait for the context to initialize before throwing an error. If specified, this value overrides squishrunner's default timeout. If not specified, the squishserver's default of 20 seconds is used, unless it has been changed. See Squish Server Settings dialog.
If you want to specify a timeout, but don't want to change the host or port, you can do so by passing an empty string as the host (which will make Squish use the configured host—localhost
by default), and by passing -1 as the port.
CanBusDeviceInfo class
CanBusDeviceInfo.deviceName
The device deviceName.
CanBusDeviceInfo.hasFlexibleDataRate
A boolean which indicates whether the device supports flexible data rate.
CanBusDeviceInfo.isVirtual
A boolean which indicates whether the device is virtual.
CanBusDevice class
The CanBusDevice
class is the core of the Squish CAN bus support. It represents a connection to a specific CAN device.
CanBusDevice CanBusDevice(driver, device)
This constructor opens a connection to the CAN hardware using specified driver
and device
.
List CanBusDevice.pluginNames()
This static method returns the list of driver names supported on current platform.
List CanBusDevice.availableDevices(driver)
This static method enumerates the available devices using the specified driver
and returns the list of CanBusDeviceInfo class objects.
CanBusFrame CanBusDevice.readFrame(timeout)
This method waits until a new CAN frame is received and returns is a CanBusFrame object. If no frame is received within the specified timeout
, an exception is thrown.
List CanBusDevice.readAllFrames()
Returns all the frames accumulates in the input buffer of the CAN device as a list of CanBusFrame objects.
CanBusDevice.writeFrame(frame)
Schedules the frame
to be sent to the CAN bus. The frame will be sent as soon as possible, but it happen some time after this method returns.
CanBusDevice.disconnectDevice()
Temporarily disconnects from the device. All frames which arrive after this call will not be added to the internal queue and will not be available using the CanBusFrame CanBusDevice.readFrame(timeout) and List CanBusDevice.readAllFrames() methods.
CanBusDevice.connectDevice()
Restores the connection to the device which was previously suspended using the CanBusDevice.disconnectDevice() method.
CanBusFrame class
The CanBusFrame
object represents a single CAN frame.
CanBusFrame.frameId
The ID of the frame.
CanBusFrame.isValid
A boolean which specifies whether the frame is valid.
CanBusFrame.frameType
The type of the frame.
CanBusFrame.hexPayload
The payload of the frame as a hexadecimal string.
CanBusFrame.extendedFrameFormat
A boolean which indicates whether the frame uses the extended 29-bit frame ID.
CanBusFrame.bitrateSwitch
A boolean which indicates if the frame uses the higher bitrate for transmission on CAN hardware which supports that feature.
CanBusFrame CanBusFrame()
This constructor creates a new invalid frame.
CanBusFrame CanBusFrame(frameId)
CanBusFrame CanBusFrame(frameId, payload)
These constructors create a new frame with the specified ID. Optionally, the data payload for the frame can be specified in form of a hexadecimal string.
String CanBusFrame.toString()()
This method returns a human readable description of the frame which includes the frame ID and the binary payload.
CanBusFrameRepeater class
The CanBusFrameRepeater
object sends the specified frame to the CAN bus repeatedly, in configurable intervals. It can be used to simulate CAN devices which send their frames in such a manner.
CanBusFrameRepeater.device
The CanBusDevice class object used to send frames to the bus. This property cannot be modified.
CanBusFrameRepeater.interval
The interval between CAN frame is sent to the bus, in milliseconds. The default interval is 500ms.
CanBusFrameRepeater.enabled
A boolean which indicates whether the repeater should send its frame to the bus. It can be used to temporarily suspend its operation.
CanBusFrameRepeater CanBusFrameRepeater(device)
CanBusFrameRepeater CanBusFrameRepeater(device, frame)
These constructors create a new frame repeater for specified device. Optionally, the frame to send out can be specified as well.
CanBusFrameReceiver class
The CanBusFrameReceiver
object receives incoming CAN frames and keeps a history of received frames. The maximal number of received frames can be configured.
Once a receiver has been created for a CanBusDevice class object, frames will not be available using the CanBusFrame CanBusDevice.readFrame(timeout) and List CanBusDevice.readAllFrames() methods. Once created, the receiver takes over the task of managing incoming frames.
CanBusFrameReceiver.device
The CanBusDevice class object used to receive frames. This property cannot be modified.
CanBusFrameReceiver CanBusFrameReceiver(device)
Creates a new CanBusFrameReceiver
instance for the specified CanBusDevice class.
CanBusFrameReceiver CanBusFrameReceiver(driver, device)
Creates a new CanBusDevice class object for the specified driver
and device
name and a new CanBusFrameReceiver
instance for that device.
CanBusFrameReceiver.setHistorySize(frameId, length)
Changes the history length for the specified frame ID to the specified value.
Integer CanBusFrameReceiver.frameCount(frameId)
Returns the number of frames with the specified ID which are currently accumulated in the receiver.
CanBusFrame CanBusFrameReceiver.latestFrame(frameId)
Retrieves the latest captured frame with the specified ID.
CanBusFrame CanBusFrameReceiver.pastFrame(frameId, index)
Retrieves one of the past frames accumulated in the receiver. The index must lie in the [0, frameCount())
range, with 0
being the latest frame received.
CanBusFrame CanBusFrameReceiver.pastFrames(frameId)
Retrieves all of the past frames accumulated in the receiver.
CanBusFrameReceiver.clearHistory(frameId)
Clear all the frames with the specified ID accumulated in the receiver.
CanBusFrameReceiver.waitForFrame(filter, timeout)
Waits for frame matching the specified filter and returns it. The filter
must be a dictionary with the frameId
field. Additionally, for known frame types the dictionary can contain expected values for the frame fields. If no frame matching the filter arrives until the timeout elapses, an exception is raised.
The timeout
argument is specified in milliseconds. The timeout is optional, the default value is 30 seconds.
In order to avoid concurrency issues, the frames already accumulated in the receiver are considered first. This may lead to a past frame being found by mistake, in order to avoid that the receiver buffer may need to be cleared with the CanBusFrameReceiver.clearHistory(frameId) method.
CAN frame schema
The contents of CAN frame payload is not standardized. Because of that, Squish cannot offer any insight into the contents of the payload buffer beyond its hexadecimal representation. Since it is very inconvenient to access payload members this way, the ApplicationContext startCAN(options) can accept a schema which defines the contents of frame payload based on the frame ID.
The CAN schema is an XML file with a canschema
root element and version="1"
attribute. The frame contents are defined in a frames
element. Each frame type is defined as a frame
element. Each frame
element must have id
and name
attributes, which contain the numeric frame ID and the name for the frame type, respectively. Each frame
should contain a fields
element which defines known fields within the frame. Each field
element defines a single field. The attributes of the field
element can be:
name
— the name of the field. This attribute is mandatory;type
— the type of the field. Currently the supported types areintegral
andfloating
. The default value for this field isintegral
.signed
— a boolean which indicates whether the integral type is signed. The default value for this field isfalse
. This attribute is ignored for field types other thanintegral
.size
— The size of the field in bits. Integral fields can specify any size between 1 and 64. Floating point fields can be either 32 or 64-bit long. The default value for this field is32
.
For each frame type in the schema, Squish will create a CanBusFrame class subclass with the specified name and Frame
suffix. The frame class defines payload fields as frame object properties. Additionally, the static field called frameId
is available on the type for easy access.
The following file demonstrates an example CAN schema:
<canschema version="1"> <frames> <frame id="0x100" name="Thermometer"> <fields> <field name="temperature" type="floating" size="32"/> </fields> </frame> <frame id="0x200" name="AirConditioning"> <fields> <field name="targetTemp" type="integral" size="32"/> <field name="cooler" type="integral" size="1"/> <field name="heater" type="integral" size="1"/> </fields> </frame> </frames> </canschema>
Using the above schema, the fields defined for the frame type can be accessed as follows:
var th = new ThermometerFrame(); th.temperature = 10.1; test.log( th.hexPayload ); // Logs "4121999a" test.log( AirConditioningFrame.frameId ); // Logs "512" var ac = new AirConditioningFrame({targetTemp: 10, cooler: 0, heater: 1}); test.log( ac.targetTemp ); // Logs "10"
th = ThermometerFrame(); th.temperature = 10.1; test.log( th.hexPayload ); # Logs "4121999a" test.log( AirConditioningFrame.frameId ); # Logs "512" ac = AirConditioningFrame({"targetTemp": 10, "cooler": 0, "heater": 1}); test.log( ac.targetTemp ); # Logs "10"
my $th = Squish::ThermometerFrame->new(); $th->temperature = 10.1; test::log( $th->hexPayload ); # Logs "4121999a" test::log( Squish::AirConditioningFrame->frameId ); # Logs "512" my %args = ( targetTemp => 10, cooler => 0, heater => 1); my $ac = Squish::AirConditioningFrame->new(%args); test::log( $ac->targetTemp ); # Logs "10"
th = ThermometerFrame.new(); th.temperature = 10.1; Test.log( th.hexPayload ); # Logs "4121999a" Test.log( AirConditioningFrame.frameId ); # Logs "512" ac = AirConditioningFrame.new(( "targetTemp" => 10, "cooler" => 0, "heater" => 1)); Test.log( ac.targetTemp ); # Logs "10"
set th [ThermometerFrame new] ThermometerFrame set th temperature 10.1 test log [ThermometerFrame get hexPayload $th] # Logs "4121999a" test log [AirConditioningFrame get frameId] # Logs "512" set ac [ AirConditioningFrame new (targetTemp, 10, cooler, 0, heater, 1) ] test log [ AirConditioningFrame get targetTemp $ac ] # Logs "10"
© 2024 The Qt Company Ltd.
Documentation contributions included herein are the copyrights of
their respective owners.
The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation.
Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property
of their respective owners.