Created
May 12, 2016 21:06
-
-
Save gabonator/5867aa2eaa8448dda719a4d3a2181f48 to your computer and use it in GitHub Desktop.
Oregon scientific WMR sniffing with CC1101 transceiver using arduino
This file contains 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
#include "cc1101.h" | |
class C1101Receiver : public CC1101 | |
{ | |
enum | |
{ | |
SS = 10, | |
MOSI = 11, | |
MISO = 12, | |
SCK = 13, | |
GDO0 = 2 | |
}; | |
public: | |
C1101Receiver() | |
{ | |
} | |
bool Init() | |
{ | |
CC1101::init(CFREQ_433, 0); | |
// http://ygorshko.blogspot.sk/2015/04/finally-set-up-c1101-to-receive-oregon.html | |
CC1101::writeReg(CC1101_FIFOTHR, 0x47); // FIFOTHR: RX FIFO and TX FIFO Thresholds | |
CC1101::writeReg(CC1101_SYNC1, 0x55); // SYNC1: Sync Word, High Byte | |
CC1101::writeReg(CC1101_SYNC0, 0x99); // SYNC0: Sync Word, Low Byte | |
CC1101::writeReg(CC1101_PKTLEN, 0x11); // PKTLEN: Packet Length | |
CC1101::writeReg(CC1101_PKTCTRL0, 0x04); // PKTCTRL0: Packet Automation Control | |
CC1101::writeReg(CC1101_FSCTRL1, 0x06); // FSCTRL1: Frequency Synthesizer Control | |
CC1101::writeReg(CC1101_FREQ2, 0x10); // FREQ2: Frequency Control Word, High Byte | |
CC1101::writeReg(CC1101_FREQ1, 0xb0); // FREQ1: Frequency Control Word, Middle Byte | |
CC1101::writeReg(CC1101_FREQ0, 0x71); // FREQ0: Frequency Control Word, Low Byte | |
CC1101::writeReg(CC1101_MDMCFG4, 0xf6); // MDMCFG4: Modem Configuration | |
CC1101::writeReg(CC1101_MDMCFG3, 0x4a); // MDMCFG3: Modem Configuration | |
CC1101::writeReg(CC1101_MDMCFG2, 0x3e); // MDMCFG2: Modem Configuration | |
CC1101::writeReg(CC1101_DEVIATN, 0x15); // DEVIATN: Modem Deviation Setting | |
CC1101::writeReg(CC1101_MCSM0, 0x18); // MCSM0: Main Radio Control State Machine Configuration | |
CC1101::writeReg(CC1101_FOCCFG, 0x16); // FOCCFG: Frequency Offset Compensation Configuration | |
CC1101::writeReg(CC1101_AGCCTRL2, 0x05); // AGCCTRL2: AGC Control | |
CC1101::writeReg(CC1101_AGCCTRL1, 0x00); // AGCCTRL1: AGC Control | |
CC1101::writeReg(CC1101_WORCTRL, 0xfb); // WORCTRL: Wake On Radio Control | |
CC1101::writeReg(CC1101_FREND0, 0x11); // FREND0: Front End TX Configuration | |
CC1101::writeReg(CC1101_FSCAL3, 0xe9); // FSCAL3: Frequency Synthesizer Calibration | |
CC1101::writeReg(CC1101_FSCAL2, 0x2a); // FSCAL2: Frequency Synthesizer Calibration | |
CC1101::writeReg(CC1101_FSCAL1, 0x00); // FSCAL1: Frequency Synthesizer Calibration | |
CC1101::writeReg(CC1101_FSCAL0, 0x1f); // FSCAL0: Frequency Synthesizer Calibration | |
CC1101::writeReg(CC1101_TEST2, 0x81); // TEST2: Various Test Settings | |
CC1101::writeReg(CC1101_TEST1, 0x35); // TEST1: Various Test Settings | |
CC1101::writeReg(CC1101_TEST0, 0x09); // TEST0: Various Test Settings | |
CC1101::setRxState(); | |
CC1101::writeReg(CC1101_MDMCFG4, 0xC8); | |
CC1101::writeReg(CC1101_MDMCFG3, 0x4A); | |
CC1101::writeReg(CC1101_MDMCFG2, 0x30); | |
CC1101::writeReg(CC1101_MDMCFG1, 0x42); | |
CC1101::writeReg(CC1101_MDMCFG0, 0xF8); | |
CC1101::writeReg(CC1101_PKTCTRL0, 0x30); // asynchronous serial mode | |
CC1101::writeReg(CC1101_IOCFG0, 0x0d); // GD0 output | |
return CC1101::readReg(CC1101_TEST1, CC1101_CONFIG_REGISTER) == 0x35; | |
} | |
byte read() | |
{ | |
return digitalRead(GDO0); | |
} | |
}; | |
class CPinReceiver | |
{ | |
enum { | |
RxPin = 7 | |
}; | |
public: | |
void Init() | |
{ | |
pinMode(5, OUTPUT); digitalWrite(5, 0); | |
pinMode(6, OUTPUT); digitalWrite(6, 1); | |
pinMode(RxPin, INPUT); | |
} | |
byte read() | |
{ | |
return digitalRead(RxPin); | |
} | |
}; | |
//CReceiver Receiver; | |
C1101Receiver Receiver; | |
class COregon | |
{ | |
public: | |
enum | |
{ | |
RxPin = 7, | |
sDelay = 230, | |
lDelay = 460, | |
PacketLength = 10, | |
HeaderBits = 20 | |
}; | |
bool WaitHeader() | |
{ | |
return Receiver.read() == 0; | |
} | |
bool GetHeader() | |
{ | |
byte headerHits = 0; | |
long lTimeout = millis() + 100; | |
while (1) | |
{ | |
delayMicroseconds(sDelay); | |
if (Receiver.read() == 0) | |
{ | |
delayMicroseconds(lDelay); | |
if (Receiver.read() == 0) | |
return false; | |
headerHits ++; | |
if (headerHits == HeaderBits) | |
return true; | |
} | |
do | |
{ | |
if ( millis() > lTimeout ) | |
return false; | |
} while (Receiver.read()==1); | |
} | |
return false; // make sure we look for another header | |
} | |
byte ReceivePacket(byte* manchester) | |
{ | |
// https://github.com/robwlakes/ArduinoWeatherOS/blob/master/Arduino_OS_WeatherV26.ino | |
boolean logic = 1; // look for rest of header 1's, these must be soaked up intil first 0 arrives to denote start of data | |
byte signal = 0; //RF Signal is at 0 after 1's 1->0 transition, inverted Manchester (see Wiki, it is a matter of opinion) | |
boolean firstZero = false; //The first zero is not immediately found, but is flagged when found | |
boolean test230 = false; | |
boolean test460 = false; | |
int nosBytes = 0; //counter for the data bytes required | |
byte dataByte = 0; //accumulates the bits of the signal | |
byte dataMask = 16; //rotates, so allows nybbles to be reversed | |
byte nosBits = 0; //counts the shifted bits in the dataByte | |
int maxBytes = 10; //sets the limits of how many data bytes will be required | |
while (1) | |
{ | |
//now get last of the header, and then store the data after trigger bit 0 arrives, and data train timing remains valid | |
long lTimeout = millis() + 100; | |
while (Receiver.read()!=signal) | |
{ //halt here while signal matches inverse of logic, if prev=1 wait for sig=0 | |
if ( millis() > lTimeout ) | |
{ | |
return 0; | |
} | |
}//exits when signal==logic | |
delayMicroseconds(sDelay); //wait for first 1/4 of a bit pulse | |
test230 = Receiver.read();//snapshot of the input | |
if ((test230 == signal)&&(nosBytes < maxBytes)){ //after a wait the signal level is the same, so all good, continue! | |
delayMicroseconds(lDelay); //wait for second 1/2 of a bit pulse | |
test460=Receiver.read();//snapshot of the input | |
if (test230==test460){ // finds a long pulse, so the logic to look for will change, so flip the logic value | |
//Assuming the manchester encoding, a long pulse means data flips, otherwise data stays the same | |
logic = logic^1; | |
signal = signal^1; | |
if (!firstZero){ //if this is the first 0-1 data transition then is the sync 0 | |
firstZero = true; //flag that legit data has begun | |
//VIP OS Seems to put the Synch '0' bit into the data, as it causes the rest to align onto byte boundaries | |
dataByte = B00000000; // set the byte as 1's (just reflects the header bit that have preceded the trigger bit=0) | |
dataMask = B00010000; // set the byte as 1's (just reflects the header bit that have preceded the trigger bit=0) | |
nosBits = 0; // preset bit counter so we have 7 bits counted already | |
} | |
} | |
//data stream has been detected begin packing bits into bytes | |
if (firstZero){ | |
if (logic){ | |
dataByte = dataByte | dataMask; //OR the data bit into the dataByte | |
} | |
dataMask = dataMask << 1;//rotate the data bit | |
if (dataMask==0){ | |
dataMask=1;//make it roll around, is there a cleaner way than this? eg dataMask *=2? | |
} | |
nosBits++; | |
if (nosBits == 8){ //one byte created, so move onto the next one | |
manchester[nosBytes] = dataByte; //store this byte | |
nosBits = 0; //found 8, rezero and get another 8 | |
dataByte = 0; //hold the bits in this one | |
dataMask = 16; //mask to do reversed nybbles on the fly | |
nosBytes++; //keep a track of how many bytes we have made | |
} | |
} | |
} | |
else { | |
//non valid data found, or maxBytes equalled by nosBytes, reset all pointers and exit the while loop | |
return 0; | |
} | |
if (nosBytes == maxBytes) | |
{ | |
return nosBytes; | |
} | |
} | |
return 0; | |
} | |
}; | |
COregon Oregon; | |
void setup() | |
{ | |
Serial.begin(38400); | |
Serial.println("Valky.eu Oregon Decoder " __DATE__ " " __TIME__); | |
while (!Receiver.Init()) | |
{ | |
Serial.print("Cannot initialize receiver!\n"); | |
delay(1000); | |
} | |
} | |
void debug() | |
{ | |
static long ltime = 0; | |
long lcur = millis(); | |
if ( lcur - ltime > 10 ) | |
ltime = lcur; | |
else | |
return; | |
static int q= 0; | |
if ( q++ == 80 ) | |
{ | |
q = 0; | |
Serial.print("\n"); | |
} | |
Serial.print(Receiver.read()); | |
} | |
void loop() | |
{ | |
//debug(); | |
if ( Oregon.WaitHeader() ) | |
{ | |
if ( Oregon.GetHeader() ) | |
{ | |
byte buffer[COregon::PacketLength] = {0}; | |
byte received = Oregon.ReceivePacket(buffer); | |
if ( received ) | |
{ | |
const char hex[] = "0123456789abcdef"; | |
Serial.print("Received buffer: "); | |
for( int i=0; i < received; i++) | |
{ | |
Serial.print(hex[buffer[i] >> 4]); | |
Serial.print(hex[buffer[i] & 15]); | |
} | |
Serial.print("\n"); | |
} else | |
Serial.print("Receive error\n"); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi. In class CC1101Receiver you invoke CC1101::init(CFREQ_433, 0); but this method doesn´t receive arguments. Do you use panStamp library or another library to set CC1101?. Many thanks.