Skip to content

Instantly share code, notes, and snippets.

@ElishaAz
Last active February 16, 2022 16:22
Show Gist options
  • Select an option

  • Save ElishaAz/ec89d474d836bf9bffe213f15f0554fc to your computer and use it in GitHub Desktop.

Select an option

Save ElishaAz/ec89d474d836bf9bffe213f15f0554fc to your computer and use it in GitHub Desktop.
An IR NEC encoder for Java
/**
* 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