blob: c4d775217e4e8453715137ed0440b94e60eb55d2 [file] [log] [blame]
/**
* \file
* Device driver and packet framing for the RFM-TR1001 radio module.
* \author FU Berlin (original implementation)
* \author Adam Dunkels <adam@sics.se>
*
* This file implements a device driver for the RFM-TR1001 radio
* tranciever as well as a simple packet framing format, simimilar to
* PPP (AHDLC) framing.
*
* \note A lot of the stuff in this file is currently a "hack" form
* (particularly the "MAC" stuff and the ackowledgements)!
*/
#include "tr1001.h"
#include "uip.h"
#include "uip-fw.h"
#include "sensors.h"
#include <io.h>
#include <signal.h>
#define RXSTATE_READY 0 /**< \internal Receive state: ready for a
new packet. */
#define RXSTATE_START1 1 /**< \internal Receive state: first start
byte read, waiting for second. */
#define RXSTATE_START2 2 /**< \internal Receive state: second start
byte read, waiting for header. */
#define RXSTATE_RAWHEADER 3 /**< \internal Receive state: reading raw
packet header, without encoding. */
#define RXSTATE_HEADER1 4 /**< \internal Receive state: reading
packet header, non-negative byte. */
#define RXSTATE_HEADER2 5 /**< \internal Receive state: reading
packet header, negative byte. */
#define RXSTATE_RAWDATA 6 /**< \internal Receive state: reading raw
packet data, without encoding. */
#define RXSTATE_DATA1 7 /**< \internal Receive state: reading
packet data, non-negative byte. */
#define RXSTATE_DATA2 8 /**< \internal Receive state: reading
packet data, negative byte. */
#define RXSTATE_ERROR 9 /**< \internal Receive state: error in
packet reception. */
#define RXSTATE_FULL 10 /**< \internal Receive state: a full packet
has been received. */
#define NEG(b) (0xff - b) /**< \internal Logical negation of an 8-bit
quantity. */
/**
* \internal
* The buffer which holds incoming data.
*/
#define RXBUFSIZE UIP_BUFSIZE
static unsigned char rxbuf[RXBUFSIZE];
/**
* \internal
* A pointer into the rxbuf buffer which points to the next available byte.
*/
static unsigned short rxpos;
/**
* \internal
* The length of the packet that currently is being received.
*/
static unsigned short rxlen;
/**
* \internal
* The reception state.
*/
static unsigned char rxstate = RXSTATE_READY;
/**
* \internal
* The structure of the packet header.
*/
struct tr1001_hdr {
u8_t type; /**< The packet type. */
u8_t id; /**< A packet identifier. */
u8_t len[2]; /**< The 16-bit length of the packet in network byte
order. */
};
/**
* \internal The length of the packet header.
*/
#define TR1001_HDRLEN 4
/**
* \internal
* The "data" packet type.
*/
#define TR1001_TYPE_DATA 1
/**
* \internal
* The "acknowledgement" packet type.
*/
#define TR1001_TYPE_ACK 2
/**
* \internal
* Determines if the negencoding should be used or not. This
* causes each byte which is sent out to be sent twice, first normally
* and second with all bits inverted. */
#define TR1001_CONF_NEGENCODING 1
/**
* \internal
* The incremental packet identifier.
*/
static u8_t packet_id;
/*------------------------------------------------------------------------------*/
/**
* \internal
* Turn on data transmission in On-Off-Keyed mode.
*/
/*------------------------------------------------------------------------------*/
static void
txook(void)
{
P3SEL = 0xf0;
P5OUT |= 0x40;
P5OUT &= 0x7f;
}
/*------------------------------------------------------------------------------*/
/**
* \internal
* Turn on data reception for the radio tranceiver.
*/
/*------------------------------------------------------------------------------*/
static void
rxon(void)
{
P3SEL = 0xe0;
P5OUT |= 0xc0;
}
/*------------------------------------------------------------------------------*/
/**
* \internal
* Clear the recevie buffer and reset the receiver state.
*/
/*------------------------------------------------------------------------------*/
static void
rxclear(void)
{
rxpos = 0;
rxstate = RXSTATE_READY;
}
/*------------------------------------------------------------------------------*/
/**
* \internal
* Send a byte of data over the radio.
*
* \param b The byte to be sent.
*/
/*------------------------------------------------------------------------------*/
static void
send(unsigned char b)
{
/* Wait until the USART0 TX buffer is ready. */
while((IFG1 & UTXIFG0) == 0);
/* Send the byte. */
TXBUF0 = b;
}
/*------------------------------------------------------------------------------*/
/**
* \internal
* Send a byte of data and its logical negation (all bits inverted)
* over the radio.
*
* \param b The byte to be sent.
*/
/*------------------------------------------------------------------------------*/
static void
send2(unsigned char b)
{
send(b);
#if TR1001_CONF_NEGENCODING
send(NEG(b));
#endif /* TR1001_CONF_NEGENCODING */
}
/*------------------------------------------------------------------------------*/
/**
* Set the transmission power of the tranciever.
*
* The sensor board is equipped with a DS1804 100 position trimmer
* potentiometer which is used to set the transmission input current
* to the radio tranciever chip, thus setting the transmission power
* of the radio tranciever.
*
* This function sets the trimmer potentiometer to a value between 1
* and 100.
*
* \param p The power of the tranciever, between 1 (lowest) and 100
* (highest).
*/
/*------------------------------------------------------------------------------*/
void
tr1001_set_txpower(unsigned char p)
{
int i;
/* Clamp maximum power. */
if(p > 100) {
p = 100;
}
/* First, run the potentiometer down to zero so that we know the
start value of the potentiometer. */
P2OUT &= 0xDF; /* P25 = 0 (down selected) */
P2OUT &= 0xBF; /* P26 = 0 (chipselect on) */
for(i = 0; i < 102; ++i) {
P2OUT &= 0xEF; /* P24 = 0 (inc) */
P2OUT |= 0x10;
}
/* Now, start to increase the value of the potentiometer until it
reaches the desired value.*/
P2OUT |= 0x20; /* P25 = 1 (up selected) */
for(i = 0; i < p; ++i) {
P2OUT &= 0xEF; /* P24 = 0 (inc) */
P2OUT |= 0x10;
}
P2OUT |= 0x40; /* P26 = 1 (chipselect off) */
}
/*------------------------------------------------------------------------------*/
/**
* Initialize the radio tranciever.
*
* Turns on reception of bytes and installs the receive interrupt
* handler.
*/
/*------------------------------------------------------------------------------*/
void
tr1001_init(void)
{
/* Turn on reception. */
rxon();
/* Reset reception state. */
rxclear();
UCTL0 = CHAR; /* 8-bit character */
UTCTL0 = SSEL1; /* UCLK = SMCLK */
#define TR1001_SPEED 19200
if(TR1001_SPEED == 19200) {
/* Set TR1001 to 19200 */
UBR00 = 0x80; /* 2,457MHz/19200 = 128 -> 0x80 */
UBR10 = 0x00; /* */
UMCTL0 = 0x00; /* no modulation */
} else if(TR1001_SPEED == 38400) {
/* Set TR1001 to 38400 */
UBR00 = 0x40; /* 2,457MHz/38400 = 64 -> 0x40 */
UBR10 = 0x00; /* */
UMCTL0 = 0x00; /* no modulation */
} else if(TR1001_SPEED == 57600) {
UBR00 = 0x2a; /* 2,457MHz/57600 = 42.7 -> 0x2A */
UBR10 = 0x00; /* */
UMCTL0 = 0x5b; /* */
} else if(TR1001_SPEED == 115200) {
UBR00 = 0x15; /* 2,457MHz/115200 = 21.4 -> 0x15 */
UBR10 = 0x00; /* */
UMCTL0 = 0x4a; /* */
}
#if 0
/* 19200 bps */
UBR00 = 0x80; /* 2,457MHz/19200 = 128 -> 0x80 */
UBR10 = 0x00; /* */
UMCTL0 = 0x00; /* no modulation */
#endif /* 0 */
ME1 |= UTXE0 + URXE0; /* Enable USART0 TXD/RXD */
/* Turn on receive interrupt. */
IE1 |= URXIE0;
}
/*------------------------------------------------------------------------------*/
/**
* Check if an incoming packet has been received.
*
* This function checks the receive buffer to see if an entire packet
* has been received. The actual reception is handled by an interrupt
* handler.
*
* \return The length of the received packet, or 0 if no packet has
* been received.
*/
/*------------------------------------------------------------------------------*/
unsigned short
tr1001_poll(void)
{
unsigned short tmplen;
if(rxstate == RXSTATE_FULL) {
if(rxlen > UIP_BUFSIZE - UIP_LLH_LEN) {
rxlen = UIP_BUFSIZE - UIP_LLH_LEN;
}
memcpy(&uip_buf[UIP_LLH_LEN], rxbuf + TR1001_HDRLEN, rxlen);
tmplen = rxlen;
rxclear();
return tmplen;
}
if(rxstate == RXSTATE_ERROR) {
blink();
rxclear();
}
return 0;
}
/*------------------------------------------------------------------------------*/
/**
* \internal
* Interrupt handler for the data reception.
*/
/*------------------------------------------------------------------------------*/
interrupt (UART0RX_VECTOR)
tr1001_rxhandler(void)
{
unsigned char c;
c = RXBUF0;
switch(rxstate) {
case RXSTATE_ERROR:
/* Do nothing, wait until error has been hendled. */
break;
case RXSTATE_READY:
if(c == 0xff) {
rxstate = RXSTATE_START1;
}
break;
case RXSTATE_START1:
if(c == 0x01) {
rxstate = RXSTATE_START2;
} else {
rxstate = RXSTATE_READY;
}
break;
case RXSTATE_START2:
if(c == 0x7f) {
#if TR1001_CONF_NEGENCODING
rxstate = RXSTATE_HEADER1;
#else /* TR1001_CONF_NEGENCODING */
rxstate = RXSTATE_RAWHEADER;
#endif /* TR1001_CONF_NEGENCODING */
} else {
rxstate = RXSTATE_READY;
}
break;
case RXSTATE_RAWHEADER:
rxbuf[rxpos] = c;
++rxpos;
if(rxpos == TR1001_HDRLEN) {
rxlen = ((((struct tr1001_hdr *)rxbuf)->len[0] << 8) +
((struct tr1001_hdr *)rxbuf)->len[1]);
rxstate = RXSTATE_RAWDATA;
}
break;
case RXSTATE_HEADER1:
/* Receive a data byte of the header. */
rxbuf[rxpos] = c;
rxstate = RXSTATE_HEADER2;
break;
case RXSTATE_HEADER2:
/* We should have received the bit-wise negation of the previously
received byte, or else something has gone wrong and we set the
error flag. */
if(NEG(c) == rxbuf[rxpos]) {
++rxpos;
if(rxpos == TR1001_HDRLEN) {
rxlen = ((((struct tr1001_hdr *)rxbuf)->len[0] << 8) +
((struct tr1001_hdr *)rxbuf)->len[1]);
rxstate = RXSTATE_DATA1;
} else {
rxstate = RXSTATE_HEADER1;
}
} else {
rxstate = RXSTATE_ERROR;
}
break;
case RXSTATE_DATA1:
/* Receive a data byte. */
rxbuf[rxpos] = c;
rxstate = RXSTATE_DATA2;
break;
case RXSTATE_DATA2:
/* We should have received the bit-wise negation of the previously
received byte, or else something has gone wrong and we set the
error flag. */
if(NEG(c) == rxbuf[rxpos]) {
++rxpos;
if(rxpos == rxlen + TR1001_HDRLEN) {
rxstate = RXSTATE_FULL;
} else if(rxpos > sizeof(rxbuf)) {
rxstate = RXSTATE_ERROR;
} else {
rxstate = RXSTATE_DATA1;
}
} else {
rxstate = RXSTATE_ERROR;
}
break;
case RXSTATE_RAWDATA:
rxbuf[rxpos] = c;
++rxpos;
if(rxpos == rxlen + TR1001_HDRLEN) {
rxstate = RXSTATE_FULL;
} else if(rxpos > sizeof(rxbuf)) {
rxstate = RXSTATE_ERROR;
}
break;
case RXSTATE_FULL:
/* Just drop the incoming byte. */
break;
default:
/* Just drop the incoming byte. */
rxstate = RXSTATE_READY;
break;
}
}
/*------------------------------------------------------------------------------*/
/**
* \internal
*
* A stupid function which causes a small delay based on its argument.
*
* It is a hack, not intended for "real" use.
*
*/
/*------------------------------------------------------------------------------*/
static void
delay_hack(int d)
{
int i, j = 2;
for(i = 0; i < d; ++i) {
j = j * j;
}
}
/*------------------------------------------------------------------------------*/
/**
* \internal
*
* Prepare a transmission.
*
* This function does the necessary setup before a packet can be sent
* out.
*/
/*------------------------------------------------------------------------------*/
static void
prepare_transmission(void)
{
unsigned short i, laststate;
/* Delay the transmission for a while. The length of the delay is
based on the lowest bits of the battery sensor, which seems to be
jumping up and down somewhat unpredictably (but I might very well
be wrong). */
/* P2OUT &= 0xFE;*/
delay_hack(400 * (sensors_battery & 0x0f));
/* P2OUT |= 0x01; */
/* First check that we don't currently are receiveing a packet, and
if so we wait until the reception has been completed. Reception
is done with interrupts so it is OK for us to wait in a while()
loop. */
i = 0;
laststate = rxstate;
while(rxstate != RXSTATE_READY &&
rxstate != RXSTATE_FULL &&
rxstate != RXSTATE_ERROR) {
/* Make sure that we don't stay too long in the same rxstate
(which would indicate that the receiving interrupt somehow has
locked up). */
if(laststate == rxstate) {
++i;
if(i == 0xffff) {
rxstate = RXSTATE_ERROR;
break;
}
} else {
i = 0;
}
laststate = rxstate;
}
/* Turn on OOK mode with transmission. */
txook();
/* Delay for a while to let the transmitted settle in its new
state. */
delay_hack(400);
}
/*------------------------------------------------------------------------------*/
/**
* Send a packet and wait for an acknowledgement.
*
* This function calls tr1001_send() to send out a packet, and waits
* for an acknowledgement from the receiver.
*
*/
/*------------------------------------------------------------------------------*/
u8_t
tr1001_send_acked(void)
{
unsigned short tmplen, count;
struct tr1001_hdr *ackhdr = (struct tr1001_hdr *)rxbuf;
ek_clock_t start;
tr1001_send();
start = ek_clock();
count = 0;
P2OUT &= 0xFB;
/* Block while checking if a packet has arrived. */
while((volatile u8_t)rxstate != RXSTATE_FULL &&
(volatile u8_t)rxstate != RXSTATE_ERROR) {
/* Wait no more than one second. */
if((ek_clock_t)(ek_clock() - start) > (ek_clock_t)CLK_TCK) {
break;
}
}
P2OUT |= 0x04;
if(rxstate == RXSTATE_FULL) {
if(ackhdr->type == TR1001_TYPE_ACK &&
ackhdr->id == packet_id) {
beep();
rxclear();
return UIP_FW_OK;
}
}
if(rxstate == RXSTATE_ERROR) {
rxclear();
blink();
}
return UIP_FW_DROPPED;
}
/*------------------------------------------------------------------------------*/
/**
* Send out a packet from the uip_buf buffer.
*
* This function causes a packet to be sent out after a small random
* delay, but without doing any MAC layer collision detection or
* back-offs. The packet is sent with a 4 byte header that contains a
* a "type" identifier, an 8-bit packet ID field and the length of the
* packet in network byte order.
*/
/*------------------------------------------------------------------------------*/
u8_t
tr1001_send(void)
{
u8_t *hdr;
u16_t hdrlen;
u8_t *data;
u16_t datalen;
int i;
hdr = &uip_buf[UIP_LLH_LEN];
hdrlen = UIP_TCPIP_HLEN;
data = uip_appdata;
if(uip_len < UIP_TCPIP_HLEN) {
datalen = 0;
} else {
datalen = uip_len - UIP_TCPIP_HLEN;
}
/* Prepare the transmission. */
prepare_transmission();
/* Send first preamble byte. */
send(0xaa);
/* Send second preamble byte. */
send(0xaa);
/* Send sync byte. */
send(0x0ff);
/* Send first start byte. */
send(0x01);
/* Send second start byte. */
send(0x07f);
/* Send packet header. */
send2(TR1001_TYPE_DATA);
send2(++packet_id);
send2(uip_len >> 8);
send2(uip_len & 0xff);
/* Send packet data. */
for(i = 0; i < hdrlen; ++i) {
send2(hdr[i]);
}
for(i = 0;i < datalen; ++i) {
send2(data[i]);
}
/* Send trailing bytes. */
send(0xaa);
send(0xaa);
/* Turn on reception again. */
rxon();
return UIP_FW_OK;
}
/*------------------------------------------------------------------------------*/
/**
* Acknowledge a received packet.
*
* This function sends out an acknowledgement packet for the
* previously received packet, which must be present in the uip_buf
* buffer.
*
* \retval UIP_FW_OK The acknowledgement was successfully.
* \retval UIP_FW_DROPPED The acknowledgement was dropped before transmission.
*/
/*------------------------------------------------------------------------------*/
u8_t
tr1001_ack(void)
{
/* Prepare the transmission. */
prepare_transmission();
/* Send first preamble byte. */
send(0xaa);
/* Send second preamble byte. */
send(0xaa);
/* Send sync byte. */
send(0x0ff);
/* Send first start byte. */
send(0x01);
/* Send second start byte. */
send(0x07f);
/* Send packet header. */
send2(TR1001_TYPE_ACK);
send2(((struct tr1001_hdr *)uip_buf)->id);
send2(0);
send2(0);
/* Send trailing bytes. */
send(0xaa);
send(0xaa);
/* Turn on reception again. */
rxon();
/* beep();*/
return UIP_FW_OK;
}
/*------------------------------------------------------------------------------*/