source: ResearchApps/MAC/Workshop_MACs/COGMAC_client/cogmac_client_hw.c

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

dyspan prep

File size: 15.4 KB
Line 
1/*! \file cogmac_client.c
2 \brief Reception Half of a CSMA MAC protocol
3
4 @version 16.1
5 @author Chris Hunter
6
7 Like the halfmac_client_hw.c exercise, the goal of this MAC is to
8 act as a receiver to a CSMA-enabled server. This server will continue
9 to retransmit packets until this client acknowledges its reception.
10
11 In addition, the server will periodically announce that it will be
12 hopping to a new channel. It will include the scheduled time of the
13 channel hop in this message.
14 
15 Note to workshop users: any names in quotes
16 are names that can be searched for in the
17 WARP API.
18
19*/
20
21
22#include "xparameters.h"
23#include "warpmac.h"
24#include "warpphy.h"
25#include "cogmac_client_hw.h"
26#include "ascii_characters.h"
27#include "string.h"
28#include "errno.h"
29#include "stdlib.h"
30#include "stdio.h"
31
32
33
34///Type of packet the server will respond to your requests with
35#define PKTTYPE_COGRESP     4
36///Type of packet you must send to the server for requesting channel
37#define PKTTYPE_COGREQ          3
38///Type of packet server broadcasts periodically to inform of hop
39#define PKTTYPE_COGHOPPENDING   2
40///Data packet with payload meant for Ethernet transmission
41#define PKTTYPE_DATA 1
42///Acknowledgement packet meant for halting retransmissions
43#define PKTTYPE_ACK 0
44
45#define COGRESP_SUCCESS         0
46#define COGRESP_ILLEGALCHAN     1
47#define COGRESP_TOOLATE         2
48
49
50///Buffer for holding a packet-to-xmit across multiple retransmissions
51Macframe txMacframe;
52///Buffer to hold received packet
53Macframe rxMacframe;
54
55unsigned short int myID;
56unsigned char pktBuf_tx_ACK;
57unsigned char pktBuf_tx_DATA;
58unsigned char pktBuf_rx;
59unsigned char pktBuf_tx_COG;
60
61unsigned int autoResp_delay;
62unsigned int autoResp_action;
63unsigned int lastRxSeqNum;
64
65unsigned char newChan;
66unsigned char requestChan;
67
68///@brief Callback for the reception of UART bytes
69///@param uartByte ASCII byte received from UART
70///
71///Provides the user with the bytes that was received over the serial port. This is useful for configuring
72///PHY and MAC parameters in real time on a board.
73void uartRecv_callback(unsigned char uartByte)
74{
75    if(uartByte != 0x0)
76    {
77        if (uartByte<=ASCII_9 && uartByte>=ASCII_0) {
78            requestChan  = uartByte - 0x30;
79            if(requestChan==0) requestChan=10;
80           
81            //WORKSHOP PSEUDOCODE:
82            //1) Print that you are going to request channel "requestChan"
83            //2) Create a new Macframe for your channel request
84            //3) Set the length of the frame to be 0 (no payload bytes)
85            //4) Set the fullRate field fo be HDR_FULLRATE_QPSK
86            //5) Set the codeRate field to be HDR_CODERATE_34
87            //6) Set the destAddr field to be the server (ID=0)
88            //7) Set the srcAddr field to be yourself (myID)
89            //8) Let the cogParam field be the requestChan
90            //9) Prep and transmit the Macframe like you have before
91           
92            /**********************USER CODE STARTS HERE***************************/
93            xil_printf("Requesting Channel %d...\r\n",requestChan);
94           
95            Macframe cogRequest;
96           
97            cogRequest.header.length = 0;
98            cogRequest.header.pktType = PKTTYPE_COGREQ;
99            cogRequest.header.fullRate = HDR_FULLRATE_QPSK;
100            cogRequest.header.codeRate = HDR_CODE_RATE_34;
101            cogRequest.header.destAddr = (unsigned short int)(NODEID_TO_ADDR(0));
102            cogRequest.header.srcAddr = (unsigned short int)(NODEID_TO_ADDR(myID));
103            cogRequest.header.cogParam = requestChan;
104           
105            //Copy the header to the Tx packet buffer
106            warpmac_prepPhyForXmit(&cogRequest, pktBuf_tx_COG);
107           
108            //Transmit the packet
109            warpmac_startPhyXmit(pktBuf_tx_COG);
110           
111            //Wait for it to finish
112            warpmac_finishPhyXmit();
113            /**********************USER CODE ENDS HERE*****************************/
114           
115           
116        }
117       
118        else{
119            switch(uartByte)
120            {
121                default:
122                    //Unused command value; ignore
123                break;
124            }//END switch(uartByte)
125        }
126    }
127
128    return;
129}
130
131///@brief Callback for the expiration of timers
132///
133///This function is responsible for handling expirations
134///of warp_timer
135void timer_callback(unsigned char timerType) {
136   
137    //WORKSHOP PSEUDOCODE:
138    //1) Check that timerType argument is the timer you specified
139    //2) Use "warpphy_setChannel" to change channels to "newChan" global
140    //3) Display the new channel on the left hex with "warpmac_leftHex"
141   
142    /**********************USER CODE STARTS HERE***************************/
143    switch(timerType) {
144        case USER_TIMER_A:
145            warpmac_leftHex(newChan);
146            warpphy_setChannel(GHZ_2, newChan);                 
147            break;
148    }
149    /**********************USER CODE ENDS HERE*****************************/
150}
151
152
153///@brief Callback for the reception of Ethernet packets
154///
155///This function is called by the ethernet MAC drivers
156///when a packet is available to send. This function fills
157///the Macframe transmit buffer with the packet and sends
158///it over the OFDM link
159///@param length Length, in bytes, of received Ethernet frame
160///@param payload address of first byte in Ethernet payload.
161void dataFromNetworkLayer_callback(Xuint32 length, char* payload)
162{
163    //Set the length field in the header
164    txMacframe.header.length = length;
165    //Set the type to be a data packet
166    txMacframe.header.pktType = PKTTYPE_DATA;
167    //Copy in the packet's destination MAC address
168    txMacframe.header.destAddr = (unsigned short int)(NODEID_TO_ADDR(0));
169    //Set the modulation scheme for the packet's full-rate symbols
170    txMacframe.header.fullRate = HDR_FULLRATE_QPSK;
171    //Set the payload coding rate
172    txMacframe.header.codeRate = HDR_CODE_RATE_34;
173    //Copy the header over to packet buffer pktBuf_tx_DATA
174    warpmac_prepPhyForXmit(&txMacframe, pktBuf_tx_DATA);
175    //Send packet buffer pktBuf_tx_DATA
176    warpmac_startPhyXmit(pktBuf_tx_DATA);
177    //Wait for it to finish and enable the receiver
178    warpmac_finishPhyXmit();
179
180    return;
181}
182
183///@brief Callback for the reception of bad wireless headers
184///
185///@param packet Pointer to received Macframe
186void phyRx_badHeader_callback()
187{
188    warpmac_incrementLEDLow();
189}
190
191///@brief Callback for the reception of good wireless headers
192///
193///This function then polls the PHY to determine if the entire packet passes checksum
194///thereby triggering the transmission of the received data over Ethernet.
195///@param packet Pointer to received Macframe
196int phyRx_goodHeader_callback(Macframe* packet)
197{
198    unsigned char state = PHYRXSTATUS_INCOMPLETE;
199    char shouldSend = 0;
200   
201    //If the packet is addressed to this node
202    if( packet->header.destAddr == (NODEID_TO_ADDR(myID)) )
203    {
204        switch(packet->header.pktType){
205            //If received packet is data
206            case PKTTYPE_DATA:
207                //At this point, we have pre-loaded the PHY transmitter with the ACK in hoping that
208                // the packet passes checksum. Now we wait for the state of the received to packet
209                // to move from PHYRXSTATUS_INCOMPLETE to either PHYRXSTATUS_GOOD or PHYRXSTATUS_BAD
210
211                //Blocks until the PHY declares the payload good or bad
212                state = warpmac_finishPhyRecv();
213
214                if(state & PHYRXSTATUS_GOOD){
215                    //The auto-reponder will send the pre-programmed ACK automatically
216                    //User code only needs to update its own state, then check to see the PHY
217                    // is finished transmitting
218
219                    //Toggle the top LEDs
220                    warpmac_incrementLEDHigh();
221
222                    //Check if this is a new packet; only send it over Ethernet if it's new
223                    if(packet->header.seqNum != lastRxSeqNum) {
224                        shouldSend = 1;
225                        lastRxSeqNum = packet->header.seqNum;
226                    }
227                   
228                    //Starts the DMA transfer of the payload into the EMAC
229                    if(shouldSend) warpmac_prepPktToNetwork((void *)warpphy_getBuffAddr(pktBuf_rx)+NUM_HEADER_BYTES, (packet->header.length));
230
231                    //Blocks until the PHY is finished sending and enables the receiver
232                    warpmac_finishPhyXmit();
233
234                    //Waits until the DMA transfer is complete, then starts the EMAC
235                    if(shouldSend) warpmac_startPktToNetwork((packet->header.length));
236                }
237
238                if(state & PHYRXSTATUS_BAD){
239                    warpmac_incrementLEDLow();
240                }
241
242                break; //END PKTTYPE_DATA
243               
244                case PKTTYPE_COGRESP:
245                   
246                    //WORKSHOP PSEUDOCODE:
247                    //1) Check the cogParam field of the received phyHeader (packet->header.cogParam)
248                    //2) cogParam will be COGRESP_SUCCESS if your request was granted,
249                    //   COGRESP_ILLEGALCHAN if you requested an illegal channel
250                    //   COGRESP_TOOLATE if the next hop has already been decided. Print
251                    //   this information so you can see whether or not your request was
252                    //   successful.
253               
254                    /**********************USER CODE STARTS HERE***************************/
255                    switch (packet->header.cogParam) {
256                        case COGRESP_SUCCESS:
257                            xil_printf("Request accepted\r\n");
258                            break;
259                        case COGRESP_ILLEGALCHAN:
260                            xil_printf("Request denied... illegal channel requested\r\n");
261                            break;
262                        case COGRESP_TOOLATE:
263                            xil_printf("Request denied... next channel already decided\r\n");
264                            break;
265                        default:
266                            break;
267                    }
268                    /**********************USER CODE ENDS HERE*****************************/
269                    break;
270
271               
272            default:
273                //Invalid packet type; ignore
274                break;
275        }
276    }//END rx.destAddr == myID
277    else if( (packet->header.destAddr) == 0xFF) {
278        //Broadcast packet
279       
280        switch(packet->header.pktType){
281            case PKTTYPE_COGHOPPENDING:
282                /**********************USER CODE STARTS HERE***************************/
283                //WORKSHOP PSEUDOCODE:
284                //1) Clear the timer, even if it's already running (using warp_timer_resetDone(USER_TIMER_A))
285                //2) Set the timer for the next hop, using the received packet header's header.timeLeft paramter, with
286                //    warp_timer_setTimer(USER_TIMER_A, 0, clockCycles);
287                //    The macro TIMERCLK_CYCLES_PER_MSEC is defined to help convert miliseconds to clock cycles
288                //3) Start the timer with warp_timer_start(USER_TIMER_A)
289                //4) Update the global variable newChan with header.cogParam
290
291                warp_timer_resetDone(USER_TIMER_A);
292                warp_timer_setTimer(USER_TIMER_A, 0, packet->header.timeLeft*TIMERCLK_CYCLES_PER_MSEC); //milliseconds
293                warp_timer_setMode(USER_TIMER_A, TIMER_MODE_NOCARRIERSENSE); 
294                warp_timer_start(USER_TIMER_A);
295       
296                newChan = packet->header.cogParam;
297       
298                /**********************USER CODE ENDS HERE***************************/
299                break;
300        }
301        state = warpmac_finishPhyRecv();
302    }
303    else { //Packet was addressed to someone else; ignore it
304        state = warpmac_finishPhyRecv();
305    }
306
307    //Return 0, indicating we didn't clear the PHY status bits (WARPMAC will handle it)
308    return 0;
309}
310
311///@brief Main function
312///
313///This function configures MAC parameters, enables the underlying frameworks, and then loops forever.
314int main()
315{
316    xil_printf("COGMAC Client v16.1: AutoResponder-driven Acknowledgments\r\n");
317
318    //Assign the packet buffers in the PHY
319    // The auto responder can't transmit from buffer 0, so we use it for Rx packets
320    // The other assignments (DATA/ACK) are arbitrary; any buffer in [1,30] will work
321    pktBuf_rx = 1;
322    pktBuf_tx_DATA = 2;
323    pktBuf_tx_ACK = 3;
324    pktBuf_tx_COG = 4;
325
326    //Initialize the framework
327    // This function sets safe defaults for many parameters in the MAC/PHY frameworks
328    // Many of these can be changed with other warpmac_ and warpphy_ calls
329    //  or by customizing the warpmac.c/warpphy.c source
330    warpmac_init();
331
332    //Read Dip Switch value from FPGA board.
333    //This value will be used as an index into the routing table for other nodes
334    myID = (unsigned short int)warpmac_getMyId();
335    warpmac_rightHex(myID);
336
337    //Set the PHY for SISO using just the radio in slot 2
338    warpphy_setAntennaMode(TX_ANTMODE_SISO_ANTA, RX_ANTMODE_SISO_ANTA);
339
340    //Set the packet detection thresholds
341    warpphy_setEnergyDetThresh(7000);       //Min RSSI (in [0,16368])
342    warpphy_setAutoCorrDetParams(90, 0);    //Min auto-correlation (in [0,2047])
343    warpphy_setLongCorrThresh(8000);        //Min cross-correlation (in [0,45e3])
344   
345    //Rx buffer is where the EMAC will DMA Wireless payloads from
346    warpmac_setRxBuffers(&rxMacframe, pktBuf_rx);
347
348    //Tx buffer is where the EMAC will DMA Ethernet payloads to
349    warpmac_setPHYTxBuffer(pktBuf_tx_DATA);
350    warpmac_setEMACRxBuffer(pktBuf_tx_DATA);
351
352    //Connect the various user-level callbacks
353    warpmac_setCallback(EVENT_DATAFROMNETWORK, (void *)dataFromNetworkLayer_callback);
354    warpmac_setCallback(EVENT_PHYGOODHEADER, (void *)phyRx_goodHeader_callback);
355    warpmac_setCallback(EVENT_PHYBADHEADER, (void *)phyRx_badHeader_callback);
356    warpmac_setCallback(EVENT_UARTRX, (void *)uartRecv_callback);
357    warpmac_setCallback(EVENT_TIMER, (void *)timer_callback);
358   
359    //Set the default center frequency
360    warpphy_setChannel(GHZ_2, 4);
361
362    lastRxSeqNum = 0;
363   
364    Macframe templatePkt;
365   
366
367/************************************/
368/***** AUTO RESPONDER CONFIG *******/
369/************************************/
370    //WORKSHOP PSEUDOCODE: Note, autoresponder functions are not currently part of the API. They are
371    //documented separately at http://warp.rice.edu/trac/wiki/OFDM/MIMO/Docs/AutoResponse
372    //1) Use the PHY_AUTORESPONSE_MATCH_CONFIG macro to make sure that it is only engaged when a
373    //   received packet's destination address matches 'myID'
374    //      NOTE: Addresses are 2-bytes wide and are located at addr PKTHEADER_INDX_DSTADDR
375    //2) Use the PHY_AUTORESPONSE_MATCH_CONFIG macro to make sure that it is only engaged when a
376    //   received packet's type is a DATAPACKET
377
378/**********************USER CODE STARTS HERE***************************/
379    //Setup the PHY's autoResponse system
380   
381    unsigned int autoResp_matchCond;
382   
383    // For CSMA, it is configured to send pktBuf pktBuf_tx_ACK when a good DATA packet is received addressed to this node
384    //Match condition 0: received header's destination address is this node's address
385    autoResp_matchCond = PHY_AUTORESPONSE_MATCH_CONFIG(PKTHEADER_INDX_DSTADDR, 2, htons(NODEID_TO_ADDR(myID)));
386    mimo_ofdmTxRx_setMatch0(autoResp_matchCond);
387
388    //Match condition 1: received header's type is PKTTYPE_DATA
389    autoResp_matchCond = PHY_AUTORESPONSE_MATCH_CONFIG(PKTHEADER_INDX_TYPE, 1, PKTTYPE_DATA);
390    mimo_ofdmTxRx_setMatch1(autoResp_matchCond);
391/**********************USER CODE ENDS HERE***************************/
392
393    //Configure the header translator to use the Rx pkt's src address as the outgoing pkt's dst address
394    // Addresses are two bytes, so two entries in the header translator need to be overridden
395    // Except for these bytes, the ACK pktBuf's contents will be sent unaltered
396    // PHY_HEADERTRANSLATE_SET(templatePktBuf, byteAddrToOverwrite, srcPktBuf, srcByteAddr)
397    PHY_HEADERTRANSLATE_SET(pktBuf_tx_ACK, (PKTHEADER_INDX_DSTADDR+0), pktBuf_rx, (PKTHEADER_INDX_SRCADDR+0));
398    PHY_HEADERTRANSLATE_SET(pktBuf_tx_ACK, (PKTHEADER_INDX_DSTADDR+1), pktBuf_rx, (PKTHEADER_INDX_SRCADDR+1));
399
400    //Create a template ACK packet
401    templatePkt.header.fullRate = HDR_FULLRATE_QPSK;
402    templatePkt.header.codeRate = HDR_CODE_RATE_34;
403    templatePkt.header.length = 0;
404    templatePkt.header.srcAddr = (unsigned short)(NODEID_TO_ADDR(myID));
405    templatePkt.header.pktType = PKTTYPE_ACK;
406
407    //Copy the header down to the PHY's packet buffer
408    // This doesn't actually send anything; the autoResponse system will use this template when sending ACKs
409    warpmac_prepPhyForXmit(&templatePkt, pktBuf_tx_ACK);
410
411    //Action defitions come last; bad things might happen if an action is enabled (set non-zero) before the template pkt is ready.
412    //All actors are disabled during warpphy_init; only load non-zero configurations for actors you intend to use
413    autoResp_delay = 0;
414
415    //Action 0: send pkt from buf pktBuf_tx_ACK when match0 & match1 & goodPkt, using header translation
416    autoResp_action = PHY_AUTORESPONSE_TXACTION_CONFIG(pktBuf_tx_ACK, PHY_AUTORESPONSE_ACT_TRANS_HDR, autoResp_delay, (PHY_AUTORESPONSE_REQ_MATCH0 | PHY_AUTORESPONSE_REQ_MATCH1 | PHY_AUTORESPONSE_REQ_GOODHDR | PHY_AUTORESPONSE_REQ_GOODPKT));
417
418    //Write the configuration word to the PHY's autoResponder
419    mimo_ofdmTxRx_setAction0(autoResp_action);
420
421    //Enable Ethernet
422    warpmac_enableDataFromNetwork();
423
424    while(1)
425    {
426        //Poll the timer, PHY and user I/O forever; actual processing will happen via callbacks above
427        warpmac_pollPeripherals();
428    }
429
430    return;
431}
Note: See TracBrowser for help on using the repository browser.