seriamp 0.1.9 → 0.1.11

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: 25ded6fbd5f32c13385dc7704f60d9d88c46bf528f79e7c67d41f295800b596d
4
- data.tar.gz: 7c2cab83327cf081c73c28743d46406213bdfaccd18f177d632f3c0922b55466
3
+ metadata.gz: f9a46cb5fe16a4b24f54a6552e98db18e6e97281f7d12ce76c78f1ca5d18d8b8
4
+ data.tar.gz: '082c51ad737e37e237248acca21d9ee6d0b74bca0be135cf99f52fbf26679c31'
5
5
  SHA512:
6
- metadata.gz: 5484fe172a3d65fb4d9778fc3734dd0a2aa5b24f459f864b5d8bc68a4766b06e5d6f2fd3ccc234b21b27fdc534abeb76655cdf29c68e1dca7afacf476e847186
7
- data.tar.gz: 64cb7cfed4265a174020f59a04671e9865739d4f573b361f560c88051fad4a63355e2401cd0d84cc2aa394babed6cc5efa6ae775573362fb3da6e09dfa716840
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.9'
4
+ VERSION = '0.1.11'
5
5
  end
@@ -15,6 +15,7 @@ module Seriamp
15
15
  set :client, nil
16
16
 
17
17
  get '/' do
18
+ clear_cache
18
19
  render_json(client.last_status)
19
20
  end
20
21
 
@@ -142,6 +143,14 @@ module Seriamp
142
143
 
143
144
  private
144
145
 
146
+ def clear_cache
147
+ if settings.client
148
+ settings.client.clear_cache
149
+ else
150
+ @client&.clear_cache
151
+ end
152
+ end
153
+
145
154
  def client
146
155
  settings.client || begin
147
156
  @client ||= Yamaha::Client.new(settings.device, logger: settings.logger)
@@ -57,6 +57,9 @@ module Seriamp
57
57
  def last_status
58
58
  unless @status
59
59
  with_device do
60
+ unless @status
61
+ do_status
62
+ end
60
63
  end
61
64
  end
62
65
  @status.dup
@@ -75,6 +78,10 @@ module Seriamp
75
78
  last_status
76
79
  end
77
80
 
81
+ def clear_cache
82
+ @status = nil
83
+ end
84
+
78
85
  %i(
79
86
  model_code firmware_version system_status power main_power zone2_power
80
87
  zone3_power input input_name audio_select audio_select_name
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.9'
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.9
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