2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.sonyprojector.internal.communication;
15 import java.io.IOException;
16 import java.io.InputStream;
17 import java.io.OutputStream;
18 import java.util.Arrays;
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.openhab.binding.sonyprojector.internal.SonyProjectorException;
23 import org.openhab.binding.sonyprojector.internal.SonyProjectorModel;
24 import org.openhab.core.i18n.CommunicationException;
25 import org.openhab.core.i18n.ConnectionException;
26 import org.openhab.core.library.types.OnOffType;
27 import org.openhab.core.util.HexUtils;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
32 * Class for communicating with Sony Projectors
34 * @author Markus Wehrle - Initial contribution
35 * @author Laurent Garnier - Refactoring to include new channels, consider serial connection and protocol depending on
37 * @author Laurent Garnier - Allow sending any IR command
40 public abstract class SonyProjectorConnector {
42 private final Logger logger = LoggerFactory.getLogger(SonyProjectorConnector.class);
44 private static final byte[] DUMMY_DATA = new byte[] { 0x00, 0x00 };
45 private static final byte[] POWER_ON = new byte[] { 0x00, 0x01 };
46 private static final byte[] POWER_OFF = new byte[] { 0x00, 0x00 };
47 private static final byte[] OVERSCAN_ON = new byte[] { 0x00, 0x01 };
48 private static final byte[] OVERSCAN_OFF = new byte[] { 0x00, 0x00 };
49 private static final byte[] PICTURE_ON = new byte[] { 0x00, 0x01 };
50 private static final byte[] PICTURE_OFF = new byte[] { 0x00, 0x00 };
51 private static final byte[] XVCOLOR_ON = new byte[] { 0x00, 0x01 };
52 private static final byte[] XVCOLOR_OFF = new byte[] { 0x00, 0x00 };
54 private SonyProjectorModel model;
56 /** The output stream */
57 protected @Nullable OutputStream dataOut;
59 /** The input stream */
60 protected @Nullable InputStream dataIn;
62 /** true if the connection is established, false if not */
63 protected boolean connected;
70 * @param model the projector model in use
71 * @param simu whether the communication is simulated or real
73 public SonyProjectorConnector(SonyProjectorModel model, boolean simu) {
79 * Set the projector model in use
81 * @param model the projector model in use
83 public void setModel(SonyProjectorModel model) {
88 * Request the projector to get the current power status
90 * @return the current power status
92 * @throws SonyProjectorException in case of any problem
94 public SonyProjectorStatusPower getStatusPower() throws SonyProjectorException {
95 return SonyProjectorStatusPower.getFromDataCode(getSetting(SonyProjectorItem.STATUS_POWER));
99 * Power ON the projector
101 * @throws SonyProjectorException in case the projector is not ready for a power ON command or any other problem
103 public void powerOn() throws SonyProjectorException {
104 SonyProjectorStatusPower status = null;
106 status = getStatusPower();
107 } catch (SonyProjectorException e) {
109 logger.debug("Current Power Status: {}", status == null ? "undefined" : status.toString());
110 if (status != null && status != SonyProjectorStatusPower.STANDBY) {
111 throw new SonyProjectorException("Projector not ready for command ON");
112 } else if (model.isPowerCmdAvailable()) {
113 logger.debug("Set Power ON using Power command");
114 setSetting(SonyProjectorItem.POWER, POWER_ON);
116 logger.debug("Set Power ON using IR Power command");
117 sendIR(SonyProjectorItem.POWER_ON);
118 if (status == null) {
119 sendIR(SonyProjectorItem.POWER_ON);
125 * Power OFF the projector
127 * @throws SonyProjectorException in case the projector is not ready for a power OFF command or any other problem
129 public void powerOff() throws SonyProjectorException {
130 SonyProjectorStatusPower status = null;
132 status = getStatusPower();
133 } catch (SonyProjectorException e) {
135 logger.debug("Current Power Status: {}", status == null ? "undefined" : status.toString());
136 if (status == null || status != SonyProjectorStatusPower.POWER_ON) {
137 throw new SonyProjectorException("Projector not ready for command OFF");
138 } else if (model.isPowerCmdAvailable()) {
139 logger.debug("Set Power OFF using Power command");
140 setSetting(SonyProjectorItem.POWER, POWER_OFF);
142 logger.debug("Set Power OFF using IR Power command");
143 sendIR(SonyProjectorItem.POWER_OFF);
148 * Request the projector to get the current calibration preset
150 * @return the current calibration preset
152 * @throws SonyProjectorException in case of any problem
154 public String getCalibrationPreset() throws SonyProjectorException {
155 return model.getCalibrPresetNameFromDataCode(getSetting(SonyProjectorItem.CALIBRATION_PRESET));
159 * Request the projector to change the calibration preset
161 * @param value the calibration preset to set
163 * @throws SonyProjectorException in case of any problem
165 public void setCalibrationPreset(String value) throws SonyProjectorException {
166 setSetting(SonyProjectorItem.CALIBRATION_PRESET, model.getCalibrPresetFromName(value).getDataCode());
170 * Request the projector to get the current video input
172 * @return the current video input
174 * @throws SonyProjectorException in case of any problem
176 public String getInput() throws SonyProjectorException {
177 return model.getInputNameFromDataCode(getSetting(SonyProjectorItem.INPUT));
181 * Request the projector to change the video input
183 * @param value the video input to set
185 * @throws SonyProjectorException in case of any problem
187 public void setInput(String value) throws SonyProjectorException {
188 setSetting(SonyProjectorItem.INPUT, model.getInputFromName(value).getDataCode());
192 * Request the projector to get the current contrast setting
194 * @return the current contrast value
196 * @throws SonyProjectorException in case of any problem
198 public int getContrast() throws SonyProjectorException {
199 return convertDataToInt(getSetting(SonyProjectorItem.CONTRAST));
203 * Request the projector to change the contrast setting
205 * @param value the contrast value to set
207 * @throws SonyProjectorException in case of any problem
209 public void setContrast(int value) throws SonyProjectorException {
210 setSetting(SonyProjectorItem.CONTRAST, convertIntToData(value));
214 * Request the projector to get the current brightness setting
216 * @return the current brightness value
218 * @throws SonyProjectorException in case of any problem
220 public int getBrightness() throws SonyProjectorException {
221 return convertDataToInt(getSetting(SonyProjectorItem.BRIGHTNESS));
225 * Request the projector to change the brightness setting
227 * @param value the brightness value to set
229 * @throws SonyProjectorException in case of any problem
231 public void setBrightness(int value) throws SonyProjectorException {
232 setSetting(SonyProjectorItem.BRIGHTNESS, convertIntToData(value));
236 * Request the projector to get the current color setting
238 * @return the current color value
240 * @throws SonyProjectorException in case of any problem
242 public int getColor() throws SonyProjectorException {
243 return convertDataToInt(getSetting(SonyProjectorItem.COLOR));
247 * Request the projector to change the color setting
249 * @param value the color value to set
251 * @throws SonyProjectorException in case of any problem
253 public void setColor(int value) throws SonyProjectorException {
254 setSetting(SonyProjectorItem.COLOR, convertIntToData(value));
258 * Request the projector to get the current hue setting
260 * @return the current hue value
262 * @throws SonyProjectorException in case of any problem
264 public int getHue() throws SonyProjectorException {
265 return convertDataToInt(getSetting(SonyProjectorItem.HUE));
269 * Request the projector to change the hue setting
271 * @param value the hue value to set
273 * @throws SonyProjectorException in case of any problem
275 public void setHue(int value) throws SonyProjectorException {
276 setSetting(SonyProjectorItem.HUE, convertIntToData(value));
280 * Request the projector to get the current sharpness setting
282 * @return the current sharpness value
284 * @throws SonyProjectorException in case of any problem
286 public int getSharpness() throws SonyProjectorException {
287 return convertDataToInt(getSetting(SonyProjectorItem.SHARPNESS));
291 * Request the projector to change the sharpness setting
293 * @param value the sharpness value to set
295 * @throws SonyProjectorException in case of any problem
297 public void setSharpness(int value) throws SonyProjectorException {
298 setSetting(SonyProjectorItem.SHARPNESS, convertIntToData(value));
302 * Request the projector to get the current contrast enhancer mode
304 * @return the current contrast enhancer mode
306 * @throws SonyProjectorException in case of any problem
308 public String getContrastEnhancer() throws SonyProjectorException {
309 return model.getContrastEnhancerNameFromDataCode(getSetting(SonyProjectorItem.CONTRAST_ENHANCER));
313 * Request the projector to change the contrast enhancer mode
315 * @param value the contrast enhancer mode to set
317 * @throws SonyProjectorException in case of any problem
319 public void setContrastEnhancer(String value) throws SonyProjectorException {
320 setSetting(SonyProjectorItem.CONTRAST_ENHANCER, model.getContrastEnhancerDataCodeFromName(value));
324 * Request the projector to get the current film mode
326 * @return the current film mode
328 * @throws SonyProjectorException in case this setting is not available for the projector or any other problem
330 public String getFilmMode() throws SonyProjectorException {
331 if (!model.isFilmModeAvailable()) {
332 throw new SonyProjectorException("Unavailable item " + SonyProjectorItem.FILM_MODE.getName()
333 + " for projector model " + model.getName());
335 return model.getFilmModeNameFromDataCode(getSetting(SonyProjectorItem.FILM_MODE));
339 * Request the projector to change the film mode
341 * @param value the film mode to set
343 * @throws SonyProjectorException in case this setting is not available for the projector or any other problem
345 public void setFilmMode(String value) throws SonyProjectorException {
346 if (!model.isFilmModeAvailable()) {
347 throw new SonyProjectorException("Unavailable item " + SonyProjectorItem.FILM_MODE.getName()
348 + " for projector model " + model.getName());
350 setSetting(SonyProjectorItem.FILM_MODE, model.getFilmModeDataCodeFromName(value));
354 * Request the projector to get the lamp use time
356 * @return the lamp use time
358 * @throws SonyProjectorException in case of any problem
360 public int getLampUseTime() throws SonyProjectorException {
361 return convertDataToInt(getSetting(SonyProjectorItem.LAMP_USE_TIME));
365 * Request the projector to get the current mode for the lamp control setting
367 * @return the current mode for the lamp control setting
369 * @throws SonyProjectorException in case this setting is not available for the projector or any other problem
371 public String getLampControl() throws SonyProjectorException {
372 if (!model.isLampControlAvailable()) {
373 throw new SonyProjectorException("Unavailable item " + SonyProjectorItem.LAMP_CONTROL.getName()
374 + " for projector model " + model.getName());
376 return SonyProjectorLampControl.getFromDataCode(getSetting(SonyProjectorItem.LAMP_CONTROL)).getName();
380 * Request the projector to change the mode for the lamp control setting
382 * @param value the mode to set for the lamp control setting
384 * @throws SonyProjectorException in case this setting is not available for the projector or any other problem
386 public void setLampControl(String value) throws SonyProjectorException {
387 if (!model.isLampControlAvailable()) {
388 throw new SonyProjectorException("Unavailable item " + SonyProjectorItem.LAMP_CONTROL.getName()
389 + " for projector model " + model.getName());
391 setSetting(SonyProjectorItem.LAMP_CONTROL, SonyProjectorLampControl.getFromName(value).getDataCode());
395 * Request the projector if the picture is muted or not
397 * @return OnOffType.ON if the picture is muted, OnOffType.OFF if not
399 * @throws SonyProjectorException in case of any problem
401 public OnOffType getPictureMuting() throws SonyProjectorException {
402 return Arrays.equals(getSetting(SonyProjectorItem.PICTURE_MUTING), PICTURE_ON) ? OnOffType.ON : OnOffType.OFF;
406 * Request the projector to mute the picture
408 * @throws SonyProjectorException in case of any problem
410 public void mutePicture() throws SonyProjectorException {
411 setSetting(SonyProjectorItem.PICTURE_MUTING, PICTURE_ON);
415 * Request the projector to unmute the picture
417 * @throws SonyProjectorException in case of any problem
419 public void unmutePicture() throws SonyProjectorException {
420 setSetting(SonyProjectorItem.PICTURE_MUTING, PICTURE_OFF);
424 * Request the projector to get the current mode for the picture position setting
426 * @return the current mode for the picture position setting
428 * @throws SonyProjectorException in case this setting is not available for the projector or any other problem
430 public String getPicturePosition() throws SonyProjectorException {
431 if (!model.isPicturePositionAvailable()) {
432 throw new SonyProjectorException("Unavailable item " + SonyProjectorItem.PICTURE_POSITION.getName()
433 + " for projector model " + model.getName());
435 return model.getPicturePositionNameFromDataCode(getSetting(SonyProjectorItem.PICTURE_POSITION));
439 * Request the projector to change the mode for the picture position setting
441 * @param value the mode to set for the picture position setting
443 * @throws SonyProjectorException in case this setting is not available for the projector or any other problem
445 public void setPicturePosition(String value) throws SonyProjectorException {
446 if (!model.isPicturePositionAvailable()) {
447 throw new SonyProjectorException("Unavailable item " + SonyProjectorItem.PICTURE_POSITION.getName()
448 + " for projector model " + model.getName());
450 setSetting(SonyProjectorItem.PICTURE_POSITION, model.getPicturePositionCodeFromName(value));
454 * Request the projector if the overscan is enabled or not
456 * @return OnOffType.ON if the overscan is enabled, OnOffType.OFF if not
458 * @throws SonyProjectorException in case this setting is not available for the projector or any other problem
460 public OnOffType getOverscan() throws SonyProjectorException {
461 if (!model.isOverscanAvailable()) {
462 throw new SonyProjectorException("Unavailable item " + SonyProjectorItem.OVERSCAN.getName()
463 + " for projector model " + model.getName());
465 return Arrays.equals(getSetting(SonyProjectorItem.OVERSCAN), OVERSCAN_ON) ? OnOffType.ON : OnOffType.OFF;
469 * Request the projector to enable the overscan
471 * @throws SonyProjectorException in case this setting is not available for the projector or any other problem
473 public void enableOverscan() throws SonyProjectorException {
474 if (!model.isOverscanAvailable()) {
475 throw new SonyProjectorException("Unavailable item " + SonyProjectorItem.OVERSCAN.getName()
476 + " for projector model " + model.getName());
478 setSetting(SonyProjectorItem.OVERSCAN, OVERSCAN_ON);
482 * Request the projector to disable the overscan
484 * @throws SonyProjectorException in case this setting is not available for the projector or any other problem
486 public void disableOverscan() throws SonyProjectorException {
487 if (!model.isOverscanAvailable()) {
488 throw new SonyProjectorException("Unavailable item " + SonyProjectorItem.OVERSCAN.getName()
489 + " for projector model " + model.getName());
491 setSetting(SonyProjectorItem.OVERSCAN, OVERSCAN_OFF);
495 * Request the projector to get the current aspect ratio mode
497 * @return the current current aspect ratio mode
499 * @throws SonyProjectorException in case of any problem
501 public String getAspect() throws SonyProjectorException {
502 return model.getAspectNameFromDataCode(getSetting(SonyProjectorItem.ASPECT));
506 * Request the projector to change the aspect ratio mode
508 * @param value the aspect ratio mode to set
510 * @throws SonyProjectorException in case of any problem
512 public void setAspect(String value) throws SonyProjectorException {
513 setSetting(SonyProjectorItem.ASPECT, model.getAspectFromName(value).getDataCode());
517 * Request the projector to get the current color temperature setting
519 * @return the current color temperature value
521 * @throws SonyProjectorException in case of any problem
523 public String getColorTemperature() throws SonyProjectorException {
524 return model.getColorTempNameFromDataCode(getSetting(SonyProjectorItem.COLOR_TEMP));
528 * Request the projector to change the color temperature setting
530 * @param value the color temperature value to set
532 * @throws SonyProjectorException in case of any problem
534 public void setColorTemperature(String value) throws SonyProjectorException {
535 setSetting(SonyProjectorItem.COLOR_TEMP, model.getColorTempCodeFromName(value));
539 * Request the projector to get the current iris mode
541 * @return the current iris mode
543 * @throws SonyProjectorException in case this setting is not available for the projector or any other problem
545 public String getIrisMode() throws SonyProjectorException {
546 if (!model.isIrisModeAvailable()) {
547 throw new SonyProjectorException("Unavailable item " + SonyProjectorItem.IRIS_MODE.getName()
548 + " for projector model " + model.getName());
550 return model.getIrisModeNameFromDataCode(getSetting(SonyProjectorItem.IRIS_MODE));
554 * Request the projector to change the iris mode
556 * @param value the iris mode to set
558 * @throws SonyProjectorException in case this setting is not available for the projector or any other problem
560 public void setIrisMode(String value) throws SonyProjectorException {
561 if (!model.isIrisModeAvailable()) {
562 throw new SonyProjectorException("Unavailable item " + SonyProjectorItem.IRIS_MODE.getName()
563 + " for projector model " + model.getName());
565 setSetting(SonyProjectorItem.IRIS_MODE, model.getIrisModeCodeFromName(value));
569 * Request the projector to get the current iris manual setting
571 * @return the current value for the iris manual setting
573 * @throws SonyProjectorException in case this setting is not available for the projector or any other problem
575 public int getIrisManual() throws SonyProjectorException {
576 if (!model.isIrisManualAvailable()) {
577 throw new SonyProjectorException("Unavailable item " + SonyProjectorItem.IRIS_MANUAL.getName()
578 + " for projector model " + model.getName());
580 return convertDataToInt(getSetting(SonyProjectorItem.IRIS_MANUAL));
584 * Request the projector to change the iris manual setting
586 * @param value the iris manual value to set
588 * @throws SonyProjectorException in case this setting is not available for the projector or any other problem
590 public void setIrisManual(int value) throws SonyProjectorException {
591 if (!model.isIrisManualAvailable()) {
592 throw new SonyProjectorException("Unavailable item " + SonyProjectorItem.IRIS_MANUAL.getName()
593 + " for projector model " + model.getName());
595 setSetting(SonyProjectorItem.IRIS_MANUAL, convertIntToData(value));
599 * Request the projector to get the current iris sensitivity
601 * @return the current iris sensitivity
603 * @throws SonyProjectorException in case this setting is not available for the projector or any other problem
605 public String getIrisSensitivity() throws SonyProjectorException {
606 if (!model.isIrisSensitivityAvailable()) {
607 throw new SonyProjectorException("Unavailable item " + SonyProjectorItem.IRIS_SENSITIVITY.getName()
608 + " for projector model " + model.getName());
610 return SonyProjectorIrisSensitivity.getFromDataCode(getSetting(SonyProjectorItem.IRIS_SENSITIVITY)).getName();
614 * Request the projector to change the iris sensitivity
616 * @param value the iris sensitivity to set
618 * @throws SonyProjectorException in case this setting is not available for the projector or any other problem
620 public void setIrisSensitivity(String value) throws SonyProjectorException {
621 if (!model.isIrisSensitivityAvailable()) {
622 throw new SonyProjectorException("Unavailable item " + SonyProjectorItem.IRIS_SENSITIVITY.getName()
623 + " for projector model " + model.getName());
625 setSetting(SonyProjectorItem.IRIS_SENSITIVITY, SonyProjectorIrisSensitivity.getFromName(value).getDataCode());
629 * Request the projector to get the current film projection mode
631 * @return the current film projection mode
633 * @throws SonyProjectorException in case this setting is not available for the projector or any other problem
635 public String getFilmProjection() throws SonyProjectorException {
636 if (!model.isFilmProjectionAvailable()) {
637 throw new SonyProjectorException("Unavailable item " + SonyProjectorItem.FILM_PROJECTION.getName()
638 + " for projector model " + model.getName());
640 return model.getFilmProjectionNameFromDataCode(getSetting(SonyProjectorItem.FILM_PROJECTION));
644 * Request the projector to change the film projection mode
646 * @param value the film projection mode to set
648 * @throws SonyProjectorException in case this setting is not available for the projector or any other problem
650 public void setFilmProjection(String value) throws SonyProjectorException {
651 if (!model.isFilmProjectionAvailable()) {
652 throw new SonyProjectorException("Unavailable item " + SonyProjectorItem.FILM_PROJECTION.getName()
653 + " for projector model " + model.getName());
655 setSetting(SonyProjectorItem.FILM_PROJECTION, model.getFilmProjectionCodeFromName(value));
659 * Request the projector to get the current motion enhancer mode
661 * @return the current motion enhancer mode
663 * @throws SonyProjectorException in case of any problem
665 public String getMotionEnhancer() throws SonyProjectorException {
666 if (!model.isMotionEnhancerAvailable()) {
667 throw new SonyProjectorException("Unavailable item " + SonyProjectorItem.MOTION_ENHANCER.getName()
668 + " for projector model " + model.getName());
670 return model.getMotionEnhancerNameFromDataCode(getSetting(SonyProjectorItem.MOTION_ENHANCER));
674 * Request the projector to change the motion enhancer mode
676 * @param value the motion enhancer mode to set
678 * @throws SonyProjectorException in case this setting is not available for the projector or any other problem
680 public void setMotionEnhancer(String value) throws SonyProjectorException {
681 if (!model.isMotionEnhancerAvailable()) {
682 throw new SonyProjectorException("Unavailable item " + SonyProjectorItem.MOTION_ENHANCER.getName()
683 + " for projector model " + model.getName());
685 setSetting(SonyProjectorItem.MOTION_ENHANCER, model.getMotionEnhancerCodeFromName(value));
689 * Request the projector to get the current gamma correction
691 * @return the current gamma correction
693 * @throws SonyProjectorException in case of any problem
695 public String getGammaCorrection() throws SonyProjectorException {
696 return model.getGammaCorrectionNameFromDataCode(getSetting(SonyProjectorItem.GAMMA_CORRECTION));
700 * Request the projector to change the gamma correction
702 * @param value the gamma correction to set
704 * @throws SonyProjectorException in case of any problem
706 public void setGammaCorrection(String value) throws SonyProjectorException {
707 setSetting(SonyProjectorItem.GAMMA_CORRECTION, model.getGammaCorrectionCodeFromName(value));
711 * Request the projector to get the current color space
713 * @return the current color space
715 * @throws SonyProjectorException in case of any problem
717 public String getColorSpace() throws SonyProjectorException {
718 return model.getColorSpaceNameFromDataCode(getSetting(SonyProjectorItem.COLOR_SPACE));
722 * Request the projector to change the color space
724 * @param value the color space to set
726 * @throws SonyProjectorException in case of any problem
728 public void setColorSpace(String value) throws SonyProjectorException {
729 setSetting(SonyProjectorItem.COLOR_SPACE, model.getColorSpaceCodeFromName(value));
733 * Request the projector to get the current noise reduction mode
735 * @return the current noise reduction mode
737 * @throws SonyProjectorException in case of any problem
739 public String getNr() throws SonyProjectorException {
740 return model.getNrNameFromDataCode(getSetting(SonyProjectorItem.NR));
744 * Request the projector to change the noise reduction mode
746 * @param value the noise reduction mode to set
748 * @throws SonyProjectorException in case of any problem
750 public void setNr(String value) throws SonyProjectorException {
751 setSetting(SonyProjectorItem.NR, model.getNrCodeFromName(value));
755 * Request the projector to get the current block noise reduction mode
757 * @return the current block noise reduction mode
759 * @throws SonyProjectorException in case this setting is not available for the projector or any other problem
761 public String getBlockNr() throws SonyProjectorException {
762 if (!model.isBlockNrAvailable()) {
763 throw new SonyProjectorException("Unavailable item " + SonyProjectorItem.BLOCK_NR.getName()
764 + " for projector model " + model.getName());
766 return SonyProjectorBlockNr.getFromDataCode(getSetting(SonyProjectorItem.BLOCK_NR)).getName();
770 * Request the projector to change the block noise reduction mode
772 * @param value the block noise reduction mode to set
774 * @throws SonyProjectorException in case this setting is not available for the projector or any other problem
776 public void setBlockNr(String value) throws SonyProjectorException {
777 if (!model.isBlockNrAvailable()) {
778 throw new SonyProjectorException("Unavailable item " + SonyProjectorItem.BLOCK_NR.getName()
779 + " for projector model " + model.getName());
781 setSetting(SonyProjectorItem.BLOCK_NR, SonyProjectorBlockNr.getFromName(value).getDataCode());
785 * Request the projector to get the current mosquito noise reduction mode
787 * @return the current mosquito noise reduction mode
789 * @throws SonyProjectorException in case this setting is not available for the projector or any other problem
791 public String getMosquitoNr() throws SonyProjectorException {
792 if (!model.isMosquitoNrAvailable()) {
793 throw new SonyProjectorException("Unavailable item " + SonyProjectorItem.MOSQUITO_NR.getName()
794 + " for projector model " + model.getName());
796 return SonyProjectorMosquitoNr.getFromDataCode(getSetting(SonyProjectorItem.MOSQUITO_NR)).getName();
800 * Request the projector to change the mosquito noise reduction mode
802 * @param value the mosquito noise reduction mode to set
804 * @throws SonyProjectorException in case this setting is not available for the projector or any other problem
806 public void setMosquitoNr(String value) throws SonyProjectorException {
807 if (!model.isMosquitoNrAvailable()) {
808 throw new SonyProjectorException("Unavailable item " + SonyProjectorItem.MOSQUITO_NR.getName()
809 + " for projector model " + model.getName());
811 setSetting(SonyProjectorItem.MOSQUITO_NR, SonyProjectorMosquitoNr.getFromName(value).getDataCode());
815 * Request the projector to get the current MPEG noise reduction mode
817 * @return the current MPEG noise reduction mode
819 * @throws SonyProjectorException in case this setting is not available for the projector or any other problem
821 public String getMpegNr() throws SonyProjectorException {
822 if (!model.isMpegNrAvailable()) {
823 throw new SonyProjectorException("Unavailable item " + SonyProjectorItem.MPEG_NR.getName()
824 + " for projector model " + model.getName());
826 return model.getMpegNrNameFromDataCode(getSetting(SonyProjectorItem.MPEG_NR));
830 * Request the projector to change the MPEG noise reduction mode
832 * @param value the MPEG noise reduction mode to set
834 * @throws SonyProjectorException in case this setting is not available for the projector or any other problem
836 public void setMpegNr(String value) throws SonyProjectorException {
837 if (!model.isMpegNrAvailable()) {
838 throw new SonyProjectorException("Unavailable item " + SonyProjectorItem.MPEG_NR.getName()
839 + " for projector model " + model.getName());
841 setSetting(SonyProjectorItem.MPEG_NR, model.getMpegNrCodeFromName(value));
845 * Request the projector to get the current value for xvColor
847 * @return the current value for xvColor
849 * @throws SonyProjectorException in case this setting is not available for the projector or any other problem
851 public OnOffType getXvColor() throws SonyProjectorException {
852 if (!model.isXvColorAvailable()) {
853 throw new SonyProjectorException("Unavailable item " + SonyProjectorItem.XVCOLOR.getName()
854 + " for projector model " + model.getName());
856 return Arrays.equals(getSetting(SonyProjectorItem.XVCOLOR), XVCOLOR_ON) ? OnOffType.ON : OnOffType.OFF;
860 * Request the projector to set xvColor to ON
862 * @throws SonyProjectorException in case this setting is not available for the projector or any other problem
864 public void enableXvColor() throws SonyProjectorException {
865 if (!model.isXvColorAvailable()) {
866 throw new SonyProjectorException("Unavailable item " + SonyProjectorItem.XVCOLOR.getName()
867 + " for projector model " + model.getName());
869 setSetting(SonyProjectorItem.XVCOLOR, XVCOLOR_ON);
873 * Request the projector to set xvColor to OFF
875 * @throws SonyProjectorException in case this setting is not available for the projector or any other problem
877 public void disableXvColor() throws SonyProjectorException {
878 if (!model.isXvColorAvailable()) {
879 throw new SonyProjectorException("Unavailable item " + SonyProjectorItem.XVCOLOR.getName()
880 + " for projector model " + model.getName());
882 setSetting(SonyProjectorItem.XVCOLOR, XVCOLOR_OFF);
886 * Send an IR command to the projector
888 * @param command the IR command
890 * @throws SonyProjectorException in case this IR command is not available or any other problem
892 public void sendIrCommand(String command) throws SonyProjectorException {
893 byte @Nullable [] irCode = null;
894 boolean found = true;
895 if (command.startsWith("INPUT_")) {
897 irCode = model.getInputFromName(command.substring(6)).getIrCode();
898 } catch (SonyProjectorException e) {
901 } else if (command.startsWith("PRESET_")) {
903 irCode = model.getCalibrPresetFromName(command.substring(7)).getIrCode();
904 } catch (SonyProjectorException e) {
907 } else if (command.startsWith("ASPECT_")) {
909 irCode = model.getAspectFromName(command.substring(7)).getIrCode();
910 } catch (SonyProjectorException e) {
915 irCode = SonyProjectorItem.getFromValue(command).getIrCode();
916 } catch (SonyProjectorException e) {
921 // Check if the command is a direct IR code in hexadecimal
922 // Must be 4 characters starting by either 17 or 19 or 1B
923 String cmd = command.trim();
924 if (cmd.length() != 4) {
925 throw new SonyProjectorException("Invalid IR code: " + command);
929 hex = Integer.parseInt(cmd, 16);
930 } catch (NumberFormatException e) {
931 throw new SonyProjectorException("Invalid IR code: " + command, e);
933 irCode = new byte[2];
934 irCode[0] = (byte) ((hex >> 8) & 0x000000FF);
935 irCode[1] = (byte) (hex & 0x000000FF);
937 if (irCode == null || !SonyProjectorItem.isValidIrCode(irCode)) {
938 throw new SonyProjectorException("Invalid IR code: " + command);
944 * Request the projector to get the current value for a setting
946 * @param item the projector setting to get
948 * @return the current value for the setting
950 * @throws SonyProjectorException in case of any problem
952 protected byte[] getSetting(SonyProjectorItem item) throws SonyProjectorException {
953 logger.debug("Get setting {}", item.getName());
956 byte[] result = getResponseData(executeCommand(item, true, DUMMY_DATA));
958 logger.debug("Get setting {} succeeded: result data: {}", item.getName(), HexUtils.bytesToHex(result));
961 } catch (CommunicationException | SonyProjectorException e) {
962 throw new SonyProjectorException("Get setting " + item.getName() + " failed", e);
967 * Request the projector to set a new value for a setting
969 * @param item the projector setting to set
970 * @param data the value to set for the setting
972 * @throws SonyProjectorException in case of any problem
974 private void setSetting(SonyProjectorItem item, byte[] data) throws SonyProjectorException {
975 logger.debug("Set setting {} data {}", item.getName(), HexUtils.bytesToHex(data));
978 executeCommand(item, false, data);
979 } catch (CommunicationException | SonyProjectorException e) {
980 throw new SonyProjectorException("Set setting " + item.getName() + " failed", e);
983 logger.debug("Set setting {} succeeded", item.getName());
987 * Send an IR command to the projector
989 * @param item the IR information to send
991 * @throws SonyProjectorException in case of any problem
993 private void sendIR(SonyProjectorItem item) throws SonyProjectorException {
994 byte @Nullable [] irCode = item.getIrCode();
995 if (irCode == null || !SonyProjectorItem.isValidIrCode(irCode)) {
996 throw new SonyProjectorException("Send IR code failed, code is invalid");
1002 * Send an IR command to the projector
1004 * @param irCode the IR code (2 bytes) to send
1006 * @throws SonyProjectorException in case of any problem
1008 private synchronized void sendIR(byte[] irCode) throws SonyProjectorException {
1009 String codeStr = String.format("%02x%02x", irCode[0], irCode[1]);
1010 logger.debug("Send IR code {}", codeStr);
1013 boolean runningSession = connected;
1017 // Build the message and send it
1018 writeCommand(buildMessage(irCode, false, DUMMY_DATA));
1020 // Wait at least 45 ms
1023 // No response expected for SIRCS commands
1025 if (!runningSession) {
1028 } catch (CommunicationException e) {
1029 throw new SonyProjectorException("Send IR code " + codeStr + " failed", e);
1030 } catch (InterruptedException e) {
1031 Thread.currentThread().interrupt();
1032 throw new SonyProjectorException("Send IR code " + codeStr + " interrupted", e);
1035 logger.debug("Send IR code {} succeeded", codeStr);
1039 * Connect to the projector, write a command, read the response and disconnect
1041 * @param item the projector setting to get or set
1042 * @param getCommand true for a GET command or false for a SET command
1043 * @param data the value to be considered in case of a SET command
1045 * @return the buffer containing the returned message
1047 * @throws ConnectionException in case of any connection problem
1048 * @throws CommunicationException in case of any communication problem
1049 * @throws SonyProjectorException in case of any other problem
1051 private synchronized byte[] executeCommand(SonyProjectorItem item, boolean getCommand, byte[] data)
1052 throws ConnectionException, CommunicationException, SonyProjectorException {
1053 byte @Nullable [] code = item.getCode();
1055 throw new SonyProjectorException("Undefined data code");
1058 boolean runningSession = connected;
1062 // Build the message and send it
1063 writeCommand(buildMessage(code, getCommand, data));
1065 // Read the response
1066 byte[] responseMessage = readResponse();
1068 if (!runningSession) {
1072 // Validate the content of the response
1073 validateResponse(responseMessage, item);
1075 return responseMessage;
1079 * Open the connection with the projector if not yet opened
1081 * @throws ConnectionException in case of any problem
1083 public abstract void open() throws ConnectionException;
1086 * Close the connection with the projector
1088 public void close() {
1090 OutputStream dataOut = this.dataOut;
1091 if (dataOut != null) {
1094 } catch (IOException e) {
1096 this.dataOut = null;
1098 InputStream dataIn = this.dataIn;
1099 if (dataIn != null) {
1102 } catch (IOException e) {
1111 * Build the message buffer corresponding to the request of a particular information
1113 * @param itemCode the code (2 bytes) of the projector setting to get or set
1114 * @param getCommand true for a GET command or false for a SET command
1115 * @param data the value to be considered in case of a SET command
1117 * @return the message buffer
1119 protected abstract byte[] buildMessage(byte[] itemCode, boolean getCommand, byte[] data);
1122 * Reads some number of bytes from the input stream and stores them into the buffer array b. The number of bytes
1123 * actually read is returned as an integer.
1125 * @param dataBuffer the buffer into which the data is read.
1126 * @return the total number of bytes read into the buffer, or -1 if there is no more data because the end of the
1127 * stream has been reached.
1128 * @throws CommunicationException if the input stream is null, if the first byte cannot be read for any reason
1129 * other than the end of the file, if the input stream has been closed, or if some other I/O error
1132 protected int readInput(byte[] dataBuffer) throws CommunicationException {
1134 throw new CommunicationException("readInput failed: should not be called in simu mode");
1136 InputStream dataIn = this.dataIn;
1137 if (dataIn == null) {
1138 throw new CommunicationException("readInput failed: input stream is null");
1141 return dataIn.read(dataBuffer);
1142 } catch (IOException e) {
1143 logger.debug("readInput failed: {}", e.getMessage());
1144 throw new CommunicationException("readInput failed", e);
1149 * Write a command to the output stream
1151 * @param message the buffer containing the message to be sent
1153 * @throws CommunicationException in case of any communication problem
1155 protected void writeCommand(byte[] message) throws CommunicationException {
1156 logger.debug("writeCommand: {}", HexUtils.bytesToHex(message));
1160 OutputStream dataOut = this.dataOut;
1161 if (dataOut == null) {
1162 throw new CommunicationException("writeCommand failed: output stream is null");
1165 dataOut.write(message);
1167 } catch (IOException e) {
1168 logger.debug("writeCommand failed: {}", e.getMessage());
1169 throw new CommunicationException("writeCommand failed", e);
1174 * Read the response from the input stream
1176 * @return the buffer containing the returned message
1178 * @throws CommunicationException in case of any communication problem
1180 protected abstract byte[] readResponse() throws CommunicationException;
1183 * Validate the content of a returned message
1185 * @param responseMessage the buffer containing the returned message
1186 * @param item the projector setting to get or set
1188 * @throws CommunicationException if the message has unexpected content
1190 protected abstract void validateResponse(byte[] responseMessage, SonyProjectorItem item)
1191 throws CommunicationException;
1194 * Extract the value from the returned message
1196 * @param responseMessage the buffer containing the returned message
1198 * @return the value of the projector setting that was requested
1200 protected abstract byte[] getResponseData(byte[] responseMessage);
1202 private int convertDataToInt(byte[] data) {
1203 return ((data[0] & 0x000000FF) << 8) | (data[1] & 0x000000FF);
1206 private byte[] convertIntToData(int value) {
1207 byte[] data = new byte[2];
1208 data[0] = (byte) ((value & 0x0000FF00) >> 8);
1209 data[1] = (byte) (value & 0x000000FF);