Skip to content

Instantly share code, notes, and snippets.

@djgrasss
Forked from gabonator/cc1101oregon.ino
Created March 23, 2017 01:34
Show Gist options
  • Select an option

  • Save djgrasss/4257fd504e9fac67f209d365dbc5be8e to your computer and use it in GitHub Desktop.

Select an option

Save djgrasss/4257fd504e9fac67f209d365dbc5be8e 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");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment