can_messenger is a Ruby gem that provides an interface for communicating over the CAN bus, allowing users to send and receive CAN messages via raw SocketCAN sockets. This gem is designed for developers who need an easy way to interact with CAN-enabled devices on Linux.
- Ruby 4.0.1 or higher.
To install can_messenger, add it to your application's Gemfile:
gem 'can_messenger'Then execute:
bundle installOr install it yourself with:
gem install can_messengerTo create a new instance of CanMessenger and start sending messages:
require 'can_messenger'
messenger = CanMessenger::Messenger.new(interface_name: 'can0')To send a message:
messenger.send_can_message(id: 0x123, data: [0xDE, 0xAD, 0xBE, 0xEF])Note: Under the hood, the gem now writes CAN frames to a raw socket instead of calling
cansend. No external dependencies are required beyond raw-socket permissions.
If you need to send an extended CAN frame (29-bit ID), set extended_id: true. The gem then sets the Extended Frame Format (EFF) bit automatically:
messenger.send_can_message(id: 0x123456, data: [0x01, 0x02, 0x03], extended_id: true)If you need to work with CAN FD frames (up to 64 data bytes), enable the mode per call or when initializing the messenger:
messenger_fd = CanMessenger::Messenger.new(interface_name: 'can0', can_fd: true)
messenger_fd.send_can_message(id: 0x123, data: Array.new(12, 0xFF))
# Or on demand
messenger.send_can_message(id: 0x123, data: Array.new(12, 0xFF), can_fd: true)To listen for incoming messages, set up a listener:
messenger.start_listening do |msg|
puts "Received ID=0x#{msg[:id].to_s(16)}, Extended=#{msg[:extended]}, Data=#{msg[:data]}"
endThe start_listening method supports filtering incoming messages based on CAN ID:
-
Single CAN ID:
messenger.start_listening(filter: 0x123) do |message| puts "Received filtered message: #{message}" end
-
Range of CAN IDs:
messenger.start_listening(filter: 0x100..0x200) do |message| puts "Received filtered message: #{message}" end
-
Array of CAN IDs:
messenger.start_listening(filter: [0x123, 0x456, 0x789]) do |message| puts "Received filtered message: #{message}" end
Parse a DBC file and let the messenger encode and decode messages automatically:
dbc = CanMessenger::DBC.load('example.dbc')
# Encode using signal values
messenger.send_dbc_message(dbc: dbc, message_name: 'Example', signals: { Speed: 100 })
# Decode received frames
messenger.start_listening(dbc: dbc) do |msg|
if msg[:decoded]
puts "#{msg[:decoded][:name]} => #{msg[:decoded][:signals]}"
end
endTo stop listening, use:
messenger.stop_listeningCanMessenger::Messenger delegates low-level CAN bus operations to an adapter. By default it uses the
SocketCAN adapter which communicates with Linux CAN interfaces using raw sockets:
messenger = CanMessenger::Messenger.new(interface_name: "can0")You can provide a custom adapter via the adapter: option:
my_adapter = MyCustomAdapter.new(interface_name: "can0", logger: Logger.new($stdout))
messenger = CanMessenger::Messenger.new(interface_name: "can0", adapter: my_adapter)To build your own adapter, subclass CanMessenger::Adapter::Base and implement the required methods
open_socket, build_can_frame, receive_message, and parse_frame.
Before using can_messenger, please note the following:
-
Environment Requirements:
- SocketCAN must be available on your Linux system.
- Permissions: Working with raw sockets may require elevated privileges or membership in a specific group to open and bind to CAN interfaces without running as root.
-
API Changes (v1.0.0 and later):
-
Keyword Arguments: The Messenger API now requires keyword arguments. For example, when initializing the Messenger:
messenger = CanMessenger::Messenger.new(interface_name: 'can0')
Similarly, methods like
send_can_messageuse named parameters:messenger.send_can_message(id: 0x123, data: [0xDE, 0xAD, 0xBE, 0xEF])
If upgrading from an earlier version, update your code accordingly.
-
Block Requirement for
start_listening:
Thestart_listeningmethod requires a block. If no block is provided, the method logs an error and exits without processing messages:messenger.start_listening do |message| puts "Received: #{message}" end
-
-
Threading & Socket Management:
- Blocking Behavior: The gem uses blocking socket calls and continuously listens for messages. Manage the listener’s lifecycle appropriately, especially in multi-threaded environments. Always call
stop_listeningto gracefully shut down the listener. - Resource Cleanup: The socket is automatically closed when the listening loop terminates. Stop the listener to avoid resource leaks.
- Blocking Behavior: The gem uses blocking socket calls and continuously listens for messages. Manage the listener’s lifecycle appropriately, especially in multi-threaded environments. Always call
-
Logging:
- Default Logger: If no logger is provided, logs go to standard output. Provide a custom logger if you want more control.
-
CAN Frame Format Assumptions:
- By default, the gem uses native endianness for CAN IDs (little-endian on most x86/ARM systems). Changed in v2.0.0: this default was previously
:big. You can override this by passingendianness: :bigorendianness: :little. - The gem expects a standard CAN frame layout (16 bytes total, with the first 4 for the ID, followed by 1 byte for DLC, 3 bytes of padding, and up to 8 bytes of data). CAN FD frames (up to 64 bytes) are supported when enabled.
- By default, the gem uses native endianness for CAN IDs (little-endian on most x86/ARM systems). Changed in v2.0.0: this default was previously
- Send CAN Messages: Send CAN messages (up to 8 data bytes, or 64 bytes with CAN FD enabled).
- Receive CAN Messages: Continuously listen for messages on a CAN interface.
- Filtering: Optional ID filters for incoming messages (single ID, range, or array).
- Logging: Logs errors and events for debugging/troubleshooting.
- DBC Parsing: Parse DBC files to encode messages by name and decode incoming frames.
After checking out the repo, run bin/setup to install dependencies. Then, run rake test:rspec to execute the test suite.
Bug reports and pull requests are welcome on GitHub at https://github.com/fk1018/can_messenger.
The gem is available as open-source under the terms of the MIT License.
Developed by fk1018.