aca-device-modules 1.0.4 → 1.0.5

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.
@@ -24,120 +24,121 @@ module Kramer::Switcher; end
24
24
  #
25
25
 
26
26
  class Kramer::Switcher::VsHdmi
27
- include ::Orchestrator::Constants
27
+ include ::Orchestrator::Constants
28
28
  include ::Orchestrator::Transcoder
29
-
30
- def on_load
31
-
32
- #
33
- # Setup constants
34
- #
35
- self[:limits_known] = false
36
-
37
- defaults({
38
- :wait => false
39
- })
29
+
30
+ def on_load
31
+
32
+ #
33
+ # Setup constants
34
+ #
35
+ self[:limits_known] = false
36
+
37
+ defaults({
38
+ :wait => false,
39
+ :delay => 200
40
+ })
40
41
 
41
- config = ({
42
- :inactivity_timeout => 10000 # We wait 10 seconds before the connection is broken (make and break)
43
- })
44
- end
45
-
46
- def connected
47
- #
48
- # Get current state of the switcher
49
- #
50
- get_machine_type
51
- end
42
+ config = ({
43
+ :inactivity_timeout => 10000 # We wait 10 seconds before the connection is broken (make and break)
44
+ })
45
+ end
46
+
47
+ def connected
48
+ #
49
+ # Get current state of the switcher
50
+ #
51
+ get_machine_type
52
+ end
52
53
 
53
-
54
- COMMANDS = {
55
- :reset_video => 0,
56
- :switch_video => 1,
57
- :status_video => 5,
58
- :define_machine => 62,
59
- :identify_machine => 61
60
- }
61
-
62
-
63
- #
64
- # Starting at input 1
65
- #
66
- def switch(map)
67
- # instr, inp, outp, machine number
68
- # Switch video
69
- command = [1, 0x80, 0x80, 0xFF]
70
-
71
- map.each do |input, outputs|
72
- outputs = [outputs] unless outputs.class == Array
73
- input = input.to_s if input.class == Symbol
74
- input = input.to_i if input.class == String
75
- outputs.each do |output|
76
- command[1] = 0x80 + input
77
- command[2] = 0x80 + output
78
- outname = :"video#{output}"
79
- send(command, name: outname)
80
- self[outname] = input
81
- end
82
- end
83
- end
84
- alias :switch_video :switch
85
-
86
- def received(data, resolve, command)
87
- logger.debug "Kramer sent 0x#{byte_to_hex(data)}"
88
-
89
- data = str_to_array(data)
90
-
91
- return nil if data[0] & 0b1000000 == 0 # Check we are the destination
54
+
55
+ COMMANDS = {
56
+ :reset_video => 0,
57
+ :switch_video => 1,
58
+ :status_video => 5,
59
+ :define_machine => 62,
60
+ :identify_machine => 61
61
+ }
62
+
63
+
64
+ #
65
+ # Starting at input 1
66
+ #
67
+ def switch(map)
68
+ # instr, inp, outp, machine number
69
+ # Switch video
70
+ command = [1, 0x80, 0x80, 0xFF]
71
+
72
+ map.each do |input, outputs|
73
+ outputs = [outputs] unless outputs.class == Array
74
+ input = input.to_s if input.class == Symbol
75
+ input = input.to_i if input.class == String
76
+ outputs.each do |output|
77
+ command[1] = 0x80 + input
78
+ command[2] = 0x80 + output
79
+ outname = :"video#{output}"
80
+ send(command, name: outname)
81
+ self[outname] = input
82
+ end
83
+ end
84
+ end
85
+ alias :switch_video :switch
86
+
87
+ def received(data, resolve, command)
88
+ logger.debug "Kramer sent 0x#{byte_to_hex(data)}"
89
+
90
+ data = str_to_array(data)
91
+
92
+ return nil if data[0] & 0b1000000 == 0 # Check we are the destination
92
93
 
93
- data[1] = data[1] & 0b1111111 # input
94
- data[2] = data[2] & 0b1111111 # output
94
+ data[1] = data[1] & 0b1111111 # input
95
+ data[2] = data[2] & 0b1111111 # output
95
96
 
96
- case data[0] & 0b111111
97
- when COMMANDS[:define_machine]
98
- if data[1] == 1
99
- self[:video_inputs] = data[2]
100
- elsif data[1] == 2
101
- self[:video_outputs] = data[2]
102
- end
103
- self[:limits_known] = true # Set here in case unsupported
104
- when COMMANDS[:status_video]
105
- if data[2] == 0 # Then data[1] has been applied to all the outputs
106
- logger.debug "Kramer switched #{data[1]} -> All"
107
-
108
- (1..self[:video_outputs]).each do |i|
109
- self["video#{i}"] = data[1]
110
- end
111
- else
112
- self["video#{data[2]}"] = data[1]
113
-
114
- logger.debug "Kramer switched #{data[1]} -> #{data[2]}"
115
-
116
- #
117
- # As we may not know the max number of inputs if get machine type didn't work
118
- #
119
- self[:video_inputs] = data[1] if data[1] > self[:video_inputs]
120
- self[:video_outputs] = data[2] if data[2] > self[:video_outputs]
121
- end
122
- when COMMANDS[:identify_machine]
123
- logger.debug "Kramer switcher protocol #{data[1]}.#{data[2]}"
124
- end
125
-
126
- return :success
127
- end
128
-
129
-
130
- private
131
-
97
+ case data[0] & 0b111111
98
+ when COMMANDS[:define_machine]
99
+ if data[1] == 1
100
+ self[:video_inputs] = data[2]
101
+ elsif data[1] == 2
102
+ self[:video_outputs] = data[2]
103
+ end
104
+ self[:limits_known] = true # Set here in case unsupported
105
+ when COMMANDS[:status_video]
106
+ if data[2] == 0 # Then data[1] has been applied to all the outputs
107
+ logger.debug "Kramer switched #{data[1]} -> All"
108
+
109
+ (1..self[:video_outputs]).each do |i|
110
+ self["video#{i}"] = data[1]
111
+ end
112
+ else
113
+ self["video#{data[2]}"] = data[1]
114
+
115
+ logger.debug "Kramer switched #{data[1]} -> #{data[2]}"
116
+
117
+ #
118
+ # As we may not know the max number of inputs if get machine type didn't work
119
+ #
120
+ self[:video_inputs] = data[1] if data[1] > self[:video_inputs]
121
+ self[:video_outputs] = data[2] if data[2] > self[:video_outputs]
122
+ end
123
+ when COMMANDS[:identify_machine]
124
+ logger.debug "Kramer switcher protocol #{data[1]}.#{data[2]}"
125
+ end
126
+
127
+ return :success
128
+ end
129
+
130
+
131
+ private
132
+
132
133
 
133
- #
134
- # No all switchers implement this
135
- #
136
- def get_machine_type
137
- # id com, video
138
- command = [62, 0x81, 0x81, 0xFF]
139
- send(command, name: :inputs) # num inputs
140
- command[1] = 0x82
141
- send(command, name: :outputs) # num outputs
142
- end
134
+ #
135
+ # No all switchers implement this
136
+ #
137
+ def get_machine_type
138
+ # id com, video
139
+ command = [62, 0x81, 0x81, 0xFF]
140
+ send(command, name: :inputs) # num inputs
141
+ command[1] = 0x82
142
+ send(command, name: :outputs) # num outputs
143
+ end
143
144
  end
@@ -33,450 +33,447 @@ module Nec::Display; end
33
33
  #
34
34
  #
35
35
  class Nec::Display::All
36
- include ::Orchestrator::Constants
36
+ include ::Orchestrator::Constants
37
37
  include ::Orchestrator::Transcoder
38
38
 
39
- #
40
- # Called on module load complete
41
- # Alternatively you can use initialize however will
42
- # not have access to settings and this is called
43
- # soon afterwards
44
- #
45
- def on_load
46
- #
47
- # Setup constants
48
- #
49
- self[:volume_min] = 0
50
- self[:brightness_min] = 0
51
- self[:contrast_min] = 0
52
- #self[:error] = [] TODO!!
53
- end
54
-
55
- def response_delimiter # Function required if device could contacts us first
56
- 0x0D
57
- end
58
-
59
- def connected
60
- do_poll
61
-
62
- @polling_timer = schedule.every('30s') do
63
- logger.debug "-- Polling Display"
64
- do_poll
65
- end
66
- end
67
-
68
- def disconnected
69
- #
70
- # Disconnected may be called without calling connected
71
- # Hence the check if timer is nil here
72
- #
73
- @polling_timer.cancel unless @polling_timer.nil?
74
- @polling_timer = nil
75
- end
76
-
77
-
78
- #
79
- # Power commands
80
- #
81
- def power(state)
82
- message = "C203D6"
83
-
84
- power? do |result|
85
- if is_affirmative?(state)
86
- if result == Off
87
- message += "0001" # Power On
88
- send_checksum(:command, message, {:name => :power})
89
- self[:warming] = true
90
- self[:power] = On
91
- logger.debug "-- NEC LCD, requested to power on"
92
-
93
- power_on_delay
94
- mute_status(0)
95
- volume_status(0)
96
- end
97
- else
98
- if result == On
99
- message += "0004" # Power Off
100
- send_checksum(:command, message, {:name => :power})
101
-
102
- self[:power] = Off
103
- logger.debug "-- NEC LCD, requested to power off"
104
- end
105
- end
106
- end
107
- end
108
-
109
- def power?(options = {}, &block)
110
- options[:emit] = block if block_given?
111
- type = :command
112
- message = "01D6"
113
- send_checksum(type, message, options)
114
- end
115
-
116
-
117
- #
118
- # Input selection
119
- #
120
- INPUTS = {
121
- :vga => 1,
122
- :rgbhv => 2,
123
- :dvi => 3,
124
- :hdmi_set => 4, # Set only?
125
- :video1 => 5,
126
- :video2 => 6,
127
- :svideo => 7,
128
-
129
- :tv => 10,
130
- :dvd1 => 12,
131
- :option => 13,
132
- :dvd2 => 14,
133
- :display_port => 15,
134
-
135
- :hdmi => 17
136
- }
137
- def switch_to(input)
138
- input = input.to_sym if input.class == String
139
- #self[:target_input] = input
140
-
141
- type = :set_parameter
142
- message = OPERATION_CODE[:video_input]
143
- message += INPUTS[input].to_s(16).upcase.rjust(4, '0') # Value of input as a hex string
144
-
145
- send_checksum(type, message, {:name => :input})
146
- brightness_status(60) # higher status than polling commands - lower than input switching
147
- contrast_status(60)
148
-
149
- logger.debug "-- NEC LCD, requested to switch to: #{input}"
150
- end
151
-
152
- AUDIO = {
153
- :audio1 => 1,
154
- :audio2 => 2,
155
- :audio3 => 3,
156
- :hdmi => 4,
157
- :tv => 6,
158
- :display_port => 7
159
- }
160
- def switch_audio(input)
161
- input = input.to_sym if input.class == String
162
- #self[:target_audio] = input
163
-
164
- type = :set_parameter
165
- message = OPERATION_CODE[:audio_input]
166
- message += AUDIO[input].to_s(16).upcase.rjust(4, '0') # Value of input as a hex string
167
-
168
- send_checksum(type, message, :name => :audio)
169
- mute_status(60) # higher status than polling commands - lower than input switching
170
- volume_status(60)
171
-
172
- logger.debug "-- NEC LCD, requested to switch audio to: #{input}"
173
- end
174
-
175
-
176
- #
177
- # Auto adjust
178
- #
179
- def auto_adjust
180
- message = OPERATION_CODE[:auto_setup] #"001E" # Page + OP code
181
- message += "0001" # Value of input as a hex string
182
-
183
- send_checksum(:set_parameter, message, :delay_on_receive => 4.0)
184
- end
185
-
186
-
187
- #
188
- # Value based set parameter
189
- #
190
- def brightness(val)
191
- val = val.to_i if val.is_a? String
192
- val = 100 if val > 100
193
- val = 0 if val < 0
194
-
195
- message = OPERATION_CODE[:brightness_status]
196
- message += val.to_s(16).upcase.rjust(4, '0') # Value of input as a hex string
197
-
198
- brightness_status
199
- send_checksum(:set_parameter, message)
200
- send_checksum(:command, '0C') # Save the settings
201
- end
202
-
203
- def contrast(val)
204
- val = val.to_i if val.is_a? String
205
- val = 100 if val > 100
206
- val = 0 if val < 0
207
-
208
- message = OPERATION_CODE[:contrast_status]
209
- message += val.to_s(16).upcase.rjust(4, '0') # Value of input as a hex string
210
-
211
- contrast_status
212
- send_checksum(:set_parameter, message)
213
- send_checksum(:command, '0C') # Save the settings
214
- end
215
-
216
- def volume(val)
217
- val = val.to_i if val.is_a? String
218
- val = 100 if val > 100
219
- val = 0 if val < 0
220
-
221
- message = OPERATION_CODE[:volume_status]
222
- message += val.to_s(16).upcase.rjust(4, '0') # Value of input as a hex string
223
-
224
- volume_status
225
- send_checksum(:set_parameter, message)
226
- send_checksum(:command, '0C') # Save the settings
227
-
228
- self[:audio_mute] = false # audio is unmuted when the volume is set
229
- end
230
-
231
-
232
- def mute_audio
233
- message = OPERATION_CODE[:mute_status]
234
- message += "0001" # Value of input as a hex string
235
-
236
- send_checksum(:set_parameter, message)
237
-
238
- logger.debug "-- NEC LCD, requested to mute audio"
239
- end
240
- alias_method :mute, :mute_audio
241
-
242
- def unmute_audio
243
- message = OPERATION_CODE[:mute_status]
244
- message += "0000" # Value of input as a hex string
245
-
246
- send_checksum(:set_parameter, message)
247
-
248
- logger.debug "-- NEC LCD, requested to unmute audio"
249
- end
250
- alias_method :unmute, :unmute_audio
251
-
252
- #
253
- # LCD Response code
254
- #
255
- def received(data, resolve, command)
256
- #
257
- # Check for valid response
258
- #
259
- if !check_checksum(data)
260
- logger.debug "-- NEC LCD, checksum failed for command: #{command[:data]}"
261
- logger.debug "-- NEC LCD, response was: #{data}"
262
- return false
263
- end
264
-
265
- #data = array_to_str(data) # Convert bytes to a string (received like this)
266
-
267
- case MSG_TYPE[data[4]] # Check the MSG_TYPE (B, D or F)
268
- when :command_reply
269
- #
270
- # Power on and off
271
- # 8..9 == "00" means no error
272
- if data[10..15] == "C203D6" # Means power comamnd
273
- if data[8..9] == "00"
274
- power_on_delay(0) # wait until the screen has turned on before sending commands (0 == high priority)
275
- else
276
- logger.info "-- NEC LCD, command failed: #{command[:data]}"
277
- logger.info "-- NEC LCD, response was: #{data}"
278
- return false # command failed
279
- end
280
- elsif data[10..13] == "00D6" # Power status response
281
- if data[10..11] == "00"
282
- if data[23] == '1' # On == 1, Off == 4
283
- self[:power] = On
284
- else
285
- self[:power] = Off
286
- self[:warming] = false
287
- end
288
- #if self[:power_target].nil?
289
- # self[:power_target] = self[:power]
290
- #elsif self[:power_target] != self[:power]
291
- # power(self[:power_target])
292
- #end
293
- else
294
- logger.info "-- NEC LCD, command failed: #{command[:data]}"
295
- logger.info "-- NEC LCD, response was: #{data}"
296
- return false # command failed
297
- end
298
-
299
- end
300
-
301
- when :get_parameter_reply, :set_parameter_reply
302
- if data[8..9] == "00"
303
- parse_response(data, command)
304
- elsif data[8..9] == 'BE' # Wait response
305
- send(command[:data]) # checksum already added
306
- logger.debug "-- NEC LCD, response was a wait command"
307
- else
308
- logger.info "-- NEC LCD, get or set failed: #{command[:data]}"
309
- logger.info "-- NEC LCD, response was: #{data}"
310
- return false
311
- end
312
- end
313
-
314
- return true # Command success
315
- end
316
-
317
-
318
- def do_poll
319
- power?({:priority => 99}) do |result|
320
- if result == On
321
- power_on_delay
322
- mute_status
323
- volume_status
324
- brightness_status
325
- contrast_status
326
- video_input
327
- audio_input
328
- end
329
- end
330
- end
331
-
332
-
333
- private
334
-
335
-
336
- def parse_response(data, command)
337
-
338
- # 14..15 == type (we don't care)
339
- max = data[16..19].to_i(16)
340
- value = data[20..23].to_i(16)
341
-
342
- case OPERATION_CODE[data[10..13]]
343
- when :video_input
344
- self[:input] = INPUTS.invert[value]
345
- #self[:target_input] = self[:input] if self[:target_input].nil?
346
- #switch_to(self[:target_input]) unless self[:input] == self[:target_input]
347
-
348
- when :audio_input
349
- self[:audio] = AUDIO.invert[value]
350
- #self[:target_audio] = self[:audio] if self[:target_audio].nil?
351
- #switch_audio(self[:target_audio]) unless self[:audio] == self[:target_audio]
352
-
353
- when :volume_status
354
- self[:volume_max] = max
355
- if not self[:audio_mute]
356
- self[:volume] = value
357
- end
358
-
359
- when :brightness_status
360
- self[:brightness_max] = max
361
- self[:brightness] = value
362
-
363
- when :contrast_status
364
- self[:contrast_max] = max
365
- self[:contrast] = value
366
-
367
- when :mute_status
368
- self[:audio_mute] = value == 1
369
- if(value == 1)
370
- self[:volume] = 0
371
- else
372
- volume_status(0) # high priority
373
- end
374
-
375
- when :power_on_delay
376
- if value > 0
377
- self[:warming] = true
378
- schedule.in("#{value}s") do # Prevent any commands being sent until the power on delay is complete
379
- power_on_delay
380
- end
381
- else
382
- schedule.in('3s') do # Reactive the interface once the display is online
383
- self[:warming] = false # allow access to the display
384
- end
385
- end
386
- when :auto_setup
387
- # auto_setup
388
- # nothing needed to do here (we are delaying the next command by 4 seconds)
389
- else
390
- logger.info "-- NEC LCD, unknown response: #{data[10..13]}"
391
- logger.info "-- NEC LCD, for command: #{command[:data]}"
392
- logger.info "-- NEC LCD, full response was: #{data}"
393
- end
394
- end
395
-
396
-
397
- #
398
- # Types of messages sent to and from the LCD
399
- #
400
- MSG_TYPE = {
401
- :command => 'A',
402
- 'B' => :command_reply,
403
- :get_parameter => 'C',
404
- 'D' => :get_parameter_reply,
405
- :set_parameter => 'E',
406
- 'F' => :set_parameter_reply
407
- }
408
-
409
-
410
- OPERATION_CODE = {
411
- :video_input => '0060', '0060' => :video_input,
412
- :audio_input => '022E', '022E' => :audio_input,
413
- :volume_status => '0062', '0062' => :volume_status,
414
- :mute_status => '008D', '008D' => :mute_status,
415
- :power_on_delay => '02D8', '02D8' => :power_on_delay,
416
- :contrast_status => '0012', '0012' => :contrast_status,
417
- :brightness_status => '0010', '0010' => :brightness_status,
418
- :auto_setup => '001E', '001E' => :auto_setup
419
- }
420
- #
421
- # Automatically creates a callable function for each command
422
- # http://blog.jayfields.com/2007/10/ruby-defining-class-methods.html
423
- # http://blog.jayfields.com/2008/02/ruby-dynamically-define-method.html
424
- #
425
- OPERATION_CODE.each_key do |command|
426
- define_method command do |*args|
427
- priority = 99
428
- if args.length > 0
429
- priority = args[0]
430
- end
431
- message = OPERATION_CODE[command]
432
- send_checksum(:get_parameter, message, {:priority => priority}) # Status polling is a low priority
433
- end
434
- end
435
-
436
-
437
- def check_checksum(data)
438
- data = str_to_array(data)
439
-
440
- check = 0
441
- #
442
- # Loop through the second to the second last element
443
- # Delimiter is removed automatically
444
- #
445
- if data.length >= 2
446
- data[1..-2].each do |byte|
447
- check = check ^ byte
448
- end
449
- return check == data[-1] # Check the check sum equals the last element
450
- else
451
- return true
452
- end
453
- end
454
-
455
-
456
- #
457
- # Builds the command and creates the checksum
458
- #
459
- def send_checksum(type, command, options = {})
460
- #
461
- # build header + command and convert to a byte array
462
- #
463
- command = "" << 0x02 << command << 0x03
464
- command = "0*0#{MSG_TYPE[type]}#{command.length.to_s(16).upcase.rjust(2, '0')}#{command}"
465
- command = str_to_array(command)
466
-
467
- #
468
- # build checksum
469
- #
470
- check = 0
471
- command.each do |byte|
472
- check = check ^ byte
473
- end
474
-
475
- command << check # Add checksum
476
- command << 0x0D # delimiter required by NEC displays
477
- command.insert(0, 0x01) # insert SOH byte (not part of the checksum)
478
-
479
- send(command, options)
480
- end
39
+ #
40
+ # Called on module load complete
41
+ # Alternatively you can use initialize however will
42
+ # not have access to settings and this is called
43
+ # soon afterwards
44
+ #
45
+ def on_load
46
+ #
47
+ # Setup constants
48
+ #
49
+ self[:volume_min] = 0
50
+ self[:brightness_min] = 0
51
+ self[:contrast_min] = 0
52
+ #self[:error] = [] TODO!!
53
+
54
+ config({
55
+ tokenize: true,
56
+ delimiter: "\x0D",
57
+ encoding: "ASCII-8BIT"
58
+ })
59
+ end
60
+
61
+ def connected
62
+ do_poll
63
+
64
+ @polling_timer = schedule.every('30s') do
65
+ logger.debug "-- Polling Display"
66
+ do_poll
67
+ end
68
+ end
69
+
70
+ def disconnected
71
+ #
72
+ # Disconnected may be called without calling connected
73
+ # Hence the check if timer is nil here
74
+ #
75
+ @polling_timer.cancel unless @polling_timer.nil?
76
+ @polling_timer = nil
77
+ end
78
+
79
+
80
+ #
81
+ # Power commands
82
+ #
83
+ def power(state)
84
+ message = "C203D6"
85
+
86
+ power? do
87
+ current = self[:power]
88
+ if is_affirmative?(state)
89
+ if current == Off
90
+ message += "0001" # Power On
91
+ send_checksum(:command, message, {:name => :power})
92
+ self[:warming] = true
93
+ self[:power] = On
94
+ logger.debug "-- NEC LCD, requested to power on"
95
+
96
+ power_on_delay
97
+ mute_status(0)
98
+ volume_status(0)
99
+ end
100
+ else
101
+ if current == On
102
+ message += "0004" # Power Off
103
+ send_checksum(:command, message, {:name => :power})
104
+
105
+ self[:power] = Off
106
+ logger.debug "-- NEC LCD, requested to power off"
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ def power?(options = {}, &block)
113
+ options[:emit] = block if block_given?
114
+ type = :command
115
+ message = "01D6"
116
+ send_checksum(type, message, options)
117
+ end
118
+
119
+
120
+ #
121
+ # Input selection
122
+ #
123
+ INPUTS = {
124
+ :vga => 1,
125
+ :rgbhv => 2,
126
+ :dvi => 3,
127
+ :hdmi_set => 4, # Set only?
128
+ :video1 => 5,
129
+ :video2 => 6,
130
+ :svideo => 7,
131
+
132
+ :tv => 10,
133
+ :dvd1 => 12,
134
+ :option => 13,
135
+ :dvd2 => 14,
136
+ :display_port => 15,
137
+
138
+ :hdmi => 17
139
+ }
140
+ def switch_to(input)
141
+ input = input.to_sym if input.class == String
142
+ #self[:target_input] = input
143
+
144
+ type = :set_parameter
145
+ message = OPERATION_CODE[:video_input]
146
+ message += INPUTS[input].to_s(16).upcase.rjust(4, '0') # Value of input as a hex string
147
+
148
+ send_checksum(type, message, {:name => :input})
149
+ brightness_status(60) # higher status than polling commands - lower than input switching
150
+ contrast_status(60)
151
+
152
+ logger.debug "-- NEC LCD, requested to switch to: #{input}"
153
+ end
154
+
155
+ AUDIO = {
156
+ :audio1 => 1,
157
+ :audio2 => 2,
158
+ :audio3 => 3,
159
+ :hdmi => 4,
160
+ :tv => 6,
161
+ :display_port => 7
162
+ }
163
+ def switch_audio(input)
164
+ input = input.to_sym if input.class == String
165
+ #self[:target_audio] = input
166
+
167
+ type = :set_parameter
168
+ message = OPERATION_CODE[:audio_input]
169
+ message += AUDIO[input].to_s(16).upcase.rjust(4, '0') # Value of input as a hex string
170
+
171
+ send_checksum(type, message, :name => :audio)
172
+ mute_status(60) # higher status than polling commands - lower than input switching
173
+ volume_status(60)
174
+
175
+ logger.debug "-- NEC LCD, requested to switch audio to: #{input}"
176
+ end
177
+
178
+
179
+ #
180
+ # Auto adjust
181
+ #
182
+ def auto_adjust
183
+ message = OPERATION_CODE[:auto_setup] #"001E" # Page + OP code
184
+ message += "0001" # Value of input as a hex string
185
+
186
+ send_checksum(:set_parameter, message, :delay_on_receive => 4.0)
187
+ end
188
+
189
+
190
+ #
191
+ # Value based set parameter
192
+ #
193
+ def brightness(val)
194
+ val = in_range(val.to_i, 100)
195
+
196
+ message = OPERATION_CODE[:brightness_status]
197
+ message += val.to_s(16).upcase.rjust(4, '0') # Value of input as a hex string
198
+
199
+ brightness_status
200
+ send_checksum(:set_parameter, message)
201
+ send_checksum(:command, '0C') # Save the settings
202
+ end
203
+
204
+ def contrast(val)
205
+ val = in_range(val.to_i, 100)
206
+
207
+ message = OPERATION_CODE[:contrast_status]
208
+ message += val.to_s(16).upcase.rjust(4, '0') # Value of input as a hex string
209
+
210
+ contrast_status
211
+ send_checksum(:set_parameter, message)
212
+ send_checksum(:command, '0C') # Save the settings
213
+ end
214
+
215
+ def volume(val)
216
+ val = in_range(val.to_i, 100)
217
+
218
+ message = OPERATION_CODE[:volume_status]
219
+ message += val.to_s(16).upcase.rjust(4, '0') # Value of input as a hex string
220
+
221
+ volume_status
222
+ send_checksum(:set_parameter, message)
223
+ send_checksum(:command, '0C') # Save the settings
224
+
225
+ self[:audio_mute] = false # audio is unmuted when the volume is set
226
+ end
227
+
228
+
229
+ def mute_audio
230
+ message = OPERATION_CODE[:mute_status]
231
+ message += "0001" # Value of input as a hex string
232
+
233
+ send_checksum(:set_parameter, message)
234
+
235
+ logger.debug "-- NEC LCD, requested to mute audio"
236
+ end
237
+ alias_method :mute, :mute_audio
238
+
239
+ def unmute_audio
240
+ message = OPERATION_CODE[:mute_status]
241
+ message += "0000" # Value of input as a hex string
242
+
243
+ send_checksum(:set_parameter, message)
244
+
245
+ logger.debug "-- NEC LCD, requested to unmute audio"
246
+ end
247
+ alias_method :unmute, :unmute_audio
248
+
249
+ #
250
+ # LCD Response code
251
+ #
252
+ def received(data, resolve, command)
253
+ #
254
+ # Check for valid response
255
+ #
256
+ if !check_checksum(data)
257
+ logger.debug "-- NEC LCD, checksum failed for command: #{command[:data]}"
258
+ logger.debug "-- NEC LCD, response was: #{data}"
259
+ return false
260
+ end
261
+
262
+ #data = array_to_str(data) # Convert bytes to a string (received like this)
263
+
264
+ case MSG_TYPE[data[4]] # Check the MSG_TYPE (B, D or F)
265
+ when :command_reply
266
+ #
267
+ # Power on and off
268
+ # 8..9 == "00" means no error
269
+ if data[10..15] == "C203D6" # Means power comamnd
270
+ if data[8..9] == "00"
271
+ power_on_delay(0) # wait until the screen has turned on before sending commands (0 == high priority)
272
+ else
273
+ logger.info "-- NEC LCD, command failed: #{command[:data]}"
274
+ logger.info "-- NEC LCD, response was: #{data}"
275
+ return false # command failed
276
+ end
277
+ elsif data[10..13] == "00D6" # Power status response
278
+ if data[10..11] == "00"
279
+ if data[23] == '1' # On == 1, Off == 4
280
+ self[:power] = On
281
+ else
282
+ self[:power] = Off
283
+ self[:warming] = false
284
+ end
285
+ #if self[:power_target].nil?
286
+ # self[:power_target] = self[:power]
287
+ #elsif self[:power_target] != self[:power]
288
+ # power(self[:power_target])
289
+ #end
290
+ else
291
+ logger.info "-- NEC LCD, command failed: #{command[:data]}"
292
+ logger.info "-- NEC LCD, response was: #{data}"
293
+ return false # command failed
294
+ end
295
+
296
+ end
297
+
298
+ when :get_parameter_reply, :set_parameter_reply
299
+ if data[8..9] == "00"
300
+ parse_response(data, command)
301
+ elsif data[8..9] == 'BE' # Wait response
302
+ send(command[:data]) # checksum already added
303
+ logger.debug "-- NEC LCD, response was a wait command"
304
+ else
305
+ logger.info "-- NEC LCD, get or set failed: #{command[:data]}"
306
+ logger.info "-- NEC LCD, response was: #{data}"
307
+ return false
308
+ end
309
+ end
310
+
311
+ return true # Command success
312
+ end
313
+
314
+
315
+ def do_poll
316
+ power?({:priority => 0}) do
317
+ if self[:power] == On
318
+ power_on_delay
319
+ mute_status
320
+ volume_status
321
+ brightness_status
322
+ contrast_status
323
+ video_input
324
+ audio_input
325
+ end
326
+ end
327
+ end
328
+
329
+
330
+ private
331
+
332
+
333
+ def parse_response(data, command)
334
+
335
+ # 14..15 == type (we don't care)
336
+ max = data[16..19].to_i(16)
337
+ value = data[20..23].to_i(16)
338
+
339
+ case OPERATION_CODE[data[10..13]]
340
+ when :video_input
341
+ self[:input] = INPUTS.invert[value]
342
+ #self[:target_input] = self[:input] if self[:target_input].nil?
343
+ #switch_to(self[:target_input]) unless self[:input] == self[:target_input]
344
+
345
+ when :audio_input
346
+ self[:audio] = AUDIO.invert[value]
347
+ #self[:target_audio] = self[:audio] if self[:target_audio].nil?
348
+ #switch_audio(self[:target_audio]) unless self[:audio] == self[:target_audio]
349
+
350
+ when :volume_status
351
+ self[:volume_max] = max
352
+ if not self[:audio_mute]
353
+ self[:volume] = value
354
+ end
355
+
356
+ when :brightness_status
357
+ self[:brightness_max] = max
358
+ self[:brightness] = value
359
+
360
+ when :contrast_status
361
+ self[:contrast_max] = max
362
+ self[:contrast] = value
363
+
364
+ when :mute_status
365
+ self[:audio_mute] = value == 1
366
+ if(value == 1)
367
+ self[:volume] = 0
368
+ else
369
+ volume_status(0) # high priority
370
+ end
371
+
372
+ when :power_on_delay
373
+ if value > 0
374
+ self[:warming] = true
375
+ schedule.in("#{value}s") do # Prevent any commands being sent until the power on delay is complete
376
+ power_on_delay
377
+ end
378
+ else
379
+ schedule.in('3s') do # Reactive the interface once the display is online
380
+ self[:warming] = false # allow access to the display
381
+ end
382
+ end
383
+ when :auto_setup
384
+ # auto_setup
385
+ # nothing needed to do here (we are delaying the next command by 4 seconds)
386
+ else
387
+ logger.info "-- NEC LCD, unknown response: #{data[10..13]}"
388
+ logger.info "-- NEC LCD, for command: #{command[:data]}"
389
+ logger.info "-- NEC LCD, full response was: #{data}"
390
+ end
391
+ end
392
+
393
+
394
+ #
395
+ # Types of messages sent to and from the LCD
396
+ #
397
+ MSG_TYPE = {
398
+ :command => 'A',
399
+ 'B' => :command_reply,
400
+ :get_parameter => 'C',
401
+ 'D' => :get_parameter_reply,
402
+ :set_parameter => 'E',
403
+ 'F' => :set_parameter_reply
404
+ }
405
+
406
+
407
+ OPERATION_CODE = {
408
+ :video_input => '0060', '0060' => :video_input,
409
+ :audio_input => '022E', '022E' => :audio_input,
410
+ :volume_status => '0062', '0062' => :volume_status,
411
+ :mute_status => '008D', '008D' => :mute_status,
412
+ :power_on_delay => '02D8', '02D8' => :power_on_delay,
413
+ :contrast_status => '0012', '0012' => :contrast_status,
414
+ :brightness_status => '0010', '0010' => :brightness_status,
415
+ :auto_setup => '001E', '001E' => :auto_setup
416
+ }
417
+ #
418
+ # Automatically creates a callable function for each command
419
+ # http://blog.jayfields.com/2007/10/ruby-defining-class-methods.html
420
+ # http://blog.jayfields.com/2008/02/ruby-dynamically-define-method.html
421
+ #
422
+ OPERATION_CODE.each_key do |command|
423
+ define_method command do |*args|
424
+ priority = 99
425
+ if args.length > 0
426
+ priority = args[0]
427
+ end
428
+ message = OPERATION_CODE[command]
429
+ send_checksum(:get_parameter, message, {:priority => priority}) # Status polling is a low priority
430
+ end
431
+ end
432
+
433
+
434
+ def check_checksum(data)
435
+ data = str_to_array(data)
436
+
437
+ check = 0
438
+ #
439
+ # Loop through the second to the second last element
440
+ # Delimiter is removed automatically
441
+ #
442
+ if data.length >= 2
443
+ data[1..-2].each do |byte|
444
+ check = check ^ byte
445
+ end
446
+ return check == data[-1] # Check the check sum equals the last element
447
+ else
448
+ return true
449
+ end
450
+ end
451
+
452
+
453
+ #
454
+ # Builds the command and creates the checksum
455
+ #
456
+ def send_checksum(type, command, options = {})
457
+ #
458
+ # build header + command and convert to a byte array
459
+ #
460
+ command = "" << 0x02 << command << 0x03
461
+ command = "0*0#{MSG_TYPE[type]}#{command.length.to_s(16).upcase.rjust(2, '0')}#{command}"
462
+ command = str_to_array(command)
463
+
464
+ #
465
+ # build checksum
466
+ #
467
+ check = 0
468
+ command.each do |byte|
469
+ check = check ^ byte
470
+ end
471
+
472
+ command << check # Add checksum
473
+ command << 0x0D # delimiter required by NEC displays
474
+ command.insert(0, 0x01) # insert SOH byte (not part of the checksum)
475
+
476
+ send(command, options)
477
+ end
481
478
  end
482
479