seriamp 0.1.10 → 0.1.11

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 50636555b1276e60e52ddf26c28f42fd1e7b1d27a89fac22f37fefce236c8f88
4
- data.tar.gz: aac82da48b0ac8887a507671af5d3d4e16fd9857bb70a635c145be12939fda70
3
+ metadata.gz: f9a46cb5fe16a4b24f54a6552e98db18e6e97281f7d12ce76c78f1ca5d18d8b8
4
+ data.tar.gz: '082c51ad737e37e237248acca21d9ee6d0b74bca0be135cf99f52fbf26679c31'
5
5
  SHA512:
6
- metadata.gz: 0c86e471aa614ce5048b168874f6c7ecacf956cf078fb0f327df230a588138e7c65f3fdc272ceaaa0f95775bdf2e9d104bbf47c7fcfa470565a83bb03d12e607
7
- data.tar.gz: dd5f494621dcd63117ce276ac97d4240dc38ec84b7dcb0775851e8b7602e45d8e2789118cbbe10b7efbc74d2a4a7429e5d2be4ee6d469fcbed9185b41da2d6a9
6
+ metadata.gz: 2b450a12d445a5b9199212eee5dba2eac298a9aa19e0e826df2fd322cd1d86d78a05815d39b3f75e417afa357720edb5ead5d1c9bfff1efefc171cb0b7e73f6e
7
+ data.tar.gz: 9461488acf8478e6f7d52ea4f824042eede1a13a99f357092f37f55afddee6608e70a0306f23844a12a594e4658c5f87a40b1b2e090539a910f6ef963acd52ae
@@ -10,17 +10,28 @@ module Seriamp
10
10
  RS232_TIMEOUT = 3
11
11
 
12
12
  class Client
13
- def initialize(device: nil, glob: nil, logger: nil)
13
+ def initialize(device: nil, glob: nil, logger: nil, retries: true)
14
14
  @logger = logger
15
15
 
16
16
  @device = device
17
17
  @detect_device = device.nil?
18
18
  @glob = glob
19
+ @retries = case retries
20
+ when nil, false
21
+ 0
22
+ when true
23
+ 1
24
+ when Integer
25
+ retries
26
+ else
27
+ raise ArgumentError, "retries must be an integer, true, false or nil: #{retries}"
28
+ end
19
29
  end
20
30
 
21
31
  attr_reader :device
22
32
  attr_reader :glob
23
33
  attr_reader :logger
34
+ attr_reader :retries
24
35
 
25
36
  def detect_device?
26
37
  @detect_device
@@ -134,7 +145,7 @@ module Seriamp
134
145
  end
135
146
 
136
147
  def get_voltage_trigger_input(zone = nil)
137
- get_zone_state('VTI', zone)
148
+ get_zone_state('VTI', zone, include_all: true)
138
149
  end
139
150
 
140
151
  def get_firmware_version
@@ -148,7 +159,7 @@ module Seriamp
148
159
  def status
149
160
  # Reusing the opened device file makes :VTIG? fail even with a delay
150
161
  # in front.
151
- #open_device do
162
+ with_device do
152
163
  {
153
164
  firmware_version: get_firmware_version,
154
165
  temperature: get_temperature,
@@ -165,13 +176,22 @@ module Seriamp
165
176
  voltage_trigger_input: get_voltage_trigger_input,
166
177
  channel_front_panel_level: get_channel_front_panel_level,
167
178
  }
168
- #end
179
+ end
169
180
  end
170
181
 
171
182
  private
172
183
 
184
+ def with_device(&block)
185
+ if @io
186
+ yield @io
187
+ else
188
+ open_device(&block)
189
+ end
190
+ end
191
+
173
192
  def open_device
174
193
  if detect_device? && device.nil?
194
+ logger&.debug("Detecting device")
175
195
  @device = Seriamp.detect_device(Sonamp, *glob, logger: logger)
176
196
  if @device
177
197
  logger&.info("Using #{device} as TTY device")
@@ -180,31 +200,58 @@ module Seriamp
180
200
  end
181
201
  end
182
202
 
183
- if @f
203
+ logger&.debug("Opening #{device}")
204
+ @io = Backend::SerialPortBackend::Device.new(device, logger: logger)
205
+
206
+ begin
207
+ yield @io
208
+ ensure
209
+ @io.close rescue nil
210
+ @io = nil
211
+ end
212
+ end
213
+
214
+ def with_retry
215
+ try = 1
216
+ begin
184
217
  yield
185
- else
186
- rv = nil
187
- Backend::SerialPortBackend::Device.new(device) do |f|
188
- @f = f
189
- rv = yield
190
- @f = nil
218
+ rescue Seriamp::Error => exc
219
+ if try <= retries
220
+ logger&.warn("Error during operation: #{exc.class}: #{exc} - will retry")
221
+ try += 1
222
+ @device = nil
223
+ retry
224
+ else
225
+ raise
191
226
  end
192
- rv
193
227
  end
194
228
  end
195
229
 
196
- def dispatch(cmd, resp_lines_count = 1)
197
- open_device do
198
- with_timeout do
199
- @f.syswrite("#{cmd}\x0d")
200
- end
201
- resp = 1.upto(resp_lines_count).map do
202
- read_line(@f, cmd)
203
- end
204
- if resp_lines_count == 1
205
- resp.first
206
- else
207
- resp
230
+ def dispatch(cmd, resp_lines_range_or_count = 1)
231
+ resp_lines_range = if Range === resp_lines_range_or_count || Array === resp_lines_range_or_count
232
+ resp_lines_range_or_count
233
+ else
234
+ 1..resp_lines_range_or_count
235
+ end
236
+
237
+ with_retry do
238
+ with_device do
239
+ with_timeout do
240
+ @io.syswrite("#{cmd}\x0d")
241
+ end
242
+ resp = resp_lines_range.map do
243
+ read_line(@io, cmd)
244
+ end
245
+
246
+ if @io && IO.select([@io.io], nil, nil, 0)
247
+ logger&.warn("Serial device readable after completely reading status response - concurrent access?")
248
+ end
249
+
250
+ if resp_lines_range_or_count == 1
251
+ resp.first
252
+ else
253
+ resp
254
+ end
208
255
  end
209
256
  end
210
257
  end
@@ -266,7 +313,7 @@ module Seriamp
266
313
  dispatch_assert(cmd, expected)
267
314
  end
268
315
 
269
- def get_zone_value(cmd_prefix, zone, boolize: false)
316
+ def get_zone_value(cmd_prefix, zone, boolize: false, include_all: false)
270
317
  if zone
271
318
  if zone < 1 || zone > 4
272
319
  raise ArgumentError, "Zone must be between 1 and 4: #{zone}"
@@ -274,22 +321,23 @@ module Seriamp
274
321
  resp = dispatch(":#{cmd_prefix}#{zone}?")
275
322
  typecast_value(resp[cmd_prefix.length + 1..], boolize)
276
323
  else
277
- hashize_query_result(dispatch(":#{cmd_prefix}G?", 4), cmd_prefix, boolize)
324
+ range = include_all ? [1, 2, 3, 4, 'A'] : (1..4).to_a
325
+ hashize_query_result(dispatch(":#{cmd_prefix}G?", range), cmd_prefix, boolize, range)
278
326
  end
279
327
  end
280
328
 
281
- def hashize_query_result(resp_lines, cmd_prefix, boolize)
329
+ def hashize_query_result(resp_lines, cmd_prefix, boolize, range)
282
330
  index = 1
283
331
  Hash[resp_lines.map do |resp|
284
- value = typecast_value(extract_suffix(resp, "#{cmd_prefix}#{index}"), boolize)
332
+ value = typecast_value(extract_suffix(resp, "#{cmd_prefix}#{range.to_a[index-1]}"), boolize)
285
333
  [index, value].tap do
286
334
  index += 1
287
335
  end
288
336
  end]
289
337
  end
290
338
 
291
- def get_zone_state(cmd_prefix, zone)
292
- get_zone_value(cmd_prefix, zone, boolize: true)
339
+ def get_zone_state(cmd_prefix, zone, include_all: false)
340
+ get_zone_value(cmd_prefix, zone, boolize: true, include_all: include_all)
293
341
  end
294
342
 
295
343
  def set_channel_value(cmd_prefix, channel, value)
@@ -309,7 +357,7 @@ module Seriamp
309
357
  typecast_value(dispatch_extract_suffix(":#{cmd_prefix}#{channel}?", "#{cmd_prefix}#{channel}"), boolize)
310
358
  else
311
359
  index = 1
312
- hashize_query_result(dispatch(":#{cmd_prefix}G?", 8), cmd_prefix, boolize)
360
+ hashize_query_result(dispatch(":#{cmd_prefix}G?", 8), cmd_prefix, boolize, 1..8)
313
361
  end
314
362
  end
315
363
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Seriamp
4
- VERSION = '0.1.10'
4
+ VERSION = '0.1.11'
5
5
  end
data/seriamp.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = "seriamp"
5
- spec.version = '0.1.10'
5
+ spec.version = '0.1.11'
6
6
  spec.authors = ['Oleg Pudeyev']
7
7
  spec.email = ['code@olegp.name']
8
8
  spec.summary = %q{Serial control for amplifiers & A/V receivers}
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: seriamp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.10
4
+ version: 0.1.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oleg Pudeyev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-15 00:00:00.000000000 Z
11
+ date: 2023-01-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: serialport