1 | uint8_t rssiRaw; // Global variable shared between RX ISRs
|
2 | #include <asf.h>
|
3 | #include <string.h>
|
4 | #include <stdio.h>
|
5 | #include <stdlib.h>
|
6 | #include <util/delay.h>
|
7 | #define F_CPU 20000000
|
8 |
|
9 | const int RF_BUFFER_SIZE = 127;
|
10 | struct ringBuffer
|
11 | {
|
12 | unsigned char buffer[127];
|
13 | volatile unsigned int head;
|
14 | volatile unsigned int tail;
|
15 | } radioRXBuffer;
|
16 |
|
17 |
|
18 | // Initialize the RFA1's low-power 2.4GHz transciever.
|
19 | // Sets up the state machine, and gets the radio into
|
20 | // the RX_ON state. Interrupts are enabled for RX
|
21 | // begin and end, as well as TX end.
|
22 | uint8_t rfBegin(uint8_t channel)
|
23 | {
|
24 | for (int i=0; i<128; i++)
|
25 | {
|
26 | radioRXBuffer.buffer[i] = 0;
|
27 | }
|
28 | radioRXBuffer.tail = 0;
|
29 | radioRXBuffer.head = 0;
|
30 |
|
31 | // Transceiver Pin Register -- TRXPR.
|
32 | // This register can be used to reset the transceiver, without
|
33 | // resetting the MCU.
|
34 | TRXPR |= (1<<TRXRST); // TRXRST = 1 (Reset state, resets all registers)
|
35 |
|
36 | // Transceiver Interrupt Enable Mask - IRQ_MASK
|
37 | // This register disables/enables individual radio interrupts.
|
38 | // First, we'll disable IRQ and clear any pending IRQ's
|
39 | IRQ_MASK = 0; // Disable all IRQs
|
40 |
|
41 | // Transceiver State Control Register -- TRX_STATE
|
42 | // This regiseter controls the states of the radio.
|
43 | // First, we'll set it to the TRX_OFF state.
|
44 | TRX_STATE = (TRX_STATE & 0xE0) | TRX_OFF; // Set to TRX_OFF state
|
45 |
|
46 |
|
47 | PORTE &= ~(1<<PE2);
|
48 | _delay_ms(1000);
|
49 | PORTE |= (1<<PE2);
|
50 |
|
51 | // Transceiver Status Register -- TRX_STATUS
|
52 | // This read-only register contains the present state of the radio transceiver.
|
53 | // After telling it to go to the TRX_OFF state, we'll make sure it's actually
|
54 | // there.
|
55 |
|
56 | if ((TRX_STATUS & 0x1F) != TRX_OFF) // Check to make sure state is correct
|
57 | return 0; // Error, TRX isn't off
|
58 |
|
59 | // Transceiver Control Register 1 - TRX_CTRL_1
|
60 | // We'll use this register to turn on automatic CRC calculations.
|
61 | TRX_CTRL_1 |= (1<<TX_AUTO_CRC_ON); // Enable automatic CRC calc.
|
62 |
|
63 | // Enable RX start/end and TX end interrupts
|
64 | IRQ_MASK = (1<<RX_START_EN) | (1<<RX_END_EN) | (1<<TX_END_EN);
|
65 |
|
66 | // Transceiver Clear Channel Assessment (CCA) -- PHY_CC_CCA
|
67 | // This register is used to set the channel. CCA_MODE should default
|
68 | // to Energy Above Threshold Mode.
|
69 | // Channel should be between 11 and 26 (2405 MHz to 2480 MHz)
|
70 | if ((channel < 11) || (channel > 26)) channel = 11;
|
71 | PHY_CC_CCA = (PHY_CC_CCA & 0xE0) | 11; // Set the channel to 11
|
72 |
|
73 | // Finally, we'll enter into the RX_ON state. Now waiting for radio RX's, unless
|
74 | // we go into a transmitting state.
|
75 | TRX_STATE = (TRX_STATE & 0xE0) | RX_ON; // Default to receiver
|
76 |
|
77 | return 1;
|
78 | }
|
79 |
|
80 |
|
81 | // This function will transmit a single byte out of the radio.
|
82 | void rfWrite(uint8_t b)
|
83 | {
|
84 | uint8_t length = 3;
|
85 |
|
86 | // Transceiver State Control Register -- TRX_STATE
|
87 | // This regiseter controls the states of the radio.
|
88 | // Set to the PLL_ON state - this state begins the TX.
|
89 | TRX_STATE = (TRX_STATE & 0xE0) | PLL_ON; // Set to TX start state
|
90 | while(!(TRX_STATUS & PLL_ON))
|
91 | ; // Wait for PLL to lock
|
92 |
|
93 | //digitalWrite(TX_LED, HIGH); // Turn on TX LED
|
94 |
|
95 | PORTE &= ~(1<<PE3);
|
96 |
|
97 | // Start of frame buffer - TRXFBST
|
98 | // This is the first byte of the 128 byte frame. It should contain
|
99 | // the length of the transmission.
|
100 | TRXFBST = length;
|
101 | // Now copy the byte-to-send into the address directly after TRXFBST.
|
102 | memcpy((void *)(&TRXFBST+1), &b, 1);
|
103 |
|
104 | // Transceiver Pin Register -- TRXPR.
|
105 | // From the PLL_ON state, setting SLPTR high will initiate the TX.
|
106 | TRXPR |= (1<<SLPTR); // SLPTR = 1
|
107 | TRXPR &= ~(1<<SLPTR); // SLPTR = 0 // Then bring it back low
|
108 |
|
109 | // After sending the byte, set the radio back into the RX waiting state.
|
110 | TRX_STATE = (TRX_STATE & 0xE0) | RX_ON;
|
111 | }
|
112 |
|
113 | // Returns how many unread bytes remain in the radio RX buffer.
|
114 | // 0 means the buffer is empty. Maxes out at RF_BUFFER_SIZE.
|
115 | unsigned int rfAvailable()
|
116 | {
|
117 | return (unsigned int)(RF_BUFFER_SIZE + radioRXBuffer.head - radioRXBuffer.tail) % RF_BUFFER_SIZE;
|
118 | }
|
119 |
|
120 | // This function reads the oldest data in the radio RX buffer.
|
121 | // If the buffer is emtpy, it'll return a 255.
|
122 | char rfRead()
|
123 | {
|
124 | if (radioRXBuffer.head == radioRXBuffer.tail)
|
125 | {
|
126 | return -1;
|
127 | }
|
128 | else
|
129 | {
|
130 | // Read from the buffer tail, and update the tail pointer.
|
131 | char c = radioRXBuffer.buffer[radioRXBuffer.tail];
|
132 | radioRXBuffer.tail = (unsigned int)(radioRXBuffer.tail + 1) % RF_BUFFER_SIZE;
|
133 | return c;
|
134 | }
|
135 | }
|
136 |
|
137 | // This interrupt is called when radio TX is complete. We'll just
|
138 | // use it to turn off our TX LED.
|
139 | ISR(TRX24_TX_END_vect)
|
140 | {
|
141 | PORTE |= (1<<PE3);
|
142 | }
|
143 |
|
144 | // This interrupt is called the moment data is received by the radio.
|
145 | // We'll use it to gather information about RSSI -- signal strength --
|
146 | // and we'll turn on the RX LED.
|
147 | ISR(TRX24_RX_START_vect)
|
148 | {
|
149 |
|
150 | rssiRaw = PHY_RSSI; // Read in the received signal strength
|
151 | PORTE &= ~(1<<PE4);
|
152 | }
|
153 |
|
154 | // This interrupt is called at the end of data receipt. Here we'll gather
|
155 | // up the data received. And store it into a global variable. We'll
|
156 | // also turn off the RX LED.
|
157 | ISR(TRX24_RX_END_vect)
|
158 | {
|
159 | uint8_t length;
|
160 | // Maximum transmission is 128 bytes
|
161 | uint8_t tempFrame[RF_BUFFER_SIZE];
|
162 |
|
163 | // The received signal must be above a certain threshold.
|
164 | if (rssiRaw & RX_CRC_VALID)
|
165 | {
|
166 | // The length of the message will be the first byte received.
|
167 | length = TST_RX_LENGTH;
|
168 | // The remaining bytes will be our received data.
|
169 | memcpy(&tempFrame[0], (void*)&TRXFBST, length);
|
170 |
|
171 | // Now we need to collect the frame into our receive buffer.
|
172 | // k will be used to make sure we don't go above the length
|
173 | // i will make sure we don't overflow our buffer.
|
174 | unsigned int k = 0;
|
175 | unsigned int i = (radioRXBuffer.head + 1) % RF_BUFFER_SIZE; // Read buffer head pos and increment;
|
176 | while ((i != radioRXBuffer.tail) && (k < length-2))
|
177 | {
|
178 | // First, we update the buffer with the first byte in the frame
|
179 | radioRXBuffer.buffer[radioRXBuffer.head] = tempFrame[k++];
|
180 | radioRXBuffer.head = i; // Update the head
|
181 | i = (i + 1) % RF_BUFFER_SIZE; // Increment i % BUFFER_SIZE
|
182 | }
|
183 | }
|
184 |
|
185 | // Turn receive LED off, and we're out
|
186 | PORTE |= (1<<PE4);
|
187 | }
|