Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
languagecpp
// ---------------------------------------------------------------------------------------
// 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(0-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

Code Block
languagecpp
// ---------------------------------------------------------------------------------------
// 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;
}

...