can_messenger 1.1.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +8 -14
- data/lib/can_messenger/messenger.rb +36 -14
- data/lib/can_messenger/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d47c9c4b19c40337cb6b58f380e9a3f07554144a14d23ef4c2589060fd25942e
|
4
|
+
data.tar.gz: 66f58f8fab19fb73ab5124e4036313459ae032282bdd07613dc6156ef86a1379
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a55c719faf6f813ff4aef9004b4b32065297773498bf92291019002520b43c940e304fa5a0244635f42c9152ab3729cbeaa8534d809b2790878ebc9ef9a00244
|
7
|
+
data.tar.gz: '014168fa0419b78aa966c4d1d9a415c2e8e70650323df2c1a4328354099ffacf038cd52ef1c1fc371334e312a91538e985b7ec98727863739aa70c88e449d4d3'
|
data/README.md
CHANGED
@@ -11,18 +11,6 @@
|
|
11
11
|
|
12
12
|
## Installation
|
13
13
|
|
14
|
-
Ensure you have `SocketCAN` available on your system. Typically on Linux (e.g., Debian/Ubuntu), you install SocketCAN support with:
|
15
|
-
|
16
|
-
```bash
|
17
|
-
sudo apt-get install net-tools iproute2
|
18
|
-
```
|
19
|
-
|
20
|
-
Then bring up your CAN interface (e.g., `can0`) using `ip` commands or a tool like `can-utils` (though this gem no longer depends on `cansend`):
|
21
|
-
|
22
|
-
```bash
|
23
|
-
sudo ip link set can0 up type can bitrate 500000
|
24
|
-
```
|
25
|
-
|
26
14
|
To install `can_messenger`, add it to your application's Gemfile:
|
27
15
|
|
28
16
|
```ruby
|
@@ -63,13 +51,19 @@ messenger.send_can_message(id: 0x123, data: [0xDE, 0xAD, 0xBE, 0xEF])
|
|
63
51
|
|
64
52
|
> **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.
|
65
53
|
|
54
|
+
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:
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
messenger.send_can_message(id: 0x123456, data: [0x01, 0x02, 0x03], extended_id: true)
|
58
|
+
```
|
59
|
+
|
66
60
|
### Receiving CAN Messages
|
67
61
|
|
68
62
|
To listen for incoming messages, set up a listener:
|
69
63
|
|
70
64
|
```ruby
|
71
|
-
messenger.start_listening do |
|
72
|
-
puts "Received
|
65
|
+
messenger.start_listening do |msg|
|
66
|
+
puts "Received ID=0x#{msg[:id].to_s(16)}, Extended=#{msg[:extended]}, Data=#{msg[:data]}"
|
73
67
|
end
|
74
68
|
```
|
75
69
|
|
@@ -15,7 +15,7 @@ module CanMessenger
|
|
15
15
|
# messenger.start_listening do |message|
|
16
16
|
# puts "Received: ID=#{message[:id]}, Data=#{message[:data].map { |b| '0x%02X' % b }}"
|
17
17
|
# end
|
18
|
-
class Messenger
|
18
|
+
class Messenger # rubocop:disable Metrics/ClassLength
|
19
19
|
FRAME_SIZE = 16
|
20
20
|
MIN_FRAME_SIZE = 8
|
21
21
|
TIMEOUT = [1, 0].pack("l_2")
|
@@ -38,11 +38,13 @@ module CanMessenger
|
|
38
38
|
# @param [Integer] id The CAN ID of the message (up to 29 bits for extended IDs).
|
39
39
|
# @param [Array<Integer>] data The data bytes of the CAN message (0 to 8 bytes).
|
40
40
|
# @return [void]
|
41
|
-
def send_can_message(id:, data:)
|
41
|
+
def send_can_message(id:, data:, extended_id: false)
|
42
42
|
with_socket do |socket|
|
43
|
-
frame = build_can_frame(id: id, data: data)
|
43
|
+
frame = build_can_frame(id: id, data: data, extended_id: extended_id)
|
44
44
|
socket.write(frame)
|
45
45
|
end
|
46
|
+
rescue ArgumentError
|
47
|
+
raise
|
46
48
|
rescue StandardError => e
|
47
49
|
@logger.error("Error sending CAN message (ID: #{id}): #{e}")
|
48
50
|
end
|
@@ -63,6 +65,8 @@ module CanMessenger
|
|
63
65
|
def start_listening(filter: nil, &block)
|
64
66
|
return @logger.error("No block provided to handle messages.") unless block_given?
|
65
67
|
|
68
|
+
@listening = true
|
69
|
+
|
66
70
|
with_socket do |socket|
|
67
71
|
@logger.info("Started listening on #{@interface_name}")
|
68
72
|
process_message(socket, filter, &block) while @listening
|
@@ -111,13 +115,16 @@ module CanMessenger
|
|
111
115
|
# @param id [Integer] the CAN ID
|
112
116
|
# @param data [Array<Integer>] up to 8 bytes
|
113
117
|
# @return [String] a 16-byte string representing a classic CAN frame
|
114
|
-
def build_can_frame(id:, data:)
|
118
|
+
def build_can_frame(id:, data:, extended_id: false)
|
115
119
|
raise ArgumentError, "CAN data cannot exceed 8 bytes" if data.size > 8
|
116
120
|
|
117
|
-
#
|
121
|
+
# Mask the ID to 29 bits
|
118
122
|
can_id = id & 0x1FFFFFFF
|
119
123
|
|
120
|
-
#
|
124
|
+
# If extended_id == true, set bit 31 (CAN_EFF_FLAG)
|
125
|
+
can_id |= 0x80000000 if extended_id
|
126
|
+
|
127
|
+
# Pack the 4‐byte ID (big-endian or little-endian)
|
121
128
|
id_bytes = @endianness == :big ? [can_id].pack("L>") : [can_id].pack("V")
|
122
129
|
|
123
130
|
# 1 byte for DLC, then 3 bytes of padding
|
@@ -126,7 +133,7 @@ module CanMessenger
|
|
126
133
|
# Up to 8 data bytes, pad with 0 if fewer
|
127
134
|
payload = data.pack("C*").ljust(8, "\x00")
|
128
135
|
|
129
|
-
# Total 16 bytes
|
136
|
+
# Total 16 bytes (4 for ID, 1 for DLC, 3 padding, 8 data)
|
130
137
|
id_bytes + dlc_and_pad + payload
|
131
138
|
end
|
132
139
|
|
@@ -166,25 +173,40 @@ module CanMessenger
|
|
166
173
|
#
|
167
174
|
# @param [String] frame
|
168
175
|
# @return [Hash, nil]
|
169
|
-
def parse_frame(frame:)
|
176
|
+
def parse_frame(frame:) # rubocop:disable Metrics/MethodLength
|
170
177
|
return nil unless frame && frame.size >= MIN_FRAME_SIZE
|
171
178
|
|
172
|
-
|
173
|
-
|
179
|
+
raw_id = unpack_frame_id(frame: frame)
|
180
|
+
|
181
|
+
# Determine if EFF bit is set
|
182
|
+
extended = raw_id.anybits?(0x80000000)
|
183
|
+
# or raw_id.anybits?(0x80000000) if your Ruby version supports `Integer#anybits?`
|
184
|
+
|
185
|
+
# Now mask off everything except the lower 29 bits
|
186
|
+
id = raw_id & 0x1FFFFFFF
|
174
187
|
|
175
188
|
# DLC is the lower 4 bits of byte 4
|
176
189
|
data_length = frame[4].ord & 0x0F
|
177
190
|
|
178
|
-
#
|
179
|
-
data =
|
180
|
-
|
191
|
+
# Extract data
|
192
|
+
data = if frame.size >= MIN_FRAME_SIZE + data_length
|
193
|
+
frame[MIN_FRAME_SIZE, data_length].unpack("C*")
|
194
|
+
else
|
195
|
+
[]
|
196
|
+
end
|
197
|
+
|
198
|
+
{ id: id, data: data, extended: extended }
|
181
199
|
rescue StandardError => e
|
182
200
|
@logger.error("Error parsing CAN frame: #{e}")
|
183
201
|
nil
|
184
202
|
end
|
185
203
|
|
186
204
|
def unpack_frame_id(frame:)
|
187
|
-
@endianness == :big
|
205
|
+
if @endianness == :big
|
206
|
+
frame[0..3].unpack1("L>")
|
207
|
+
else
|
208
|
+
frame[0..3].unpack1("V")
|
209
|
+
end
|
188
210
|
end
|
189
211
|
|
190
212
|
# Checks whether the given message ID matches the specified filter.
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: can_messenger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1
|
4
|
+
version: 1.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- fk1018
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-06-05 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: CanMessenger provides an interface to send and receive messages over
|
14
14
|
the CAN bus, useful for applications requiring CAN communication in Ruby.
|