Table of Contents
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.
Squish 6.7 and later allows testing the CAN messages send and received by the device running the application. In order to facilitate this, the test setup must include a PC with with supported CAN hardware attached and connected to the same CAN bus as the tested system, and the corresponding driver package installed.
Table 6.1. Supported CAN hardware
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
startCAN
.
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 (Section 6.21.7).
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 is used—this is 20
seconds, unless it has been changed; see
Squish Server Settings dialog (Section 8.3.22).
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.
The device name.
CanBusDeviceInfo.hasFlexibleDataRateA boolean which indicates whether the device supports flexible data rate.
CanBusDeviceInfo.isVirtualA boolean which indicates whether the device is virtual.
The CanBusDevice
class is the core of the Squish CAN
bus support. It represents a connection to a specific CAN device.
This constructor opens a connection to the CAN hardware using specified
driver
and device
.
This static method returns the list of driver names supported on current platform.
This static method enumerates the available devices using the specified
driver
and returns the list of
CanBusDeviceInfo objects.
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.
Returns all the frames accumulates in the input buffer of the CAN device as a list of CanBusFrame objects.
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.
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
CanBusDevice.readFrame
and
CanBusDevice.readAllFrames
methods.
Restores the connection to the device which was previously suspended using the
CanBusDevice.disconnectDevice
method.
The CanBusFrame
object represents a single CAN frame.
The ID of the frame.
CanBusFrame.isValidA boolean which specifies whether the frame is valid.
CanBusFrame.frameTypeThe type of the frame.
CanBusFrame.hexPayloadThe payload of the frame as a hexadecimal string.
CanBusFrame.extendedFrameFormatA boolean which indicates whether the frame uses the extended 29-bit frame ID.
CanBusFrame.bitrateSwitchA boolean which indicates if the frame uses the higher bitrate for transmission on CAN hardware which supports that feature.
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.
This method returns a human readable description of the frame which includes the frame ID and the binary payload.
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.
The CanBusDevice object used to send frames to the bus. This property cannot be modified.
CanBusFrame.intervalThe interval between CAN frame is sent to the bus, in milliseconds. The default interval is 500ms.
CanBusFrame.enabledA 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, frame)
;
These constructors create a new frame repeater for specified device. Optionally, the frame to send out can be specified as well.
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 object,
frames will not be available using the
CanBusDevice.readFrame
and
CanBusDevice.readAllFrames
methods. Once created,
the receiver takes over the task of managing incoming frames.
The CanBusDevice object used to receive frames. This property cannot be modified.
Creates a new CanBusFrameReceiver
instance for the
specified
CanBusDevice.
CanBusFrameReceiver CanBusFrameReceiver
(
driver, device)
;
Creates a new CanBusDevice
object for the specified driver
and
device
name and a new
CanBusFrameReceiver
instance for that device.
Changes the history length for the specified frame ID to the specified value.
Returns the number of frames with the specified ID which are currently accumulated in the receiver.
Retrieves the latest captured frame with the specified ID.
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.
Retrieves all of the past frames accumulated in the receiver.
Clear all the frames with the specified ID accumulated in the receiver.
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
method.
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 startCAN
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 are integral
and floating
.
The default value for this field is integral
.
signed
— a boolean which indicates whether
the integral type is signed. The default value for this field is
false
. This attribute is ignored for field types other than
integral
.
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 is
32
.
For each frame type in the schema Squish will create a
CanBusFrame 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"