Class: CanMessenger::Adapter::Socketcan
- Defined in:
- lib/can_messenger/adapter/socketcan.rb
Overview
Adapter implementation for Linux SocketCAN interfaces.
Constant Summary collapse
- CAN_RAW =
rubocop:disable Metrics/ClassLength
1- SOL_CAN_BASE =
100- SOL_CAN_RAW =
SOL_CAN_BASE + CAN_RAW
- CAN_RAW_FD_FRAMES =
5- FRAME_SIZE =
16- CANFD_FRAME_SIZE =
72- MIN_FRAME_SIZE =
8- MAX_FD_DATA =
64- MAX_STANDARD_ID =
0x7FF- SOCKADDR_CAN_ADDR_SIZE =
16- SOCKADDR_CAN_SIZE =
24- SOCKADDR_CAN_PADDING =
2- TIMEOUT =
[1, 0].pack("l_2")
- ZERO_CAN_ADDR =
"\x00" * SOCKADDR_CAN_ADDR_SIZE
Instance Attribute Summary
Attributes inherited from Base
#endianness, #interface_name, #logger
Instance Method Summary collapse
-
#build_can_frame(id:, data:, extended_id: false, can_fd: nil) ⇒ Object
Builds a raw CAN or CAN FD frame for SocketCAN.
-
#open_socket(can_fd: nil) ⇒ Object
Creates and configures a CAN socket bound to the interface.
-
#parse_frame(frame:, can_fd: nil) ⇒ Object
Parses a raw CAN frame string into a hash with id, data and extended flag.
-
#receive_message(socket:, can_fd: nil) ⇒ Object
Reads a frame from the socket and parses it into a hash.
Methods inherited from Base
#initialize, native_endianness
Constructor Details
This class inherits a constructor from CanMessenger::Adapter::Base
Instance Method Details
#build_can_frame(id:, data:, extended_id: false, can_fd: nil) ⇒ Object
Builds a raw CAN or CAN FD frame for SocketCAN.
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/can_messenger/adapter/socketcan.rb', line 38 def build_can_frame(id:, data:, extended_id: false, can_fd: nil) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/PerceivedComplexity if can_fd raise ArgumentError, "CAN FD data cannot exceed #{MAX_FD_DATA} bytes" if data.size > MAX_FD_DATA elsif data.size > 8 raise ArgumentError, "CAN data cannot exceed 8 bytes" end validate_can_id!(id, extended_id: extended_id) can_id = id # Set bit 31 for extended frames can_id |= Constants::EXTENDED_ID_FLAG if extended_id # Pack the ID based on endianness id_bytes = endianness == :big ? [can_id].pack("L>") : [can_id].pack("V") dlc_and_pad = [data.size, 0, 0, 0].pack("C*") payload = if can_fd data.pack("C*").ljust(MAX_FD_DATA, "\x00") else data.pack("C*").ljust(8, "\x00") end id_bytes + dlc_and_pad + payload end |
#open_socket(can_fd: nil) ⇒ Object
Creates and configures a CAN socket bound to the interface.
27 28 29 30 31 32 33 34 35 |
# File 'lib/can_messenger/adapter/socketcan.rb', line 27 def open_socket(can_fd: nil) socket = Socket.open(Socket::PF_CAN, Socket::SOCK_RAW, CAN_RAW) configure_socket(socket, can_fd: can_fd) socket rescue StandardError => e close_socket(socket) logger.error("Error creating CAN socket on interface #{interface_name}: #{e}") nil end |
#parse_frame(frame:, can_fd: nil) ⇒ Object
Parses a raw CAN frame string into a hash with id, data and extended flag.
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/can_messenger/adapter/socketcan.rb', line 80 def parse_frame(frame:, can_fd: nil) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/PerceivedComplexity return nil unless frame && frame.size >= MIN_FRAME_SIZE use_fd = can_fd.nil? ? frame.size >= CANFD_FRAME_SIZE : can_fd raw_id = unpack_frame_id(frame: frame) extended = raw_id.anybits?(Constants::EXTENDED_ID_FLAG) id = raw_id & Constants::MAX_EXTENDED_ID data_length = if use_fd frame[4].ord else frame[4].ord & 0x0F end data = if frame.size >= MIN_FRAME_SIZE + data_length frame[MIN_FRAME_SIZE, data_length].unpack("C*") else [] end { id: id, data: data, extended: extended } rescue StandardError => e logger.error("Error parsing CAN frame: #{e}") nil end |
#receive_message(socket:, can_fd: nil) ⇒ Object
Reads a frame from the socket and parses it into a hash.
66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/can_messenger/adapter/socketcan.rb', line 66 def (socket:, can_fd: nil) frame_size = can_fd ? CANFD_FRAME_SIZE : FRAME_SIZE frame = socket.recv(frame_size) return nil if frame.nil? || frame.size < MIN_FRAME_SIZE parse_frame(frame: frame, can_fd: can_fd) rescue IO::WaitReadable nil rescue StandardError => e logger.error("Error receiving CAN message on interface #{interface_name}: #{e}") nil end |