aca-device-modules 1.0.4 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -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