Overview


Specifications


Product:


Transmitter:

SpecificationValue
Model00606TXA1
FCC IDRNE606TXA1

Receiver:

SpecificationValue
Model00606TXA1
FCC IDRNE606TXA1


RTL_433 Reverse Engineering 

Using rtl_433: 


> rtl_433

Output: 

rtl_433 version 19.08-18-g8eecdbb branch master at 201909241811 inputs file rtl_tcp RTL-SDR
Use -h for usage help and see https://triq.org/ for documentation.
Trying conf file at "rtl_433.conf"...
Trying conf file at "/Users/john.mehan/.config/rtl_433/rtl_433.conf"...
Trying conf file at "/usr/local/etc/rtl_433/rtl_433.conf"...
Trying conf file at "/etc/rtl_433/rtl_433.conf"...

Consider using "-M newmodel" to transition to new model keys. This will become the default someday.
A table of changes and discussion is at https://github.com/merbanan/rtl_433/pull/986.

Registered 108 out of 138 device decoding protocols [ 1-4 8 11-12 15-17 19-21 23 25-26 29-36 38-60 63 67-71 73-100 102-103 108-116 119 121 124-128 131-138 ]
Found Rafael Micro R820T tuner
Exact sample rate is: 250000.000414 Hz
[R82XX] PLL not locked!
Sample rate set to 250000 S/s.
Tuner gain set to Auto.
Tuned to 433.920MHz.
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
time : 2019-10-03 11:08:26
model : Acurite 606TX Sensor id : 120
Battery : OK Temperature: 25.9 C Integrity : CHECKSUM


> rtl 

Detected OOK package	2019-10-03 11:49:46
Analyzing pulses...
Total count:  237,  width: 744.45 ms		(186112 S)
Pulse width distribution:
 [ 0] count:  237,  width:  508 us [496;516]	( 127 S)
Gap width distribution:
 [ 0] count:  154,  width: 1932 us [1924;1944]	( 483 S)
 [ 1] count:   70,  width: 3884 us [3876;3896]	( 971 S)
 [ 2] count:    5,  width:  468 us [460;476]	( 117 S)
 [ 3] count:    6,  width: 8520 us [8516;8532]	(2130 S)
 [ 4] count:    1,  width:  708 us [708;708]	( 177 S)
Pulse period distribution:
 [ 0] count:  154,  width: 2440 us [2432;2456]	( 610 S)
 [ 1] count:   70,  width: 4392 us [4380;4408]	(1098 S)
 [ 2] count:    5,  width:  972 us [972;980]	( 243 S)
 [ 3] count:    6,  width: 9032 us [9028;9040]	(2258 S)
 [ 4] count:    1,  width: 1220 us [1220;1220]	( 305 S)
Level estimates [high, low]:  15939,   1378
RSSI: -0.1 dB SNR: 10.6 dB Noise: -10.7 dB
Frequency offsets [F1, F2]:   18554,      0	(+70.8 kHz, +0.0 kHz)
Guessing modulation: Pulse Position Modulation with fixed pulse width
Attempting demodulation... short_width: 468, long_width: 708, reset_limit: 8536, sync_width: 0
Use a flex decoder with -X 'n=name,m=OOK_PPM,s=468,l=708,g=712,r=8536'
pulse_demod_ppm(): Analyzer Device 
bitbuffer:: Number of rows: 25 
[00] { 0}           : 
[01] { 0}           : 
[02] { 0}           : 
[03] { 0}           : 
[04] { 0}           : 
[05] { 0}           : 
[06] { 0}           : 
[07] { 0}           : 
[08] { 0}           : 
[09] { 0}           : 
[10] { 0}           : 
[11] { 0}           : 
[12] { 0}           : 
[13] { 0}           : 
[14] { 0}           : 
[15] { 0}           : 
[16] { 0}           : 
[17] { 0}           : 
[18] { 0}           : 
[19] { 0}           : 
[20] { 0}           : 
[21] { 0}           : 
[22] { 0}           : 
[23] { 0}           : 
[24] { 0}           : 
... Maximum number of rows reached. Message is likely truncated.

So, this is showing us that it detected OOK modulation but when it tries to convert to bits, it fails... 

What is an OOK package?

On Off Keying is a form of Amplitude Shift Keying (ASK) limited to two values. If you use ASK with only two values, you are essentially using OOK.



Finding the Bits

Install Let's install Universal Radio Hacker.

pip3 install urh


Running URH

> urh


From the initial window, select File → Record Signal

Click Start button and once you noticed your signal, click Stop and Save. Close the window 

The Interpretation Screen should appear.

  • zoom in on the first burst.
  • Set the signal view to Demodulated.

Looking at the entire signal, we see that it sends the identical information 7 times. 


This particular signal starts every bit by turning ON the RF signal and then turning if off for either 2 or 4 milliseconds. Staying off for 2 ms signifies a value of 0 while staying off for 4 ms signifies a value of 1.


What we deduced from looking at the signal:

PulseDelay
On Pulse0.5 ms
0 value2 ms off between On Pulse
1 value

4 ms off between On Pulse

Stop Pulse0.5 ms

9 ms delay between repeats

repeat the whole thing a total of 7 times.


If we look at just one of the pulses, we see that it contains 32 bits or 4 bytes:

We received the following data:

1110 0110 1000 0001 0011 0110 0001 0011  (E6 81 36 13 hex)



The Protocol

The protocol for this device is publish at the following URL: 

http://www.osengr.org/WxShield/Downloads/Weather-Sensor-RF-Protocols.pdf

Details

The protocol for the AcuRite 00606TX is:

 


All in nibbles (4 bits). 

Rolling Code(2), Status(1), Temperature (signed binary), Hash Code


Data being sent:

NiblePurposeOur ValueDescription
1-2Rolling CodeE6

The rolling code randomly generated when the transmitter powers up.

After the receiver receives it's first rolling code, it will not accept messages with a different code unless rebooted.

3Status8

A status of 8 signifies that the batter is ok.

The status nibble's MSB is a "battery okay" flag which is normally one. It goes to zero when the battery drops below about 2.6 volts or so.

4-6Temperature136

The temperature with 1 decimal place. 

A temperature of 31.0C = 31.0*10 = 310 dec = 136 hex

7-8Hash13Hash computed using 


Checksum/Hash

This sensor does not use a simple checksum or even a more advanced CRC. Instead data integrity is verified by a hash code, generated by multiplying the message bits with the byte sequence generated by a linear feedback shift register (LFSR). This algorithm has been referred to as "an LFSR-based Toeplitz hash" in some of the literature.


Algorithm

1. Generate LSFR sequence equal to the length of the message.

In our case, our message is 24 bits long, so we will need 24 values plus an addition 5 since we are going to start at the fifth byte in the sequence.


  • Start with an 8-bit register initialized to the value 0x7C (0111 1100)
  • Generate a number of values equal to the message size in bits by repeating the following operations once for each bit.

• Rotate the register right one bit.

• If the bit shifted out of the LSB and into the MSB during the rotation was a one, then exclusive-or the value 0x18 into the register (i.e. flip the state of bits 3 and 4). Do this after the rotate operation.

• The register value after these two operations is the sequence value to be stored. Perform these steps once for each bit in the message. If the message contains 32 bits for example (as with the F007TH message) then you will need to generate a sequence of 40 bytes. Because this sequence does not depend on the data message contents and can be pre-computed once and stored to save time.


Start ValueShift Right

XOR with 0x18 if MSB =1

(flip bits 3 and 4)

XorValue
10111 1100 (0x7C)→ 0011 1110 NO -0011 1110 (0x3e)
20011 1110 (0x3e)→ 0001 1111NO-0001 1111 (0x1f)
30001 1111 (0x1f)→ 1000 1111YESxor 0x181001 0111 (0x97)
41001 0111 (0x97)→ 1100 1011YESxor 0x181101 0011 (0xd3)
51101 0011 (0xd3)→ 1110 1001YESxor 0x181111 0001 (0xf1)
...




321000 0110 (0x86)→ 0100 0011NO-0100 0011 (0x43)
...




370011 0001 (0x31)→ 1001 1000YESxor 0x181000 000 (0x80)


Values


2. Combines the LSFR sequence with message bits to form the final hash value

To compute the message hash value, sequence through the 24 message bits in the order they were received. Since everything here is big-endian, that means proceeding from MSB to LSB. Start by initializing the hash register to the value 0x00. As the message bits are read, for every bit in the message that is a one, exclusive-or the corresponding value (+5) from the LSFR sequence into the hash register.

For example, if the 10th bit is a one, then take the 15th value from the LFSR sequence and exclusive-or it into the hash register. If the message were all zeros, then nothing would be added to the hash register and the result would be the initial value of 0x00.

From MSB to LSB for message 1110 0110 1000 0001 0011 0110  (E6 81 36 hex)

Register ValueIndexValueValue=1?Calculation

New Register Value

(xor with LSFR Sequence starting at the 5th (0xF1)

0023 -MSB1Yes00 xor f1f1
f1221Yesf1 xor e011
11211Yes11 xor 7061
...




1300No-13


Checksum/Hash Source Code

#define MESSAGE_SIZE 32
#define OFFSET 4

uint8_t LSFR_sequence[MESSAGE_SIZE] = {0};

void calculateLSFR() {
	int i;
	uint8_t reg = 0x7C;
	uint8_t temp_reg = 0;

	for (i = 0; i < MESSAGE_SIZE; i++) {
		temp_reg = reg & 0x01;
		reg >>= 1;
		reg |= (temp_reg << 7);

		if (temp_reg) {
			reg ^= 0x18;
		}

		LSFR_sequence[i] = reg;
		//printf("%02x\n", LSFR_sequence[i]);
	}
}

uint8_t combineLSFR(uint8_t len, uint8_t *data) {
	uint8_t hash_reg = 0; // not 0x64
	int byte_idx, bit_idx;
	uint8_t byte, bit;
	//printf("***COMBINE\n");

	for (byte_idx = 0; byte_idx < len; byte_idx++) {
		for (bit_idx = 7; bit_idx >= 0; bit_idx--) {
			bit = (data[byte_idx] & (1 << bit_idx)) >> bit_idx;
			if (bit) {
				hash_reg ^= LSFR_sequence[byte_idx * 8 + (7 - bit_idx) + OFFSET];
				//printf("[%d]: %02x\n", byte_idx * 8 + (7 - bit_idx), hash_reg);
			}
			bit = 0;
		}
	}

	return hash_reg;
}

uint8_t Checksum(int length, uint8_t *buff) {
	calculateLSFR();
	return combineLSFR(length, buff);
}


Sending Temperatures to the Receiver

In an effort to send our own temperatures to the receiver, we put together a program running on an ESP8266 (Wemos mini) connected with RF transmitter.

Transmitter Code

// ---------------------------------------------------------------------------------------
// Acurite 00606TX Transmitter
// ---------------------------------------------------------------------------------------

#define SYNC_LENGTH  9000
#define SEP_LENGTH   500
#define BIT1_LENGTH  4000
#define BIT0_LENGTH  2000

#define MESSAGE_SIZE 32
#define LSFR_OFFSET 4

uint8_t LSFR_sequence[MESSAGE_SIZE] = {0};

const int TX_PIN = D2;
byte payload[4];

// ---------------------------------------------------------------------------------------
// setup
// ---------------------------------------------------------------------------------------
void setup ( void ) {
    pinMode(TX_PIN, OUTPUT);
    Serial.begin ( 115200 );
    Serial.println("Sending...");
    generatePayload();
    doTransmission();
}
// ---------------------------------------------------------------------------------------
// loop
// ---------------------------------------------------------------------------------------
void loop ( void ) {
  delay(20000);
}

// ---------------------------------------------------------------------------------------
// generatePayload
// ---------------------------------------------------------------------------------------
void generatePayload(){
      //define rolling code
    byte rollingCode = 0xAA;
    
    //generate random temperature
    int temperature = (int)random(-400,400);
    Serial.printf("Temp: %.1f\n",temperature/10.0);

    unsigned int hightByteTemp = temperature >> 8;
    unsigned int lowByteTemp = temperature & 0xff;

    //add battery OK flag to 
    hightByteTemp = 0x80 + (hightByteTemp & 0x0F);

    payload[0] = rollingCode;
    payload[1] = hightByteTemp;
    payload[2] = lowByteTemp;
    payload[3] = computeChecksum(3,payload);

    Serial.print("Payload: ");
    for(int i=0;i<4;i++){
      Serial.printf("%02x ",payload[i]);
    }
    Serial.println("");
}

// ---------------------------------------------------------------------------------------
// toggleLED
// ---------------------------------------------------------------------------------------
void toggleLED(){
    //flash led
    digitalWrite(LED_BUILTIN, HIGH);
    delay(500);
    digitalWrite(LED_BUILTIN, LOW);
}

// ---------------------------------------------------------------------------------------
// doTransmission
// ---------------------------------------------------------------------------------------
void doTransmission() {

    Serial.println("Doing transmission...");
    toggleLED();

    for (int burst = 1; burst <= 7; burst++) {
      Serial.print("Sending: ");
      sendPayload();
      sendSync();
      Serial.println("");
    }
}

// ---------------------------------------------------------------------------------------
// sendPayload
// ---------------------------------------------------------------------------------------
void sendPayload(){
  for(int i=0;i<4;i++){
    sendByte(payload[i]);
  }  
}

// ---------------------------------------------------------------------------------------
// sendByte
// ---------------------------------------------------------------------------------------
void sendByte(byte b){
  for(int i=7;i>=0;i--){
    int bitValue = readBit(b,i); 
    sendBit(bitValue);
    if(i%4==0){
      Serial.print(" ");
    }
  }  
}

// ---------------------------------------------------------------------------------------
// readBit
// ---------------------------------------------------------------------------------------
int readBit(byte b, int bitPos){
  int x = b & (1 << bitPos);
  return x == 0 ? 0 : 1;
}

// ---------------------------------------------------------------------------------------
// sendBit
// ---------------------------------------------------------------------------------------
void sendBit(int val){
  
  digitalWrite(TX_PIN, HIGH );    
  delayMicroseconds(SEP_LENGTH );  

  digitalWrite(TX_PIN, LOW );
  if(val==0){
    delayMicroseconds(BIT0_LENGTH );    
    Serial.print("0");
  }else{
    delayMicroseconds(BIT1_LENGTH );    
    Serial.print("1");
  }
}

// ---------------------------------------------------------------------------------------
// sendSync
// ---------------------------------------------------------------------------------------
void sendSync(){
  digitalWrite(TX_PIN, HIGH );
  delayMicroseconds(SEP_LENGTH);
  digitalWrite(TX_PIN, LOW );
  delayMicroseconds(SYNC_LENGTH );
  Serial.print(" -");
}

// ---------------------------------------------------------------------------------------
// calculateLSFR
// ---------------------------------------------------------------------------------------
void calculateLSFR() {
    int i;
    uint8_t reg = 0x7C;
    uint8_t temp_reg = 0;
 
    for (i = 0; i < MESSAGE_SIZE; i++) {
        temp_reg = reg & 0x01;
        reg >>= 1;
        reg |= (temp_reg << 7);
 
        if (temp_reg) {
            reg ^= 0x18;
        }
 
        LSFR_sequence[i] = reg;
        //printf("%02x\n", LSFR_sequence[i]);
    }
}
// ---------------------------------------------------------------------------------------
// combineLSFR
// --------------------------------------------------------------------------------------- 
uint8_t combineLSFR(uint8_t len, uint8_t *data) {
    uint8_t hash_reg = 0; // not 0x64
    int byte_idx, bit_idx;
    uint8_t byte, bit;
    //printf("***COMBINE\n");
 
    for (byte_idx = 0; byte_idx < len; byte_idx++) {
        for (bit_idx = 7; bit_idx >= 0; bit_idx--) {
            bit = (data[byte_idx] & (1 << bit_idx)) >> bit_idx;
            if (bit) {
                hash_reg ^= LSFR_sequence[byte_idx * 8 + (7 - bit_idx) + LSFR_OFFSET];
                //printf("[%d]: %02x\n", byte_idx * 8 + (7 - bit_idx), hash_reg);
            }
            bit = 0;
        }
    }
 
    return hash_reg;
}
 
// ---------------------------------------------------------------------------------------
// computeChecksum
// --------------------------------------------------------------------------------------- 
uint8_t computeChecksum(int length, uint8_t *buff) {
    calculateLSFR();
    return combineLSFR(length, buff);
}


Reading the values from the Transmitter

Receiver Code

// ---------------------------------------------------------------------------------------
// Acurite 00606TX Reader
// Adapted from code by Ray Wang (Rayshobby LLC)
// ---------------------------------------------------------------------------------------

#define DATAPIN  D2  

// ring buffer size has to be large enough to fit
// data between two successive sync signals
#define RING_BUFFER_SIZE  256

#define SYNC_LENGTH  9000
#define SEP_LENGTH   500
#define BIT1_LENGTH  4000
#define BIT0_LENGTH  2000

#define MESSAGE_SIZE 32
#define LSFR_OFFSET 4

uint8_t LSFR_sequence[MESSAGE_SIZE] = {0};

//ringbuffer contains the time since the last signal was off.
unsigned long timings[RING_BUFFER_SIZE];

unsigned int syncIndex1 = 0;  // index of the first sync signal
unsigned int syncIndex2 = 0;  // index of the second sync signal
bool received = false;

//protypes
void ICACHE_RAM_ATTR handler();

// ---------------------------------------------------------------------------------------
// setup
// ---------------------------------------------------------------------------------------
void setup() {
  Serial.begin(115200);
  pinMode(DATAPIN, INPUT);
  attachInterrupt(digitalPinToInterrupt(DATAPIN), handler, CHANGE);
  Serial.println("\n\nStarted");
}

// ---------------------------------------------------------------------------------------
// loop
// ---------------------------------------------------------------------------------------
void loop() {

  //Did we get a message?
  if (received == true) {
    Serial.println("\nReceived...");
    
    // disable interrupt to avoid new data corrupting the buffer
    detachInterrupt(digitalPinToInterrupt(DATAPIN));

    //processSignal
    unsigned int bits[34];
    bool error = processSignal(bits); 

   if(error==false){

      //convert our bits to byte array
      byte data[4];
      bool success = bitsToByteArray(bits,32,data,4);

      if(success){
        byte rollingCode = data[0];
        Serial.printf("Rolling Code: 0x%02x\n",rollingCode);
    
        byte batteryStatus = (data[1] & 0xf0) >> 4;
        Serial.printf("Battery Status: 0x%02x\n",batteryStatus);

        float temperature = computeTemperature(data[1],data[2]);
        Serial.printf("Temp: %0.1f C\n",temperature);
  
        byte checksum = data[3];
        Serial.printf("checksum: 0x%02x\n",checksum);
  
        //uint8_t computeChecksum(int length, uint8_t *buff) {
        byte computedChecksum = computeChecksum(3,data);
        if(checksum==computedChecksum){
          Serial.printf("Checksum Verified!\n");
        }else{
          Serial.printf("Checksum Invalid!\n");
        }
      }else{
        Serial.printf("Failed to convert bits to bytes array\n");
      }
      
   }//if(error==false){

    // delay for 1 second to avoid repetitions
    delay(1000);
    received = false;
    syncIndex1 = 0;
    syncIndex2 = 0;

    // re-enable interrupt
    attachInterrupt(digitalPinToInterrupt(DATAPIN), handler, CHANGE);
    
  }//if (received == true) {

}

// ---------------------------------------------------------------------------------------
// computeTemperature
// ---------------------------------------------------------------------------------------
// Temperature is a signed 12-bit value with resolution of 0.1C. For example,
// 25.6C is encoded as the value 256 (0x100 hexadecimal). A value of -0.1C is
// encoded as -1 (0xFFF hexadecimal).         
// ---------------------------------------------------------------------------------------
float computeTemperature(byte highbyte, byte lowbyte){
  
    bool negative=false;
    Serial.printf("highbyte : 0x%02x \n",highbyte);
    if((highbyte & 0x08) == 0x08){
      negative=true;
      Serial.println("Negative");
    }
    
    int rawTemperature = ((highbyte & 0x0f) << 8) + lowbyte;
    Serial.printf("rawTemperature: %d\n",rawTemperature);
    
    if(negative){
      rawTemperature = rawTemperature - 4096;
      //limit to -40C like the acurite receiver
      if(rawTemperature < -400){
        rawTemperature = -400;
      }
    }
    
    float temperature = rawTemperature / 10.0;
    return temperature;
}

// ---------------------------------------------------------------------------------------
// processSignal
// ---------------------------------------------------------------------------------------
// Message is composed of:
// - Rolling Code(2 nibbles - 8 bits), 
// - Status(1 nibble - 4 bits), 
// - Temperature (signed binary - 3 nibbles - 12 bits ), 
// - Hash Code (2 nibles - 8 bits)
//
// Each bit is composed of two signals - a seperator signal followed by a short/long
// ---------------------------------------------------------------------------------------
bool processSignal(unsigned int *bits){
  
    bool error = false;
  
    int totalSignalsInMessage = 32 *2;
    int count =0;
    for(unsigned int i=syncIndex1; i!=(syncIndex1+totalSignalsInMessage)%RING_BUFFER_SIZE; i=(i+2)%RING_BUFFER_SIZE) {

      unsigned long t0 = timings[i];
      unsigned long t1 = timings[(i+1)%RING_BUFFER_SIZE];

      if (t0>(SEP_LENGTH-150) && t0<(SEP_LENGTH+150)){
        if (t1>(BIT1_LENGTH-1000) && t1<(BIT1_LENGTH+1000)) {
          bits[count]=1;         
        } else if (t1>(BIT0_LENGTH-1000) && t1<(BIT0_LENGTH+1000)) {
          bits[count]=0;
        } else {          
          bits[count]=-1;
        }
      }else {
//        Serial.printf("** t0: %d, t1: %d\n",t0,t1);
//        Serial.printf("Read Error\n");
        error=true;
        break; 
      }
      count++;
    }//for

   if(error==false){

      //print bits received
      Serial.print("bits: ");
      for(int i=0;i<32;i++){
        if(bits[i]>=0){
          Serial.print(bits[i]);
        }else{
          Serial.print("X");
        }
        if((i+1)%4==0){
          Serial.printf(" ");
        }
      }
      Serial.println("");
   }
  return error;
}
// ---------------------------------------------------------------------------------------
// isSync
// ---------------------------------------------------------------------------------------
// Detect if a sync signal is present. A sync signal is composed of a seperator signal 
// (short off 0.5ms) followed by a sync signal (9ms off).
// ---------------------------------------------------------------------------------------
bool isSync(unsigned int idx) {

  //get the last two indexes from the ring buffer
  int t0Index = (idx+RING_BUFFER_SIZE-1) % RING_BUFFER_SIZE;
  unsigned long t0 = timings[t0Index];
  unsigned long t1 = timings[idx];

  //check that t0 is a seperator signal, should be around 0.5ms
  if (t0>(SEP_LENGTH-100) && t0<(SEP_LENGTH+100) ){
    
    //check that t1 is a sync signal, allow for anything between 8-10ms
    if (t1>(SYNC_LENGTH-1000) && t1<(SYNC_LENGTH+1000)){
      if (digitalRead(DATAPIN) == HIGH) {
        
//        Serial.printf("toIndex=%d, idx=%d, RING_BUFFER_SIZE=%d \n",t0Index, idx, RING_BUFFER_SIZE);
//        Serial.printf("t0=%d, t1=%d\n",t0,t1);

        //found
        return true;         
      }
    }
  }
  return false;
}

// ---------------------------------------------------------------------------------------
// handler
// ---------------------------------------------------------------------------------------
// Interrupt handler - reads incoming signal changes from receiver
// ---------------------------------------------------------------------------------------
void ICACHE_RAM_ATTR handler() {
  static unsigned long duration = 0;
  static unsigned long lastTime = 0;
  static unsigned int ringIndex = 0;
  static unsigned int syncCount = 0;

  // exit out if we are in processing a signal.
  if (received == true) {
//    Serial.println("received==true");
    return;
  }

  // calculating timing since last change
  long time = micros();
  duration = time - lastTime;
  lastTime = time;

  // store data in ring buffer
  ringIndex = (ringIndex + 1) % RING_BUFFER_SIZE;
  timings[ringIndex] = duration;

  // detect sync signal
  if (isSync(ringIndex)) {
    
    syncCount ++;
   
    if (syncCount == 1) {
      
       // first time sync is seen, record buffer index      
      syncIndex1 = (ringIndex+1) % RING_BUFFER_SIZE;
      
    }else if (syncCount == 2) {
      syncCount = 0;
      
      // second time sync is seen, start bit conversion
      syncIndex2 = (ringIndex+1) % RING_BUFFER_SIZE;

      //check how many signals we have received between syncs
      unsigned int changeCount  = 0;
      if(syncIndex2 < syncIndex1){
        changeCount = syncIndex2+RING_BUFFER_SIZE - syncIndex1;
      }else{
        changeCount = syncIndex2 - syncIndex1;
      }
      
      if (changeCount < 66 || changeCount > 68) {
        //too many signals, disregard
        received = false;
        syncIndex1 = 0;
        syncIndex2 = 0;
      } else {
        
        //we found our signal
        received = true;
        
      }
    }

  }
}



// ---------------------------------------------------------------------------------------
// calculateLSFR
// ---------------------------------------------------------------------------------------
void calculateLSFR() {
    int i;
    uint8_t reg = 0x7C;
    uint8_t temp_reg = 0;
 
    for (i = 0; i < MESSAGE_SIZE; i++) {
        temp_reg = reg & 0x01;
        reg >>= 1;
        reg |= (temp_reg << 7);
 
        if (temp_reg) {
            reg ^= 0x18;
        }
 
        LSFR_sequence[i] = reg;
        //printf("%02x\n", LSFR_sequence[i]);
    }
}
// ---------------------------------------------------------------------------------------
// combineLSFR
// --------------------------------------------------------------------------------------- 
uint8_t combineLSFR(uint8_t len, uint8_t *data) {
    uint8_t hash_reg = 0; // not 0x64
    int byte_idx, bit_idx;
    uint8_t byte, bit;
    //printf("***COMBINE\n");
 
    for (byte_idx = 0; byte_idx < len; byte_idx++) {
        for (bit_idx = 7; bit_idx >= 0; bit_idx--) {
            bit = (data[byte_idx] & (1 << bit_idx)) >> bit_idx;
            if (bit) {
                hash_reg ^= LSFR_sequence[byte_idx * 8 + (7 - bit_idx) + LSFR_OFFSET];
                //printf("[%d]: %02x\n", byte_idx * 8 + (7 - bit_idx), hash_reg);
            }
            bit = 0;
        }
    }
 
    return hash_reg;
}
 
// ---------------------------------------------------------------------------------------
// computeChecksum
// --------------------------------------------------------------------------------------- 
uint8_t computeChecksum(int length, uint8_t *buff) {
    calculateLSFR();
    return combineLSFR(length, buff);
}

// ---------------------------------------------------------------------------------------
// bitsToByteArray
// ---------------------------------------------------------------------------------------
// Convert array of integers containing the bits received into byte array
// ---------------------------------------------------------------------------------------
bool bitsToByteArray(unsigned int *bits, int len, byte* buffer, int bufferLen){

  int bidx=0;
  unsigned int sum = 0;
  
  for(int i=0;i<len;i++){
  
    
    //break out if we have filled up the buffer    
    if(bidx >= bufferLen){
      return false;
    }
    
    sum += bits[i];

    //new byte?
    if((i+1)%8==0){
      
      //save to buffer, reset sum and increment bidx
      buffer[bidx]=sum;
      sum=0;
      bidx++;
      
    }else{
      sum<<=1;
    }
  }
  
  return true;
}


Presentation

References