Oskar Weigl
/
Quadcopterv2
This is for ICRS\' second generation Quadcopter
Diff: RF12B/RF12B.cpp
- Revision:
- 0:0bbf2f16da9c
diff -r 000000000000 -r 0bbf2f16da9c RF12B/RF12B.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/RF12B/RF12B.cpp Fri Nov 18 18:23:33 2011 +0000 @@ -0,0 +1,377 @@ +#include "RF12B.h" + +#include "RF_defs.h" +#include <algorithm> + +RF12B::RF12B(PinName _SDI, + PinName _SDO, + PinName _SCK, + PinName _NCS, + PinName _NIRQ):spi(_SDI, _SDO, _SCK), + NCS(_NCS), NIRQ(_NIRQ), NIRQ_in(_NIRQ), rfled(LED3) { + + /* SPI frequency, word lenght, polarity and phase */ + spi.format(16,0); + spi.frequency(2000000); + + /* Set ~CS high */ + NCS = 1; + + /* Initialise RF Module */ + init(); + + /* Setup interrupt to happen on falling edge of NIRQ */ + NIRQ.fall(this, &RF12B::rxISR); +} + +/* Returns the packet length if data is available in the receive buffer, 0 otherwise*/ +unsigned int RF12B::available() { + return fifo.size(); +} + +/* Reads a packet of data, with length "size" Returns false if read failed. TODO: make a metafifo to isolate packets*/ +bool RF12B::read(unsigned char* data, unsigned int size) { + if (fifo.size() == 0) { + return false; + } else { + unsigned int i = 0; + while (fifo.size() > 0 && i < size) { + data[i++] = fifo.front(); + fifo.pop(); + } + return true; + } +} + +/* Reads a byte of data from the receive buffer */ +unsigned char RF12B::read() { + if (available()) { + unsigned char data = fifo.front(); + fifo.pop(); + return data; + } else { + return 0xFF; // Error val although could also be data... + } +} + +/* Sends a packet of data to the RF module for transmission TODO: Make asych*/ +void RF12B::write(unsigned char *data, unsigned char length) { + unsigned char crc = 0; + + /* Transmitter mode */ + changeMode(TX); + + writeCmd(0x0000); + send(0xAA); // PREAMBLE + send(0xAA); + send(0xAA); + send(0x2D); // SYNC + send(0xD4); + /* Packet Length */ + send(length); + crc = crc8(crc, length); + send(crc); + crc = crc8(crc, crc); + /* Packet Data */ + for (unsigned char i=0; i<length; i++) { + send(data[i]); + crc = crc8(crc, data[i]); + } + send(crc); + send(0xAA); // DUMMY BYTES + send(0xAA); + send(0xAA); + + /* Back to receiver mode */ + changeMode(RX); + status(); +} + +/* Transmit a 1-byte data packet */ +void RF12B::write(unsigned char data) { + write(&data, 1); +} + +void RF12B::write(queue<char> &data, int length) { + char crc = 0; + char length_byte = 0; + + /* -1 means try to transmit everything in the queue */ + if(length == -1) { + length = data.size(); + } + + /* max length of packet is 255 */ + length_byte = min(length, 255); + + /* Transmitter mode */ + changeMode(TX); + + writeCmd(0x0000); + send(0xAA); // PREAMBLE + send(0xAA); + send(0xAA); + send(0x2D); // SYNC + send(0xD4); + /* Packet Length */ + send(length_byte); + crc = crc8(crc, length_byte); + send(crc); + crc = crc8(crc, crc); + /* Packet Data */ + for (char i=0; i<length_byte; i++) { + send(data.front()); + crc = crc8(crc, data.front()); + data.pop(); + } + send(crc); + send(0xAA); // DUMMY BYTES + send(0xAA); + send(0xAA); + + /* Back to receiver mode */ + changeMode(RX); + status(); +} + +/********************************************************************** + * PRIVATE FUNCTIONS + *********************************************************************/ + +/* Initialises the RF12B module */ +void RF12B::init() { + /* writeCmd(0x80E7); //EL,EF,868band,12.0pF + changeMode(RX); + writeCmd(0xA640); //frequency select + writeCmd(0xC647); //4.8kbps + writeCmd(0x94A0); //VDI,FAST,134kHz,0dBm,-103dBm + writeCmd(0xC2AC); //AL,!ml,DIG,DQD4 + writeCmd(0xCA81); //FIFO8,SYNC,!ff,DR + writeCmd(0xCED4); //SYNC=2DD4 + writeCmd(0xC483); //@PWR,NO RSTRIC,!st,!fi,OE,EN + writeCmd(0x9850); //!mp,90kHz,MAX OUT + writeCmd(0xCC17); //OB1, COB0, LPX, Iddy, CDDIT�CBW0 + writeCmd(0xE000); //NOT USED + writeCmd(0xC800); //NOT USED + writeCmd(0xC040); //1.66MHz,2.2V */ + + writeCmd( + RFM_CONFIG_EL | + RFM_CONFIG_EF | + RFM_CONFIG_BAND_433 //| + //RFM_CONFIG_X_11_0pf // meh, using default + ); + + // 2. Power Management Command + // leave everything switched off for now + /* + writeCmd( + RFM_POWER_MANAGEMENT // switch all off + ); + */ + + // 3. Frequency Setting Command + writeCmd( + RFM_FREQUENCY | + RFM_FREQ_433Band(435.7) //I totally made this value up... if someone knows where the sweetspots are in this band, tell me! + ); + + + // 4. Data Rate Command + writeCmd(RFM_DATA_RATE_9600); + + + // 5. Receiver Control Command + writeCmd( + RFM_RX_CONTROL_P20_VDI | + RFM_RX_CONTROL_VDI_FAST | + //RFM_RX_CONTROL_BW(RFM_BAUD_RATE) | + RFM_RX_CONTROL_BW_134 | // CHANGE THIS TO 67 TO IMPROVE RANGE! (though the bitrate must then be below 8kbaud, and fsk modulation changed) + RFM_RX_CONTROL_GAIN_0 | + RFM_RX_CONTROL_RSSI_103 // Might need adjustment. Datasheet says around 10^-5 bit error rate at this level and baudrate. + ); + + // 6. Data Filter Command + writeCmd( + RFM_DATA_FILTER_AL | + RFM_DATA_FILTER_ML | + RFM_DATA_FILTER_DIG //| + //RFM_DATA_FILTER_DQD(4) + ); + + // 7. FIFO and Reset Mode Command + writeCmd( + RFM_FIFO_IT(8) | + RFM_FIFO_DR | + 0x8 //turn on 16bit sync word + ); + + // 8. FIFO Syncword + // Leave as default: 0xD4 + + // 9. Receiver FIFO Read + // when the interupt goes high, (and if we can assume that it was a fifo fill interrupt) we can read a byte using: + // result = RFM_READ_FIFO(); + + // 10. AFC Command + writeCmd( + //RFM_AFC_AUTO_VDI | //Note this might be changed to improve range. Refer to datasheet. + RFM_AFC_AUTO_INDEPENDENT | + RFM_AFC_RANGE_LIMIT_7_8 | + RFM_AFC_EN | + RFM_AFC_OE | + RFM_AFC_FI + ); + + // 11. TX Configuration Control Command + writeCmd( + RFM_TX_CONTROL_MOD_60 | + RFM_TX_CONTROL_POW_0 + ); + + + // 12. PLL Setting Command + writeCmd( + 0xCC77 & ~0x01 // Setting the PLL bandwith, less noise, but max bitrate capped at 86.2 + // I think this will slow down the pll's reaction time. Not sure, check with someone! + ); + + changeMode(RX); + resetRX(); + status(); +} + +/* Write a command to the RF Module */ +unsigned int RF12B::writeCmd(unsigned int cmd) { + NCS = 0; + unsigned int recv = spi.write(cmd); + NCS = 1; + return recv; +} + +/* Sends a byte of data across RF */ +void RF12B::send(unsigned char data) { + while (NIRQ); + writeCmd(0xB800 + data); +} + +/* Change the mode of the RF module to Transmitting or Receiving */ +void RF12B::changeMode(rfmode_t _mode) { + mode = _mode; + if (_mode == TX) { + writeCmd(0x8239); //!er,!ebb,ET,ES,EX,!eb,!ew,DC + } else { /* mode == RX */ + writeCmd(0x8299); //er,!ebb,ET,ES,EX,!eb,!ew,DC + } +} + +/* Interrupt routine for data reception */ +void RF12B::rxISR() { + unsigned int data = 0; + static int i = -2; + static unsigned char packet_length = 0; + static unsigned char crc = 0; + static queue<unsigned char> temp; + + //Loop while interrupt is asserted + while (!NIRQ_in && mode == RX) { + + /* Grab the packet's length byte */ + if (i == -2) { + data = writeCmd(0x0000); + if ( (data&0x8000) ) { + data = writeCmd(0xB000); + packet_length = (data&0x00FF); + crc = crc8(crc, packet_length); + i++; + } + } + + //If we exhaust the interrupt, exit + if (NIRQ_in) + break; + + // Check that packet length was correct + if (i == -1) { + data = writeCmd(0x0000); + if ( (data&0x8000) ) { + data = writeCmd(0xB000); + unsigned char crcofsize = (data&0x00FF); + if (crcofsize != crc) { + //It was wrong, start over + i = -2; + packet_length = 0; + crc = 0; + temp = queue<unsigned char>(); + resetRX(); + } else { + crc = crc8(crc, crcofsize); + i++; + } + } + } + + //If we exhaust the interrupt, exit + if (NIRQ_in) + break; + + /* Grab the packet's data */ + if (i >= 0 && i < packet_length) { + data = writeCmd(0x0000); + if ( (data&0x8000) ) { + data = writeCmd(0xB000); + temp.push(data&0x00FF); + crc = crc8(crc, (unsigned char)(data&0x00FF)); + i++; + } + } + + //If we exhaust the interrupt, exit + if (NIRQ_in) + break; + + if (i >= packet_length) { + data = writeCmd(0x0000); + if ( (data&0x8000) ) { + data = writeCmd(0xB000); + if ((unsigned char)(data & 0x00FF) == crc) { + //If the checksum is correct, add our data to the end of the output buffer + while (!temp.empty()) { + fifo.push(temp.front()); + temp.pop(); + } + } + + /* Tell RF Module we are finished, and clean up */ + i = -2; + packet_length = 0; + crc = 0; + temp = queue<unsigned char>(); + resetRX(); + } + } + } +} + +unsigned int RF12B::status() { + return writeCmd(0x0000); +} + +/* Tell the RF Module this packet is received and wait for the next */ +void RF12B::resetRX() { + writeCmd(0xCA81); + writeCmd(0xCA83); +}; + +/* Calculate CRC8 */ +unsigned char RF12B::crc8(unsigned char crc, unsigned char data) { + crc = crc ^ data; + for (int i = 0; i < 8; i++) { + if (crc & 0x01) { + crc = (crc >> 1) ^ 0x8C; + } else { + crc >>= 1; + } + } + return crc; +} \ No newline at end of file