source: ResearchApps/MAC/Workshop_MACs/COGMAC_server/cogmac_server.c

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

dyspan prep

File size: 18.4 KB
Line 
1/*! \file cogmac_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. It
9 extends halfmac_server.c to allow frequency hopping and accepts requests
10 from halfmac_client.c for particular channels.
11 
12 */
13
14#include "warpmac.h"
15#include "warpphy.h"
16#include "cogmac_server.h"
17#include "xparameters.h"
18#include "ascii_characters.h"
19#include "ofdm_txrx_mimo_regMacros.h"
20#include "wired_frame_formats.h"
21
22Macframe templatePkt;
23
24unsigned int autoResp_matchCond;
25unsigned int autoResp_action;
26unsigned char pktBuf_tx_DATA;
27unsigned char pktBuf_tx_COG;
28unsigned char pktBuf_rx;
29
30unsigned char maximumReSend;
31
32///ID of this node
33unsigned short int myID;
34
35///Full rate modulation selection; QPSK by default
36unsigned int pktFullRate;
37
38//Payload code rate selection
39unsigned int pktCodeRate;
40
41///Buffer for holding a packet-to-xmit across multiple retransmissions
42Macframe txMacframe;
43///Buffer to hold received packet
44Macframe rxMacframe;
45
46///Current 802.11 channel
47unsigned char chan;
48unsigned char nextChan;
49
50unsigned int txSeqNum;
51
52//Define handy macros for CSMA MAC packet types
53#define PKTTYPE_COGRESP         4
54#define PKTTYPE_COGREQ          3
55#define PKTTYPE_COGHOPPENDING   2
56#define PKTTYPE_DATA            1
57#define PKTTYPE_ACK             0
58
59#define COGRESP_SUCCESS         0
60#define COGRESP_ILLEGALCHAN     1
61#define COGRESP_TOOLATE         2
62
63////Some globals specific to cogMac server////
64unsigned char legalChannels[14];
65unsigned int updateDuration;
66unsigned int numUpdates;
67unsigned int numUpdatesReq;
68unsigned int currUpdate;
69unsigned char allowReq;
70unsigned char cogRespReason;
71unsigned char debugPrint;
72///////////////////////////////////////////////
73
74///@brief Callback for the depression of the left push button
75///
76///This function is empty by default
77void leftButton() {
78}
79
80///@brief Callback for the reception of UART bytes
81///@param uartByte ASCII byte received from UART
82///
83///Provides the user with the bytes that was received over the serial port. This is useful for configuring
84///PHY and MAC parameters in real time on a board.
85void uartRecv_callback(unsigned char uartByte)
86{
87    static char chanVal = 0;
88    char index;
89    if(uartByte != 0x0)
90    {       
91
92        switch(uartByte)
93        {   
94            case ASCII_SPACE:
95                printMenu();
96                break;
97            case ASCII_P:
98                xil_printf("Enabling debug prints...\r\n");
99                debugPrint=1;
100                break;
101               
102            case ASCII_p:
103                xil_printf("Disabling debug prints...\r\n");
104                debugPrint=0;
105                break;
106               
107            case ASCII_d:
108                if(updateDuration>10000) updateDuration = updateDuration-10000;
109                xil_printf("-updateDuration = %duSec\r\n",updateDuration);
110                break;
111            case ASCII_D:
112                updateDuration = updateDuration+10000;
113                xil_printf("+updateDuration = %duSec\r\n",updateDuration);
114                break;
115
116            case ASCII_n:
117                if(numUpdates>1) numUpdates = numUpdates-1;
118                xil_printf("-numUpdates = %d\r\n",numUpdates);
119                break;             
120            case ASCII_N:
121                numUpdates = numUpdates+1;
122                xil_printf("+numUpdates = %d\r\n",numUpdates);
123                break;
124
125            case ASCII_r:
126                if(numUpdatesReq>1) numUpdatesReq = numUpdatesReq-1;
127                xil_printf("-numUpdatesReq = %d\r\n",numUpdatesReq);
128                break;             
129            case ASCII_R:
130                numUpdatesReq = numUpdatesReq+1;
131                xil_printf("+numUpdatesReq = %d\r\n",numUpdatesReq);
132                break;
133               
134            case ASCII_o:
135                legalChannels[chanVal] = 0;
136                xil_printf("[ ");
137                for (index=0; index<14; index++) {
138                    xil_printf("%2d ",legalChannels[index]);
139                }
140                xil_printf("]\r\n");
141                xil_printf("[ ");
142                for (index=0; index<14; index++) {
143                    xil_printf("%2d ",index+1);
144                }
145                xil_printf("]\r\n\r\n");   
146                break;
147               
148            case ASCII_O:
149                legalChannels[chanVal] = 1;
150                xil_printf("[ ");
151                for (index=0; index<14; index++) {
152                    xil_printf("%2d ",legalChannels[index]);
153                }
154                xil_printf("]\r\n");
155                xil_printf("[ ");
156                for (index=0; index<14; index++) {
157                    xil_printf("%2d ",index+1);
158                }
159                xil_printf("]\r\n\r\n");   
160                break;
161               
162            case ASCII_C:
163                if(chanVal<13) chanVal++;
164                xil_printf("Chan: %d\r\n",chanVal+1);
165                break;
166           
167            case ASCII_c:
168                if(chanVal>0) chanVal--;
169                xil_printf("Chan: %d\r\n",chanVal+1);
170                break;
171
172   
173            default:
174                xil_printf("Undefined command\r\n");
175                break;
176        }
177    }
178   
179    return;
180}
181///@brief Callback for the expiration of timers
182///
183///This function is responsible for handling #TIMEOUT and #BACKOFF.
184///The job responsibilities of this function are to:
185///-increase the contention window upon the expiration of a #TIMEOUT
186///-initiate a #BACKOFF timer upon the expiration of a #TIMEOUT
187///-retransmit a packet upon the expiration of a #BACKOFF
188///@param timerType #TIMEOUT or #BACKOFF
189void timer_callback(unsigned char timerType) {
190    unsigned int randomValue = rand();
191    unsigned char numLegal=0;
192    unsigned char index;
193    unsigned char legalChannelsList[14];
194   
195    Macframe cogMacframe;
196   
197    switch(timerType) {
198        case TIMEOUT_TIMER:
199            warpmac_setTimer(BACKOFF_TIMER);
200            break;
201           
202        case BACKOFF_TIMER:
203            if(txMacframe.header.remainingTx) {
204                //Copy the header over to the Tx packet buffer
205                warpmac_prepPhyForXmit(&txMacframe, pktBuf_tx_DATA);
206               
207                //Send from the Tx packet buffer
208                warpmac_startPhyXmit(pktBuf_tx_DATA);
209               
210                //Wait for it to finish
211                warpmac_finishPhyXmit();
212               
213                //Start a timeout timer
214                warpmac_setTimer(TIMEOUT_TIMER);
215                warpmac_decrementRemainingReSend(&txMacframe);
216            }
217            else {
218                //Either the packet has been sent the max number of times, or
219                // we just got an ACK and need to backoff before starting with a new packet
220                warpmac_enableDataFromNetwork();
221            }
222            break; //END BACKOFF_TIMER
223            case USER_TIMER_A:
224           
225                if (currUpdate<numUpdates) {
226                    if (currUpdate>numUpdatesReq && allowReq==1) {
227                        allowReq = 0;
228                    }
229                    currUpdate++;
230                    cogMacframe.header.length = 0;
231                    cogMacframe.header.pktType = PKTTYPE_COGHOPPENDING;
232                    cogMacframe.header.fullRate = HDR_FULLRATE_QPSK;
233                    cogMacframe.header.codeRate = HDR_CODE_RATE_34;
234                    cogMacframe.header.destAddr = (unsigned short int)(NODEID_TO_ADDR(0xFF)); //Broadcast
235                    cogMacframe.header.timeLeft = (numUpdates-currUpdate+1)*updateDuration/1000;
236                    cogMacframe.header.cogParam = nextChan;
237                   
238                    //Copy the header to the Tx packet buffer
239                    warpmac_prepPhyForXmit(&cogMacframe, pktBuf_tx_COG);
240                   
241                    //Transmit the packet
242                    warpmac_startPhyXmit(pktBuf_tx_COG);
243                   
244                    //Wait for it to finish
245                    warpmac_finishPhyXmit();
246                   
247                    //if(debugPrint) xil_printf("Sending Update %d, ETA: %d, nextChan: %d, allowReq = %d\r\n",currUpdate,(numUpdates-currUpdate+1)*updateDuration/1000,nextChan,allowReq);
248                }
249                else {
250                    allowReq = 1;
251                    currUpdate=0;
252                    for (index=0; index<14; index++) {
253                        if (legalChannels[index]==1 && index!=(nextChan-1)) {
254                            legalChannelsList[numLegal] = index+1;
255                            numLegal++;
256                        }
257                    }
258                    if (numLegal>0) {
259                        randomValue = (randomValue&0xFF) % numLegal;
260                        chan = nextChan;
261                       
262                        warpphy_setChannel(GHZ_2, chan);
263                        warpmac_leftHex(chan);
264                        nextChan = legalChannelsList[randomValue];
265                    } else {
266                        nextChan = chan;
267                    }
268                   
269                }
270           
271                warp_timer_setTimer(USER_TIMER_A, 0, updateDuration*TIMERCLK_CYCLES_PER_USEC); //uSec
272                warp_timer_setMode(USER_TIMER_A, TIMER_MODE_NOCARRIERSENSE); 
273                warp_timer_start(USER_TIMER_A);
274
275                break;
276
277    }
278}
279
280
281///@brief Callback for the reception of Ethernet packets
282///
283///This function is called by the ethernet MAC drivers
284///when a packet is available to send. This function fills
285///the Macframe transmit buffer with the packet and sends
286///it over the OFDM link
287///@param length Length, in bytes, of received Ethernet frame
288void dataFromNetworkLayer_callback(Xuint32 length, char* payload){
289    unsigned char destNode;
290    int i;
291   
292    //Struct pointers to help decode the Ethernet payload
293    ethernet_header* hdrPtr_ethernet;
294    arp_header*     hdrPtr_arp;
295    ipv4_header*    hdrPtr_ip;
296
297    hdrPtr_ethernet = (ethernet_header*)payload;
298    hdrPtr_arp = (arp_header*)(payload+sizeof(ethernet_header));
299    hdrPtr_ip = (ipv4_header*)(payload+sizeof(ethernet_header));
300   
301    //Check the Ethertype of the received payload, and extract the
302    // last byte of the destination IP address
303    switch(hdrPtr_ethernet->ethertype) {
304        case ETHERTYPE_ARP:
305            destNode = (unsigned char)((hdrPtr_arp->dest_addr_ip)&0xFF);
306//          xil_printf("ARP pkt to %d\r\n", destNode);
307
308//          for(i=0; i<28; i++)
309//              xil_printf("[%02d] 0x%02x\r\n", i, payload[i]);
310            break;
311
312        case ETHERTYPE_IP:
313            destNode = (unsigned char)((hdrPtr_ip->dest_addr_ip)&0xFF);
314//          xil_printf("IP pkt to %d\r\n", destNode);
315            break;
316
317        default:
318            //Invlaid Ethertype value; default to highest node ID
319//          xil_printf("Unknown pkt format\r\n");
320            destNode = 15;
321    }
322
323    if(destNode > 15)
324        destNode = 15;
325
326    //Reset the contention window to its minimum
327    warpmac_resetCurrentCW();
328   
329    //Disable further Ethernet packets (will be re-enabled after this packet is ACK'd or dropped)
330    warpmac_disableDataFromNetwork();
331   
332    //Update the Tx packet header with this packet's values
333    txMacframe.header.length = length;
334    txMacframe.header.pktType = PKTTYPE_DATA;
335   
336    //Set the modulation scheme for the packet's full-rate symbols
337    txMacframe.header.fullRate = pktFullRate;
338   
339    //Set the code rate for the packet's payload
340    txMacframe.header.codeRate = pktCodeRate;
341   
342    //Copy in the packet's destination MAC address
343    txMacframe.header.destAddr = (unsigned short int)(NODEID_TO_ADDR(destNode));
344   
345    txMacframe.header.seqNum = txSeqNum++;
346   
347    //Set the remaining Tx counter to the maximum numeber of transmissions
348    txMacframe.header.remainingTx = (maximumReSend+1);
349   
350    if(warpmac_carrierSense()) {
351        //If the modium is idle:
352       
353        //Copy the header to the Tx packet buffer
354        warpmac_prepPhyForXmit(&txMacframe, pktBuf_tx_DATA);
355       
356        //Transmit the packet
357        warpmac_startPhyXmit(pktBuf_tx_DATA);
358       
359        //Wait for it to finish
360        warpmac_finishPhyXmit();
361       
362        //Start a timeout timer
363        warpmac_setTimer(TIMEOUT_TIMER);
364        warpmac_decrementRemainingReSend(&txMacframe);
365    }
366    else {
367        //Medium was busy; start a backoff timer
368        warpmac_setTimer(BACKOFF_TIMER);
369    }
370   
371    return;
372}
373
374///@brief Callback for the reception of bad wireless headers
375///
376///@param packet Pointer to received Macframe
377void phyRx_badHeader_callback() {
378   
379    //Don't do anything with the packet (it had errors, and can't be trusted)
380   
381    //Increment the bottom LEDs
382    warpmac_incrementLEDLow();
383   
384    return;
385}
386
387///@brief Callback for the reception of good wireless headers
388///
389///This function then polls the PHY to determine if the entire packet passes checksum
390///thereby triggering the transmission of the ACK and the transmission of the received
391///data over Ethernet.
392///@param packet Pointer to received Macframe
393int phyRx_goodHeader_callback(Macframe* packet){
394   
395    Macframe cogMacframe;
396   
397    unsigned char state = PHYRXSTATUS_INCOMPLETE;
398    unsigned char srcNode;
399    unsigned char shouldSend = 0;
400    unsigned char illegalChan;
401    unsigned char userChan;
402   
403    //Calculate the node ID from the packet's source MAC address
404    srcNode = ADDR_TO_NODEID( (packet->header.srcAddr) );
405   
406    //If the packet is addressed to this node
407    if( packet->header.destAddr == (NODEID_TO_ADDR(myID)) ) {
408       
409        switch(packet->header.pktType) {
410                //If received packet is data
411            case PKTTYPE_DATA:
412                //At this point, we have pre-loaded the PHY transmitter with the ACK in hoping that
413                //the packet passes checksum. Now we wait for the state of the received to packet
414                //to move from PHYRXSTATUS_INCOMPLETE to either PHYRXSTATUS_GOOD or PHYRXSTATUS_BAD
415               
416                //Poll the PHY until the payload is declared good or bad
417                state = warpmac_finishPhyRecv();
418               
419                if(state & PHYRXSTATUS_GOOD){
420                    //The auto-reponder will send the pre-programmed ACK automatically
421                    //User code only needs to update its stats, then check to see the PHY is finished transmitting
422                   
423                    //Toggle the top LEDs
424                    warpmac_incrementLEDHigh();
425                   
426                    //Starts the DMA transfer of the payload into the EMAC
427                    warpmac_prepPktToNetwork((void *)warpphy_getBuffAddr(pktBuf_rx)+NUM_HEADER_BYTES, (packet->header.length));
428                   
429                    //Blocks until the PHY is finished sending and enables the receiver
430                    warpmac_finishPhyXmit();
431                   
432                    //Waits until the DMA transfer is complete, then starts the EMAC
433                    warpmac_startPktToNetwork((packet->header.length));
434                }
435               
436                if(state & PHYRXSTATUS_BAD) {
437                    warpmac_incrementLEDLow();
438                }
439               
440                break; //END PKTTYPE_DATA
441               
442            case PKTTYPE_ACK:
443                //Clear the TIMEOUT and enable Ethernet
444                if(warpmac_inTimeout()) {
445                    warpmac_incrementLEDHigh();
446                   
447                    //Clear the timeout timer, set when we transmitted the data packet
448                    warpmac_clearTimer(TIMEOUT_TIMER);
449                   
450                    //Clear the remaining transmit count to assure this packet won't be re-transmitted
451                    txMacframe.header.remainingTx = 0;
452                   
453                    //Start a backoff, to gaurantee a random time before attempting to transmit again
454                    warpmac_setTimer(BACKOFF_TIMER);
455                   
456                    //Re-enable EMAC polling immediately (for testing; using the post-ACK backoff is better for real use)
457                    //warpmac_enableDataFromNetwork();
458                }
459                else {
460                    //Got an unexpected ACK; ignore it
461                }
462               
463                break; //END PKTTYPE_ACK
464               
465            case PKTTYPE_COGREQ:
466                userChan = (packet->header.cogParam);
467               
468                if(userChan<=14 && userChan>=1){
469                    illegalChan = (legalChannels[userChan- 1]==0);
470                }
471                else {
472                    illegalChan = 1;
473                }
474
475                if(illegalChan){
476                    cogRespReason = COGRESP_ILLEGALCHAN;
477                } else if (allowReq==0){
478                    cogRespReason = COGRESP_TOOLATE;
479                } else {
480                    allowReq = 0;
481                    cogRespReason = COGRESP_SUCCESS;
482                    nextChan = userChan;
483                }
484               
485                if(debugPrint) xil_printf("Request from %d. Sending code %d.\r\n",packet->header.srcAddr,cogRespReason);
486               
487                cogMacframe.header.length = 0;
488                cogMacframe.header.pktType = PKTTYPE_COGRESP;
489                cogMacframe.header.fullRate = HDR_FULLRATE_QPSK;
490                cogMacframe.header.codeRate = HDR_CODE_RATE_34;
491                cogMacframe.header.destAddr = (unsigned short int)(packet->header.srcAddr);
492                cogMacframe.header.cogParam = cogRespReason;
493               
494                //Copy the header to the Tx packet buffer
495                warpmac_prepPhyForXmit(&cogMacframe, pktBuf_tx_COG);
496               
497                //Transmit the packet
498                warpmac_startPhyXmit(pktBuf_tx_COG);
499               
500                //Wait for it to finish
501                warpmac_finishPhyXmit();
502               
503                break;
504
505        }
506    }
507    else {
508        state = warpmac_finishPhyRecv();
509    }
510   
511    //Return 0, indicating we didn't clear the PHY status bits (WARPMAC will handle it)
512    return 0;
513}
514
515void printMenu()
516{
517    xil_printf("***********************************************\r\n");
518    xil_printf("* -c/C arrow keys to select                   *\r\n");
519    xil_printf("*  channels and o/O keys to toggle legality   *\r\n");
520    xil_printf("* -p/P to disable/enable debug prints         *\r\n");
521    xil_printf("* -d/D to change interval between updates     *\r\n");
522    xil_printf("* -n/N to change updates per hop              *\r\n");
523    xil_printf("* -r/R to change allowed request region       *\r\n");
524    xil_printf("***********************************************\r\n");
525
526    return;
527}
528
529///@brief Main function
530///
531///This function configures MAC parameters, enables the underlying frameworks, and then loops forever.
532int main(){
533   
534    //Initialize global variables
535    chan = 4;
536    nextChan = chan;
537   
538    //Assign the packet buffers in the PHY
539    // The auto responder can't transmit from buffer 0, so we use it for Rx packets
540    // The other assignments (DATA/ACK) are arbitrary; any buffer in [1,30] will work
541    pktBuf_rx = 1;
542    pktBuf_tx_DATA = 2;
543    pktBuf_tx_COG = 3;
544    //Set the full-rate modulation to QPSK by default
545//  pktFullRate = HDR_FULLRATE_QPSK;
546    pktFullRate = HDR_FULLRATE_QAM_16;
547   
548    //Set the payload coding rate to 3/4 rate by default
549    pktCodeRate = HDR_CODE_RATE_34;
550   
551    //Initialize the MAC/PHY frameworks
552    warpmac_init();
553    maximumReSend = 8;
554    warpmac_setMaxResend(maximumReSend);
555    warpmac_setMaxCW(5);
556    warpmac_setTimeout(120);
557    warpmac_setSlotTime(22);
558   
559    //Read Dip Switch value from FPGA board.
560    //This value will be used as an index into the routing table for other nodes
561    myID = (unsigned short int)warpmac_getMyId();
562    warpmac_rightHex(myID);
563   
564    //Configure the PHY and radios for single antenna (SISO) mode
565    warpphy_setAntennaMode(TX_ANTMODE_SISO_ANTA, RX_ANTMODE_SISO_ANTA);
566    //warpphy_setAntennaMode(TX_ANTMODE_MULTPLX, RX_ANTMODE_MULTPLX);
567    //warpphy_setAntennaMode(TX_ANTMODE_ALAMOUTI_ANTA, RX_ANTMODE_ALAMOUTI_ANTA);
568   
569    //Set the packet detection thresholds
570    warpphy_setEnergyDetThresh(7000);       //Min RSSI (in [0,16368])
571    warpphy_setAutoCorrDetParams(90, 0);    //Min auto-correlation (in [0,2047])
572    warpphy_setLongCorrThresh(8000);        //Min cross-correlation (in [0,45e3])
573   
574    //Rx buffer is where the EMAC will DMA Wireless payloads from
575    warpmac_setRxBuffers(&rxMacframe, pktBuf_rx);
576   
577    //Tx buffer is where the EMAC will DMA Ethernet payloads to
578    warpmac_setPHYTxBuffer(pktBuf_tx_DATA);
579    warpmac_setEMACRxBuffer(pktBuf_tx_DATA);
580   
581    //Set the modulation scheme use for base rate (header) symbols
582    warpmac_setBaseRate(QPSK);
583   
584    //Copy this node's MAC address into the Tx buffer's source address field
585    txMacframe.header.srcAddr = (unsigned short int)(NODEID_TO_ADDR(myID));
586   
587    //Register callbacks
588    warpmac_setCallback(EVENT_TIMER, (void *)timer_callback);
589    warpmac_setCallback(EVENT_DATAFROMNETWORK, (void *)dataFromNetworkLayer_callback);
590    warpmac_setCallback(EVENT_PHYGOODHEADER, (void *)phyRx_goodHeader_callback);
591    warpmac_setCallback(EVENT_PHYBADHEADER, (void *)phyRx_badHeader_callback);
592    warpmac_setCallback(EVENT_UARTRX, (void *)uartRecv_callback);
593   
594    //Set the default center frequency
595    warpphy_setChannel(GHZ_2, chan);
596   
597    //Enable carrier sensing
598    warpmac_setCSMA(1);
599   
600    txSeqNum = 0;
601   
602    //halfmac_server doesn't send ACKs, so skip autoResponder setup
603   
604    legalChannels[1-1] =    1;
605    legalChannels[2-1] =    1;
606    legalChannels[3-1] =    1;
607    legalChannels[4-1] =    1;
608    legalChannels[5-1] =    1;
609    legalChannels[6-1] =    0;
610    legalChannels[7-1] =    0;
611    legalChannels[8-1] =    0;
612    legalChannels[9-1] =    0;
613    legalChannels[10-1] =   0;
614    legalChannels[11-1] =   0;
615    legalChannels[12-1] =   0;
616    legalChannels[13-1] =   0;
617   
618    debugPrint = 0;
619   
620    updateDuration = 250000;
621    numUpdates = 10;//20;
622    numUpdatesReq = 5;//10;
623    currUpdate = 0;
624    warp_timer_setTimer(USER_TIMER_A, 0, updateDuration*TIMERCLK_CYCLES_PER_USEC); //uSec
625    warp_timer_setMode(USER_TIMER_A, TIMER_MODE_NOCARRIERSENSE); 
626    warp_timer_start(USER_TIMER_A);
627   
628    //Listen for new packets to send (either from Ethernet or local dummy packets)
629    warpmac_enableDataFromNetwork();
630   
631    xil_printf("Reference Design v16.1 COGMAC SERVER\r\n");
632    printMenu();
633   
634    xil_printf("Beginning main loop\r\n");
635   
636    while(1)
637    {
638        //Poll the timer, PHY and user I/O forever; actual processing will happen via callbacks above
639        warpmac_pollPeripherals();
640    }
641   
642    return 0;
643}
Note: See TracBrowser for help on using the repository browser.