├── .gitignore ├── JenkinsFile ├── LICENSE ├── README.md ├── pom.xml └── src ├── main └── java │ └── nu │ └── nethome │ └── coders │ ├── RollerTrol.java │ ├── RollerTrolG.java │ ├── decoders │ ├── CRC8.java │ ├── CRC8Table.java │ ├── Decoders.java │ ├── DeltronicDecoder.java │ ├── EmotivaDecoder.java │ ├── FineOffsetDecoder.java │ ├── HKDecoder.java │ ├── JVCDecoder.java │ ├── NexaDecoder.java │ ├── NexaFireDecoder.java │ ├── NexaLDecoder.java │ ├── OregonDecoder.java │ ├── PioneerDecoder.java │ ├── PrologueDecoder.java │ ├── ProntoDecoder.java │ ├── RC5Decoder.java │ ├── RC6Decoder.java │ ├── RisingSunDecoder.java │ ├── RollerTrolDecoder.java │ ├── RollerTrolGDecoder.java │ ├── SIRCDecoder.java │ ├── UPMDecoder.java │ ├── ViasatDecoder.java │ ├── WavemanDecoder.java │ ├── X10Decoder.java │ └── ZhejiangDecoder.java │ └── encoders │ ├── DeltronicEncoder.java │ ├── EmotivaEncoder.java │ ├── Encoders.java │ ├── NexaEncoder.java │ ├── NexaFireEncoder.java │ ├── NexaLEncoder.java │ ├── ProntoEncoder.java │ ├── RisingSunEncoder.java │ ├── RollerTrolEncoder.java │ ├── RollerTrolGEncoder.java │ ├── ShortBeepEncoder.java │ ├── WavemanEncoder.java │ ├── X10Encoder.java │ └── ZhejiangEncoder.java └── test ├── java └── nu │ └── nethome │ └── coders │ ├── decoders │ ├── EmotivaDecoderTest.java │ ├── FineOffsetDecoderTest.java │ ├── OregonDecoderTest.java │ ├── PrologueDecoderTest.java │ ├── RisingSunDecoderTest.java │ ├── RollerTrolDecoderTest.java │ ├── RollerTrolGDecoderTest.java │ ├── TestDeltronicDecoderEncoder.java │ ├── TestNexaDecoder.java │ ├── TestNexaFire.java │ ├── TestNexaLDecoder.java │ ├── TestProntoDecoder.java │ ├── TestWaveman.java │ ├── TestX10Decoder.java │ ├── ZhejiangDecoderTest.java │ └── util │ │ └── JirFileTestPlayer.java │ └── encoders │ └── RollerTrolEncoderTest.java └── resources └── nu └── nethome └── coders └── decoders ├── fine_offset.jir ├── fine_offset_neg.jir ├── nexa1.jir ├── nexa_fire.jir ├── nexal1.jir ├── nexal_dn.jir ├── oregon1.jir ├── prologue.jir └── rollertrol_3_stop.jir /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | #IDEA 3 | target 4 | *.iml 5 | *.ipr 6 | *.iws 7 | 8 | *.class 9 | # Package Files # 10 | *.jar 11 | *.war 12 | *.ear 13 | -------------------------------------------------------------------------------- /JenkinsFile: -------------------------------------------------------------------------------- 1 | #!groovy​ 2 | 3 | node { 4 | withEnv(["JAVA_HOME=${ tool 'Java8' }", "PATH+MAVEN=${tool 'Maven3'}/bin:${env.JAVA_HOME}/bin"]) { 5 | stage('Checkout') { 6 | git url: 'https://github.com/NetHome/Coders.git' 7 | } 8 | stage('Build') { 9 | sh "mvn --batch-mode -V -U -e clean install -Dsurefire.useFile=false" 10 | } 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Coders 2 | ====== 3 | Encoders and Decoders for RF and IR protocols used for remote control and data acquisition. 4 | Both Encoders and Decoders can be supplied as plugins in the NetHome server to support new protocols. 5 | They can also be used as plugins in the ProtocolAnalyzer tool, which is designed to aid in reverse engineering of 6 | simple pulse length based protocols. 7 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | coders 7 | nu.nethome 8 | 1.2 9 | coders 10 | http://www.nethome.nu 11 | 12 | UTF-8 13 | 14 | 15 | ${project.artifactId} 16 | 17 | 18 | 19 | org.apache.maven.plugins 20 | maven-compiler-plugin 21 | 2.3.2 22 | 23 | 1.6 24 | 1.6 25 | 26 | 27 | 28 | org.apache.maven.plugins 29 | maven-source-plugin 30 | 31 | 32 | attach-sources 33 | 34 | jar 35 | 36 | 37 | 38 | 39 | 40 | org.apache.maven.plugins 41 | maven-javadoc-plugin 42 | 43 | 44 | attach-javadocs 45 | 46 | jar 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | org.rxtx 56 | rxtx 57 | 2.1.7 58 | 59 | 60 | junit 61 | junit 62 | 4.8.1 63 | test 64 | 65 | 66 | org.mockito 67 | mockito-all 68 | 1.8.5 69 | test 70 | 71 | 72 | org.hamcrest 73 | hamcrest-all 74 | 1.1 75 | test 76 | 77 | 78 | nu.nethome 79 | utils 80 | 1.1 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/RollerTrol.java: -------------------------------------------------------------------------------- 1 | package nu.nethome.coders; 2 | 3 | import nu.nethome.coders.decoders.RollerTrolDecoder; 4 | import nu.nethome.util.ps.BitString; 5 | import nu.nethome.util.ps.ProtocolInfo; 6 | import nu.nethome.util.ps.PulseLength; 7 | 8 | /** 9 | * Constants for the RollerTrol protocol 10 | * 11 | * My current understanding of the protocol is: 12 | * 13 | * h = House Code 14 | * d = Device Code (Channel) 15 | * c = Command 16 | * s = Check Sum 17 | * 18 | * Message is sent LSB first 19 | * 20 | * ____Byte 4_____ ____Byte 3_____ ____Byte 2_____ ____Byte 1_____ ____Byte 0_____ 21 | * 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 22 | * s s s s s s s s 0 0 0 0 0 0 0 1 c c c c d d d d h h h h h h h h h h h h h h h h 23 | */ 24 | 25 | 26 | public class RollerTrol { 27 | public static final String ROLLER_TROL_PROTOCOL_NAME = "RollerTrol"; 28 | public static final ProtocolInfo ROLLERTROL_PROTOCOL_INFO = new ProtocolInfo(ROLLER_TROL_PROTOCOL_NAME, "Mark Length", "RollerTrol", 40, 1); 29 | public static final int MESSAGE_BIT_LENGTH = 40; 30 | 31 | // This are the pulse length constants for the protocol. The default values may 32 | // be overridden by system properties 33 | public static final PulseLength LONG_PREAMBLE_MARK = 34 | new PulseLength(RollerTrolDecoder.class, "LONG_PREAMBLE_MARK", 4885, 4000, 5000); 35 | public static final PulseLength LONG_PREAMBLE_SPACE = 36 | new PulseLength(RollerTrolDecoder.class, "LONG_PREAMBLE_SPACE", 2450, 2300, 2600); 37 | public static final PulseLength SHORT_PREAMBLE_MARK = 38 | new PulseLength(RollerTrolDecoder.class, "SHORT_PREAMBLE_MARK", 1650, 1500, 1800); 39 | public static final PulseLength SHORT = 40 | new PulseLength(RollerTrolDecoder.class, "SHORT", 300, 200, 490); 41 | public static final PulseLength LONG = 42 | new PulseLength(RollerTrolDecoder.class, "LONG", 600, 500, 800); 43 | public static final PulseLength SHORT_MARK = 44 | new PulseLength(RollerTrolDecoder.class, "SHORT_MARK", 500, 300, 700); 45 | 46 | public static final PulseLength SPACE = 47 | new PulseLength(RollerTrolDecoder.class, "SPACE", 1000, 800, 1200); 48 | // These are the fields in the binary message 49 | public static final BitString.Field HOUSE_CODE = new BitString.Field(0, 16); 50 | public static final BitString.Field DEVICE_CODE = new BitString.Field(16, 4); 51 | public static final BitString.Field COMMAND = new BitString.Field(20, 4); 52 | public static final BitString.Field CHECK_SUM = new BitString.Field(32, 8); 53 | public static final BitString.Field CONSTANT_FIELD = new BitString.Field(24, 8); 54 | 55 | // Message field names 56 | public static final String HOUSE_CODE_NAME = "HouseCode"; 57 | public static final String COMMAND_NAME = "Command"; 58 | public static final String DEVICE_CODE_NAME = "DeviceCode"; 59 | 60 | // Commands 61 | public static final int UP = 12; 62 | public static final int STOP = 5; 63 | public static final int DOWN = 1; 64 | public static final int REVERSE = 8; 65 | public static final int LIMIT = 3; 66 | public static final int CONFIRM = 4; 67 | public static final int ALL_CHANNELS = 15; 68 | 69 | public static int calculateChecksum(BitString binaryMessage) { 70 | int calculatedCheckSum = binaryMessage.extractInt(RollerTrolDecoder.BYTE0) + 71 | binaryMessage.extractInt(RollerTrolDecoder.BYTE1) + 72 | binaryMessage.extractInt(RollerTrolDecoder.BYTE2) + 73 | binaryMessage.extractInt(RollerTrolDecoder.BYTE3); 74 | calculatedCheckSum = (((calculatedCheckSum / 256) + 1) * 256 + 1) - calculatedCheckSum; 75 | return calculatedCheckSum; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/RollerTrolG.java: -------------------------------------------------------------------------------- 1 | package nu.nethome.coders; 2 | 3 | import nu.nethome.coders.decoders.RollerTrolGDecoder; 4 | import nu.nethome.util.ps.BitString; 5 | import nu.nethome.util.ps.ProtocolInfo; 6 | import nu.nethome.util.ps.PulseLength; 7 | 8 | public class RollerTrolG { 9 | public static final String ROLLER_TROL_G_PROTOCOL_NAME = "RollerTrolG"; 10 | public static final int PROTOCOL_BIT_LENGTH = 40; 11 | public static final ProtocolInfo ROLLERTROL_PROTOCOL_INFO = new ProtocolInfo(ROLLER_TROL_G_PROTOCOL_NAME, "Mark Length", "RollerTrol", PROTOCOL_BIT_LENGTH, 1); 12 | 13 | public static final int COMMAND_STOP = 0x55; 14 | public static final int COMMAND_UP = 0x11; 15 | public static final int COMMAND_UP_END = 0x1E; 16 | public static final int COMMAND_DOWN = 0x33; 17 | public static final int COMMAND_DOWN_END = 0x3C; 18 | public static final int COMMAND_LEARN = 0xCC; 19 | 20 | public static final PulseLength LONG_PREAMBLE_MARK = 21 | new PulseLength(RollerTrolGDecoder.class, "LONG_PREAMBLE_MARK", 5170, 4000, 5900); 22 | public static final PulseLength LONG_PREAMBLE_SPACE = 23 | new PulseLength(RollerTrolGDecoder.class, "LONG_PREAMBLE_SPACE", 1665, 1000, 2000); 24 | public static final PulseLength SHORT = 25 | new PulseLength(RollerTrolGDecoder.class, "SHORT", 360, 200, 500); 26 | public static final PulseLength LONG = 27 | new PulseLength(RollerTrolGDecoder.class, "LONG", 770, 600, 900); 28 | public static final PulseLength REPEAT_SPACE = 29 | new PulseLength(RollerTrolGDecoder.class, "REPEAT_SPACE", 7400, 7000, 11000); 30 | 31 | public static final BitString.Field COMMAND = new BitString.Field(0, 8); 32 | public static final BitString.Field CHANNEL = new BitString.Field(8, 4); 33 | public static final BitString.Field ADDRESS = new BitString.Field(12, 28); 34 | public static final String COMMAND_NAME = "Command"; 35 | public static final String CHANNEL_NAME = "Channel"; 36 | public static final String ADDRESS_NAME = "Address"; 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/decoders/CRC8.java: -------------------------------------------------------------------------------- 1 | package nu.nethome.coders.decoders; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | 6 | public interface CRC8 { 7 | 8 | /** 9 | * Calculates a CRC8 from the given data block. 10 | * @param block the array from which the CRC is calculated 11 | * @param from the initial index of the range to be copied, inclusive 12 | * @param to the final index of the range to be copied, exclusive. (This index may lie outside the array.) 13 | * @return the calculated CRC8 (8-bit) 14 | */ 15 | public abstract int calc(byte[] block, int from, int to); 16 | 17 | /** 18 | * Calculates a CRC8 from the given data block. 19 | * @param block the array from which the CRC is calculated 20 | * @param from the initial index of the range to be copied, inclusive 21 | * @param to the final index of the range to be copied, exclusive. (This index may lie outside the array.) 22 | * @param initial the initial CRC value (normally 0) 23 | * @return the calculated CRC8 (8-bit) 24 | */ 25 | public abstract int calc(byte[] block, int from, int to, int initial); 26 | 27 | /** 28 | * Calculates a CRC8 from the given data block. 29 | * @param block the array from which the CRC is calculated 30 | * @param initial the initial CRC value (normally 0) 31 | * @return the calculated CRC8 (8-bit) 32 | */ 33 | public abstract int calc(byte[] block, int initial); 34 | 35 | /** 36 | * Calculates a CRC8 from the given data block. 37 | * @param block the array from which the CRC is calculated 38 | * @return the calculated CRC8 (8-bit) 39 | */ 40 | public abstract int calc(byte[] block); 41 | 42 | /** 43 | * Calculates a CRC8 from the given InputStream. 44 | * @param stream the stream to calculate the CRC8 from 45 | * @return the calculated CRC8 (8-bit) 46 | * @throws IOException if an I/O error occurs 47 | */ 48 | public abstract int calc(InputStream stream) throws IOException; 49 | 50 | /** 51 | * Calculates a CRC8 from the given InputStream. 52 | * @param stream the stream to calculate the CRC8 from 53 | * @param initial the initial CRC value (normally 0) 54 | * @return the calculated CRC8 (8-bit) 55 | * @throws IOException if an I/O error occurs 56 | */ 57 | public abstract int calc(InputStream stream, int initial) 58 | throws IOException; 59 | 60 | /** 61 | * Calculates a CRC8 from the given InputStream. Note that this function may return before count has been reached if an end of stream occurred. 62 | * @param stream the stream to calculate the CRC8 from 63 | * @param length the number of bytes to read 64 | * @param initial the initial CRC value (normally 0) 65 | * @return the calculated CRC8 (8-bit) 66 | * @throws IOException if an I/O error occurs 67 | */ 68 | public abstract int calc(InputStream stream, int length, int initial) 69 | throws IOException; 70 | } -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/decoders/CRC8Table.java: -------------------------------------------------------------------------------- 1 | package nu.nethome.coders.decoders; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | 6 | public class CRC8Table implements CRC8 { 7 | 8 | private final int[] table; 9 | 10 | public CRC8Table(int polynomial) { 11 | table = generateTable(polynomial); 12 | } 13 | 14 | public CRC8Table(int[] table) { 15 | this.table = table; 16 | } 17 | 18 | public static byte[] compress(int[] table) { 19 | byte[] tmp = new byte[table.length]; 20 | for (int i = 0; i < table.length; ++i) { 21 | tmp[i] = (byte) table[i]; 22 | } 23 | return tmp; 24 | } 25 | 26 | public static int[] decompress(byte[] table) { 27 | int[] tmp = new int[table.length]; 28 | for (int i = 0; i < table.length; ++i) { 29 | tmp[i] = table[i] & 0xFF; 30 | } 31 | return tmp; 32 | } 33 | 34 | private static int pushByte(int b, int polynomial) { 35 | for (int i = 0; i < 8; ++i) { 36 | if ((b & 0x80) != 0) { 37 | int step1 = b << 1; 38 | b = step1 ^ polynomial; 39 | } else { 40 | b = b << 1; 41 | } 42 | } 43 | return b & 0xFF; 44 | } 45 | 46 | /** 47 | * Creates a CRC8 table given a polynomial. 48 | * 49 | * @param polynomial 50 | * @return 51 | */ 52 | public static int[] generateTable(int polynomial) { 53 | int[] table = new int[256]; 54 | for (int i = 0; i < 256; ++i) { 55 | table[i] = pushByte(i, polynomial); 56 | } 57 | return table; 58 | } 59 | 60 | private int calcImpl(byte[] block, int from, int to, int initial) { 61 | int crc = initial; 62 | for (int i = from; i < to; ++i) { 63 | crc = getTable()[crc ^ (block[i] & 0xFF)]; 64 | } 65 | return crc; 66 | } 67 | 68 | /* (non-Javadoc) 69 | * @see CRC8#calc(byte[], int, int) 70 | */ 71 | @Override 72 | public int calc(byte[] block, int from, int to) { 73 | return calcImpl(block, from, to, 0); 74 | } 75 | 76 | /* (non-Javadoc) 77 | * @see CRC8#calc(byte[], int, int, int) 78 | */ 79 | @Override 80 | public int calc(byte[] block, int from, int to, int initial) { 81 | return calcImpl(block, from, to, initial); 82 | } 83 | 84 | /* (non-Javadoc) 85 | * @see CRC8#calc(byte[], int) 86 | */ 87 | @Override 88 | public int calc(byte[] block, int initial) { 89 | return calcImpl(block, 0, block.length, initial); 90 | } 91 | 92 | /* (non-Javadoc) 93 | * @see CRC8#calc(byte[]) 94 | */ 95 | @Override 96 | public int calc(byte[] block) { 97 | return calc(block, 0, block.length, 0); 98 | } 99 | 100 | /* (non-Javadoc) 101 | * @see CRC8#calc(java.io.InputStream) 102 | */ 103 | @Override 104 | public int calc(InputStream stream) throws IOException { 105 | return calc(stream, 0); 106 | } 107 | 108 | /* (non-Javadoc) 109 | * @see CRC8#calc(java.io.InputStream, int) 110 | */ 111 | @Override 112 | public int calc(InputStream stream, int initial) throws IOException { 113 | int b; 114 | int crc = initial; 115 | while ((b = stream.read()) != -1) { 116 | crc = getTable()[crc ^ (b & 0xFF)]; 117 | } 118 | return crc; 119 | } 120 | 121 | /* (non-Javadoc) 122 | * @see CRC8#calc(java.io.InputStream, int, int) 123 | */ 124 | @Override 125 | public int calc(InputStream stream, int length, int initial) throws IOException { 126 | int b; 127 | int crc = initial; 128 | for (int i = 0; (b = stream.read()) != -1 || i < length; ++i) { 129 | crc = getTable()[crc ^ (b & 0xFF)]; 130 | } 131 | return crc; 132 | } 133 | 134 | public int[] getTable() { 135 | return table; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/decoders/Decoders.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2013, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.decoders; 21 | 22 | import nu.nethome.util.ps.ProtocolDecoder; 23 | 24 | import java.util.ArrayList; 25 | import java.util.Collection; 26 | 27 | public class Decoders { 28 | public static Collection> getAllTypes() { 29 | Collection> result = new ArrayList>(); 30 | result.add(DeltronicDecoder.class); 31 | result.add(EmotivaDecoder.class); 32 | result.add(HKDecoder.class); 33 | result.add(JVCDecoder.class); 34 | result.add(NexaDecoder.class); 35 | result.add(NexaFireDecoder.class); 36 | result.add(NexaLDecoder.class); 37 | result.add(PioneerDecoder.class); 38 | result.add(ProntoDecoder.class); 39 | result.add(RC5Decoder.class); 40 | result.add(RC6Decoder.class); 41 | result.add(RisingSunDecoder.class); 42 | result.add(SIRCDecoder.class); 43 | result.add(UPMDecoder.class); 44 | result.add(ViasatDecoder.class); 45 | result.add(WavemanDecoder.class); 46 | result.add(X10Decoder.class); 47 | result.add(ZhejiangDecoder.class); 48 | result.add(OregonDecoder.class); 49 | result.add(FineOffsetDecoder.class); 50 | result.add(RollerTrolDecoder.class); 51 | result.add(RollerTrolGDecoder.class); 52 | result.add(PrologueDecoder.class); 53 | return result; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/decoders/EmotivaDecoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2013, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.decoders; 21 | 22 | import nu.nethome.util.plugin.Plugin; 23 | import nu.nethome.util.ps.FieldValue; 24 | import nu.nethome.util.ps.ProtocolDecoder; 25 | import nu.nethome.util.ps.ProtocolInfo; 26 | import nu.nethome.util.ps.ProtocolMessage; 27 | 28 | @Plugin 29 | public class EmotivaDecoder extends PioneerDecoder implements ProtocolDecoder { 30 | 31 | protected int addressLo = 0; 32 | protected int addressHi = 0; 33 | protected int command = 0; 34 | protected int commandChecksum = 0; 35 | 36 | public ProtocolInfo getInfo() { 37 | return new ProtocolInfo("Emotiva", "Space Length", "Emotiva", 24, 5); 38 | } 39 | 40 | protected void addBit(int b) { 41 | if (m_BitCounter < 8) { 42 | addressLo >>= 1; 43 | addressLo |= (b << 7); 44 | } else if (m_BitCounter < 16) { 45 | addressHi >>= 1; 46 | addressHi |= (b << 7); 47 | } else if (m_BitCounter < 24) { 48 | command >>= 1; 49 | command |= (b << 7); 50 | } else if (m_BitCounter < 32) { 51 | commandChecksum >>= 1; 52 | commandChecksum |= (b << 7); 53 | } 54 | // Check if this is a complete message 55 | if (m_BitCounter == 31) { 56 | 57 | // It is, verify checksum 58 | if ((command != (commandChecksum ^ 0xFF))) { 59 | // Checksum error 60 | reportPartial(); 61 | m_State = IDLE; 62 | return; 63 | } 64 | 65 | ProtocolMessage message = new ProtocolMessage("Emotiva", command, addressLo + (addressHi << 8), 3); 66 | message.setRawMessageByteAt(0, addressLo); 67 | message.setRawMessageByteAt(1, addressHi); 68 | message.setRawMessageByteAt(2, command); 69 | // It is, check if this really is a repeat 70 | if ((m_RepeatCount > 0) && (addressLo == m_LastCommand) && (command == m_LastAddress)) { 71 | message.setRepeat(m_RepeatCount); 72 | } else { 73 | // It is not a repeat, reset counter 74 | m_RepeatCount = 0; 75 | } 76 | message.addField(new FieldValue("Command", command)); 77 | message.addField(new FieldValue("Address", addressLo + (addressHi << 8))); 78 | // Report the parsed message 79 | m_Sink.parsedMessage(message); 80 | m_State = TRAILING_BIT; 81 | } 82 | m_BitCounter++; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/decoders/HKDecoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2013, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.decoders; 21 | 22 | import nu.nethome.util.plugin.Plugin; 23 | import nu.nethome.util.ps.*; 24 | 25 | 26 | @Plugin 27 | public class HKDecoder implements ProtocolDecoder { 28 | protected static final int IDLE = 0; 29 | protected static final int READING_HEADER = 1; 30 | protected static final int READING_BIT_MARK = 2; 31 | protected static final int READING_BIT_SPACE = 3; 32 | protected static final int TRAILING_BIT = 4; 33 | protected static final int REPEAT_SCAN = 5; 34 | protected static final int REPEAT_HEADER_SCAN = 6; 35 | protected static final int REPEAT_BODY_SPACE_SCAN = 7; 36 | protected static final int REPEAT_BODY_MARK_SCAN = 8; 37 | protected static final int REPEAT_REPEAT_SCAN = 9; 38 | 39 | protected int m_State = IDLE; 40 | 41 | protected int m_Command = 0; 42 | protected int m_CommandCheck = 0; 43 | protected int m_Address = 0; 44 | protected int m_AddressCheck = 0; 45 | 46 | protected int m_LastCommand = 0; 47 | protected int m_LastAddress = 0; 48 | 49 | protected int m_BitCounter = 0; 50 | protected int m_RepeatCount = 0; 51 | protected ProtocolDecoderSink m_Sink = null; 52 | 53 | public void setTarget(ProtocolDecoderSink sink) { 54 | m_Sink = sink; 55 | } 56 | 57 | public ProtocolInfo getInfo() { 58 | return new ProtocolInfo("HK", "Space Length", "Harman/Kardon", 16, 5); 59 | } 60 | 61 | protected boolean pulseCompare(double candidate, double standard) { 62 | return Math.abs(standard - candidate) < standard * 0.4; 63 | } 64 | 65 | protected boolean pulseCompare(double candidate, double min, double max) { 66 | return ((candidate > min) && (candidate < max)); 67 | } 68 | 69 | protected void reportPartial() { 70 | if (m_BitCounter > 0) { 71 | m_Sink.partiallyParsedMessage("HK", m_BitCounter); 72 | } 73 | } 74 | 75 | protected void addBit(int b) { 76 | if (m_BitCounter < 8) { 77 | m_Address >>= 1; 78 | m_Address |= (b << 7); 79 | } 80 | else if (m_BitCounter < 16) { 81 | m_AddressCheck >>= 1; 82 | m_AddressCheck |= (b << 7); 83 | } 84 | else if (m_BitCounter < 24) { 85 | m_Command >>= 1; 86 | m_Command |= (b << 7); 87 | } 88 | else if (m_BitCounter < 32) { 89 | m_CommandCheck >>= 1; 90 | m_CommandCheck |= (b << 7); 91 | } 92 | // Check if this is a complete message 93 | if (m_BitCounter == 31){ 94 | // It is, verify checksum 95 | if (((m_Address & 0xF0) != ((m_AddressCheck ^ 0xFF) & 0xF0)) || 96 | ((m_AddressCheck & 0x0F) != 0) || 97 | (m_Command != (m_CommandCheck ^ 0xFF))) { 98 | // Checksum error 99 | reportPartial(); 100 | m_State = IDLE; 101 | return; 102 | } 103 | ProtocolMessage message = new ProtocolMessage("HK", m_Command, m_Address, 4); 104 | message.setRawMessageByteAt(0, m_Address); 105 | message.setRawMessageByteAt(1, m_AddressCheck); 106 | message.setRawMessageByteAt(2, m_Command); 107 | message.setRawMessageByteAt(3, m_CommandCheck); 108 | message.addField(new FieldValue("Command", m_Command)); 109 | message.addField(new FieldValue("Address", m_Address)); 110 | // Report the parsed message 111 | m_Sink.parsedMessage(message); 112 | m_State = TRAILING_BIT; 113 | } 114 | m_BitCounter++; 115 | } 116 | 117 | /* (non-Javadoc) 118 | * @see ssg.ir.IRDecoder#parse(java.lang.Double) 119 | */ 120 | public int parse(double pulse, boolean state) { 121 | switch (m_State) { 122 | case IDLE: { 123 | if (pulseCompare(pulse, 8400.0 + 60) && state) { 124 | m_State = READING_HEADER; 125 | m_Command = 0; 126 | m_Address = 0; 127 | m_CommandCheck = 0; 128 | m_AddressCheck = 0; 129 | m_BitCounter = 0; 130 | } 131 | break; 132 | } 133 | case READING_HEADER: { 134 | if (pulseCompare(pulse, 4200.0 - 60)) { 135 | m_State = READING_BIT_MARK; 136 | } 137 | else { 138 | m_State = IDLE; 139 | reportPartial(); 140 | } 141 | break; 142 | } 143 | case READING_BIT_MARK: { 144 | // The mark pulse seems to vary a lot in length 145 | if (pulseCompare(pulse, 50, 700)) { 146 | m_State = READING_BIT_SPACE; 147 | } 148 | else { 149 | m_State = IDLE; 150 | reportPartial(); 151 | } 152 | break; 153 | } 154 | case READING_BIT_SPACE: { 155 | if (pulseCompare(pulse, 1575.0 - 60)) { 156 | m_State = READING_BIT_MARK; 157 | addBit(1); 158 | } 159 | else if (pulseCompare(pulse, 524.0 + 60)) { 160 | m_State = READING_BIT_MARK; 161 | addBit(0); 162 | } 163 | else { 164 | m_State = IDLE; 165 | reportPartial(); 166 | } 167 | break; 168 | } 169 | 170 | case TRAILING_BIT: { 171 | // The mark pulse seems to vary a lot in length 172 | if (pulseCompare(pulse, 100, 700)) { 173 | m_State = REPEAT_SCAN; 174 | } 175 | else { 176 | m_State = IDLE; 177 | } 178 | break; 179 | } 180 | case REPEAT_SCAN: { 181 | if (pulseCompare(pulse, 45000.0)) { 182 | m_State = REPEAT_HEADER_SCAN; 183 | } 184 | else { 185 | m_RepeatCount = 0; 186 | m_State = IDLE; 187 | } 188 | break; 189 | } 190 | case REPEAT_HEADER_SCAN: { 191 | if (pulseCompare(pulse, 9000.0)) { 192 | m_State = REPEAT_BODY_SPACE_SCAN; 193 | } 194 | else { 195 | m_RepeatCount = 0; 196 | m_State = IDLE; 197 | } 198 | break; 199 | } 200 | case REPEAT_BODY_SPACE_SCAN: { 201 | if (pulseCompare(pulse, 2300.0 - 60)) { 202 | m_State = REPEAT_BODY_MARK_SCAN; 203 | } 204 | else { 205 | m_RepeatCount = 0; 206 | m_State = IDLE; 207 | } 208 | break; 209 | } 210 | case REPEAT_BODY_MARK_SCAN: { 211 | if (pulseCompare(pulse, 600.0 + 60)) { 212 | m_State = REPEAT_REPEAT_SCAN; 213 | // Ok, this was arepeat stub, create a fake new message 214 | m_RepeatCount++; 215 | ProtocolMessage message = new ProtocolMessage("HK", m_Command, m_Address, 4); 216 | message.setRepeat(m_RepeatCount); 217 | message.setRawMessageByteAt(0, m_Address); 218 | message.setRawMessageByteAt(1, m_AddressCheck); 219 | message.setRawMessageByteAt(2, m_Command); 220 | message.setRawMessageByteAt(3, m_CommandCheck); 221 | message.addField(new FieldValue("Command", m_Command)); 222 | message.addField(new FieldValue("Address", m_Address)); 223 | // Report the parsed message 224 | m_Sink.parsedMessage(message); 225 | } 226 | else { 227 | m_RepeatCount = 0; 228 | m_State = IDLE; 229 | } 230 | break; 231 | } 232 | case REPEAT_REPEAT_SCAN: { 233 | if (pulseCompare(pulse, 95000.0)) { 234 | m_State = REPEAT_HEADER_SCAN; 235 | } 236 | else { 237 | m_RepeatCount = 0; 238 | m_State = IDLE; 239 | } 240 | break; 241 | } 242 | } 243 | return m_State; 244 | } 245 | } 246 | 247 | -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/decoders/JVCDecoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2013, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.decoders; 21 | 22 | import nu.nethome.util.plugin.Plugin; 23 | import nu.nethome.util.ps.*; 24 | 25 | 26 | @Plugin 27 | public class JVCDecoder implements ProtocolDecoder { 28 | protected static final int IDLE = 0; 29 | protected static final int READING_HEADER = 1; 30 | protected static final int READING_BIT_MARK = 2; 31 | protected static final int READING_BIT_SPACE = 3; 32 | protected static final int TRAILING_BIT = 4; 33 | protected static final int REPEAT_SCAN = 5; 34 | 35 | protected int m_State = IDLE; 36 | 37 | protected int m_Command = 0; 38 | protected int m_Address = 0; 39 | 40 | protected int m_LastCommand = 0; 41 | protected int m_LastAddress = 0; 42 | 43 | protected int m_BitCounter = 0; 44 | protected int m_RepeatCount = 0; 45 | protected ProtocolDecoderSink m_Sink = null; 46 | 47 | public void setTarget(ProtocolDecoderSink sink) { 48 | m_Sink = sink; 49 | } 50 | 51 | public ProtocolInfo getInfo() { 52 | return new ProtocolInfo("JVC", "Space Length", "JVC", 16, 5); 53 | } 54 | 55 | protected boolean pulseCompare(double candidate, double standard) { 56 | return Math.abs(standard - candidate) < standard * 0.4; 57 | } 58 | 59 | protected boolean pulseCompare(double candidate, double min, double max) { 60 | return ((candidate > min) && (candidate < max)); 61 | } 62 | 63 | protected void reportPartial() { 64 | if (m_BitCounter > 0) { 65 | m_Sink.partiallyParsedMessage("JVC", m_BitCounter); 66 | } 67 | } 68 | 69 | protected void addBit(int b) { 70 | if (m_BitCounter < 8) { 71 | m_Address >>= 1; 72 | m_Address |= (b << 7); 73 | } 74 | else if (m_BitCounter < 16) { 75 | m_Command >>= 1; 76 | m_Command |= (b << 7); 77 | } 78 | // Check if this is a complete message 79 | if (m_BitCounter == 15){ 80 | // It is, create the message 81 | ProtocolMessage message = new ProtocolMessage("JVC", m_Command, m_Address, 2); 82 | message.setRawMessageByteAt(0, m_Command); 83 | message.setRawMessageByteAt(1, m_Address); 84 | // It is, check if this really is a repeat 85 | if ((m_RepeatCount > 0) && (m_Command == m_LastCommand) && (m_Address == m_LastAddress)) { 86 | message.setRepeat(m_RepeatCount); 87 | } 88 | else { 89 | // It is not a repeat, reset counter 90 | m_RepeatCount = 0; 91 | } 92 | message.addField(new FieldValue("Command", m_Command)); 93 | message.addField(new FieldValue("Address", m_Address)); 94 | // Report the parsed message 95 | m_Sink.parsedMessage(message); 96 | m_State = TRAILING_BIT; 97 | } 98 | m_BitCounter++; 99 | } 100 | 101 | /* (non-Javadoc) 102 | * @see ssg.ir.IRDecoder#parse(java.lang.Double) 103 | */ 104 | public int parse(double pulse, boolean state) { 105 | switch (m_State) { 106 | case IDLE: { 107 | if (pulseCompare(pulse, 8400.0 + 60) && state) { 108 | m_State = READING_HEADER; 109 | m_Command = 0; 110 | m_Address = 0; 111 | m_BitCounter = 0; 112 | } 113 | break; 114 | } 115 | case READING_HEADER: { 116 | if (pulseCompare(pulse, 4200.0 - 60)) { 117 | m_State = READING_BIT_MARK; 118 | } 119 | else { 120 | m_State = IDLE; 121 | reportPartial(); 122 | } 123 | break; 124 | } 125 | case READING_BIT_MARK: { 126 | // The mark pulse seems to vary a lot in length 127 | if (pulseCompare(pulse, 50, 700 + 60)) { 128 | m_State = READING_BIT_SPACE; 129 | } 130 | else { 131 | m_State = IDLE; 132 | reportPartial(); 133 | } 134 | break; 135 | } 136 | case READING_BIT_SPACE: { 137 | if (pulseCompare(pulse, 1575.0 - 60)) { 138 | m_State = READING_BIT_MARK; 139 | addBit(1); 140 | } 141 | else if (pulseCompare(pulse, 524.0 - 60)) { 142 | m_State = READING_BIT_MARK; 143 | addBit(0); 144 | } 145 | else { 146 | m_State = IDLE; 147 | reportPartial(); 148 | } 149 | break; 150 | } 151 | 152 | case TRAILING_BIT: { 153 | // The mark pulse seems to vary a lot in length 154 | if (pulseCompare(pulse, 100, 700 + 60)) { 155 | m_State = REPEAT_SCAN; 156 | } 157 | else { 158 | m_State = IDLE; 159 | } 160 | break; 161 | } 162 | case REPEAT_SCAN: { 163 | if (pulseCompare(pulse, 16000.0, 23000.0)) { 164 | m_RepeatCount += 1; // Start repeat sequence 165 | // Save this sequence 166 | m_LastCommand = m_Command; 167 | m_LastAddress = m_Address; 168 | m_Command = 0; 169 | m_Address = 0; 170 | m_BitCounter = 0; 171 | m_State = READING_BIT_MARK; 172 | } 173 | else { 174 | m_RepeatCount = 0; 175 | m_State = IDLE; 176 | } 177 | break; 178 | } 179 | } 180 | return m_State; 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/decoders/NexaFireDecoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2013, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.decoders; 21 | 22 | import nu.nethome.util.plugin.Plugin; 23 | import nu.nethome.util.ps.*; 24 | 25 | /** 26 | * The NexaFireDecoder parses a set of pulse lengths and decodes a protocol used 27 | * by Nexa Fire Detector transmitted over 433MHz AM-modulated RF-signal. 28 | * The reception of the pulses may for example be made via the AudioProtocolSampler. 29 | * The NexaDecoder implements the ProtocolDecoder-interface and accepts the pulses 30 | * one by one. It contains a state machine, and when a complete message is decoded, 31 | * this is reported over the ProtocolDecoderSink-interface which is given at 32 | * construction. 33 | * 34 | * The protocol is mark length encoded and the protocol messages has the following 35 | * layout:
36 | * 37 | * a = Address
38 | *
39 | * ____Byte 2_____ ____Byte 1_____ ____Byte 0_____
40 | * 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
41 | * a a a a a a a a a a a a a a a a a a a a a a a a
42 | * 43 | * @author Stefan 44 | * 45 | */ 46 | @Plugin 47 | public class NexaFireDecoder implements ProtocolDecoder { 48 | protected static final int IDLE = 0; 49 | protected static final int READING_HEADER_SPACE = 1; 50 | protected static final int READING_BIT_MARK = 2; 51 | protected static final int READING_BIT_SPACE = 3; 52 | protected static final int READING_TRAILING_MARK = 4; 53 | protected static final int REPEAT_SCAN = 5; 54 | 55 | protected static final String s_StateNames[] = {"IDLE","READING_BIT_MARK","READING_BIT_SHORT_SPACE", 56 | "READING_BIT_LONG_SPACE","REPEAT_SCAN"}; 57 | 58 | protected int m_State = IDLE; 59 | 60 | // This are the pulse length constants for the protocol. The default values may 61 | // be overridden by system properties 62 | public static final PulseLength NEXAF_HEADER_MARK = 63 | new PulseLength(NexaDecoder.class,"NEXAF_HEADER_MARK", 8100, 400); 64 | public static final PulseLength NEXAF_HEADER_SPACE = 65 | new PulseLength(NexaDecoder.class,"NEXAF_HEADER_SPACE", 900, 100); 66 | public static final PulseLength NEXAF_MARK = 67 | new PulseLength(NexaDecoder.class,"NEXAF_MARK", 800, 200); 68 | public static final PulseLength NEXAF_LONG_SPACE = 69 | new PulseLength(NexaDecoder.class,"NEXAF_LONG_SPACE", 2740, 300); 70 | public static final PulseLength NEXAF_SHORT_SPACE = 71 | new PulseLength(NexaDecoder.class,"NEXAF_SHORT_SPACE", 1400, 200); 72 | public static final PulseLength NEXAF_REPEAT = 73 | new PulseLength(NexaDecoder.class,"NEXAF_REPEAT", 14500, 2000); 74 | 75 | protected PulseLength HEADER_MARK = NEXAF_HEADER_MARK; 76 | protected PulseLength HEADER_SPACE = NEXAF_HEADER_SPACE; 77 | protected PulseLength MARK = NEXAF_MARK; 78 | protected PulseLength LONG_SPACE = NEXAF_LONG_SPACE; 79 | protected PulseLength SHORT_SPACE = NEXAF_SHORT_SPACE; 80 | protected PulseLength REPEAT = NEXAF_REPEAT; 81 | 82 | int m_Data = 0; 83 | int m_LastData = 0; 84 | 85 | protected int m_BitCounter = 0; 86 | protected int m_RepeatCount = 0; 87 | protected ProtocolDecoderSink m_Sink = null; 88 | private double m_LastPulse = REPEAT.length() / 2; 89 | public StatePulseAnalyzer analyzer = new StatePulseAnalyzer(); 90 | private boolean m_PrintAnalyze = false; 91 | protected String m_ProtocolName; 92 | 93 | public void setTarget(ProtocolDecoderSink sink) { 94 | m_Sink = sink; 95 | } 96 | 97 | /** 98 | * Template method pattern. Used to initiate variables that may be modified by 99 | * subclasses. 100 | */ 101 | public void setup() { 102 | m_ProtocolName = "NexaFire"; 103 | } 104 | 105 | public NexaFireDecoder() { 106 | setup(); 107 | } 108 | 109 | public ProtocolInfo getInfo() { 110 | return new ProtocolInfo(m_ProtocolName, "Space Length", m_ProtocolName, 24, 5); 111 | } 112 | 113 | /** 114 | * 115 | * a = Address
116 | *
117 | * ____Byte 2_____ ____Byte 1_____ ____Byte 0_____
118 | * 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
119 | * a a a a a a a a a a a a a a a a a a a a a a a a
120 | * 121 | */ 122 | protected void addBit(int b) { 123 | // Shift in data 124 | m_Data >>= 1; 125 | m_Data |= (b << 23); 126 | // Check if this is a complete message 127 | if (m_BitCounter == 23){ 128 | // It is, create the message 129 | ProtocolMessage message = new ProtocolMessage(m_ProtocolName, 1, m_Data, 1); 130 | message.setRawMessageByteAt(0, m_Data); 131 | 132 | message.addField(new FieldValue("Address", m_Data)); 133 | 134 | // It is, check if this really is a repeat 135 | if ((m_RepeatCount > 0) && (m_Data == m_LastData)) { 136 | message.setRepeat(m_RepeatCount); 137 | } 138 | else { 139 | // It is not a repeat, reset counter 140 | m_RepeatCount = 0; 141 | } 142 | // Report the parsed message 143 | m_Sink.parsedMessage(message); 144 | m_State = READING_TRAILING_MARK; 145 | if (m_PrintAnalyze) { 146 | analyzer.printPulses(); 147 | } 148 | } 149 | m_BitCounter++; 150 | } 151 | 152 | /** 153 | * Report that part of a message was parsed, but aborted due to a non valid 154 | * pulse length. 155 | * 156 | * @param state Current state when parsing was aborted 157 | * @param length Length of the pulse which was not accepted 158 | */ 159 | protected void partiallyParsed(String state, double length) { 160 | if (m_BitCounter > 1) { 161 | m_Sink.partiallyParsedMessage(m_ProtocolName + " " + state + ": " + Double.toString(length), m_BitCounter); 162 | } 163 | } 164 | 165 | /* (non-Javadoc) 166 | * @see ssg.ir.IRDecoder#parse(java.lang.Double) 167 | */ 168 | public int parse(double pulse, boolean state) { 169 | switch (m_State) { 170 | case IDLE: { 171 | if (HEADER_MARK.matches(pulse) && state && (m_LastPulse > (REPEAT.length() / 2))) { 172 | m_State = READING_HEADER_SPACE; 173 | m_Data = 0; 174 | m_BitCounter = 0; 175 | } 176 | break; 177 | } 178 | case READING_HEADER_SPACE: { 179 | if (HEADER_SPACE.matches(pulse)) { 180 | m_State = READING_BIT_MARK; 181 | } else { 182 | m_State = IDLE; 183 | } 184 | break; 185 | } 186 | case READING_BIT_MARK: { 187 | if (MARK.matches(pulse) && state) { 188 | m_State = READING_BIT_SPACE; 189 | } else { 190 | partiallyParsed("M" ,pulse); 191 | m_State = IDLE; 192 | } 193 | break; 194 | } 195 | case READING_BIT_SPACE: { 196 | if (LONG_SPACE.matches(pulse)) { 197 | m_State = READING_BIT_MARK; 198 | addBit(1); 199 | } else if (SHORT_SPACE.matches(pulse)) { 200 | m_State = READING_BIT_MARK; 201 | addBit(0); 202 | } else { 203 | partiallyParsed("S", pulse); 204 | m_State = IDLE; 205 | } 206 | break; 207 | } 208 | case READING_TRAILING_MARK: { 209 | if (MARK.matches(pulse)) { 210 | m_State = REPEAT_SCAN; 211 | } else { 212 | m_State = IDLE; 213 | } 214 | break; 215 | } 216 | case REPEAT_SCAN: { 217 | if (REPEAT.matches(pulse)) { 218 | m_RepeatCount += 1; // Start repeat sequence 219 | // Save this sequence 220 | m_LastData = m_Data; 221 | } 222 | else { 223 | m_RepeatCount = 0; 224 | } 225 | m_State = IDLE; 226 | break; 227 | } 228 | } 229 | m_LastPulse = pulse; 230 | return m_State; 231 | } 232 | } 233 | 234 | -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/decoders/PioneerDecoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2013, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.decoders; 21 | 22 | import nu.nethome.util.plugin.Plugin; 23 | import nu.nethome.util.ps.*; 24 | 25 | 26 | @Plugin 27 | public class PioneerDecoder implements ProtocolDecoder { 28 | protected static final int IDLE = 0; 29 | protected static final int READING_HEADER = 1; 30 | protected static final int READING_BIT_MARK = 2; 31 | protected static final int READING_BIT_SPACE = 3; 32 | protected static final int TRAILING_BIT = 4; 33 | protected static final int REPEAT_SCAN = 5; 34 | 35 | protected int m_State = IDLE; 36 | 37 | protected int m_Command = 0; 38 | protected int m_CommandCheck = 0; 39 | protected int m_Address = 0; 40 | protected int m_AddressCheck = 0; 41 | 42 | protected int m_LastCommand = 0; 43 | protected int m_LastAddress = 0; 44 | 45 | protected int m_BitCounter = 0; 46 | protected int m_RepeatCount = 0; 47 | protected ProtocolDecoderSink m_Sink = null; 48 | 49 | public void setTarget(ProtocolDecoderSink sink) { 50 | m_Sink = sink; 51 | } 52 | 53 | public ProtocolInfo getInfo() { 54 | return new ProtocolInfo("Pioneer", "Space Length", "Pioneer", 16, 5); 55 | } 56 | 57 | protected boolean pulseCompare(double candidate, double standard) { 58 | return Math.abs(standard - candidate) < standard * 0.4; 59 | } 60 | 61 | protected boolean pulseCompare(double candidate, double min, double max) { 62 | return ((candidate > min) && (candidate < max)); 63 | } 64 | 65 | protected void reportPartial() { 66 | if (m_BitCounter > 0) { 67 | m_Sink.partiallyParsedMessage("Pioneer", m_BitCounter); 68 | } 69 | } 70 | 71 | protected void addBit(int b) { 72 | if (m_BitCounter < 8) { 73 | m_Address >>= 1; 74 | m_Address |= (b << 7); 75 | } 76 | else if (m_BitCounter < 16) { 77 | m_AddressCheck >>= 1; 78 | m_AddressCheck |= (b << 7); 79 | } 80 | else if (m_BitCounter < 24) { 81 | m_Command >>= 1; 82 | m_Command |= (b << 7); 83 | } 84 | else if (m_BitCounter < 32) { 85 | m_CommandCheck >>= 1; 86 | m_CommandCheck |= (b << 7); 87 | } 88 | // Check if this is a complete message 89 | if (m_BitCounter == 31){ 90 | // It is, verify checksum 91 | if ((m_Address != (m_AddressCheck ^ 0xFF)) || (m_Command != (m_CommandCheck ^ 0xFF))) { 92 | // Checksum error 93 | reportPartial(); 94 | m_State = IDLE; 95 | return; 96 | } 97 | ProtocolMessage message = new ProtocolMessage("Pioneer", m_Command, m_Address, 2); 98 | message.setRawMessageByteAt(0, m_Command); 99 | message.setRawMessageByteAt(1, m_Address); 100 | // It is, check if this really is a repeat 101 | if ((m_RepeatCount > 0) && (m_Command == m_LastCommand) && (m_Address == m_LastAddress)) { 102 | message.setRepeat(m_RepeatCount); 103 | } 104 | else { 105 | // It is not a repeat, reset counter 106 | m_RepeatCount = 0; 107 | } 108 | message.addField(new FieldValue("Command", m_Command)); 109 | message.addField(new FieldValue("Address", m_Address)); 110 | // Report the parsed message 111 | m_Sink.parsedMessage(message); 112 | m_State = TRAILING_BIT; 113 | } 114 | m_BitCounter++; 115 | } 116 | 117 | /* (non-Javadoc) 118 | * @see ssg.ir.IRDecoder#parse(java.lang.Double) 119 | */ 120 | public int parse(double pulse, boolean state) { 121 | switch (m_State) { 122 | case IDLE: { 123 | if (pulseCompare(pulse, 8400.0 + 60) && state) { 124 | m_State = READING_HEADER; 125 | m_Command = 0; 126 | m_Address = 0; 127 | m_CommandCheck = 0; 128 | m_AddressCheck = 0; 129 | m_BitCounter = 0; 130 | } 131 | break; 132 | } 133 | case READING_HEADER: { 134 | if (pulseCompare(pulse, 4200.0 - 60)) { 135 | m_State = READING_BIT_MARK; 136 | } 137 | else { 138 | m_State = IDLE; 139 | reportPartial(); 140 | } 141 | break; 142 | } 143 | case READING_BIT_MARK: { 144 | // The mark pulse seems to vary a lot in length 145 | if (pulseCompare(pulse, 50, 700)) { 146 | m_State = READING_BIT_SPACE; 147 | } 148 | else { 149 | m_State = IDLE; 150 | reportPartial(); 151 | } 152 | break; 153 | } 154 | case READING_BIT_SPACE: { 155 | if (pulseCompare(pulse, 1575.0 - 60)) { 156 | m_State = READING_BIT_MARK; 157 | addBit(1); 158 | } 159 | else if (pulseCompare(pulse, 524.0 - 60)) { 160 | m_State = READING_BIT_MARK; 161 | addBit(0); 162 | } 163 | else { 164 | m_State = IDLE; 165 | reportPartial(); 166 | } 167 | break; 168 | } 169 | 170 | case TRAILING_BIT: { 171 | // The mark pulse seems to vary a lot in length 172 | if (pulseCompare(pulse, 100, 700)) { 173 | m_State = REPEAT_SCAN; 174 | } 175 | else { 176 | m_State = IDLE; 177 | } 178 | break; 179 | } 180 | case REPEAT_SCAN: { 181 | if (pulseCompare(pulse, 24000.0, 28000.0)) { 182 | m_RepeatCount += 1; // Start repeat sequence 183 | // Save this sequence 184 | m_LastCommand = m_Command; 185 | m_LastAddress = m_Address; 186 | m_Command = 0; 187 | m_Address = 0; 188 | m_BitCounter = 0; 189 | m_State = READING_BIT_MARK; 190 | } 191 | else { 192 | m_RepeatCount = 0; 193 | m_State = IDLE; 194 | } 195 | break; 196 | } 197 | } 198 | return m_State; 199 | } 200 | } 201 | 202 | -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/decoders/PrologueDecoder.java: -------------------------------------------------------------------------------- 1 | package nu.nethome.coders.decoders; 2 | 3 | import nu.nethome.util.ps.*; 4 | import nu.nethome.util.ps.BitString.Field; 5 | 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | /** 10 | * The PrologueDecoder parses a set of pulse lengths and decodes a protocol used 11 | * by Prologue-thermometers which is transmitted over 433MHz AM-modulated RF-signal. 12 | * The reception of the pulses may for example be made via the AudioProtocolSampler. 13 | * The NexaDecoder implements the ProtocolDecoder-interface and accepts the pulses 14 | * one by one. It contains a state machine, and when a complete message is decoded, 15 | * this is reported over the ProtocolDecoderSink-interface which is given at 16 | * construction. 17 | * 18 | * The protocol is space length encoded and sent with MSB first. 19 | * the protocol messages has the following layout:
20 | * 21 | * h = Humidity 22 | * t = Temperature * 10 23 | * c = Channel 0 - 2 24 | * u = button 25 | * b = Battery (1 = low) 26 | * r = rolling id 27 | * i = id 28 | *
29 | * _Nyb 4_ ____Byte 3_____ ____Byte 2_____ ____Byte 1_____ ____Byte 0_____ _S_
30 | * 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 0
31 | * i i i i r r r r r r r r b u c c t t t t t t t t t t t t h h h h h h h h x
32 | * 33 | * @author Stefan 34 | * 35 | */ 36 | public class PrologueDecoder implements ProtocolDecoder { 37 | 38 | protected static final int IDLE = 0; 39 | protected static final int READING_MARK = 5; 40 | protected static final int READING_SPACE = 6; 41 | protected static final int REPEAT_SCAN = 10; 42 | protected static final int PROLOGUE_BIT_LENGTH = 36 + 1; 43 | private static final String PROTOCOL_NAME = "Prologue"; 44 | public static final ProtocolInfo PROLOGUE_PROTOCOL_INFO = new ProtocolInfo(PROTOCOL_NAME, "Space Length", PROTOCOL_NAME, PROLOGUE_BIT_LENGTH, 1); 45 | 46 | public static final PulseLength PREAMBLE_SPACE = 47 | new PulseLength(PrologueDecoder.class, "PREAMBLE_SPACE", 8770, 7000, 10000); 48 | public static final PulseLength LONG_SPACE = 49 | new PulseLength(PrologueDecoder.class, "LONG_SPACE", 3880, 3000, 5000); 50 | public static final PulseLength SHORT_SPACE = 51 | new PulseLength(PrologueDecoder.class, "SHORT_SPACE", 1930, 1000, 2999); 52 | public static final PulseLength MARK = 53 | new PulseLength(PrologueDecoder.class, "MARK", 500, 300, 700); 54 | 55 | protected ProtocolDecoderSink m_Sink = null; 56 | BitString data = new BitString(); 57 | BitString lastParsedData = new BitString(); 58 | protected int state = IDLE; 59 | private int repeat = 0; 60 | private Map fields = new HashMap(); 61 | 62 | public PrologueDecoder() { 63 | fields.put("Humidity", new Field(0, 8)); 64 | fields.put("Temp", new Field(8, 12)); 65 | fields.put("Channel", new Field(20, 2)); 66 | fields.put("Button", new Field(22, 1)); 67 | fields.put("Battery", new Field(23, 1)); 68 | fields.put("RollingId", new Field(24, 8)); 69 | fields.put("Id", new Field(32, 4)); 70 | } 71 | 72 | public void setTarget(ProtocolDecoderSink sink) { 73 | m_Sink = sink; 74 | } 75 | 76 | public ProtocolInfo getInfo() { 77 | return PROLOGUE_PROTOCOL_INFO; 78 | } 79 | 80 | protected void addBit(boolean b) { 81 | data.addLsb(b); 82 | if (data.length() == PROLOGUE_BIT_LENGTH) { 83 | decodeMessage(data); 84 | } 85 | } 86 | 87 | public void decodeMessage(BitString binaryMessage) { 88 | binaryMessage.shiftRight(1); // last bit is ignored - parity? 89 | // Assure we get same data twice in a row as simple error detection strategy 90 | if (this.data.equals(lastParsedData)) { 91 | ProtocolMessage message = new ProtocolMessage(PROTOCOL_NAME, binaryMessage.extractInt(fields.get("Temp")), binaryMessage.extractInt(fields.get("Channel")), binaryMessage.toByteInts()); 92 | for (String field : fields.keySet()) { 93 | message.addField(new FieldValue(field, binaryMessage.extractInt(fields.get(field)))); 94 | } 95 | message.setRepeat(repeat - 1); 96 | m_Sink.parsedMessage(message); 97 | } 98 | lastParsedData.setValue(binaryMessage); 99 | state = REPEAT_SCAN; 100 | } 101 | 102 | public int parse(double pulse, boolean bitstate) { 103 | switch (state) { 104 | case IDLE: { 105 | if (PREAMBLE_SPACE.matches(pulse) && !bitstate) { 106 | data.clear(); 107 | repeat = 0; 108 | state = READING_MARK; 109 | } 110 | break; 111 | } 112 | case READING_MARK: { 113 | if (MARK.matches(pulse)) { 114 | state = READING_SPACE; 115 | } else { 116 | quitParsing(pulse); 117 | } 118 | break; 119 | } 120 | case READING_SPACE: { 121 | if (SHORT_SPACE.matches(pulse)) { 122 | state = READING_MARK; 123 | addBit(false); 124 | } else if (LONG_SPACE.matches(pulse)) { 125 | state = READING_MARK; 126 | addBit(true); 127 | } else { 128 | quitParsing(pulse); 129 | } 130 | break; 131 | } 132 | case REPEAT_SCAN: { 133 | if (MARK.matches(pulse) && bitstate) { 134 | // Ok read mark 135 | } else if (PREAMBLE_SPACE.matches(pulse) && !bitstate) { 136 | data.clear(); 137 | repeat++; 138 | state = READING_MARK; 139 | } else { 140 | state = IDLE; 141 | } 142 | break; 143 | } 144 | } 145 | return state; 146 | } 147 | 148 | private void quitParsing(double pulseLength) { 149 | if (data.length() > 5) { 150 | m_Sink.partiallyParsedMessage(String.format("Prologue Pulse: %g ms, State: %d", pulseLength, state), data.length()); 151 | } 152 | state = IDLE; 153 | lastParsedData.clear(); 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/decoders/ProntoDecoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2013, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.decoders; 21 | 22 | import nu.nethome.util.plugin.Plugin; 23 | import nu.nethome.util.ps.*; 24 | 25 | import java.util.LinkedList; 26 | 27 | 28 | /** 29 | * The PRONTO-format is named after a manufacturer of generic remote controls. It is a format 30 | * for describing raw IR-protocol messages. This decoder does not really decode the signal, 31 | * it formats the raw sampled pulses in the pronto-format. 32 | * 33 | * @author Stefan Str�mberg 34 | */ 35 | @Plugin 36 | public class ProntoDecoder implements ProtocolDecoder { 37 | protected static final int IDLE = 0; 38 | protected static final int SAMPLING = 1; 39 | private static final int MIN_MESSAGELENGTH = 10; 40 | 41 | protected int m_State = IDLE; 42 | 43 | /** Modulation frequency set to use when calculating the burst length numbers */ 44 | protected double m_Freq = 0; 45 | 46 | /** 47 | * Modulation frequency actually used when calculating the burst length numbers 48 | * Because of rounding this is not exactly same as the set frequency 49 | */ 50 | protected double m_UsedFreq = 0; 51 | 52 | 53 | /** Constant for the pronto remote's internal clock frequency */ 54 | protected double m_ProntoFreqConstant = .241246; 55 | 56 | /** Minimum time (in uS) to regard as space between protocol messages */ 57 | protected int m_LeadOutMinTime = 9000; 58 | 59 | /** Amount of time (in uS) that has to be added to bursts to compensate for slow 60 | * reaction in the receivers 61 | */ 62 | protected double m_PulseWidthModification = 0; 63 | 64 | protected ProtocolDecoderSink m_Sink = null; 65 | 66 | LinkedList m_Bursts = new LinkedList(); 67 | 68 | public void setTarget(ProtocolDecoderSink sink) { 69 | m_Sink = sink; 70 | } 71 | 72 | public ProntoDecoder() { 73 | this.setModulationFrequency(40000); 74 | } 75 | 76 | public ProtocolInfo getInfo() { 77 | return new ProtocolInfo("Pronto", "None", "Pronto", 0, 5); 78 | } 79 | 80 | public void addBurst(double burstUs, boolean state) { 81 | // Adjust for imperfections in receiver 82 | burstUs = state ? burstUs - m_PulseWidthModification : 83 | burstUs + m_PulseWidthModification; 84 | 85 | int prontoBurst = (int)(0.5 + (burstUs * m_UsedFreq) / 1000000.0); 86 | 87 | // Trim if burst is VERY long 88 | if (prontoBurst > 0xFFFF) prontoBurst = 0xFFFF; 89 | 90 | // Add burst to burst pairs 91 | m_Bursts.add(prontoBurst); 92 | 93 | // Check if this was the Lead Out burst pair 94 | if (burstUs > m_LeadOutMinTime) { 95 | // Ok, this is possibly the end of the sequence 96 | // Check how long it is 97 | if (m_Bursts.size() < MIN_MESSAGELENGTH) { 98 | // This was to short to be a real message, it is probably noise - ignore it 99 | m_Bursts.clear(); 100 | m_State = IDLE; 101 | return; 102 | } 103 | if ((m_Bursts.size() & 1) == 1) { 104 | // Something is wrong, there should be an even number of bursts to form 105 | // burst pairs. Add a dummy burst to be able to go on. 106 | m_Bursts.add(prontoBurst); 107 | } 108 | // Add leading 0 to signal this is a sampled signal 109 | String prontoMessage = "0000"; 110 | // Add the burst frequency 111 | // No rounding here, Pronto takes pure integer part 112 | Integer prontoFreq = (int)(1000000.0 /(m_Freq * m_ProntoFreqConstant)); 113 | prontoMessage += String.format(" %04x", prontoFreq); 114 | // Add zero to signal that we have no one time bursts 115 | prontoMessage += " 0000"; 116 | // Add number of burst pairs in signal 117 | prontoMessage += String.format(" %04x", m_Bursts.size() / 2); 118 | // Add the burst pairs 119 | for (int burst : m_Bursts) { 120 | prontoMessage += String.format(" %04x", burst); 121 | } 122 | // Create a report of the message 123 | ProtocolMessage message = new ProtocolMessage("Pronto", 0, m_Bursts.size(), 1); 124 | message.setRawMessageByteAt(0, m_Bursts.size()); 125 | message.addField(new FieldValue("Message", prontoMessage)); 126 | // Report the parsed message 127 | m_Sink.parsedMessage(message); 128 | m_Bursts.clear(); 129 | m_State = IDLE; 130 | } 131 | } 132 | 133 | /* (non-Javadoc) 134 | * @see ssg.ir.IRDecoder#parse(java.lang.Double) 135 | */ 136 | public int parse(double pulse, boolean state) { 137 | switch (m_State) { 138 | case IDLE: { 139 | if ((pulse < m_LeadOutMinTime) && (pulse > 0)) { 140 | m_State = SAMPLING; 141 | addBurst(pulse, state); 142 | } 143 | } 144 | break; 145 | 146 | case SAMPLING: { 147 | addBurst(pulse, state); 148 | } 149 | break; 150 | } 151 | return m_State; 152 | } 153 | 154 | public double getModulationFrequency() { 155 | return m_Freq; 156 | } 157 | 158 | public void setModulationFrequency(double freq) { 159 | m_Freq = freq; 160 | Integer prontoFreq = (int)(1000000.0 /(m_Freq * m_ProntoFreqConstant)); 161 | m_UsedFreq = 1000000.0 /(prontoFreq * m_ProntoFreqConstant); 162 | } 163 | 164 | public int getLeadOutTime() { 165 | return m_LeadOutMinTime; 166 | } 167 | 168 | public void setLeadOutTime(int leadOutMinTime) { 169 | m_LeadOutMinTime = leadOutMinTime; 170 | } 171 | 172 | public double getPulseWidthModification() { 173 | return m_PulseWidthModification; 174 | } 175 | 176 | public void setPulseWidthModification(double pulseWidthModification) { 177 | m_PulseWidthModification = pulseWidthModification; 178 | } 179 | } 180 | 181 | -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/decoders/RC5Decoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2013, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.decoders; 21 | 22 | import nu.nethome.util.plugin.Plugin; 23 | import nu.nethome.util.ps.*; 24 | 25 | 26 | @Plugin 27 | public class RC5Decoder implements ProtocolDecoder { 28 | protected static final int IDLE = 0; 29 | protected static final int HI_IN = 2; 30 | protected static final int HI_BETWEEN = 3; 31 | protected static final int LO_IN = 4; 32 | protected static final int LO_BETWEEN = 5; 33 | 34 | protected static final int RC5SHORT = 889; 35 | protected static final int RC5LONG = 1778; 36 | protected static final int RC5REPEAT = 85000; 37 | 38 | protected int m_State = IDLE; 39 | 40 | protected int m_Header = 0; 41 | protected int m_Command = 0; 42 | protected int m_Address = 0; 43 | 44 | protected int m_LastHeader = 0; 45 | protected int m_LastCommand = 0; 46 | protected int m_LastAddress = 0; 47 | 48 | protected int m_BitCounter = 0; 49 | protected int m_RepeatCount = 0; 50 | protected double m_LastValue = 0; 51 | protected ProtocolDecoderSink m_Sink = null; 52 | 53 | public void setTarget(ProtocolDecoderSink sink) { 54 | m_Sink = sink; 55 | } 56 | 57 | public ProtocolInfo getInfo() { 58 | return new ProtocolInfo("RC5", "Manchester", "Philips", 14, 5); 59 | } 60 | 61 | protected boolean pulseCompare(double candidate, double standard) { 62 | return Math.abs(standard - candidate) < standard * 0.2; 63 | } 64 | 65 | protected void addBit(int b) { 66 | if (m_BitCounter < 3) { 67 | m_Header = (m_Header << 1) + b ; 68 | } 69 | else if (m_BitCounter < 8) { 70 | m_Address = (m_Address << 1) + b ; 71 | } 72 | else if (m_BitCounter < 14) { 73 | m_Command = (m_Command << 1) + b ; 74 | } 75 | // Check if this is a complete message 76 | if (m_BitCounter == 13){ 77 | // It is, create the message 78 | ProtocolMessage message = new ProtocolMessage("RC5", m_Command, m_Address, 3); 79 | message.setRawMessageByteAt(2, m_Command); 80 | message.setRawMessageByteAt(1, m_Address); 81 | message.setRawMessageByteAt(0, m_Header); 82 | 83 | message.addField(new FieldValue("Header", m_Header)); 84 | message.addField(new FieldValue("Address", m_Address)); 85 | message.addField(new FieldValue("Command", m_Command)); 86 | 87 | // Check if this is a repeat 88 | if ((m_Command == m_LastCommand) && (m_Address == m_LastAddress) 89 | && (m_Header == m_LastHeader)) { 90 | m_RepeatCount++; 91 | message.setRepeat(m_RepeatCount); 92 | } 93 | else { 94 | // It is not a repeat, reset counter 95 | m_RepeatCount = 0; 96 | } 97 | // Report the parsed message 98 | m_Sink.parsedMessage(message); 99 | // Reset state 100 | m_State = IDLE; 101 | // Save message for repeat check 102 | m_LastCommand = m_Command; 103 | m_LastAddress = m_Address; 104 | m_LastHeader = m_Header; 105 | } 106 | m_BitCounter++; 107 | } 108 | 109 | 110 | /* (non-Javadoc) 111 | * @see ssg.ir.IRDecoder#parse(java.lang.Double) 112 | */ 113 | public int parse(double pulse, boolean state) { 114 | switch (m_State) { 115 | case IDLE: { 116 | if (pulseCompare(pulse, RC5SHORT) && state && (m_LastValue > 5000)) { 117 | m_Header = 0; 118 | m_Command = 0; 119 | m_Address = 0; 120 | m_BitCounter = 0; 121 | m_State = HI_BETWEEN; 122 | addBit(1); 123 | } 124 | else if (pulseCompare(pulse, RC5LONG) && state && (m_LastValue > 5000)) { 125 | m_Header = 0; 126 | m_Command = 0; 127 | m_Address = 0; 128 | m_BitCounter = 0; 129 | m_State = HI_IN; 130 | addBit(1); 131 | addBit(0); 132 | } 133 | if (pulseCompare(m_LastValue, RC5REPEAT) && (m_State != IDLE)) { 134 | m_RepeatCount++; 135 | } 136 | break; 137 | } 138 | case HI_IN: { 139 | if (pulseCompare(pulse, RC5SHORT)) { 140 | m_State = LO_BETWEEN; 141 | } else if (pulseCompare(pulse, RC5LONG)) { 142 | m_State = LO_IN; 143 | addBit(1); 144 | } else { 145 | m_State = IDLE; 146 | } 147 | break; 148 | } 149 | case HI_BETWEEN: { 150 | if (pulseCompare(pulse, RC5SHORT)) { 151 | m_State = LO_IN; 152 | addBit(1); 153 | } else { 154 | m_State = IDLE; 155 | } 156 | break; 157 | } 158 | case LO_IN: { 159 | if (pulseCompare(pulse, RC5SHORT)) { 160 | m_State = HI_BETWEEN; 161 | break; 162 | } else if (pulseCompare(pulse, RC5LONG)) { 163 | m_State = HI_IN; 164 | addBit(0); 165 | } else { 166 | m_State = IDLE; 167 | } 168 | break; 169 | } 170 | case LO_BETWEEN: { 171 | if (pulseCompare(pulse, RC5SHORT)) { 172 | m_State = HI_IN; 173 | addBit(0); 174 | } else { 175 | m_State = IDLE; 176 | } 177 | break; 178 | } 179 | } 180 | m_LastValue = pulse; 181 | return m_State; 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/decoders/RC6Decoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2013, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.decoders; 21 | 22 | import nu.nethome.util.plugin.Plugin; 23 | import nu.nethome.util.ps.*; 24 | 25 | @Plugin 26 | public class RC6Decoder implements ProtocolDecoder { 27 | protected static final int IDLE = 0; 28 | protected static final int READING_HEADER = 1; 29 | protected static final int HI_IN = 2; 30 | protected static final int HI_BETWEEN = 3; 31 | protected static final int LO_IN = 4; 32 | protected static final int LO_BETWEEN = 5; 33 | 34 | protected static final int RC6SHORT = 444; 35 | protected static final int RC6LONG = 889; 36 | 37 | protected int m_State = IDLE; 38 | 39 | protected int m_Header = 0; 40 | protected int m_Command = 0; 41 | protected int m_Address = 0; 42 | protected int m_Extra = 0; 43 | 44 | protected int m_LastCommand = 0; 45 | protected int m_LastAddress = 0; 46 | protected int m_LastExtra = 0; 47 | 48 | protected int m_BitCounter = 0; 49 | protected int m_RepeatCount = 0; 50 | protected double m_LastValue = 0; 51 | protected ProtocolDecoderSink m_Sink = null; 52 | 53 | public void setTarget(ProtocolDecoderSink sink) { 54 | m_Sink = sink; 55 | } 56 | 57 | public ProtocolInfo getInfo() { 58 | return new ProtocolInfo("RC6", "Manchester", "Philips", 20, 5); 59 | } 60 | 61 | protected boolean pulseCompare(double candidate, double standard) { 62 | return Math.abs(standard - candidate) < standard * 0.2; 63 | } 64 | 65 | protected void addBit(int b) { 66 | if (m_BitCounter < 4) { 67 | m_Header = (m_Header << 1) + b ; 68 | } 69 | else if (m_BitCounter == 4){ 70 | m_Extra = b; 71 | } 72 | else if (m_BitCounter < 13) { 73 | m_Address = (m_Address << 1) + b ; 74 | } 75 | else if (m_BitCounter < 21) { 76 | m_Command = (m_Command << 1) + b ; 77 | } 78 | // Check if this is a complete message 79 | if (m_BitCounter == 20){ 80 | // It is, create the message 81 | ProtocolMessage message = new ProtocolMessage("RC6", m_Command, m_Address, 3); 82 | message.setRawMessageByteAt(0, m_Command); 83 | message.setRawMessageByteAt(1, m_Address); 84 | message.setRawMessageByteAt(2, m_Extra); 85 | 86 | message.addField(new FieldValue("Header", m_Header)); 87 | message.addField(new FieldValue("Flip", m_Extra)); 88 | message.addField(new FieldValue("Address", m_Address)); 89 | message.addField(new FieldValue("Command", m_Command)); 90 | 91 | // Check if this is a repeat 92 | if ((m_RepeatCount > 0) && (m_Command == m_LastCommand) && (m_Address == m_LastAddress) 93 | && (m_Extra == m_LastExtra)) { 94 | message.setRepeat(m_RepeatCount); 95 | } 96 | else { 97 | // It is not a repeat, reset counter 98 | m_RepeatCount = 0; 99 | } 100 | // Report the parsed message 101 | m_Sink.parsedMessage(message); 102 | // Reset state 103 | m_State = IDLE; 104 | // Save message for repeat check 105 | m_LastCommand = m_Command; 106 | m_LastAddress = m_Address; 107 | m_LastExtra = m_Extra; 108 | } 109 | m_BitCounter++; 110 | } 111 | 112 | /** 113 | * Corrects for the fact that the trailer bit is double as long as the other bits. We handle this 114 | * by adjusting the received puls lengths when we get to the trailer bit. 115 | * @param pulse The measured pulse 116 | * @param bitCounter Which bit we are currently processing 117 | * @return The adjusted pulse length 118 | */ 119 | protected double trailerBitAdjust(double pulse, int bitCounter) { 120 | if ((bitCounter == 4) && ((m_State == HI_IN) || (m_State == LO_IN)) && pulseCompare(pulse, 1333)) { 121 | return RC6LONG; 122 | } 123 | else if ((bitCounter == 4) && ((m_State == HI_BETWEEN) || (m_State == LO_BETWEEN))) { 124 | return pulse / 2.0; 125 | } 126 | else if ((bitCounter == 5) && ((m_State == HI_IN) || (m_State == LO_IN))) { 127 | if (pulseCompare(pulse, 889)) { 128 | return RC6SHORT; 129 | } 130 | else if (pulseCompare(pulse, 1333)) { 131 | return RC6LONG; 132 | } 133 | } 134 | return pulse; 135 | } 136 | 137 | 138 | /* (non-Javadoc) 139 | * @see ssg.ir.IRDecoder#parse(java.lang.Double) 140 | */ 141 | public int parse(double pulse, boolean state) { 142 | pulse = trailerBitAdjust(pulse, m_BitCounter); 143 | switch (m_State) { 144 | case IDLE: { 145 | if (pulseCompare(pulse, 2666.0) && state) { 146 | m_State = READING_HEADER; 147 | m_Header = 0; 148 | m_Command = 0; 149 | m_Address = 0; 150 | m_Extra = 0; 151 | m_BitCounter = 0; 152 | 153 | if (pulseCompare(m_LastValue, 85000.0)) { 154 | m_RepeatCount++; 155 | } 156 | else { 157 | m_RepeatCount = 0; 158 | } 159 | break; 160 | } 161 | } 162 | case READING_HEADER: { 163 | if (pulseCompare(pulse, 889.0)) { 164 | m_State = LO_BETWEEN; 165 | } 166 | else { 167 | m_State = IDLE; 168 | } 169 | break; 170 | } 171 | case HI_IN: { 172 | if (pulseCompare(pulse, RC6SHORT)) { 173 | m_State = LO_BETWEEN; 174 | } else if (pulseCompare(pulse, RC6LONG)) { 175 | m_State = LO_IN; 176 | addBit(0); 177 | } else { 178 | m_State = IDLE; 179 | } 180 | break; 181 | } 182 | case HI_BETWEEN: { 183 | if (pulseCompare(pulse, RC6SHORT)) { 184 | m_State = LO_IN; 185 | addBit(0); 186 | } else { 187 | m_State = IDLE; 188 | } 189 | break; 190 | } 191 | case LO_IN: { 192 | if (pulseCompare(pulse, RC6SHORT)) { 193 | m_State = HI_BETWEEN; 194 | break; 195 | } else if (pulseCompare(pulse, RC6LONG)) { 196 | m_State = HI_IN; 197 | addBit(1); 198 | } else { 199 | m_State = IDLE; 200 | } 201 | break; 202 | } 203 | case LO_BETWEEN: { 204 | if (pulseCompare(pulse, RC6SHORT)) { 205 | m_State = HI_IN; 206 | addBit(1); 207 | } else { 208 | m_State = IDLE; 209 | } 210 | break; 211 | } 212 | } 213 | m_LastValue = pulse; 214 | return m_State; 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/decoders/RisingSunDecoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2013, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.decoders; 21 | 22 | import nu.nethome.util.plugin.Plugin; 23 | import nu.nethome.util.ps.FieldValue; 24 | import nu.nethome.util.ps.ProtocolMessage; 25 | import nu.nethome.util.ps.PulseLength; 26 | 27 | /** 28 | * The RisingSunDecoder parses a set of pulse lengths and decodes a protocol used 29 | * by UPM-thermometers which is transmitted over 433MHz AM-modulated RF-signal. 30 | * The reception of the pulses may for example be made via the AudioProtocolSampler. 31 | * The RisingSunDecoder implements the ProtocolDecoder-interface and accepts the pulses 32 | * one by one. It contains a state machine, and when a complete message is decoded, 33 | * this is reported over the ProtocolDecoderSink-interface which is given at 34 | * construction. 35 | * 36 | * The protocol is mark length encoded and the protocol messages has the following 37 | * layout:
38 | * 39 | * s = Start bit = 0
40 | * a = Channel 1 not selected
41 | * b = Channel 2 not selected
42 | * c = Channel 3 not selected
43 | * d = Channel 4 not selected
44 | * e = Button 1 not pressed
45 | * f = Button 2 not pressed
46 | * g = Button 3 not pressed
47 | * h = Button 4 not pressed
48 | * o = On/Off-bit
49 | *
50 | * ____Byte 2_____ ____Byte 1_____ ____Byte 0_____ _S_
51 | * 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 0
52 | * x o x x x x x x x h x g x f x e x d x c x b x a s
53 | * 54 | * This protocol is almost exactly the same as NEXA, so the entire implementation is reused. 55 | * 56 | * @author Stefan 57 | * 58 | */ 59 | 60 | @Plugin 61 | public class RisingSunDecoder extends NexaDecoder{ 62 | 63 | protected final static int buttonmapping[] = {10,11,12,13,14,15,16,4,18,19,10,3,22,2,1,0}; 64 | 65 | // This are the pulse length constants for the protocol. The default values may 66 | // be overridden by system properties 67 | public static final PulseLength RISING_SUN_LONG_MARK = 68 | new PulseLength(RisingSunDecoder.class,"RISING_SUN_LONG_MARK", 1300, 200); 69 | public static final PulseLength RISING_SUN_SHORT_MARK = 70 | new PulseLength(RisingSunDecoder.class,"RISING_SUN_SHORT_MARK", 450, 200); 71 | public static final PulseLength RISING_SUN_LONG_SPACE = 72 | new PulseLength(RisingSunDecoder.class,"RISING_SUN_LONG_SPACE", 1280, 200); 73 | public static final PulseLength RISING_SUN_SHORT_SPACE = 74 | new PulseLength(RisingSunDecoder.class,"RISING_SUN_SHORT_SPACE", 420, 150); 75 | public static final PulseLength RISING_SUN_REPEAT = 76 | new PulseLength(RisingSunDecoder.class,"RISING_SUN_REPEAT", 13400, 500); 77 | 78 | public void setup() { 79 | m_ProtocolName = "RisingSun"; 80 | LONG_MARK = RISING_SUN_LONG_MARK; 81 | SHORT_MARK = RISING_SUN_SHORT_MARK; 82 | LONG_SPACE = RISING_SUN_LONG_SPACE; 83 | SHORT_SPACE = RISING_SUN_SHORT_SPACE; 84 | REPEAT = RISING_SUN_REPEAT; 85 | } 86 | 87 | protected int bytemap(int raw) { 88 | return buttonmapping[(raw & 1) + ((raw >> 1) & 2) + ((raw >> 2) & 4) + ((raw >> 3) & 8)]; 89 | } 90 | 91 | protected void addBit(int b) { 92 | // Shift in data 93 | m_Data >>= 1; 94 | m_Data |= (b << 24); 95 | // Check if this is a complete message 96 | if (m_BitCounter == 24){ 97 | // It is, create the message 98 | int command = (m_Data >> 23) & 1; 99 | int button = bytemap((m_Data >> 9) & 0xFF); 100 | int address = bytemap((m_Data >> 1) & 0xFF); 101 | 102 | // Sender ends a message sequence by a signal saying "no button is pressed". 103 | // We ignore that message. 104 | if (button == 0) { 105 | m_State = IDLE; 106 | m_RepeatCount = 0; 107 | return; 108 | } 109 | 110 | ProtocolMessage message = new ProtocolMessage(m_ProtocolName, command, (button << 4) + address, 4); 111 | message.setRawMessageByteAt(3, m_Data & 0x1); 112 | message.setRawMessageByteAt(0, (m_Data >> 17) & 0xFF); 113 | message.setRawMessageByteAt(1, (m_Data >> 9) & 0xFF); 114 | message.setRawMessageByteAt(2, (m_Data >> 1) & 0xFF); 115 | 116 | message.addField(new FieldValue("Command", command)); 117 | message.addField(new FieldValue("Button", button)); 118 | message.addField(new FieldValue("Channel", address)); 119 | 120 | // It is, check if this really is a repeat 121 | if ((m_RepeatCount > 0) && (m_Data == m_LastData)) { 122 | message.setRepeat(m_RepeatCount); 123 | } 124 | else { 125 | // It is not a repeat, reset counter 126 | m_RepeatCount = 0; 127 | } 128 | // Report the parsed message 129 | m_Sink.parsedMessage(message); 130 | m_State = REPEAT_SCAN; 131 | } 132 | m_BitCounter++; 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/decoders/RollerTrolDecoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2015, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.decoders; 21 | 22 | import nu.nethome.coders.RollerTrol; 23 | import nu.nethome.util.plugin.Plugin; 24 | import nu.nethome.util.ps.*; 25 | 26 | import static nu.nethome.coders.RollerTrol.*; 27 | 28 | @Plugin 29 | public class RollerTrolDecoder implements ProtocolDecoder { 30 | 31 | protected static final int IDLE = 0; 32 | protected static final int READING_LONG_PREAMBLE_MARK = 1; 33 | protected static final int READING_LONG_PREAMBLE_SPACE = 2; 34 | protected static final int READING_SHORT_PREAMBLE_MARK = 3; 35 | protected static final int READING_SHORT_PREAMBLE_SPACE = 4; 36 | protected static final int READING_MARK = 5; 37 | protected static final int READING_SHORT_SPACE = 6; 38 | protected static final int READING_LONG_SPACE = 7; 39 | protected static final int REPEAT_SCAN = 10; 40 | /*This is the minimum repeat gap that Tellstick supports, so I accept this as a repeat gap too*/ 41 | public static final PulseLength TELLSTICK_MIN_REPEAT_GAP = 42 | new PulseLength(RollerTrolDecoder.class, "TELLSTICK_MIN_REPEAT_GAP", 1000, 800, 1200); 43 | 44 | public static final BitString.Field BYTE4 = new BitString.Field(32, 8); 45 | public static final BitString.Field BYTE3 = new BitString.Field(24, 8); 46 | public static final BitString.Field BYTE2 = new BitString.Field(16, 8); 47 | public static final BitString.Field BYTE1 = new BitString.Field(8, 8); 48 | public static final BitString.Field BYTE0 = new BitString.Field(0, 8); 49 | 50 | protected ProtocolDecoderSink m_Sink = null; 51 | BitString data = new BitString(); 52 | protected int state = IDLE; 53 | private int repeat; 54 | 55 | public void setTarget(ProtocolDecoderSink sink) { 56 | m_Sink = sink; 57 | } 58 | 59 | public ProtocolInfo getInfo() { 60 | return RollerTrol.ROLLERTROL_PROTOCOL_INFO; 61 | } 62 | 63 | protected void addBit(boolean b) { 64 | data.addMsb(b); 65 | if (data.length() == MESSAGE_BIT_LENGTH) { 66 | decodeMessage(data); 67 | } 68 | } 69 | 70 | public void decodeMessage(BitString binaryMessage) { 71 | int houseCode = binaryMessage.extractInt(HOUSE_CODE); 72 | int deviceCode = binaryMessage.extractInt(DEVICE_CODE); 73 | int command = binaryMessage.extractInt(COMMAND); 74 | int checkSum = binaryMessage.extractInt(CHECK_SUM); 75 | int calculatedCheckSum = calculateChecksum(binaryMessage); 76 | if (checkSum == calculatedCheckSum) { 77 | byte bytes[] = new byte[5]; 78 | bytes[0] = (byte) binaryMessage.extractInt(BYTE4); 79 | bytes[1] = (byte) binaryMessage.extractInt(BYTE3); 80 | bytes[2] = (byte) binaryMessage.extractInt(BYTE2); 81 | bytes[3] = (byte) binaryMessage.extractInt(BYTE1); 82 | bytes[4] = (byte) binaryMessage.extractInt(BYTE0); 83 | ProtocolMessage message = new ProtocolMessage(ROLLER_TROL_PROTOCOL_NAME, command, deviceCode, 5); 84 | message.setRawMessageByteAt(0, bytes[0]); 85 | message.setRawMessageByteAt(1, bytes[1]); 86 | message.setRawMessageByteAt(2, bytes[2]); 87 | message.setRawMessageByteAt(3, bytes[3]); 88 | message.setRawMessageByteAt(4, bytes[4]); 89 | 90 | message.addField(new FieldValue(HOUSE_CODE_NAME, houseCode)); 91 | message.addField(new FieldValue(DEVICE_CODE_NAME, deviceCode)); 92 | message.addField(new FieldValue(COMMAND_NAME, command)); 93 | message.setRepeat(repeat); 94 | m_Sink.parsedMessage(message); 95 | } 96 | state = REPEAT_SCAN; 97 | } 98 | 99 | public int parse(double pulse, boolean bitstate) { 100 | switch (state) { 101 | case IDLE: { 102 | if (RollerTrol.LONG_PREAMBLE_MARK.matches(pulse) && bitstate) { 103 | data.clear(); 104 | repeat = 0; 105 | state = READING_LONG_PREAMBLE_SPACE; 106 | } 107 | break; 108 | } 109 | case READING_LONG_PREAMBLE_SPACE: { 110 | if (RollerTrol.LONG_PREAMBLE_SPACE.matches(pulse)) { 111 | state = READING_SHORT_PREAMBLE_MARK; 112 | } else { 113 | quitParsing(pulse); 114 | } 115 | break; 116 | } 117 | case READING_SHORT_PREAMBLE_MARK: { 118 | if (RollerTrol.SHORT_PREAMBLE_MARK.matches(pulse)) { 119 | state = READING_SHORT_PREAMBLE_SPACE; 120 | } else { 121 | quitParsing(pulse); 122 | } 123 | break; 124 | } 125 | case READING_SHORT_PREAMBLE_SPACE: { 126 | if (RollerTrol.SHORT.matches(pulse)) { 127 | state = READING_MARK; 128 | } else { 129 | quitParsing(pulse); 130 | } 131 | break; 132 | } 133 | case READING_MARK: { 134 | if (RollerTrol.SHORT.matches(pulse)) { 135 | state = READING_LONG_SPACE; 136 | } else if (RollerTrol.LONG.matches(pulse)) { 137 | state = READING_SHORT_SPACE; 138 | } else { 139 | quitParsing(pulse); 140 | } 141 | break; 142 | } 143 | case READING_SHORT_SPACE: { 144 | if (RollerTrol.SHORT.matches(pulse)) { 145 | state = READING_MARK; 146 | addBit(true); 147 | } else { 148 | quitParsing(pulse); 149 | } 150 | break; 151 | } 152 | case READING_LONG_SPACE: { 153 | if (RollerTrol.LONG.matches(pulse)) { 154 | state = READING_MARK; 155 | addBit(false); 156 | } else { 157 | quitParsing(pulse); 158 | } 159 | break; 160 | } 161 | case REPEAT_SCAN: { 162 | if (RollerTrol.LONG_PREAMBLE_MARK.matches(pulse) && bitstate) { 163 | data.clear(); 164 | repeat++; 165 | state = READING_LONG_PREAMBLE_SPACE; 166 | } else if (!RollerTrol.LONG.matches(pulse) && 167 | !RollerTrol.SHORT.matches(pulse) && 168 | !TELLSTICK_MIN_REPEAT_GAP.matches(pulse)) { 169 | state = IDLE; 170 | } 171 | break; 172 | } 173 | 174 | } 175 | return state; 176 | } 177 | 178 | private void quitParsing(double pulseLength) { 179 | if (data.length() > 5) { 180 | m_Sink.partiallyParsedMessage(String.format("RollerTrol Pulse: %g ms, State: %d", pulseLength, state), data.length()); 181 | } 182 | state = IDLE; 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/decoders/RollerTrolGDecoder.java: -------------------------------------------------------------------------------- 1 | package nu.nethome.coders.decoders; 2 | 3 | import nu.nethome.coders.RollerTrol; 4 | import nu.nethome.coders.RollerTrolG; 5 | import nu.nethome.util.ps.*; 6 | 7 | /** 8 | * 9 | */ 10 | public class RollerTrolGDecoder implements ProtocolDecoder { 11 | 12 | protected static final int IDLE = 0; 13 | protected static final int READING_LONG_PREAMBLE_SPACE = 2; 14 | protected static final int READING_PREAMBLE_MARK = 3; 15 | protected static final int READING_MARK = 5; 16 | protected static final int READING_SHORT_SPACE = 6; 17 | protected static final int READING_LONG_SPACE = 7; 18 | protected static final int REPEAT_SCAN = 10; 19 | 20 | 21 | public static final BitString.Field BYTE4 = new BitString.Field(32, 8); 22 | public static final BitString.Field BYTE3 = new BitString.Field(24, 8); 23 | public static final BitString.Field BYTE2 = new BitString.Field(16, 8); 24 | public static final BitString.Field BYTE1 = new BitString.Field(8, 8); 25 | public static final BitString.Field BYTE0 = new BitString.Field(0, 8); 26 | 27 | 28 | protected ProtocolDecoderSink m_Sink = null; 29 | BitString data = new BitString(); 30 | protected int state = IDLE; 31 | private int repeat = 0; 32 | 33 | public void setTarget(ProtocolDecoderSink sink) { 34 | m_Sink = sink; 35 | } 36 | 37 | public ProtocolInfo getInfo() { 38 | return RollerTrolG.ROLLERTROL_PROTOCOL_INFO; 39 | } 40 | 41 | protected void addBit(boolean b) { 42 | data.addLsb(b); 43 | if (data.length() == RollerTrolG.PROTOCOL_BIT_LENGTH) { 44 | decodeMessage(data); 45 | } 46 | } 47 | 48 | public void decodeMessage(BitString binaryMessage) { 49 | int channel = binaryMessage.extractInt(RollerTrolG.CHANNEL); 50 | int address = binaryMessage.extractInt(RollerTrolG.ADDRESS); 51 | int command = binaryMessage.extractInt(RollerTrolG.COMMAND); 52 | int bytes[] = new int[5]; 53 | bytes[0] = binaryMessage.extractInt(BYTE4); 54 | bytes[1] = binaryMessage.extractInt(BYTE3); 55 | bytes[2] = binaryMessage.extractInt(BYTE2); 56 | bytes[3] = binaryMessage.extractInt(BYTE1); 57 | bytes[4] = binaryMessage.extractInt(BYTE0); 58 | ProtocolMessage message = new ProtocolMessage(RollerTrolG.ROLLER_TROL_G_PROTOCOL_NAME, command, channel, 5); 59 | message.setRawMessageByteAt(0, bytes[0]); 60 | message.setRawMessageByteAt(1, bytes[1]); 61 | message.setRawMessageByteAt(2, bytes[2]); 62 | message.setRawMessageByteAt(3, bytes[3]); 63 | message.setRawMessageByteAt(4, bytes[4]); 64 | 65 | message.addField(new FieldValue(RollerTrolG.COMMAND_NAME, command)); 66 | message.addField(new FieldValue(RollerTrolG.CHANNEL_NAME, channel)); 67 | message.addField(new FieldValue(RollerTrolG.ADDRESS_NAME, address)); 68 | message.setRepeat(repeat); 69 | m_Sink.parsedMessage(message); 70 | state = REPEAT_SCAN; 71 | } 72 | 73 | public int parse(double pulse, boolean bitstate) { 74 | switch (state) { 75 | case IDLE: { 76 | if (RollerTrolG.LONG_PREAMBLE_MARK.matches(pulse) && bitstate) { 77 | data.clear(); 78 | repeat = 0; 79 | state = READING_LONG_PREAMBLE_SPACE; 80 | } 81 | break; 82 | } 83 | case READING_LONG_PREAMBLE_SPACE: { 84 | if (RollerTrolG.LONG_PREAMBLE_SPACE.matches(pulse)) { 85 | state = READING_MARK; 86 | } else { 87 | quitParsing(pulse); 88 | } 89 | break; 90 | } 91 | case READING_MARK: { 92 | if (RollerTrolG.SHORT.matches(pulse)) { 93 | state = READING_LONG_SPACE; 94 | addBit(false); 95 | } else if (RollerTrolG.LONG.matches(pulse)) { 96 | state = READING_SHORT_SPACE; 97 | addBit(true); 98 | } else { 99 | quitParsing(pulse); 100 | } 101 | break; 102 | } 103 | case READING_SHORT_SPACE: { 104 | if (RollerTrolG.SHORT.matches(pulse)) { 105 | state = READING_MARK; 106 | } else { 107 | quitParsing(pulse); 108 | } 109 | break; 110 | } 111 | case READING_LONG_SPACE: { 112 | if (RollerTrolG.LONG.matches(pulse)) { 113 | state = READING_MARK; 114 | } else { 115 | quitParsing(pulse); 116 | } 117 | break; 118 | } 119 | case REPEAT_SCAN: { 120 | if (RollerTrolG.REPEAT_SPACE.matches(pulse)) { 121 | state = READING_PREAMBLE_MARK; 122 | } else { 123 | state = IDLE; 124 | } 125 | break; 126 | } 127 | case READING_PREAMBLE_MARK: { 128 | if (RollerTrolG.LONG_PREAMBLE_MARK.matches(pulse) && bitstate) { 129 | state = READING_LONG_PREAMBLE_SPACE; 130 | data.clear(); 131 | repeat++; 132 | } else { 133 | state = IDLE; 134 | } 135 | break; 136 | } 137 | } 138 | return state; 139 | } 140 | 141 | private void quitParsing(double pulseLength) { 142 | if (data.length() > 5) { 143 | m_Sink.partiallyParsedMessage(String.format("RollerTrol Pulse: %g ms, State: %d", pulseLength, state), data.length()); 144 | } 145 | state = IDLE; 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/decoders/SIRCDecoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2013, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.decoders; 21 | 22 | import nu.nethome.util.plugin.Plugin; 23 | import nu.nethome.util.ps.*; 24 | 25 | @Plugin 26 | public class SIRCDecoder implements ProtocolDecoder { 27 | protected static final int IDLE = 0; 28 | protected static final int READING_HEADER = 1; 29 | protected static final int READING_BIT_MARK = 2; 30 | protected static final int READING_BIT_SPACE = 3; 31 | protected static final int REPEAT_SCAN = 4; 32 | 33 | protected int m_State = IDLE; 34 | 35 | protected int m_Command = 0; 36 | protected int m_Address = 0; 37 | protected int m_Extra = 0; 38 | 39 | protected int m_LastCommand = 0; 40 | protected int m_LastAddress = 0; 41 | protected int m_LastExtra = 0; 42 | 43 | protected int m_BitCounter = 0; 44 | protected int m_RepeatCount = 0; 45 | protected ProtocolDecoderSink m_Sink = null; 46 | 47 | public void setTarget(ProtocolDecoderSink sink) { 48 | m_Sink = sink; 49 | } 50 | 51 | public ProtocolInfo getInfo() { 52 | return new ProtocolInfo("SIRC20", "Mark Length", "Sony", 20, 5); 53 | } 54 | 55 | protected boolean pulseCompare(double candidate, double standard) { 56 | return Math.abs(standard - candidate) < standard * 0.3; 57 | } 58 | 59 | protected void addBit(int b) { 60 | if (m_BitCounter < 7) { 61 | m_Command += b << m_BitCounter; 62 | } 63 | else if (m_BitCounter < 12) { 64 | m_Address += b << (m_BitCounter - 7); 65 | } 66 | else if (m_BitCounter < 20) { 67 | m_Extra += b << (m_BitCounter - 12); 68 | } 69 | // Check if this is a complete message 70 | if (m_BitCounter == 19){ 71 | // It is, create the message 72 | ProtocolMessage message = new ProtocolMessage("SIRC20", m_Command, m_Address, 3); 73 | message.setRawMessageByteAt(0, m_Command); 74 | message.setRawMessageByteAt(1, m_Address); 75 | message.setRawMessageByteAt(2, m_Extra); 76 | message.addField(new FieldValue("Command", m_Command)); 77 | message.addField(new FieldValue("Address", m_Address)); 78 | message.addField(new FieldValue("Extended", m_Extra)); 79 | 80 | // It is, check if this really is a repeat 81 | if ((m_RepeatCount > 0) && (m_Command == m_LastCommand) && (m_Address == m_LastAddress) 82 | && (m_Extra == m_LastExtra)) { 83 | message.setRepeat(m_RepeatCount); 84 | } 85 | else { 86 | // It is not a repeat, reset counter 87 | m_RepeatCount = 0; 88 | } 89 | // Report the parsed message 90 | m_Sink.parsedMessage(message); 91 | m_State = REPEAT_SCAN; 92 | } 93 | m_BitCounter++; 94 | } 95 | 96 | /* (non-Javadoc) 97 | * @see ssg.ir.IRDecoder#parse(java.lang.Double) 98 | */ 99 | public int parse(double pulse, boolean state) { 100 | switch (m_State) { 101 | case IDLE: { 102 | if (pulseCompare(pulse, 2400.0 + 60) && state) { 103 | m_State = READING_HEADER; 104 | m_Command = 0; 105 | m_Address = 0; 106 | m_Extra = 0; 107 | m_BitCounter = 0; 108 | } 109 | break; 110 | } 111 | case READING_HEADER: { 112 | if (pulseCompare(pulse, 600.0 - 60)) { 113 | m_State = READING_BIT_MARK; 114 | } 115 | else { 116 | m_State = IDLE; 117 | } 118 | break; 119 | } 120 | case READING_BIT_MARK: { 121 | if (pulseCompare(pulse, 1200.0 + 60)) { 122 | m_State = READING_BIT_SPACE; 123 | addBit(1); 124 | } 125 | else if (pulseCompare(pulse, 600.0 + 60)) { 126 | m_State = READING_BIT_SPACE; 127 | addBit(0); 128 | } 129 | else { 130 | m_State = IDLE; 131 | } 132 | break; 133 | } 134 | case READING_BIT_SPACE: { 135 | if (pulseCompare(pulse, 600.0 - 60)) { 136 | m_State = READING_BIT_MARK; 137 | } 138 | else { 139 | m_State = IDLE; 140 | } 141 | break; 142 | } 143 | case REPEAT_SCAN: { 144 | if (pulseCompare(pulse, 12000.0)) { 145 | m_RepeatCount += 1; // Start repeat sequence 146 | // Save this sequence 147 | m_LastCommand = m_Command; 148 | m_LastAddress = m_Address; 149 | m_LastExtra = m_Extra ; 150 | } 151 | else { 152 | m_RepeatCount = 0; 153 | } 154 | m_State = IDLE; 155 | break; 156 | } 157 | } 158 | return m_State; 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/decoders/ViasatDecoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2013, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.decoders; 21 | 22 | import nu.nethome.util.plugin.Plugin; 23 | import nu.nethome.util.ps.*; 24 | 25 | @Plugin 26 | public class ViasatDecoder implements ProtocolDecoder { 27 | protected static final int IDLE = 0; 28 | protected static final int READING_HEADER = 1; 29 | protected static final int READING_HEADER2 = 6; 30 | protected static final int HI_IN = 2; 31 | protected static final int HI_BETWEEN = 3; 32 | protected static final int LO_IN = 4; 33 | protected static final int LO_BETWEEN = 5; 34 | 35 | protected static final int VIA_SHORT = 320; 36 | protected static final int VIA_LONG = 720; 37 | 38 | protected int m_State = IDLE; 39 | 40 | protected int m_Byte1 = 0; 41 | protected int m_Byte2 = 0; 42 | protected int m_Byte3 = 0; 43 | protected int m_Byte4 = 0; 44 | protected int m_LastWord = 0; 45 | 46 | 47 | protected int m_LastCommand = 0; 48 | protected int m_LastAddress = 0; 49 | protected int m_LastExtra = 0; 50 | 51 | protected int m_BitCounter = 0; 52 | protected int m_RepeatCount = 0; 53 | protected double m_LastValue = 0; 54 | protected ProtocolDecoderSink m_Sink = null; 55 | 56 | public void setTarget(ProtocolDecoderSink sink) { 57 | m_Sink = sink; 58 | } 59 | 60 | public ProtocolInfo getInfo() { 61 | return new ProtocolInfo("Viasat", "Diff Manchester", "Viasat", 32, 5); 62 | } 63 | 64 | protected boolean pulseCompare(double candidate, double standard) { 65 | return Math.abs(standard - candidate) < standard * 0.3; 66 | } 67 | 68 | protected void addBit(int b) { 69 | if (m_BitCounter < 8) { 70 | m_Byte1 = (m_Byte1 << 1) + b ; 71 | } 72 | else if (m_BitCounter < 16){ 73 | m_Byte2 = (m_Byte2 << 1) + b ; 74 | } 75 | else if (m_BitCounter < 24) { 76 | m_Byte3 = (m_Byte3 << 1) + b ; 77 | } 78 | else if (m_BitCounter < 32) { 79 | m_Byte4 = (m_Byte4 << 1) + b ; 80 | } 81 | // Check if this is a complete message 82 | if (m_BitCounter == 31){ 83 | // It is, create the message 84 | ProtocolMessage message = new ProtocolMessage("Viasat", m_Byte3, m_Byte4, 4); 85 | message.setRawMessageByteAt(0, m_Byte1); 86 | message.setRawMessageByteAt(1, m_Byte2); 87 | message.setRawMessageByteAt(2, m_Byte3); 88 | message.setRawMessageByteAt(3, m_Byte4); 89 | 90 | message.addField(new FieldValue("Header", m_Byte1)); 91 | message.addField(new FieldValue("Flip", m_Byte2)); 92 | message.addField(new FieldValue("Command", m_Byte3)); 93 | message.addField(new FieldValue("Checksum?", m_Byte4)); 94 | 95 | // Check if it is a repeat 96 | int newWord = m_Byte4 << 24 + m_Byte4 << 16 + m_Byte4 << 8 + m_Byte4; 97 | if ((newWord == m_LastWord) && m_RepeatCount != 0) { 98 | message.setRepeat(m_RepeatCount); 99 | } 100 | else { 101 | m_RepeatCount = 0; 102 | } 103 | 104 | // Report the parsed message 105 | m_Sink.parsedMessage(message); 106 | // Reset state 107 | m_State = IDLE; 108 | // Save message for repeat check 109 | m_LastWord = newWord; 110 | } 111 | m_BitCounter++; 112 | } 113 | 114 | public void parseMan(double pulse, boolean state) { 115 | switch (m_State) { 116 | case IDLE: { 117 | if (pulseCompare(pulse, 2666.0) && state) { 118 | m_State = READING_HEADER; 119 | m_Byte1 = 0; 120 | m_Byte2 = 0; 121 | m_Byte3 = 0; 122 | m_Byte4 = 0; 123 | m_BitCounter = 0; 124 | 125 | if (pulseCompare(m_LastValue, 75000.0)) { 126 | m_RepeatCount++; 127 | } 128 | else { 129 | m_RepeatCount = 0; 130 | } 131 | } 132 | break; 133 | } 134 | case READING_HEADER: { 135 | if (pulseCompare(pulse, 1850.0)) { 136 | m_State = LO_IN; 137 | } 138 | else { 139 | invalidMessage("Viasat h"); 140 | } 141 | break; 142 | } 143 | case HI_IN: { 144 | if (pulseCompare(pulse, VIA_SHORT)) { 145 | m_State = LO_BETWEEN; 146 | } else if (pulseCompare(pulse, VIA_LONG)) { 147 | m_State = LO_IN; 148 | addBit(0); 149 | } else { 150 | invalidMessage("Viasat"); 151 | } 152 | break; 153 | } 154 | case HI_BETWEEN: { 155 | if (pulseCompare(pulse, VIA_SHORT)) { 156 | m_State = LO_IN; 157 | addBit(0); 158 | } else { 159 | invalidMessage("Viasat"); 160 | } 161 | break; 162 | } 163 | case LO_IN: { 164 | if (pulseCompare(pulse, VIA_SHORT)) { 165 | m_State = HI_BETWEEN; 166 | break; 167 | } else if (pulseCompare(pulse, VIA_LONG)) { 168 | m_State = HI_IN; 169 | addBit(1); 170 | } else { 171 | invalidMessage("Viasat"); 172 | } 173 | break; 174 | } 175 | case LO_BETWEEN: { 176 | if (pulseCompare(pulse, VIA_SHORT)) { 177 | m_State = HI_IN; 178 | addBit(1); 179 | } else { 180 | invalidMessage("Viasat"); 181 | } 182 | break; 183 | } 184 | } 185 | m_LastValue = pulse; 186 | } 187 | 188 | private void invalidMessage(String message) { 189 | if (m_BitCounter > 4) { 190 | m_Sink.partiallyParsedMessage(message, m_BitCounter); 191 | } 192 | m_State = IDLE; 193 | } 194 | 195 | 196 | /* (non-Javadoc) 197 | * @see ssg.ir.IRDecoder#parse(java.lang.Double) 198 | */ 199 | public int parse(double pulse, boolean state) { 200 | switch (m_State) { 201 | case IDLE: { 202 | if (pulseCompare(pulse, 2666.0) && state) { 203 | m_State = READING_HEADER; 204 | m_Byte1 = 0; 205 | m_Byte2 = 0; 206 | m_Byte3 = 0; 207 | m_Byte4 = 0; 208 | m_BitCounter = 0; 209 | 210 | if (pulseCompare(m_LastValue, 85000.0)) { 211 | m_RepeatCount++; 212 | } 213 | else { 214 | m_RepeatCount = 0; 215 | } 216 | } 217 | break; 218 | } 219 | case READING_HEADER: { 220 | if (pulseCompare(pulse, 1850.0)) { 221 | m_State = HI_BETWEEN; 222 | } 223 | else { 224 | invalidMessage("Viasat h1"); 225 | } 226 | break; 227 | } 228 | case READING_HEADER2: { 229 | if (pulseCompare(pulse, VIA_LONG)) { 230 | m_State = HI_BETWEEN; 231 | } 232 | else { 233 | invalidMessage("Viasat h2"); 234 | } 235 | break; 236 | } 237 | case HI_IN: { 238 | if (pulseCompare(pulse, VIA_SHORT)) { 239 | m_State = LO_BETWEEN; 240 | addBit(0); 241 | } else if (pulseCompare(pulse, VIA_LONG)) { 242 | m_State = LO_IN; 243 | addBit(1); 244 | } else { 245 | invalidMessage("Viasat"); 246 | } 247 | break; 248 | } 249 | case HI_BETWEEN: { 250 | if (pulseCompare(pulse, VIA_SHORT)) { 251 | m_State = LO_IN; 252 | } else if (pulseCompare(pulse, VIA_LONG)) { 253 | m_State = LO_BETWEEN; 254 | addBit(0); 255 | } else { 256 | invalidMessage("Viasat"); 257 | } 258 | break; 259 | } 260 | case LO_IN: { 261 | if (pulseCompare(pulse, VIA_SHORT)) { 262 | m_State = HI_BETWEEN; 263 | addBit(0); 264 | break; 265 | } else if (pulseCompare(pulse, VIA_LONG)) { 266 | m_State = HI_IN; 267 | addBit(1); 268 | } else { 269 | invalidMessage("Viasat"); 270 | } 271 | break; 272 | } 273 | case LO_BETWEEN: { 274 | if (pulseCompare(pulse, VIA_SHORT)) { 275 | m_State = HI_IN; 276 | } else if (pulseCompare(pulse, VIA_LONG)) { 277 | m_State = HI_BETWEEN; 278 | addBit(0); 279 | } else { 280 | invalidMessage("Viasat"); 281 | } 282 | break; 283 | } 284 | } 285 | m_LastValue = pulse; 286 | return m_State; 287 | } 288 | } 289 | 290 | -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/decoders/WavemanDecoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2013, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.decoders; 21 | 22 | import nu.nethome.util.plugin.Plugin; 23 | import nu.nethome.util.ps.ProtocolDecoder; 24 | 25 | /** 26 | * The WavemanDecoder parses a set of pulse lengths and decodes a protocol used 27 | * by UPM-thermometers which is transmitted over 433MHz AM-modulated RF-signal. 28 | * The reception of the pulses may for example be made via the AudioProtocolSampler. 29 | * The WavemanDecoder implements the ProtocolDecoder-interface and accepts the pulses 30 | * one by one. It contains a state machine, and when a complete message is decoded, 31 | * this is reported over the ProtocolDecoderSink-interface which is given at 32 | * construction. 33 | * 34 | * The protocol is mark length encoded and the protocol messages has the following 35 | * layout:
36 | * 37 | * s = Start bit = 0
38 | * b = Button number
39 | * a = Address
40 | * o = On/Off-bit
41 | *
42 | * ____Byte 2_____ ____Byte 1_____ ____Byte 0_____ _S_
43 | * 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 0
44 | * x o x o x o x x x b x b x b x b x a x a x a x a s
45 | * 46 | * This protocol is almost exactly the same as NEXA, so the entire implementation is reused. 47 | * The difference is that bit 2 and 4 of Byte 2 is always 1 in NEXA. 48 | * 49 | * @author Stefan 50 | * 51 | */ 52 | @Plugin 53 | public class WavemanDecoder extends NexaDecoder implements ProtocolDecoder{ 54 | 55 | public void setup() { 56 | m_ProtocolName = "Waveman"; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/decoders/ZhejiangDecoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2013, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.decoders; 21 | 22 | import nu.nethome.util.plugin.Plugin; 23 | import nu.nethome.util.ps.FieldValue; 24 | import nu.nethome.util.ps.ProtocolDecoder; 25 | import nu.nethome.util.ps.ProtocolMessage; 26 | import nu.nethome.util.ps.PulseLength; 27 | 28 | /** 29 | * The ZhejiangDecoder parses a set of pulse lengths and decodes a protocol used 30 | * by lamp remote controls which is transmitted over 433MHz AM-modulated RF-signal. 31 | * The reception of the pulses may for example be made via the AudioProtocolSampler. 32 | * The ZhejiangDecoder implements the ProtocolDecoder-interface and accepts the pulses 33 | * one by one. It contains a state machine, and when a complete message is decoded, 34 | * this is reported over the ProtocolDecoderSink-interface which is given at 35 | * construction. 36 | *
37 | * The protocol is mark length encoded and the protocol messages has the following 38 | * layout:
39 | *
40 | * s = Start bit = 0
41 | * a = Channel 1 not selected
42 | * b = Channel 2 not selected
43 | * c = Channel 3 not selected
44 | * d = Channel 4 not selected
45 | * e = Channel 5 not selected
46 | * f = Button A not pressed
47 | * g = Button B not pressed
48 | * h = Button C not pressed
49 | * i = Button D not pressed
50 | * j = Button E not pressed
51 | * o = On/Off-bit
52 | *
53 | *_S_ ____Byte 2_____ ____Byte 1_____ ____Byte 0_____
54 | * 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
55 | * x o 0 1 0 j 0 i 0 h 0 g 0 f 0 1 e 1 d 1 c 1 b 1 a
56 | *
57 | * This protocol is almost exactly the same as NEXA, so the entire implementation is reused. 58 | * 59 | * @author Stefan 60 | */ 61 | @Plugin 62 | public class ZhejiangDecoder extends NexaDecoder implements ProtocolDecoder{ 63 | 64 | // This are the pulse length constants for the protocol. The default values may 65 | // be overridden by system properties 66 | public static final PulseLength ZHEJ_LONG_MARK = 67 | new PulseLength(ZhejiangDecoder.class, "ZHEJ_LONG_MARK", 430, 370, 550); 68 | public static final PulseLength ZHEJ_SHORT_MARK = 69 | new PulseLength(ZhejiangDecoder.class, "ZHEJ_SHORT_MARK", 140, 100, 220); 70 | public static final PulseLength ZHEJ_LONG_SPACE = 71 | new PulseLength(ZhejiangDecoder.class, "ZHEJ_LONG_SPACE", 450, 370, 550); 72 | public static final PulseLength ZHEJ_SHORT_SPACE = 73 | new PulseLength(ZhejiangDecoder.class, "ZHEJ_SHORT_SPACE", 170, 100, 220); 74 | public static final PulseLength ZHEJ_REPEAT = 75 | new PulseLength(ZhejiangDecoder.class, "ZHEJ_REPEAT", 4560, 500); 76 | 77 | public void setup() { 78 | m_ProtocolName = "Zhejiang"; 79 | LONG_MARK = ZHEJ_LONG_MARK; 80 | SHORT_MARK = ZHEJ_SHORT_MARK; 81 | LONG_SPACE = ZHEJ_LONG_SPACE; 82 | SHORT_SPACE = ZHEJ_SHORT_SPACE; 83 | REPEAT = ZHEJ_REPEAT; 84 | } 85 | 86 | protected int bytemap(int raw) { 87 | return (raw & 1) + ((raw >> 1) & 2) + ((raw >> 2) & 4) + ((raw >> 3) & 8) + ((raw >> 4) & 0x10); 88 | } 89 | 90 | protected void addBit(int b) { 91 | // Shift in data 92 | m_Data >>= 1; 93 | m_Data |= (b << 24); 94 | // Check if this is a complete message 95 | if (m_BitCounter == 24) { 96 | // It is, create the message 97 | int command = ((m_Data >> 23) & 1) ^ 1; 98 | int rawButton = bytemap(((m_Data >> 11) ^ 0x3FF) & 0x3FF); 99 | int address = bytemap((m_Data ^ 0x3FF) & 0x3FF); 100 | int button = bitPosToInt(rawButton); 101 | 102 | // Sender ends a message sequence by a signal saying "no button is pressed". 103 | // We ignore that message. 104 | if (rawButton == 0) { 105 | m_State = IDLE; 106 | m_RepeatCount = 0; 107 | return; 108 | } 109 | 110 | ProtocolMessage message = new ProtocolMessage(m_ProtocolName, command, (rawButton << 8) + address, 4); 111 | message.setRawMessageByteAt(0, (m_Data >> 24) & 0x1); 112 | message.setRawMessageByteAt(1, (m_Data >> 16) & 0xFF); 113 | message.setRawMessageByteAt(2, (m_Data >> 8) & 0xFF); 114 | message.setRawMessageByteAt(3, (m_Data) & 0xFF); 115 | 116 | message.addField(new FieldValue("Command", command)); 117 | message.addField(new FieldValue("Button", button)); 118 | message.addField(new FieldValue("Address", address)); 119 | 120 | // It is, check if this really is a repeat 121 | if ((m_RepeatCount > 0) && (m_Data == m_LastData)) { 122 | message.setRepeat(m_RepeatCount); 123 | } else { 124 | // It is not a repeat, reset counter 125 | m_RepeatCount = 0; 126 | } 127 | // Report the parsed message 128 | m_Sink.parsedMessage(message); 129 | m_State = REPEAT_SCAN; 130 | } 131 | m_BitCounter++; 132 | } 133 | 134 | private int bitPosToInt(int rawButton) { 135 | int shift = rawButton; 136 | for (int i = 0; i < 5; i++) { 137 | if ((shift & 1) == 1) { 138 | return i; 139 | } 140 | shift >>= 1; 141 | } 142 | return 5; 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/encoders/DeltronicEncoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2013, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.encoders; 21 | 22 | import nu.nethome.util.plugin.Plugin; 23 | import nu.nethome.util.ps.*; 24 | 25 | import java.util.ArrayList; 26 | 27 | /** 28 | * The DeltronicEncoder is an encoder for the RF-protocol used by 29 | * Deltronic products such as remote switches. The DeltronicEncoder 30 | * can take the data from a protocol message and encode that into a sequence 31 | * of pulse lengths which may be played by RF-transmitting hardware for instance 32 | * via the AudioPulsePlayer. 33 | * 34 | * @author Stefan 35 | */ 36 | @Plugin 37 | public class DeltronicEncoder implements ProtocolEncoder { 38 | 39 | public int repeatCount = 3; 40 | private int address = 0; 41 | private int command = 1; 42 | private int button = 0; 43 | 44 | protected static final int DELTRONIC_HEADER_MARK = 330 - 60; 45 | protected static final int DELTRONIC_HEADER_SPACE = 830 + 60; 46 | protected static final int DELTRONIC_LONG_MARK = 835 - 60; 47 | protected static final int DELTRONIC_SHORT_MARK = 280 - 60; 48 | protected static final int DELTRONIC_LONG_SPACE = 845 + 60; 49 | protected static final int DELTRONIC_SHORT_SPACE = 300 + 60; 50 | protected static final int DELTRONIC_INTER_SPACE = 850 + 60; 51 | protected static final int DELTRONIC_REPEAT = 8810 + 60; 52 | 53 | protected static final int MESSAGE_LENGTH = 12; 54 | protected static final int HIGH_BIT = 1 << (MESSAGE_LENGTH - 1); 55 | 56 | static final int s_Buttons[] = {0x20, 0x10, 0x04, 0x08}; 57 | 58 | /** 59 | * Encodes the current message according to the following protocol: 60 | * 61 | * a = Address 62 | * A = Button A 63 | * B = Button B 64 | * C = Button C 65 | * D = Button D 66 | * f = Off-bit 67 | * n = On-bit 68 | * 69 | * ____Byte 1_____ ____Byte 0_____ 70 | * 3 2 1 0 7 6 5 4 3 2 1 0 71 | * a a a a a a A B D C f n 72 | */ 73 | public int[] encode() { 74 | ArrayList result = new ArrayList(); 75 | long message = 0; 76 | 77 | // encode message 78 | long messageTemplate = 0x00000000; 79 | messageTemplate |= (command == 1) ? 0x01 : 0x02; 80 | messageTemplate |= s_Buttons[button]; 81 | messageTemplate |= (address << 6); 82 | 83 | // Start encoding the data pulses 84 | for (int i = 0; i < repeatCount; i++) { 85 | message = messageTemplate; 86 | 87 | // Encode header 88 | result.add(DELTRONIC_HEADER_MARK); 89 | result.add(DELTRONIC_HEADER_SPACE); 90 | 91 | // Encode message bits 92 | for (int j = 0; j < (MESSAGE_LENGTH); j++) { 93 | if ((message & HIGH_BIT) == HIGH_BIT) { 94 | result.add(DELTRONIC_SHORT_MARK); 95 | result.add(DELTRONIC_LONG_SPACE); 96 | } 97 | else { 98 | result.add(DELTRONIC_LONG_MARK); 99 | result.add(DELTRONIC_SHORT_SPACE); 100 | } 101 | result.add(DELTRONIC_SHORT_MARK); 102 | result.add(DELTRONIC_INTER_SPACE); 103 | message <<= 1; 104 | } 105 | // Add the repeat delay 106 | int last = result.size() - 1; 107 | // Add the repeat delay to the last space period 108 | result.set(last, DELTRONIC_REPEAT); 109 | } 110 | int resultArray[] = new int[result.size()]; 111 | for (int i = 0; i < result.size(); i++) { 112 | resultArray[i] = result.get(i); 113 | } 114 | return resultArray; 115 | } 116 | 117 | public int getAddress() { 118 | return address; 119 | } 120 | 121 | public void setAddress(int address) { 122 | if ((address >= (1<<6)) || (address < 0)) { 123 | return; 124 | } 125 | this.address = address; 126 | } 127 | 128 | public int getCommand() { 129 | return command; 130 | } 131 | 132 | public void setCommand(int command) { 133 | if ((command > 1) || (command < 0)) { 134 | return; 135 | } 136 | this.command = command; 137 | } 138 | 139 | public int getRepeatCount() { 140 | return repeatCount; 141 | } 142 | 143 | public void setRepeatCount(int repeatCount) { 144 | if ((repeatCount < 1) || (repeatCount > 100)) { 145 | return; 146 | } 147 | this.repeatCount = repeatCount; 148 | } 149 | 150 | public int getButton() { 151 | return button; 152 | } 153 | 154 | public void setButton(int button) { 155 | if ((button < 0) || (button > 3)) { 156 | return; 157 | } 158 | this.button = button; 159 | } 160 | 161 | public ProtocolInfo getInfo() { 162 | return new ProtocolInfo("Deltronic", "Space Length", "Deltronic", 12, 5); 163 | } 164 | 165 | public int[] encode(Message message, Phase phase) throws BadMessageException { 166 | if (Phase.FIRST == phase) { 167 | return new int[0]; 168 | } 169 | for (FieldValue field : message.getFields()) { 170 | if (field.getName().equals("Command")) { 171 | setCommand(field.getValue()); 172 | } else if (field.getName().equals("Button")) { 173 | setButton(field.getValue()); 174 | } else if (field.getName().equals("Address")) { 175 | setAddress(field.getValue()); 176 | } else { 177 | throw new BadMessageException(field); 178 | } 179 | } 180 | setRepeatCount(1); 181 | return encode(); 182 | } 183 | 184 | @Override 185 | public int modulationFrequency(Message message) { 186 | return 0; 187 | } 188 | 189 | public static Message buildCommandMessage(boolean on, int button, int address) { 190 | ProtocolMessage result = new ProtocolMessage("Deltronic", on ? 1 :0, address, 0); 191 | result.addField(new FieldValue("Command", on ? 1 : 0)); 192 | result.addField(new FieldValue("Button", button)); 193 | result.addField(new FieldValue("Address", address)); 194 | return result; 195 | }; 196 | } 197 | 198 | -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/encoders/EmotivaEncoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2013, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.encoders; 21 | 22 | import nu.nethome.util.plugin.Plugin; 23 | import nu.nethome.util.ps.*; 24 | 25 | import java.util.ArrayList; 26 | 27 | /** 28 | * User: Stefan 29 | * Date: 2013-01-27 30 | * Time: 21:06 31 | */ 32 | @Plugin 33 | public class EmotivaEncoder implements ProtocolEncoder { 34 | 35 | 36 | public static final int EMOTIVA_RAW_MESSAGE_LENGTH = 32; 37 | public static final int EMOTIVA_HEADER_MARK = 9100; 38 | public static final int EMOTIVA_HEADER_SPACE = 4400; 39 | public static final int EMOTIVA_MARK = 630; 40 | public static final int EMOTIVA_LONG_SPACE = 1600; 41 | public static final int EMOTIVA_SHORT_SPACE = 500; 42 | public static final int EMOTIVA_REPEAT_SPACE = 9100; 43 | 44 | public ProtocolInfo getInfo() { 45 | return new ProtocolInfo("Emotiva", "Space Length", "Emotiva", 24, 5); 46 | } 47 | 48 | public int[] encode(Message message, Phase phase) throws BadMessageException { 49 | if (Phase.FIRST == phase) { 50 | return new int[0]; 51 | } 52 | int command = 0; 53 | int address = 0; 54 | for (FieldValue field : message.getFields()) { 55 | if (field.getName().equals("Command")) { 56 | command = field.getValue(); 57 | } else if (field.getName().equals("Address")) { 58 | address = field.getValue(); 59 | } else { 60 | throw new BadMessageException(field); 61 | } 62 | } 63 | return encode(command, address); 64 | } 65 | 66 | @Override 67 | public int modulationFrequency(Message message) { 68 | return 40000; 69 | } 70 | 71 | public static Message buildMessage(int command, int address) { 72 | ProtocolMessage result = new ProtocolMessage("Emotiva", command, address, 0); 73 | result.addField(new FieldValue("Command", command)); 74 | result.addField(new FieldValue("Address", address)); 75 | return result; 76 | } 77 | 78 | private int[] encode(int command, int address) { 79 | ArrayList result = new ArrayList(); 80 | long message = address + (command << 16) + ((command ^ 0xFF) << 24); 81 | // Encode header 82 | result.add(EMOTIVA_HEADER_MARK); 83 | result.add(EMOTIVA_HEADER_SPACE); 84 | 85 | // Encode message bits 86 | for (int j = 0; j < (EMOTIVA_RAW_MESSAGE_LENGTH); j++) { 87 | result.add(EMOTIVA_MARK); 88 | if ((message & 1) == 1) { 89 | result.add(EMOTIVA_LONG_SPACE); 90 | } else { 91 | result.add(EMOTIVA_SHORT_SPACE); 92 | } 93 | message >>= 1; 94 | } 95 | result.add(EMOTIVA_MARK); 96 | result.add(EMOTIVA_REPEAT_SPACE); 97 | 98 | int resultArray[] = new int[result.size()]; 99 | for (int i = 0; i < result.size(); i++) { 100 | resultArray[i] = result.get(i); 101 | } 102 | return resultArray; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/encoders/Encoders.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2015, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.encoders; 21 | 22 | import nu.nethome.util.ps.ProtocolEncoder; 23 | 24 | import java.util.ArrayList; 25 | import java.util.Collection; 26 | 27 | public class Encoders { 28 | public static Collection> getAllTypes() { 29 | Collection> result = new ArrayList>(); 30 | result.add(DeltronicEncoder.class); 31 | result.add(EmotivaEncoder.class); 32 | result.add(NexaEncoder.class); 33 | result.add(NexaFireEncoder.class); 34 | result.add(NexaLEncoder.class); 35 | result.add(ProntoEncoder.class); 36 | result.add(RisingSunEncoder.class); 37 | result.add(WavemanEncoder.class); 38 | result.add(X10Encoder.class); 39 | result.add(ZhejiangEncoder.class); 40 | result.add(RollerTrolEncoder.class); 41 | result.add(RollerTrolGEncoder.class); 42 | return result; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/encoders/NexaFireEncoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2013, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.encoders; 21 | 22 | import nu.nethome.coders.decoders.NexaFireDecoder; 23 | import nu.nethome.util.plugin.Plugin; 24 | import nu.nethome.util.ps.*; 25 | 26 | import java.util.ArrayList; 27 | 28 | /** 29 | * The NexaFireEncoder is an encoder for the RF-protocol used by NEXA Fire Detectors 30 | * with RF connection. The NexaFireEncoder can take the data from a protocol message 31 | * and encode that into a sequence of pulse lengths which may be played by 32 | * RF-transmitting hardware for instance via the AudioPulsePlayer. 33 | * 34 | * @author Stefan 35 | * 36 | */ 37 | @Plugin 38 | public class NexaFireEncoder implements ProtocolEncoder { 39 | 40 | public int m_RepeatCount = 15; 41 | private int m_Address = 0; 42 | 43 | // Get the pulse lengths from the decoder 44 | protected int HEADER_MARK = NexaFireDecoder.NEXAF_HEADER_MARK.length(); 45 | protected int HEADER_SPACE = NexaFireDecoder.NEXAF_HEADER_SPACE.length(); 46 | protected int MARK = NexaFireDecoder.NEXAF_MARK.length(); 47 | protected int LONG_SPACE = NexaFireDecoder.NEXAF_LONG_SPACE.length(); 48 | protected int SHORT_SPACE = NexaFireDecoder.NEXAF_SHORT_SPACE.length(); 49 | protected int REPEAT = NexaFireDecoder.NEXAF_REPEAT.length(); 50 | 51 | public NexaFireEncoder() { 52 | setup(); 53 | } 54 | 55 | /** 56 | * Template method pattern. This is called by the constructor in order to be able to let 57 | * subclasses change pulse lengths and other parameters 58 | */ 59 | protected void setup() { 60 | } 61 | 62 | /** 63 | * Encodes the current message according to the following protocol: 64 | * 65 | * a = Address
66 | *
67 | * ____Byte 2_____ ____Byte 1_____ ____Byte 0_____
68 | * 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
69 | * a a a a a a a a a a a a a a a a a a a a a a a a
70 | */ 71 | public int[] encode() { 72 | ArrayList result = new ArrayList(); 73 | long message = 0; 74 | 75 | // Start actually encoding the data pulses 76 | for (int i = 0; i < m_RepeatCount; i++) { 77 | message = m_Address; 78 | 79 | // Encode header 80 | result.add(HEADER_MARK); 81 | result.add(HEADER_SPACE); 82 | 83 | // 24 bits of data 84 | for (int j = 0; j < 24; j++) { 85 | result.add(MARK); 86 | if ((message & 1) == 1) { 87 | result.add(LONG_SPACE); 88 | } 89 | else { 90 | result.add(SHORT_SPACE); 91 | } 92 | message >>= 1; 93 | } 94 | // Add trailing mark and repeat space 95 | result.add(MARK); 96 | result.add(REPEAT); 97 | } 98 | int resultArray[] = new int[result.size()]; 99 | for (int i = 0; i < result.size(); i++) { 100 | resultArray[i] = result.get(i); 101 | } 102 | return resultArray; 103 | } 104 | 105 | /** 106 | * @return the Address 107 | */ 108 | public int getAddress() { 109 | return m_Address; 110 | } 111 | 112 | /** 113 | * @param address the Address to set 114 | */ 115 | public void setAddress(int address) { 116 | if (address > 0xFFFFFF) return; 117 | this.m_Address = address; 118 | } 119 | 120 | public int getRepeatCount() { 121 | return m_RepeatCount; 122 | } 123 | 124 | public void setRepeatCount(int repeatCount) { 125 | if ((repeatCount < 1) || (repeatCount > 100)) { 126 | return; 127 | } 128 | this.m_RepeatCount = repeatCount; 129 | } 130 | 131 | @Override 132 | public ProtocolInfo getInfo() { 133 | return new ProtocolInfo("NexaFire", "Space Length", "NexaFire", 24, 15); 134 | } 135 | 136 | @Override 137 | public int[] encode(Message message, Phase phase) throws BadMessageException { 138 | if (Phase.FIRST == phase) { 139 | return new int[0]; 140 | } 141 | for (FieldValue field : message.getFields()) { 142 | if (field.getName().equals("Address")) { 143 | setAddress(field.getValue()); 144 | } else { 145 | throw new BadMessageException(field); 146 | } 147 | } 148 | setRepeatCount(1); 149 | return encode(); 150 | } 151 | 152 | @Override 153 | public int modulationFrequency(Message message) { 154 | return 0; 155 | } 156 | } 157 | 158 | -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/encoders/ProntoEncoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2013, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.encoders; 21 | 22 | import nu.nethome.util.plugin.Plugin; 23 | import nu.nethome.util.ps.*; 24 | 25 | import java.util.NoSuchElementException; 26 | import java.util.Scanner; 27 | 28 | /** 29 | * Pronto Encoder takes a message string encoded in the Pronto-format 30 | * and decodes it into a format used to transmit messages via RF or IR. 31 | * Messages can be sent by {@link nu.nethome.util.ps.impl.AudioPulsePlayer}. 32 | * 33 | * @author Stefan 34 | */ 35 | @Plugin 36 | public class ProntoEncoder implements ProtocolEncoder{ 37 | 38 | /** Constant for the pronto remote's internal clock frequency */ 39 | protected final double m_ProntoFreqConstant = .241246; 40 | 41 | protected String m_Message = ""; 42 | protected int m_RepeatCount = 5; 43 | 44 | /** 45 | * Extract the modulation frequency in Hz from a Pronto message 46 | * @param prontoMessage 47 | * @return modulation frequency 48 | */ 49 | public int modulationFrequency(Message prontoMessage) { 50 | if(prontoMessage.getFields().size() != 1 || !prontoMessage.getFields().get(0).getName().equals("Message")) { 51 | return 0; 52 | } 53 | Scanner scanner = new Scanner(prontoMessage.getFields().get(0).getStringValue()); 54 | double period = 10; 55 | try { 56 | // Extract type, 0000 for sampled signal. This is the only format we support 57 | if (scanner.nextInt(16) != 0) return 0; 58 | // Extract modulation frequency period length 59 | period = scanner.nextInt(16) * m_ProntoFreqConstant; 60 | if (period < 10) return 0; 61 | } 62 | catch (NoSuchElementException e) { 63 | return 0; 64 | } 65 | return (int)(1000000 / period); 66 | } 67 | 68 | /** 69 | * Encode the current message as a sequence of pulse lengths. Note that this encodes 70 | * both sequence #1 and sequence #2 into the pulse sequence. Use getRepeatPoint() to find out 71 | * at what position sequence #2 begins. 72 | * @return list of pulse lengths in micro seconds 73 | */ 74 | public int[] encode() { 75 | int fail[] = new int[0]; 76 | int result[]; 77 | Scanner scanner = new Scanner(m_Message); 78 | try { 79 | // Extract type, 0000 for sampled signal. This is the only format we support 80 | if (scanner.nextInt(16) != 0) return fail; 81 | // Extract modulation frequency period length 82 | double period = scanner.nextInt(16) * m_ProntoFreqConstant; 83 | // Number of burst pairs in sequence #1 84 | int count = scanner.nextInt(16) * 2; 85 | // Extract number of burst pairs in sequence #2 and add to the total 86 | count += scanner.nextInt(16) * 2; 87 | result = new int[count * m_RepeatCount]; 88 | // Extract the burst pairs and convert the time to uS 89 | for (int i = 0; i < count; i++) { 90 | result[i] = (int)(period * scanner.nextInt(16) + 0.5); 91 | // fill in the repeat sequences 92 | for (int j = 1; j < m_RepeatCount; j++) { 93 | result[i + (j * count)] = result[i]; 94 | } 95 | } 96 | } 97 | catch (NoSuchElementException e) { 98 | return fail; 99 | } 100 | return result; 101 | } 102 | 103 | public String getMessage() { 104 | return m_Message; 105 | } 106 | 107 | public void setMessage(String message) { 108 | m_Message = message; 109 | } 110 | 111 | public int getRepeatCount() { 112 | return m_RepeatCount; 113 | } 114 | 115 | public void setRepeatCount(int repeatCount) { 116 | if ((repeatCount > 0) && (repeatCount < 20)) { 117 | m_RepeatCount = repeatCount; 118 | } 119 | } 120 | 121 | public int getRepeatPoint() { 122 | Scanner scanner = new Scanner(m_Message); 123 | try { 124 | // Extract type, 0000 for sampled signal. This is the only format we support 125 | if (scanner.nextInt(16) != 0) return 0; 126 | // Extract modulation frequency period length, and ignore it 127 | scanner.nextInt(16); 128 | // Number of burst pairs in sequence #1, this is the repeat point 129 | return scanner.nextInt(16) * 2; 130 | } 131 | catch (NoSuchElementException e) { 132 | } 133 | return 0; 134 | } 135 | 136 | public ProtocolInfo getInfo() { 137 | return new ProtocolInfo("Pronto", "None", "Pronto", 0, 5); 138 | } 139 | 140 | public int[] encode(Message message, Phase phase) throws BadMessageException { 141 | int fail[] = new int[0]; 142 | int result[]; 143 | for (FieldValue field : message.getFields()) { 144 | if (field.getName().equals("Message")) { 145 | setMessage(field.getStringValue()); 146 | } else { 147 | throw new BadMessageException(field); 148 | } 149 | } 150 | Scanner scanner = new Scanner(m_Message); 151 | try { 152 | // Extract type, 0000 for sampled signal. This is the only format we support 153 | if (scanner.nextInt(16) != 0) return fail; 154 | // Extract modulation frequency period length 155 | double period = scanner.nextInt(16) * m_ProntoFreqConstant; 156 | // Number of burst pairs in sequence #1 157 | int header = scanner.nextInt(16) * 2; 158 | // Extract number of burst pairs in sequence #2 and add to the total 159 | int body = scanner.nextInt(16) * 2; 160 | int length; 161 | int skip; 162 | if (phase == Phase.FIRST) { 163 | skip = 0; 164 | length = header; 165 | } else { 166 | skip = header; 167 | length = body; 168 | } 169 | result = new int[length]; 170 | // Skip header (if needed) 171 | for (int i = 0; i < skip; i++) { 172 | scanner.nextInt(16); 173 | } 174 | 175 | // Extract the burst pairs and convert the time to uS 176 | for (int i = 0; i < length; i++) { 177 | result[i] = (int)(period * scanner.nextInt(16) + 0.5); 178 | } 179 | } 180 | catch (NoSuchElementException e) { 181 | return fail; 182 | } 183 | return result; 184 | } 185 | 186 | public static Message createMessage(String prontoString) { 187 | ProtocolMessage result = new ProtocolMessage("Pronto", 0, 0, 0); 188 | result.addField(new FieldValue("Message", prontoString)); 189 | return result; 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/encoders/RisingSunEncoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2013, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.encoders; 21 | 22 | import nu.nethome.coders.decoders.RisingSunDecoder; 23 | import nu.nethome.util.plugin.Plugin; 24 | import nu.nethome.util.ps.*; 25 | 26 | import java.util.ArrayList; 27 | 28 | @Plugin 29 | public class RisingSunEncoder implements ProtocolEncoder{ 30 | 31 | public int repeatCount = 5; 32 | private int channel = 1; 33 | private int button = 1; 34 | private int command = 1; 35 | protected int onCommandValue; 36 | protected int offCommandValue; 37 | 38 | // Get the pulse lengths from the decoder 39 | protected int LONG_MARK = RisingSunDecoder.RISING_SUN_LONG_MARK.length(); 40 | protected int SHORT_MARK = RisingSunDecoder.RISING_SUN_SHORT_MARK.length(); 41 | protected int LONG_SPACE = RisingSunDecoder.RISING_SUN_LONG_SPACE.length(); 42 | protected int SHORT_SPACE = RisingSunDecoder.RISING_SUN_SHORT_SPACE.length(); 43 | protected int REPEAT = RisingSunDecoder.RISING_SUN_REPEAT.length(); 44 | protected static int BUTTON_MAP[] = {0x54, 0x51, 0x45, 0x15}; 45 | 46 | public RisingSunEncoder() { 47 | setup(); 48 | } 49 | 50 | protected void setup() { 51 | offCommandValue = 0x15 << 17; 52 | onCommandValue = 0x55 << 17; 53 | } 54 | 55 | /** 56 | * s = Start bit = 0
57 | * a = Channel 1 not selected
58 | * b = Channel 2 not selected
59 | * c = Channel 3 not selected
60 | * d = Channel 4 not selected
61 | * e = Button 1 not pressed
62 | * f = Button 2 not pressed
63 | * g = Button 3 not pressed
64 | * h = Button 4 not pressed
65 | * o = On/Off-bit
66 | *
67 | * ____Byte 2_____ ____Byte 1_____ ____Byte 0_____ _S_
68 | * 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 0
69 | * x o x x x x x x x h x g x f x e x d x c x b x a s
70 | * 71 | */ 72 | public int[] encode() { 73 | ArrayList result = new ArrayList(); 74 | long messageTemplate = 0; 75 | long message = 0; 76 | 77 | // encode message 78 | int sendChannel = this.channel - 1; 79 | int sendButton = this.button - 1; 80 | messageTemplate |= BUTTON_MAP[sendChannel] << 1; 81 | messageTemplate |= BUTTON_MAP[sendButton] << 9; 82 | 83 | messageTemplate |= (command == 0) ? offCommandValue : onCommandValue; 84 | 85 | // Start actually encoding the data pulses 86 | for (int i = 0; i < repeatCount; i++) { 87 | message = messageTemplate; 88 | 89 | // 25 bits of data including start bit 90 | for (int j = 0; j < 25; j++) { 91 | if ((message & 1) == 1) { 92 | result.add(LONG_MARK); 93 | result.add(SHORT_SPACE); 94 | } 95 | else { 96 | result.add(SHORT_MARK); 97 | result.add(LONG_SPACE); 98 | } 99 | message >>= 1; 100 | } 101 | int last = result.size() - 1; 102 | // Add the repeat delay as the last space period 103 | result.set(last, REPEAT); 104 | } 105 | int resultArray[] = new int[result.size()]; 106 | for (int i = 0; i < result.size(); i++) { 107 | resultArray[i] = result.get(i); 108 | } 109 | return resultArray; 110 | } 111 | 112 | public int getChannel() { 113 | return channel; 114 | } 115 | 116 | public void setChannel(int channel) { 117 | if ((channel < 1) || (channel > 4)) { 118 | return; 119 | } 120 | this.channel = channel; 121 | } 122 | 123 | public int getButton() { 124 | return button; 125 | } 126 | 127 | public void setButton(int deviceCode) { 128 | if ((deviceCode < 1) || (deviceCode > 4)) { 129 | return; 130 | } 131 | button = deviceCode; 132 | } 133 | 134 | public int getCommand() { 135 | return command; 136 | } 137 | 138 | public void setCommand(int command) { 139 | if ((command < 0) || (command > 1)) { 140 | return; 141 | } 142 | this.command = command; 143 | } 144 | 145 | public int getRepeatCount() { 146 | return repeatCount; 147 | } 148 | 149 | public void setRepeatCount(int repeatCount) { 150 | if ((repeatCount < 1) || (repeatCount > 100)) { 151 | return; 152 | } 153 | this.repeatCount = repeatCount; 154 | } 155 | 156 | public ProtocolInfo getInfo() { 157 | return new ProtocolInfo("RisingSun", "Mark Length", "RisingSun", 25, 5); 158 | } 159 | 160 | public int[] encode(Message message, Phase phase) throws BadMessageException { 161 | if (Phase.FIRST == phase) { 162 | return new int[0]; 163 | } 164 | for (FieldValue field : message.getFields()) { 165 | if (field.getName().equals("Command")) { 166 | setCommand(field.getValue()); 167 | } else if (field.getName().equals("Button")) { 168 | setButton(field.getValue()); 169 | } else if (field.getName().equals("Channel")) { 170 | setChannel(field.getValue()); 171 | } else { 172 | throw new BadMessageException(field); 173 | } 174 | } 175 | setRepeatCount(1); 176 | return encode(); 177 | } 178 | 179 | @Override 180 | public int modulationFrequency(Message message) { 181 | return 0; 182 | } 183 | 184 | /** 185 | * Build a correct protocol message for the Nexa protocol 186 | * @param command 0 or 1 meaning off or on 187 | * @param button which button is pressed 1-16 188 | * @param channel which address (or house code) to send to 0-15 189 | * @return a message with the specified parameters 190 | */ 191 | public static Message buildMessage(int command, int button, int channel) { 192 | ProtocolMessage result = new ProtocolMessage("RisingSun", command, channel, 0); 193 | result.addField(new FieldValue("Command", command)); 194 | result.addField(new FieldValue("Button", button)); 195 | result.addField(new FieldValue("Channel", channel)); 196 | return result; 197 | }; 198 | 199 | } 200 | 201 | 202 | -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/encoders/RollerTrolEncoder.java: -------------------------------------------------------------------------------- 1 | package nu.nethome.coders.encoders; 2 | 3 | import nu.nethome.coders.RollerTrol; 4 | import nu.nethome.util.ps.*; 5 | 6 | import static nu.nethome.coders.RollerTrol.*; 7 | 8 | /** 9 | * 10 | */ 11 | public class RollerTrolEncoder implements ProtocolEncoder { 12 | 13 | public static final int PREAMBLE_LENGTH = 4; 14 | public static final int CONSTANT_FIELD_VALUE = 1; 15 | 16 | @Override 17 | public ProtocolInfo getInfo() { 18 | return ROLLERTROL_PROTOCOL_INFO; 19 | } 20 | 21 | @Override 22 | public int[] encode(Message message, Phase phase) throws BadMessageException { 23 | int houseCode = 0; 24 | int deviceCode = 0; 25 | int command = 0; 26 | for (FieldValue f : message.getFields()) { 27 | if (f.getName().equals(HOUSE_CODE_NAME)) { 28 | houseCode = f.getValue(); 29 | } 30 | if (f.getName().equals(DEVICE_CODE_NAME)) { 31 | deviceCode = f.getValue(); 32 | } 33 | if (f.getName().equals(COMMAND_NAME)) { 34 | command = f.getValue(); 35 | } 36 | } 37 | return encode(houseCode, deviceCode, command); 38 | } 39 | 40 | private int[] encode(int houseCode, int deviceCode, int command) { 41 | int[] result = new int[PREAMBLE_LENGTH + MESSAGE_BIT_LENGTH * 2]; 42 | result[0] = RollerTrol.LONG_PREAMBLE_MARK.length(); 43 | result[1] = RollerTrol.LONG_PREAMBLE_SPACE.length(); 44 | result[2] = RollerTrol.SHORT_PREAMBLE_MARK.length(); 45 | result[3] = RollerTrol.SHORT.length(); 46 | BitString message = new BitString(MESSAGE_BIT_LENGTH); 47 | message.insert(RollerTrol.COMMAND, command); 48 | message.insert(RollerTrol.HOUSE_CODE, houseCode); 49 | message.insert(RollerTrol.DEVICE_CODE, deviceCode); 50 | message.insert(CONSTANT_FIELD, CONSTANT_FIELD_VALUE); 51 | message.insert(CHECK_SUM, RollerTrol.calculateChecksum(message)); 52 | int resultPosition = PREAMBLE_LENGTH; 53 | for (int i = 0; i < MESSAGE_BIT_LENGTH; i++) { 54 | if (message.getBit(i)) { 55 | result[resultPosition++] = LONG.length(); 56 | result[resultPosition++] = SHORT.length(); 57 | } else { 58 | result[resultPosition++] = SHORT.length(); 59 | result[resultPosition++] = LONG.length(); 60 | } 61 | } 62 | return result; 63 | } 64 | 65 | @Override 66 | public int modulationFrequency(Message message) { 67 | return 0; 68 | } 69 | 70 | public static Message buildMessage(int command, int houseCode, int deviceCode) { 71 | ProtocolMessage result = new ProtocolMessage(ROLLER_TROL_PROTOCOL_NAME, command, deviceCode, 0); 72 | result.addField(new FieldValue(COMMAND_NAME, command)); 73 | result.addField(new FieldValue(HOUSE_CODE_NAME, houseCode)); 74 | result.addField(new FieldValue(DEVICE_CODE_NAME, deviceCode)); 75 | return result; 76 | } 77 | 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/encoders/RollerTrolGEncoder.java: -------------------------------------------------------------------------------- 1 | package nu.nethome.coders.encoders; 2 | 3 | import nu.nethome.coders.RollerTrolG; 4 | import nu.nethome.util.ps.*; 5 | 6 | import static nu.nethome.coders.RollerTrolG.*; 7 | 8 | /** 9 | * 10 | */ 11 | public class RollerTrolGEncoder implements ProtocolEncoder { 12 | 13 | public static final int PREAMBLE_LENGTH = 2; 14 | public static final int CONSTANT_FIELD_VALUE = 1; 15 | 16 | @Override 17 | public ProtocolInfo getInfo() { 18 | return ROLLERTROL_PROTOCOL_INFO; 19 | } 20 | 21 | @Override 22 | public int[] encode(Message message, Phase phase) throws BadMessageException { 23 | int address = 0; 24 | int channel = 0; 25 | int command = 0; 26 | for (FieldValue f : message.getFields()) { 27 | if (RollerTrolG.ADDRESS_NAME.equals(f.getName())) { 28 | address = f.getValue(); 29 | } 30 | if (RollerTrolG.CHANNEL_NAME.equals(f.getName())) { 31 | channel = f.getValue(); 32 | } 33 | if (RollerTrolG.COMMAND_NAME.equals(f.getName())) { 34 | command = f.getValue(); 35 | } 36 | } 37 | return encode(address, channel, command); 38 | } 39 | 40 | private int[] encode(int address, int channel, int command) { 41 | int[] result = new int[PREAMBLE_LENGTH + RollerTrolG.PROTOCOL_BIT_LENGTH * 2 + 1]; 42 | result[0] = RollerTrolG.LONG_PREAMBLE_MARK.length(); 43 | result[1] = RollerTrolG.LONG_PREAMBLE_SPACE.length(); 44 | BitString message = new BitString(RollerTrolG.PROTOCOL_BIT_LENGTH); 45 | message.insert(RollerTrolG.COMMAND, command); 46 | message.insert(RollerTrolG.ADDRESS, address); 47 | message.insert(RollerTrolG.CHANNEL, channel); 48 | int resultPosition = PREAMBLE_LENGTH; 49 | for (int i = 0; i < RollerTrolG.PROTOCOL_BIT_LENGTH; i++) { 50 | if (message.getBit(PROTOCOL_BIT_LENGTH - i - 1)) { 51 | result[resultPosition++] = LONG.length(); 52 | result[resultPosition++] = SHORT.length(); 53 | } else { 54 | result[resultPosition++] = SHORT.length(); 55 | result[resultPosition++] = LONG.length(); 56 | } 57 | } 58 | result[resultPosition] = RollerTrolG.REPEAT_SPACE.length(); 59 | return result; 60 | } 61 | 62 | @Override 63 | public int modulationFrequency(Message message) { 64 | return 0; 65 | } 66 | 67 | public static Message buildMessage(int command, int address, int channel) { 68 | ProtocolMessage result = new ProtocolMessage(RollerTrolG.ROLLER_TROL_G_PROTOCOL_NAME, command, channel, 0); 69 | result.addField(new FieldValue(COMMAND_NAME, command)); 70 | result.addField(new FieldValue(ADDRESS_NAME, address)); 71 | result.addField(new FieldValue(CHANNEL_NAME, channel)); 72 | return result; 73 | } 74 | 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/encoders/ShortBeepEncoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2013, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.encoders; 21 | 22 | import java.util.ArrayList; 23 | 24 | /** 25 | * Encodes a signal that when played with an AudioPulseTransmitter will be heard 26 | * as a short beep if speakers are attached to the audio output used. This is 27 | * used for testing setup and configuration and should NOT be used when an 28 | * RF-Transmitting device is attached to the output. 29 | * 30 | * @author Stefan 31 | */ 32 | public class ShortBeepEncoder { 33 | 34 | private static final float MICROSECS_PER_SEC = 1000000; 35 | private int m_Frequency = 2000; 36 | private float m_Duration = 0.8F; 37 | private ArrayList result = new ArrayList(); 38 | 39 | /** 40 | * Encode a pulse set which will be heard as a short beep if played by 41 | * an AudioProtocolTransmitter. 42 | * @return 43 | */ 44 | public int[] encode() { 45 | int noFlanks = (int)(m_Duration * MICROSECS_PER_SEC * 2F) / m_Frequency; 46 | int flank = ((int)MICROSECS_PER_SEC / m_Frequency) / 2; 47 | for (int i = 0; i < noFlanks; i++) { 48 | result.add(flank); 49 | } 50 | int resultArray[] = new int[result.size()]; 51 | for (int i = 0; i < result.size(); i++) { 52 | resultArray[i] = result.get(i); 53 | } 54 | return resultArray; 55 | } 56 | 57 | public int getFrequency() { 58 | return m_Frequency; 59 | } 60 | 61 | /** 62 | * @param frequency Frequency of the beep,1 - 18000 Hz 63 | */ 64 | public void setFrequency(int frequency) { 65 | if ((frequency < 0) || (frequency > 18000)) { 66 | throw new IllegalArgumentException("Bad frequence value"); 67 | } 68 | m_Frequency = frequency; 69 | } 70 | 71 | public float getDuration() { 72 | return m_Duration; 73 | } 74 | 75 | /** 76 | * @param duration Duration of the Beep, 0 - 1 Second 77 | */ 78 | public void setDuration(float duration) { 79 | if ((duration < 0) || (duration > 1)) { 80 | throw new IllegalArgumentException("Bad duration value"); 81 | } 82 | m_Duration = duration; 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/encoders/WavemanEncoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2013, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.encoders; 21 | 22 | import nu.nethome.util.plugin.Plugin; 23 | import nu.nethome.util.ps.ProtocolInfo; 24 | 25 | /** 26 | * The Waveman Encoder is an encoder for the RF-protocol used by Waveman products 27 | * such as remote switches, dimmers, PIR-detectors and so on. The WavemanEncoder 28 | * can take the data from a protocol message and encode that into a sequence 29 | * of pulse lengths which may be played by RF-transmitting hardware for instance 30 | * via the AudioPulsePlayer. 31 | * 32 | * @author Stefan 33 | */ 34 | @Plugin 35 | public class WavemanEncoder extends NexaEncoder { 36 | 37 | public WavemanEncoder() { 38 | super(); 39 | } 40 | 41 | /** 42 | * The protocol for Waveman is the same as for Nexa, except for the off 43 | * command encoding, where all three bits in the command byte are set to 0. 44 | *
45 | * s = Start bit = 0
46 | * b = Button number
47 | * a = Address
48 | * o = On/Off-bit
49 | *
50 | * ____Byte 2_____ ____Byte 1_____ ____Byte 0_____ _S_
51 | * 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 0
52 | * x o x o x o x x x b x b x b x b x a x a x a x a s
53 | * 54 | */ 55 | protected void setup() { 56 | offCommandValue = 0x00; 57 | onCommandValue = 0x54 << 17; 58 | } 59 | 60 | public ProtocolInfo getInfo() { 61 | return new ProtocolInfo("Waveman", "Space Length", "Waveman", 32, 5); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/nu/nethome/coders/encoders/ZhejiangEncoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2013, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.encoders; 21 | 22 | import nu.nethome.coders.decoders.ZhejiangDecoder; 23 | import nu.nethome.util.plugin.Plugin; 24 | import nu.nethome.util.ps.*; 25 | 26 | import java.util.ArrayList; 27 | 28 | @Plugin 29 | public class ZhejiangEncoder implements ProtocolEncoder { 30 | 31 | public static final int ZHEJIANG_RAW_MESSAGE_LENGTH = 25; 32 | 33 | public ProtocolInfo getInfo() { 34 | return new ProtocolInfo("Zhejiang", "Mark Length", "Zhejiang", 25, 5); 35 | } 36 | 37 | public int[] encode(Message message, Phase phase) throws BadMessageException { 38 | if (Phase.FIRST == phase) { 39 | return new int[0]; 40 | } 41 | int command = 0; 42 | int address = 0; 43 | int button = 0; 44 | for (FieldValue field : message.getFields()) { 45 | if (field.getName().equals("Command")) { 46 | command = field.getValue(); 47 | } else if (field.getName().equals("Address")) { 48 | address = field.getValue(); 49 | } else if (field.getName().equals("Button")) { 50 | button = field.getValue(); 51 | } else { 52 | throw new BadMessageException(field); 53 | } 54 | } 55 | if (command < 0 || command > 1 || address < 0 || address > 31 || button < 0 || button > 4) { 56 | throw new BadMessageException(null); 57 | } 58 | return encode(command, button, address); 59 | } 60 | 61 | @Override 62 | public int modulationFrequency(Message message) { 63 | return 0; 64 | } 65 | 66 | public static Message buildMessage(int command, int button, int address) { 67 | ProtocolMessage result = new ProtocolMessage("Zhejiang", command, address, 0); 68 | result.addField(new FieldValue("Command", command)); 69 | result.addField(new FieldValue("Address", address)); 70 | result.addField(new FieldValue("Button", button)); 71 | return result; 72 | } 73 | 74 | private int[] encode(int command, int button, int address) { 75 | ArrayList result = new ArrayList(); 76 | long message = 0x2003FF; 77 | message = copyBit(command, 0, message, 21, false); 78 | message = copyBit(command, 0, message, 23, true); 79 | int buttonBit = 1 << button; 80 | message = copyBit(buttonBit, 0, message, 11, true); 81 | message = copyBit(buttonBit, 1, message, 13, true); 82 | message = copyBit(buttonBit, 2, message, 15, true); 83 | message = copyBit(buttonBit, 3, message, 17, true); 84 | message = copyBit(buttonBit, 4, message, 19, true); 85 | 86 | message = copyBit(address, 0, message, 0, true); 87 | message = copyBit(address, 1, message, 2, true); 88 | message = copyBit(address, 2, message, 4, true); 89 | message = copyBit(address, 3, message, 6, true); 90 | message = copyBit(address, 4, message, 8, true); 91 | 92 | // Encode message bits 93 | for (int j = 0; j < (ZHEJIANG_RAW_MESSAGE_LENGTH); j++) { 94 | if ((message & 1) == 1) { 95 | result.add(ZhejiangDecoder.ZHEJ_LONG_MARK.length()); 96 | result.add(ZhejiangDecoder.ZHEJ_SHORT_SPACE.length()); 97 | } else { 98 | result.add(ZhejiangDecoder.ZHEJ_SHORT_MARK.length()); 99 | result.add(ZhejiangDecoder.ZHEJ_LONG_SPACE.length()); 100 | } 101 | message >>= 1; 102 | } 103 | result.remove(result.size() - 1); 104 | result.add(ZhejiangDecoder.ZHEJ_REPEAT.length()); 105 | 106 | int resultArray[] = new int[result.size()]; 107 | for (int i = 0; i < result.size(); i++) { 108 | resultArray[i] = result.get(i); 109 | } 110 | return resultArray; 111 | } 112 | 113 | private long copyBit(int source, int sourceBit, long destination, int destinationBit, boolean invert) { 114 | if ((((source >> sourceBit) & 1) == 1) ^ invert) { 115 | return destination | (1L << destinationBit); 116 | } 117 | return destination & ~(1L << destinationBit); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/test/java/nu/nethome/coders/decoders/EmotivaDecoderTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2013, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.decoders; 21 | 22 | import nu.nethome.coders.encoders.EmotivaEncoder; 23 | import nu.nethome.util.ps.BadMessageException; 24 | import nu.nethome.util.ps.FieldValue; 25 | import nu.nethome.util.ps.Message; 26 | import nu.nethome.util.ps.ProtocolEncoder; 27 | import nu.nethome.util.ps.impl.PulseTestPlayer; 28 | import org.junit.Before; 29 | import org.junit.Test; 30 | 31 | import static org.hamcrest.Matchers.hasItem; 32 | import static org.hamcrest.Matchers.is; 33 | import static org.junit.Assert.assertEquals; 34 | import static org.junit.Assert.assertThat; 35 | 36 | /** 37 | * User: Stefan 38 | * Date: 2013-01-27 39 | * Time: 21:53 40 | */ 41 | public class EmotivaDecoderTest { 42 | 43 | private EmotivaEncoder encoder; 44 | private EmotivaDecoder decoder; 45 | private PulseTestPlayer player; 46 | 47 | @Before 48 | public void setUp() throws Exception { 49 | encoder = new EmotivaEncoder(); 50 | player = new PulseTestPlayer(); 51 | decoder = new EmotivaDecoder(); 52 | decoder.setTarget(player); 53 | player.setDecoder(decoder); 54 | player.setPulseWidthModification(0); 55 | } 56 | 57 | @Test 58 | public void canCreateCommand() { 59 | Message message = EmotivaEncoder.buildMessage(1, 0x5533); 60 | assertThat(message.getFields().size(), is(2)); 61 | assertThat(message.getFields(), hasItem(new FieldValue("Command", 1))); 62 | assertThat(message.getFields(), hasItem(new FieldValue("Address", 0x5533))); 63 | } 64 | 65 | @Test 66 | public void canDecodeEncodedMessage() throws BadMessageException { 67 | player.playMessage(encoder.encode(EmotivaEncoder.buildMessage(17, 6543), ProtocolEncoder.Phase.REPEATED)); 68 | assertEquals(1, player.getMessageCount()); 69 | assertEquals(17, player.getMessageField(0, "Command")); 70 | assertEquals(6543, player.getMessageField(0, "Address")); 71 | assertEquals(0, player.getMessages()[0].getRepeat()); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/test/java/nu/nethome/coders/decoders/FineOffsetDecoderTest.java: -------------------------------------------------------------------------------- 1 | package nu.nethome.coders.decoders; 2 | 3 | import nu.nethome.coders.decoders.util.JirFileTestPlayer; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | 7 | import static org.hamcrest.MatcherAssert.assertThat; 8 | import static org.hamcrest.Matchers.is; 9 | 10 | 11 | public class FineOffsetDecoderTest { 12 | @Before 13 | public void setUp() throws Exception { 14 | 15 | } 16 | 17 | @Test 18 | public void basicJir() { 19 | JirFileTestPlayer player = new JirFileTestPlayer(JirFileTestPlayer.FINE_OFFSET_DECODER); 20 | 21 | // Using a known test vector 22 | player.playFile(this.getClass().getClassLoader() 23 | .getResourceAsStream("nu/nethome/coders/decoders/fine_offset.jir")); 24 | 25 | assertThat(player.getMessageField(0, "Identity"), is(0x4B1)); 26 | assertThat(player.getMessageField(0, "Temp"), is(225)); 27 | } 28 | 29 | @Test 30 | public void negativeJir() { 31 | JirFileTestPlayer player = new JirFileTestPlayer(JirFileTestPlayer.FINE_OFFSET_DECODER); 32 | 33 | // Using a known test vector 34 | player.playFile(this.getClass().getClassLoader() 35 | .getResourceAsStream("nu/nethome/coders/decoders/fine_offset_neg.jir")); 36 | 37 | assertThat(player.getMessageField(0, "Identity"), is(0x46D)); 38 | assertThat(player.getMessageField(0, "Temp"), is(-14)); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/test/java/nu/nethome/coders/decoders/OregonDecoderTest.java: -------------------------------------------------------------------------------- 1 | package nu.nethome.coders.decoders; 2 | 3 | import nu.nethome.coders.decoders.util.JirFileTestPlayer; 4 | import nu.nethome.util.ps.FieldValue; 5 | import nu.nethome.util.ps.ProtocolDecoderSink; 6 | import nu.nethome.util.ps.ProtocolMessage; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | import org.mockito.ArgumentCaptor; 10 | 11 | import java.util.List; 12 | 13 | import static org.hamcrest.MatcherAssert.assertThat; 14 | import static org.hamcrest.Matchers.is; 15 | import static org.junit.Assert.assertEquals; 16 | import static org.mockito.Mockito.mock; 17 | import static org.mockito.Mockito.times; 18 | import static org.mockito.Mockito.verify; 19 | 20 | /** 21 | * 22 | */ 23 | public class OregonDecoderTest { 24 | 25 | OregonDecoder decoder; 26 | ProtocolDecoderSink sink; 27 | ArgumentCaptor messageCaptor; 28 | 29 | @Before 30 | public void setUp() throws Exception { 31 | decoder = new OregonDecoder(); 32 | sink = mock(ProtocolDecoderSink.class); 33 | messageCaptor = ArgumentCaptor.forClass(ProtocolMessage.class); 34 | decoder.setTarget(sink); 35 | } 36 | 37 | @Test 38 | public void tempHumiditySensor1D20WithKnownTestVector() throws Exception { 39 | receiveMessage("A1D2016B1091073A14"); 40 | verifyTemperature(0x1D20, 190); 41 | assertThat(getMessageField("Moisture"), is(37)); 42 | } 43 | 44 | @Test 45 | public void tempHumiditySensor1D20WithKnownTestVectorDirectly() throws Exception { 46 | final byte message[] = {0xA, 0x1, 0xD, 0x2, 0x0, 0x1, 0x6, 0xB, 0x1, 0x0, 0x9, 0x1, 0x0, 0x7, 0x3, 0xA, 0x1, 0x4}; 47 | decoder.decodeMessage(message); 48 | verifyTemperature(0x1D20, 190); 49 | assertThat(getMessageField("Moisture"), is(37)); 50 | } 51 | 52 | @Test 53 | public void tempHumiditySensor1D20WithLowBattery() throws Exception { 54 | receiveMessage("A1D2016B5091073A54"); 55 | verify(sink, times(1)).parsedMessage(messageCaptor.capture()); 56 | assertThat(getMessageField("LowBattery"), is(1)); 57 | } 58 | 59 | @Test 60 | public void tempHumiditySensorF824WithKnownTestVector() throws Exception { 61 | receiveMessage("AF82416B1091073AE4"); 62 | verifyTemperature(0xF824, 190); 63 | assertThat(getMessageField("Moisture"), is(37)); 64 | } 65 | 66 | @Test 67 | public void tempHumiditySensorF8B4WithKnownTestVector() throws Exception { 68 | receiveMessage("AF8B416B1091073A75"); 69 | verifyTemperature(0xF8B4, 190); 70 | assertThat(getMessageField("Moisture"), is(37)); 71 | } 72 | 73 | @Test 74 | public void tempSensorEC40WithKnownTestVector() throws Exception { 75 | receiveMessage("AEC4016B1091834"); 76 | verifyTemperature(0xEC40, -190); 77 | } 78 | 79 | @Test 80 | public void tempSensorC844WithKnownTestVector() throws Exception { 81 | receiveMessage("AC84416B1091814"); 82 | verifyTemperature(0xC844, -190); 83 | } 84 | 85 | @Test 86 | public void windSensor1984WithKnownTestVector() throws Exception { 87 | receiveMessage("A198416B1800063892D4"); 88 | verifyWind(0x1984); 89 | } 90 | 91 | @Test 92 | public void windSensor1994WithKnownTestVector() throws Exception { 93 | receiveMessage("A199416B1800063892E4"); 94 | verifyWind(0x1994); 95 | } 96 | 97 | @Test 98 | public void rainSensor2D10WithKnownTestVector() throws Exception { 99 | receiveMessage("A2D1016B15211235063"); 100 | verifyRain(0x2D10); 101 | } 102 | 103 | @Test 104 | public void tempHumidityPressureSensor5D60WithKnownTestVector() throws Exception { 105 | receiveMessage("A5D6016B109107300FF1E5"); 106 | verifyTemperature(0x5D60, 190); 107 | assertThat(getMessageField("Moisture"), is(37)); 108 | assertThat(getMessageField("Pressure"), is(511)); 109 | } 110 | 111 | private void verifyTemperature(int sensorId, int temperature) { 112 | verify(sink, times(1)).parsedMessage(messageCaptor.capture()); 113 | assertThat(getMessageField("SensorId"), is(sensorId)); 114 | assertThat(getMessageField("Channel"), is(1)); 115 | assertThat(getMessageField("Id"), is(0x6B)); 116 | assertThat(getMessageField("Temp"), is(temperature)); 117 | assertThat(getMessageField("LowBattery"), is(0)); 118 | } 119 | 120 | private void verifyWind(int sensorId) { 121 | verify(sink, times(1)).parsedMessage(messageCaptor.capture()); 122 | assertThat(getMessageField("SensorId"), is(sensorId)); 123 | assertThat(getMessageField("Channel"), is(1)); 124 | assertThat(getMessageField("Id"), is(0x6B)); 125 | assertThat(getMessageField("LowBattery"), is(0)); 126 | assertThat(getMessageField("Direction"), is(8)); 127 | assertThat(getMessageField("Wind"), is(360)); 128 | assertThat(getMessageField("AverageWind"), is(298)); 129 | } 130 | 131 | private void verifyRain(int sensorId) { 132 | verify(sink, times(1)).parsedMessage(messageCaptor.capture()); 133 | assertThat(getMessageField("SensorId"), is(sensorId)); 134 | assertThat(getMessageField("Channel"), is(1)); 135 | assertThat(getMessageField("Id"), is(0x6B)); 136 | assertThat(getMessageField("LowBattery"), is(0)); 137 | assertThat(getMessageField("RainRate"), is(125)); 138 | assertThat(getMessageField("TotalRain"), is(5321)); 139 | } 140 | 141 | private void receiveMessage(String s) { 142 | for(char c : s.toCharArray()) { 143 | decoder.addNibble(Byte.parseByte("" + c, 16)); 144 | } 145 | } 146 | 147 | public int getMessageField(String fieldName) { 148 | List fields = messageCaptor.getValue().getFields(); 149 | for (FieldValue field : fields) { 150 | if (fieldName.equals(field.getName())) { 151 | return field.getValue(); 152 | } 153 | } 154 | return -1; 155 | } 156 | 157 | @Test 158 | public void basicJir() { 159 | JirFileTestPlayer player = new JirFileTestPlayer(JirFileTestPlayer.OREGON_DECODER); 160 | 161 | // Using a known test vector 162 | player.playFile(this.getClass().getClassLoader() 163 | .getResourceAsStream("nu/nethome/coders/decoders/oregon1.jir")); 164 | 165 | assertThat(player.getMessageField(0, "SensorId"), is(0x1D20)); 166 | assertThat(player.getMessageField(0, "Channel"), is(1)); 167 | assertThat(player.getMessageField(0, "Id"), is(0xEB)); 168 | assertThat(player.getMessageField(0, "Temp"), is(263)); 169 | assertThat(player.getMessageField(0, "Moisture"), is(20)); 170 | assertThat(player.getMessageField(0, "LowBattery"), is(0)); 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /src/test/java/nu/nethome/coders/decoders/PrologueDecoderTest.java: -------------------------------------------------------------------------------- 1 | package nu.nethome.coders.decoders; 2 | 3 | import nu.nethome.coders.decoders.util.JirFileTestPlayer; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | 7 | import static org.hamcrest.MatcherAssert.assertThat; 8 | import static org.hamcrest.Matchers.is; 9 | import static org.junit.Assert.*; 10 | 11 | public class PrologueDecoderTest { 12 | 13 | @Before 14 | public void setUp() throws Exception { 15 | } 16 | 17 | @Test 18 | public void basicJir() { 19 | JirFileTestPlayer player = new JirFileTestPlayer(JirFileTestPlayer.PROLOGUE_DECODER); 20 | 21 | // Using a known test vector 22 | player.playFile(this.getClass().getClassLoader() 23 | .getResourceAsStream("nu/nethome/coders/decoders/prologue.jir")); 24 | 25 | assertThat(player.m_Messages.size(), is(5)); 26 | assertThat(player.m_Messages.get(4).getRepeat(), is(4)); 27 | assertThat(player.getMessageField(0, "Temp"), is(261)); 28 | assertThat(player.getMessageField(0, "Button"), is(1)); 29 | assertThat(player.getMessageField(0, "Battery"), is(0)); 30 | assertThat(player.getMessageField(0, "RollingId"), is(80)); 31 | assertThat(player.getMessageField(0, "Channel"), is(0)); 32 | assertThat(player.getMessageField(0, "Humidity"), is(204)); 33 | assertThat(player.getMessageField(0, "Id"), is(9)); 34 | } 35 | } -------------------------------------------------------------------------------- /src/test/java/nu/nethome/coders/decoders/RollerTrolDecoderTest.java: -------------------------------------------------------------------------------- 1 | package nu.nethome.coders.decoders; 2 | 3 | import nu.nethome.coders.RollerTrol; 4 | import nu.nethome.coders.decoders.util.JirFileTestPlayer; 5 | import org.junit.Test; 6 | 7 | import static nu.nethome.coders.RollerTrol.*; 8 | import static org.hamcrest.MatcherAssert.assertThat; 9 | import static org.hamcrest.Matchers.is; 10 | 11 | public class RollerTrolDecoderTest { 12 | public void setUp() throws Exception { 13 | 14 | } 15 | 16 | @Test 17 | public void basicJir() { 18 | JirFileTestPlayer player = new JirFileTestPlayer(JirFileTestPlayer.ROLLERTROL_DECODER); 19 | 20 | // Using a known test vector 21 | player.playFile(this.getClass().getClassLoader() 22 | .getResourceAsStream("nu/nethome/coders/decoders/rollertrol_3_stop.jir")); 23 | 24 | assertThat(player.getMessageField(0, DEVICE_CODE_NAME), is(3)); 25 | assertThat(player.getMessageField(0, COMMAND_NAME), is(STOP)); 26 | assertThat(player.getMessageField(0, HOUSE_CODE_NAME), is(36600)); 27 | assertThat(player.m_Messages.size(), is(15)); 28 | assertThat(player.m_Messages.get(14).getRepeat(), is(14)); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/nu/nethome/coders/decoders/RollerTrolGDecoderTest.java: -------------------------------------------------------------------------------- 1 | package nu.nethome.coders.decoders; 2 | 3 | import nu.nethome.coders.RollerTrolG; 4 | import nu.nethome.coders.encoders.RisingSunEncoder; 5 | import nu.nethome.coders.encoders.RollerTrolGEncoder; 6 | import nu.nethome.util.ps.BadMessageException; 7 | import nu.nethome.util.ps.Message; 8 | import nu.nethome.util.ps.MessageRepeater; 9 | import nu.nethome.util.ps.impl.PulseTestPlayer; 10 | import org.junit.Before; 11 | import org.junit.Test; 12 | 13 | import static org.hamcrest.MatcherAssert.assertThat; 14 | import static org.hamcrest.Matchers.is; 15 | import static org.junit.Assert.assertEquals; 16 | 17 | 18 | public class RollerTrolGDecoderTest { 19 | 20 | public static final int CHANNEL = 3; 21 | public static final int ADDRESS = 123456; 22 | private RollerTrolGEncoder encoder; 23 | private PulseTestPlayer player; 24 | private RollerTrolGDecoder decoder; 25 | 26 | @Before 27 | public void setUp() throws Exception { 28 | encoder = new RollerTrolGEncoder(); 29 | player = new PulseTestPlayer(); 30 | decoder = new RollerTrolGDecoder(); 31 | decoder.setTarget(player); 32 | player.setDecoder(decoder); 33 | player.setPulseWidthModification(0); 34 | 35 | } 36 | 37 | @Test 38 | public void testNewEncoderInterface() throws BadMessageException { 39 | Message toSend = RollerTrolGEncoder.buildMessage(RollerTrolG.COMMAND_STOP, ADDRESS, CHANNEL); 40 | player.playMessage(MessageRepeater.repeat(encoder, toSend, 1)); 41 | assertThat(player.getMessageCount(), is(1)); 42 | assertThat(player.getMessageField(0, RollerTrolG.COMMAND_NAME), is(RollerTrolG.COMMAND_STOP)); 43 | assertThat(player.getMessageField(0, RollerTrolG.ADDRESS_NAME), is(ADDRESS)); 44 | assertThat(player.getMessageField(0, RollerTrolG.CHANNEL_NAME), is(CHANNEL)); 45 | assertThat(player.getMessages()[0].getRepeat(), is(0)); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/test/java/nu/nethome/coders/decoders/TestDeltronicDecoderEncoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2013, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.decoders; 21 | 22 | import nu.nethome.coders.encoders.DeltronicEncoder; 23 | import nu.nethome.util.ps.BadMessageException; 24 | import nu.nethome.util.ps.Message; 25 | import nu.nethome.util.ps.MessageRepeater; 26 | import nu.nethome.util.ps.ProtocolInfo; 27 | import nu.nethome.util.ps.impl.PulseTestPlayer; 28 | import org.junit.After; 29 | import org.junit.Before; 30 | import org.junit.Test; 31 | 32 | import static org.hamcrest.CoreMatchers.is; 33 | import static org.junit.Assert.assertEquals; 34 | import static org.junit.Assert.assertThat; 35 | 36 | /** 37 | * Unit tests for DeltronicEncoder and DeltronicDecoder. 38 | * @author �garen 39 | * 40 | */ 41 | public class TestDeltronicDecoderEncoder { 42 | 43 | private DeltronicEncoder m_Encoder; 44 | private DeltronicDecoder m_Decoder; 45 | private PulseTestPlayer m_Player; 46 | 47 | @Before 48 | public void setUp() throws Exception { 49 | m_Encoder = new DeltronicEncoder(); 50 | m_Player = new PulseTestPlayer(); 51 | m_Decoder = new DeltronicDecoder(); 52 | m_Decoder.setTarget(m_Player); 53 | m_Player.setDecoder(m_Decoder); 54 | m_Player.setPulseWidthModification(0); 55 | } 56 | 57 | @After 58 | public void tearDown() throws Exception { 59 | } 60 | 61 | @Test 62 | public void testSetAddress() { 63 | assertEquals(0, m_Encoder.getAddress()); 64 | m_Encoder.setAddress(0x3F); 65 | assertEquals(0x3F, m_Encoder.getAddress()); 66 | m_Encoder.setAddress(0x40); 67 | assertEquals(0x3F, m_Encoder.getAddress()); 68 | } 69 | 70 | @Test 71 | public void testSetButton() { 72 | assertEquals(0, m_Encoder.getButton()); 73 | m_Encoder.setButton(2); 74 | assertEquals(2, m_Encoder.getButton()); 75 | m_Encoder.setButton(-1); 76 | assertEquals(2, m_Encoder.getButton()); 77 | m_Encoder.setButton(4); 78 | assertEquals(2, m_Encoder.getButton()); 79 | } 80 | 81 | @Test 82 | public void testSetCommand() { 83 | assertEquals(1, m_Encoder.getCommand()); 84 | m_Encoder.setCommand(0); 85 | assertEquals(0, m_Encoder.getCommand()); 86 | m_Encoder.setCommand(2); 87 | assertEquals(0, m_Encoder.getCommand()); 88 | } 89 | 90 | @Test 91 | public void testSetRepeatCount() { 92 | assertEquals(3, m_Encoder.getRepeatCount()); 93 | m_Encoder.setRepeatCount(5); 94 | assertEquals(5, m_Encoder.getRepeatCount()); 95 | m_Encoder.setRepeatCount(0); 96 | assertEquals(5, m_Encoder.getRepeatCount()); 97 | } 98 | 99 | @Test 100 | public void testSingleMessage() { 101 | m_Encoder.setRepeatCount(1); 102 | m_Encoder.setAddress(1); 103 | m_Encoder.setButton(2); 104 | m_Encoder.setCommand(1); 105 | m_Player.playMessage(m_Encoder.encode()); 106 | assertEquals(1, m_Player.getMessageCount()); 107 | assertEquals(1, m_Player.getMessageField(0, "Address")); 108 | assertEquals(2, m_Player.getMessageField(0, "Button")); 109 | assertEquals(1, m_Player.getMessageField(0, "Command")); 110 | assertEquals(0, m_Player.getMessages()[0].getRepeat()); 111 | } 112 | 113 | @Test 114 | public void testSingleMessageNewInterface() throws BadMessageException { 115 | Message toSend = DeltronicEncoder.buildCommandMessage(true, 2, 1); 116 | m_Player.playMessage(MessageRepeater.repeat(m_Encoder, toSend, 1)); 117 | assertEquals(1, m_Player.getMessageCount()); 118 | assertEquals(1, m_Player.getMessageField(0, "Address")); 119 | assertEquals(2, m_Player.getMessageField(0, "Button")); 120 | assertEquals(1, m_Player.getMessageField(0, "Command")); 121 | assertEquals(0, m_Player.getMessages()[0].getRepeat()); 122 | } 123 | 124 | @Test 125 | public void testTwoMessages() { 126 | m_Encoder.setRepeatCount(2); 127 | m_Encoder.setAddress(0x1A); 128 | m_Encoder.setButton(3); 129 | m_Encoder.setCommand(0); 130 | m_Player.playMessage(m_Encoder.encode()); 131 | assertEquals(2, m_Player.getMessageCount()); 132 | assertEquals(0x1A, m_Player.getMessageField(0, "Address")); 133 | assertEquals(3, m_Player.getMessageField(0, "Button")); 134 | assertEquals(0, m_Player.getMessageField(0, "Command")); 135 | assertEquals(0, m_Player.getMessages()[0].getRepeat()); 136 | assertEquals(0x1A, m_Player.getMessageField(1, "Address")); 137 | assertEquals(3, m_Player.getMessageField(1, "Button")); 138 | assertEquals(0, m_Player.getMessageField(1, "Command")); 139 | assertEquals(1, m_Player.getMessages()[1].getRepeat()); 140 | } 141 | 142 | @Test 143 | public void testTwoMessagesNewInterface() throws BadMessageException { 144 | Message toSend = DeltronicEncoder.buildCommandMessage(false, 3, 0x1a); 145 | m_Player.playMessage(MessageRepeater.repeat(m_Encoder, toSend, 2)); 146 | assertEquals(2, m_Player.getMessageCount()); 147 | assertEquals(0x1A, m_Player.getMessageField(0, "Address")); 148 | assertEquals(3, m_Player.getMessageField(0, "Button")); 149 | assertEquals(0, m_Player.getMessageField(0, "Command")); 150 | assertEquals(0, m_Player.getMessages()[0].getRepeat()); 151 | assertEquals(0x1A, m_Player.getMessageField(1, "Address")); 152 | assertEquals(3, m_Player.getMessageField(1, "Button")); 153 | assertEquals(0, m_Player.getMessageField(1, "Command")); 154 | assertEquals(1, m_Player.getMessages()[1].getRepeat()); 155 | } 156 | 157 | @Test 158 | public void info() { 159 | ProtocolInfo info = m_Encoder.getInfo(); 160 | assertThat(info.getName(), is("Deltronic")); 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/test/java/nu/nethome/coders/decoders/TestNexaFire.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2013, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.decoders; 21 | 22 | import nu.nethome.coders.decoders.util.JirFileTestPlayer; 23 | import nu.nethome.coders.encoders.NexaFireEncoder; 24 | import nu.nethome.util.ps.impl.PulseTestPlayer; 25 | import org.junit.After; 26 | import org.junit.Before; 27 | import org.junit.Test; 28 | 29 | import static org.junit.Assert.assertEquals; 30 | 31 | /** 32 | * Unit tests for NexaFireEncoder and NexaFireDecoder 33 | * @author Stefan 34 | * 35 | */ 36 | public class TestNexaFire { 37 | 38 | private NexaFireEncoder m_Encoder; 39 | private NexaFireDecoder m_Decoder; 40 | private PulseTestPlayer m_Player; 41 | 42 | @Before 43 | public void setUp() throws Exception { 44 | m_Encoder = new NexaFireEncoder(); 45 | m_Player = new PulseTestPlayer(); 46 | m_Decoder = new NexaFireDecoder(); 47 | m_Decoder.setTarget(m_Player); 48 | m_Player.setDecoder(m_Decoder); 49 | } 50 | 51 | @After 52 | public void tearDown() throws Exception { 53 | } 54 | 55 | @Test 56 | public void testSetAddress() { 57 | assertEquals(0, m_Encoder.getAddress()); 58 | m_Encoder.setAddress(255); 59 | assertEquals(255, m_Encoder.getAddress()); 60 | m_Encoder.setAddress(0x0FFFFFFF); 61 | assertEquals(255, m_Encoder.getAddress()); 62 | } 63 | 64 | @Test 65 | public void testSetRepeatCount() { 66 | assertEquals(15, m_Encoder.getRepeatCount()); 67 | m_Encoder.setRepeatCount(4); 68 | assertEquals(4, m_Encoder.getRepeatCount()); 69 | m_Encoder.setRepeatCount(0); 70 | assertEquals(4, m_Encoder.getRepeatCount()); 71 | } 72 | 73 | @Test 74 | public void testSingleMessage() { 75 | m_Encoder.setRepeatCount(1); 76 | m_Encoder.setAddress(1); 77 | m_Player.playMessage(m_Encoder.encode()); 78 | assertEquals(1, m_Player.getMessageCount()); 79 | assertEquals(1, m_Player.getMessageField(0, "Address")); 80 | } 81 | 82 | @Test 83 | public void testTwoMessages() { 84 | m_Encoder.setRepeatCount(2); 85 | m_Encoder.setAddress(0xFFFEFD); 86 | m_Player.playMessage(m_Encoder.encode()); 87 | assertEquals(2, m_Player.getMessageCount()); 88 | // Verify first message 89 | assertEquals(0xFFFEFD, m_Player.getMessageField(0, "Address")); 90 | assertEquals(0, m_Player.getMessages()[0].getRepeat()); 91 | // Verify second message 92 | assertEquals(0xFFFEFD, m_Player.getMessageField(1, "Address")); 93 | assertEquals(1, m_Player.getMessages()[1].getRepeat()); 94 | } 95 | 96 | @Test 97 | public void JirWalterK() { 98 | JirFileTestPlayer player = new JirFileTestPlayer(JirFileTestPlayer.ALL_DECODERS); 99 | player.m_FlankDetector.setFlankSwing(50); 100 | player.m_FlankDetector.setFlankLength(4); 101 | player.m_FlankDetector.setPulseWidthCompensation(0); 102 | 103 | // This file contains a NexaFire message repeated 11 times 104 | player.playFile(this.getClass().getClassLoader() 105 | .getResourceAsStream("nu/nethome/coders/decoders/nexa_fire.jir")); 106 | 107 | // Verify result 108 | assertEquals(8, player.m_Messages.size()); 109 | assertEquals("NexaFire", player.m_Messages.get(7).getProtocol()); 110 | assertEquals(7, player.m_Messages.get(7).getRepeat()); 111 | assertEquals(0x0BD6BC, player.getMessageField(7, "Address")); 112 | 113 | // assertEquals(0xBC, player.getMessageField(7, "Raw1")); 114 | // assertEquals(0xD6, player.getMessageField(7, "Raw2")); 115 | // assertEquals(0x0B, player.getMessageField(7, "Raw3")); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/test/java/nu/nethome/coders/decoders/TestNexaLDecoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2013, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.decoders; 21 | 22 | import nu.nethome.coders.decoders.util.JirFileTestPlayer; 23 | import nu.nethome.coders.encoders.NexaLEncoder; 24 | import nu.nethome.util.ps.BadMessageException; 25 | import nu.nethome.util.ps.Message; 26 | import nu.nethome.util.ps.MessageRepeater; 27 | import nu.nethome.util.ps.impl.PulseTestPlayer; 28 | import org.junit.After; 29 | import org.junit.Before; 30 | import org.junit.Test; 31 | 32 | import static org.junit.Assert.assertEquals; 33 | 34 | /** 35 | * Unit tests for NexaLEncoder and NexaLDecoder 36 | * @author Stefan 37 | * 38 | */ 39 | public class TestNexaLDecoder { 40 | 41 | private NexaLEncoder m_Encoder; 42 | private NexaLDecoder m_Decoder; 43 | private PulseTestPlayer m_Player; 44 | 45 | @Before 46 | public void setUp() throws Exception { 47 | m_Encoder = new NexaLEncoder(); 48 | m_Player = new PulseTestPlayer(); 49 | m_Decoder = new NexaLDecoder(); 50 | m_Decoder.setTarget(m_Player); 51 | m_Player.setDecoder(m_Decoder); 52 | } 53 | 54 | @After 55 | public void tearDown() throws Exception { 56 | } 57 | 58 | @Test 59 | public void testSetAddress() { 60 | assertEquals(0, m_Encoder.getAddress()); 61 | m_Encoder.setAddress(0xaabbcc); 62 | assertEquals(0xaabbcc, m_Encoder.getAddress()); 63 | } 64 | 65 | @Test 66 | public void testSetButton() { 67 | assertEquals(1, m_Encoder.getButton()); 68 | m_Encoder.setButton(3); 69 | assertEquals(3, m_Encoder.getButton()); 70 | m_Encoder.setButton(16); 71 | assertEquals(16, m_Encoder.getButton()); 72 | m_Encoder.setButton(17); 73 | assertEquals(17, m_Encoder.getButton()); 74 | } 75 | 76 | @Test 77 | public void testSetCommand() { 78 | assertEquals(1, m_Encoder.getCommand()); 79 | m_Encoder.setCommand(0); 80 | assertEquals(0, m_Encoder.getCommand()); 81 | m_Encoder.setCommand(2); 82 | assertEquals(0, m_Encoder.getCommand()); 83 | } 84 | 85 | @Test 86 | public void testSetRepeatCount() { 87 | assertEquals(5, m_Encoder.getRepeatCount()); 88 | m_Encoder.setRepeatCount(4); 89 | assertEquals(4, m_Encoder.getRepeatCount()); 90 | m_Encoder.setRepeatCount(0); 91 | assertEquals(4, m_Encoder.getRepeatCount()); 92 | } 93 | 94 | @Test 95 | public void testSingleMessage() { 96 | m_Encoder.setRepeatCount(1); 97 | m_Encoder.setAddress(0xaabbcc); 98 | m_Encoder.setButton(3); 99 | m_Encoder.setCommand(1); 100 | m_Player.playMessage(m_Encoder.encode()); 101 | assertEquals(1, m_Player.getMessageCount()); 102 | assertEquals(0xaabbcc, m_Player.getMessageField(0, "Address")); 103 | assertEquals(3, m_Player.getMessageField(0, "Button")); 104 | assertEquals(1, m_Player.getMessageField(0, "Command")); 105 | } 106 | 107 | @Test 108 | public void testSingleMessageNewEncoder() throws BadMessageException { 109 | Message toSend = NexaLEncoder.buildMessage(1, 3, 0xaabbcc); 110 | m_Player.playMessage(MessageRepeater.repeat(m_Encoder, toSend, 1)); 111 | assertEquals(1, m_Player.getMessageCount()); 112 | assertEquals(0xaabbcc, m_Player.getMessageField(0, "Address")); 113 | assertEquals(3, m_Player.getMessageField(0, "Button")); 114 | assertEquals(1, m_Player.getMessageField(0, "Command")); 115 | } 116 | 117 | @Test 118 | public void testTwoMessages() { 119 | m_Encoder.setRepeatCount(2); 120 | m_Encoder.setAddress(0x3ffffff); 121 | m_Encoder.setButton(17); 122 | m_Encoder.setCommand(0); 123 | m_Player.playMessage(m_Encoder.encode()); 124 | assertEquals(2, m_Player.getMessageCount()); 125 | assertEquals(0x3ffffff, m_Player.getMessageField(0, "Address")); 126 | assertEquals(17, m_Player.getMessageField(0, "Button")); 127 | assertEquals(0, m_Player.getMessageField(0, "Command")); 128 | assertEquals(0, m_Player.getMessages()[0].getRepeat()); 129 | assertEquals(0x3ffffff, m_Player.getMessageField(1, "Address")); 130 | //assertEquals(17, m_Player.getMessageField(1, "Button")); 131 | assertEquals(0, m_Player.getMessageField(1, "Command")); 132 | assertEquals(1, m_Player.getMessages()[1].getRepeat()); 133 | } 134 | 135 | @Test 136 | public void testThreeMessages() { 137 | m_Encoder.setRepeatCount(3); 138 | m_Encoder.setAddress(0x248a957); 139 | m_Encoder.setButton(17); 140 | m_Encoder.setCommand(0); 141 | m_Player.playMessage(m_Encoder.encode()); 142 | assertEquals(3, m_Player.getMessageCount()); 143 | assertEquals(0x248a957, m_Player.getMessageField(0, "Address")); 144 | assertEquals(17, m_Player.getMessageField(0, "Button")); 145 | assertEquals(0, m_Player.getMessageField(0, "Command")); 146 | assertEquals(0, m_Player.getMessages()[0].getRepeat()); 147 | assertEquals(0x248a957, m_Player.getMessageField(1, "Address")); 148 | //assertEquals(17, m_Player.getMessageField(1, "Button")); 149 | //assertEquals(0, m_Player.getMessageField(1, "Command")); 150 | assertEquals(1, m_Player.getMessages()[1].getRepeat()); 151 | assertEquals(0x248a957, m_Player.getMessageField(2, "Address")); 152 | assertEquals(17, m_Player.getMessageField(2, "Button")); 153 | assertEquals(0, m_Player.getMessageField(2, "Command")); 154 | assertEquals(2, m_Player.getMessages()[2].getRepeat()); 155 | } 156 | 157 | @Test 158 | public void basicJir() { 159 | JirFileTestPlayer player = new JirFileTestPlayer(JirFileTestPlayer.ALL_DECODERS); 160 | 161 | // This file contains a NexaL message repeated 11 times 162 | player.playFile(this.getClass().getClassLoader() 163 | .getResourceAsStream("nu/nethome/coders/decoders/nexal1.jir")); 164 | 165 | // Verify result 166 | assertEquals(11, player.m_Messages.size()); 167 | assertEquals("NexaL", player.m_Messages.get(10).getProtocol()); 168 | assertEquals(10, player.m_Messages.get(10).getRepeat()); 169 | assertEquals(0x155be6, player.getMessageField(10, "Address")); 170 | assertEquals(10, player.getMessageField(10, "Button")); 171 | } 172 | 173 | @Test 174 | public void JirDavidNaslund() { 175 | JirFileTestPlayer player = new JirFileTestPlayer(JirFileTestPlayer.ALL_DECODERS); 176 | player.m_FlankDetector.setFlankSwing(40); 177 | player.m_FlankDetector.setFlankLength(4); 178 | player.m_FlankDetector.setPulseWidthCompensation(0); 179 | 180 | // This file contains a NexaL message repeated 11 times 181 | player.playFile(this.getClass().getClassLoader() 182 | .getResourceAsStream("nu/nethome/coders/decoders/nexal_dn.jir")); 183 | 184 | // Verify result 185 | assertEquals(5, player.m_Messages.size()); 186 | assertEquals("NexaL", player.m_Messages.get(4).getProtocol()); 187 | assertEquals(4, player.m_Messages.get(4).getRepeat()); 188 | assertEquals(0x2b38aa, player.getMessageField(4, "Address")); 189 | assertEquals(11, player.getMessageField(4, "Button")); 190 | } 191 | 192 | } 193 | -------------------------------------------------------------------------------- /src/test/java/nu/nethome/coders/decoders/TestProntoDecoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2013, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.decoders; 21 | 22 | import nu.nethome.coders.encoders.ProntoEncoder; 23 | import nu.nethome.util.ps.BadMessageException; 24 | import nu.nethome.util.ps.Message; 25 | import nu.nethome.util.ps.MessageRepeater; 26 | import nu.nethome.util.ps.ProtocolEncoder; 27 | import nu.nethome.util.ps.impl.PulseTestPlayer; 28 | import org.junit.After; 29 | import org.junit.Before; 30 | import org.junit.Test; 31 | 32 | import static org.hamcrest.CoreMatchers.is; 33 | import static org.junit.Assert.*; 34 | 35 | /** 36 | * Unit tests for X10Encoder and X10Decoder. 37 | * @author �garen 38 | * 39 | */ 40 | public class TestProntoDecoder { 41 | 42 | private ProntoEncoder m_Encoder; 43 | private ProntoDecoder m_Decoder; 44 | private PulseTestPlayer m_Player; 45 | 46 | @Before 47 | public void setUp() throws Exception { 48 | m_Encoder = new ProntoEncoder(); 49 | m_Player = new PulseTestPlayer(); 50 | m_Decoder = new ProntoDecoder(); 51 | m_Decoder.setTarget(m_Player); 52 | m_Player.setDecoder(m_Decoder); 53 | } 54 | 55 | @After 56 | public void tearDown() throws Exception { 57 | } 58 | 59 | @Test 60 | public void testGeneral() { 61 | m_Decoder.addBurst(10000, false); 62 | } 63 | @Test 64 | public void testSetCommand() { 65 | assertEquals("", m_Encoder.getMessage()); 66 | m_Encoder.setMessage("0000 1111 2222"); 67 | assertEquals("0000 1111 2222", m_Encoder.getMessage()); 68 | } 69 | 70 | @Test 71 | public void testSetRepeatCount() { 72 | assertEquals(5, m_Encoder.getRepeatCount()); 73 | m_Encoder.setRepeatCount(6); 74 | assertEquals(6, m_Encoder.getRepeatCount()); 75 | m_Encoder.setRepeatCount(0); 76 | assertEquals(6, m_Encoder.getRepeatCount()); 77 | } 78 | 79 | protected final String sonyMessage1 = 80 | "0000 0067 0000 0015 0060 0018 0018 0018 0030 0018 0030 0018 0030 " + 81 | "0018 0018 0018 0030 0018 0018 0018 0018 0018 0030 0018 0018 0018 " + 82 | "0030 0018 0030 0018 0030 0018 0018 0018 0018 0018 0030 0018 0018 " + 83 | "0018 0018 0018 0030 0018 0018 03f6"; 84 | 85 | protected final String sonyMessage2 = 86 | "0000 0067 0001 0014 0060 0018 0018 0018 0030 0018 0030 0018 0030 " + 87 | "0018 0018 0018 0030 0018 0018 0018 0018 0018 0030 0018 0018 0018 " + 88 | "0030 0018 0030 0018 0030 0018 0018 0018 0018 0018 0030 0018 0018 " + 89 | "0018 0018 0018 0030 0018 0018 03f6"; 90 | 91 | @Test 92 | public void testSingleEncodingNoHeader() throws BadMessageException { 93 | Message toSend = ProntoEncoder.createMessage(sonyMessage1); 94 | int header[] = m_Encoder.encode(toSend, ProtocolEncoder.Phase.FIRST); 95 | int body[] = m_Encoder.encode(toSend, ProtocolEncoder.Phase.REPEATED); 96 | assertThat(header.length, is(0)); 97 | assertThat(body.length, is(42)); 98 | } 99 | 100 | @Test 101 | public void testSingleEncodingWithHeader() throws BadMessageException { 102 | Message toSend = ProntoEncoder.createMessage(sonyMessage2); 103 | int header[] = m_Encoder.encode(toSend, ProtocolEncoder.Phase.FIRST); 104 | int body[] = m_Encoder.encode(toSend, ProtocolEncoder.Phase.REPEATED); 105 | assertThat(header.length, is(2)); 106 | assertThat(body.length, is(40)); 107 | } 108 | 109 | 110 | @Test 111 | public void testSingleMessageNoMod() { 112 | m_Encoder.setRepeatCount(1); 113 | m_Encoder.setMessage(sonyMessage1); 114 | m_Player.setPulseWidthModification(0); 115 | m_Decoder.setPulseWidthModification(0); 116 | m_Player.playMessage(m_Encoder.encode()); 117 | assertEquals(1, m_Player.getMessageCount()); 118 | assertEquals(sonyMessage1, m_Player.getMessageFieldString(0, "Message")); 119 | assertEquals(0, m_Player.getMessages()[0].getRepeat()); 120 | } 121 | 122 | @Test 123 | public void testSingleMessageMod() { 124 | m_Encoder.setRepeatCount(1); 125 | m_Encoder.setMessage(sonyMessage1); 126 | m_Player.setPulseWidthModification(60); 127 | m_Decoder.setPulseWidthModification(60); 128 | m_Player.playMessage(m_Encoder.encode()); 129 | assertEquals(1, m_Player.getMessageCount()); 130 | assertEquals(sonyMessage1, m_Player.getMessageFieldString(0, "Message")); 131 | assertEquals(0, m_Player.getMessages()[0].getRepeat()); 132 | } 133 | 134 | @Test 135 | public void testSingleMessageFailMod() { 136 | m_Encoder.setRepeatCount(1); 137 | m_Encoder.setMessage(sonyMessage1); 138 | m_Player.setPulseWidthModification(0); 139 | m_Decoder.setPulseWidthModification(60); 140 | m_Player.playMessage(m_Encoder.encode()); 141 | assertEquals(1, m_Player.getMessageCount()); 142 | assertFalse(sonyMessage1.equals(m_Player.getMessageFieldString(0, "Message"))); 143 | assertEquals(0, m_Player.getMessages()[0].getRepeat()); 144 | } 145 | 146 | @Test 147 | public void testThreeMessages() { 148 | m_Encoder.setRepeatCount(3); 149 | m_Encoder.setMessage(sonyMessage1); 150 | m_Player.setPulseWidthModification(60); 151 | m_Decoder.setPulseWidthModification(60); 152 | m_Player.playMessage(m_Encoder.encode()); 153 | assertEquals(3, m_Player.getMessageCount()); 154 | assertEquals(sonyMessage1, m_Player.getMessageFieldString(0, "Message")); 155 | assertEquals(0, m_Player.getMessages()[0].getRepeat()); 156 | assertEquals(sonyMessage1, m_Player.getMessageFieldString(1, "Message")); 157 | assertEquals(0, m_Player.getMessages()[1].getRepeat()); 158 | assertEquals(sonyMessage1, m_Player.getMessageFieldString(2, "Message")); 159 | assertEquals(0, m_Player.getMessages()[2].getRepeat()); 160 | } 161 | 162 | @Test 163 | public void testThreeMessagesNewInterface() throws BadMessageException { 164 | Message toSend = ProntoEncoder.createMessage(sonyMessage1); 165 | m_Player.playMessage(MessageRepeater.repeat(m_Encoder, toSend, 3)); 166 | assertEquals(3, m_Player.getMessageCount()); 167 | assertEquals(sonyMessage1, m_Player.getMessageFieldString(0, "Message")); 168 | assertEquals(0, m_Player.getMessages()[0].getRepeat()); 169 | assertEquals(sonyMessage1, m_Player.getMessageFieldString(1, "Message")); 170 | assertEquals(0, m_Player.getMessages()[1].getRepeat()); 171 | assertEquals(sonyMessage1, m_Player.getMessageFieldString(2, "Message")); 172 | assertEquals(0, m_Player.getMessages()[2].getRepeat()); 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /src/test/java/nu/nethome/coders/decoders/TestWaveman.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2013, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.decoders; 21 | 22 | import nu.nethome.coders.decoders.util.JirFileTestPlayer; 23 | import nu.nethome.coders.encoders.WavemanEncoder; 24 | import nu.nethome.util.ps.impl.PulseTestPlayer; 25 | import org.junit.After; 26 | import org.junit.Before; 27 | import org.junit.Test; 28 | 29 | import static org.junit.Assert.assertEquals; 30 | 31 | /** 32 | * Unit tests for WavemanEncoder and WavemanDecoder. 33 | * @author Stefan 34 | * 35 | */ 36 | public class TestWaveman { 37 | 38 | private WavemanEncoder m_Encoder; 39 | private WavemanDecoder m_Decoder; 40 | private PulseTestPlayer m_Player; 41 | 42 | @Before 43 | public void setUp() throws Exception { 44 | m_Encoder = new WavemanEncoder(); 45 | m_Player = new PulseTestPlayer(); 46 | m_Decoder = new WavemanDecoder(); 47 | m_Decoder.setTarget(m_Player); 48 | m_Player.setDecoder(m_Decoder); 49 | m_Player.setPulseWidthModification(0); 50 | } 51 | 52 | @After 53 | public void tearDown() throws Exception { 54 | } 55 | 56 | @Test 57 | public void testSetAddress() { 58 | assertEquals('A', m_Encoder.getAddress()); 59 | m_Encoder.setAddress('F'); 60 | assertEquals('F', m_Encoder.getAddress()); 61 | } 62 | 63 | @Test 64 | public void testSetButton() { 65 | assertEquals(1, m_Encoder.getButton()); 66 | m_Encoder.setButton(2); 67 | assertEquals(2, m_Encoder.getButton()); 68 | m_Encoder.setButton(0); 69 | assertEquals(2, m_Encoder.getButton()); 70 | } 71 | 72 | @Test 73 | public void testSetCommand() { 74 | assertEquals(1, m_Encoder.getCommand()); 75 | m_Encoder.setCommand(0); 76 | assertEquals(0, m_Encoder.getCommand()); 77 | m_Encoder.setCommand(2); 78 | assertEquals(0, m_Encoder.getCommand()); 79 | } 80 | 81 | @Test 82 | public void testSetRepeatCount() { 83 | assertEquals(5, m_Encoder.getRepeatCount()); 84 | m_Encoder.setRepeatCount(6); 85 | assertEquals(6, m_Encoder.getRepeatCount()); 86 | m_Encoder.setRepeatCount(0); 87 | assertEquals(6, m_Encoder.getRepeatCount()); 88 | } 89 | 90 | @Test 91 | public void testSingleMessage() { 92 | m_Encoder.setRepeatCount(1); 93 | m_Encoder.setAddress('B'); 94 | m_Encoder.setButton(2); 95 | m_Encoder.setCommand(1); 96 | m_Player.playMessage(m_Encoder.encode()); 97 | assertEquals(1, m_Player.getMessageCount()); 98 | assertEquals(1, m_Player.getMessageField(0, "HouseCode")); 99 | assertEquals(2, m_Player.getMessageField(0, "Button")); 100 | assertEquals(1, m_Player.getMessageField(0, "Command")); 101 | assertEquals(0, m_Player.getMessages()[0].getRepeat()); 102 | } 103 | 104 | @Test 105 | public void testTwoMessages() { 106 | m_Encoder.setRepeatCount(2); 107 | m_Encoder.setAddress('H'); 108 | m_Encoder.setButton(8); 109 | m_Encoder.setCommand(0); 110 | m_Player.playMessage(m_Encoder.encode()); 111 | assertEquals(2, m_Player.getMessageCount()); 112 | assertEquals(7, m_Player.getMessageField(0, "HouseCode")); 113 | assertEquals(8, m_Player.getMessageField(0, "Button")); 114 | assertEquals(0, m_Player.getMessageField(0, "Command")); 115 | assertEquals(0, m_Player.getMessages()[0].getRepeat()); 116 | assertEquals(7, m_Player.getMessageField(1, "HouseCode")); 117 | assertEquals(8, m_Player.getMessageField(1, "Button")); 118 | assertEquals(0, m_Player.getMessageField(1, "Command")); 119 | assertEquals(1, m_Player.getMessages()[1].getRepeat()); 120 | } 121 | 122 | @Test 123 | public void testThreeMessages() { 124 | m_Encoder.setRepeatCount(3); 125 | m_Encoder.setAddress('H'); 126 | m_Encoder.setButton(8); 127 | m_Encoder.setCommand(0); 128 | m_Player.playMessage(m_Encoder.encode()); 129 | assertEquals(3, m_Player.getMessageCount()); 130 | assertEquals(7, m_Player.getMessageField(0, "HouseCode")); 131 | assertEquals(8, m_Player.getMessageField(0, "Button")); 132 | assertEquals(0, m_Player.getMessageField(0, "Command")); 133 | assertEquals(0, m_Player.getMessages()[0].getRepeat()); 134 | assertEquals(7, m_Player.getMessageField(1, "HouseCode")); 135 | assertEquals(8, m_Player.getMessageField(1, "Button")); 136 | assertEquals(0, m_Player.getMessageField(1, "Command")); 137 | assertEquals(1, m_Player.getMessages()[1].getRepeat()); 138 | assertEquals(7, m_Player.getMessageField(2, "HouseCode")); 139 | assertEquals(8, m_Player.getMessageField(2, "Button")); 140 | assertEquals(0, m_Player.getMessageField(2, "Command")); 141 | assertEquals(2, m_Player.getMessages()[2].getRepeat()); 142 | } 143 | 144 | @Test 145 | public void basicJir() { 146 | JirFileTestPlayer player = new JirFileTestPlayer(JirFileTestPlayer.ALL_DECODERS - JirFileTestPlayer.Nexa_DECODER); 147 | 148 | // This file contains a Waveman message repeated 6 times 149 | player.playFile(this.getClass().getClassLoader() 150 | .getResourceAsStream("nu/nethome/coders/decoders/nexa1.jir")); 151 | 152 | // Verify result 153 | assertEquals(6, player.m_Messages.size()); 154 | assertEquals("Waveman", player.m_Messages.get(5).getProtocol()); 155 | assertEquals(5, player.m_Messages.get(5).getRepeat()); 156 | assertEquals(1, player.getMessageField(5, "Command")); 157 | assertEquals(3, player.getMessageField(5, "Button")); 158 | assertEquals(2, player.getMessageField(5, "HouseCode")); 159 | } 160 | 161 | } 162 | -------------------------------------------------------------------------------- /src/test/java/nu/nethome/coders/decoders/ZhejiangDecoderTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2013, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.decoders; 21 | 22 | import nu.nethome.coders.encoders.ZhejiangEncoder; 23 | import nu.nethome.util.ps.BadMessageException; 24 | import nu.nethome.util.ps.FieldValue; 25 | import nu.nethome.util.ps.Message; 26 | import nu.nethome.util.ps.ProtocolEncoder; 27 | import nu.nethome.util.ps.impl.PulseTestPlayer; 28 | import org.junit.Before; 29 | import org.junit.Test; 30 | 31 | import static org.hamcrest.Matchers.hasItem; 32 | import static org.hamcrest.Matchers.is; 33 | import static org.junit.Assert.assertThat; 34 | 35 | /** 36 | * User: Stefan 37 | * Date: 2013-03-24 38 | * Time: 22:26 39 | */ 40 | public class ZhejiangDecoderTest { 41 | private ZhejiangEncoder encoder; 42 | private ZhejiangDecoder decoder; 43 | private PulseTestPlayer player; 44 | 45 | @Before 46 | public void setUp() throws Exception { 47 | encoder = new ZhejiangEncoder(); 48 | player = new PulseTestPlayer(); 49 | decoder = new ZhejiangDecoder(); 50 | decoder.setTarget(player); 51 | player.setDecoder(decoder); 52 | player.setPulseWidthModification(0); 53 | } 54 | 55 | @Test 56 | public void canCreateCommand() { 57 | Message message = ZhejiangEncoder.buildMessage(1, 2, 3); 58 | assertThat(message.getFields().size(), is(3)); 59 | assertThat(message.getFields(), hasItem(new FieldValue("Command", 1))); 60 | assertThat(message.getFields(), hasItem(new FieldValue("Button", 2))); 61 | assertThat(message.getFields(), hasItem(new FieldValue("Address", 3))); 62 | } 63 | 64 | @Test 65 | public void canDecodeEncodedMessage() throws BadMessageException { 66 | player.playMessage(encoder.encode(ZhejiangEncoder.buildMessage(1, 2, 3), ProtocolEncoder.Phase.REPEATED)); 67 | assertThat(player.getMessageCount(), is(1)); 68 | assertThat(player.getMessageField(0, "Command"), is(1)); 69 | assertThat(player.getMessageField(0, "Button"), is(2)); 70 | assertThat(player.getMessageField(0, "Address"), is(3)); 71 | assertThat(player.getMessages()[0].getRepeat(), is(0)); 72 | } 73 | 74 | @Test 75 | public void CompareWithKnownOnTestVector() throws BadMessageException { 76 | player.playMessage(encoder.encode(ZhejiangEncoder.buildMessage(1, 2, 0), ProtocolEncoder.Phase.REPEATED)); 77 | assertThat(player.getMessageCount(), is(1)); 78 | assertThat(player.getMessages()[0].getRawMessage()[0], is(0)); 79 | assertThat(player.getMessages()[0].getRawMessage()[1], is(0x2A)); 80 | assertThat(player.getMessages()[0].getRawMessage()[2], is(0x2B)); 81 | assertThat(player.getMessages()[0].getRawMessage()[3], is(0xFF)); 82 | } 83 | 84 | @Test 85 | public void CompareWithKnownOffTestVector() throws BadMessageException { 86 | player.playMessage(encoder.encode(ZhejiangEncoder.buildMessage(0, 2, 0), ProtocolEncoder.Phase.REPEATED)); 87 | assertThat(player.getMessageCount(), is(1)); 88 | assertThat(player.getMessages()[0].getRawMessage()[0], is(0)); 89 | assertThat(player.getMessages()[0].getRawMessage()[1], is(0x8A)); 90 | assertThat(player.getMessages()[0].getRawMessage()[2], is(0x2B)); 91 | assertThat(player.getMessages()[0].getRawMessage()[3], is(0xFF)); 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /src/test/java/nu/nethome/coders/decoders/util/JirFileTestPlayer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2005-2013, Stefan Strömberg 3 | * 4 | * This file is part of OpenNetHome (http://www.nethome.nu). 5 | * 6 | * OpenNetHome is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * OpenNetHome is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | package nu.nethome.coders.decoders.util; 21 | 22 | import nu.nethome.coders.decoders.*; 23 | import nu.nethome.util.ps.FieldValue; 24 | import nu.nethome.util.ps.ProtocolDecoderSink; 25 | import nu.nethome.util.ps.ProtocolMessage; 26 | import nu.nethome.util.ps.RawProtocolMessage; 27 | import nu.nethome.util.ps.impl.FIRFilter6000; 28 | import nu.nethome.util.ps.impl.ProtocolDecoderGroup; 29 | import nu.nethome.util.ps.impl.SimpleFlankDetector; 30 | 31 | import java.io.IOException; 32 | import java.io.InputStream; 33 | import java.io.ObjectInputStream; 34 | import java.util.ArrayList; 35 | import java.util.List; 36 | 37 | public class JirFileTestPlayer implements ProtocolDecoderSink{ 38 | 39 | public static final int SIRC_DECODER = 1 << 0; 40 | public static final int RC6_DECODER = 1 << 1; 41 | public static final int RC5_DECODER = 1 << 2; 42 | public static final int JVC_DECODER = 1 << 3; 43 | public static final int Viasat_DECODER = 1 << 4; 44 | public static final int Pioneer_DECODER = 1 << 5; 45 | public static final int HK_DECODER = 1 << 6; 46 | public static final int UPM_DECODER = 1 << 7; 47 | public static final int Nexa_DECODER = 1 << 8; 48 | public static final int NexaL_DECODER = 1 << 9; 49 | public static final int Deltronic_DECODER = 1 << 10; 50 | public static final int X10_DECODER = 1 << 11; 51 | public static final int Waveman_DECODER = 1 << 12; 52 | public static final int NexaFire_DECODER = 1 << 13; 53 | public static final int OREGON_DECODER = 1 << 14; 54 | public static final int FINE_OFFSET_DECODER = 1 << 15; 55 | public static final int ROLLERTROL_DECODER = 1 << 16; 56 | public static final int ROLLERTROL_G_DECODER = 1 << 17; 57 | public static final int PROLOGUE_DECODER = 1 << 18; 58 | 59 | public static final int ALL_DECODERS = 0x7FFFFFFF; 60 | 61 | 62 | public SimpleFlankDetector m_FlankDetector; 63 | public ProtocolDecoderGroup m_ProtocolDecoders = new ProtocolDecoderGroup(); 64 | public FIRFilter6000 m_Filter; 65 | 66 | public ArrayList m_Messages = new ArrayList(); 67 | public boolean m_PartlyParsedMessage = false; 68 | 69 | public JirFileTestPlayer(int decoders) { 70 | 71 | // Create the Protocol-Decoders and add them to the decoder group 72 | if ((decoders & SIRC_DECODER) != 0) m_ProtocolDecoders.add(new SIRCDecoder()); 73 | if ((decoders & RC6_DECODER) != 0) m_ProtocolDecoders.add(new RC6Decoder()); 74 | if ((decoders & RC5_DECODER) != 0) m_ProtocolDecoders.add(new RC5Decoder()); 75 | if ((decoders & JVC_DECODER) != 0) m_ProtocolDecoders.add(new JVCDecoder()); 76 | if ((decoders & Viasat_DECODER) != 0) m_ProtocolDecoders.add(new ViasatDecoder()); 77 | if ((decoders & Pioneer_DECODER) != 0) m_ProtocolDecoders.add(new PioneerDecoder()); 78 | if ((decoders & HK_DECODER) != 0) m_ProtocolDecoders.add(new HKDecoder()); 79 | if ((decoders & UPM_DECODER) != 0) m_ProtocolDecoders.add(new UPMDecoder()); 80 | if ((decoders & Nexa_DECODER) != 0) m_ProtocolDecoders.add(new NexaDecoder()); 81 | if ((decoders & NexaL_DECODER) != 0) m_ProtocolDecoders.add(new NexaLDecoder()); 82 | if ((decoders & Deltronic_DECODER) != 0) m_ProtocolDecoders.add(new DeltronicDecoder()); 83 | if ((decoders & X10_DECODER) != 0) m_ProtocolDecoders.add(new X10Decoder()); 84 | if ((decoders & Waveman_DECODER) != 0) m_ProtocolDecoders.add(new WavemanDecoder()); 85 | if ((decoders & NexaFire_DECODER) != 0) m_ProtocolDecoders.add(new NexaFireDecoder()); 86 | if ((decoders & OREGON_DECODER) != 0) m_ProtocolDecoders.add(new OregonDecoder()); 87 | if ((decoders & FINE_OFFSET_DECODER) != 0) m_ProtocolDecoders.add(new FineOffsetDecoder()); 88 | if ((decoders & ROLLERTROL_DECODER) != 0) m_ProtocolDecoders.add(new RollerTrolDecoder()); 89 | if ((decoders & ROLLERTROL_G_DECODER) != 0) m_ProtocolDecoders.add(new RollerTrolGDecoder()); 90 | if ((decoders & PROLOGUE_DECODER) != 0) m_ProtocolDecoders.add(new PrologueDecoder()); 91 | 92 | // Set the Sink - which is this class 93 | m_ProtocolDecoders.setTarget(this); 94 | 95 | // Create The Flank Detector and attach the decoders 96 | m_FlankDetector = new SimpleFlankDetector(); 97 | m_FlankDetector.setProtocolDecoder(m_ProtocolDecoders); 98 | 99 | // Create the FIR-Filter and attach to the samplers 100 | m_Filter = new FIRFilter6000(m_FlankDetector); 101 | 102 | m_FlankDetector.setSampleRate(44100); 103 | 104 | } 105 | 106 | public void playFile(InputStream fileStream) { 107 | ObjectInputStream ois; 108 | 109 | // Add a quiet period (200ms) before signal 110 | int numberOfEndSamples = m_FlankDetector.getSampleRate() / 5; 111 | for (int i = 0; i < numberOfEndSamples; i++) { 112 | m_FlankDetector.addSample(0); 113 | } 114 | 115 | int lastSample = 0; 116 | try { 117 | ois = new ObjectInputStream(fileStream); 118 | 119 | int length = ois.readInt(); 120 | for (int i = 0; i < length; i++) { 121 | ProtocolMessage irm = (ProtocolMessage) ois.readObject(); 122 | // Check that it is a raw sample 123 | if (irm.getProtocol().equals("Raw")) { 124 | RawProtocolMessage mess = (RawProtocolMessage) irm; 125 | for (int sample : mess.m_Samples) { 126 | // Push sample into decoders 127 | m_FlankDetector.addSample(sample); 128 | lastSample = sample; 129 | } 130 | } 131 | 132 | } 133 | ois.close(); 134 | } catch (IOException e) { 135 | e.printStackTrace(); 136 | } catch (ClassNotFoundException e) { 137 | e.printStackTrace(); 138 | } 139 | 140 | // Add a quiet period (200ms)to end detection 141 | numberOfEndSamples = m_FlankDetector.getSampleRate() / 5; 142 | for (int i = 0; i < numberOfEndSamples; i++) { 143 | m_FlankDetector.addSample(lastSample); 144 | } 145 | 146 | 147 | } 148 | 149 | public int getMessageField(int messageNumber, String fieldName) { 150 | if (messageNumber >= m_Messages.size()) { 151 | return -1; 152 | } 153 | List fields = m_Messages.get(messageNumber).getFields(); 154 | for (FieldValue field : fields) { 155 | if (fieldName.equals(field.getName())) { 156 | return field.getValue(); 157 | } 158 | } 159 | return -1; 160 | } 161 | 162 | public String getMessageFieldString(int messageNumber, String fieldName) { 163 | if (messageNumber >= m_Messages.size()) { 164 | return ""; 165 | } 166 | List fields = m_Messages.get(messageNumber).getFields(); 167 | for (FieldValue field : fields) { 168 | if (fieldName.equals(field.getName()) && (field.getStringValue() != null)) { 169 | return field.getStringValue(); 170 | } 171 | } 172 | return ""; 173 | } 174 | 175 | public void parsedMessage(ProtocolMessage message) { 176 | m_Messages.add(message); 177 | } 178 | 179 | public void partiallyParsedMessage(String protocol, int bits) { 180 | m_PartlyParsedMessage = true; 181 | } 182 | 183 | public void reportLevel(int level) { 184 | // Nothing to do 185 | } 186 | 187 | } 188 | -------------------------------------------------------------------------------- /src/test/java/nu/nethome/coders/encoders/RollerTrolEncoderTest.java: -------------------------------------------------------------------------------- 1 | package nu.nethome.coders.encoders; 2 | 3 | import nu.nethome.coders.RollerTrol; 4 | import nu.nethome.coders.decoders.RollerTrolDecoder; 5 | import nu.nethome.util.ps.ProtocolEncoder; 6 | import nu.nethome.util.ps.impl.PulseTestPlayer; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | 10 | import static nu.nethome.coders.RollerTrol.*; 11 | import static org.hamcrest.MatcherAssert.assertThat; 12 | import static org.hamcrest.Matchers.greaterThanOrEqualTo; 13 | import static org.hamcrest.Matchers.is; 14 | 15 | /** 16 | * 17 | */ 18 | public class RollerTrolEncoderTest { 19 | 20 | private RollerTrolEncoder rollerTrolEncoder; 21 | private PulseTestPlayer player; 22 | private RollerTrolDecoder rollerTrolDecoder; 23 | 24 | @Before 25 | public void setUp() throws Exception { 26 | rollerTrolEncoder = new RollerTrolEncoder(); 27 | player = new PulseTestPlayer(); 28 | rollerTrolDecoder = new RollerTrolDecoder(); 29 | rollerTrolDecoder.setTarget(player); 30 | player.setDecoder(rollerTrolDecoder); 31 | player.setPulseWidthModification(0); 32 | 33 | } 34 | 35 | @Test 36 | public void encodesPreamble() throws Exception { 37 | int[] data = rollerTrolEncoder.encode(RollerTrolEncoder.buildMessage(1, 1, 1), ProtocolEncoder.Phase.FIRST); 38 | assertThat(data.length, is(greaterThanOrEqualTo(4))); 39 | assertThat(data[0], is(LONG_PREAMBLE_MARK.length())); 40 | assertThat(data[1], is(LONG_PREAMBLE_SPACE.length())); 41 | assertThat(data[2], is(SHORT_PREAMBLE_MARK.length())); 42 | assertThat(data[3], is(SHORT.length())); 43 | } 44 | 45 | @Test 46 | public void encodes40BitsPlusPreamble() throws Exception { 47 | int[] data = rollerTrolEncoder.encode(RollerTrolEncoder.buildMessage(1, 1, 1), ProtocolEncoder.Phase.FIRST); 48 | assertThat(data.length, is(4 + 40 * 2)); 49 | } 50 | 51 | @Test 52 | public void canEncodeHouseCode() throws Exception { 53 | player.playMessage(rollerTrolEncoder.encode(RollerTrolEncoder.buildMessage(1, 12345, 1), ProtocolEncoder.Phase.FIRST)); 54 | assertThat(player.getMessageCount(), is(1)); 55 | assertThat(player.getMessageField(0, RollerTrol.HOUSE_CODE_NAME), is(12345)); 56 | } 57 | 58 | @Test 59 | public void canEncodeDeviceCode() throws Exception { 60 | player.playMessage(rollerTrolEncoder.encode(RollerTrolEncoder.buildMessage(1, 12345, 9), ProtocolEncoder.Phase.FIRST)); 61 | assertThat(player.getMessageCount(), is(1)); 62 | assertThat(player.getMessageField(0, RollerTrol.DEVICE_CODE_NAME), is(9)); 63 | } 64 | 65 | @Test 66 | public void canEncodeCommand() throws Exception { 67 | player.playMessage(rollerTrolEncoder.encode(RollerTrolEncoder.buildMessage(5, 12345, 9), ProtocolEncoder.Phase.FIRST)); 68 | assertThat(player.getMessageCount(), is(1)); 69 | assertThat(player.getMessageField(0, RollerTrol.COMMAND_NAME), is(5)); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/test/resources/nu/nethome/coders/decoders/fine_offset.jir: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetHome/Coders/b476ce7b9e65f2d4ce9a02db3d8ec775e9c1a82a/src/test/resources/nu/nethome/coders/decoders/fine_offset.jir -------------------------------------------------------------------------------- /src/test/resources/nu/nethome/coders/decoders/fine_offset_neg.jir: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetHome/Coders/b476ce7b9e65f2d4ce9a02db3d8ec775e9c1a82a/src/test/resources/nu/nethome/coders/decoders/fine_offset_neg.jir -------------------------------------------------------------------------------- /src/test/resources/nu/nethome/coders/decoders/nexa1.jir: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetHome/Coders/b476ce7b9e65f2d4ce9a02db3d8ec775e9c1a82a/src/test/resources/nu/nethome/coders/decoders/nexa1.jir -------------------------------------------------------------------------------- /src/test/resources/nu/nethome/coders/decoders/nexa_fire.jir: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetHome/Coders/b476ce7b9e65f2d4ce9a02db3d8ec775e9c1a82a/src/test/resources/nu/nethome/coders/decoders/nexa_fire.jir -------------------------------------------------------------------------------- /src/test/resources/nu/nethome/coders/decoders/nexal1.jir: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetHome/Coders/b476ce7b9e65f2d4ce9a02db3d8ec775e9c1a82a/src/test/resources/nu/nethome/coders/decoders/nexal1.jir -------------------------------------------------------------------------------- /src/test/resources/nu/nethome/coders/decoders/nexal_dn.jir: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetHome/Coders/b476ce7b9e65f2d4ce9a02db3d8ec775e9c1a82a/src/test/resources/nu/nethome/coders/decoders/nexal_dn.jir -------------------------------------------------------------------------------- /src/test/resources/nu/nethome/coders/decoders/oregon1.jir: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetHome/Coders/b476ce7b9e65f2d4ce9a02db3d8ec775e9c1a82a/src/test/resources/nu/nethome/coders/decoders/oregon1.jir -------------------------------------------------------------------------------- /src/test/resources/nu/nethome/coders/decoders/prologue.jir: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetHome/Coders/b476ce7b9e65f2d4ce9a02db3d8ec775e9c1a82a/src/test/resources/nu/nethome/coders/decoders/prologue.jir -------------------------------------------------------------------------------- /src/test/resources/nu/nethome/coders/decoders/rollertrol_3_stop.jir: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetHome/Coders/b476ce7b9e65f2d4ce9a02db3d8ec775e9c1a82a/src/test/resources/nu/nethome/coders/decoders/rollertrol_3_stop.jir --------------------------------------------------------------------------------