Skip to content

Instantly share code, notes, and snippets.

@gabonator
Created May 12, 2016 21:06
Show Gist options
  • Save gabonator/5867aa2eaa8448dda719a4d3a2181f48 to your computer and use it in GitHub Desktop.
Save gabonator/5867aa2eaa8448dda719a4d3a2181f48 to your computer and use it in GitHub Desktop.
Oregon scientific WMR sniffing with CC1101 transceiver using arduino
#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");
}
}
}
@joebazoka
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment