예제 #1
0
	/** \param [val]  The wakeup timer period value to be passed to the rf12. \n
	* See the rf12 datasheet for valid values.
	*/
	void rfm12_set_wakeup_timer(uint16_t val)
	{	
		//set wakeup timer
		rfm12_data (RFM12_CMD_WAKEUP | (val & 0x1FFF));
	
		//reset wakeup timer
		rfm12_data(RFM12_CMD_PWRMGT | (PWRMGT_DEFAULT & ~RFM12_PWRMGT_EW));
		rfm12_data(RFM12_CMD_PWRMGT |  PWRMGT_DEFAULT);		
	}
예제 #2
0
파일: rfm12.c 프로젝트: JHTW/smarthomatic
/**
* 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();
}
예제 #3
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;
		}
	}
예제 #4
0
파일: rfm12.c 프로젝트: JHTW/smarthomatic
/**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();	
}
예제 #5
0
파일: rfm12.c 프로젝트: JHTW/smarthomatic
/** 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();
	}
}
예제 #6
0
	/** \param [val]  The register value to be passed to the rf12. \n
	* See the rf12 datasheet for valid values.
	* \see rfm12_get_batt_status()
	*/
	void rfm12_set_batt_detector(uint16_t val)
	{	
		//set the low battery detector and microcontroller clock divider register
		rfm12_data (RFM12_CMD_LBDMCD | (val & 0x01FF));
	}
예제 #7
0
	/** This will usually stop a transmission.
	* This function is used to emulate amplitude modulated signals.
	*
	* \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_ask_tx_mode()
	*/
	inline void rfm12_tx_off(void)
	{
		/* turn off everything. */
		rfm12_data(RFM12_CMD_PWRMGT);
	}
예제 #8
0
	/** This will send out the current buffer contents.
	* This function is used to emulate amplitude modulated signals.
	*
	* \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_off() and rfm12_ask_tx_mode()
	*/
	inline void rfm12_tx_on(void)
	{
		/* set enable transmission bit now. */
		rfm12_data(RFM12_CMD_PWRMGT | PWRMGT_DEFAULT | RFM12_PWRMGT_ET | RFM12_PWRMGT_ES | RFM12_PWRMGT_EX);
	}
예제 #9
0
/** The frequency has to be specified using the RFM12_FREQUENCY_CALC_433(x) macro.
*
* Please refer to the rfm12 library configuration header for a demo macro usage. \n
* The frequency calculation macro can be found in  rfm12_hw.h.
* It is not included as a function for code-size reasons.
*/
void rfm12_set_frequency (uint16_t in_freq)
{
	rfm12_data(RFM12_CMD_FREQUENCY | in_freq );
}
예제 #10
0
/** The data rate has to be specified using the following macros:
* - RFM12_DATARATE_CALC_HIGH(x) for rates >= 2700 Baud
* - RFM12_DATARATE_CALC_LOW(x) for rates from 340 to < 2700 Baud
*
* Please refer to the rfm12 library configuration header for a demo macro usage. \n
* The data rate calculation macros can be found in  rfm12_hw.h.
* They are not included as a function for code-size reasons.
*/
void rfm12_set_rate (uint16_t in_datarate)
{
	rfm12_data(RFM12_CMD_DATARATE | DATARATE_VALUE );
}
예제 #11
0
파일: rfm12.c 프로젝트: damg/rts_mesh
//#warning "RFM12_INT_VECT enabled"
ISR(RFM12_INT_VECT, ISR_NOBLOCK)
#endif
{
    RFM12_INT_OFF();
    uint8_t status;

    //debug
#if RFM12_UART_DEBUG >= 2
    uart_putc('i');
#endif

    //if receive mode is not disabled (default)
#if !(RFM12_TRANSMIT_ONLY)
    static uint8_t checksum; //static local variables produce smaller code size than globals
#endif /* !(RFM12_TRANSMIT_ONLY) */

    //first we read the first byte of the status register
    //to get the interrupt flags
    status = rfm12_read_int_flags_inline();

    //low battery detector feature
#if RFM12_LOW_BATT_DETECTOR
    if(status & (RFM12_STATUS_LBD>>8))
    {
        //debug
#if RFM12_UART_DEBUG >= 2
        uart_putc('L');
#endif

        //set status variable to low battery
        ctrl.low_batt = RFM12_BATT_LOW;
    }
#endif /* RFM12_LOW_BATT_DETECTOR */

    //wakeup timer feature
#if RFM12_USE_WAKEUP_TIMER
    if(status & (RFM12_STATUS_WKUP>>8))
    {
        //debug
#if RFM12_UART_DEBUG >= 2
        uart_putc('W');
#endif

        //restart the wakeup timer by toggling the bit on and off
        rfm12_data(ctrl.pwrmgt_shadow & ~RFM12_PWRMGT_EW);
        rfm12_data(ctrl.pwrmgt_shadow);
    }
#endif /* RFM12_USE_WAKEUP_TIMER */

    //check if the fifo interrupt occurred
    if(!(status & (RFM12_STATUS_FFIT>>8)))
        goto END;

    //see what we have to do (start rx, rx or tx)
    switch(ctrl.rfm12_state)
    {
    case STATE_RX_IDLE:
        //if receive mode is not disabled (default)
#if !(RFM12_TRANSMIT_ONLY)
        //init the bytecounter - remember, we will read the length byte, so this must be 1
        ctrl.bytecount = 1;

        //read the length byte,  and write it to the checksum
        //remember, the first byte is the length byte
        checksum = rfm12_read_fifo_inline();

        //add the packet overhead and store it into a working variable
        ctrl.num_bytes = checksum + PACKET_OVERHEAD;

        //debug
#if RFM12_UART_DEBUG >= 2
        uart_putc('I');
        uart_putc(checksum);
#endif

        //see whether our buffer is free
        //FIXME: put this into global statekeeping struct, the free state can be set by the function which pulls the packet, i guess
        if(ctrl.rf_buffer_in->status == STATUS_FREE)
        {
            //the current receive buffer is empty, so we start receiving
            ctrl.rfm12_state = STATE_RX_ACTIVE;

            //store the received length into the packet buffer
            //FIXME:  why the hell do we need this?!
            //in principle, the length is stored alongside with the buffer.. the only problem is, that the buffer might be cleared during reception
            ctrl.rf_buffer_in->len = checksum;

            //end the interrupt without resetting the fifo
            goto END;
        }

        /* if we're here, the buffer is full, so we ignore this transmission by resetting the fifo (at the end of the function)  */
#endif /* !(RFM12_TRANSMIT_ONLY) */
        break;

    case STATE_RX_ACTIVE:
        //if receive mode is not disabled (default)
#if !(RFM12_TRANSMIT_ONLY)
        //check if transmission is complete
        if(ctrl.bytecount < ctrl.num_bytes)
        {
            uint8_t data;

            //read a byte
            data = rfm12_read_fifo_inline();

            //debug
#if RFM12_UART_DEBUG >= 2
            uart_putc('R');
            uart_putc(data);
#endif

            //xor the remaining bytes onto the checksum
            //note: only the header will be effectively checked
            checksum ^= data;

            //put next byte into buffer, if there is enough space
            if(ctrl.bytecount < (RFM12_RX_BUFFER_SIZE + 3))
            {
                //hackhack: begin writing to struct at offsetof len
                (& ctrl.rf_buffer_in->len)[ctrl.bytecount] = data;
            }

            //check header against checksum
            if (ctrl.bytecount == 2 && checksum != 0xff)
            {
                //if the checksum does not match, reset the fifo
                break;
            }

            //increment bytecount
            ctrl.bytecount++;

            //end the interrupt without resetting the fifo
            goto END;
        }

        /* if we're here, receiving is done */
        /* the fifo will be reset at the end of the function */

        //debug
#if RFM12_UART_DEBUG >= 2
        uart_putc('D');
#endif

        //indicate that the buffer is ready to be used
        ctrl.rf_buffer_in->status = STATUS_COMPLETE;

        //switch to other buffer
        ctrl.buffer_in_num = (ctrl.buffer_in_num + 1) % 2;
        ctrl.rf_buffer_in = &rf_rx_buffers[ctrl.buffer_in_num];
#endif /* !(RFM12_TRANSMIT_ONLY) */
        break;

    case STATE_TX:
        //debug
#if RFM12_UART_DEBUG >= 2
        uart_putc('T');
#endif

        if(ctrl.bytecount < ctrl.num_bytes)
        {
            //load the next byte from our buffer struct.
            rfm12_data_inline( (RFM12_CMD_TX>>8), rf_tx_buffer.sync[ctrl.bytecount++]);

            //end the interrupt without resetting the fifo
            goto END;
        }

        /* if we're here, we're finished transmitting the bytes */
        /* the fifo will be reset at the end of the function */

        //flag the buffer as free again
        ctrl.txstate = STATUS_FREE;

#if RFM12_UART_DEBUG >= 2
        uart_putc('f');
#endif

        //wakeup timer feature
#if RFM12_USE_WAKEUP_TIMER
        //clear wakeup timer once
        rfm12_data(ctrl.pwrmgt_shadow & ~RFM12_PWRMGT_EW);
        //set shadow register to default receive state
        //the define correctly handles the transmit only mode
        ctrl.pwrmgt_shadow = (RFM12_CMD_PWRMGT | PWRMGT_RECEIVE);
#endif /* RFM12_USE_WAKEUP_TIMER */

        //turn off the transmitter and enable receiver
        //the receiver is not enabled in transmit only mode
        //if the wakeup timer is used, this will re-enable the wakeup timer bit
        //the magic is done via defines
        rfm12_data(RFM12_CMD_PWRMGT | PWRMGT_RECEIVE);

        //load a dummy byte to clear int status
        rfm12_data_inline( (RFM12_CMD_TX>>8), 0xaa);
        break;
    }