can_messenger 2.1.0 → 2.2.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b79b0febdca3de5f068c142413eef6f959461518e3928cd9beed52b14ee8ceef
4
- data.tar.gz: aca5cf8fde09f75b6f0d7a81ab1bca9e6a59fc2d3d811a72321eb6b9d6b88ba9
3
+ metadata.gz: 51737c6d0bee83617a3cb2c68b634f63a65ae5b1c711a4720d7a5a37a08a0612
4
+ data.tar.gz: aebcbd5b0904849633ce3326f60bf9fd28ca47f8c1982601d25161ec383f3a05
5
5
  SHA512:
6
- metadata.gz: 864bd3e56da612dee5e02bd6e575eff32adab311c3090e2a874704ee7fb6f84895146294a83362be40faef5477e3951c69203f6ecd4ad094a79067d4a5928d1e
7
- data.tar.gz: c1bc154e2b42b3373aadd0e27572d66221d3859fb5272f0594fc5d1adb1a4e1382de1e04e02e7e2171bf28b6f2a1cfc33500b4c4af0f0acd3edf35ea3b87c1f4
6
+ metadata.gz: f6d8a36f95f8afcc859d25bd48b5c49b878b7fd1e2e51245ebe142e83dc3e05bc0e2572233da563ec470b0e0b52b3b59ee55c50c7165dc46b7d13302d2df465c
7
+ data.tar.gz: 88bca2b12015fa26df773080f8ad540ec30967b486e6a878afe4319c93b743eb758c6dcef9fe302b2af3ee5776e162129a49236368f31ca1343cc30a117096fc
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [2.2.0] - 2026-03-11
4
+
5
+ ### Changed
6
+
7
+ - Make the Ruby Docker workflow install gems against the checked-in lockfile and self-heal stale bundle cache volumes.
8
+ - Promote the docs site stable snapshot to `2.2.0` and add global RubyGems navigation links.
9
+
10
+ ### Fixed
11
+
12
+ - Respect DBC-defined extended CAN IDs when sending messages and when decoding received extended frames.
13
+ - Reject invalid outbound CAN IDs instead of silently coercing them to a different wire value.
14
+
3
15
  ## [2.1.0] - 2026-02-23
4
16
 
5
17
  ### Changed
@@ -164,7 +176,8 @@
164
176
  ## [0.1.0] - 2024-11-10
165
177
 
166
178
  - Initial release
167
- [Unreleased]: https://github.com/fk1018/can_messenger/compare/v2.1.0...HEAD
179
+ [Unreleased]: https://github.com/fk1018/can_messenger/compare/v2.2.0...HEAD
180
+ [2.2.0]: https://github.com/fk1018/can_messenger/compare/v2.1.0...v2.2.0
168
181
  [2.1.0]: https://github.com/fk1018/can_messenger/compare/v2.0.0...v2.1.0
169
182
  [2.0.0]: https://github.com/fk1018/can_messenger/compare/v1.3.0...v2.0.0
170
183
  [1.3.0]: https://github.com/fk1018/can_messenger/compare/v1.2.1...v1.3.0
data/README.md CHANGED
@@ -35,6 +35,8 @@ Or install it yourself with:
35
35
  gem install can_messenger
36
36
  ```
37
37
 
38
+ RubyGems page: [https://rubygems.org/gems/can_messenger](https://rubygems.org/gems/can_messenger)
39
+
38
40
  ## Usage
39
41
 
40
42
  ### Initializing the Messenger
@@ -128,6 +130,8 @@ messenger.start_listening(dbc: dbc) do |msg|
128
130
  end
129
131
  ```
130
132
 
133
+ If the DBC message definition uses an extended CAN ID, `send_dbc_message` automatically sends it as an extended frame and `start_listening(dbc: ...)` decodes received extended frames back through the same DBC definition.
134
+
131
135
  ### Stopping the Listener
132
136
 
133
137
  To stop listening, use:
@@ -207,7 +211,7 @@ Before using `can_messenger`, please note the following:
207
211
 
208
212
  ## Development
209
213
 
210
- ### Docker-first workflow (no local Ruby required)
214
+ ### Docker-first workflow
211
215
 
212
216
  Build the development image:
213
217
 
@@ -215,6 +219,8 @@ Build the development image:
215
219
  docker compose build app
216
220
  ```
217
221
 
222
+ The Ruby services automatically run `bundle check || bundle install` inside the container, so an existing bundle cache volume stays usable after dependency changes.
223
+
218
224
  Run RuboCop:
219
225
 
220
226
  ```bash
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "socket"
4
4
  require_relative "base"
5
+ require_relative "../constants"
5
6
 
6
7
  module CanMessenger
7
8
  module Adapter
@@ -11,10 +12,11 @@ module CanMessenger
11
12
  CANFD_FRAME_SIZE = 72
12
13
  MIN_FRAME_SIZE = 8
13
14
  MAX_FD_DATA = 64
15
+ MAX_STANDARD_ID = 0x7FF
14
16
  TIMEOUT = [1, 0].pack("l_2")
15
17
 
16
18
  # Creates and configures a CAN socket bound to the interface.
17
- def open_socket(can_fd: false)
19
+ def open_socket(can_fd: nil)
18
20
  socket = Socket.open(Socket::PF_CAN, Socket::SOCK_RAW, Socket::CAN_RAW)
19
21
  configure_socket(socket, can_fd: can_fd)
20
22
  socket
@@ -25,17 +27,18 @@ module CanMessenger
25
27
  end
26
28
 
27
29
  # Builds a raw CAN or CAN FD frame for SocketCAN.
28
- def build_can_frame(id:, data:, extended_id: false, can_fd: false) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/PerceivedComplexity
30
+ def build_can_frame(id:, data:, extended_id: false, can_fd: nil) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/PerceivedComplexity
29
31
  if can_fd
30
32
  raise ArgumentError, "CAN FD data cannot exceed #{MAX_FD_DATA} bytes" if data.size > MAX_FD_DATA
31
33
  elsif data.size > 8
32
34
  raise ArgumentError, "CAN data cannot exceed 8 bytes"
33
35
  end
34
36
 
35
- # Mask the ID to 29 bits
36
- can_id = id & 0x1FFFFFFF
37
+ validate_can_id!(id, extended_id: extended_id)
38
+
39
+ can_id = id
37
40
  # Set bit 31 for extended frames
38
- can_id |= 0x80000000 if extended_id
41
+ can_id |= Constants::EXTENDED_ID_FLAG if extended_id
39
42
 
40
43
  # Pack the ID based on endianness
41
44
  id_bytes = endianness == :big ? [can_id].pack("L>") : [can_id].pack("V")
@@ -52,7 +55,7 @@ module CanMessenger
52
55
  end
53
56
 
54
57
  # Reads a frame from the socket and parses it into a hash.
55
- def receive_message(socket:, can_fd: false)
58
+ def receive_message(socket:, can_fd: nil)
56
59
  frame_size = can_fd ? CANFD_FRAME_SIZE : FRAME_SIZE
57
60
  frame = socket.recv(frame_size)
58
61
  return nil if frame.nil? || frame.size < MIN_FRAME_SIZE
@@ -72,8 +75,8 @@ module CanMessenger
72
75
  use_fd = can_fd.nil? ? frame.size >= CANFD_FRAME_SIZE : can_fd
73
76
 
74
77
  raw_id = unpack_frame_id(frame: frame)
75
- extended = raw_id.anybits?(0x80000000)
76
- id = raw_id & 0x1FFFFFFF
78
+ extended = raw_id.anybits?(Constants::EXTENDED_ID_FLAG)
79
+ id = raw_id & Constants::MAX_EXTENDED_ID
77
80
 
78
81
  data_length = if use_fd
79
82
  frame[4].ord
@@ -120,6 +123,16 @@ module CanMessenger
120
123
  rescue StandardError
121
124
  # Ignore close errors so we can report the original failure.
122
125
  end
126
+
127
+ def validate_can_id!(id, extended_id:)
128
+ raise ArgumentError, "id must be an Integer" unless id.is_a?(Integer)
129
+ raise ArgumentError, "CAN id cannot be negative" if id.negative?
130
+
131
+ max_id = extended_id ? Constants::MAX_EXTENDED_ID : MAX_STANDARD_ID
132
+ return if id <= max_id
133
+
134
+ raise ArgumentError, "#{extended_id ? "Extended" : "Standard"} CAN id cannot exceed 0x#{max_id.to_s(16).upcase}"
135
+ end
123
136
  end
124
137
  end
125
138
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CanMessenger
4
+ module Constants
5
+ CAN_ID_MASK = 0x1FFFFFFF
6
+ EXTENDED_ID_FLAG = 0x80000000
7
+ MAX_EXTENDED_ID = 0x1FFFFFFF
8
+ end
9
+ end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "logger"
4
4
  require_relative "adapter/socketcan"
5
+ require_relative "constants"
5
6
 
6
7
  module CanMessenger
7
8
  # Messenger
@@ -64,8 +65,8 @@ module CanMessenger
64
65
  def send_dbc_message(message_name:, signals:, dbc: @dbc, extended_id: false, can_fd: nil)
65
66
  raise ArgumentError, "dbc is required" if dbc.nil?
66
67
 
67
- encoded = dbc.encode_can(message_name, signals)
68
- send_can_message(id: encoded[:id], data: encoded[:data], extended_id: extended_id, can_fd: can_fd)
68
+ encoded = normalized_dbc_message(dbc.encode_can(message_name, signals), extended_id: extended_id)
69
+ send_can_message(id: encoded[:id], data: encoded[:data], extended_id: encoded[:extended_id], can_fd: can_fd)
69
70
  rescue ArgumentError
70
71
  raise
71
72
  rescue StandardError => e
@@ -134,7 +135,7 @@ module CanMessenger
134
135
  return if filter && !matches_filter?(message_id: message[:id], filter: filter)
135
136
 
136
137
  if dbc
137
- decoded = dbc.decode_can(message[:id], message[:data])
138
+ decoded = dbc.decode_can(dbc_decode_id(message), message[:data])
138
139
  message[:decoded] = decoded if decoded
139
140
  end
140
141
 
@@ -156,5 +157,27 @@ module CanMessenger
156
157
  else true
157
158
  end
158
159
  end
160
+
161
+ def normalize_can_id(id)
162
+ id & Constants::CAN_ID_MASK
163
+ end
164
+
165
+ def dbc_extended_id?(id)
166
+ id.anybits?(Constants::EXTENDED_ID_FLAG)
167
+ end
168
+
169
+ def normalized_dbc_message(encoded, extended_id:)
170
+ {
171
+ id: normalize_can_id(encoded[:id]),
172
+ data: encoded[:data],
173
+ extended_id: extended_id || dbc_extended_id?(encoded[:id])
174
+ }
175
+ end
176
+
177
+ def dbc_decode_id(message)
178
+ return message[:id] unless message[:extended]
179
+
180
+ message[:id] | Constants::EXTENDED_ID_FLAG
181
+ end
159
182
  end
160
183
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CanMessenger
4
- VERSION = "2.1.0"
4
+ VERSION = "2.2.0"
5
5
  end
data/lib/can_messenger.rb CHANGED
@@ -2,6 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require_relative "can_messenger/version"
5
+ require_relative "can_messenger/constants"
5
6
  require_relative "can_messenger/messenger"
6
7
  require_relative "can_messenger/dbc"
7
8
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: can_messenger
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - fk1018
@@ -23,15 +23,16 @@ files:
23
23
  - lib/can_messenger.rb
24
24
  - lib/can_messenger/adapter/base.rb
25
25
  - lib/can_messenger/adapter/socketcan.rb
26
+ - lib/can_messenger/constants.rb
26
27
  - lib/can_messenger/dbc.rb
27
28
  - lib/can_messenger/messenger.rb
28
29
  - lib/can_messenger/version.rb
29
- homepage: https://github.com/fk1018/can_messenger
30
+ homepage: https://can-messenger.github.io/
30
31
  licenses:
31
32
  - MIT
32
33
  metadata:
33
34
  allowed_push_host: https://rubygems.org
34
- homepage_uri: https://github.com/fk1018/can_messenger
35
+ homepage_uri: https://can-messenger.github.io/
35
36
  source_code_uri: https://github.com/fk1018/can_messenger
36
37
  changelog_uri: https://github.com/fk1018/can_messenger/blob/main/CHANGELOG.md
37
38
  rubygems_mfa_required: 'true'