...
Transmitter Code
Code Block | ||
---|---|---|
| ||
const int TX_PIN = 4; // ESP8266 pin D2
typedef struct {
boolean power;
int duration; // micro seconds
} signal;
const signal SHORT_ON { true, 500 };
const signal SHORT_OFF { false, 2000 };
const signal LONG_ON { true, 850 }; // not used
const signal LONG_OFF { false, 4000 };
const signal STOP_OFF { false, 500 };
const int REST = 9000; // 9 ms gap
// Here's a temperature of 24.5 forever...
//
signal sig_1 [] {
SHORT_ON, // start bit
SHORT_OFF, SHORT_ON, // a zero (0) bit
LONG_OFF, SHORT_ON, // a one (1) bit
LONG_OFF, SHORT_ON, // a one (1) bit
LONG_OFF, SHORT_ON, // a one (1) bit
LONG_OFF, SHORT_ON, // a one (1) bit
SHORT_OFF, SHORT_ON, // a zero (0) bit
SHORT_OFF, SHORT_ON, // a zero (0) bit
SHORT_OFF, SHORT_ON, // a zero (0) bit
LONG_OFF, SHORT_ON, // a one (1) bit
SHORT_OFF, SHORT_ON, // a zero (0) bit
SHORT_OFF, SHORT_ON, // a zero (0) bit
SHORT_OFF, SHORT_ON, // a zero (0) bit
SHORT_OFF, SHORT_ON, // a zero (0) bit
SHORT_OFF, SHORT_ON, // a zero (0) bit
SHORT_OFF, SHORT_ON, // a zero (0) bit
SHORT_OFF, SHORT_ON, // a zero (0) bit
// LONG_OFF, SHORT_ON, // a one (1) bit
LONG_OFF, SHORT_ON, // a one (1) bit
LONG_OFF, SHORT_ON, // a one (1) bit
LONG_OFF, SHORT_ON, // a one (1) bit
LONG_OFF, SHORT_ON, // a one (1) bit
SHORT_OFF, SHORT_ON, // a zero (0) bit
LONG_OFF, SHORT_ON, // a one (1) bit
SHORT_OFF, SHORT_ON, // a zero (0) bit
LONG_OFF, SHORT_ON, // a one (1) bit
SHORT_OFF, SHORT_ON, // a zero (0) bit
SHORT_OFF, SHORT_ON, // a zero (0) bit
SHORT_OFF, SHORT_ON, // a zero (0) bit
SHORT_OFF, SHORT_ON, // a zero (0) bit
LONG_OFF, SHORT_ON, // a one (1) bit
LONG_OFF, SHORT_ON, // a one (1) bit
LONG_OFF, SHORT_ON, // a one (1) bit
SHORT_OFF, SHORT_ON, // a zero (0) bit
STOP_OFF, SHORT_ON // stop bit
};
void doTransmission(signal array[67]) {
Serial.println("Doing transmission...");
for (int burst = 1; burst <= 7; burst++) {
for (int idx = 0; idx < 66; ++idx ) { // payload
digitalWrite(TX_PIN, array[idx].power);
delayMicroseconds( array[idx].duration );
}
delayMicroseconds(REST); // rest between bursts
}
}
void setup ( void ) {
pinMode(TX_PIN, OUTPUT);
Serial.begin ( 115200 );
}
void loop ( void ) {
Serial.println("Sending...");
doTransmission(sig_1);
delay(10000);
} |
Reading the values from the Transmitter
Code Block | ||
---|---|---|
| ||
/* Convert RF signal into bits (temperature sensor version) * Written by : Ray Wang (Rayshobby LLC) * http://rayshobby.net/?p=8827 */ // 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 DATAPIN D2 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; void ICACHE_RAM_ATTR handler(); // detect if a sync signal is present bool isSync(unsigned int idx) { unsigned long t0 = timings[(idx+RING_BUFFER_SIZE-1) % RING_BUFFER_SIZE]; unsigned long t1 = timings[idx]; // on the temperature sensor, the sync signal // is roughtly 9.0ms. Accounting for error // it should be within 8.0ms and 10.0ms if (t0>(SEP_LENGTH-100) && t0<(SEP_LENGTH+100) ){ if (t1>(SYNC_LENGTH-1000) && t1<(SYNC_LENGTH+1000)){ if (digitalRead(DATAPIN) == HIGH) { return true; } } } return false; } /* Interrupt handler */ 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; // ignore if we haven't processed the previous received 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 ++; // first time sync is seen, record buffer index if (syncCount == 1) { syncIndex1 = (ringIndex+1) % RING_BUFFER_SIZE; } else if (syncCount == 2) { // second time sync is seen, start bit conversion syncCount = 0; syncIndex2 = (ringIndex+1) % RING_BUFFER_SIZE; unsigned int changeCount = (syncIndex2 < syncIndex1) ? (syncIndex2+RING_BUFFER_SIZE - syncIndex1) : (syncIndex2 - syncIndex1); // changeCount must be 66 -- 32 bits x 2 + 2 for sync // Serial.print("ChangeCount:"); // Serial.println(changeCount); if (changeCount < 66 || changeCount > 68// --------------------------------------------------------------------------------------- // 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--) { received = false; bit = (data[byte_idx] & (1 << syncIndex1 = 0; bit_idx)) >> bit_idx; syncIndex2if = 0; (bit) { } else { received = truehash_reg ^= LSFR_sequence[byte_idx * 8 + (7 - bit_idx) + LSFR_OFFSET]; } } } } void setup() { Serial.begin(115200); Serial.println("Started."); pinMode(DATAPIN, INPUT //printf("[%d]: %02x\n", byte_idx * 8 + (7 - bit_idx), hash_reg); attachInterrupt(digitalPinToInterrupt(DATAPIN), handler, CHANGE); Serial.println("\n\nStarted"); } void loop() { if (received ==} true) { Serial.println("Received..."); bit = 0; // disable interrupt to avoid new data corrupting the buffer } detachInterrupt(digitalPinToInterrupt(DATAPIN)); // loop over the lowest 12 bits of the middle 2 bytes} unsigned long temp = 0; bool negative = false; bool fail = false; for(unsigned int i=(syncIndex1+24)%RING_BUFFER_SIZE; i!=(syncIndex1+48)%RING_BUFFER_SIZE; i=(i+2)%RING_BUFFER_SIZE) { unsigned long t0 = timings[i], t1 = timings[(i+1)%RING_BUFFER_SIZE]return hash_reg; } // --------------------------------------------------------------------------------------- // computeChecksum // --------------------------------------------------------------------------------------- uint8_t computeChecksum(int length, uint8_t *buff) { calculateLSFR(); return if (t0>(SEP_LENGTH-100) && t0<(SEP_LENGTH+100)) { if (t1>(BIT1_LENGTH-1000) && t1<(BIT1_LENGTH+1000)) { if(i == (syncIndex1+24)%RING_BUFFER_SIZE) negative = true; temp = (temp << 1) + 1; } else if (t1>(BIT0_LENGTH-1000) && t1<(BIT0_LENGTH+1000)) { temp = (temp << 1) + 0; } else { fail = true; } } else { fail = true; } } if (!fail) { if (negative) { temp = 4096 - temp; Serial.print("-"); } Serial.print(temp/10.0); //temp in C Serial.write(176); // degree symbol Serial.print("C/"); Serial.print((temp)*9/50.0+32); // convert to F Serial.write(176); // degree symbol Serial.println("F"); } else { Serial.println("Decoding error."); } // delay for 1 second to avoid repetitions delay(1000); received = false; syncIndex1 = 0; syncIndex2 = 0; // re-enable interrupt attachInterrupt(digitalPinToInterrupt(DATAPIN), handler, CHANGE); } combineLSFR(length, buff); } |
Reading the values from the Transmitter
Receiver Code
Code Block | ||
---|---|---|
| ||
// ---------------------------------------------------------------------------------------
// 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
View file | ||||
---|---|---|---|---|
|
...
Reference | URL |
---|---|
RF Protocol | http://www.osengr.org/WxShield/Downloads/Weather-Sensor-RF-Protocols.pdf |
Reverse Engineer Wireless Temperature / Humidity / Rain Sensors — Part 1 | https://rayshobby.net/wordpress/reverse-engineer-wireless-temperature-humidity-rain-sensors-part-1/ |
Acurite Receiver Code | http://raysfiles.com/arduino/temperature_display.ino |
FCC Info | https://fccid.io/RNE606TXA1 |
On Off Keying | https://www.youtube.com/watch?v=w6V9NyXwohI |
...