Exemple #1
0
uint8_t Rfm12b::Send (uint8_t* Data, uint8_t Length) {
	uint8_t i;
	
	RFM12_INT_OFF();
	if ((InputLength > 0) ||
        (Rfm12bSpi.GetWord (RFM12B_STATUS_CMD) & RFM12B_STATUS_RSSI_PIN) != 0) {
        // either already receiving something or RFM12B detects a 
        // signal, so don't send now
	    RFM12_INT_ON();
	    return 0;
        }        
	Rfm12bSpi.SendWord (RF_IDLE_MODE);      // switch off receiver
	OutputData[LENGTH_BYTE] = Length + 2;   // include 2 crc bytes in length
    memcpy ((void*) &OutputData[LENGTH_BYTE+1], Data, Length);
	OutputLength = Length + LENGTH_BYTE + 1;    // include 4 preamble bytes + 1 Length byte
    // calculate crc and put it into output buffer
	Crc = ~0;
	for (i=0; i <= Length; i++)
		Crc = _crc16_update(Crc, OutputData[i+4]);
	OutputData[OutputLength++] = Crc & 0xFF;
	OutputData[OutputLength++] = Crc >> 8;
    // add trailer byte to end of packet to ensure last byte of data is transmitted completely
	OutputData[OutputLength] = PREAMBLE;
    // pre-load preamble byte into transmit buffer to get things going quickly
	Rfm12bSpi.SendWord (RFM12B_TX_CMD + PREAMBLE);
    // turn on transmitter
    Rfm12bSpi.SendWord (RF_XMITTER_ON); // bytes will be fed via interrupts
	RFM12_INT_ON();
    return Length;
	}
Exemple #2
0
void Rfm12b::Initialize () {	
	Rfm12bSpi.SendWord (RFM12B_STATUS_CMD);              // initial SPI transfer added to avoid power-up problem?
	Rfm12bSpi.SendWord (RF_IDLE_MODE);                   // disable clk pin
	Rfm12bSpi.SendWord (RFM12B_TX_CMD);                  // in case we're still in OOK mode
	Rfm12bSpi.SendWord (CONFIGURATION | (BAND << 4));    // EL (enable TX), EF (enable RX FIFO), 12.0pF, 915 MHz
	Rfm12bSpi.SendWord (RFM12B_DATARATE_CMD | DATARATE); // approx 49.2 Kbps, i.e. 10000/29/(1+6) Kbps
	Rfm12bSpi.SendWord (RX_CONFIG);                      // VDI, FAST, 134kHz, 0dBm, -91dBm
	Rfm12bSpi.SendWord (DATA_FILTER);                    // AL, !ml, DIG, DQD=4
	Rfm12bSpi.SendWord (FIFO_CONFIG);                    // FIFO8, 2-SYNC, !ff, DR
	Rfm12bSpi.SendWord (AFC_CONFIG);                     // @PWR, NO RSTRIC, !st, !fi, OE, EN
	Rfm12bSpi.SendWord (TX_CONFIG);                      // !mp, 90kHz, MAX OUT
	Rfm12bSpi.SendWord (PLL_CONFIG);                     // force to POR for A1 version per manual (CC77)
	Rfm12bSpi.SendWord (RFM12B_WAKEUP_CMD);              // Wake-Up Timer not used
	Rfm12bSpi.SendWord (RFM12B_DUTYCYCLE_CMD);           // Low Duty-Cycle not used

	//memset ((void*) InputData, 0, 10);
	OutputIndex = OutputLength = InputLength = 0;
	Crc = ~0;
	DEBUG_INIT;
	
	RFM12_INT_ON();
	sei();
	// start receiving
	Rfm12bSpi.SendWord (RF_RECEIVER_ON);
    }
Exemple #3
0
/**
* Call a SW reset in case the module hangs (does not receive any data).
*/
void rfm12_sw_reset(void)
{
	RFM12_INT_OFF();
	rfm12_data(RFM12_CMD_RESET_FE);
	_delay_ms(200); // datasheet lists 150ms max.
	rfm12_data(RFM12_CMD_RESET_FF);
	_delay_ms(200);
	RFM12_INT_ON();
}
Exemple #4
0
	/** When enabling ASK tx mode, this function puts the internal state machine
	* into transmit mode and disables the interrupt.
	* Otherwise it will restore normale operation.
	*
	* \param [setting] Pass 1 to enable the raw mode, 0 to disable it.
	* \note You need to define RFM12_TRANSMIT_ASK as 1 to enable this.
	* \warning This will interfere with the wakeup timer feature.
	* \todo Use power management shadow register if the wakeup timer feature is enabled.
	* \see rfm12_tx_on() and rfm12_tx_off()
	*/
	void rfm12_ask_tx_mode(uint8_t setting)
	{
		if (setting)
		{
		#if 0
			/* disable the receiver */
			rfm12_data(RFM12_CMD_PWRMGT | PWRMGT_DEFAULT);

			/* fill preamble into buffer */
			rfm12_data(RFM12_CMD_TX | PREAMBLE);
			rfm12_data(RFM12_CMD_TX | PREAMBLE);
		#endif
			ctrl.rfm12_state = STATE_TX;
			RFM12_INT_OFF();
		} else
		{
			/* re-enable the receiver */
			rfm12_data(RFM12_CMD_PWRMGT | PWRMGT_DEFAULT | RFM12_PWRMGT_ER);
			RFM12_INT_ON();
			ctrl.rfm12_state = STATE_RX_IDLE;
		}
	}
Exemple #5
0
/**This function takes care of all module initialization, including:
* - Setup of the used frequency band and external capacitor
* - Setting the exact frequency (channel)
* - Setting the transmission data rate
* - Configuring various module related rx parameters, including the amplification
* - Enabling the digital data filter
* - Enabling the use of the modules fifo, as well as enabling sync pattern detection
* - Configuring the automatic frequency correction
* - Setting the transmit power 
*
* This initialization function also sets up various library internal configuration structs and
* puts the module into receive mode before returning.
*
* \note Please note that the transmit power and receive amplification values are currently hard coded.
* Have a look into rfm12_hw.h for possible settings.
*/
void rfm12_init(void)
{
	RFM12_INT_OFF(); // in case rfm12_init is called twice, make sure rfm module does not interfere

	//initialize spi
	SS_RELEASE();
	DDR_SS |= (1<<BIT_SS);	
	spi_init();

	//enable internal data register and fifo
	//setup selected band
	rfm12_data(RFM12_CMD_CFG | RFM12_CFG_EL | RFM12_CFG_EF | RFM12_BASEBAND | RFM12_XTAL_12PF);
	
	//set power default state (usually disable clock output)
	//do not write the power register two times in a short time
	//as it seems to need some recovery
	rfm12_data(RFM12_CMD_PWRMGT | PWRMGT_DEFAULT);

	//set frequency
	rfm12_data(RFM12_CMD_FREQUENCY | RFM12_FREQUENCY_CALC(FREQ) );

	//set data rate
	rfm12_data(RFM12_CMD_DATARATE | DATARATE_VALUE );
	
	//set rx parameters: int-in/vdi-out pin is vdi-out,
	//Bandwith, LNA, RSSI
	rfm12_data(RFM12_CMD_RXCTRL | RFM12_RXCTRL_P16_VDI 
			| RFM12_RXCTRL_VDI_FAST | RFM12_RXCTRL_BW_400 | RFM12_RXCTRL_LNA_6 
			| RFM12_RXCTRL_RSSI_79 );	
	
	//automatic clock lock control(AL), digital Filter(!S),
	//Data quality detector value 3, slow clock recovery lock
	rfm12_data(RFM12_CMD_DATAFILTER | RFM12_DATAFILTER_AL | 3);
	
	//2 Byte Sync Pattern, Start fifo fill when sychron pattern received,
	//disable sensitive reset, Fifo filled interrupt at 8 bits
	rfm12_data(RFM12_CMD_FIFORESET | RFM12_FIFORESET_DR | (8<<4));

	//set AFC to automatic, (+4 or -3)*2.5kHz Limit, fine mode, active and enabled
	rfm12_data(RFM12_CMD_AFC | RFM12_AFC_AUTO_KEEP | RFM12_AFC_LIMIT_4
				| RFM12_AFC_FI | RFM12_AFC_OE | RFM12_AFC_EN);
	
	//set TX Power to -0dB, frequency shift = +-125kHz
	rfm12_data(RFM12_CMD_TXCONF | RFM12_TXCONF_POWER_0 | RFM12_TXCONF_FS_CALC(125000) );
	
	//disable low dutycycle mode
	rfm12_data(RFM12_CMD_DUTYCYCLE);
	
	//disable wakeup timer
	rfm12_data(RFM12_CMD_WAKEUP);

	//store the syncronization pattern to the transmission buffer
	//the sync pattern is used by the receiver to distinguish noise from real transmissions
	//the sync pattern is hardcoded into the receiver
	rf_tx_buffer.sync[0] = SYNC_MSB;
	rf_tx_buffer.sync[1] = SYNC_LSB;
	
	//if receive mode is not disabled (default)
	#if !(RFM12_TRANSMIT_ONLY)
		//init buffer pointers
		ctrl.rf_buffer_out = &rf_rx_buffers[0];
		ctrl.rf_buffer_in  = &rf_rx_buffers[0];
		//ctrl.buffer_in_num = 0;
		//ctrl.buffer_out_num = 0;
	#endif /* !(RFM12_TRANSMIT_ONLY) */
	
	//low battery detector feature initialization
	#if RFM12_LOW_BATT_DETECTOR
		ctrl.low_batt = RFM12_BATT_OKAY;
	#endif /* RFM12_LOW_BATT_DETECTOR */
	
	//enable rf receiver chain, if receiving is not disabled (default)
	//the magic is done via defines
	rfm12_data(RFM12_CMD_PWRMGT | PWRMGT_RECEIVE);
	
	//wakeup timer feature setup
	#if RFM12_USE_WAKEUP_TIMER
		//set power management shadow register to receiver chain enabled or disabled
		//the define correctly handles the transmit only mode
		ctrl.pwrmgt_shadow = (RFM12_CMD_PWRMGT | PWRMGT_RECEIVE);
	#endif /* RFM12_USE_WAKEUP_TIMER */
	
	//ASK receive mode feature initialization
	#if RFM12_RECEIVE_ASK
		adc_init();
	#endif

	//setup interrupt for falling edge trigger
	RFM12_INT_SETUP();
	
	//clear int flag
	rfm12_read(RFM12_CMD_STATUS);
	RFM12_INT_FLAG |= (1<<RFM12_FLAG_BIT);		
	
	//init receiver fifo, we now begin receiving.
	rfm12_data(CLEAR_FIFO);
	rfm12_data(ACCEPT_DATA);
	
	//activate the interrupt
	RFM12_INT_ON();	
}
Exemple #6
0
/** This function has to be called periodically.
* It will read the rfm12 status register to check if a carrier is being received,
* which would indicate activity on the chosen radio channel. \n
* If there has been no activity for long enough, the channel is believed to be free.
*
* When there is a packet waiting for transmission and the collision avoidance
* algorithm indicates that the air is free, then the interrupt control variables are
* setup for packet transmission and the rfm12 is switched to transmit mode.
* This function also fills the rfm12 tx fifo with a preamble.
*
* \warning Warning, if you do not call this function periodically, then no packet will get transmitted.
* \see rfm12_tx() and rfm12_start_tx()
*/
void rfm12_tick(void)
{	
	//collision detection is enabled by default
	#if !(RFM12_NOCOLLISIONDETECTION)
		uint16_t status;
		
		//start with a channel free count of 16, this is necessary for the ASK receive feature to work
		static uint8_t channel_free_count = 16; //static local variables produce smaller code size than globals
	#endif

	//debug
	#if RFM12_UART_DEBUG
		static uint8_t oldstate;
		uint8_t state = ctrl.rfm12_state;
		if (oldstate != state)
		{
			uart_putstr ("mode change: ");
			switch (state)
			{
				case STATE_RX_IDLE:
					uart_putc ('i');
					break;
				case STATE_RX_ACTIVE:
					uart_putc ('r');
					break;
				case STATE_TX:
					uart_putc ('t');
					break;
				default:
					uart_putc ('?');
			}
			uart_putstr ("\r\n");
			oldstate = state;
		}
	#endif
	
	//don't disturb RFM12 if transmitting or receiving
	if(ctrl.rfm12_state != STATE_RX_IDLE)
	{
		return;
	}	
		
	//collision detection is enabled by default
	#if !(RFM12_NOCOLLISIONDETECTION)
		//disable the interrupt (as we're working directly with the transceiver now)
		//hint: we could be losing an interrupt here 
		//solutions: check status flag if int is set, launch int and exit ... OR implement packet retransmission
		RFM12_INT_OFF();	
		status = rfm12_read(RFM12_CMD_STATUS);
		RFM12_INT_ON();

		//check if we see a carrier
		if(status & RFM12_STATUS_RSSI)
		{
			//yes: reset free counter and return
			channel_free_count = CHANNEL_FREE_TIME;
			return;
		}
		
		//no: decrement counter
		channel_free_count--;
		
		//is the channel free long enough ?
		if(channel_free_count != 0)
		{
			return;
		}
		
		//reset the channel free count for the next decrement (during the next call..)
		channel_free_count = 1;
	#endif	
	
	//do we have something to transmit?
	if(ctrl.txstate == STATUS_OCCUPIED)
	{ //yes: start transmitting
		//disable the interrupt (as we're working directly with the transceiver now)
		//hint: we could be losing an interrupt here, too
		//we could also disturb an ongoing reception,
		//if it just started some cpu cycles ago 
		//(as the check for this case is some lines (cpu cycles) above)
		//anyhow, we MUST transmit at some point...
		RFM12_INT_OFF();
		
		//disable receiver - if you don't do this, tx packets will get lost
		//as the fifo seems to be in use by the receiver
		rfm12_data(RFM12_CMD_PWRMGT | PWRMGT_DEFAULT);
		
		//calculate number of bytes to be sent by ISR
		//2 sync bytes + len byte + type byte + checksum + message length + 1 dummy byte
		ctrl.num_bytes = rf_tx_buffer.len + 6;
		
		//reset byte sent counter
		ctrl.bytecount = 0;
		
		//set mode for interrupt handler
		ctrl.rfm12_state = STATE_TX;
		
		//wakeup timer feature
		#if RFM12_USE_WAKEUP_TIMER		
			ctrl.pwrmgt_shadow = (RFM12_CMD_PWRMGT | PWRMGT_DEFAULT | RFM12_PWRMGT_ET);
		#endif /* RFM12_USE_WAKEUP_TIMER */
		
		//fill 2byte 0xAA preamble into data register
		//the preamble helps the receivers AFC circuit to lock onto the exact frequency
		//(hint: the tx FIFO [if el is enabled] is two staged, so we can safely write 2 bytes before starting)
		rfm12_data(RFM12_CMD_TX | PREAMBLE);
		rfm12_data(RFM12_CMD_TX | PREAMBLE);
		
		//set ET in power register to enable transmission (hint: TX starts now)
		rfm12_data(RFM12_CMD_PWRMGT | PWRMGT_DEFAULT | RFM12_PWRMGT_ET);

		//enable the interrupt to continue the transmission
		RFM12_INT_ON();
	}
}