#include "cc1101.h" class C1101Receiver : public CC1101 { enum { SS = 10, MOSI = 11, MISO = 12, SCK = 13, GDO0 = 2 }; 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"); } } }