source: ResearchApps/MAC/Workshop_MACs/HALFMAC_server/halfmac_server.c

Last change on this file was 1639, checked in by murphpo, 13 years ago

updates for dyspan workshop

  • Property svn:executable set to *
File size: 13.0 KB
Line 
1/*! \file halfmac_server.c
2 \brief Server for halfmac workshop exercise
3 
4 @version 16.1
5 @author Chris Hunter
6 
7 This code is a simple manipulation of csmaMac.c that allows for addressing
8 multiple WARP nodes based upon the IP address of the packet being sent.
9 
10 */
11
12#include "warpmac.h"
13#include "warpphy.h"
14#include "halfmac_server.h"
15#include "xparameters.h"
16#include "ascii_characters.h"
17#include "ofdm_txrx_mimo_regMacros.h"
18#include "wired_frame_formats.h"
19
20Macframe templatePkt;
21
22unsigned int autoResp_matchCond;
23unsigned int autoResp_action;
24unsigned char pktBuf_tx_DATA;
25unsigned char pktBuf_rx;
26
27unsigned char maximumReSend;
28
29///ID of this node
30unsigned short int myID;
31
32///Full rate modulation selection; QPSK by default
33unsigned int pktFullRate;
34
35//Payload code rate selection
36unsigned int pktCodeRate;
37
38///Buffer for holding a packet-to-xmit across multiple retransmissions
39Macframe txMacframe;
40///Buffer to hold received packet
41Macframe rxMacframe;
42
43///Current 802.11 channel
44unsigned char chan;
45
46unsigned int txSeqNum;
47
48//Define handy macros for CSMA MAC packet types
49///Data packet with payload meant for Ethernet transmission
50#define PKTTYPE_DATA    1
51#define PKTTYPE_ACK     0
52
53///@brief Callback for the depression of the left push button
54///
55///This function is empty by default
56void leftButton() {
57}
58
59///@brief Callback for the reception of UART bytes
60///@param uartByte ASCII byte received from UART
61///
62///Provides the user with the bytes that was received over the serial port. This is useful for configuring
63///PHY and MAC parameters in real time on a board.
64void uartRecv_callback(unsigned char uartByte)
65{
66    if(uartByte != 0x0)
67    {
68        xil_printf("(%c)\t", uartByte);
69       
70        switch(uartByte)
71        {
72            case ASCII_1:
73                pktFullRate = HDR_FULLRATE_BPSK;
74                xil_printf("Tx Full Rate = BPSK\r\n");
75                break;
76               
77            case ASCII_2:
78                pktFullRate = HDR_FULLRATE_QPSK;
79                xil_printf("Tx Full Rate = QPSK\r\n");
80                break;
81               
82            case ASCII_4:
83                pktFullRate = HDR_FULLRATE_QAM_16;
84                xil_printf("Tx Full Rate = 16-QAM\r\n");
85                break;
86               
87            case ASCII_6:
88                pktFullRate = HDR_FULLRATE_QAM_64;
89                xil_printf("Tx Full Rate = 64-QAM\r\n");
90                break;
91               
92            case ASCII_7:
93                pktCodeRate = HDR_CODE_RATE_12;
94                xil_printf("Coding Rate = 1/2\r\n");
95                break;
96            case ASCII_8:
97                pktCodeRate = HDR_CODE_RATE_23;
98                xil_printf("Coding Rate = 2/3\r\n");
99                break;
100            case ASCII_9:
101                pktCodeRate = HDR_CODE_RATE_34;
102                xil_printf("Coding Rate = 3/4\r\n");
103                break;
104            case ASCII_0:
105                pktCodeRate = HDR_CODE_RATE_NONE;
106                xil_printf("Coding Rate = 1 (no coding)\r\n");
107                break;
108            case ASCII_F:
109                if(chan<14) chan++;
110                warpphy_setChannel(GHZ_2, chan);
111                xil_printf("Current channel: %d\r\n",chan);
112                break;
113            case ASCII_f:
114                if(chan>1) chan--;
115                warpphy_setChannel(GHZ_2, chan);
116                xil_printf("Current channel: %d\r\n",chan);
117                break;
118
119            default:
120                xil_printf("Undefined command\r\n");
121                break;
122        }
123    }
124   
125    return;
126}
127///@brief Callback for the expiration of timers
128///
129///This function is responsible for handling #TIMEOUT and #BACKOFF.
130///The job responsibilities of this function are to:
131///-increase the contention window upon the expiration of a #TIMEOUT
132///-initiate a #BACKOFF timer upon the expiration of a #TIMEOUT
133///-retransmit a packet upon the expiration of a #BACKOFF
134///@param timerType #TIMEOUT or #BACKOFF
135void timer_callback(unsigned char timerType) {
136   
137    switch(timerType) {
138        case TIMEOUT_TIMER:
139            warpmac_setTimer(BACKOFF_TIMER);
140            break;
141           
142        case BACKOFF_TIMER:
143            if(txMacframe.header.remainingTx) {
144                //Copy the header over to the Tx packet buffer
145                warpmac_prepPhyForXmit(&txMacframe, pktBuf_tx_DATA);
146               
147                //Send from the Tx packet buffer
148                warpmac_startPhyXmit(pktBuf_tx_DATA);
149               
150                //Wait for it to finish
151                warpmac_finishPhyXmit();
152               
153                //Start a timeout timer
154                warpmac_setTimer(TIMEOUT_TIMER);
155                warpmac_decrementRemainingReSend(&txMacframe);
156            }
157            else {
158                //Either the packet has been sent the max number of times, or
159                // we just got an ACK and need to backoff before starting with a new packet
160                warpmac_enableDataFromNetwork();
161            }
162            break; //END BACKOFF_TIMER
163    }
164}
165
166
167///@brief Callback for the reception of Ethernet packets
168///
169///This function is called by the ethernet MAC drivers
170///when a packet is available to send. This function fills
171///the Macframe transmit buffer with the packet and sends
172///it over the OFDM link
173///@param length Length, in bytes, of received Ethernet frame
174void dataFromNetworkLayer_callback(Xuint32 length, char* payload){
175    unsigned char destNode;
176    int i;
177   
178    //Struct pointers to help decode the Ethernet payload
179    ethernet_header* hdrPtr_ethernet;
180    arp_header*     hdrPtr_arp;
181    ipv4_header*    hdrPtr_ip;
182
183    hdrPtr_ethernet = (ethernet_header*)payload;
184    hdrPtr_arp = (arp_header*)(payload+sizeof(ethernet_header));
185    hdrPtr_ip = (ipv4_header*)(payload+sizeof(ethernet_header));
186   
187    //Check the Ethertype of the received payload, and extract the
188    // last byte of the destination IP address
189    switch(hdrPtr_ethernet->ethertype) {
190        case ETHERTYPE_ARP:
191            destNode = (unsigned char)((hdrPtr_arp->dest_addr_ip)&0xFF);
192//          xil_printf("ARP pkt to %d\r\n", destNode);
193
194//          for(i=0; i<28; i++)
195//              xil_printf("[%02d] 0x%02x\r\n", i, payload[i]);
196            break;
197
198        case ETHERTYPE_IP:
199            destNode = (unsigned char)((hdrPtr_ip->dest_addr_ip)&0xFF);
200//          xil_printf("IP pkt to %d\r\n", destNode);
201            break;
202
203        default:
204            //Invlaid Ethertype value; default to highest node ID
205//          xil_printf("Unknown pkt format\r\n");
206            destNode = 15;
207    }
208
209    if(destNode > 15)
210        destNode = 15;
211
212    //Reset the contention window to its minimum
213    warpmac_resetCurrentCW();
214   
215    //Disable further Ethernet packets (will be re-enabled after this packet is ACK'd or dropped)
216    warpmac_disableDataFromNetwork();
217   
218    //Update the Tx packet header with this packet's values
219    txMacframe.header.length = length;
220    txMacframe.header.pktType = PKTTYPE_DATA;
221   
222    //Set the modulation scheme for the packet's full-rate symbols
223    txMacframe.header.fullRate = pktFullRate;
224   
225    //Set the code rate for the packet's payload
226    txMacframe.header.codeRate = pktCodeRate;
227   
228    //Copy in the packet's destination MAC address
229    txMacframe.header.destAddr = (unsigned short int)(NODEID_TO_ADDR(destNode));
230   
231    txMacframe.header.seqNum = txSeqNum++;
232   
233    //Set the remaining Tx counter to the maximum numeber of transmissions
234    txMacframe.header.remainingTx = (maximumReSend+1);
235   
236    if(warpmac_carrierSense()) {
237        //If the modium is idle:
238       
239        //Copy the header to the Tx packet buffer
240        warpmac_prepPhyForXmit(&txMacframe, pktBuf_tx_DATA);
241       
242        //Transmit the packet
243        warpmac_startPhyXmit(pktBuf_tx_DATA);
244       
245        //Wait for it to finish
246        warpmac_finishPhyXmit();
247       
248        //Start a timeout timer
249        warpmac_setTimer(TIMEOUT_TIMER);
250        warpmac_decrementRemainingReSend(&txMacframe);
251    }
252    else {
253        //Medium was busy; start a backoff timer
254        warpmac_setTimer(BACKOFF_TIMER);
255    }
256   
257    return;
258}
259
260///@brief Callback for the reception of bad wireless headers
261///
262///@param packet Pointer to received Macframe
263void phyRx_badHeader_callback() {
264   
265    //Don't do anything with the packet (it had errors, and can't be trusted)
266   
267    //Increment the bottom LEDs
268    warpmac_incrementLEDLow();
269   
270    return;
271}
272
273///@brief Callback for the reception of good wireless headers
274///
275///This function then polls the PHY to determine if the entire packet passes checksum
276///thereby triggering the transmission of the ACK and the transmission of the received
277///data over Ethernet.
278///@param packet Pointer to received Macframe
279int phyRx_goodHeader_callback(Macframe* packet){
280   
281    unsigned char state = PHYRXSTATUS_INCOMPLETE;
282    unsigned char srcNode;
283    unsigned char shouldSend = 0;
284   
285    //Calculate the node ID from the packet's source MAC address
286    srcNode = ADDR_TO_NODEID( (packet->header.srcAddr) );
287   
288    //If the packet is addressed to this node
289    if( packet->header.destAddr == (NODEID_TO_ADDR(myID)) ) {
290       
291        switch(packet->header.pktType) {
292                //If received packet is data
293            case PKTTYPE_DATA:
294                //At this point, we have pre-loaded the PHY transmitter with the ACK in hoping that
295                //the packet passes checksum. Now we wait for the state of the received to packet
296                //to move from PHYRXSTATUS_INCOMPLETE to either PHYRXSTATUS_GOOD or PHYRXSTATUS_BAD
297               
298                //Poll the PHY until the payload is declared good or bad
299                state = warpmac_finishPhyRecv();
300               
301                if(state & PHYRXSTATUS_GOOD){
302                    //The auto-reponder will send the pre-programmed ACK automatically
303                    //User code only needs to update its stats, then check to see the PHY is finished transmitting
304                   
305                    //Toggle the top LEDs
306                    warpmac_incrementLEDHigh();
307                   
308                    //Update the right-hex display with the current sequence number
309                    warpmac_leftHex(0xF & (packet->header.seqNum));
310                   
311                    //Starts the DMA transfer of the payload into the EMAC
312                    warpmac_prepPktToNetwork((void *)warpphy_getBuffAddr(pktBuf_rx)+NUM_HEADER_BYTES, (packet->header.length));
313                   
314                    //Blocks until the PHY is finished sending and enables the receiver
315                    warpmac_finishPhyXmit();
316                   
317                    //Waits until the DMA transfer is complete, then starts the EMAC
318                    warpmac_startPktToNetwork((packet->header.length));
319                }
320               
321                if(state & PHYRXSTATUS_BAD) {
322                    warpmac_incrementLEDLow();
323                }
324               
325                break; //END PKTTYPE_DATA
326               
327            case PKTTYPE_ACK:
328                //Clear the TIMEOUT and enable Ethernet
329                if(warpmac_inTimeout()) {
330                    warpmac_incrementLEDHigh();
331                   
332                    //Clear the timeout timer, set when we transmitted the data packet
333                    warpmac_clearTimer(TIMEOUT_TIMER);
334                   
335                    //Clear the remaining transmit count to assure this packet won't be re-transmitted
336                    txMacframe.header.remainingTx = 0;
337                   
338                    //Start a backoff, to gaurantee a random time before attempting to transmit again
339                    warpmac_setTimer(BACKOFF_TIMER);
340                   
341                    //Re-enable EMAC polling immediately (for testing; using the post-ACK backoff is better for real use)
342                    //warpmac_enableDataFromNetwork();
343                }
344                else {
345                    //Got an unexpected ACK; ignore it
346                }
347               
348                break; //END PKTTYPE_ACK
349        }
350    }
351    else {
352        state = warpmac_finishPhyRecv();
353    }
354   
355    //Return 0, indicating we didn't clear the PHY status bits (WARPMAC will handle it)
356    return 0;
357}
358
359///@brief Main function
360///
361///This function configures MAC parameters, enables the underlying frameworks, and then loops forever.
362int main(){
363   
364    //Initialize global variables
365    chan = 4;
366   
367    //Assign the packet buffers in the PHY
368    // The auto responder can't transmit from buffer 0, so we use it for Rx packets
369    // The other assignments (DATA/ACK) are arbitrary; any buffer in [1,30] will work
370    pktBuf_rx = 1;
371    pktBuf_tx_DATA = 2;
372   
373    //Set the full-rate modulation to QPSK by default
374//  pktFullRate = HDR_FULLRATE_QPSK;
375    pktFullRate = HDR_FULLRATE_QAM_16;
376   
377    //Set the payload coding rate to 3/4 rate by default
378    pktCodeRate = HDR_CODE_RATE_34;
379   
380    //Initialize the MAC/PHY frameworks
381    warpmac_init();
382    maximumReSend = 8;
383    warpmac_setMaxResend(maximumReSend);
384    warpmac_setMaxCW(5);
385    warpmac_setTimeout(120);
386    warpmac_setSlotTime(22);
387   
388    //Read Dip Switch value from FPGA board.
389    //This value will be used as an index into the routing table for other nodes
390    myID = (unsigned short int)warpmac_getMyId();
391    warpmac_rightHex(myID);
392   
393    //Configure the PHY and radios for single antenna (SISO) mode
394    warpphy_setAntennaMode(TX_ANTMODE_SISO_ANTA, RX_ANTMODE_SISO_ANTA);
395    //warpphy_setAntennaMode(TX_ANTMODE_MULTPLX, RX_ANTMODE_MULTPLX);
396    //warpphy_setAntennaMode(TX_ANTMODE_ALAMOUTI_ANTA, RX_ANTMODE_ALAMOUTI_ANTA);
397   
398    //Set the packet detection thresholds
399    warpphy_setEnergyDetThresh(7000);       //Min RSSI (in [0,16368])
400    warpphy_setAutoCorrDetParams(90, 0);    //Min auto-correlation (in [0,2047])
401    warpphy_setLongCorrThresh(8000);        //Min cross-correlation (in [0,45e3])
402   
403    //Rx buffer is where the EMAC will DMA Wireless payloads from
404    warpmac_setRxBuffers(&rxMacframe, pktBuf_rx);
405   
406    //Tx buffer is where the EMAC will DMA Ethernet payloads to
407    warpmac_setPHYTxBuffer(pktBuf_tx_DATA);
408    warpmac_setEMACRxBuffer(pktBuf_tx_DATA);
409   
410    //Set the modulation scheme use for base rate (header) symbols
411    warpmac_setBaseRate(QPSK);
412   
413    //Copy this node's MAC address into the Tx buffer's source address field
414    txMacframe.header.srcAddr = (unsigned short int)(NODEID_TO_ADDR(myID));
415   
416    //Register callbacks
417    warpmac_setCallback(EVENT_TIMER, (void *)timer_callback);
418    warpmac_setCallback(EVENT_DATAFROMNETWORK, (void *)dataFromNetworkLayer_callback);
419    warpmac_setCallback(EVENT_PHYGOODHEADER, (void *)phyRx_goodHeader_callback);
420    warpmac_setCallback(EVENT_PHYBADHEADER, (void *)phyRx_badHeader_callback);
421    warpmac_setCallback(EVENT_UARTRX, (void *)uartRecv_callback);
422   
423    //Set the default center frequency
424    warpphy_setChannel(GHZ_2, chan);
425   
426    //Enable carrier sensing
427    warpmac_setCSMA(1);
428   
429    txSeqNum = 0;
430   
431    //halfmac_server doesn't send ACKs, so skip autoResponder setup
432   
433    //Listen for new packets to send (either from Ethernet or local dummy packets)
434    warpmac_enableDataFromNetwork();
435   
436    xil_printf("Reference Design v16.1 HALFMAC SERVER\r\n");
437   
438    xil_printf("Beginning main loop\r\n");
439   
440    while(1)
441    {
442        //Poll the timer, PHY and user I/O forever; actual processing will happen via callbacks above
443        warpmac_pollPeripherals();
444    }
445   
446    return 0;
447}
Note: See TracBrowser for help on using the repository browser.