[rotel] Refactor to separate comm handling from protocol handling (#12521)
* [rotel] Refactor to separate comm handling from protocol handling Each protocol is now handled in a separate class. Allow to reduce the size of class RotelConnector Signed-off-by: Laurent Garnier <lg.hc@free.fr> * buildCommandMessage now throwing RotelException Comment added when RotelException is catched without any specific handling Signed-off-by: Laurent Garnier <lg.hc@free.fr>
This commit is contained in:
parent
9a7df9fb5b
commit
c1073cd89f
|
@ -161,4 +161,82 @@ public class RotelBindingConstants {
|
|||
|
||||
// List of all properties
|
||||
public static final String PROPERTY_PROTOCOL = "protocol";
|
||||
|
||||
// Message types (HEX protocol)
|
||||
public static final byte PRIMARY_CMD = (byte) 0x10;
|
||||
public static final byte MAIN_ZONE_CMD = (byte) 0x14;
|
||||
public static final byte RECORD_SRC_CMD = (byte) 0x15;
|
||||
public static final byte ZONE2_CMD = (byte) 0x16;
|
||||
public static final byte ZONE3_CMD = (byte) 0x17;
|
||||
public static final byte ZONE4_CMD = (byte) 0x18;
|
||||
public static final byte VOLUME_CMD = (byte) 0x30;
|
||||
public static final byte ZONE2_VOLUME_CMD = (byte) 0x32;
|
||||
public static final byte ZONE3_VOLUME_CMD = (byte) 0x33;
|
||||
public static final byte ZONE4_VOLUME_CMD = (byte) 0x34;
|
||||
public static final byte TRIGGER_CMD = (byte) 0x40;
|
||||
public static final byte STANDARD_RESPONSE = (byte) 0x20;
|
||||
public static final byte TRIGGER_STATUS = (byte) 0x21;
|
||||
public static final byte SMART_DISPLAY_DATA_1 = (byte) 0x22;
|
||||
public static final byte SMART_DISPLAY_DATA_2 = (byte) 0x23;
|
||||
|
||||
// Common (output) keys used by the HEX and ASCII protocols
|
||||
public static final String KEY_POWER = "power";
|
||||
public static final String KEY_VOLUME = "volume";
|
||||
public static final String KEY_MUTE = "mute";
|
||||
public static final String KEY_BASS = "bass";
|
||||
public static final String KEY_TREBLE = "treble";
|
||||
public static final String KEY_SOURCE = "source";
|
||||
public static final String KEY_DSP_MODE = "dsp_mode";
|
||||
public static final String KEY_ERROR = "error";
|
||||
// Keys only used by the ASCII protocol
|
||||
public static final String KEY_UPDATE_MODE = "update_mode";
|
||||
public static final String KEY_DISPLAY_UPDATE = "display_update";
|
||||
public static final String KEY_VOLUME_MIN = "volume_min";
|
||||
public static final String KEY_VOLUME_MAX = "volume_max";
|
||||
public static final String KEY_TONE_MAX = "tone_max";
|
||||
public static final String KEY1_PLAY_STATUS = "play_status";
|
||||
public static final String KEY2_PLAY_STATUS = "status";
|
||||
public static final String KEY_TRACK = "track";
|
||||
public static final String KEY_DIMMER = "dimmer";
|
||||
public static final String KEY_FREQ = "freq";
|
||||
public static final String KEY_TONE = "tone";
|
||||
public static final String KEY_TCBYPASS = "bypass";
|
||||
public static final String KEY_BALANCE = "balance";
|
||||
public static final String KEY_SPEAKER = "speaker";
|
||||
// Output keys only used by the HEX protocol
|
||||
public static final String KEY_LINE1 = "line1";
|
||||
public static final String KEY_LINE2 = "line2";
|
||||
public static final String KEY_RECORD = "record";
|
||||
public static final String KEY_RECORD_SEL = "record_sel";
|
||||
public static final String KEY_ZONE = "zone";
|
||||
public static final String KEY_POWER_ZONE2 = "power_zone2";
|
||||
public static final String KEY_POWER_ZONE3 = "power_zone3";
|
||||
public static final String KEY_POWER_ZONE4 = "power_zone4";
|
||||
public static final String KEY_SOURCE_ZONE2 = "source_zone2";
|
||||
public static final String KEY_SOURCE_ZONE3 = "source_zone3";
|
||||
public static final String KEY_SOURCE_ZONE4 = "source_zone4";
|
||||
public static final String KEY_VOLUME_ZONE2 = "volume_zone2";
|
||||
public static final String KEY_VOLUME_ZONE3 = "volume_zone3";
|
||||
public static final String KEY_VOLUME_ZONE4 = "volume_zone4";
|
||||
public static final String KEY_MUTE_ZONE2 = "mute_zone2";
|
||||
public static final String KEY_MUTE_ZONE3 = "mute_zone3";
|
||||
public static final String KEY_MUTE_ZONE4 = "mute_zone4";
|
||||
|
||||
// Specific values for keys
|
||||
public static final String MSG_VALUE_OFF = "off";
|
||||
public static final String MSG_VALUE_ON = "on";
|
||||
public static final String POWER_ON = "on";
|
||||
public static final String STANDBY = "standby";
|
||||
public static final String POWER_OFF_DELAYED = "off_delayed";
|
||||
public static final String MSG_VALUE_SPEAKER_A = "a";
|
||||
public static final String MSG_VALUE_SPEAKER_B = "b";
|
||||
public static final String MSG_VALUE_SPEAKER_AB = "a_b";
|
||||
public static final String MSG_VALUE_MIN = "min";
|
||||
public static final String MSG_VALUE_MAX = "max";
|
||||
public static final String MSG_VALUE_FIX = "fix";
|
||||
public static final String AUTO = "auto";
|
||||
public static final String MANUAL = "manual";
|
||||
public static final String PLAY = "play";
|
||||
public static final String PAUSE = "pause";
|
||||
public static final String STOP = "stop";
|
||||
}
|
||||
|
|
|
@ -12,13 +12,15 @@
|
|||
*/
|
||||
package org.openhab.binding.rotel.internal;
|
||||
|
||||
import static org.openhab.binding.rotel.internal.communication.RotelCommand.*;
|
||||
import static org.openhab.binding.rotel.internal.protocol.ascii.RotelAbstractAsciiProtocolHandler.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.rotel.internal.communication.RotelCommand;
|
||||
import org.openhab.binding.rotel.internal.communication.RotelConnector;
|
||||
import org.openhab.binding.rotel.internal.communication.RotelDsp;
|
||||
import org.openhab.binding.rotel.internal.communication.RotelFlagsMapping;
|
||||
import org.openhab.binding.rotel.internal.communication.RotelSource;
|
||||
|
@ -32,78 +34,64 @@ import org.openhab.core.types.StateOption;
|
|||
@NonNullByDefault
|
||||
public enum RotelModel {
|
||||
|
||||
RSP1066("RSP-1066", 19200, 3, 1, false, 90, false, 12, false, RotelCommand.ZONE_SELECT, 1, (byte) 0xC2, 13, 8, true,
|
||||
RSP1066("RSP-1066", 19200, 3, 1, false, 90, false, 12, false, ZONE_SELECT, 1, (byte) 0xC2, 13, 8, true,
|
||||
RotelFlagsMapping.MAPPING1),
|
||||
RSP1068("RSP-1068", 19200, 1, 1, true, 96, true, 6, false, RotelCommand.RECORD_FONCTION_SELECT, 2, (byte) 0xA1, 42,
|
||||
5, true, RotelFlagsMapping.MAPPING2),
|
||||
RSP1069("RSP-1069", 38400, 1, 3, true, 96, true, 6, false, RotelCommand.RECORD_FONCTION_SELECT, 2, (byte) 0xA2, 42,
|
||||
5, true, RotelFlagsMapping.MAPPING5),
|
||||
RSP1098("RSP-1098", 19200, 1, 1, true, 96, true, 6, false, RotelCommand.ZONE_SELECT, 2, (byte) 0xA0, 13, 8, true,
|
||||
RotelFlagsMapping.MAPPING1),
|
||||
RSP1570("RSP-1570", 115200, 1, 3, true, 96, true, 6, false, RotelCommand.RECORD_FONCTION_SELECT, 3, (byte) 0xA3, 42,
|
||||
5, true, RotelFlagsMapping.MAPPING5),
|
||||
RSP1572("RSP-1572", 115200, 2, 3, true, 96, true, null, false, RotelCommand.RECORD_FONCTION_SELECT, 4, (byte) 0xA5,
|
||||
42, 5, true, RotelFlagsMapping.MAPPING5),
|
||||
RSX1055("RSX-1055", 19200, 3, 1, false, 90, false, 12, false, RotelCommand.ZONE_SELECT, 1, (byte) 0xC3, 13, 8, true,
|
||||
RotelFlagsMapping.MAPPING1),
|
||||
RSX1056("RSX-1056", 19200, 1, 1, true, 96, true, 12, false, RotelCommand.ZONE_SELECT, 2, (byte) 0xC5, 13, 8, true,
|
||||
RotelFlagsMapping.MAPPING1),
|
||||
RSX1057("RSX-1057", 19200, 1, 1, true, 96, true, 6, false, RotelCommand.RECORD_FONCTION_SELECT, 2, (byte) 0xC7, 13,
|
||||
8, true, RotelFlagsMapping.MAPPING1),
|
||||
RSX1058("RSX-1058", 38400, 1, 3, true, 96, true, 6, false, RotelCommand.RECORD_FONCTION_SELECT, 2, (byte) 0xC8, 13,
|
||||
8, true, RotelFlagsMapping.MAPPING4),
|
||||
RSX1065("RSX-1065", 19200, 3, 1, false, 96, false, 12, false, RotelCommand.ZONE_SELECT, 1, (byte) 0xC1, 42, 5, true,
|
||||
RSP1068("RSP-1068", 19200, 1, 1, true, 96, true, 6, false, RECORD_FONCTION_SELECT, 2, (byte) 0xA1, 42, 5, true,
|
||||
RotelFlagsMapping.MAPPING2),
|
||||
RSX1067("RSX-1067", 19200, 1, 1, true, 96, true, 6, false, RotelCommand.RECORD_FONCTION_SELECT, 2, (byte) 0xC4, 42,
|
||||
5, true, RotelFlagsMapping.MAPPING2),
|
||||
RSX1550("RSX-1550", 115200, 1, 3, true, 96, true, 6, false, RotelCommand.RECORD_FONCTION_SELECT, 3, (byte) 0xC9, 13,
|
||||
8, true, RotelFlagsMapping.MAPPING3),
|
||||
RSX1560("RSX-1560", 115200, 1, 3, true, 96, true, 6, false, RotelCommand.RECORD_FONCTION_SELECT, 3, (byte) 0xCA, 42,
|
||||
5, true, RotelFlagsMapping.MAPPING5),
|
||||
RSX1562("RSX-1562", 115200, 2, 3, true, 96, true, null, false, RotelCommand.RECORD_FONCTION_SELECT, 4, (byte) 0xCC,
|
||||
42, 5, true, RotelFlagsMapping.MAPPING5),
|
||||
A11("A11", 115200, 4, 96, true, 10, 15, false, -1, false, true, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS),
|
||||
A12("A12", 115200, 5, 96, true, 10, 15, false, -1, true, true, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS),
|
||||
A14("A14", 115200, 5, 96, true, 10, 15, false, -1, true, true, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS),
|
||||
CD11("CD11", 57600, 0, null, false, null, true, -1, false, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS),
|
||||
CD14("CD14", 57600, 0, null, false, null, true, -1, false, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS),
|
||||
RA11("RA-11", 115200, 6, 96, true, 10, 15, true, -1, true, false, false, 6, 0, RotelConnector.SPECIAL_CHARACTERS),
|
||||
RA12("RA-12", 115200, 6, 96, true, 10, 15, true, -1, true, false, false, 6, 0, RotelConnector.SPECIAL_CHARACTERS),
|
||||
RA1570("RA-1570", 115200, 7, 96, true, 10, 15, true, -1, true, true, false, 6, 0,
|
||||
RotelConnector.SPECIAL_CHARACTERS),
|
||||
RA1572("RA-1572", 115200, 8, 96, true, 10, 15, false, -1, true, true, true, 6, 0,
|
||||
RotelConnector.SPECIAL_CHARACTERS),
|
||||
RA1592("RA-1592", 115200, 9, 96, true, 10, 15, false, -1, true, true, true, 6, 0,
|
||||
RotelConnector.SPECIAL_CHARACTERS),
|
||||
RAP1580("RAP-1580", 115200, 11, 96, true, null, false, 5, false, false, -10, 10,
|
||||
RotelConnector.NO_SPECIAL_CHARACTERS),
|
||||
RC1570("RC-1570", 115200, 7, 96, true, 10, 15, true, -1, true, false, false, 6, 0,
|
||||
RotelConnector.SPECIAL_CHARACTERS),
|
||||
RC1572("RC-1572", 115200, 8, 96, true, 10, 15, false, -1, true, false, true, 6, 0,
|
||||
RotelConnector.SPECIAL_CHARACTERS),
|
||||
RC1590("RC-1590", 115200, 9, 96, true, 10, 15, false, -1, true, false, true, 6, 0,
|
||||
RotelConnector.SPECIAL_CHARACTERS),
|
||||
RCD1570("RCD-1570", 115200, 0, null, false, null, true, -1, false, true, 6, 0, RotelConnector.SPECIAL_CHARACTERS),
|
||||
RCD1572("RCD-1572", 57600, 0, null, false, null, true, -1, false, true, 6, 0,
|
||||
RotelConnector.SPECIAL_CHARACTERS_RCD1572),
|
||||
RCX1500("RCX-1500", 115200, 17, 86, true, null, true, -1, false, false, null, null,
|
||||
RotelConnector.SPECIAL_CHARACTERS),
|
||||
RDD1580("RDD-1580", 115200, 15, null, false, null, true, -1, true, false, null, null,
|
||||
RotelConnector.NO_SPECIAL_CHARACTERS),
|
||||
RDG1520("RDG-1520", 115200, 16, null, false, null, true, -1, false, false, null, null,
|
||||
RotelConnector.SPECIAL_CHARACTERS),
|
||||
RSP1576("RSP-1576", 115200, 10, 96, true, null, false, 5, false, false, -10, 10,
|
||||
RotelConnector.NO_SPECIAL_CHARACTERS),
|
||||
RSP1582("RSP-1582", 115200, 11, 96, true, null, false, 6, false, false, -10, 10,
|
||||
RotelConnector.NO_SPECIAL_CHARACTERS),
|
||||
RT11("RT-11", 115200, 12, null, false, null, false, -1, false, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS),
|
||||
RT1570("RT-1570", 115200, 14, null, false, null, false, -1, false, true, 6, 0,
|
||||
RotelConnector.NO_SPECIAL_CHARACTERS),
|
||||
T11("T11", 115200, 12, null, false, null, false, -1, false, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS),
|
||||
T14("T14", 115200, 13, null, false, null, false, -1, false, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS),
|
||||
P5("P5", 115200, 20, 96, true, 10, 10, false, -1, true, false, true, 4, 0, RotelConnector.NO_SPECIAL_CHARACTERS),
|
||||
X3("X3", 115200, 18, 96, true, 10, 10, false, -1, true, false, true, 4, 0, RotelConnector.NO_SPECIAL_CHARACTERS),
|
||||
X5("X5", 115200, 19, 96, true, 10, 10, false, -1, true, false, true, 4, 0, RotelConnector.NO_SPECIAL_CHARACTERS);
|
||||
RSP1069("RSP-1069", 38400, 1, 3, true, 96, true, 6, false, RECORD_FONCTION_SELECT, 2, (byte) 0xA2, 42, 5, true,
|
||||
RotelFlagsMapping.MAPPING5),
|
||||
RSP1098("RSP-1098", 19200, 1, 1, true, 96, true, 6, false, ZONE_SELECT, 2, (byte) 0xA0, 13, 8, true,
|
||||
RotelFlagsMapping.MAPPING1),
|
||||
RSP1570("RSP-1570", 115200, 1, 3, true, 96, true, 6, false, RECORD_FONCTION_SELECT, 3, (byte) 0xA3, 42, 5, true,
|
||||
RotelFlagsMapping.MAPPING5),
|
||||
RSP1572("RSP-1572", 115200, 2, 3, true, 96, true, null, false, RECORD_FONCTION_SELECT, 4, (byte) 0xA5, 42, 5, true,
|
||||
RotelFlagsMapping.MAPPING5),
|
||||
RSX1055("RSX-1055", 19200, 3, 1, false, 90, false, 12, false, ZONE_SELECT, 1, (byte) 0xC3, 13, 8, true,
|
||||
RotelFlagsMapping.MAPPING1),
|
||||
RSX1056("RSX-1056", 19200, 1, 1, true, 96, true, 12, false, ZONE_SELECT, 2, (byte) 0xC5, 13, 8, true,
|
||||
RotelFlagsMapping.MAPPING1),
|
||||
RSX1057("RSX-1057", 19200, 1, 1, true, 96, true, 6, false, RECORD_FONCTION_SELECT, 2, (byte) 0xC7, 13, 8, true,
|
||||
RotelFlagsMapping.MAPPING1),
|
||||
RSX1058("RSX-1058", 38400, 1, 3, true, 96, true, 6, false, RECORD_FONCTION_SELECT, 2, (byte) 0xC8, 13, 8, true,
|
||||
RotelFlagsMapping.MAPPING4),
|
||||
RSX1065("RSX-1065", 19200, 3, 1, false, 96, false, 12, false, ZONE_SELECT, 1, (byte) 0xC1, 42, 5, true,
|
||||
RotelFlagsMapping.MAPPING2),
|
||||
RSX1067("RSX-1067", 19200, 1, 1, true, 96, true, 6, false, RECORD_FONCTION_SELECT, 2, (byte) 0xC4, 42, 5, true,
|
||||
RotelFlagsMapping.MAPPING2),
|
||||
RSX1550("RSX-1550", 115200, 1, 3, true, 96, true, 6, false, RECORD_FONCTION_SELECT, 3, (byte) 0xC9, 13, 8, true,
|
||||
RotelFlagsMapping.MAPPING3),
|
||||
RSX1560("RSX-1560", 115200, 1, 3, true, 96, true, 6, false, RECORD_FONCTION_SELECT, 3, (byte) 0xCA, 42, 5, true,
|
||||
RotelFlagsMapping.MAPPING5),
|
||||
RSX1562("RSX-1562", 115200, 2, 3, true, 96, true, null, false, RECORD_FONCTION_SELECT, 4, (byte) 0xCC, 42, 5, true,
|
||||
RotelFlagsMapping.MAPPING5),
|
||||
A11("A11", 115200, 4, 96, true, 10, 15, false, -1, false, true, true, 6, 0, NO_SPECIAL_CHARACTERS),
|
||||
A12("A12", 115200, 5, 96, true, 10, 15, false, -1, true, true, true, 6, 0, NO_SPECIAL_CHARACTERS),
|
||||
A14("A14", 115200, 5, 96, true, 10, 15, false, -1, true, true, true, 6, 0, NO_SPECIAL_CHARACTERS),
|
||||
CD11("CD11", 57600, 0, null, false, null, true, -1, false, true, 6, 0, NO_SPECIAL_CHARACTERS),
|
||||
CD14("CD14", 57600, 0, null, false, null, true, -1, false, true, 6, 0, NO_SPECIAL_CHARACTERS),
|
||||
RA11("RA-11", 115200, 6, 96, true, 10, 15, true, -1, true, false, false, 6, 0, SPECIAL_CHARACTERS),
|
||||
RA12("RA-12", 115200, 6, 96, true, 10, 15, true, -1, true, false, false, 6, 0, SPECIAL_CHARACTERS),
|
||||
RA1570("RA-1570", 115200, 7, 96, true, 10, 15, true, -1, true, true, false, 6, 0, SPECIAL_CHARACTERS),
|
||||
RA1572("RA-1572", 115200, 8, 96, true, 10, 15, false, -1, true, true, true, 6, 0, SPECIAL_CHARACTERS),
|
||||
RA1592("RA-1592", 115200, 9, 96, true, 10, 15, false, -1, true, true, true, 6, 0, SPECIAL_CHARACTERS),
|
||||
RAP1580("RAP-1580", 115200, 11, 96, true, null, false, 5, false, false, -10, 10, NO_SPECIAL_CHARACTERS),
|
||||
RC1570("RC-1570", 115200, 7, 96, true, 10, 15, true, -1, true, false, false, 6, 0, SPECIAL_CHARACTERS),
|
||||
RC1572("RC-1572", 115200, 8, 96, true, 10, 15, false, -1, true, false, true, 6, 0, SPECIAL_CHARACTERS),
|
||||
RC1590("RC-1590", 115200, 9, 96, true, 10, 15, false, -1, true, false, true, 6, 0, SPECIAL_CHARACTERS),
|
||||
RCD1570("RCD-1570", 115200, 0, null, false, null, true, -1, false, true, 6, 0, SPECIAL_CHARACTERS),
|
||||
RCD1572("RCD-1572", 57600, 0, null, false, null, true, -1, false, true, 6, 0, SPECIAL_CHARACTERS_RCD1572),
|
||||
RCX1500("RCX-1500", 115200, 17, 86, true, null, true, -1, false, false, null, null, SPECIAL_CHARACTERS),
|
||||
RDD1580("RDD-1580", 115200, 15, null, false, null, true, -1, true, false, null, null, NO_SPECIAL_CHARACTERS),
|
||||
RDG1520("RDG-1520", 115200, 16, null, false, null, true, -1, false, false, null, null, SPECIAL_CHARACTERS),
|
||||
RSP1576("RSP-1576", 115200, 10, 96, true, null, false, 5, false, false, -10, 10, NO_SPECIAL_CHARACTERS),
|
||||
RSP1582("RSP-1582", 115200, 11, 96, true, null, false, 6, false, false, -10, 10, NO_SPECIAL_CHARACTERS),
|
||||
RT11("RT-11", 115200, 12, null, false, null, false, -1, false, true, 6, 0, NO_SPECIAL_CHARACTERS),
|
||||
RT1570("RT-1570", 115200, 14, null, false, null, false, -1, false, true, 6, 0, NO_SPECIAL_CHARACTERS),
|
||||
T11("T11", 115200, 12, null, false, null, false, -1, false, true, 6, 0, NO_SPECIAL_CHARACTERS),
|
||||
T14("T14", 115200, 13, null, false, null, false, -1, false, true, 6, 0, NO_SPECIAL_CHARACTERS),
|
||||
P5("P5", 115200, 20, 96, true, 10, 10, false, -1, true, false, true, 4, 0, NO_SPECIAL_CHARACTERS),
|
||||
X3("X3", 115200, 18, 96, true, 10, 10, false, -1, true, false, true, 4, 0, NO_SPECIAL_CHARACTERS),
|
||||
X5("X5", 115200, 19, 96, true, 10, 10, false, -1, true, false, true, 4, 0, NO_SPECIAL_CHARACTERS);
|
||||
|
||||
private String name;
|
||||
private int baudRate;
|
||||
|
@ -154,10 +142,9 @@ public enum RotelModel {
|
|||
@Nullable Integer volumeMax, boolean directVolume, @Nullable Integer toneLevelMax, boolean playControl,
|
||||
@Nullable RotelCommand zoneSelectCmd, int dspCategory, byte deviceId, int respNbChars, int respNbFlags,
|
||||
boolean charsBeforeFlags, RotelFlagsMapping flagsMapping) {
|
||||
this(name, baudRate, RotelCommand.DISPLAY_REFRESH, sourceCategory, nbAdditionalZones, additionalCommands,
|
||||
volumeMax, directVolume, toneLevelMax, null, playControl, zoneSelectCmd, dspCategory, false, false,
|
||||
false, null, null, deviceId, respNbChars, respNbFlags, charsBeforeFlags, flagsMapping,
|
||||
RotelConnector.NO_SPECIAL_CHARACTERS);
|
||||
this(name, baudRate, DISPLAY_REFRESH, sourceCategory, nbAdditionalZones, additionalCommands, volumeMax,
|
||||
directVolume, toneLevelMax, null, playControl, zoneSelectCmd, dspCategory, false, false, false, null,
|
||||
null, deviceId, respNbChars, respNbFlags, charsBeforeFlags, flagsMapping, NO_SPECIAL_CHARACTERS);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -181,8 +168,8 @@ public enum RotelModel {
|
|||
@Nullable Integer toneLevelMax, boolean playControl, int dspCategory, boolean getFrequencyAvailable,
|
||||
boolean getDimmerLevelAvailable, @Nullable Integer diummerLevelMin, @Nullable Integer diummerLevelMax,
|
||||
byte[][] specialCharacters) {
|
||||
this(name, baudRate, RotelCommand.POWER, sourceCategory, 0, false, volumeMax, directVolume, toneLevelMax, null,
|
||||
playControl, null, dspCategory, getFrequencyAvailable, false, getDimmerLevelAvailable, diummerLevelMin,
|
||||
this(name, baudRate, POWER, sourceCategory, 0, false, volumeMax, directVolume, toneLevelMax, null, playControl,
|
||||
null, dspCategory, getFrequencyAvailable, false, getDimmerLevelAvailable, diummerLevelMin,
|
||||
diummerLevelMax, (byte) 0, 0, 0, false, RotelFlagsMapping.NO_MAPPING, specialCharacters);
|
||||
}
|
||||
|
||||
|
@ -209,8 +196,8 @@ public enum RotelModel {
|
|||
@Nullable Integer toneLevelMax, @Nullable Integer balanceLevelMax, boolean playControl, int dspCategory,
|
||||
boolean getFrequencyAvailable, boolean getSpeakerGroupsAvailable, boolean getDimmerLevelAvailable,
|
||||
@Nullable Integer diummerLevelMin, @Nullable Integer diummerLevelMax, byte[][] specialCharacters) {
|
||||
this(name, baudRate, RotelCommand.POWER, sourceCategory, 0, false, volumeMax, directVolume, toneLevelMax,
|
||||
balanceLevelMax, playControl, null, dspCategory, getFrequencyAvailable, getSpeakerGroupsAvailable,
|
||||
this(name, baudRate, POWER, sourceCategory, 0, false, volumeMax, directVolume, toneLevelMax, balanceLevelMax,
|
||||
playControl, null, dspCategory, getFrequencyAvailable, getSpeakerGroupsAvailable,
|
||||
getDimmerLevelAvailable, diummerLevelMin, diummerLevelMax, (byte) 0, 0, 0, false,
|
||||
RotelFlagsMapping.NO_MAPPING, specialCharacters);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
*/
|
||||
package org.openhab.binding.rotel.internal.communication;
|
||||
|
||||
import static org.openhab.binding.rotel.internal.RotelBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.rotel.internal.RotelException;
|
||||
|
@ -24,71 +26,71 @@ import org.openhab.binding.rotel.internal.RotelException;
|
|||
@NonNullByDefault
|
||||
public enum RotelCommand {
|
||||
|
||||
POWER_TOGGLE("Power Toggle", RotelConnector.PRIMARY_CMD, (byte) 0x0A, "power_toggle", "power_toggle"),
|
||||
POWER_OFF("Power Off", RotelConnector.PRIMARY_CMD, (byte) 0x4A, "power_off", "power_off"),
|
||||
POWER_ON("Power On", RotelConnector.PRIMARY_CMD, (byte) 0x4B, "power_on", "power_on"),
|
||||
POWER_TOGGLE("Power Toggle", PRIMARY_CMD, (byte) 0x0A, "power_toggle", "power_toggle"),
|
||||
POWER_OFF("Power Off", PRIMARY_CMD, (byte) 0x4A, "power_off", "power_off"),
|
||||
POWER_ON("Power On", PRIMARY_CMD, (byte) 0x4B, "power_on", "power_on"),
|
||||
POWER("Request current power status", "get_current_power", "power?"),
|
||||
ZONE_SELECT("Zone Select", RotelConnector.PRIMARY_CMD, (byte) 0x23),
|
||||
MAIN_ZONE_POWER_TOGGLE("Main Zone Power Toggle", RotelConnector.MAIN_ZONE_CMD, (byte) 0x0A),
|
||||
MAIN_ZONE_POWER_OFF("Main Zone Power Off", RotelConnector.MAIN_ZONE_CMD, (byte) 0x4A),
|
||||
MAIN_ZONE_POWER_ON("Main Zone Power On", RotelConnector.MAIN_ZONE_CMD, (byte) 0x4B),
|
||||
ZONE2_POWER_TOGGLE("Zone 2 Power Toggle", RotelConnector.ZONE2_CMD, (byte) 0x0A),
|
||||
ZONE2_POWER_OFF("Zone 2 Power Off", RotelConnector.ZONE2_CMD, (byte) 0x4A),
|
||||
ZONE2_POWER_ON("Zone 2 Power On", RotelConnector.ZONE2_CMD, (byte) 0x4B),
|
||||
ZONE3_POWER_TOGGLE("Zone 3 Power Toggle", RotelConnector.ZONE3_CMD, (byte) 0x0A),
|
||||
ZONE3_POWER_OFF("Zone 3 Power Off", RotelConnector.ZONE3_CMD, (byte) 0x4A),
|
||||
ZONE3_POWER_ON("Zone 3 Power On", RotelConnector.ZONE3_CMD, (byte) 0x4B),
|
||||
ZONE4_POWER_TOGGLE("Zone 4 Power Toggle", RotelConnector.ZONE4_CMD, (byte) 0x0A),
|
||||
ZONE4_POWER_OFF("Zone 4 Power Off", RotelConnector.ZONE4_CMD, (byte) 0x4A),
|
||||
ZONE4_POWER_ON("Zone 4 Power On", RotelConnector.ZONE4_CMD, (byte) 0x4B),
|
||||
VOLUME_UP("Volume Up", RotelConnector.PRIMARY_CMD, (byte) 0x0B, "volume_up", "vol_up"),
|
||||
VOLUME_DOWN("Volume Down", RotelConnector.PRIMARY_CMD, (byte) 0x0C, "volume_down", "vol_dwn"),
|
||||
VOLUME_SET("Set Volume to level", RotelConnector.VOLUME_CMD, (byte) 0, "volume_", "vol_"),
|
||||
ZONE_SELECT("Zone Select", PRIMARY_CMD, (byte) 0x23),
|
||||
MAIN_ZONE_POWER_TOGGLE("Main Zone Power Toggle", MAIN_ZONE_CMD, (byte) 0x0A),
|
||||
MAIN_ZONE_POWER_OFF("Main Zone Power Off", MAIN_ZONE_CMD, (byte) 0x4A),
|
||||
MAIN_ZONE_POWER_ON("Main Zone Power On", MAIN_ZONE_CMD, (byte) 0x4B),
|
||||
ZONE2_POWER_TOGGLE("Zone 2 Power Toggle", ZONE2_CMD, (byte) 0x0A),
|
||||
ZONE2_POWER_OFF("Zone 2 Power Off", ZONE2_CMD, (byte) 0x4A),
|
||||
ZONE2_POWER_ON("Zone 2 Power On", ZONE2_CMD, (byte) 0x4B),
|
||||
ZONE3_POWER_TOGGLE("Zone 3 Power Toggle", ZONE3_CMD, (byte) 0x0A),
|
||||
ZONE3_POWER_OFF("Zone 3 Power Off", ZONE3_CMD, (byte) 0x4A),
|
||||
ZONE3_POWER_ON("Zone 3 Power On", ZONE3_CMD, (byte) 0x4B),
|
||||
ZONE4_POWER_TOGGLE("Zone 4 Power Toggle", ZONE4_CMD, (byte) 0x0A),
|
||||
ZONE4_POWER_OFF("Zone 4 Power Off", ZONE4_CMD, (byte) 0x4A),
|
||||
ZONE4_POWER_ON("Zone 4 Power On", ZONE4_CMD, (byte) 0x4B),
|
||||
VOLUME_UP("Volume Up", PRIMARY_CMD, (byte) 0x0B, "volume_up", "vol_up"),
|
||||
VOLUME_DOWN("Volume Down", PRIMARY_CMD, (byte) 0x0C, "volume_down", "vol_dwn"),
|
||||
VOLUME_SET("Set Volume to level", VOLUME_CMD, (byte) 0, "volume_", "vol_"),
|
||||
VOLUME_GET("Request current volume level", "get_volume", "volume?"),
|
||||
VOLUME_GET_MIN("Request Min volume level", "get_volume_min", null),
|
||||
VOLUME_GET_MAX("Request Max volume level", "get_volume_max", null),
|
||||
MUTE_TOGGLE("Mute Toggle", RotelConnector.PRIMARY_CMD, (byte) 0x1E, "mute", "mute"),
|
||||
MUTE_TOGGLE("Mute Toggle", PRIMARY_CMD, (byte) 0x1E, "mute", "mute"),
|
||||
MUTE_ON("Mute On", "mute_on", "mute_on"),
|
||||
MUTE_OFF("Mute Off", "mute_off", "mute_off"),
|
||||
MUTE("Request current mute status", "get_mute_status", "mute?"),
|
||||
MAIN_ZONE_VOLUME_UP("Main Zone Volume Up", RotelConnector.MAIN_ZONE_CMD, (byte) 0),
|
||||
MAIN_ZONE_VOLUME_DOWN("Main Zone Volume Down", RotelConnector.MAIN_ZONE_CMD, (byte) 1),
|
||||
MAIN_ZONE_MUTE_TOGGLE("Main Zone Mute Toggle", RotelConnector.MAIN_ZONE_CMD, (byte) 0x1E),
|
||||
MAIN_ZONE_MUTE_ON("Main Zone Mute On", RotelConnector.MAIN_ZONE_CMD, (byte) 0x6C),
|
||||
MAIN_ZONE_MUTE_OFF("Main Zone Mute Off", RotelConnector.MAIN_ZONE_CMD, (byte) 0x6D),
|
||||
ZONE2_VOLUME_UP("Zone 2 Volume Up", RotelConnector.ZONE2_CMD, (byte) 0),
|
||||
ZONE2_VOLUME_DOWN("Zone 2 Volume Down", RotelConnector.ZONE2_CMD, (byte) 1),
|
||||
ZONE2_VOLUME_SET("Set Zone 2 Volume to level", RotelConnector.ZONE2_VOLUME_CMD, (byte) 0),
|
||||
ZONE2_MUTE_TOGGLE("Zone 2 Mute Toggle", RotelConnector.ZONE2_CMD, (byte) 0x1E),
|
||||
ZONE2_MUTE_ON("Zone 2 Mute On", RotelConnector.ZONE2_CMD, (byte) 0x6C),
|
||||
ZONE2_MUTE_OFF("Zone 2 Mute Off", RotelConnector.ZONE2_CMD, (byte) 0x6D),
|
||||
ZONE3_VOLUME_UP("Zone 3 Volume Up", RotelConnector.ZONE3_CMD, (byte) 0),
|
||||
ZONE3_VOLUME_DOWN("Zone 3 Volume Down", RotelConnector.ZONE3_CMD, (byte) 1),
|
||||
ZONE3_VOLUME_SET("Set Zone 3 Volume to level", RotelConnector.ZONE3_VOLUME_CMD, (byte) 0),
|
||||
ZONE3_MUTE_TOGGLE("Zone 3 Mute Toggle", RotelConnector.ZONE3_CMD, (byte) 0x1E),
|
||||
ZONE3_MUTE_ON("Zone 3 Mute On", RotelConnector.ZONE3_CMD, (byte) 0x6C),
|
||||
ZONE3_MUTE_OFF("Zone 3 Mute Off", RotelConnector.ZONE3_CMD, (byte) 0x6D),
|
||||
ZONE4_VOLUME_UP("Zone 4 Volume Up", RotelConnector.ZONE4_CMD, (byte) 0),
|
||||
ZONE4_VOLUME_DOWN("Zone 4 Volume Down", RotelConnector.ZONE4_CMD, (byte) 1),
|
||||
ZONE4_VOLUME_SET("Set Zone 4 Volume to level", RotelConnector.ZONE4_VOLUME_CMD, (byte) 0),
|
||||
ZONE4_MUTE_TOGGLE("Zone 4 Mute Toggle", RotelConnector.ZONE4_CMD, (byte) 0x1E),
|
||||
ZONE4_MUTE_ON("Zone 4 Mute On", RotelConnector.ZONE4_CMD, (byte) 0x6C),
|
||||
ZONE4_MUTE_OFF("Zone 4 Mute Off", RotelConnector.ZONE4_CMD, (byte) 0x6D),
|
||||
SOURCE_CD("Source CD", RotelConnector.PRIMARY_CMD, (byte) 0x02, "cd", "cd"),
|
||||
SOURCE_TUNER("Source Tuner", RotelConnector.PRIMARY_CMD, (byte) 0x03, "tuner", "tuner"),
|
||||
SOURCE_TAPE("Source Tape", RotelConnector.PRIMARY_CMD, (byte) 0x04, "tape", "tape"),
|
||||
SOURCE_VIDEO1("Source Video 1", RotelConnector.PRIMARY_CMD, (byte) 0x05, "video1", "video1"),
|
||||
SOURCE_VIDEO2("Source Video 2", RotelConnector.PRIMARY_CMD, (byte) 0x06, "video2", "video2"),
|
||||
SOURCE_VIDEO3("Source Video 3", RotelConnector.PRIMARY_CMD, (byte) 0x07, "video3", "video3"),
|
||||
SOURCE_VIDEO4("Source Video 4", RotelConnector.PRIMARY_CMD, (byte) 0x08, "video4", "video4"),
|
||||
SOURCE_VIDEO5("Source Video 5", RotelConnector.PRIMARY_CMD, (byte) 0x09, "video5", "video5"),
|
||||
SOURCE_VIDEO6("Source Video 6", RotelConnector.PRIMARY_CMD, (byte) 0x94, "video6", "video6"),
|
||||
MAIN_ZONE_VOLUME_UP("Main Zone Volume Up", MAIN_ZONE_CMD, (byte) 0),
|
||||
MAIN_ZONE_VOLUME_DOWN("Main Zone Volume Down", MAIN_ZONE_CMD, (byte) 1),
|
||||
MAIN_ZONE_MUTE_TOGGLE("Main Zone Mute Toggle", MAIN_ZONE_CMD, (byte) 0x1E),
|
||||
MAIN_ZONE_MUTE_ON("Main Zone Mute On", MAIN_ZONE_CMD, (byte) 0x6C),
|
||||
MAIN_ZONE_MUTE_OFF("Main Zone Mute Off", MAIN_ZONE_CMD, (byte) 0x6D),
|
||||
ZONE2_VOLUME_UP("Zone 2 Volume Up", ZONE2_CMD, (byte) 0),
|
||||
ZONE2_VOLUME_DOWN("Zone 2 Volume Down", ZONE2_CMD, (byte) 1),
|
||||
ZONE2_VOLUME_SET("Set Zone 2 Volume to level", ZONE2_VOLUME_CMD, (byte) 0),
|
||||
ZONE2_MUTE_TOGGLE("Zone 2 Mute Toggle", ZONE2_CMD, (byte) 0x1E),
|
||||
ZONE2_MUTE_ON("Zone 2 Mute On", ZONE2_CMD, (byte) 0x6C),
|
||||
ZONE2_MUTE_OFF("Zone 2 Mute Off", ZONE2_CMD, (byte) 0x6D),
|
||||
ZONE3_VOLUME_UP("Zone 3 Volume Up", ZONE3_CMD, (byte) 0),
|
||||
ZONE3_VOLUME_DOWN("Zone 3 Volume Down", ZONE3_CMD, (byte) 1),
|
||||
ZONE3_VOLUME_SET("Set Zone 3 Volume to level", ZONE3_VOLUME_CMD, (byte) 0),
|
||||
ZONE3_MUTE_TOGGLE("Zone 3 Mute Toggle", ZONE3_CMD, (byte) 0x1E),
|
||||
ZONE3_MUTE_ON("Zone 3 Mute On", ZONE3_CMD, (byte) 0x6C),
|
||||
ZONE3_MUTE_OFF("Zone 3 Mute Off", ZONE3_CMD, (byte) 0x6D),
|
||||
ZONE4_VOLUME_UP("Zone 4 Volume Up", ZONE4_CMD, (byte) 0),
|
||||
ZONE4_VOLUME_DOWN("Zone 4 Volume Down", ZONE4_CMD, (byte) 1),
|
||||
ZONE4_VOLUME_SET("Set Zone 4 Volume to level", ZONE4_VOLUME_CMD, (byte) 0),
|
||||
ZONE4_MUTE_TOGGLE("Zone 4 Mute Toggle", ZONE4_CMD, (byte) 0x1E),
|
||||
ZONE4_MUTE_ON("Zone 4 Mute On", ZONE4_CMD, (byte) 0x6C),
|
||||
ZONE4_MUTE_OFF("Zone 4 Mute Off", ZONE4_CMD, (byte) 0x6D),
|
||||
SOURCE_CD("Source CD", PRIMARY_CMD, (byte) 0x02, "cd", "cd"),
|
||||
SOURCE_TUNER("Source Tuner", PRIMARY_CMD, (byte) 0x03, "tuner", "tuner"),
|
||||
SOURCE_TAPE("Source Tape", PRIMARY_CMD, (byte) 0x04, "tape", "tape"),
|
||||
SOURCE_VIDEO1("Source Video 1", PRIMARY_CMD, (byte) 0x05, "video1", "video1"),
|
||||
SOURCE_VIDEO2("Source Video 2", PRIMARY_CMD, (byte) 0x06, "video2", "video2"),
|
||||
SOURCE_VIDEO3("Source Video 3", PRIMARY_CMD, (byte) 0x07, "video3", "video3"),
|
||||
SOURCE_VIDEO4("Source Video 4", PRIMARY_CMD, (byte) 0x08, "video4", "video4"),
|
||||
SOURCE_VIDEO5("Source Video 5", PRIMARY_CMD, (byte) 0x09, "video5", "video5"),
|
||||
SOURCE_VIDEO6("Source Video 6", PRIMARY_CMD, (byte) 0x94, "video6", "video6"),
|
||||
SOURCE_VIDEO7("Source Video 7", "video7", "video7"),
|
||||
SOURCE_VIDEO8("Source Video 8", "video8", "video8"),
|
||||
SOURCE_PHONO("Source Phono", RotelConnector.PRIMARY_CMD, (byte) 0x35, "phono", "phono"),
|
||||
SOURCE_USB("Source Front USB", RotelConnector.PRIMARY_CMD, (byte) 0x8E, "usb", "usb"),
|
||||
SOURCE_PHONO("Source Phono", PRIMARY_CMD, (byte) 0x35, "phono", "phono"),
|
||||
SOURCE_USB("Source Front USB", PRIMARY_CMD, (byte) 0x8E, "usb", "usb"),
|
||||
SOURCE_PCUSB("Source PC USB", "pc_usb", "pcusb"),
|
||||
SOURCE_MULTI_INPUT("Source Multi Input", RotelConnector.PRIMARY_CMD, (byte) 0x15, "multi_input", "multi_input"),
|
||||
SOURCE_MULTI_INPUT("Source Multi Input", PRIMARY_CMD, (byte) 0x15, "multi_input", "multi_input"),
|
||||
SOURCE_AUX("Source Aux", "aux", "aux"),
|
||||
SOURCE_AUX1("Source Aux 1", "aux1", "aux1"),
|
||||
SOURCE_AUX2("Source Aux 2", "aux2", "aux2"),
|
||||
|
@ -111,126 +113,114 @@ public enum RotelCommand {
|
|||
SOURCE_IRADIO("Source iRadio", "iradio", "iradio"),
|
||||
SOURCE_NETWORK("Source Network", "network", "network"),
|
||||
SOURCE("Request current source", "get_current_source", "source?"),
|
||||
MAIN_ZONE_SOURCE_CD("Main Zone Source CD", RotelConnector.MAIN_ZONE_CMD, (byte) 0x02, "main_zone_cd",
|
||||
"main_zone_cd"),
|
||||
MAIN_ZONE_SOURCE_TUNER("Main Zone Source Tuner", RotelConnector.MAIN_ZONE_CMD, (byte) 0x03, "main_zone_tuner",
|
||||
"main_zone_tuner"),
|
||||
MAIN_ZONE_SOURCE_TAPE("Main Zone Source Tape", RotelConnector.MAIN_ZONE_CMD, (byte) 0x04, "main_zone_tape",
|
||||
"main_zone_tape"),
|
||||
MAIN_ZONE_SOURCE_VIDEO1("Main Zone Source Video 1", RotelConnector.MAIN_ZONE_CMD, (byte) 0x05, "main_zone_video1",
|
||||
MAIN_ZONE_SOURCE_CD("Main Zone Source CD", MAIN_ZONE_CMD, (byte) 0x02, "main_zone_cd", "main_zone_cd"),
|
||||
MAIN_ZONE_SOURCE_TUNER("Main Zone Source Tuner", MAIN_ZONE_CMD, (byte) 0x03, "main_zone_tuner", "main_zone_tuner"),
|
||||
MAIN_ZONE_SOURCE_TAPE("Main Zone Source Tape", MAIN_ZONE_CMD, (byte) 0x04, "main_zone_tape", "main_zone_tape"),
|
||||
MAIN_ZONE_SOURCE_VIDEO1("Main Zone Source Video 1", MAIN_ZONE_CMD, (byte) 0x05, "main_zone_video1",
|
||||
"main_zone_video1"),
|
||||
MAIN_ZONE_SOURCE_VIDEO2("Main Zone Source Video 2", RotelConnector.MAIN_ZONE_CMD, (byte) 0x06, "main_zone_video2",
|
||||
MAIN_ZONE_SOURCE_VIDEO2("Main Zone Source Video 2", MAIN_ZONE_CMD, (byte) 0x06, "main_zone_video2",
|
||||
"main_zone_video2"),
|
||||
MAIN_ZONE_SOURCE_VIDEO3("Main Zone Source Video 3", RotelConnector.MAIN_ZONE_CMD, (byte) 0x07, "main_zone_video3",
|
||||
MAIN_ZONE_SOURCE_VIDEO3("Main Zone Source Video 3", MAIN_ZONE_CMD, (byte) 0x07, "main_zone_video3",
|
||||
"main_zone_video3"),
|
||||
MAIN_ZONE_SOURCE_VIDEO4("Main Zone Source Video 4", RotelConnector.MAIN_ZONE_CMD, (byte) 0x08, "main_zone_video4",
|
||||
MAIN_ZONE_SOURCE_VIDEO4("Main Zone Source Video 4", MAIN_ZONE_CMD, (byte) 0x08, "main_zone_video4",
|
||||
"main_zone_video4"),
|
||||
MAIN_ZONE_SOURCE_VIDEO5("Main Zone Source Video 5", RotelConnector.MAIN_ZONE_CMD, (byte) 0x09, "main_zone_video5",
|
||||
MAIN_ZONE_SOURCE_VIDEO5("Main Zone Source Video 5", MAIN_ZONE_CMD, (byte) 0x09, "main_zone_video5",
|
||||
"main_zone_video5"),
|
||||
MAIN_ZONE_SOURCE_VIDEO6("Main Zone Source Video 6", RotelConnector.MAIN_ZONE_CMD, (byte) 0x94, "main_zone_video6",
|
||||
MAIN_ZONE_SOURCE_VIDEO6("Main Zone Source Video 6", MAIN_ZONE_CMD, (byte) 0x94, "main_zone_video6",
|
||||
"main_zone_video6"),
|
||||
MAIN_ZONE_SOURCE_USB("Main Zone Source Front USB", RotelConnector.MAIN_ZONE_CMD, (byte) 0x8E, "main_zone_usb",
|
||||
"main_zone_usb"),
|
||||
MAIN_ZONE_SOURCE_MULTI_INPUT("Main Zone Source Multi Input", RotelConnector.MAIN_ZONE_CMD, (byte) 0x15,
|
||||
"main_zone_multi_input", "main_zone_multi_input"),
|
||||
RECORD_SOURCE_CD("Record Source CD", RotelConnector.RECORD_SRC_CMD, (byte) 0x02, "record_cd", "record_cd"),
|
||||
RECORD_SOURCE_TUNER("Record Source Tuner", RotelConnector.RECORD_SRC_CMD, (byte) 0x03, "record_tuner",
|
||||
"record_tuner"),
|
||||
RECORD_SOURCE_TAPE("Record Source Tape", RotelConnector.RECORD_SRC_CMD, (byte) 0x04, "record_tape", "record_tape"),
|
||||
RECORD_SOURCE_VIDEO1("Record Source Video 1", RotelConnector.RECORD_SRC_CMD, (byte) 0x05, "record_video1",
|
||||
"record_video1"),
|
||||
RECORD_SOURCE_VIDEO2("Record Source Video 2", RotelConnector.RECORD_SRC_CMD, (byte) 0x06, "record_video2",
|
||||
"record_video2"),
|
||||
RECORD_SOURCE_VIDEO3("Record Source Video 3", RotelConnector.RECORD_SRC_CMD, (byte) 0x07, "record_video3",
|
||||
"record_video3"),
|
||||
RECORD_SOURCE_VIDEO4("Record Source Video 4", RotelConnector.RECORD_SRC_CMD, (byte) 0x08, "record_video4",
|
||||
"record_video4"),
|
||||
RECORD_SOURCE_VIDEO5("Record Source Video 5", RotelConnector.RECORD_SRC_CMD, (byte) 0x09, "record_video5",
|
||||
"record_video5"),
|
||||
RECORD_SOURCE_VIDEO6("Record Source Video 6", RotelConnector.RECORD_SRC_CMD, (byte) 0x94, "record_video6",
|
||||
"record_video6"),
|
||||
RECORD_SOURCE_USB("Record Source Front USB", RotelConnector.RECORD_SRC_CMD, (byte) 0x8E, "record_usb",
|
||||
"record_usb"),
|
||||
RECORD_SOURCE_MAIN("Record Follow Main Zone Source", RotelConnector.RECORD_SRC_CMD, (byte) 0x6B,
|
||||
"record_follow_main", "record_follow_main"),
|
||||
ZONE2_SOURCE_CD("Zone 2 Source CD", RotelConnector.ZONE2_CMD, (byte) 0x02, "zone2_cd", "zone2_cd"),
|
||||
ZONE2_SOURCE_TUNER("Zone 2 Source Tuner", RotelConnector.ZONE2_CMD, (byte) 0x03, "zone2_tuner", "zone2_tuner"),
|
||||
ZONE2_SOURCE_TAPE("Zone 2 Source Tape", RotelConnector.ZONE2_CMD, (byte) 0x04, "zone2_tape", "zone2_tape"),
|
||||
ZONE2_SOURCE_VIDEO1("Zone 2 Source Video 1", RotelConnector.ZONE2_CMD, (byte) 0x05, "zone2_video1", "zone2_video1"),
|
||||
ZONE2_SOURCE_VIDEO2("Zone 2 Source Video 2", RotelConnector.ZONE2_CMD, (byte) 0x06, "zone2_video2", "zone2_video2"),
|
||||
ZONE2_SOURCE_VIDEO3("Zone 2 Source Video 3", RotelConnector.ZONE2_CMD, (byte) 0x07, "zone2_video3", "zone2_video3"),
|
||||
ZONE2_SOURCE_VIDEO4("Zone 2 Source Video 4", RotelConnector.ZONE2_CMD, (byte) 0x08, "zone2_video4", "zone2_video4"),
|
||||
ZONE2_SOURCE_VIDEO5("Zone 2 Source Video 5", RotelConnector.ZONE2_CMD, (byte) 0x09, "zone2_video5", "zone2_video5"),
|
||||
ZONE2_SOURCE_VIDEO6("Zone 2 Source Video 6", RotelConnector.ZONE2_CMD, (byte) 0x94, "zone2_video6", "zone2_video6"),
|
||||
ZONE2_SOURCE_USB("Zone 2 Source Front USB", RotelConnector.ZONE2_CMD, (byte) 0x8E, "zone2_usb", "zone2_usb"),
|
||||
ZONE2_SOURCE_MAIN("Zone 2 Follow Main Zone Source", RotelConnector.ZONE2_CMD, (byte) 0x6B, "zone2_follow_main",
|
||||
MAIN_ZONE_SOURCE_USB("Main Zone Source Front USB", MAIN_ZONE_CMD, (byte) 0x8E, "main_zone_usb", "main_zone_usb"),
|
||||
MAIN_ZONE_SOURCE_MULTI_INPUT("Main Zone Source Multi Input", MAIN_ZONE_CMD, (byte) 0x15, "main_zone_multi_input",
|
||||
"main_zone_multi_input"),
|
||||
RECORD_SOURCE_CD("Record Source CD", RECORD_SRC_CMD, (byte) 0x02, "record_cd", "record_cd"),
|
||||
RECORD_SOURCE_TUNER("Record Source Tuner", RECORD_SRC_CMD, (byte) 0x03, "record_tuner", "record_tuner"),
|
||||
RECORD_SOURCE_TAPE("Record Source Tape", RECORD_SRC_CMD, (byte) 0x04, "record_tape", "record_tape"),
|
||||
RECORD_SOURCE_VIDEO1("Record Source Video 1", RECORD_SRC_CMD, (byte) 0x05, "record_video1", "record_video1"),
|
||||
RECORD_SOURCE_VIDEO2("Record Source Video 2", RECORD_SRC_CMD, (byte) 0x06, "record_video2", "record_video2"),
|
||||
RECORD_SOURCE_VIDEO3("Record Source Video 3", RECORD_SRC_CMD, (byte) 0x07, "record_video3", "record_video3"),
|
||||
RECORD_SOURCE_VIDEO4("Record Source Video 4", RECORD_SRC_CMD, (byte) 0x08, "record_video4", "record_video4"),
|
||||
RECORD_SOURCE_VIDEO5("Record Source Video 5", RECORD_SRC_CMD, (byte) 0x09, "record_video5", "record_video5"),
|
||||
RECORD_SOURCE_VIDEO6("Record Source Video 6", RECORD_SRC_CMD, (byte) 0x94, "record_video6", "record_video6"),
|
||||
RECORD_SOURCE_USB("Record Source Front USB", RECORD_SRC_CMD, (byte) 0x8E, "record_usb", "record_usb"),
|
||||
RECORD_SOURCE_MAIN("Record Follow Main Zone Source", RECORD_SRC_CMD, (byte) 0x6B, "record_follow_main",
|
||||
"record_follow_main"),
|
||||
ZONE2_SOURCE_CD("Zone 2 Source CD", ZONE2_CMD, (byte) 0x02, "zone2_cd", "zone2_cd"),
|
||||
ZONE2_SOURCE_TUNER("Zone 2 Source Tuner", ZONE2_CMD, (byte) 0x03, "zone2_tuner", "zone2_tuner"),
|
||||
ZONE2_SOURCE_TAPE("Zone 2 Source Tape", ZONE2_CMD, (byte) 0x04, "zone2_tape", "zone2_tape"),
|
||||
ZONE2_SOURCE_VIDEO1("Zone 2 Source Video 1", ZONE2_CMD, (byte) 0x05, "zone2_video1", "zone2_video1"),
|
||||
ZONE2_SOURCE_VIDEO2("Zone 2 Source Video 2", ZONE2_CMD, (byte) 0x06, "zone2_video2", "zone2_video2"),
|
||||
ZONE2_SOURCE_VIDEO3("Zone 2 Source Video 3", ZONE2_CMD, (byte) 0x07, "zone2_video3", "zone2_video3"),
|
||||
ZONE2_SOURCE_VIDEO4("Zone 2 Source Video 4", ZONE2_CMD, (byte) 0x08, "zone2_video4", "zone2_video4"),
|
||||
ZONE2_SOURCE_VIDEO5("Zone 2 Source Video 5", ZONE2_CMD, (byte) 0x09, "zone2_video5", "zone2_video5"),
|
||||
ZONE2_SOURCE_VIDEO6("Zone 2 Source Video 6", ZONE2_CMD, (byte) 0x94, "zone2_video6", "zone2_video6"),
|
||||
ZONE2_SOURCE_USB("Zone 2 Source Front USB", ZONE2_CMD, (byte) 0x8E, "zone2_usb", "zone2_usb"),
|
||||
ZONE2_SOURCE_MAIN("Zone 2 Follow Main Zone Source", ZONE2_CMD, (byte) 0x6B, "zone2_follow_main",
|
||||
"zone2_follow_main"),
|
||||
ZONE3_SOURCE_CD("Zone 3 Source CD", RotelConnector.ZONE3_CMD, (byte) 0x02, "zone3_cd", "zone3_cd"),
|
||||
ZONE3_SOURCE_TUNER("Zone 3 Source Tuner", RotelConnector.ZONE3_CMD, (byte) 0x03, "zone3_tuner", "zone3_tuner"),
|
||||
ZONE3_SOURCE_TAPE("Zone 3 Source Tape", RotelConnector.ZONE3_CMD, (byte) 0x04, "zone3_tape", "zone3_tape"),
|
||||
ZONE3_SOURCE_VIDEO1("Zone 3 Source Video 1", RotelConnector.ZONE3_CMD, (byte) 0x05, "zone3_video1", "zone3_video1"),
|
||||
ZONE3_SOURCE_VIDEO2("Zone 3 Source Video 2", RotelConnector.ZONE3_CMD, (byte) 0x06, "zone3_video2", "zone3_video2"),
|
||||
ZONE3_SOURCE_VIDEO3("Zone 3 Source Video 3", RotelConnector.ZONE3_CMD, (byte) 0x07, "zone3_video3", "zone3_video3"),
|
||||
ZONE3_SOURCE_VIDEO4("Zone 3 Source Video 4", RotelConnector.ZONE3_CMD, (byte) 0x08, "zone3_video4", "zone3_video4"),
|
||||
ZONE3_SOURCE_VIDEO5("Zone 3 Source Video 5", RotelConnector.ZONE3_CMD, (byte) 0x09, "zone3_video5", "zone3_video5"),
|
||||
ZONE3_SOURCE_VIDEO6("Zone 3 Source Video 6", RotelConnector.ZONE3_CMD, (byte) 0x94, "zone3_video6", "zone3_video6"),
|
||||
ZONE3_SOURCE_USB("Zone 3 Source Front USB", RotelConnector.ZONE3_CMD, (byte) 0x8E, "zone3_usb", "zone3_usb"),
|
||||
ZONE3_SOURCE_MAIN("Zone 3 Follow Main Zone Source", RotelConnector.ZONE3_CMD, (byte) 0x6B, "zone3_follow_main",
|
||||
ZONE3_SOURCE_CD("Zone 3 Source CD", ZONE3_CMD, (byte) 0x02, "zone3_cd", "zone3_cd"),
|
||||
ZONE3_SOURCE_TUNER("Zone 3 Source Tuner", ZONE3_CMD, (byte) 0x03, "zone3_tuner", "zone3_tuner"),
|
||||
ZONE3_SOURCE_TAPE("Zone 3 Source Tape", ZONE3_CMD, (byte) 0x04, "zone3_tape", "zone3_tape"),
|
||||
ZONE3_SOURCE_VIDEO1("Zone 3 Source Video 1", ZONE3_CMD, (byte) 0x05, "zone3_video1", "zone3_video1"),
|
||||
ZONE3_SOURCE_VIDEO2("Zone 3 Source Video 2", ZONE3_CMD, (byte) 0x06, "zone3_video2", "zone3_video2"),
|
||||
ZONE3_SOURCE_VIDEO3("Zone 3 Source Video 3", ZONE3_CMD, (byte) 0x07, "zone3_video3", "zone3_video3"),
|
||||
ZONE3_SOURCE_VIDEO4("Zone 3 Source Video 4", ZONE3_CMD, (byte) 0x08, "zone3_video4", "zone3_video4"),
|
||||
ZONE3_SOURCE_VIDEO5("Zone 3 Source Video 5", ZONE3_CMD, (byte) 0x09, "zone3_video5", "zone3_video5"),
|
||||
ZONE3_SOURCE_VIDEO6("Zone 3 Source Video 6", ZONE3_CMD, (byte) 0x94, "zone3_video6", "zone3_video6"),
|
||||
ZONE3_SOURCE_USB("Zone 3 Source Front USB", ZONE3_CMD, (byte) 0x8E, "zone3_usb", "zone3_usb"),
|
||||
ZONE3_SOURCE_MAIN("Zone 3 Follow Main Zone Source", ZONE3_CMD, (byte) 0x6B, "zone3_follow_main",
|
||||
"zone3_follow_main"),
|
||||
ZONE4_SOURCE_CD("Zone 4 Source CD", RotelConnector.ZONE4_CMD, (byte) 0x02, "zone4_cd", "zone4_cd"),
|
||||
ZONE4_SOURCE_TUNER("Zone 4 Source Tuner", RotelConnector.ZONE4_CMD, (byte) 0x03, "zone4_tuner", "zone4_tuner"),
|
||||
ZONE4_SOURCE_TAPE("Zone 4 Source Tape", RotelConnector.ZONE4_CMD, (byte) 0x04, "zone4_tape", "zone4_tape"),
|
||||
ZONE4_SOURCE_VIDEO1("Zone 4 Source Video 1", RotelConnector.ZONE4_CMD, (byte) 0x05, "zone4_video1", "zone4_video1"),
|
||||
ZONE4_SOURCE_VIDEO2("Zone 4 Source Video 2", RotelConnector.ZONE4_CMD, (byte) 0x06, "zone4_video2", "zone4_video2"),
|
||||
ZONE4_SOURCE_VIDEO3("Zone 4 Source Video 3", RotelConnector.ZONE4_CMD, (byte) 0x07, "zone4_video3", "zone4_video3"),
|
||||
ZONE4_SOURCE_VIDEO4("Zone 4 Source Video 4", RotelConnector.ZONE4_CMD, (byte) 0x08, "zone4_video4", "zone4_video4"),
|
||||
ZONE4_SOURCE_VIDEO5("Zone 4 Source Video 5", RotelConnector.ZONE4_CMD, (byte) 0x09, "zone4_video5", "zone4_video5"),
|
||||
ZONE4_SOURCE_VIDEO6("Zone 4 Source Video 6", RotelConnector.ZONE4_CMD, (byte) 0x94, "zone4_video6", "zone4_video6"),
|
||||
ZONE4_SOURCE_USB("Zone 4 Source Front USB", RotelConnector.ZONE4_CMD, (byte) 0x8E, "zone4_usb", "zone4_usb"),
|
||||
ZONE4_SOURCE_MAIN("Zone 4 Follow Main Zone Source", RotelConnector.ZONE4_CMD, (byte) 0x6B, "zone4_follow_main",
|
||||
ZONE4_SOURCE_CD("Zone 4 Source CD", ZONE4_CMD, (byte) 0x02, "zone4_cd", "zone4_cd"),
|
||||
ZONE4_SOURCE_TUNER("Zone 4 Source Tuner", ZONE4_CMD, (byte) 0x03, "zone4_tuner", "zone4_tuner"),
|
||||
ZONE4_SOURCE_TAPE("Zone 4 Source Tape", ZONE4_CMD, (byte) 0x04, "zone4_tape", "zone4_tape"),
|
||||
ZONE4_SOURCE_VIDEO1("Zone 4 Source Video 1", ZONE4_CMD, (byte) 0x05, "zone4_video1", "zone4_video1"),
|
||||
ZONE4_SOURCE_VIDEO2("Zone 4 Source Video 2", ZONE4_CMD, (byte) 0x06, "zone4_video2", "zone4_video2"),
|
||||
ZONE4_SOURCE_VIDEO3("Zone 4 Source Video 3", ZONE4_CMD, (byte) 0x07, "zone4_video3", "zone4_video3"),
|
||||
ZONE4_SOURCE_VIDEO4("Zone 4 Source Video 4", ZONE4_CMD, (byte) 0x08, "zone4_video4", "zone4_video4"),
|
||||
ZONE4_SOURCE_VIDEO5("Zone 4 Source Video 5", ZONE4_CMD, (byte) 0x09, "zone4_video5", "zone4_video5"),
|
||||
ZONE4_SOURCE_VIDEO6("Zone 4 Source Video 6", ZONE4_CMD, (byte) 0x94, "zone4_video6", "zone4_video6"),
|
||||
ZONE4_SOURCE_USB("Zone 4 Source Front USB", ZONE4_CMD, (byte) 0x8E, "zone4_usb", "zone4_usb"),
|
||||
ZONE4_SOURCE_MAIN("Zone 4 Follow Main Zone Source", ZONE4_CMD, (byte) 0x6B, "zone4_follow_main",
|
||||
"zone4_follow_main"),
|
||||
STEREO("Stereo", RotelConnector.PRIMARY_CMD, (byte) 0x11, "2channel", "2channel"),
|
||||
STEREO3("Dolby 3 Stereo ", RotelConnector.PRIMARY_CMD, (byte) 0x12, "3channel", "3channel"),
|
||||
STEREO5("5 Channel Stereo", RotelConnector.PRIMARY_CMD, (byte) 0x5B, "5channel", "5channel"),
|
||||
STEREO7("7 Channel Stereo", RotelConnector.PRIMARY_CMD, (byte) 0x5C, "7channel", "7channel"),
|
||||
STEREO("Stereo", PRIMARY_CMD, (byte) 0x11, "2channel", "2channel"),
|
||||
STEREO3("Dolby 3 Stereo ", PRIMARY_CMD, (byte) 0x12, "3channel", "3channel"),
|
||||
STEREO5("5 Channel Stereo", PRIMARY_CMD, (byte) 0x5B, "5channel", "5channel"),
|
||||
STEREO7("7 Channel Stereo", PRIMARY_CMD, (byte) 0x5C, "7channel", "7channel"),
|
||||
STEREO9("9 Channel Stereo", "9channel", "9channel"),
|
||||
STEREO11("11 Channel Stereo", "11channel", "11channel"),
|
||||
DSP1("DSP 1", RotelConnector.PRIMARY_CMD, (byte) 0x57),
|
||||
DSP2("DSP 2", RotelConnector.PRIMARY_CMD, (byte) 0x58),
|
||||
DSP3("DSP 3", RotelConnector.PRIMARY_CMD, (byte) 0x59),
|
||||
DSP4("DSP 4", RotelConnector.PRIMARY_CMD, (byte) 0x5A),
|
||||
PROLOGIC("Dolby Pro Logic", RotelConnector.PRIMARY_CMD, (byte) 0x5F),
|
||||
PLII_CINEMA("Dolby PLII Cinema", RotelConnector.PRIMARY_CMD, (byte) 0x5D, "prologic_movie", "prologic_movie"),
|
||||
PLII_MUSIC("Dolby PLII Music", RotelConnector.PRIMARY_CMD, (byte) 0x5E, "prologic_music", "prologic_music"),
|
||||
PLII_GAME("Dolby PLII Game", RotelConnector.PRIMARY_CMD, (byte) 0x74, "prologic_game", "prologic_game"),
|
||||
PLIIZ("Dolby PLIIz", RotelConnector.PRIMARY_CMD, (byte) 0x92, "prologic_iiz", "prologic_iiz"),
|
||||
NEO6_MUSIC("dts Neo:6 Music", RotelConnector.PRIMARY_CMD, (byte) 0x60, "neo6_music", "neo6_music"),
|
||||
NEO6_CINEMA("dts Neo:6 Cinema", RotelConnector.PRIMARY_CMD, (byte) 0x61, "neo6_cinema", "neo6_cinema"),
|
||||
DSP1("DSP 1", PRIMARY_CMD, (byte) 0x57),
|
||||
DSP2("DSP 2", PRIMARY_CMD, (byte) 0x58),
|
||||
DSP3("DSP 3", PRIMARY_CMD, (byte) 0x59),
|
||||
DSP4("DSP 4", PRIMARY_CMD, (byte) 0x5A),
|
||||
PROLOGIC("Dolby Pro Logic", PRIMARY_CMD, (byte) 0x5F),
|
||||
PLII_CINEMA("Dolby PLII Cinema", PRIMARY_CMD, (byte) 0x5D, "prologic_movie", "prologic_movie"),
|
||||
PLII_MUSIC("Dolby PLII Music", PRIMARY_CMD, (byte) 0x5E, "prologic_music", "prologic_music"),
|
||||
PLII_GAME("Dolby PLII Game", PRIMARY_CMD, (byte) 0x74, "prologic_game", "prologic_game"),
|
||||
PLIIZ("Dolby PLIIz", PRIMARY_CMD, (byte) 0x92, "prologic_iiz", "prologic_iiz"),
|
||||
NEO6_MUSIC("dts Neo:6 Music", PRIMARY_CMD, (byte) 0x60, "neo6_music", "neo6_music"),
|
||||
NEO6_CINEMA("dts Neo:6 Cinema", PRIMARY_CMD, (byte) 0x61, "neo6_cinema", "neo6_cinema"),
|
||||
ATMOS("Dolby Atmos", "dolby_atmos", "dolby_atmos"),
|
||||
NEURAL_X("dts Neural:X", "dts_neural", "dts_neural"),
|
||||
BYPASS("Analog Bypass", RotelConnector.PRIMARY_CMD, (byte) 0x11, "bypass", "bypass"),
|
||||
BYPASS("Analog Bypass", PRIMARY_CMD, (byte) 0x11, "bypass", "bypass"),
|
||||
DSP_MODE("Request current DSP mode", "get_dsp_mode", "dsp_mode"),
|
||||
TONE_MAX("Request Max tone level", "get_tone_max", null),
|
||||
TONE_CONTROL_SELECT("Tone Control Select", RotelConnector.PRIMARY_CMD, (byte) 0x67),
|
||||
TREBLE_UP("Treble Up", RotelConnector.PRIMARY_CMD, (byte) 0x0D, "treble_up", "treble_up"),
|
||||
TREBLE_DOWN("Treble Down", RotelConnector.PRIMARY_CMD, (byte) 0x0E, "treble_down", "treble_down"),
|
||||
TONE_CONTROL_SELECT("Tone Control Select", PRIMARY_CMD, (byte) 0x67),
|
||||
TREBLE_UP("Treble Up", PRIMARY_CMD, (byte) 0x0D, "treble_up", "treble_up"),
|
||||
TREBLE_DOWN("Treble Down", PRIMARY_CMD, (byte) 0x0E, "treble_down", "treble_down"),
|
||||
TREBLE_SET("Set Treble to level", "treble_", "treble_"),
|
||||
TREBLE("Request current treble level", "get_treble", "treble?"),
|
||||
BASS_UP("Bass Up", RotelConnector.PRIMARY_CMD, (byte) 0x0F, "bass_up", "bass_up"),
|
||||
BASS_DOWN("Bass Down", RotelConnector.PRIMARY_CMD, (byte) 0x10, "bass_down", "bass_down"),
|
||||
BASS_UP("Bass Up", PRIMARY_CMD, (byte) 0x0F, "bass_up", "bass_up"),
|
||||
BASS_DOWN("Bass Down", PRIMARY_CMD, (byte) 0x10, "bass_down", "bass_down"),
|
||||
BASS_SET("Set Bass to level", "bass_", "bass_"),
|
||||
BASS("Request current bass level", "get_bass", "bass?"),
|
||||
RECORD_FONCTION_SELECT("Record Function Select", RotelConnector.PRIMARY_CMD, (byte) 0x17),
|
||||
PLAY("Play Source", RotelConnector.PRIMARY_CMD, (byte) 0x04, "play", "play"),
|
||||
STOP("Stop Source", RotelConnector.PRIMARY_CMD, (byte) 0x06, "stop", "stop"),
|
||||
PAUSE("Pause Source", RotelConnector.PRIMARY_CMD, (byte) 0x05, "pause", "pause"),
|
||||
RECORD_FONCTION_SELECT("Record Function Select", PRIMARY_CMD, (byte) 0x17),
|
||||
PLAY("Play Source", PRIMARY_CMD, (byte) 0x04, "play", "play"),
|
||||
STOP("Stop Source", PRIMARY_CMD, (byte) 0x06, "stop", "stop"),
|
||||
PAUSE("Pause Source", PRIMARY_CMD, (byte) 0x05, "pause", "pause"),
|
||||
CD_PLAY_STATUS("Request CD play status", "get_cd_play_status", null),
|
||||
PLAY_STATUS("Request source play status", "get_play_status", "status"),
|
||||
TRACK_FORWARD("Track Forward", RotelConnector.PRIMARY_CMD, (byte) 0x09, "track_fwd", "trkf"),
|
||||
TRACK_BACKWORD("Track Backward", RotelConnector.PRIMARY_CMD, (byte) 0x08, "track_back", "trkb"),
|
||||
TRACK_FORWARD("Track Forward", PRIMARY_CMD, (byte) 0x09, "track_fwd", "trkf"),
|
||||
TRACK_BACKWORD("Track Backward", PRIMARY_CMD, (byte) 0x08, "track_back", "trkb"),
|
||||
TRACK("Request current CD track number", null, "track"),
|
||||
FREQUENCY("Request current frequency for digital source input", "get_current_freq", "freq?"),
|
||||
DISPLAY_REFRESH("Display Refresh", RotelConnector.PRIMARY_CMD, (byte) 0xFF),
|
||||
DISPLAY_REFRESH("Display Refresh", PRIMARY_CMD, (byte) 0xFF),
|
||||
DIMMER_LEVEL_GET("Request current front display dimmer level", "get_current_dimmer", "dimmer?"),
|
||||
DIMMER_LEVEL_SET("Set front display dimmer to level", "dimmer_", "dimmer_"),
|
||||
UPDATE_AUTO("Set Update to Auto", "display_update_auto", "rs232_update_on"),
|
||||
|
@ -245,10 +235,10 @@ public enum RotelCommand {
|
|||
BALANCE_LEFT("Balance Left", "balance_left", "balance_l"),
|
||||
BALANCE_SET("Set Balance to level", "balance_", "balance_"),
|
||||
BALANCE("Request current balance setting", "get_balance", "balance?"),
|
||||
SPEAKER_A_TOGGLE("Toggle Speaker A Output", RotelConnector.PRIMARY_CMD, (byte) 0x50, "speaker_a", "speaker_a"),
|
||||
SPEAKER_A_TOGGLE("Toggle Speaker A Output", PRIMARY_CMD, (byte) 0x50, "speaker_a", "speaker_a"),
|
||||
SPEAKER_A_ON("Set Speaker A Output", "speaker_a_on", "speaker_a_on"),
|
||||
SPEAKER_A_OFF("Unset Speaker A Output", "speaker_a_off", "speaker_a_off"),
|
||||
SPEAKER_B_TOGGLE("Toggle Speaker B Output", RotelConnector.PRIMARY_CMD, (byte) 0x51, "speaker_b", "speaker_b"),
|
||||
SPEAKER_B_TOGGLE("Toggle Speaker B Output", PRIMARY_CMD, (byte) 0x51, "speaker_b", "speaker_b"),
|
||||
SPEAKER_B_ON("Set Speaker B Output", "speaker_b_on", "speaker_b_on"),
|
||||
SPEAKER_B_OFF("Unset Speaker B Output", "speaker_b_off", "speaker_b_off"),
|
||||
SPEAKER("Request current active speaker outputs", "get_current_speaker", "speaker?");
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -19,12 +19,11 @@ import java.io.InputStream;
|
|||
import java.io.InterruptedIOException;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.rotel.internal.RotelException;
|
||||
import org.openhab.binding.rotel.internal.RotelModel;
|
||||
import org.openhab.binding.rotel.internal.protocol.RotelAbstractProtocolHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -48,13 +47,12 @@ public class RotelIpConnector extends RotelConnector {
|
|||
*
|
||||
* @param address the IP address of the projector
|
||||
* @param port the TCP port to be used
|
||||
* @param model the projector model in use
|
||||
* @param protocol the protocol to be used
|
||||
* @param protocolHandler the protocol handler
|
||||
* @param readerThreadName the name of thread to be created
|
||||
*/
|
||||
public RotelIpConnector(String address, Integer port, RotelModel model, RotelProtocol protocol,
|
||||
Map<RotelSource, String> sourcesLabels, String readerThreadName) {
|
||||
super(model, protocol, sourcesLabels, false, readerThreadName);
|
||||
public RotelIpConnector(String address, Integer port, RotelAbstractProtocolHandler protocolHandler,
|
||||
String readerThreadName) {
|
||||
super(protocolHandler, false, readerThreadName);
|
||||
|
||||
this.address = address;
|
||||
this.port = port;
|
||||
|
@ -70,9 +68,7 @@ public class RotelIpConnector extends RotelConnector {
|
|||
dataOut = new DataOutputStream(clientSocket.getOutputStream());
|
||||
dataIn = new DataInputStream(clientSocket.getInputStream());
|
||||
|
||||
Thread thread = new RotelReaderThread(this, readerThreadName);
|
||||
setReaderThread(thread);
|
||||
thread.start();
|
||||
readerThread.start();
|
||||
|
||||
this.clientSocket = clientSocket;
|
||||
|
||||
|
|
|
@ -13,10 +13,10 @@
|
|||
package org.openhab.binding.rotel.internal.communication;
|
||||
|
||||
import java.io.InterruptedIOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.rotel.internal.RotelException;
|
||||
import org.openhab.binding.rotel.internal.protocol.RotelAbstractProtocolHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -28,79 +28,38 @@ import org.slf4j.LoggerFactory;
|
|||
@NonNullByDefault
|
||||
public class RotelReaderThread extends Thread {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(RotelReaderThread.class);
|
||||
|
||||
private static final int READ_BUFFER_SIZE = 16;
|
||||
|
||||
private RotelConnector connector;
|
||||
private final Logger logger = LoggerFactory.getLogger(RotelReaderThread.class);
|
||||
|
||||
private final RotelConnector connector;
|
||||
private final RotelAbstractProtocolHandler protocolHandler;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param connector the object that should handle the received message
|
||||
* @param connector the connector to read input data
|
||||
* @param protocolHandler the protocol handler
|
||||
* @param threadName the name of the thread
|
||||
*/
|
||||
public RotelReaderThread(RotelConnector connector, String threadName) {
|
||||
public RotelReaderThread(RotelConnector connector, RotelAbstractProtocolHandler protocolHandler,
|
||||
String threadName) {
|
||||
super(threadName);
|
||||
this.connector = connector;
|
||||
this.protocolHandler = protocolHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
logger.debug("Data listener started");
|
||||
|
||||
RotelProtocol protocol = connector.getProtocol();
|
||||
final int size = (protocol == RotelProtocol.HEX)
|
||||
? (6 + connector.getModel().getRespNbChars() + connector.getModel().getRespNbFlags())
|
||||
: 64;
|
||||
byte[] readDataBuffer = new byte[READ_BUFFER_SIZE];
|
||||
byte[] dataBuffer = new byte[size];
|
||||
boolean startCodeReached = false;
|
||||
int count = 0;
|
||||
int index = 0;
|
||||
final char terminatingChar = (protocol == RotelProtocol.ASCII_V1) ? '!' : '$';
|
||||
|
||||
try {
|
||||
while (!Thread.interrupted()) {
|
||||
int len = connector.readInput(readDataBuffer);
|
||||
if (len > 0) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (protocol == RotelProtocol.HEX) {
|
||||
if (readDataBuffer[i] == RotelConnector.START) {
|
||||
startCodeReached = true;
|
||||
count = 0;
|
||||
index = 0;
|
||||
}
|
||||
if (startCodeReached) {
|
||||
if (index < size) {
|
||||
dataBuffer[index++] = readDataBuffer[i];
|
||||
}
|
||||
if (index == 2) {
|
||||
count = readDataBuffer[i];
|
||||
} else if ((count > 0) && (index == (count + 3))) {
|
||||
if ((readDataBuffer[i] & 0x000000FF) == 0x000000FD) {
|
||||
count++;
|
||||
} else {
|
||||
byte[] msg = Arrays.copyOf(dataBuffer, index);
|
||||
connector.handleIncomingMessage(msg);
|
||||
startCodeReached = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (index < size) {
|
||||
dataBuffer[index++] = readDataBuffer[i];
|
||||
}
|
||||
if (readDataBuffer[i] == terminatingChar) {
|
||||
if (index >= size) {
|
||||
dataBuffer[index - 1] = (byte) terminatingChar;
|
||||
}
|
||||
byte[] msg = Arrays.copyOf(dataBuffer, index);
|
||||
connector.handleIncomingMessage(msg);
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
protocolHandler.handleIncomingData(readDataBuffer, len);
|
||||
}
|
||||
}
|
||||
} catch (InterruptedIOException e) {
|
||||
|
@ -108,7 +67,7 @@ public class RotelReaderThread extends Thread {
|
|||
logger.debug("Interrupted via InterruptedIOException");
|
||||
} catch (RotelException e) {
|
||||
logger.debug("Reading failed: {}", e.getMessage(), e);
|
||||
connector.handleIncomingMessage(RotelConnector.READ_ERROR);
|
||||
protocolHandler.handleInIncomingError();
|
||||
}
|
||||
|
||||
logger.debug("Data listener stopped");
|
||||
|
|
|
@ -15,12 +15,11 @@ package org.openhab.binding.rotel.internal.communication;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.rotel.internal.RotelException;
|
||||
import org.openhab.binding.rotel.internal.RotelModel;
|
||||
import org.openhab.binding.rotel.internal.protocol.RotelAbstractProtocolHandler;
|
||||
import org.openhab.core.io.transport.serial.PortInUseException;
|
||||
import org.openhab.core.io.transport.serial.SerialPort;
|
||||
import org.openhab.core.io.transport.serial.SerialPortIdentifier;
|
||||
|
@ -42,6 +41,8 @@ public class RotelSerialConnector extends RotelConnector {
|
|||
private String serialPortName;
|
||||
private SerialPortManager serialPortManager;
|
||||
|
||||
private int baudRate;
|
||||
|
||||
private @Nullable SerialPort serialPort;
|
||||
|
||||
/**
|
||||
|
@ -49,14 +50,15 @@ public class RotelSerialConnector extends RotelConnector {
|
|||
*
|
||||
* @param serialPortManager the serial port manager
|
||||
* @param serialPortName the serial port name to be used
|
||||
* @param model the projector model in use
|
||||
* @param protocol the protocol to be used
|
||||
* @param baudRate the baud rate to be used
|
||||
* @param protocolHandler the protocol handler
|
||||
* @param readerThreadName the name of thread to be created
|
||||
*/
|
||||
public RotelSerialConnector(SerialPortManager serialPortManager, String serialPortName, RotelModel model,
|
||||
RotelProtocol protocol, Map<RotelSource, String> sourcesLabels, String readerThreadName) {
|
||||
super(model, protocol, sourcesLabels, false, readerThreadName);
|
||||
public RotelSerialConnector(SerialPortManager serialPortManager, String serialPortName, int baudRate,
|
||||
RotelAbstractProtocolHandler protocolHandler, String readerThreadName) {
|
||||
super(protocolHandler, false, readerThreadName);
|
||||
|
||||
this.baudRate = baudRate;
|
||||
this.serialPortManager = serialPortManager;
|
||||
this.serialPortName = serialPortName;
|
||||
}
|
||||
|
@ -73,7 +75,7 @@ public class RotelSerialConnector extends RotelConnector {
|
|||
|
||||
SerialPort commPort = portIdentifier.open(this.getClass().getName(), 2000);
|
||||
|
||||
commPort.setSerialPortParams(getModel().getBaudRate(), SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
|
||||
commPort.setSerialPortParams(baudRate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
|
||||
SerialPort.PARITY_NONE);
|
||||
commPort.enableReceiveThreshold(1);
|
||||
commPort.enableReceiveTimeout(100);
|
||||
|
@ -92,9 +94,7 @@ public class RotelSerialConnector extends RotelConnector {
|
|||
}
|
||||
}
|
||||
|
||||
Thread thread = new RotelReaderThread(this, readerThreadName);
|
||||
setReaderThread(thread);
|
||||
thread.start();
|
||||
readerThread.start();
|
||||
|
||||
this.serialPort = commPort;
|
||||
this.dataIn = dataIn;
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
*/
|
||||
package org.openhab.binding.rotel.internal.communication;
|
||||
|
||||
import static org.openhab.binding.rotel.internal.RotelBindingConstants.*;
|
||||
import static org.openhab.binding.rotel.internal.protocol.hex.RotelHexProtocolHandler.START;
|
||||
|
||||
import java.io.InterruptedIOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
|
@ -23,6 +26,9 @@ import org.eclipse.jdt.annotation.Nullable;
|
|||
import org.openhab.binding.rotel.internal.RotelException;
|
||||
import org.openhab.binding.rotel.internal.RotelModel;
|
||||
import org.openhab.binding.rotel.internal.RotelPlayStatus;
|
||||
import org.openhab.binding.rotel.internal.protocol.RotelAbstractProtocolHandler;
|
||||
import org.openhab.binding.rotel.internal.protocol.RotelProtocol;
|
||||
import org.openhab.binding.rotel.internal.protocol.hex.RotelHexProtocolHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -34,9 +40,13 @@ import org.slf4j.LoggerFactory;
|
|||
@NonNullByDefault
|
||||
public class RotelSimuConnector extends RotelConnector {
|
||||
|
||||
private static final int STEP_TONE_LEVEL = 1;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(RotelSimuConnector.class);
|
||||
|
||||
private static final int STEP_TONE_LEVEL = 1;
|
||||
private final RotelModel model;
|
||||
private final RotelProtocol protocol;
|
||||
private final Map<RotelSource, String> sourcesLabels;
|
||||
|
||||
private Object lock = new Object();
|
||||
|
||||
|
@ -80,12 +90,16 @@ public class RotelSimuConnector extends RotelConnector {
|
|||
* Constructor
|
||||
*
|
||||
* @param model the projector model in use
|
||||
* @param protocol the protocol to be used
|
||||
* @param protocolHandler the protocol handler
|
||||
* @param sourcesLabels the custom labels for sources
|
||||
* @param readerThreadName the name of thread to be created
|
||||
*/
|
||||
public RotelSimuConnector(RotelModel model, RotelProtocol protocol, Map<RotelSource, String> sourcesLabels,
|
||||
String readerThreadName) {
|
||||
super(model, protocol, sourcesLabels, true, readerThreadName);
|
||||
public RotelSimuConnector(RotelModel model, RotelAbstractProtocolHandler protocolHandler,
|
||||
Map<RotelSource, String> sourcesLabels, String readerThreadName) {
|
||||
super(protocolHandler, true, readerThreadName);
|
||||
this.model = model;
|
||||
this.protocol = protocolHandler.getProtocol();
|
||||
this.sourcesLabels = sourcesLabels;
|
||||
this.minVolume = 0;
|
||||
this.maxVolume = model.hasVolumeControl() ? model.getVolumeMax() : 0;
|
||||
this.maxToneLevel = model.hasToneControl() ? model.getToneLevelMax() : 0;
|
||||
|
@ -95,9 +109,7 @@ public class RotelSimuConnector extends RotelConnector {
|
|||
@Override
|
||||
public synchronized void open() throws RotelException {
|
||||
logger.debug("Opening simulated connection");
|
||||
Thread thread = new RotelReaderThread(this, readerThreadName);
|
||||
setReaderThread(thread);
|
||||
thread.start();
|
||||
readerThread.start();
|
||||
setConnected(true);
|
||||
logger.debug("Simulated connection opened");
|
||||
}
|
||||
|
@ -132,23 +144,13 @@ public class RotelSimuConnector extends RotelConnector {
|
|||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendCommand(RotelCommand cmd, @Nullable Integer value) throws RotelException {
|
||||
super.sendCommand(cmd, value);
|
||||
if ((getProtocol() == RotelProtocol.HEX && cmd.getHexType() != 0)
|
||||
|| (getProtocol() == RotelProtocol.ASCII_V1 && cmd.getAsciiCommandV1() != null)
|
||||
|| (getProtocol() == RotelProtocol.ASCII_V2 && cmd.getAsciiCommandV2() != null)) {
|
||||
buildFeedbackMessage(cmd, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Built the simulated feedback message for a sent command
|
||||
*
|
||||
* @param cmd the sent command
|
||||
* @param value the integer value considered in the sent command for volume, bass or treble adjustment
|
||||
*/
|
||||
private void buildFeedbackMessage(RotelCommand cmd, @Nullable Integer value) {
|
||||
public void buildFeedbackMessage(RotelCommand cmd, @Nullable Integer value) {
|
||||
String text = buildSourceLine1Response();
|
||||
String textLine1Left = buildSourceLine1LeftResponse();
|
||||
String textLine1Right = buildVolumeLine1RightResponse();
|
||||
|
@ -180,14 +182,14 @@ public class RotelSimuConnector extends RotelConnector {
|
|||
break;
|
||||
case ZONE2_POWER_OFF:
|
||||
powerZone2 = false;
|
||||
text = textLine2 = buildZonePowerResponse(getModel().getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
|
||||
text = textLine2 = buildZonePowerResponse(model.getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
|
||||
powerZone2, sourceZone2);
|
||||
showZone = 2;
|
||||
resetZone = false;
|
||||
break;
|
||||
case ZONE2_POWER_ON:
|
||||
powerZone2 = true;
|
||||
text = textLine2 = buildZonePowerResponse(getModel().getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
|
||||
text = textLine2 = buildZonePowerResponse(model.getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
|
||||
powerZone2, sourceZone2);
|
||||
showZone = 2;
|
||||
resetZone = false;
|
||||
|
@ -217,9 +219,9 @@ public class RotelSimuConnector extends RotelConnector {
|
|||
resetZone = false;
|
||||
break;
|
||||
case RECORD_FONCTION_SELECT:
|
||||
if (getModel().getNbAdditionalZones() >= 1 && getModel().getZoneSelectCmd() == cmd) {
|
||||
if (model.getNbAdditionalZones() >= 1 && model.getZoneSelectCmd() == cmd) {
|
||||
showZone++;
|
||||
if (showZone > getModel().getNbAdditionalZones()) {
|
||||
if (showZone > model.getNbAdditionalZones()) {
|
||||
showZone = 1;
|
||||
if (!power) {
|
||||
showZone++;
|
||||
|
@ -234,7 +236,7 @@ public class RotelSimuConnector extends RotelConnector {
|
|||
textLine2 = buildRecordResponse();
|
||||
} else if (showZone == 2) {
|
||||
selectingRecord = false;
|
||||
text = textLine2 = buildZonePowerResponse(getModel().getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
|
||||
text = textLine2 = buildZonePowerResponse(model.getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
|
||||
powerZone2, sourceZone2);
|
||||
} else if (showZone == 3) {
|
||||
selectingRecord = false;
|
||||
|
@ -246,12 +248,12 @@ public class RotelSimuConnector extends RotelConnector {
|
|||
resetZone = false;
|
||||
break;
|
||||
case ZONE_SELECT:
|
||||
if (getModel().getNbAdditionalZones() == 0
|
||||
|| (getModel().getNbAdditionalZones() > 1 && getModel().getZoneSelectCmd() == cmd)
|
||||
|| (showZone == 1 && getModel().getZoneSelectCmd() != cmd)) {
|
||||
if (model.getNbAdditionalZones() == 0
|
||||
|| (model.getNbAdditionalZones() > 1 && model.getZoneSelectCmd() == cmd)
|
||||
|| (showZone == 1 && model.getZoneSelectCmd() != cmd)) {
|
||||
accepted = false;
|
||||
} else {
|
||||
if (getModel().getZoneSelectCmd() == cmd) {
|
||||
if (model.getZoneSelectCmd() == cmd) {
|
||||
if (!power && !powerZone2) {
|
||||
showZone = 2;
|
||||
powerZone2 = true;
|
||||
|
@ -270,8 +272,8 @@ public class RotelSimuConnector extends RotelConnector {
|
|||
}
|
||||
}
|
||||
if (showZone == 2) {
|
||||
text = textLine2 = buildZonePowerResponse(
|
||||
getModel().getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE", powerZone2, sourceZone2);
|
||||
text = textLine2 = buildZonePowerResponse(model.getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
|
||||
powerZone2, sourceZone2);
|
||||
} else if (showZone == 3) {
|
||||
text = textLine2 = buildZonePowerResponse("ZONE3", powerZone3, sourceZone3);
|
||||
} else if (showZone == 4) {
|
||||
|
@ -291,54 +293,54 @@ public class RotelSimuConnector extends RotelConnector {
|
|||
if (volumeZone2 < maxVolume) {
|
||||
volumeZone2++;
|
||||
}
|
||||
text = textLine2 = buildZoneVolumeResponse(getModel().getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
|
||||
text = textLine2 = buildZoneVolumeResponse(model.getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
|
||||
muteZone2, volumeZone2);
|
||||
break;
|
||||
case ZONE2_VOLUME_DOWN:
|
||||
if (volumeZone2 > minVolume) {
|
||||
volumeZone2--;
|
||||
}
|
||||
text = textLine2 = buildZoneVolumeResponse(getModel().getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
|
||||
text = textLine2 = buildZoneVolumeResponse(model.getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
|
||||
muteZone2, volumeZone2);
|
||||
break;
|
||||
case ZONE2_VOLUME_SET:
|
||||
if (value != null) {
|
||||
volumeZone2 = value;
|
||||
}
|
||||
text = textLine2 = buildZoneVolumeResponse(getModel().getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
|
||||
text = textLine2 = buildZoneVolumeResponse(model.getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
|
||||
muteZone2, volumeZone2);
|
||||
break;
|
||||
case VOLUME_UP:
|
||||
if (!getModel().hasZone2Commands() && getModel().getNbAdditionalZones() >= 1 && showZone == 2) {
|
||||
if (!model.hasZone2Commands() && model.getNbAdditionalZones() >= 1 && showZone == 2) {
|
||||
if (volumeZone2 < maxVolume) {
|
||||
volumeZone2++;
|
||||
}
|
||||
text = textLine2 = buildZoneVolumeResponse(
|
||||
getModel().getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE", muteZone2, volumeZone2);
|
||||
text = textLine2 = buildZoneVolumeResponse(model.getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
|
||||
muteZone2, volumeZone2);
|
||||
resetZone = false;
|
||||
} else {
|
||||
accepted = false;
|
||||
}
|
||||
break;
|
||||
case VOLUME_DOWN:
|
||||
if (!getModel().hasZone2Commands() && getModel().getNbAdditionalZones() >= 1 && showZone == 2) {
|
||||
if (!model.hasZone2Commands() && model.getNbAdditionalZones() >= 1 && showZone == 2) {
|
||||
if (volumeZone2 > minVolume) {
|
||||
volumeZone2--;
|
||||
}
|
||||
text = textLine2 = buildZoneVolumeResponse(
|
||||
getModel().getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE", muteZone2, volumeZone2);
|
||||
text = textLine2 = buildZoneVolumeResponse(model.getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
|
||||
muteZone2, volumeZone2);
|
||||
resetZone = false;
|
||||
} else {
|
||||
accepted = false;
|
||||
}
|
||||
break;
|
||||
case VOLUME_SET:
|
||||
if (!getModel().hasZone2Commands() && getModel().getNbAdditionalZones() >= 1 && showZone == 2) {
|
||||
if (!model.hasZone2Commands() && model.getNbAdditionalZones() >= 1 && showZone == 2) {
|
||||
if (value != null) {
|
||||
volumeZone2 = value;
|
||||
}
|
||||
text = textLine2 = buildZoneVolumeResponse(
|
||||
getModel().getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE", muteZone2, volumeZone2);
|
||||
text = textLine2 = buildZoneVolumeResponse(model.getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
|
||||
muteZone2, volumeZone2);
|
||||
resetZone = false;
|
||||
} else {
|
||||
accepted = false;
|
||||
|
@ -346,17 +348,17 @@ public class RotelSimuConnector extends RotelConnector {
|
|||
break;
|
||||
case ZONE2_MUTE_TOGGLE:
|
||||
muteZone2 = !muteZone2;
|
||||
text = textLine2 = buildZoneVolumeResponse(getModel().getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
|
||||
text = textLine2 = buildZoneVolumeResponse(model.getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
|
||||
muteZone2, volumeZone2);
|
||||
break;
|
||||
case ZONE2_MUTE_ON:
|
||||
muteZone2 = true;
|
||||
text = textLine2 = buildZoneVolumeResponse(getModel().getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
|
||||
text = textLine2 = buildZoneVolumeResponse(model.getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
|
||||
muteZone2, volumeZone2);
|
||||
break;
|
||||
case ZONE2_MUTE_OFF:
|
||||
muteZone2 = false;
|
||||
text = textLine2 = buildZoneVolumeResponse(getModel().getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
|
||||
text = textLine2 = buildZoneVolumeResponse(model.getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
|
||||
muteZone2, volumeZone2);
|
||||
break;
|
||||
default:
|
||||
|
@ -365,9 +367,9 @@ public class RotelSimuConnector extends RotelConnector {
|
|||
}
|
||||
if (!accepted) {
|
||||
try {
|
||||
sourceZone2 = getModel().getZone2SourceFromCommand(cmd);
|
||||
sourceZone2 = model.getZone2SourceFromCommand(cmd);
|
||||
powerZone2 = true;
|
||||
text = textLine2 = buildZonePowerResponse(getModel().getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
|
||||
text = textLine2 = buildZonePowerResponse(model.getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
|
||||
powerZone2, sourceZone2);
|
||||
muteZone2 = false;
|
||||
accepted = true;
|
||||
|
@ -376,12 +378,11 @@ public class RotelSimuConnector extends RotelConnector {
|
|||
} catch (RotelException e) {
|
||||
}
|
||||
}
|
||||
if (!accepted && !getModel().hasZone2Commands() && getModel().getNbAdditionalZones() >= 1
|
||||
&& showZone == 2) {
|
||||
if (!accepted && !model.hasZone2Commands() && model.getNbAdditionalZones() >= 1 && showZone == 2) {
|
||||
try {
|
||||
sourceZone2 = getModel().getSourceFromCommand(cmd);
|
||||
sourceZone2 = model.getSourceFromCommand(cmd);
|
||||
powerZone2 = true;
|
||||
text = textLine2 = buildZonePowerResponse(getModel().getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
|
||||
text = textLine2 = buildZonePowerResponse(model.getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
|
||||
powerZone2, sourceZone2);
|
||||
muteZone2 = false;
|
||||
accepted = true;
|
||||
|
@ -429,7 +430,7 @@ public class RotelSimuConnector extends RotelConnector {
|
|||
}
|
||||
if (!accepted) {
|
||||
try {
|
||||
sourceZone3 = getModel().getZone3SourceFromCommand(cmd);
|
||||
sourceZone3 = model.getZone3SourceFromCommand(cmd);
|
||||
powerZone3 = true;
|
||||
text = textLine2 = buildZonePowerResponse("ZONE3", powerZone3, sourceZone3);
|
||||
muteZone3 = false;
|
||||
|
@ -479,7 +480,7 @@ public class RotelSimuConnector extends RotelConnector {
|
|||
}
|
||||
if (!accepted) {
|
||||
try {
|
||||
sourceZone4 = getModel().getZone4SourceFromCommand(cmd);
|
||||
sourceZone4 = model.getZone4SourceFromCommand(cmd);
|
||||
powerZone4 = true;
|
||||
text = textLine2 = buildZonePowerResponse("ZONE4", powerZone4, sourceZone4);
|
||||
muteZone4 = false;
|
||||
|
@ -495,11 +496,11 @@ public class RotelSimuConnector extends RotelConnector {
|
|||
switch (cmd) {
|
||||
case UPDATE_AUTO:
|
||||
textAscii = buildAsciiResponse(
|
||||
getProtocol() == RotelProtocol.ASCII_V1 ? KEY_DISPLAY_UPDATE : KEY_UPDATE_MODE, "AUTO");
|
||||
protocol == RotelProtocol.ASCII_V1 ? KEY_DISPLAY_UPDATE : KEY_UPDATE_MODE, AUTO);
|
||||
break;
|
||||
case UPDATE_MANUAL:
|
||||
textAscii = buildAsciiResponse(
|
||||
getProtocol() == RotelProtocol.ASCII_V1 ? KEY_DISPLAY_UPDATE : KEY_UPDATE_MODE, "MANUAL");
|
||||
protocol == RotelProtocol.ASCII_V1 ? KEY_DISPLAY_UPDATE : KEY_UPDATE_MODE, MANUAL);
|
||||
break;
|
||||
case VOLUME_GET_MIN:
|
||||
textAscii = buildAsciiResponse(KEY_VOLUME_MIN, minVolume);
|
||||
|
@ -668,7 +669,7 @@ public class RotelSimuConnector extends RotelConnector {
|
|||
multiinput = !multiinput;
|
||||
text = "MULTI IN " + (multiinput ? "ON" : "OFF");
|
||||
try {
|
||||
source = getModel().getSourceFromCommand(cmd);
|
||||
source = model.getSourceFromCommand(cmd);
|
||||
textLine1Left = buildSourceLine1LeftResponse();
|
||||
textAscii = buildSourceAsciiResponse();
|
||||
mute = false;
|
||||
|
@ -795,7 +796,7 @@ public class RotelSimuConnector extends RotelConnector {
|
|||
}
|
||||
if (!accepted) {
|
||||
try {
|
||||
source = getModel().getMainZoneSourceFromCommand(cmd);
|
||||
source = model.getMainZoneSourceFromCommand(cmd);
|
||||
text = buildSourceLine1Response();
|
||||
textLine1Left = buildSourceLine1LeftResponse();
|
||||
textAscii = buildSourceAsciiResponse();
|
||||
|
@ -805,10 +806,10 @@ public class RotelSimuConnector extends RotelConnector {
|
|||
}
|
||||
if (!accepted) {
|
||||
try {
|
||||
if (selectingRecord && !getModel().hasOtherThanPrimaryCommands()) {
|
||||
recordSource = getModel().getSourceFromCommand(cmd);
|
||||
if (selectingRecord && !model.hasOtherThanPrimaryCommands()) {
|
||||
recordSource = model.getSourceFromCommand(cmd);
|
||||
} else {
|
||||
source = getModel().getSourceFromCommand(cmd);
|
||||
source = model.getSourceFromCommand(cmd);
|
||||
}
|
||||
text = buildSourceLine1Response();
|
||||
textLine1Left = buildSourceLine1LeftResponse();
|
||||
|
@ -820,7 +821,7 @@ public class RotelSimuConnector extends RotelConnector {
|
|||
}
|
||||
if (!accepted) {
|
||||
try {
|
||||
recordSource = getModel().getRecordSourceFromCommand(cmd);
|
||||
recordSource = model.getRecordSourceFromCommand(cmd);
|
||||
text = buildSourceLine1Response();
|
||||
textLine2 = buildRecordResponse();
|
||||
accepted = true;
|
||||
|
@ -840,7 +841,7 @@ public class RotelSimuConnector extends RotelConnector {
|
|||
showZone = 0;
|
||||
}
|
||||
|
||||
if (getModel().getRespNbChars() == 42) {
|
||||
if (model.getRespNbChars() == 42) {
|
||||
while (textLine1Left.length() < 14) {
|
||||
textLine1Left += " ";
|
||||
}
|
||||
|
@ -853,44 +854,44 @@ public class RotelSimuConnector extends RotelConnector {
|
|||
text = textLine1Left + textLine1Right + textLine2;
|
||||
}
|
||||
|
||||
if (getProtocol() == RotelProtocol.HEX) {
|
||||
byte[] chars = Arrays.copyOf(text.getBytes(StandardCharsets.US_ASCII), getModel().getRespNbChars());
|
||||
byte[] flags = new byte[getModel().getRespNbFlags()];
|
||||
if (protocol == RotelProtocol.HEX) {
|
||||
byte[] chars = Arrays.copyOf(text.getBytes(StandardCharsets.US_ASCII), model.getRespNbChars());
|
||||
byte[] flags = new byte[model.getRespNbFlags()];
|
||||
try {
|
||||
getModel().setMultiInput(flags, multiinput);
|
||||
model.setMultiInput(flags, multiinput);
|
||||
} catch (RotelException e) {
|
||||
}
|
||||
try {
|
||||
getModel().setZone2(flags, powerZone2);
|
||||
model.setZone2(flags, powerZone2);
|
||||
} catch (RotelException e) {
|
||||
}
|
||||
try {
|
||||
getModel().setZone3(flags, powerZone3);
|
||||
model.setZone3(flags, powerZone3);
|
||||
} catch (RotelException e) {
|
||||
}
|
||||
try {
|
||||
getModel().setZone4(flags, powerZone4);
|
||||
model.setZone4(flags, powerZone4);
|
||||
} catch (RotelException e) {
|
||||
}
|
||||
int size = 6 + getModel().getRespNbChars() + getModel().getRespNbFlags();
|
||||
int size = 6 + model.getRespNbChars() + model.getRespNbFlags();
|
||||
byte[] dataBuffer = new byte[size];
|
||||
int idx = 0;
|
||||
dataBuffer[idx++] = START;
|
||||
dataBuffer[idx++] = (byte) (size - 4);
|
||||
dataBuffer[idx++] = getModel().getDeviceId();
|
||||
dataBuffer[idx++] = model.getDeviceId();
|
||||
dataBuffer[idx++] = STANDARD_RESPONSE;
|
||||
if (getModel().isCharsBeforeFlags()) {
|
||||
System.arraycopy(chars, 0, dataBuffer, idx, getModel().getRespNbChars());
|
||||
idx += getModel().getRespNbChars();
|
||||
System.arraycopy(flags, 0, dataBuffer, idx, getModel().getRespNbFlags());
|
||||
idx += getModel().getRespNbFlags();
|
||||
if (model.isCharsBeforeFlags()) {
|
||||
System.arraycopy(chars, 0, dataBuffer, idx, model.getRespNbChars());
|
||||
idx += model.getRespNbChars();
|
||||
System.arraycopy(flags, 0, dataBuffer, idx, model.getRespNbFlags());
|
||||
idx += model.getRespNbFlags();
|
||||
} else {
|
||||
System.arraycopy(flags, 0, dataBuffer, idx, getModel().getRespNbFlags());
|
||||
idx += getModel().getRespNbFlags();
|
||||
System.arraycopy(chars, 0, dataBuffer, idx, getModel().getRespNbChars());
|
||||
idx += getModel().getRespNbChars();
|
||||
System.arraycopy(flags, 0, dataBuffer, idx, model.getRespNbFlags());
|
||||
idx += model.getRespNbFlags();
|
||||
System.arraycopy(chars, 0, dataBuffer, idx, model.getRespNbChars());
|
||||
idx += model.getRespNbChars();
|
||||
}
|
||||
byte checksum = computeCheckSum(dataBuffer, idx - 1);
|
||||
byte checksum = RotelHexProtocolHandler.computeCheckSum(dataBuffer, idx - 1);
|
||||
if ((checksum & 0x000000FF) == 0x000000FD) {
|
||||
dataBuffer[idx++] = (byte) 0xFD;
|
||||
dataBuffer[idx++] = 0;
|
||||
|
@ -905,7 +906,7 @@ public class RotelSimuConnector extends RotelConnector {
|
|||
idxInFeedbackMsg = 0;
|
||||
}
|
||||
} else {
|
||||
String command = textAscii + (getProtocol() == RotelProtocol.ASCII_V1 ? "!" : "$");
|
||||
String command = textAscii + (protocol == RotelProtocol.ASCII_V1 ? "!" : "$");
|
||||
synchronized (lock) {
|
||||
feedbackMsg = command.getBytes(StandardCharsets.US_ASCII);
|
||||
idxInFeedbackMsg = 0;
|
||||
|
@ -978,8 +979,7 @@ public class RotelSimuConnector extends RotelConnector {
|
|||
status = STOP;
|
||||
break;
|
||||
}
|
||||
return buildAsciiResponse(getProtocol() == RotelProtocol.ASCII_V1 ? KEY1_PLAY_STATUS : KEY2_PLAY_STATUS,
|
||||
status);
|
||||
return buildAsciiResponse(protocol == RotelProtocol.ASCII_V1 ? KEY1_PLAY_STATUS : KEY2_PLAY_STATUS, status);
|
||||
}
|
||||
|
||||
private String buildTrackAsciiResponse() {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,133 @@
|
|||
/**
|
||||
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.rotel.internal.protocol;
|
||||
|
||||
import static org.openhab.binding.rotel.internal.RotelBindingConstants.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.rotel.internal.RotelException;
|
||||
import org.openhab.binding.rotel.internal.RotelModel;
|
||||
import org.openhab.binding.rotel.internal.communication.RotelCommand;
|
||||
import org.openhab.core.util.HexUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Abstract class for handling a Rotel protocol (build of command messages, decoding of incoming data)
|
||||
*
|
||||
* @author Laurent Garnier - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class RotelAbstractProtocolHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(RotelAbstractProtocolHandler.class);
|
||||
|
||||
protected final RotelModel model;
|
||||
|
||||
private final List<RotelMessageEventListener> listeners = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param model the Rotel model in use
|
||||
*/
|
||||
public RotelAbstractProtocolHandler(RotelModel model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
public abstract RotelProtocol getProtocol();
|
||||
|
||||
/**
|
||||
* Build the message associated to a Rotel command
|
||||
*
|
||||
* @param cmd the command to execute
|
||||
* @param value the integer value to consider for volume, bass or treble adjustment
|
||||
*
|
||||
* @throws RotelException - In case the command is not supported by the protocol
|
||||
*/
|
||||
public abstract byte[] buildCommandMessage(RotelCommand cmd, @Nullable Integer value) throws RotelException;
|
||||
|
||||
public abstract void handleIncomingData(byte[] inDataBuffer, int length);
|
||||
|
||||
public void handleInIncomingError() {
|
||||
dispatchKeyValue(KEY_ERROR, MSG_VALUE_ON);
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyze an incoming message and dispatch corresponding (key, value) to the event listeners
|
||||
*
|
||||
* @param incomingMessage the received message
|
||||
*/
|
||||
protected void handleIncomingMessage(byte[] incomingMessage) {
|
||||
logger.debug("handleIncomingMessage: bytes {}", HexUtils.bytesToHex(incomingMessage));
|
||||
|
||||
try {
|
||||
validateResponse(incomingMessage);
|
||||
} catch (RotelException e) {
|
||||
return;
|
||||
}
|
||||
|
||||
handleValidMessage(incomingMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the content of a feedback message
|
||||
*
|
||||
* @param responseMessage the buffer containing the feedback message
|
||||
*
|
||||
* @throws RotelException - If the message has unexpected content
|
||||
*/
|
||||
protected abstract void validateResponse(byte[] responseMessage) throws RotelException;
|
||||
|
||||
/**
|
||||
* Analyze a valid HEX message and dispatch corresponding (key, value) to the event listeners
|
||||
*
|
||||
* @param incomingMessage the received message
|
||||
*/
|
||||
protected abstract void handleValidMessage(byte[] incomingMessage);
|
||||
|
||||
/**
|
||||
* Add a listener to the list of listeners to be notified with events
|
||||
*
|
||||
* @param listener the listener
|
||||
*/
|
||||
public void addEventListener(RotelMessageEventListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a listener from the list of listeners to be notified with events
|
||||
*
|
||||
* @param listener the listener
|
||||
*/
|
||||
public void removeEventListener(RotelMessageEventListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch an event (key, value) to the event listeners
|
||||
*
|
||||
* @param key the key
|
||||
* @param value the value
|
||||
*/
|
||||
protected void dispatchKeyValue(String key, String value) {
|
||||
RotelMessageEvent event = new RotelMessageEvent(this, key, value);
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
listeners.get(i).onNewMessageEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,7 +10,7 @@
|
|||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.rotel.internal.communication;
|
||||
package org.openhab.binding.rotel.internal.protocol;
|
||||
|
||||
import java.util.EventObject;
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.rotel.internal.communication;
|
||||
package org.openhab.binding.rotel.internal.protocol;
|
||||
|
||||
import java.util.EventListener;
|
||||
import java.util.EventObject;
|
|
@ -10,7 +10,7 @@
|
|||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.rotel.internal.communication;
|
||||
package org.openhab.binding.rotel.internal.protocol;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.rotel.internal.RotelException;
|
|
@ -0,0 +1,195 @@
|
|||
/**
|
||||
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.rotel.internal.protocol.ascii;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.rotel.internal.RotelException;
|
||||
import org.openhab.binding.rotel.internal.RotelModel;
|
||||
import org.openhab.binding.rotel.internal.protocol.RotelAbstractProtocolHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Abstract class for handling a Rotel ASCII protocol (build of command messages, decoding of incoming data)
|
||||
*
|
||||
* @author Laurent Garnier - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class RotelAbstractAsciiProtocolHandler extends RotelAbstractProtocolHandler {
|
||||
|
||||
/** Special characters that can be found in the feedback messages for several devices using the ASCII protocol */
|
||||
public static final byte[][] SPECIAL_CHARACTERS = { { (byte) 0xEE, (byte) 0x82, (byte) 0x85 },
|
||||
{ (byte) 0xEE, (byte) 0x82, (byte) 0x84 }, { (byte) 0xEE, (byte) 0x82, (byte) 0x92 },
|
||||
{ (byte) 0xEE, (byte) 0x82, (byte) 0x87 }, { (byte) 0xEE, (byte) 0x82, (byte) 0x8E },
|
||||
{ (byte) 0xEE, (byte) 0x82, (byte) 0x89 }, { (byte) 0xEE, (byte) 0x82, (byte) 0x93 },
|
||||
{ (byte) 0xEE, (byte) 0x82, (byte) 0x8C }, { (byte) 0xEE, (byte) 0x82, (byte) 0x8F },
|
||||
{ (byte) 0xEE, (byte) 0x82, (byte) 0x8A }, { (byte) 0xEE, (byte) 0x82, (byte) 0x8B },
|
||||
{ (byte) 0xEE, (byte) 0x82, (byte) 0x81 }, { (byte) 0xEE, (byte) 0x82, (byte) 0x82 },
|
||||
{ (byte) 0xEE, (byte) 0x82, (byte) 0x83 }, { (byte) 0xEE, (byte) 0x82, (byte) 0x94 },
|
||||
{ (byte) 0xEE, (byte) 0x82, (byte) 0x97 }, { (byte) 0xEE, (byte) 0x82, (byte) 0x98 },
|
||||
{ (byte) 0xEE, (byte) 0x82, (byte) 0x80 }, { (byte) 0xEE, (byte) 0x82, (byte) 0x99 },
|
||||
{ (byte) 0xEE, (byte) 0x82, (byte) 0x9A }, { (byte) 0xEE, (byte) 0x82, (byte) 0x88 },
|
||||
{ (byte) 0xEE, (byte) 0x82, (byte) 0x95 }, { (byte) 0xEE, (byte) 0x82, (byte) 0x96 },
|
||||
{ (byte) 0xEE, (byte) 0x82, (byte) 0x90 }, { (byte) 0xEE, (byte) 0x82, (byte) 0x91 },
|
||||
{ (byte) 0xEE, (byte) 0x82, (byte) 0x8D }, { (byte) 0xEE, (byte) 0x80, (byte) 0x80, (byte) 0xEE,
|
||||
(byte) 0x80, (byte) 0x81, (byte) 0xEE, (byte) 0x80, (byte) 0x82 } };
|
||||
|
||||
/** Special characters that can be found in the feedback messages for the RCD-1572 */
|
||||
public static final byte[][] SPECIAL_CHARACTERS_RCD1572 = { { (byte) 0xC2, (byte) 0x8C },
|
||||
{ (byte) 0xC2, (byte) 0x54 }, { (byte) 0xC2, (byte) 0x81 }, { (byte) 0xC2, (byte) 0x82 },
|
||||
{ (byte) 0xC2, (byte) 0x83 } };
|
||||
|
||||
/** Empty table of special characters */
|
||||
public static final byte[][] NO_SPECIAL_CHARACTERS = {};
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(RotelAbstractAsciiProtocolHandler.class);
|
||||
|
||||
private final char terminatingChar;
|
||||
private final int size;
|
||||
private final byte[] dataBuffer;
|
||||
|
||||
private int index;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param model the Rotel model in use
|
||||
* @param protocol the protocol to be used
|
||||
*/
|
||||
public RotelAbstractAsciiProtocolHandler(RotelModel model, char terminatingChar) {
|
||||
super(model);
|
||||
this.terminatingChar = terminatingChar;
|
||||
this.size = 64;
|
||||
this.dataBuffer = new byte[size];
|
||||
this.index = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleIncomingData(byte[] inDataBuffer, int length) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (index < size) {
|
||||
dataBuffer[index++] = inDataBuffer[i];
|
||||
}
|
||||
if (inDataBuffer[i] == terminatingChar) {
|
||||
if (index >= size) {
|
||||
dataBuffer[index - 1] = (byte) terminatingChar;
|
||||
}
|
||||
byte[] msg = Arrays.copyOf(dataBuffer, index);
|
||||
handleIncomingMessage(msg);
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the content of a feedback message
|
||||
*
|
||||
* @param responseMessage the buffer containing the feedback message
|
||||
*
|
||||
* @throws RotelException - If the message has unexpected content
|
||||
*/
|
||||
@Override
|
||||
protected void validateResponse(byte[] responseMessage) throws RotelException {
|
||||
// Check minimum message length
|
||||
if (responseMessage.length < 1) {
|
||||
logger.debug("Unexpected message length: {}", responseMessage.length);
|
||||
throw new RotelException("Unexpected message length");
|
||||
}
|
||||
|
||||
if (responseMessage[responseMessage.length - 1] != '!' && responseMessage[responseMessage.length - 1] != '$') {
|
||||
logger.debug("Unexpected ending character in response: {}",
|
||||
Integer.toHexString(responseMessage[responseMessage.length - 1] & 0x000000FF));
|
||||
throw new RotelException("Unexpected ending character in response");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyze a valid ASCII message and dispatch corresponding (key, value) to the event listeners
|
||||
*
|
||||
* @param incomingMessage the received message
|
||||
*/
|
||||
@Override
|
||||
protected void handleValidMessage(byte[] incomingMessage) {
|
||||
byte[] message = filterMessage(incomingMessage, model.getSpecialCharacters());
|
||||
|
||||
// Replace characters with code < 32 by a space before converting to a string
|
||||
for (int i = 0; i < message.length; i++) {
|
||||
if (message[i] < 0x20) {
|
||||
message[i] = 0x20;
|
||||
}
|
||||
}
|
||||
|
||||
String value = new String(message, 0, message.length - 1, StandardCharsets.US_ASCII);
|
||||
logger.debug("handleValidAsciiMessage: chars *{}*", value);
|
||||
value = value.trim();
|
||||
if (value.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
String[] splittedValue = value.split("=");
|
||||
if (splittedValue.length != 2) {
|
||||
logger.debug("handleValidAsciiMessage: ignored message {}", value);
|
||||
} else {
|
||||
dispatchKeyValue(splittedValue[0].trim().toLowerCase(), splittedValue[1]);
|
||||
}
|
||||
} catch (PatternSyntaxException e) {
|
||||
logger.debug("handleValidAsciiMessage: ignored message {}", value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Suppress certain sequences of bytes from a message
|
||||
*
|
||||
* @param message the message as a table of bytes
|
||||
* @param bytesSequences the table containing the sequence of bytes to be ignored
|
||||
*
|
||||
* @return the message without the unexpected sequence of bytes
|
||||
*/
|
||||
private byte[] filterMessage(byte[] message, byte[][] bytesSequences) {
|
||||
if (bytesSequences.length == 0) {
|
||||
return message;
|
||||
}
|
||||
byte[] filteredMsg = new byte[message.length];
|
||||
int srcIdx = 0;
|
||||
int dstIdx = 0;
|
||||
while (srcIdx < message.length) {
|
||||
int ignoredLength = 0;
|
||||
for (int i = 0; i < bytesSequences.length; i++) {
|
||||
int size = bytesSequences[i].length;
|
||||
if ((message.length - srcIdx) >= size) {
|
||||
boolean match = true;
|
||||
for (int j = 0; j < size; j++) {
|
||||
if (message[srcIdx + j] != bytesSequences[i][j]) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
ignoredLength = size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ignoredLength > 0) {
|
||||
srcIdx += ignoredLength;
|
||||
} else {
|
||||
filteredMsg[dstIdx++] = message[srcIdx++];
|
||||
}
|
||||
}
|
||||
return Arrays.copyOf(filteredMsg, dstIdx);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
/**
|
||||
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.rotel.internal.protocol.ascii;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.rotel.internal.RotelException;
|
||||
import org.openhab.binding.rotel.internal.RotelModel;
|
||||
import org.openhab.binding.rotel.internal.communication.RotelCommand;
|
||||
import org.openhab.binding.rotel.internal.protocol.RotelProtocol;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Class for handling the Rotel ASCII V1 protocol (build of command messages, decoding of incoming data)
|
||||
*
|
||||
* @author Laurent Garnier - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class RotelAsciiV1ProtocolHandler extends RotelAbstractAsciiProtocolHandler {
|
||||
|
||||
private static final char CHAR_END_RESPONSE = '!';
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(RotelAsciiV1ProtocolHandler.class);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param model the Rotel model in use
|
||||
*/
|
||||
public RotelAsciiV1ProtocolHandler(RotelModel model) {
|
||||
super(model, CHAR_END_RESPONSE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RotelProtocol getProtocol() {
|
||||
return RotelProtocol.ASCII_V1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] buildCommandMessage(RotelCommand cmd, @Nullable Integer value) throws RotelException {
|
||||
String messageStr = cmd.getAsciiCommandV1();
|
||||
if (messageStr == null) {
|
||||
throw new RotelException("Command \"" + cmd.getName() + "\" ignored: not available for ASCII V1 protocol");
|
||||
}
|
||||
if (value != null) {
|
||||
switch (cmd) {
|
||||
case VOLUME_SET:
|
||||
messageStr += String.format("%d", value);
|
||||
break;
|
||||
case BASS_SET:
|
||||
case TREBLE_SET:
|
||||
if (value == 0) {
|
||||
messageStr += "000";
|
||||
} else if (value > 0) {
|
||||
messageStr += String.format("+%02d", value);
|
||||
} else {
|
||||
messageStr += String.format("-%02d", -value);
|
||||
}
|
||||
break;
|
||||
case BALANCE_SET:
|
||||
if (value == 0) {
|
||||
messageStr += "000";
|
||||
} else if (value > 0) {
|
||||
messageStr += String.format("R%02d", value);
|
||||
} else {
|
||||
messageStr += String.format("L%02d", -value);
|
||||
}
|
||||
break;
|
||||
case DIMMER_LEVEL_SET:
|
||||
if (value > 0 && model.getDimmerLevelMin() < 0) {
|
||||
messageStr += String.format("+%d", value);
|
||||
} else {
|
||||
messageStr += String.format("%d", value);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!messageStr.endsWith("?")) {
|
||||
messageStr += "!";
|
||||
}
|
||||
byte[] message = messageStr.getBytes(StandardCharsets.US_ASCII);
|
||||
logger.debug("Command \"{}\" => {}", cmd.getName(), messageStr);
|
||||
return message;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
/**
|
||||
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.rotel.internal.protocol.ascii;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.rotel.internal.RotelException;
|
||||
import org.openhab.binding.rotel.internal.RotelModel;
|
||||
import org.openhab.binding.rotel.internal.communication.RotelCommand;
|
||||
import org.openhab.binding.rotel.internal.protocol.RotelProtocol;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Class for handling the Rotel ASCII V2 protocol (build of command messages, decoding of incoming data)
|
||||
*
|
||||
* @author Laurent Garnier - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class RotelAsciiV2ProtocolHandler extends RotelAbstractAsciiProtocolHandler {
|
||||
|
||||
private static final char CHAR_END_RESPONSE = '$';
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(RotelAsciiV2ProtocolHandler.class);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param model the Rotel model in use
|
||||
*/
|
||||
public RotelAsciiV2ProtocolHandler(RotelModel model) {
|
||||
super(model, CHAR_END_RESPONSE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RotelProtocol getProtocol() {
|
||||
return RotelProtocol.ASCII_V2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] buildCommandMessage(RotelCommand cmd, @Nullable Integer value) throws RotelException {
|
||||
String messageStr = cmd.getAsciiCommandV2();
|
||||
if (messageStr == null) {
|
||||
throw new RotelException("Command \"" + cmd.getName() + "\" ignored: not available for ASCII V2 protocol");
|
||||
}
|
||||
if (value != null) {
|
||||
switch (cmd) {
|
||||
case VOLUME_SET:
|
||||
messageStr += String.format("%02d", value);
|
||||
break;
|
||||
case BASS_SET:
|
||||
case TREBLE_SET:
|
||||
if (value == 0) {
|
||||
messageStr += "000";
|
||||
} else if (value > 0) {
|
||||
messageStr += String.format("+%02d", value);
|
||||
} else {
|
||||
messageStr += String.format("-%02d", -value);
|
||||
}
|
||||
break;
|
||||
case BALANCE_SET:
|
||||
if (value == 0) {
|
||||
messageStr += "000";
|
||||
} else if (value > 0) {
|
||||
messageStr += String.format("r%02d", value);
|
||||
} else {
|
||||
messageStr += String.format("l%02d", -value);
|
||||
}
|
||||
break;
|
||||
case DIMMER_LEVEL_SET:
|
||||
if (value > 0 && model.getDimmerLevelMin() < 0) {
|
||||
messageStr += String.format("+%d", value);
|
||||
} else {
|
||||
messageStr += String.format("%d", value);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!messageStr.endsWith("?")) {
|
||||
messageStr += "!";
|
||||
}
|
||||
byte[] message = messageStr.getBytes(StandardCharsets.US_ASCII);
|
||||
logger.debug("Command \"{}\" => {}", cmd.getName(), messageStr);
|
||||
return message;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,778 @@
|
|||
/**
|
||||
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.rotel.internal.protocol.hex;
|
||||
|
||||
import static org.openhab.binding.rotel.internal.RotelBindingConstants.*;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.rotel.internal.RotelException;
|
||||
import org.openhab.binding.rotel.internal.RotelModel;
|
||||
import org.openhab.binding.rotel.internal.communication.RotelCommand;
|
||||
import org.openhab.binding.rotel.internal.communication.RotelDsp;
|
||||
import org.openhab.binding.rotel.internal.communication.RotelFlagsMapping;
|
||||
import org.openhab.binding.rotel.internal.communication.RotelSource;
|
||||
import org.openhab.binding.rotel.internal.protocol.RotelAbstractProtocolHandler;
|
||||
import org.openhab.binding.rotel.internal.protocol.RotelProtocol;
|
||||
import org.openhab.core.util.HexUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Class for handling the Rotel HEX protocol (build of command messages, decoding of incoming data)
|
||||
*
|
||||
* @author Laurent Garnier - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class RotelHexProtocolHandler extends RotelAbstractProtocolHandler {
|
||||
|
||||
public static final byte START = (byte) 0xFE;
|
||||
|
||||
private static final String KEY1_HEX_VOLUME = "volume ";
|
||||
private static final String KEY2_HEX_VOLUME = "vol ";
|
||||
private static final String KEY_HEX_MUTE = "mute ";
|
||||
private static final String KEY1_HEX_BASS = "bass ";
|
||||
private static final String KEY2_HEX_BASS = "lf ";
|
||||
private static final String KEY1_HEX_TREBLE = "treble ";
|
||||
private static final String KEY2_HEX_TREBLE = "hf ";
|
||||
private static final String KEY_HEX_MULTI_IN = "multi in ";
|
||||
private static final String KEY_HEX_STEREO = "stereo";
|
||||
private static final String KEY1_HEX_3CH = "3 stereo";
|
||||
private static final String KEY2_HEX_3CH = "dolby 3 stereo";
|
||||
private static final String KEY_HEX_5CH = "5ch stereo";
|
||||
private static final String KEY_HEX_7CH = "7ch stereo";
|
||||
private static final String KEY_HEX_MUSIC1 = "music 1";
|
||||
private static final String KEY_HEX_MUSIC2 = "music 2";
|
||||
private static final String KEY_HEX_MUSIC3 = "music 3";
|
||||
private static final String KEY_HEX_MUSIC4 = "music 4";
|
||||
private static final String KEY_HEX_DSP1 = "dsp 1";
|
||||
private static final String KEY_HEX_DSP2 = "dsp 2";
|
||||
private static final String KEY_HEX_DSP3 = "dsp 3";
|
||||
private static final String KEY_HEX_DSP4 = "dsp 4";
|
||||
private static final String KEY1_HEX_PROLOGIC = "prologic emu";
|
||||
private static final String KEY2_HEX_PROLOGIC = "dolby pro logic";
|
||||
private static final String KEY1_HEX_PLII_CINEMA = "prologic cin";
|
||||
private static final String KEY2_HEX_PLII_CINEMA = "dolby pl c";
|
||||
private static final String KEY1_HEX_PLII_MUSIC = "prologic mus";
|
||||
private static final String KEY2_HEX_PLII_MUSIC = "dolby pl m";
|
||||
private static final String KEY1_HEX_PLII_GAME = "prologic gam";
|
||||
private static final String KEY2_HEX_PLII_GAME = "dolby pl g";
|
||||
private static final String KEY1_HEX_PLIIX_CINEMA = "pl x cinema";
|
||||
private static final String KEY2_HEX_PLIIX_CINEMA = "dolby pl x c";
|
||||
private static final String KEY1_HEX_PLIIX_MUSIC = "pl x music";
|
||||
private static final String KEY2_HEX_PLIIX_MUSIC = "dolby pl x m";
|
||||
private static final String KEY1_HEX_PLIIX_GAME = "pl x game";
|
||||
private static final String KEY2_HEX_PLIIX_GAME = "dolby pl x g";
|
||||
private static final String KEY_HEX_PLIIZ = "dolby pl z";
|
||||
private static final String KEY1_HEX_DTS_NEO6_CINEMA = "neo 6 cinema";
|
||||
private static final String KEY2_HEX_DTS_NEO6_CINEMA = "dts neo:6 c";
|
||||
private static final String KEY1_HEX_DTS_NEO6_MUSIC = "neo 6 music";
|
||||
private static final String KEY2_HEX_DTS_NEO6_MUSIC = "dts neo:6 m";
|
||||
private static final String KEY_HEX_DTS = "dts";
|
||||
private static final String KEY_HEX_DTS_ES = "dts-es";
|
||||
private static final String KEY_HEX_DTS_96 = "dts 96";
|
||||
private static final String KEY_HEX_DD = "dolby digital";
|
||||
private static final String KEY_HEX_DD_EX = "dolby d ex";
|
||||
private static final String KEY_HEX_PCM = "pcm";
|
||||
private static final String KEY_HEX_LPCM = "lpcm";
|
||||
private static final String KEY_HEX_MPEG = "mpeg";
|
||||
private static final String KEY_HEX_BYPASS = "bypass";
|
||||
private static final String KEY1_HEX_ZONE2 = "zone ";
|
||||
private static final String KEY2_HEX_ZONE2 = "zone2 ";
|
||||
private static final String KEY_HEX_ZONE3 = "zone3 ";
|
||||
private static final String KEY_HEX_ZONE4 = "zone4 ";
|
||||
private static final String KEY_HEX_RECORD = "rec ";
|
||||
private static final String SOURCE = "source";
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(RotelHexProtocolHandler.class);
|
||||
|
||||
private final Map<RotelSource, String> sourcesLabels;
|
||||
|
||||
private final int size;
|
||||
private final byte[] dataBuffer;
|
||||
|
||||
private boolean startCodeReached;
|
||||
private int count;
|
||||
private int index;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param model the Rotel model in use
|
||||
* @param sourcesLabels the custom labels for sources
|
||||
*/
|
||||
public RotelHexProtocolHandler(RotelModel model, Map<RotelSource, String> sourcesLabels) {
|
||||
super(model);
|
||||
this.sourcesLabels = sourcesLabels;
|
||||
this.size = (6 + model.getRespNbChars() + model.getRespNbFlags());
|
||||
this.dataBuffer = new byte[size];
|
||||
this.startCodeReached = false;
|
||||
this.count = 0;
|
||||
this.index = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RotelProtocol getProtocol() {
|
||||
return RotelProtocol.HEX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] buildCommandMessage(RotelCommand cmd, @Nullable Integer value) throws RotelException {
|
||||
if (cmd.getHexType() == 0) {
|
||||
throw new RotelException("Command \"" + cmd.getName() + "\" ignored: not available for HEX protocol");
|
||||
}
|
||||
final int size = 6;
|
||||
byte[] message = new byte[size];
|
||||
int idx = 0;
|
||||
message[idx++] = START;
|
||||
message[idx++] = 3;
|
||||
message[idx++] = model.getDeviceId();
|
||||
message[idx++] = cmd.getHexType();
|
||||
message[idx++] = (value == null) ? cmd.getHexKey() : (byte) (value & 0x000000FF);
|
||||
final byte checksum = computeCheckSum(message, idx - 1);
|
||||
if ((checksum & 0x000000FF) == 0x000000FD || (checksum & 0x000000FF) == 0x000000FE) {
|
||||
message = Arrays.copyOf(message, size + 1);
|
||||
message[idx++] = (byte) 0xFD;
|
||||
message[idx++] = ((checksum & 0x000000FF) == 0x000000FD) ? (byte) 0 : (byte) 1;
|
||||
} else {
|
||||
message[idx++] = checksum;
|
||||
}
|
||||
logger.debug("Command \"{}\" => {}", cmd.getName(), HexUtils.bytesToHex(message));
|
||||
return message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleIncomingData(byte[] inDataBuffer, int length) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (inDataBuffer[i] == RotelHexProtocolHandler.START) {
|
||||
startCodeReached = true;
|
||||
count = 0;
|
||||
index = 0;
|
||||
}
|
||||
if (startCodeReached) {
|
||||
if (index < size) {
|
||||
dataBuffer[index++] = inDataBuffer[i];
|
||||
}
|
||||
if (index == 2) {
|
||||
count = inDataBuffer[i];
|
||||
} else if ((count > 0) && (index == (count + 3))) {
|
||||
if ((inDataBuffer[i] & 0x000000FF) == 0x000000FD) {
|
||||
count++;
|
||||
} else {
|
||||
byte[] msg = Arrays.copyOf(dataBuffer, index);
|
||||
handleIncomingMessage(msg);
|
||||
startCodeReached = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the content of a feedback message
|
||||
*
|
||||
* @param responseMessage the buffer containing the feedback message
|
||||
*
|
||||
* @throws RotelException - If the message has unexpected content
|
||||
*/
|
||||
@Override
|
||||
protected void validateResponse(byte[] responseMessage) throws RotelException {
|
||||
// Check minimum message length
|
||||
if (responseMessage.length < 6) {
|
||||
logger.debug("Unexpected message length: {}", responseMessage.length);
|
||||
throw new RotelException("Unexpected message length");
|
||||
}
|
||||
|
||||
// Check START
|
||||
if (responseMessage[0] != START) {
|
||||
logger.debug("Unexpected START in response: {} rather than {}",
|
||||
Integer.toHexString(responseMessage[0] & 0x000000FF), Integer.toHexString(START & 0x000000FF));
|
||||
throw new RotelException("Unexpected START in response");
|
||||
}
|
||||
|
||||
// Check ID
|
||||
if (responseMessage[2] != model.getDeviceId()) {
|
||||
logger.debug("Unexpected ID in response: {} rather than {}",
|
||||
Integer.toHexString(responseMessage[2] & 0x000000FF),
|
||||
Integer.toHexString(model.getDeviceId() & 0x000000FF));
|
||||
throw new RotelException("Unexpected ID in response");
|
||||
}
|
||||
|
||||
// Check TYPE
|
||||
if (responseMessage[3] != STANDARD_RESPONSE && responseMessage[3] != TRIGGER_STATUS
|
||||
&& responseMessage[3] != SMART_DISPLAY_DATA_1 && responseMessage[3] != SMART_DISPLAY_DATA_2
|
||||
&& responseMessage[3] != PRIMARY_CMD && responseMessage[3] != MAIN_ZONE_CMD
|
||||
&& responseMessage[3] != RECORD_SRC_CMD && responseMessage[3] != ZONE2_CMD
|
||||
&& responseMessage[3] != ZONE3_CMD && responseMessage[3] != ZONE4_CMD
|
||||
&& responseMessage[3] != VOLUME_CMD && responseMessage[3] != ZONE2_VOLUME_CMD
|
||||
&& responseMessage[3] != ZONE3_VOLUME_CMD && responseMessage[3] != ZONE4_VOLUME_CMD
|
||||
&& responseMessage[3] != TRIGGER_CMD) {
|
||||
logger.debug("Unexpected TYPE in response: {}", Integer.toHexString(responseMessage[3] & 0x000000FF));
|
||||
throw new RotelException("Unexpected TYPE in response");
|
||||
}
|
||||
|
||||
int expectedLen = (responseMessage[3] == STANDARD_RESPONSE)
|
||||
? (5 + model.getRespNbChars() + model.getRespNbFlags())
|
||||
: responseMessage.length;
|
||||
|
||||
// Check COUNT
|
||||
if (responseMessage[1] != (expectedLen - 3)) {
|
||||
logger.debug("Unexpected COUNT in response: {} rather than {}",
|
||||
Integer.toHexString(responseMessage[1] & 0x000000FF),
|
||||
Integer.toHexString((expectedLen - 3) & 0x000000FF));
|
||||
throw new RotelException("Unexpected COUNT in response");
|
||||
}
|
||||
|
||||
final byte checksum = computeCheckSum(responseMessage, expectedLen - 2);
|
||||
if ((checksum & 0x000000FF) == 0x000000FD || (checksum & 0x000000FF) == 0x000000FE) {
|
||||
expectedLen++;
|
||||
}
|
||||
|
||||
// Check message length
|
||||
if (responseMessage.length != expectedLen) {
|
||||
logger.debug("Unexpected message length: {} rather than {}", responseMessage.length, expectedLen);
|
||||
throw new RotelException("Unexpected message length");
|
||||
}
|
||||
|
||||
// Check sum
|
||||
if ((checksum & 0x000000FF) == 0x000000FD) {
|
||||
if ((responseMessage[responseMessage.length - 2] & 0x000000FF) != 0x000000FD
|
||||
|| (responseMessage[responseMessage.length - 1] & 0x000000FF) != 0) {
|
||||
logger.debug("Invalid check sum in response: {} rather than FD00", HexUtils.bytesToHex(
|
||||
Arrays.copyOfRange(responseMessage, responseMessage.length - 2, responseMessage.length)));
|
||||
throw new RotelException("Invalid check sum in response");
|
||||
}
|
||||
} else if ((checksum & 0x000000FF) == 0x000000FE) {
|
||||
if ((responseMessage[responseMessage.length - 2] & 0x000000FF) != 0x000000FD
|
||||
|| (responseMessage[responseMessage.length - 1] & 0x000000FF) != 1) {
|
||||
logger.debug("Invalid check sum in response: {} rather than FD01", HexUtils.bytesToHex(
|
||||
Arrays.copyOfRange(responseMessage, responseMessage.length - 2, responseMessage.length)));
|
||||
throw new RotelException("Invalid check sum in response");
|
||||
}
|
||||
} else if ((checksum & 0x000000FF) != (responseMessage[responseMessage.length - 1] & 0x000000FF)) {
|
||||
logger.debug("Invalid check sum in response: {} rather than {}",
|
||||
Integer.toHexString(responseMessage[responseMessage.length - 1] & 0x000000FF),
|
||||
Integer.toHexString(checksum & 0x000000FF));
|
||||
throw new RotelException("Invalid check sum in response");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the checksum of a message
|
||||
*
|
||||
* @param message the buffer containing the message
|
||||
* @param maxIdx the position in the buffer at which the sum has to be stopped
|
||||
*
|
||||
* @return the checksum as a byte
|
||||
*/
|
||||
public static byte computeCheckSum(byte[] message, int maxIdx) {
|
||||
int result = 0;
|
||||
for (int i = 1; i <= maxIdx; i++) {
|
||||
result += (message[i] & 0x000000FF);
|
||||
}
|
||||
return (byte) (result & 0x000000FF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyze a valid HEX message and dispatch corresponding (key, value) to the event listeners
|
||||
*
|
||||
* @param incomingMessage the received message
|
||||
*/
|
||||
@Override
|
||||
protected void handleValidMessage(byte[] incomingMessage) {
|
||||
if (incomingMessage[3] != STANDARD_RESPONSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int idxChars = model.isCharsBeforeFlags() ? 4 : (4 + model.getRespNbFlags());
|
||||
|
||||
// Replace characters with code < 32 by a space before converting to a string
|
||||
for (int i = idxChars; i < (idxChars + model.getRespNbChars()); i++) {
|
||||
if (incomingMessage[i] < 0x20) {
|
||||
incomingMessage[i] = 0x20;
|
||||
}
|
||||
}
|
||||
|
||||
String value = new String(incomingMessage, idxChars, model.getRespNbChars(), StandardCharsets.US_ASCII);
|
||||
logger.debug("handleValidHexMessage: chars *{}*", value);
|
||||
|
||||
final int idxFlags = model.isCharsBeforeFlags() ? (4 + model.getRespNbChars()) : 4;
|
||||
final byte[] flags = Arrays.copyOfRange(incomingMessage, idxFlags, idxFlags + model.getRespNbFlags());
|
||||
if (logger.isTraceEnabled()) {
|
||||
for (int i = 1; i <= flags.length; i++) {
|
||||
try {
|
||||
logger.trace("handleValidHexMessage: Flag {} = {} bits 7-0 = {} {} {} {} {} {} {} {}", i,
|
||||
Integer.toHexString(flags[i - 1] & 0x000000FF), RotelFlagsMapping.isBitFlagOn(flags, i, 7),
|
||||
RotelFlagsMapping.isBitFlagOn(flags, i, 6), RotelFlagsMapping.isBitFlagOn(flags, i, 5),
|
||||
RotelFlagsMapping.isBitFlagOn(flags, i, 4), RotelFlagsMapping.isBitFlagOn(flags, i, 3),
|
||||
RotelFlagsMapping.isBitFlagOn(flags, i, 2), RotelFlagsMapping.isBitFlagOn(flags, i, 1),
|
||||
RotelFlagsMapping.isBitFlagOn(flags, i, 0));
|
||||
} catch (RotelException e1) {
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
dispatchKeyValue(KEY_POWER_ZONE2, model.isZone2On(flags) ? POWER_ON : STANDBY);
|
||||
} catch (RotelException e1) {
|
||||
// Can't get zone power information from flags data, so we just do not notify of this information that way
|
||||
}
|
||||
try {
|
||||
dispatchKeyValue(KEY_POWER_ZONE3, model.isZone3On(flags) ? POWER_ON : STANDBY);
|
||||
} catch (RotelException e1) {
|
||||
// Can't get zone power information from flags data, so we just do not notify of this information that way
|
||||
}
|
||||
try {
|
||||
dispatchKeyValue(KEY_POWER_ZONE4, model.isZone4On(flags) ? POWER_ON : STANDBY);
|
||||
} catch (RotelException e1) {
|
||||
// Can't get zone power information from flags data, so we just do not notify of this information that way
|
||||
}
|
||||
boolean checkMultiIn = false;
|
||||
boolean checkSource = true;
|
||||
try {
|
||||
if (model.isMultiInputOn(flags)) {
|
||||
checkSource = false;
|
||||
try {
|
||||
RotelSource source = model.getSourceFromName(RotelSource.CAT1_MULTI.getName());
|
||||
RotelCommand cmd = source.getCommand();
|
||||
if (cmd != null) {
|
||||
String value2 = cmd.getAsciiCommandV2();
|
||||
if (value2 != null) {
|
||||
dispatchKeyValue(KEY_SOURCE, value2);
|
||||
}
|
||||
}
|
||||
} catch (RotelException e1) {
|
||||
// MULTI source not declared for the model (should not happen), we do not notify of this source
|
||||
}
|
||||
}
|
||||
} catch (RotelException e1) {
|
||||
// Can't get status of multiple input source from flags data, checkMultiIn is set to true to get this
|
||||
// information in another way
|
||||
checkMultiIn = true;
|
||||
}
|
||||
boolean checkStereo = true;
|
||||
try {
|
||||
checkStereo = !model.isMoreThan2Channels(flags);
|
||||
} catch (RotelException e1) {
|
||||
// Can't get stereo information from flags data, checkStereo is set to true to get this information in
|
||||
// another way
|
||||
}
|
||||
|
||||
String valueLowerCase = value.trim().toLowerCase();
|
||||
if (!valueLowerCase.isEmpty() && !valueLowerCase.startsWith(KEY1_HEX_ZONE2)
|
||||
&& !valueLowerCase.startsWith(KEY2_HEX_ZONE2) && !valueLowerCase.startsWith(KEY_HEX_ZONE3)
|
||||
&& !valueLowerCase.startsWith(KEY_HEX_ZONE4)) {
|
||||
dispatchKeyValue(KEY_POWER, POWER_ON);
|
||||
}
|
||||
|
||||
if (model.getRespNbChars() == 42) {
|
||||
// 2 lines of 21 characters with a left part and a right part
|
||||
|
||||
// Line 1 left
|
||||
value = new String(incomingMessage, idxChars, 14, StandardCharsets.US_ASCII);
|
||||
logger.debug("handleValidHexMessage: line 1 left *{}*", value);
|
||||
parseText(value, checkSource, checkMultiIn, false, false, false, false, false, true);
|
||||
|
||||
// Line 1 right
|
||||
value = new String(incomingMessage, idxChars + 14, 7, StandardCharsets.US_ASCII);
|
||||
logger.debug("handleValidHexMessage: line 1 right *{}*", value);
|
||||
parseText(value, false, false, false, false, false, false, false, true);
|
||||
|
||||
// Full line 1
|
||||
value = new String(incomingMessage, idxChars, 21, StandardCharsets.US_ASCII);
|
||||
dispatchKeyValue(KEY_LINE1, value);
|
||||
|
||||
// Line 2 right
|
||||
value = new String(incomingMessage, idxChars + 35, 7, StandardCharsets.US_ASCII);
|
||||
logger.debug("handleValidHexMessage: line 2 right *{}*", value);
|
||||
parseText(value, false, false, false, false, false, false, false, true);
|
||||
|
||||
// Full line 2
|
||||
value = new String(incomingMessage, idxChars + 21, 21, StandardCharsets.US_ASCII);
|
||||
logger.debug("handleValidHexMessage: line 2 *{}*", value);
|
||||
parseText(value, false, false, true, true, false, true, true, true);
|
||||
dispatchKeyValue(KEY_LINE2, value);
|
||||
} else {
|
||||
value = new String(incomingMessage, idxChars, model.getRespNbChars(), StandardCharsets.US_ASCII);
|
||||
parseText(value, checkSource, checkMultiIn, true, false, true, true, checkStereo, false);
|
||||
dispatchKeyValue(KEY_LINE1, value);
|
||||
}
|
||||
|
||||
if (valueLowerCase.isEmpty()) {
|
||||
dispatchKeyValue(KEY_POWER, POWER_OFF_DELAYED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a text and dispatch appropriate (key, value) to the event listeners for found information
|
||||
*
|
||||
* @param text the text to be parsed
|
||||
* @param searchSource true if a source has to be searched in the text
|
||||
* @param searchMultiIn true if MULTI IN indication has to be searched in the text
|
||||
* @param searchZone true if a zone information has to be searched in the text
|
||||
* @param searchRecord true if a record source has to be searched in the text
|
||||
* @param searchRecordAfterSource true if a record source has to be searched in the text after the a found source
|
||||
* @param searchDsp true if a DSP mode has to be searched in the text
|
||||
* @param searchStereo true if a STEREO has to be considered in the search
|
||||
* @param multipleInfo true if source and volume/mute are provided separately
|
||||
*/
|
||||
private void parseText(String text, boolean searchSource, boolean searchMultiIn, boolean searchZone,
|
||||
boolean searchRecord, boolean searchRecordAfterSource, boolean searchDsp, boolean searchStereo,
|
||||
boolean multipleInfo) {
|
||||
String value = text.trim();
|
||||
String valueLowerCase = value.toLowerCase();
|
||||
if (searchRecord) {
|
||||
dispatchKeyValue(KEY_RECORD_SEL, valueLowerCase.startsWith(KEY_HEX_RECORD) ? MSG_VALUE_ON : MSG_VALUE_OFF);
|
||||
}
|
||||
if (searchZone) {
|
||||
if (valueLowerCase.startsWith(KEY1_HEX_ZONE2) || valueLowerCase.startsWith(KEY2_HEX_ZONE2)) {
|
||||
dispatchKeyValue(KEY_ZONE, "2");
|
||||
} else if (valueLowerCase.startsWith(KEY_HEX_ZONE3)) {
|
||||
dispatchKeyValue(KEY_ZONE, "3");
|
||||
} else if (valueLowerCase.startsWith(KEY_HEX_ZONE4)) {
|
||||
dispatchKeyValue(KEY_ZONE, "4");
|
||||
} else {
|
||||
dispatchKeyValue(KEY_ZONE, "1");
|
||||
}
|
||||
}
|
||||
if (valueLowerCase.startsWith(KEY1_HEX_VOLUME) || valueLowerCase.startsWith(KEY2_HEX_VOLUME)) {
|
||||
value = extractNumber(value,
|
||||
valueLowerCase.startsWith(KEY1_HEX_VOLUME) ? KEY1_HEX_VOLUME.length() : KEY2_HEX_VOLUME.length());
|
||||
dispatchKeyValue(KEY_VOLUME, value);
|
||||
dispatchKeyValue(KEY_MUTE, MSG_VALUE_OFF);
|
||||
} else if (valueLowerCase.startsWith(KEY_HEX_MUTE)) {
|
||||
value = value.substring(KEY_HEX_MUTE.length()).trim();
|
||||
if (MSG_VALUE_ON.equalsIgnoreCase(value)) {
|
||||
dispatchKeyValue(KEY_MUTE, MSG_VALUE_ON);
|
||||
} else {
|
||||
logger.debug("Invalid value {} for zone mute", value);
|
||||
}
|
||||
} else if (valueLowerCase.startsWith(KEY1_HEX_BASS) || valueLowerCase.startsWith(KEY2_HEX_BASS)) {
|
||||
value = extractNumber(value,
|
||||
valueLowerCase.startsWith(KEY1_HEX_BASS) ? KEY1_HEX_BASS.length() : KEY2_HEX_BASS.length());
|
||||
dispatchKeyValue(KEY_BASS, value);
|
||||
} else if (valueLowerCase.startsWith(KEY1_HEX_TREBLE) || valueLowerCase.startsWith(KEY2_HEX_TREBLE)) {
|
||||
value = extractNumber(value,
|
||||
valueLowerCase.startsWith(KEY1_HEX_TREBLE) ? KEY1_HEX_TREBLE.length() : KEY2_HEX_TREBLE.length());
|
||||
dispatchKeyValue(KEY_TREBLE, value);
|
||||
} else if (searchMultiIn && valueLowerCase.startsWith(KEY_HEX_MULTI_IN)) {
|
||||
value = value.substring(KEY_HEX_MULTI_IN.length()).trim();
|
||||
if (MSG_VALUE_ON.equalsIgnoreCase(value)) {
|
||||
try {
|
||||
RotelSource source = model.getSourceFromName(RotelSource.CAT1_MULTI.getName());
|
||||
RotelCommand cmd = source.getCommand();
|
||||
if (cmd != null) {
|
||||
String value2 = cmd.getAsciiCommandV2();
|
||||
if (value2 != null) {
|
||||
dispatchKeyValue(KEY_SOURCE, value2);
|
||||
}
|
||||
}
|
||||
} catch (RotelException e1) {
|
||||
// MULTI source not declared for the model (should not happen), we do not notify of this source
|
||||
}
|
||||
} else if (!MSG_VALUE_OFF.equalsIgnoreCase(value)) {
|
||||
logger.debug("Invalid value {} for MULTI IN", value);
|
||||
}
|
||||
} else if (searchDsp && valueLowerCase.startsWith(KEY_HEX_BYPASS)) {
|
||||
dispatchKeyValue(KEY_DSP_MODE, RotelDsp.CAT4_BYPASS.getFeedback());
|
||||
} else if (searchDsp && searchStereo && valueLowerCase.startsWith(KEY_HEX_STEREO)) {
|
||||
dispatchKeyValue(KEY_DSP_MODE, RotelDsp.CAT4_NONE.getFeedback());
|
||||
} else if (searchDsp && (valueLowerCase.startsWith(KEY1_HEX_3CH) || valueLowerCase.startsWith(KEY2_HEX_3CH))) {
|
||||
dispatchKeyValue(KEY_DSP_MODE, RotelDsp.CAT4_STEREO3.getFeedback());
|
||||
} else if (searchDsp && valueLowerCase.startsWith(KEY_HEX_5CH)) {
|
||||
dispatchKeyValue(KEY_DSP_MODE, RotelDsp.CAT4_STEREO5.getFeedback());
|
||||
} else if (searchDsp && valueLowerCase.startsWith(KEY_HEX_7CH)) {
|
||||
dispatchKeyValue(KEY_DSP_MODE, RotelDsp.CAT4_STEREO7.getFeedback());
|
||||
} else if (searchDsp
|
||||
&& (valueLowerCase.startsWith(KEY_HEX_MUSIC1) || valueLowerCase.startsWith(KEY_HEX_DSP1))) {
|
||||
dispatchKeyValue(KEY_DSP_MODE, RotelDsp.CAT4_DSP1.getFeedback());
|
||||
} else if (searchDsp
|
||||
&& (valueLowerCase.startsWith(KEY_HEX_MUSIC2) || valueLowerCase.startsWith(KEY_HEX_DSP2))) {
|
||||
dispatchKeyValue(KEY_DSP_MODE, RotelDsp.CAT4_DSP2.getFeedback());
|
||||
} else if (searchDsp
|
||||
&& (valueLowerCase.startsWith(KEY_HEX_MUSIC3) || valueLowerCase.startsWith(KEY_HEX_DSP3))) {
|
||||
dispatchKeyValue(KEY_DSP_MODE, RotelDsp.CAT4_DSP3.getFeedback());
|
||||
} else if (searchDsp
|
||||
&& (valueLowerCase.startsWith(KEY_HEX_MUSIC4) || valueLowerCase.startsWith(KEY_HEX_DSP4))) {
|
||||
dispatchKeyValue(KEY_DSP_MODE, RotelDsp.CAT4_DSP4.getFeedback());
|
||||
} else if (searchDsp && (valueLowerCase.startsWith(KEY1_HEX_PLII_CINEMA)
|
||||
|| valueLowerCase.startsWith(KEY2_HEX_PLII_CINEMA) || valueLowerCase.startsWith(KEY1_HEX_PLIIX_CINEMA)
|
||||
|| searchDsp && valueLowerCase.startsWith(KEY2_HEX_PLIIX_CINEMA))) {
|
||||
dispatchKeyValue(KEY_DSP_MODE, RotelDsp.CAT2_PLII_CINEMA.getFeedback());
|
||||
} else if (searchDsp && (valueLowerCase.startsWith(KEY1_HEX_PLII_MUSIC)
|
||||
|| valueLowerCase.startsWith(KEY2_HEX_PLII_MUSIC) || valueLowerCase.startsWith(KEY1_HEX_PLIIX_MUSIC)
|
||||
|| valueLowerCase.startsWith(KEY2_HEX_PLIIX_MUSIC))) {
|
||||
dispatchKeyValue(KEY_DSP_MODE, RotelDsp.CAT2_PLII_MUSIC.getFeedback());
|
||||
} else if (searchDsp && (valueLowerCase.startsWith(KEY1_HEX_PLII_GAME)
|
||||
|| valueLowerCase.startsWith(KEY2_HEX_PLII_GAME) || valueLowerCase.startsWith(KEY1_HEX_PLIIX_GAME)
|
||||
|| valueLowerCase.startsWith(KEY2_HEX_PLIIX_GAME))) {
|
||||
dispatchKeyValue(KEY_DSP_MODE, RotelDsp.CAT2_PLII_GAME.getFeedback());
|
||||
} else if (searchDsp && valueLowerCase.startsWith(KEY_HEX_PLIIZ)) {
|
||||
dispatchKeyValue(KEY_DSP_MODE, RotelDsp.CAT4_PLIIZ.getFeedback());
|
||||
} else if (searchDsp
|
||||
&& (valueLowerCase.startsWith(KEY1_HEX_PROLOGIC) || valueLowerCase.startsWith(KEY2_HEX_PROLOGIC))) {
|
||||
dispatchKeyValue(KEY_DSP_MODE, RotelDsp.CAT4_PROLOGIC.getFeedback());
|
||||
} else if (searchDsp && (valueLowerCase.startsWith(KEY1_HEX_DTS_NEO6_CINEMA)
|
||||
|| valueLowerCase.startsWith(KEY2_HEX_DTS_NEO6_CINEMA))) {
|
||||
dispatchKeyValue(KEY_DSP_MODE, RotelDsp.CAT4_NEO6_CINEMA.getFeedback());
|
||||
} else if (searchDsp && (valueLowerCase.startsWith(KEY1_HEX_DTS_NEO6_MUSIC)
|
||||
|| valueLowerCase.startsWith(KEY2_HEX_DTS_NEO6_MUSIC))) {
|
||||
dispatchKeyValue(KEY_DSP_MODE, RotelDsp.CAT4_NEO6_MUSIC.getFeedback());
|
||||
} else if (searchDsp && valueLowerCase.startsWith(KEY_HEX_DTS_ES)) {
|
||||
logger.debug("DTS-ES");
|
||||
dispatchKeyValue(KEY_DSP_MODE, RotelDsp.CAT4_NONE.getFeedback());
|
||||
} else if (searchDsp && valueLowerCase.startsWith(KEY_HEX_DTS_96)) {
|
||||
logger.debug("DTS 96");
|
||||
dispatchKeyValue(KEY_DSP_MODE, RotelDsp.CAT4_NONE.getFeedback());
|
||||
} else if (searchDsp && valueLowerCase.startsWith(KEY_HEX_DTS)) {
|
||||
logger.debug("DTS");
|
||||
dispatchKeyValue(KEY_DSP_MODE, RotelDsp.CAT4_NONE.getFeedback());
|
||||
} else if (searchDsp && valueLowerCase.startsWith(KEY_HEX_DD_EX)) {
|
||||
logger.debug("DD-EX");
|
||||
dispatchKeyValue(KEY_DSP_MODE, RotelDsp.CAT4_NONE.getFeedback());
|
||||
} else if (searchDsp && valueLowerCase.startsWith(KEY_HEX_DD)) {
|
||||
logger.debug("DD");
|
||||
dispatchKeyValue(KEY_DSP_MODE, RotelDsp.CAT4_NONE.getFeedback());
|
||||
} else if (searchDsp && valueLowerCase.startsWith(KEY_HEX_LPCM)) {
|
||||
logger.debug("LPCM");
|
||||
dispatchKeyValue(KEY_DSP_MODE, RotelDsp.CAT4_NONE.getFeedback());
|
||||
} else if (searchDsp && valueLowerCase.startsWith(KEY_HEX_PCM)) {
|
||||
logger.debug("PCM");
|
||||
dispatchKeyValue(KEY_DSP_MODE, RotelDsp.CAT4_NONE.getFeedback());
|
||||
} else if (searchDsp && valueLowerCase.startsWith(KEY_HEX_MPEG)) {
|
||||
logger.debug("MPEG");
|
||||
dispatchKeyValue(KEY_DSP_MODE, RotelDsp.CAT4_NONE.getFeedback());
|
||||
} else if (searchZone
|
||||
&& (valueLowerCase.startsWith(KEY1_HEX_ZONE2) || valueLowerCase.startsWith(KEY2_HEX_ZONE2))) {
|
||||
value = value.substring(
|
||||
valueLowerCase.startsWith(KEY1_HEX_ZONE2) ? KEY1_HEX_ZONE2.length() : KEY2_HEX_ZONE2.length());
|
||||
parseZone2(value, multipleInfo);
|
||||
} else if (searchZone && valueLowerCase.startsWith(KEY_HEX_ZONE3)) {
|
||||
parseZone3(value.substring(KEY_HEX_ZONE3.length()), multipleInfo);
|
||||
} else if (searchZone && valueLowerCase.startsWith(KEY_HEX_ZONE4)) {
|
||||
parseZone4(value.substring(KEY_HEX_ZONE4.length()), multipleInfo);
|
||||
} else if (searchRecord && valueLowerCase.startsWith(KEY_HEX_RECORD)) {
|
||||
parseRecord(value.substring(KEY_HEX_RECORD.length()));
|
||||
} else if (searchSource || searchRecordAfterSource) {
|
||||
parseSourceAndRecord(value, searchSource, searchRecordAfterSource, multipleInfo);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a text to identify a source
|
||||
*
|
||||
* @param text the text to be parsed
|
||||
* @param acceptFollowMain true if follow main has to be considered in the search
|
||||
*
|
||||
* @return the identified source or null if no source is identified in the text
|
||||
*/
|
||||
private @Nullable RotelSource parseSource(String text, boolean acceptFollowMain) {
|
||||
String value = text.trim();
|
||||
RotelSource source = null;
|
||||
if (!value.isEmpty()) {
|
||||
if (acceptFollowMain && SOURCE.equalsIgnoreCase(value)) {
|
||||
try {
|
||||
source = model.getSourceFromName(RotelSource.CAT1_FOLLOW_MAIN.getName());
|
||||
} catch (RotelException e) {
|
||||
// MAIN (follow main zone source) source not declared for the model, we return null
|
||||
}
|
||||
} else {
|
||||
for (RotelSource src : sourcesLabels.keySet()) {
|
||||
String label = sourcesLabels.get(src);
|
||||
if (label != null && value.startsWith(label)) {
|
||||
if (source == null || sourcesLabels.get(source).length() < label.length()) {
|
||||
source = src;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
private void parseSourceAndRecord(String text, boolean searchSource, boolean searchRecordAfterSource,
|
||||
boolean multipleInfo) {
|
||||
RotelSource source = parseSource(text, false);
|
||||
if (source != null) {
|
||||
if (searchSource) {
|
||||
RotelCommand cmd = source.getCommand();
|
||||
if (cmd != null) {
|
||||
String value2 = cmd.getAsciiCommandV2();
|
||||
if (value2 != null) {
|
||||
dispatchKeyValue(KEY_SOURCE, value2);
|
||||
if (!multipleInfo) {
|
||||
dispatchKeyValue(KEY_MUTE, MSG_VALUE_OFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (searchRecordAfterSource) {
|
||||
String value = text.substring(getSourceLabel(source).length()).trim();
|
||||
source = parseSource(value, true);
|
||||
if (source != null) {
|
||||
RotelCommand cmd = source.getRecordCommand();
|
||||
if (cmd != null) {
|
||||
value = cmd.getAsciiCommandV2();
|
||||
if (value != null) {
|
||||
dispatchKeyValue(KEY_RECORD, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getSourceLabel(RotelSource source) {
|
||||
String label = sourcesLabels.get(source);
|
||||
return (label == null) ? source.getLabel() : label;
|
||||
}
|
||||
|
||||
private void parseRecord(String text) {
|
||||
String value = text.trim();
|
||||
RotelSource source = parseSource(value, true);
|
||||
if (source != null) {
|
||||
RotelCommand cmd = source.getRecordCommand();
|
||||
if (cmd != null) {
|
||||
value = cmd.getAsciiCommandV2();
|
||||
if (value != null) {
|
||||
dispatchKeyValue(KEY_RECORD, value);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.debug("Invalid value {} for record source", value);
|
||||
}
|
||||
}
|
||||
|
||||
private void parseZone2(String text, boolean multipleInfo) {
|
||||
String value = text.trim();
|
||||
String valueLowerCase = value.toLowerCase();
|
||||
if (valueLowerCase.startsWith(KEY1_HEX_VOLUME) || valueLowerCase.startsWith(KEY2_HEX_VOLUME)) {
|
||||
value = extractNumber(value,
|
||||
valueLowerCase.startsWith(KEY1_HEX_VOLUME) ? KEY1_HEX_VOLUME.length() : KEY2_HEX_VOLUME.length());
|
||||
dispatchKeyValue(KEY_VOLUME_ZONE2, value);
|
||||
dispatchKeyValue(KEY_MUTE_ZONE2, MSG_VALUE_OFF);
|
||||
} else if (valueLowerCase.startsWith(KEY_HEX_MUTE)) {
|
||||
value = value.substring(KEY_HEX_MUTE.length()).trim();
|
||||
if (MSG_VALUE_ON.equalsIgnoreCase(value)) {
|
||||
dispatchKeyValue(KEY_MUTE_ZONE2, MSG_VALUE_ON);
|
||||
} else {
|
||||
logger.debug("Invalid value {} for zone mute", value);
|
||||
}
|
||||
} else if (!MSG_VALUE_OFF.equalsIgnoreCase(value)) {
|
||||
RotelSource source = parseSource(value, true);
|
||||
if (source != null) {
|
||||
RotelCommand cmd = source.getZone2Command();
|
||||
if (cmd != null) {
|
||||
value = cmd.getAsciiCommandV2();
|
||||
if (value != null) {
|
||||
dispatchKeyValue(KEY_SOURCE_ZONE2, value);
|
||||
if (!multipleInfo) {
|
||||
dispatchKeyValue(KEY_MUTE_ZONE2, MSG_VALUE_OFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.debug("Invalid value {} for zone 2 source", value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void parseZone3(String text, boolean multipleInfo) {
|
||||
String value = text.trim();
|
||||
String valueLowerCase = value.toLowerCase();
|
||||
if (valueLowerCase.startsWith(KEY1_HEX_VOLUME) || valueLowerCase.startsWith(KEY2_HEX_VOLUME)) {
|
||||
value = extractNumber(value,
|
||||
valueLowerCase.startsWith(KEY1_HEX_VOLUME) ? KEY1_HEX_VOLUME.length() : KEY2_HEX_VOLUME.length());
|
||||
dispatchKeyValue(KEY_VOLUME_ZONE3, value);
|
||||
dispatchKeyValue(KEY_MUTE_ZONE3, MSG_VALUE_OFF);
|
||||
} else if (valueLowerCase.startsWith(KEY_HEX_MUTE)) {
|
||||
value = value.substring(KEY_HEX_MUTE.length()).trim();
|
||||
if (MSG_VALUE_ON.equalsIgnoreCase(value)) {
|
||||
dispatchKeyValue(KEY_MUTE_ZONE3, MSG_VALUE_ON);
|
||||
} else {
|
||||
logger.debug("Invalid value {} for zone mute", value);
|
||||
}
|
||||
} else if (!MSG_VALUE_OFF.equalsIgnoreCase(value)) {
|
||||
RotelSource source = parseSource(value, true);
|
||||
if (source != null) {
|
||||
RotelCommand cmd = source.getZone3Command();
|
||||
if (cmd != null) {
|
||||
value = cmd.getAsciiCommandV2();
|
||||
if (value != null) {
|
||||
dispatchKeyValue(KEY_SOURCE_ZONE3, value);
|
||||
if (!multipleInfo) {
|
||||
dispatchKeyValue(KEY_MUTE_ZONE3, MSG_VALUE_OFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.debug("Invalid value {} for zone 3 source", value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void parseZone4(String text, boolean multipleInfo) {
|
||||
String value = text.trim();
|
||||
String valueLowerCase = value.toLowerCase();
|
||||
if (valueLowerCase.startsWith(KEY1_HEX_VOLUME) || valueLowerCase.startsWith(KEY2_HEX_VOLUME)) {
|
||||
value = extractNumber(value,
|
||||
valueLowerCase.startsWith(KEY1_HEX_VOLUME) ? KEY1_HEX_VOLUME.length() : KEY2_HEX_VOLUME.length());
|
||||
dispatchKeyValue(KEY_VOLUME_ZONE4, value);
|
||||
dispatchKeyValue(KEY_MUTE_ZONE4, MSG_VALUE_OFF);
|
||||
} else if (valueLowerCase.startsWith(KEY_HEX_MUTE)) {
|
||||
value = value.substring(KEY_HEX_MUTE.length()).trim();
|
||||
if (MSG_VALUE_ON.equalsIgnoreCase(value)) {
|
||||
dispatchKeyValue(KEY_MUTE_ZONE4, MSG_VALUE_ON);
|
||||
} else {
|
||||
logger.debug("Invalid value {} for zone mute", value);
|
||||
}
|
||||
} else if (!MSG_VALUE_OFF.equalsIgnoreCase(value)) {
|
||||
RotelSource source = parseSource(value, true);
|
||||
if (source != null) {
|
||||
RotelCommand cmd = source.getZone4Command();
|
||||
if (cmd != null) {
|
||||
value = cmd.getAsciiCommandV2();
|
||||
if (value != null) {
|
||||
dispatchKeyValue(KEY_SOURCE_ZONE4, value);
|
||||
if (!multipleInfo) {
|
||||
dispatchKeyValue(KEY_MUTE_ZONE4, MSG_VALUE_OFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.debug("Invalid value {} for zone 4 source", value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract from a string a number
|
||||
*
|
||||
* @param value the string
|
||||
* @param startIndex the index in the string at which the integer has to be extracted
|
||||
*
|
||||
* @return the number as a string with its sign and no blank between the sign and the digits
|
||||
*/
|
||||
private String extractNumber(String value, int startIndex) {
|
||||
String result = value.substring(startIndex).trim();
|
||||
// Delete possible blank(s) between the sign and the number
|
||||
if (result.startsWith("+") || result.startsWith("-")) {
|
||||
result = result.substring(0, 1) + result.substring(1, result.length()).trim();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue