aca-device-modules 1.0.3 → 1.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/aca-device-modules/version.rb +1 -1
- data/modules/biamp/nexia.rb +45 -26
- data/modules/bss/blu100.rb +49 -31
- data/modules/chiyu/cyt.rb +183 -0
- data/modules/epson/projector/esc_vp21.rb +5 -0
- data/modules/kramer/switcher/protocol3000.rb +243 -0
- data/modules/nec/display/all.rb +482 -0
- data/modules/nec/projector/np_series.rb +648 -0
- data/modules/panasonic/projector/tcp.rb +250 -0
- data/modules/screen_technics/connect.rb +73 -0
- data/modules/sony/display/{gdx_and_fwd.rb → id_talk.rb} +38 -7
- data/modules/sony/projector/pj_talk.rb +300 -0
- data/modules/transmitsms/api.rb +52 -0
- data/modules/vaddio/camera/clear_view_ptz_telnet.rb +3 -3
- metadata +11 -4
- data/modules/panasonic/projector/pj_link.rb +0 -266
@@ -0,0 +1,648 @@
|
|
1
|
+
module Nec; end
|
2
|
+
module Nec::Projector; end
|
3
|
+
|
4
|
+
|
5
|
+
# :title:All NEC Control Module (default port - )
|
6
|
+
#
|
7
|
+
# Controls all NEC projectors as of 9/01/2011
|
8
|
+
# Status information avaliable:
|
9
|
+
# -----------------------------
|
10
|
+
#
|
11
|
+
# (built in)
|
12
|
+
# connected
|
13
|
+
#
|
14
|
+
# (module defined)
|
15
|
+
# error (array of strings)
|
16
|
+
#
|
17
|
+
# lamp_status
|
18
|
+
# lamp_target
|
19
|
+
# lamp_warming
|
20
|
+
# lamp_cooling
|
21
|
+
# lamp_usage (array of integers representing hours)
|
22
|
+
# filter_usage
|
23
|
+
#
|
24
|
+
# volume
|
25
|
+
# volume_min == 0
|
26
|
+
# volume_max == 63
|
27
|
+
#
|
28
|
+
# zoom
|
29
|
+
# zoom_min
|
30
|
+
# zoom_max
|
31
|
+
#
|
32
|
+
# mute (picture and audio)
|
33
|
+
# picture_mute
|
34
|
+
# audio_mute
|
35
|
+
# onscreen_mute
|
36
|
+
# picture_freeze
|
37
|
+
#
|
38
|
+
# target_input
|
39
|
+
# input_selected
|
40
|
+
#
|
41
|
+
# model_name
|
42
|
+
# model_series
|
43
|
+
#
|
44
|
+
#
|
45
|
+
|
46
|
+
|
47
|
+
class Nec::Projector::NpSeries
|
48
|
+
include ::Orchestrator::Constants
|
49
|
+
include ::Orchestrator::Transcoder
|
50
|
+
|
51
|
+
def on_unload
|
52
|
+
end
|
53
|
+
|
54
|
+
def on_update
|
55
|
+
self[:power_stable] = true
|
56
|
+
self[:input_stable] = true
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
#
|
62
|
+
# Sets up any constants
|
63
|
+
#
|
64
|
+
def on_load
|
65
|
+
|
66
|
+
#
|
67
|
+
# Setup constants
|
68
|
+
#
|
69
|
+
self[:volume_min] = 0
|
70
|
+
self[:volume_max] = 63
|
71
|
+
self[:lamp_usage] = []
|
72
|
+
self[:filter_usage] = []
|
73
|
+
self[:error] = []
|
74
|
+
|
75
|
+
self[:power_stable] = true
|
76
|
+
self[:input_stable] = true
|
77
|
+
end
|
78
|
+
|
79
|
+
#
|
80
|
+
# Connect and request projector status
|
81
|
+
# NOTE:: Only connected and disconnected are threadsafe
|
82
|
+
# Access of other variables should be protected outside of these functions
|
83
|
+
#
|
84
|
+
def connected
|
85
|
+
#
|
86
|
+
# Get current state of the projector
|
87
|
+
#
|
88
|
+
do_poll
|
89
|
+
|
90
|
+
#
|
91
|
+
# Get the state every 50 seconds :)
|
92
|
+
#
|
93
|
+
@polling_timer = schedule.every('50s') do
|
94
|
+
do_poll
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def disconnected
|
99
|
+
#
|
100
|
+
# Perform any cleanup functions here
|
101
|
+
#
|
102
|
+
@polling_timer.cancel unless @polling_timer.nil?
|
103
|
+
@polling_timer = nil
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
#
|
108
|
+
# Command Listing
|
109
|
+
# Second byte used to detect command type
|
110
|
+
#
|
111
|
+
COMMAND = {
|
112
|
+
# Mute controls
|
113
|
+
:mute_picture => "$02,$10,$00,$00,$00,$12",
|
114
|
+
:unmute_picture => "$02,$11,$00,$00,$00,$13",
|
115
|
+
:mute_audio => "02H 12H 00H 00H 00H 14H",
|
116
|
+
:unmute_audio => "02H 13H 00H 00H 00H 15H",
|
117
|
+
:mute_onscreen => "02H 14H 00H 00H 00H 16H",
|
118
|
+
:unmute_onscreen => "02H 15H 00H 00H 00H 17H",
|
119
|
+
|
120
|
+
:freeze_picture => "$01,$98,$00,$00,$01,$01,$9B",
|
121
|
+
:unfreeze_picture =>"$01,$98,$00,$00,$01,$02,$9C",
|
122
|
+
|
123
|
+
:status_lamp => "00H 81H 00H 00H 00H 81H", # Running sense (ret 81)
|
124
|
+
:status_input => "$00,$85,$00,$00,$01,$02,$88", # Input status (ret 85)
|
125
|
+
:status_mute => "00H 85H 00H 00H 01H 03H 89H", # MUTE STATUS REQUEST (Check 10H on byte 5)
|
126
|
+
:status_error => "00H 88H 00H 00H 00H 88H", # ERROR STATUS REQUEST (ret 88)
|
127
|
+
:status_model => "00H 85H 00H 00H 01H 04H 8A", # request model name (both of these are related)
|
128
|
+
|
129
|
+
# lamp hours / remaining information
|
130
|
+
:lamp_information => "03H 8AH 00H 00H 00H 8DH", # LAMP INFORMATION REQUEST
|
131
|
+
:filter_information => "03H 8AH 00H 00H 00H 8DH",
|
132
|
+
:projector_information => "03H 8AH 00H 00H 00H 8DH",
|
133
|
+
|
134
|
+
:background_black =>"$03,$B1,$00,$00,$02,$0B,$01,$C2", # set mute to be a black screen
|
135
|
+
:background_blue => "$03,$B1,$00,$00,$02,$0B,$00,$C1", # set mute to be a blue screen
|
136
|
+
:background_logo => "$03,$B1,$00,$00,$02,$0B,$02,$C3" # set mute to be the company logo
|
137
|
+
}
|
138
|
+
|
139
|
+
|
140
|
+
#
|
141
|
+
# Automatically creates a callable function for each command
|
142
|
+
# http://blog.jayfields.com/2007/10/ruby-defining-class-methods.html
|
143
|
+
# http://blog.jayfields.com/2008/02/ruby-dynamically-define-method.html
|
144
|
+
#
|
145
|
+
COMMAND.each_key do |command|
|
146
|
+
define_method command do
|
147
|
+
send(COMMAND[command], :hex_string => true, :name => command)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
|
152
|
+
#
|
153
|
+
# Volume Modification
|
154
|
+
#
|
155
|
+
def volume(vol)
|
156
|
+
# volume base command D1 D2 D3 D4 D5 + CKS
|
157
|
+
command = [0x03, 0x10, 0x00, 0x00, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00]
|
158
|
+
# D3 = 00 (absolute vol) or 01 (relative vol)
|
159
|
+
# D4 = value (lower bits 0 to 63)
|
160
|
+
# D5 = value (higher bits always 00h)
|
161
|
+
|
162
|
+
vol = 63 if vol > 63
|
163
|
+
vol = 0 if vol < 0
|
164
|
+
command[-2] = vol
|
165
|
+
|
166
|
+
self[:volume] = vol
|
167
|
+
|
168
|
+
send_checksum(command)
|
169
|
+
end
|
170
|
+
|
171
|
+
#
|
172
|
+
# Mutes everything
|
173
|
+
#
|
174
|
+
def mute(state = true)
|
175
|
+
if state
|
176
|
+
mute_picture
|
177
|
+
mute_onscreen
|
178
|
+
else
|
179
|
+
unmute
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
#
|
184
|
+
# unmutes everything desirable
|
185
|
+
#
|
186
|
+
def unmute
|
187
|
+
unmute_picture
|
188
|
+
end
|
189
|
+
|
190
|
+
#
|
191
|
+
# Sets the lamp power value
|
192
|
+
#
|
193
|
+
def power(power)
|
194
|
+
#:lamp_on => "$02,$00,$00,$00,$00,$02",
|
195
|
+
#:lamp_off => "$02,$01,$00,$00,$00,$03",
|
196
|
+
self[:power_stable] = false
|
197
|
+
|
198
|
+
command = [0x02, 0x00, 0x00, 0x00, 0x00, 0x02]
|
199
|
+
if is_affirmative?(power)
|
200
|
+
command[1] += 1 # power off
|
201
|
+
command[-1] += 1 # checksum
|
202
|
+
self[:power_target] = Off
|
203
|
+
else
|
204
|
+
self[:power_target] = On
|
205
|
+
end
|
206
|
+
|
207
|
+
send(command, :name => :power)
|
208
|
+
end
|
209
|
+
|
210
|
+
def power?(options = {}, &block)
|
211
|
+
options[:emit] = block if block_given?
|
212
|
+
options[:hex_string] = true
|
213
|
+
send(COMMAND[:status_lamp], options)
|
214
|
+
end
|
215
|
+
|
216
|
+
|
217
|
+
INPUTS = {
|
218
|
+
:vga1 => 0x01,
|
219
|
+
:vga => 0x01,
|
220
|
+
:rgbhv => 0x02, # \
|
221
|
+
:dvi_a => 0x02, # } - all of these are the same
|
222
|
+
:vga2 => 0x02, # /
|
223
|
+
|
224
|
+
:composite => 0x06,
|
225
|
+
:svideo => 0x0B,
|
226
|
+
|
227
|
+
:component1 => 0x10,
|
228
|
+
:component => 0x10,
|
229
|
+
:component2 => 0x11,
|
230
|
+
|
231
|
+
:hdmi => 0x1A, # \
|
232
|
+
:dvi => 0x1A, # | - These are the same
|
233
|
+
:hdmi2 => 0x1B,
|
234
|
+
|
235
|
+
:lan => 0x20,
|
236
|
+
:viewer => 0x1F
|
237
|
+
}
|
238
|
+
def switch_to(input)
|
239
|
+
input = input.to_sym if input.class == String
|
240
|
+
|
241
|
+
#
|
242
|
+
# Input status update
|
243
|
+
# As much for internal use as external
|
244
|
+
# and with the added benefit of being thread safe
|
245
|
+
#
|
246
|
+
self[:target_input] = input # should do this for power on and off (ensures correct state)
|
247
|
+
self[:input_stable] = false
|
248
|
+
|
249
|
+
command = [0x02, 0x03, 0x00, 0x00, 0x02, 0x01]
|
250
|
+
command << INPUTS[input]
|
251
|
+
send_checksum(command, :name => :input)
|
252
|
+
end
|
253
|
+
|
254
|
+
|
255
|
+
#
|
256
|
+
# Return true if command success, nil if still waiting, false if fail
|
257
|
+
#
|
258
|
+
def received(data, resolve, command)
|
259
|
+
response = data
|
260
|
+
data = str_to_array(data)
|
261
|
+
command[:data] = str_to_array(command[:data]) unless command[:data].nil?
|
262
|
+
|
263
|
+
logger.info "NEC projector sent: 0x#{byte_to_hex(response)}"
|
264
|
+
|
265
|
+
#
|
266
|
+
# Command failed
|
267
|
+
#
|
268
|
+
if data[0] & 0xA0 == 0xA0
|
269
|
+
#
|
270
|
+
# We were changing power state at time of failure we should keep trying
|
271
|
+
#
|
272
|
+
if [0x00, 0x01].include?(command[:data][1])
|
273
|
+
command[:delay_on_receive] = 6
|
274
|
+
power?
|
275
|
+
return true
|
276
|
+
end
|
277
|
+
logger.info "-- NEC projector, sent fail code for command: 0x#{byte_to_hex(command[:data])}"
|
278
|
+
logger.info "-- NEC projector, response was: 0x#{byte_to_hex(response)}"
|
279
|
+
return false
|
280
|
+
end
|
281
|
+
|
282
|
+
#
|
283
|
+
# Check checksum
|
284
|
+
#
|
285
|
+
if !check_checksum(data)
|
286
|
+
logger.debug "-- NEC projector, checksum failed for command: 0x#{byte_to_hex(command[:data])}"
|
287
|
+
return false
|
288
|
+
end
|
289
|
+
|
290
|
+
#
|
291
|
+
# Process a successful command
|
292
|
+
# add 0x20 to the first byte of the send command
|
293
|
+
# Then match the second byte to the second byte of the send command
|
294
|
+
#
|
295
|
+
case data[0]
|
296
|
+
when 0x20
|
297
|
+
case data[1]
|
298
|
+
when 0x81
|
299
|
+
process_power_status(data, command)
|
300
|
+
return true
|
301
|
+
when 0x88
|
302
|
+
process_error_status(data, command)
|
303
|
+
return true
|
304
|
+
when 0x85
|
305
|
+
case command[:data][-2]
|
306
|
+
when 0x02
|
307
|
+
process_input_state(data, command)
|
308
|
+
return true
|
309
|
+
when 0x03
|
310
|
+
process_mute_state(data, command)
|
311
|
+
return true
|
312
|
+
end
|
313
|
+
end
|
314
|
+
when 0x22
|
315
|
+
case data[1]
|
316
|
+
when 0x03
|
317
|
+
return process_input_switch(data, command)
|
318
|
+
when 0x00, 0x01
|
319
|
+
process_lamp_command(data, command)
|
320
|
+
return true
|
321
|
+
when 0x10, 0x11, 0x12, 0x13, 0x14, 0x15
|
322
|
+
status_mute # update mute status's (dry)
|
323
|
+
return true
|
324
|
+
end
|
325
|
+
when 0x23
|
326
|
+
case data[1]
|
327
|
+
when 0x10
|
328
|
+
#
|
329
|
+
# Picture, Volume, Keystone, Image adjust mode
|
330
|
+
# how to play this?
|
331
|
+
#
|
332
|
+
# TODO:: process volume control
|
333
|
+
#
|
334
|
+
return true
|
335
|
+
when 0x8A
|
336
|
+
process_projector_information(data, command)
|
337
|
+
return true
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
logger.warn "-- NEC projector, no status updates defined for response: #{byte_to_hex(response)}"
|
342
|
+
logger.warn "-- NEC projector, command was: 0x#{byte_to_hex(command[:data])}"
|
343
|
+
return true # to prevent retries on commands we were not expecting
|
344
|
+
end
|
345
|
+
|
346
|
+
|
347
|
+
private # All response handling functions should be private so they cannot be called from the outside world
|
348
|
+
|
349
|
+
|
350
|
+
#
|
351
|
+
# The polling routine for the projector
|
352
|
+
#
|
353
|
+
def do_poll
|
354
|
+
power?({:priority => 0})
|
355
|
+
#status_input
|
356
|
+
#projector_information
|
357
|
+
#status_error
|
358
|
+
end
|
359
|
+
|
360
|
+
|
361
|
+
#
|
362
|
+
# Process the lamp on/off command response
|
363
|
+
#
|
364
|
+
def process_lamp_command(data, command)
|
365
|
+
logger.debug "-- NEC projector sent a response to a power command"
|
366
|
+
|
367
|
+
#
|
368
|
+
# Ensure a change of power state was the last command sent
|
369
|
+
#
|
370
|
+
#self[:power] = data[1] == 0x00
|
371
|
+
if command.present?
|
372
|
+
last = command[:data]
|
373
|
+
if [0x00, 0x01].include?(last[1])
|
374
|
+
power? # Queues the status power command
|
375
|
+
end
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
#
|
380
|
+
# Process the lamp status response
|
381
|
+
# Intimately entwinded with the power power command
|
382
|
+
# (as we need to control ensure we are in the correct target state)
|
383
|
+
#
|
384
|
+
def process_power_status(data, command)
|
385
|
+
logger.debug "-- NEC projector sent a response to a power status command"
|
386
|
+
|
387
|
+
self[:power] = (data[-2] & 0b10) > 0x0 # Power on?
|
388
|
+
|
389
|
+
if (data[-2] & 0b100000) > 0 || (data[-2] & 0b10000000) > 0
|
390
|
+
# Projector cooling || power on off processing
|
391
|
+
|
392
|
+
if self[:power_target] == On
|
393
|
+
self[:cooling] = false
|
394
|
+
self[:warming] = true
|
395
|
+
|
396
|
+
logger.debug "power warming..."
|
397
|
+
|
398
|
+
|
399
|
+
elsif self[:power_target] == Off
|
400
|
+
self[:warming] = false
|
401
|
+
self[:cooling] = true
|
402
|
+
|
403
|
+
logger.debug "power cooling..."
|
404
|
+
end
|
405
|
+
|
406
|
+
|
407
|
+
command[:delay_on_receive] = 4
|
408
|
+
power? # Then re-queue this command
|
409
|
+
|
410
|
+
|
411
|
+
# Signal processing
|
412
|
+
elsif (data[-2] & 0b1000000) > 0
|
413
|
+
command[:delay_on_receive] = 3
|
414
|
+
power? # Then re-queue this command
|
415
|
+
else
|
416
|
+
#
|
417
|
+
# We are in a stable state!
|
418
|
+
#
|
419
|
+
if (self[:power] != self[:power_target]) && !self[:power_stable]
|
420
|
+
if self[:power_target].nil?
|
421
|
+
self[:power_target] = self[:power] # setup initial state if the control system is just coming online
|
422
|
+
self[:power_stable] = true
|
423
|
+
else
|
424
|
+
#
|
425
|
+
# if we are in an undesirable state then correct it
|
426
|
+
#
|
427
|
+
logger.debug "NEC projector in an undesirable power state... (Correcting)"
|
428
|
+
power(self[:power_target])
|
429
|
+
|
430
|
+
#
|
431
|
+
# ensures lamp targets are set in case of disconnect
|
432
|
+
#
|
433
|
+
command[:delay_on_receive] = 15
|
434
|
+
end
|
435
|
+
else
|
436
|
+
logger.debug "NEC projector is in a good power state..."
|
437
|
+
|
438
|
+
self[:warming] = false
|
439
|
+
self[:cooling] = false
|
440
|
+
self[:power_stable] = true
|
441
|
+
|
442
|
+
#
|
443
|
+
# Ensure the input is in the correct state unless the lamp is off
|
444
|
+
#
|
445
|
+
status_input unless self[:power] == Off # calls status mute
|
446
|
+
end
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
|
451
|
+
#
|
452
|
+
# NEC has different values for the input status when compared to input selection
|
453
|
+
#
|
454
|
+
INPUT_MAP = {
|
455
|
+
0x01 => {
|
456
|
+
0x01 => [:vga, :vga1],
|
457
|
+
0x02 => [:composite],
|
458
|
+
0x03 => [:svideo],
|
459
|
+
0x06 => [:hdmi, :dvi],
|
460
|
+
0x07 => [:viewer]
|
461
|
+
},
|
462
|
+
0x02 => {
|
463
|
+
0x01 => [:vga2, :dvi_a, :rgbhv],
|
464
|
+
0x04 => [:component2],
|
465
|
+
0x06 => [:hdmi2],
|
466
|
+
0x07 => [:lan]
|
467
|
+
},
|
468
|
+
0x03 => {
|
469
|
+
0x04 => [:component, :component1]
|
470
|
+
}
|
471
|
+
}
|
472
|
+
def process_input_state(data, command)
|
473
|
+
logger.debug "-- NEC projector sent a response to an input state command"
|
474
|
+
|
475
|
+
|
476
|
+
return if self[:power] == Off # no point doing anything here if the projector is off
|
477
|
+
|
478
|
+
self[:input_selected] = INPUT_MAP[data[-15]][data[-14]]
|
479
|
+
self[:input] = self[:input_selected].nil? ? :unknown : self[:input_selected][0]
|
480
|
+
if data[-17] == 0x01
|
481
|
+
command[:delay_on_receive] = 3 # still processing signal
|
482
|
+
status_input
|
483
|
+
else
|
484
|
+
status_mute # get mute status one signal has settled
|
485
|
+
end
|
486
|
+
|
487
|
+
#
|
488
|
+
# Notify of bad input selection for debugging
|
489
|
+
# We ensure at the very least power state and input are always correct
|
490
|
+
#
|
491
|
+
if !self[:input_selected].include?(self[:target_input]) && !self[:input_stable]
|
492
|
+
if self[:target_input].nil?
|
493
|
+
self[:target_input] = self[:input_selected][0]
|
494
|
+
self[:input_stable] = true
|
495
|
+
else
|
496
|
+
switch_to(self[:target_input])
|
497
|
+
logger.debug "-- NEC input state may not be correct, desired: #{self[:target_input]} current: #{self[:input_selected]}"
|
498
|
+
end
|
499
|
+
else
|
500
|
+
self[:input_stable] = true
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
504
|
+
|
505
|
+
#
|
506
|
+
# Check the input switching command was successful
|
507
|
+
#
|
508
|
+
def process_input_switch(data, command)
|
509
|
+
logger.debug "-- NEC projector responded to switch input command"
|
510
|
+
|
511
|
+
if data[-2] != 0xFF
|
512
|
+
status_input # Double check with a status update
|
513
|
+
return true
|
514
|
+
end
|
515
|
+
|
516
|
+
logger.debug "-- NEC projector failed to switch input with command: #{byte_to_hex(command[:data])}"
|
517
|
+
return false # retry the command
|
518
|
+
end
|
519
|
+
|
520
|
+
|
521
|
+
#
|
522
|
+
# Process the mute state response
|
523
|
+
#
|
524
|
+
def process_mute_state(data, command)
|
525
|
+
logger.debug "-- NEC projector responded to mute state command"
|
526
|
+
|
527
|
+
self[:picture_mute] = data[-17] == 0x01
|
528
|
+
self[:audio_mute] = data[-16] == 0x01
|
529
|
+
self[:onscreen_mute] = data[-15] == 0x01
|
530
|
+
|
531
|
+
#if !self[:onscreen_mute] && self[:power]
|
532
|
+
#
|
533
|
+
# Always mute onscreen
|
534
|
+
#
|
535
|
+
# mute_onscreen
|
536
|
+
#end
|
537
|
+
|
538
|
+
self[:mute] = data[-17] == 0x01 # Same as picture mute
|
539
|
+
end
|
540
|
+
|
541
|
+
|
542
|
+
#
|
543
|
+
# Process projector information response
|
544
|
+
# lamp1 hours + filter hours
|
545
|
+
#
|
546
|
+
def process_projector_information(data, command)
|
547
|
+
logger.debug "-- NEC projector sent a response to a projector information command"
|
548
|
+
|
549
|
+
lamp = 0
|
550
|
+
filter = 0
|
551
|
+
|
552
|
+
#
|
553
|
+
# get lamp usage
|
554
|
+
#
|
555
|
+
shift = 0
|
556
|
+
data[87..90].each do |byte|
|
557
|
+
lamp += byte << shift
|
558
|
+
shift += 8
|
559
|
+
end
|
560
|
+
|
561
|
+
#
|
562
|
+
# get filter usage
|
563
|
+
#
|
564
|
+
shift = 0
|
565
|
+
data[91..94].each do |byte|
|
566
|
+
filter += byte << shift
|
567
|
+
shift += 8
|
568
|
+
end
|
569
|
+
|
570
|
+
self[:lamp_usage] = [lamp / 3600] # Lamp usage in hours
|
571
|
+
self[:filter_usage] = [filter / 3600]
|
572
|
+
end
|
573
|
+
|
574
|
+
|
575
|
+
#
|
576
|
+
# provide all the error information required
|
577
|
+
#
|
578
|
+
ERROR_CODES = [{
|
579
|
+
0b1 => "Lamp cover error",
|
580
|
+
0b10 => "Temperature error (Bimetal)",
|
581
|
+
#0b100 == not used
|
582
|
+
0b1000 => "Fan Error",
|
583
|
+
0b10000 => "Fan Error",
|
584
|
+
0b100000 => "Power Error",
|
585
|
+
0b1000000 => "Lamp Error",
|
586
|
+
0b10000000 => "Lamp has reached its end of life"
|
587
|
+
}, {
|
588
|
+
0b1 => "Lamp has been used beyond its limit",
|
589
|
+
0b10 => "Formatter error",
|
590
|
+
0b100 => "Lamp no.2 Error"
|
591
|
+
}, {
|
592
|
+
#0b1 => "not used",
|
593
|
+
0b10 => "FPGA error",
|
594
|
+
0b100 => "Temperature error (Sensor)",
|
595
|
+
0b1000 => "Lamp housing error",
|
596
|
+
0b10000 => "Lamp data error",
|
597
|
+
0b100000 => "Mirror cover error",
|
598
|
+
0b1000000 => "Lamp no.2 has reached its end of life",
|
599
|
+
0b10000000 => "Lamp no.2 has been used beyond its limit"
|
600
|
+
}, {
|
601
|
+
0b1 => "Lamp no.2 housing error",
|
602
|
+
0b10 => "Lamp no.2 data error",
|
603
|
+
0b100 => "High temperature due to dust pile-up",
|
604
|
+
0b1000 => "A foreign object sensor error"
|
605
|
+
}]
|
606
|
+
def process_error_status(data, command)
|
607
|
+
logger.debug "-- NEC projector sent a response to an error status command"
|
608
|
+
|
609
|
+
errors = []
|
610
|
+
error = data[5..8]
|
611
|
+
error.each_index do |byte_no|
|
612
|
+
if error[byte_no] > 0 # run throught each byte
|
613
|
+
ERROR_CODES[byte_no].each_key do |key| # if error indicated run though each key
|
614
|
+
if (key & error[byte_no]) > 0 # check individual bits
|
615
|
+
errors << ERROR_CODES[byte_no][key] # add errors to the error list
|
616
|
+
end
|
617
|
+
end
|
618
|
+
end
|
619
|
+
end
|
620
|
+
self[:error] = errors
|
621
|
+
end
|
622
|
+
|
623
|
+
|
624
|
+
#
|
625
|
+
# For commands that require a checksum (volume, zoom)
|
626
|
+
#
|
627
|
+
def send_checksum(command, options = {})
|
628
|
+
#
|
629
|
+
# Prepare command for sending
|
630
|
+
#
|
631
|
+
command = str_to_array(hex_to_byte(command)) unless command.class == Array
|
632
|
+
check = 0
|
633
|
+
command.each do |byte| # Loop through the first to second last element
|
634
|
+
check = (check + byte) & 0xFF
|
635
|
+
end
|
636
|
+
command << check
|
637
|
+
send(command, options)
|
638
|
+
end
|
639
|
+
|
640
|
+
def check_checksum(data)
|
641
|
+
check = 0
|
642
|
+
data[0..-2].each do |byte| # Loop through the first to second last element
|
643
|
+
check = (check + byte) & 0xFF
|
644
|
+
end
|
645
|
+
return check == data[-1] # Check the check sum equals the last element
|
646
|
+
end
|
647
|
+
end
|
648
|
+
|