#include #include #include #define m_pinMOSI 11 // SPI master data out pin #define m_pinMISO 12 // SPI master data in pin #define m_pinSCK 13 // SPI clockd pin #define m_pinCS 10 // SPI slave select pin #define IRQ 9 #define TX_LED 2 #define RX_LED 3 #define STATUS_LED 4 #define BUTTON1 5 #define CRC_LENGTH 2 // the CRC length #define SOPPN_BINDING 16 // this is the default binding SOPPN. This will never change #define SOPPN_LENGTH 24 // this is the total length of the SOP/PN. #define SOP_LENGTH 8 // this is just the length of the SOP #define PN_LENGTH 16 // this is just the PN length #define PAYLOAD_LENGTH 16 // number of bytes in data payload #define DelayUs(x) delayCount = x; while(--delayCount){ __asm__("nop\n\t"); } // delay for x microseconds //#define TOGGLE7 bitWrite(PORTD, 7, 1); bitWrite(PORTD, 7, 0); CYRF6936 chip(m_pinCS, m_pinSCK, m_pinMOSI, m_pinMISO); unsigned char current_channel = 0; unsigned char sequence_number; unsigned char next_sequence; //unsigned char channel = 0x00; unsigned char CRC[2] = {0x00, 0x00}; //set to zero so we can figure it out... //unsigned char CRCLSB = 0x00; //set to zero so we can figure it out... //note that the first 8 chars are the SOP, and the next 16 = Spreading Code unsigned char soppn_binding[16]={0xD7, 0xA1, 0x54, 0xB1, 0x5E, 0x89, 0xAE, 0x86, 0x98, 0x88, 0x1B, 0xE4, 0x30, 0x79, 0x03, 0x84}; unsigned char soppn_sequences[][24]= { {0xD0,0xD2,0x8E,0xBC,0x82,0x2F,0xE3,0xB4,0x8C,0xFA,0x47,0x9B,0x83,0xA5,0x66,0xD0,0x07,0xBD,0x9F,0x26,0xC8,0x31,0x0F,0xB8}, {0xBC,0x5D,0x9A,0x5B,0xEE,0x7F,0x42,0xEB,0x24,0xF5,0xDD,0xF8,0x7A,0x77,0x74,0xE7,0x3D,0x70,0x7C,0x94,0xDC,0x84,0xAD,0x95}, {0x0C,0x5D,0x24,0x30,0x9F,0xCA,0x6D,0xBD,0x50,0x14,0x33,0xDE,0xF1,0x78,0x95,0xAD,0x0C,0x3C,0xFA,0xF9,0xF0,0xF2,0x10,0xC9}, {0xB6,0xF2,0xE6,0x1B,0x80,0x5A,0x36,0xB4,0x42,0xAE,0x9C,0x1C,0xDA,0x67,0x05,0xF6,0x9B,0x75,0xF7,0xE0,0x14,0x8D,0xB5,0x80}, {0xE0,0x83,0x01,0xFA,0xAB,0x3E,0x8F,0xAC,0x5C,0xD5,0x9C,0xB8,0x46,0x9C,0x7D,0x84,0xF1,0xC6,0xFE,0x5C,0x9D,0xA5,0x4F,0xB7} }; unsigned char soppnrow = 0; unsigned char payload[PAYLOAD_LENGTH] = {0xFF,0xFE,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF}; unsigned char rx_payload[PAYLOAD_LENGTH]; unsigned char rx_count; char i; unsigned char mfg_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // 7B F5 71 F6 46 FF volatile unsigned int delayCount=0; volatile unsigned char flag=0; volatile unsigned int timer_count=0; unsigned char blinkCounter=0; unsigned char TX_LED_toggle, RX_LED_toggle, status_LED_toggle; unsigned char buttonReset=1; unsigned char system_mode = 0; // 0 = rx scan, 1 = rx taking over, 2 = tx unsigned char freq_1=0, freq_2=0; // two frequencies used by DSM2 system unsigned char freq_toggle=1; // using freq_1 or freq_2? #define SERIAL_BUF_SIZE 12 char serial_buf[SERIAL_BUF_SIZE]; int serial_buf_pos=0; unsigned char tx_flag=1; // printf macro void p(char *fmt, ... ) { char tmp[128]; // resulting string limited to 128 chars va_list args; va_start (args, fmt ); vsnprintf(tmp, 128, fmt, args); va_end (args); Serial.print(tmp); } void setup() { int i; unsigned char a, b; Serial.begin(115200); Serial.println("\r\n\r\n--------------------"); Serial.println("System Powered. Initializing.\r\n\r\n"); SPI.setDataMode(0); SPI.setClockDivider(SPI_CLOCK_DIV8); pinMode(IRQ, INPUT); pinMode(TX_LED, OUTPUT); pinMode(RX_LED, OUTPUT); pinMode(STATUS_LED, OUTPUT); pinMode(BUTTON1, INPUT); /* // initialize Timer1 cli(); // disable global interrupts TCCR1A = 0; // set entire TCCR1A register to 0 TCCR1B = 0; // same for TCCR1B OCR1A = 1595; // set compare match register to desired timer count: (0.1 ms) TCCR1B |= (1 << WGM12); // turn on CTC mode: TCCR1B |= (1 << CS10); // no prescaler TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt: TIMSK0 = 0; // disable timer0 sei(); // enable global interrupts: // end Timer1 code */ chip.init(); chip.init(); digitalWrite(TX_LED, 1); digitalWrite(STATUS_LED, 1); digitalWrite(RX_LED, 1); // bootup of CYRF636, common to TX and RX modes chip.sendCommand(0x9D, 0x01); //RESET!!! DelayUs(1212); //now we wait just like the real RX does chip.sendCommand(0xA8, 0x02); //CLK_EN_ADR, writes 2 because this is a streaming application chip.sendCommand(0xB2, 0x3C); //AUTO_CAL_TIME_ADR...MUST write 0x3C to this register during initalization. So we will. chip.sendCommand(0xB5, 0x14); //AUTO_CAL_OFFSET_ADR must write 0x14 to this during initalization... chip.sendCommand(0x0D, 0x01); // reading IO_CFG_ADR before it writes to it? MISO stays 0x00...unsure why this is here but it is. chip.sendCommand(0x8D, 0x40); //now it writes to IO_CFG_ADR = 0x40 => sets IRQ polarity to be active high. Not really sure why... chip.sendCommand(0x86, 0x4A); //48 RX_CFG_ADR, LNA controlled by LNA bit, sets wide band (>1MHz above and below RX freq) chip.sendCommand(0x9B, 0x55); //TX_OFFSET_LSB_ADR, increases TX freq by 1MHz. used to avoid swithing between freqs for TX/RX. chip.sendCommand(0x9C, 0x05); //TX_OFFSET_MSB_ADR, typ. loaded with 0x05 (which it is) chip.sendCommand(0xA5, 0xFF); // unlock register chip.receiveBurstData(0x25, mfg_id, 6); // read MFG ID chip.sendCommand(0xA5, 0x00); // lock register Serial.print("MFG ID: "); printArray(mfg_id, 6); digitalWrite(TX_LED, 0); digitalWrite(RX_LED, 0); digitalWrite(STATUS_LED, 0); // set system mode. 0 = RX, 2 = TX // for takeover, use 0. for just transmit control, use 2. do not use 1. system_mode = 0; if ( digitalRead(BUTTON1) ) system_mode = 2; CRC[0] = 0xF5; CRC[1] = 0xDC; freq_1 = 72; loadSOPPN(freq_1); chip.sendCommand2(0xD5, CRC[0], CRC[1]); // CRC seed if (system_mode < 2) { RXinit(); digitalWrite(RX_LED, 1); Serial.println("Init complete! System mode is RX.\r\n\r\n"); } else { TXinit(); printArray(mfg_id, 6); digitalWrite(TX_LED, 1); digitalWrite(STATUS_LED, 1); Serial.println("Init complete! System mode is TX.\r\n\r\n"); //delay(2000); } } ISR(TIMER1_COMPA_vect) // timer interrupt: count every ~0.1 ms { timer_count++; } void loop() { unsigned char num=55; if (system_mode == 0 || system_mode == 1) { //RXinit(); if (RX_scan()) { TXinit(); payload[6] = num; TX(freq_1); if (RX_scan()) { if (rx_payload[6] == num + 20) { p("Transaction success!\r\n"); } else { p("Transaction failed! Got %i\r\n", rx_payload[2]); } } //RXinit(); } if (rx_count++ == 100) // waited for a long time and still haven't heard anything { system_mode = 1; if (RX_LED_toggle == 0 && TX_LED_toggle == 0) RX_LED_toggle = 1; } } else if (tx_flag) // TX Mode { TXinit(); digitalWrite(TX_LED, 1); p("Sending token: %i\r\n", payload[2]); TX(freq_1); //TX(freq_1); tx_flag = 0; delay(100); //digitalWrite(TX_LED, 0); //digitalWrite(RX_LED, 1); //system_mode = 0; } // read the button to toggle takeover if ( digitalRead(BUTTON1))// && system_mode<=1) { if (buttonReset) // for debouncing { buttonReset = 0; tx_flag = 1; digitalWrite(STATUS_LED, 1); blinkCounter = 0; //system_mode = 2; //RX_LED_toggle = 0; //TX_LED_toggle = 0; //digitalWrite(RX_LED, 0); } } else { buttonReset = 1; // for debouncing } if (++blinkCounter >= 10) { blinkCounter = 0; digitalWrite(STATUS_LED, 0); if (TX_LED_toggle > 0) { TX_LED_toggle--; digitalWrite(TX_LED, TX_LED_toggle); TX_LED_toggle = !TX_LED_toggle + 1; } if (RX_LED_toggle > 0) { RX_LED_toggle--; digitalWrite(RX_LED, RX_LED_toggle); RX_LED_toggle = !RX_LED_toggle + 1; } } } void TXinit() { // initialize the CYRF6936 for Transmit mode chip.sendCommand(0x85, 0x00); // RX_CTL_ADR - disable all RX interrupts chip.sendCommand(0x8F, 0xA7); // 24 ** XACT_CFG_ADR, forces transition to END STATE. Transitions to RX Synth mode after RX a packet. chip.sendCommand(0x8F, 0x87); // 24 ** XACT_CFG_ADR, forces transition to END STATE. Transitions to RX Synth mode after RX a packet. chip.sendCommand(0x83, 0x2F); // ** TX_CFG_ADR,64 chip codes, 8DR mode, +4dBm chip.sendCommand(0x92, 0x0A); // ** Data64_THOLD_ADR, 64chip dataPN code correlator. typical = 0x07, but ours is 0x0E... chip.sendCommand(0x8C, 0x80); //XTAL_CTRL_ADR, Radio data serial bit stream. chip.sendCommand(0xB9, 0x01); //ANALOG_CTRL_ADR, Enable All Slow ( synth settling time for all channels is the same as for slow channels) chip.sendCommand(0xA4, 0x04); // framing preamble chip.sendCommand(0xA4, 0x33); // framing preamble chip.sendCommand(0xA4, 0x33); // framing preamble chip.sendCommand(0x90, 0xEE); //FRAMING_CFG_ADR, SOP enable, SOP_CODE_ADR = 64chips, Packet length EN, 8 bits following SOP are packet length, SOP correlator thold...we'll probably end up changing this so we don't care aobut the CRC. chip.sendCommand(0x9F, 0x00); //TX_OVERRIDE_ADR, does nothing... chip.sendCommand(0x9E, 0x02); //does nothing... //chip.sendCommand(0x8F, 0x24); // ** XACT_CFG_ADR, } void RXinit() { // initialize the CYRF6936 for Receive mode //chip.sendCommand(0x8F, 0x2C); // XACT_CFG_ADR, fForce end state, set end state = synth mode RX //chip.sendCommand(0x83, 0x3F); // TX_CFG_ADR, SDR Data Mode, PA to max chip.sendCommand(0x92, 0x0E); // DATA64_THOLD_ADR,Set 64- Chip Data PN Code Correlator Threshold to 0E chip.sendCommand(0x8C, 0x80); // XTAL_CTRL_ADR, Radio data serial bit stream. chip.sendCommand(0x8F, 0x8F); // 0c XACT_CFG_ADR, Set end state = synth mode RX DelayUs(400); chip.sendCommand(0x83, 0x2F); // TX_CFG_ADR, Use 64 chip codes, 8DR data mode, PA to max chip.sendCommand(0x90, 0xEE); // FRAMING_CFG_ADR, SOP enable, Packet Length Enable, 64 chip codes, SOP threshold E chip.sendCommand(0x9F, 0x00); // TX_OVERRIDE_ADR, Do not override any TX device defaults chip.sendCommand(0x9E, 0x02); // RX_OVERRIDE_ADR, Do not override any RX device defaults } void TX(unsigned char channel) { // transmit payload data on a specific frequency unsigned char tx_irq_stat; unsigned char tx_repeat_num=0; //if (!takeoverEnabled) return; // must push the button to enable takeover tx_start: chip.sendCommand(0x80, channel); // set channel (2400 + channel MHz) //chip.sendCommand2(0xD5, CRC[0], CRC[1]); // CRC seed //loadSOPPN(channel); // load the SOP and PN chip.sendCommand2(0xC1, 0x10, 0x43); // set packet length to 16, clear TX FIFO chip.sendBurstCommand(0xA0, payload, PAYLOAD_LENGTH); // add data to TX FIFO chip.sendCommand(0x82, 0x83); // TX GO, interrupts on TX completion and error while (digitalRead(IRQ) == 0) { } // wait for TX to finish or error digitalWrite(STATUS_LED, 0); tx_irq_stat = chip.sendCommand(0x04, 0x00); // read TX_IRQ_STATUS_ADR //delay(4); if (tx_irq_stat & 0x01) //if TX Error { if (tx_repeat_num++ >= 5) { p("TX Error: 0x%02X, giving up.\r\n", tx_irq_stat); TX_LED_toggle = 1; return; } //p("TX Error: 0x%02X, resending packet.\r\n", tx_irq_stat); //delay(10); goto tx_start; } p("TX success!\r\n"); } void loadSOPPN(unsigned char channel) { // load the SOP and PN codes for a specific channel soppnrow = channel % 5; // 5 SOP/PN pairs total, find the one that matches based on the channel for (i=0; i 0) // check if data in FIFO { chip.receiveBurstData(0x21, rx_payload, rx_size); // might not be valid if < PAYLOAD_LENGTH if (rx_size == PAYLOAD_LENGTH && (rx_irq_stat & 0x02) && !(rx_irq_stat & 0x04)) // valid data { printArray(rx_payload, PAYLOAD_LENGTH); payload[2] = rx_payload[2]+1; digitalWrite(STATUS_LED, 1); p("Got token: %i\r\n", rx_payload[2]); digitalWrite(STATUS_LED, 1); blinkCounter = 0; //TXinit(); //TX(channel); system_mode = 2; // switch to transmit mode //rx_count = 0; RX_LED_toggle = 0; //delay(100); digitalWrite(RX_LED, 0); return 1; } } } chip.sendCommand(0xA9, 0x20); //abort enable chip.sendCommand(0x13, 0x00); //dummy read RSSI //chip.sendCommand(0x8F, 0x2C); //XACT_CFG_ADR, forces transition to END STATE. Transitions to RX Synth mode after RX a packet. //chip.sendCommand(0x0F, 0x01); //read XACT_CFG_ADR? chip.sendCommand(0xA9, 0x00); //abort disable return 0; } void emptyPayload() { // set all bytes in rx_payload to 0 unsigned char i; for (i=0; i<=PAYLOAD_LENGTH; i++) rx_payload[i] = 0; } void printPayload(unsigned char *payload) { unsigned char i; p("Payload: "); for (i=0; i