Last active
February 16, 2022 16:22
-
-
Save ElishaAz/ec89d474d836bf9bffe213f15f0554fc to your computer and use it in GitHub Desktop.
An IR NEC encoder for Java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Encodes a packet in NEC for transmitting in IR. | |
| * <p> | |
| * Can be used in android as follows: | |
| * <pre>{@code | |
| * int frequency = 38028; | |
| * NECEncoder encoder = new NECEncoder(frequency); | |
| * | |
| * ConsumerIrManager cim = (ConsumerIrManager) getApplicationContext().getSystemService(Context.CONSUMER_IR_SERVICE); | |
| * | |
| * // Check that the device has an IR blaster | |
| * if (cim.hasIrEmitter()) { | |
| * | |
| * String packet = "0xABC123" | |
| * | |
| * // encode packet | |
| * int[] pattern = encoder.encode(packet); | |
| * | |
| * // transmit packet | |
| * cim.transmit(frequency, pattern); | |
| * } | |
| * // Note: you need the "android.permission.TRANSMIT_IR" permission | |
| * }</pre> | |
| */ | |
| public class NECEncoder { | |
| public final int frequency; | |
| /** | |
| * Create a new encoder with default frequency. | |
| */ | |
| public NECEncoder() { | |
| this(38028); | |
| } | |
| /** | |
| * Create a new encoder with a given frequency. | |
| */ | |
| public NECEncoder(int frequency) { | |
| this.frequency = frequency; | |
| } | |
| /** | |
| * Encode a packet. | |
| * <pre>The packet can be in: | |
| * hexadecimal, with 0x prefix | |
| * binary, with 0b prefix | |
| * decimal, without a prefix. | |
| * </pre> | |
| * | |
| * @param packet the packet to encode, as a string. | |
| * @return the packet encoded in NEC. | |
| */ | |
| public int[] encode(String packet) { | |
| packet = packet.trim(); | |
| boolean[] bits; | |
| if (packet.startsWith("0x")) bits = hexToBits(packet); | |
| else if (packet.startsWith("0b")) bits = binToBits(packet); | |
| else bits = decToBits(packet); | |
| return encodeBits(bits); | |
| } | |
| /** | |
| * Encode a packet | |
| * | |
| * @param packet to encode, as a number. | |
| * @return the packet encoded in NEC. | |
| */ | |
| public int[] encode(long packet) { | |
| return encodeBits(numToBits(packet)); | |
| } | |
| /** | |
| * Represents a hex string as a bits array. | |
| */ | |
| private boolean[] hexToBits(String hex) { | |
| hex = hex.substring(2).toLowerCase(); | |
| boolean[] bits = new boolean[hex.length() * 4]; | |
| for (int i = 0; i < hex.length(); i++) { | |
| int num = 0; | |
| char c = hex.charAt(i); | |
| if ('0' <= c && c <= '9') { | |
| num = c - '0'; | |
| } else if ('a' <= c && c <= 'f') { | |
| num = (c - 'a') + 10; | |
| } else { | |
| throw new RuntimeException("Error parsing packet: '" + hex + "'. Not a hexadecimal number!"); | |
| } | |
| setBits(bits, i * 4, 4, num); | |
| } | |
| return bits; | |
| } | |
| /** | |
| * Represents a decimal string as a bits array. | |
| */ | |
| private boolean[] decToBits(String dec) { | |
| long number = Long.parseLong(dec); | |
| if (number < 0) throw new RuntimeException(); | |
| return numToBits(number); | |
| } | |
| /** | |
| * Represents a number as a bits array. | |
| */ | |
| private boolean[] numToBits(long number) { | |
| int size = (int) Math.ceil(Math.log(number) / Math.log(2)); | |
| boolean[] bits = new boolean[size]; | |
| setBits(bits, 0, size, number); | |
| return bits; | |
| } | |
| /** | |
| * Represents a binary string as a bits array. | |
| */ | |
| private boolean[] binToBits(String packet) { | |
| boolean[] bits = new boolean[packet.length()]; | |
| for (int i = 0; i < packet.length(); i++) { | |
| int bin = 0; | |
| char c = packet.charAt(i); | |
| if ('0' <= c && c <= '1') { | |
| bin = c - '0'; | |
| } else { | |
| throw new RuntimeException("Error parsing packet: '" + packet + "'. Not a binary number!"); | |
| } | |
| setBits(bits, i * 2, 2, bin); | |
| } | |
| return bits; | |
| } | |
| /** | |
| * Sets bits in a bit array to the given number at the given place. | |
| * | |
| * @param bits the bits array. | |
| * @param startIndex the starting index in the bits array (you might want to multiply this by 'size') | |
| * @param size the size of the number in bits (sqrt(num)). | |
| * @param num the number to set to. | |
| */ | |
| private void setBits(boolean[] bits, int startIndex, int size, long num) { | |
| for (int i = size - 1; i >= 0; i--) { | |
| bits[startIndex + i] = num % 2 == 1; | |
| num /= 2; | |
| } | |
| } | |
| /** | |
| * Encodes a given packet represented as a bits array. | |
| * | |
| * @param bits the packet as a bits array. | |
| * @return the encoded packet. | |
| */ | |
| public int[] encodeBits(boolean[] bits) { | |
| final int T = 1000000 / frequency; | |
| // values from https://github.com/timnew/AndroidInfrared | |
| final int HDR_MARK = 342 * T; | |
| final int HDR_SPACE = 171 * T; | |
| final int BIT_MARK = 21 * T; | |
| final int ONE_SPACE = 60 * T; | |
| final int ZERO_SPACE = 21 * T; | |
| int[] pattern = new int[bits.length * 2 + 3]; | |
| pattern[0] = HDR_MARK; | |
| pattern[1] = HDR_SPACE; | |
| for (int i = 0; i < bits.length; i++) { | |
| int patternIndex = 2 + (bits.length - 1 - i) * 2; | |
| pattern[patternIndex] = BIT_MARK; | |
| pattern[patternIndex + 1] = bits[i] ? ONE_SPACE : ZERO_SPACE; | |
| } | |
| pattern[pattern.length - 1] = BIT_MARK; | |
| return pattern; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment