aca-device-modules 1.0.3 → 1.0.4
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 +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
|
+
|