View Source Cantastic

Cantastic is an Elixir library to interact with CAN/Bus via lib_socket_can (Linux only). It does all the heavy lifting of parsing the incoming frames and sending the outgoing ones at the right frequencies.

RAW and ISOTP modes are currently supported, BCM (Broadcast Manager) support is planned.

Installation

in the mix.exs file:

def deps do
  [{:cantastic, "~> 1.0.1"}]
end

OTP App Configuration

Example

config :cantastic,
  can_network_mappings: "ovcs:vcan0,leaf_drive:vcan1,polo_drive:vcan2",
  setup_can_interfaces: true,
  otp_app: :vms_core,
  priv_can_config_path: "polo_2007.yml",
  enable_socketcand: true,
  socketcand_ip_interface: "wlan0"

Description

Cantastic supports the following configuration options:

KeyDescriptionDefault value
:can_network_mappingsA comma separated list of can network names and related interfaces.
:setup_can_interfacesWheher Cantastic should setup the CAN interfaces. It requires the Elixir user to have the approriate rights (usually the case for Nerves hosts).false
:otp_appThe name of the OTP app owning the priv directory where the can config file is stored
:priv_can_config_pathThe relative path where the Yaml config file is located
:enable_socketcandWheter Cantastic should start the socketcand server on all configured interfaces. This allows to remotely access the CAN interfaces for debugging.false
:socketcand_ip_interfaceThe IP interface on which socketcand should listen to."eth0"

YAML configuration file

Cantastic requires you to define a YAML file describing the frames to be sent and received and how to interpret them. This allows you to declaratively define your CAN networks in a clear and maintainable format.

Example

---
can_networks:
  ovcs:
    bitrate: 500000
    emitted_frames:
      - name: contactors_status_request
        id: 0x100
        frequency: 20
        signals:
          - name: main_negative_contactor_enabled
            kind: enum
            value_start: 0
            value_length: 8
            mapping:
              0x00: false
              0x01: true
          - name: main_positive_contactor_enabled
            kind: enum
            value_start: 8
            value_length: 8
            mapping:
              0x00: false
              0x01: true
    received_frames:
      - name: car_controls_status
        id: 0x200
        frequency: 10
        signals:
          - name: raw_max_throttle
            kind: integer
            value_start: 0
            value_length: 16
          - name: raw_throttle
            kind: integer
            value_start: 16
            value_length: 16
          - name: requested_gear
            kind: enum
            value_start: 48
            value_length: 8
            mapping:
              0x00: drive
              0x01: neutral
              0x02: reverse
              0x03: parking

Detailed YAML file structure:

Top level property

KeyDescriptionRequiredDefault value
:can_networksa map of can networks to connect to in the form network_name: {...network definitions...}True

Network properties

KeyDescriptionRequiredDefault value
:bitrateThe CAN network speed in bits per seconds.True
:emitted_framesAn array of frame definitions.False[]
:received_framesAn array of frame definitions.False[]
:obd2_requestsAn array of OBD2 request definitions.False[]
Example
#  my_vehicle.yml
---
can_networks:
  my_network:
    bitrate: 500000
    emitted_frames:
      - name: frame1
      - .....
    received_frames:
      - name: frame2
        ....
    obd2_requests:
      - name: request1
      - ....

Frame definitions

KeyDescriptionRequiredDefault value
:idThe CAN Frame IDTrue
:nameThe CAN Frame name, will be used in your own code to reference itTrue
:frequencyThe frequency is milliseconds at which the frame should be emitted/is expected to be receivedTrue for emitted frames, False for received frames
:allowed_frequency_leewayThe tolerance in milliseconds to be added to the frequency by the Cantastic.ReceivedFrameWatcher when monitoring the frame frequencyFalse10
:allowed_missing_framesThe number of missed frames before Cantastic.ReceivedFrameWatcher should send handle_missing_frame messages to subscribersFalse5
:allowed_missing_frames_periodTimeframe in milliseconds during which Cantastic.ReceivedFrameWatcher is counting the number of missing framesFalse5_000
:required_on_time_framesThe number of frames received at the expected frequency to consider a frame back to 'normal'false5
:signalsAn array of signals to be interpreted in this frameFalse[]
Example
---
can_networks:
  my_network:
    bitrate: 500000
    received_frames:
      - name: frame1
        id: 0x100
        frequency: 20
        signals:
          - name: signal1
            ....
          - name: signal1
            ....

Signal definitions

KeyDescriptionRequiredDefault value
:nameThe signal name, will be used in your own code to reference itTrue
:value_startThe bit number where the raw signal startsTrue
:value_lengthThe number of bits to use for this signalTrue
:kindThe type of value to be returned, one of: "decimal", "integer", "static", "enum"False"decimal"
:precisionThe precision to which a decimal signal should be rounded toFalse2
:signWheter the signal should be interpreted as a signed or unsigned integerFalse"unsigned"
:endiannessThe endianness to be used to interpret the signalFalse"little"
:mappingFor "enum" values, a map for each integer valueFalse{}
:unitAn informational unit related to the signal's valueFalse
:scaleA decimal scale to be applied on the raw value, defined as a string in YAMLFalse"1"
:offsetA decimal offset to be applied on the raw value, defined as a string in YAMLFalse"0"
:valueFor "static" values, the integer raw representation to be usedFalse
Example
---
can_networks:
  my_network:
    bitrate: 500000
    received_frames:
      - name: frame1
        id: 0x100
        frequency: 20
        signals:
          - name: decimal_signal
            value_start: 0
            value_length: 8
            kind: decimal
            precision: 3
            sign: signed
            endianness: big
            scale: "0.3444"
            offset: "30"
          - name: boolean_signal
            value_start: 8
            value_length: 1
            kind: mapping
            mapping:
              0x00: false
              0x01: true
          - name: static_signal
            value_start: 9
            value_length: 8
            kind: static
            value: 0xAB

OBD2 request definitions

KeyDescriptionRequiredDefault value
:nameThe OBD2 Request name, will be used in your own code to reference itTrue
:request_frame_idThe CAN Frame ID to be used for the OBD2 requestTrue
:response_frame_idThe CAN Frame ID of the frame used for the responseTrue
:frequencyThe frequency is milliseconds at which the request should be emittedTrue
:modeThe OBD2 mode to be usedTrue
:parametersAn array of parameters to be interpreted in this requestFalse[]
Example
---
can_networks:
  my_network:
    bitrate: 500000
    obd2_requests:
      - name: obd2_request1
        request_frame_id: 0x7DF
        response_frame_id: 0x7E8
        frequency: 20
        mode: 0x01
        parameters:
          - name: parameter1
            ....

OBD2 parameters definitions

KeyDescriptionRequiredDefault value
:nameThe parameter name, will be used in your own code to reference itTrue
:kindThe type of value to be returned, one of: "decimal", "integer"False"decimal"
:precisionThe precision to which a decimal parameter should be rounded toFalse2
:signWheter the parameter should be interpreted as a signed or unsigned integerFalse"unsigned"
:value_lengthThe number of bits to use for this parameterTrue
:endiannessThe endianness to be used to interpret the parameterFalse"little"
:unitAn informational unit related to the parameter's valueFalse
:scaleA decimal scale to be applied on the raw value, defined as a string in YAMLFalse"1"
:offsetA decimal offset to be applied on the raw value, defined as a string in YAMLFalse"0"
Example
---
can_networks:
  my_network:
    bitrate: 500000
    obd2_requests:
      - name: obd2_request1
        request_frame_id: 0x7DF
        response_frame_id: 0x7E8
        frequency: 20
        mode: 0x01
        parameters:
          - name: speed
            id: 0x0D
            value_length: 8
          - name: rotation_per_minute
            id: 0x0C
            value_length: 16
            scale: "0.25"

Utilities

In order to keep your YAML file maintainable, Cantastic allows you to split it in multiple files and to import them using the following syntax:

import!:ovcs_mini/generic_controller/0x701_main_controller_alive.yml

Example:
#  my_vehicle.yml
---
can_networks:
  ovcs:
    bitrate: 500000
    emitted_frames:
      - import!:./frames/frame1.yml
      - ...
    received_frames:
      - import!:./frames/frame2.yml
      - ...
    obd2_requests:
      - import!:./obd2_requests/frame2.yml
      - ....
#  frames/frame1.yml
TODO

Real world example

Cantastic is used in the Open Vehicle Control System, you will find concrete usage example in this repository

More concretely: