source: ResearchApps/MAC/Workshop_MACs/HALFMAC_client_hw/halfmac_client_hw.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.6 KB
Line 
1/*! \file halfmac_client_hw.c
2 \brief Reception Half of a CSMA MAC protocol
3
4 @version 16.1
5 @author Chris Hunter
6
7 The goal of this MAC is to act as a receiver to a CSMA-enabled server.
8 This server will continue to retransmit packets until this client
9 acknowledges its reception.
10
11 In this variant, ACK transmission is handled automatically by the
12 autoresponder core.
13
14 Note to workshop users: any names in quotes
15 are names that can be searched for in the
16 WARP API.
17
18*/
19
20
21#include "xparameters.h"
22#include "warpmac.h"
23#include "warpphy.h"
24#include "halfmac_client_hw.h"
25#include "ascii_characters.h"
26#include "string.h"
27#include "errno.h"
28#include "stdlib.h"
29#include "stdio.h"
30
31
32//Define handy macros for CSMA MAC packet types
33///Data packet with payload meant for Ethernet transmission
34#define PKTTYPE_DATA 1
35///Acknowledgement packet meant for halting retransmissions
36#define PKTTYPE_ACK 0
37
38///Buffer for holding a packet-to-xmit across multiple retransmissions
39Macframe txMacframe;
40///Buffer to hold received packet
41Macframe rxMacframe;
42
43unsigned short int myID;
44unsigned char pktBuf_tx_ACK;
45unsigned char pktBuf_tx_DATA;
46unsigned char pktBuf_rx;
47
48unsigned int autoResp_delay;
49unsigned int autoResp_action;
50unsigned int lastRxSeqNum;
51
52///@brief Callback for the reception of UART bytes
53///@param uartByte ASCII byte received from UART
54///
55///Provides the user with the bytes that was received over the serial port. This is useful for configuring
56///PHY and MAC parameters in real time on a board.
57void uartRecv_callback(unsigned char uartByte)
58{
59    if(uartByte != 0x0)
60    {
61        xil_printf("(%c)\t", uartByte);
62
63        switch(uartByte)
64        {
65            case ASCII_a:
66            /**********************DELETE FOR WORKSHOP***************************/
67                autoResp_delay += 10;
68                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));
69                mimo_ofdmTxRx_setAction0(autoResp_action);
70                xil_printf("Autoresponse ACK Delay: %d\r\n", autoResp_delay);
71                break;
72
73            case ASCII_z:
74                autoResp_delay -= 10;
75                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));
76                mimo_ofdmTxRx_setAction0(autoResp_action);
77                xil_printf("Autoresponse ACK Delay: %d\r\n", autoResp_delay);
78            break;
79            /**********************DELETE FOR WORKSHOP***************************/
80            default:
81                //Unused command value; ignore
82            break;
83        }//END switch(uartByte)
84    }
85
86    return;
87}
88
89
90///@brief Callback for the reception of Ethernet packets
91///
92///This function is called by the ethernet MAC drivers
93///when a packet is available to send. This function fills
94///the Macframe transmit buffer with the packet and sends
95///it over the OFDM link
96///@param length Length, in bytes, of received Ethernet frame
97///@param payload address of first byte in Ethernet payload.
98void dataFromNetworkLayer_callback(Xuint32 length, char* payload)
99{
100    //Set the length field in the header
101    txMacframe.header.length = length;
102    //Set the type to be a data packet
103    txMacframe.header.pktType = PKTTYPE_DATA;
104    //Copy in the packet's destination MAC address
105    txMacframe.header.destAddr = (unsigned short int)(NODEID_TO_ADDR(0));
106    //Set the modulation scheme for the packet's full-rate symbols
107    txMacframe.header.fullRate = HDR_FULLRATE_QPSK;
108    //Set the payload coding rate
109    txMacframe.header.codeRate = HDR_CODE_RATE_34;
110    //Copy the header over to packet buffer pktBuf_tx_DATA
111    warpmac_prepPhyForXmit(&txMacframe, pktBuf_tx_DATA);
112    //Send packet buffer pktBuf_tx_DATA
113    warpmac_startPhyXmit(pktBuf_tx_DATA);
114    //Wait for it to finish and enable the receiver
115    warpmac_finishPhyXmit();
116
117    return;
118}
119
120///@brief Callback for the reception of bad wireless headers
121///
122///@param packet Pointer to received Macframe
123void phyRx_badHeader_callback()
124{
125    warpmac_incrementLEDLow();
126}
127
128///@brief Callback for the reception of good wireless headers
129///
130///This function then polls the PHY to determine if the entire packet passes checksum
131///thereby triggering the transmission of the received data over Ethernet.
132///@param packet Pointer to received Macframe
133int phyRx_goodHeader_callback(Macframe* packet)
134{
135
136//WORKSHOP PSEUDOCODE:
137//1) Instantiate an unsigned char variable to monitor the OFDM receiver's state. Default this state variable to "PHYRXSTATUS_INCOMPLETE"
138//2) Check the 'destAddr' element in the 'header' struct of the 'packet' Macframe. Only proceed if this value matches 'myID'
139//          Note: myID is a global that is assigned in main(), based on your node's DIP switch setting at boot
140//3) Check the 'pktType' field of the header.
141//  If 'PKTTYPE_DATA'
142//      4) Poll the state of the state of the receiver using "warpmac_finishPhyRecv." Block until the state turns to either "PHYRXSTATUS_GOOD" or "PHYRXSTATUS_BAD"
143//      If "PHYRXSTATUS_GOOD"
144//          5a) Animate the top two LEDs to visualize this behavior using the "warpmac_incrementLEDHigh" function
145//          6a) Copy the received "Macframe" to the Ethernet MAC (Emac) using "warpmac_prepPktToNetwork"
146//                  Note: The first argument of this function is the beginning of the packet that you want sent over the wire.
147//                        This does NOT include all of the extra wireless MAC header information of the packet. The first byte
148//                         of the payload is located at (void *)warpphy_getBuffAddr(pktBuf_rx)+NUM_HEADER_BYTES,
149//                        where pktBuf_rx is an already defined global in this file (noMac.c) that specifies the location of
150//                        the Macframe in the PHY.
151//          7a) Wait for the ACK to finish sending with "warpmac_finishPhyXmit"
152//                  Note: Even though we did not explicitly transmit an ACK via software, we know that one is currently being sent
153//                        since we configured the autoresponder to do so.
154//          8a) Start the Emac using "warpmac_startPktToNetwork"
155//              Note: The only argument to this function is the length (in bytes) of the packet to be sent. This length is stored in the
156//              the 'length' field of the 'header' struct belonging to the 'packet' Macframe (i.e. packet->header.length).
157//      If "PHYRXSTATUS_BAD"
158//          5b) Animate the bottom two LEDs to visualize this behavior using the "warpmac_incrementLEDLow" function
159
160
161/**********************USER CODE STARTS HERE***************************/
162    unsigned char state = PHYRXSTATUS_INCOMPLETE;
163    char shouldSend = 0;
164   
165    //If the packet is addressed to this node
166    if( packet->header.destAddr == (NODEID_TO_ADDR(myID)) )
167    {
168        switch(packet->header.pktType){
169            //If received packet is data
170            case PKTTYPE_DATA:
171                //At this point, we have pre-loaded the PHY transmitter with the ACK in hoping that
172                // the packet passes checksum. Now we wait for the state of the received to packet
173                // to move from PHYRXSTATUS_INCOMPLETE to either PHYRXSTATUS_GOOD or PHYRXSTATUS_BAD
174
175                //Blocks until the PHY declares the payload good or bad
176                state = warpmac_finishPhyRecv();
177
178                if(state & PHYRXSTATUS_GOOD){
179                    //The auto-reponder will send the pre-programmed ACK automatically
180                    //User code only needs to update its own state, then check to see the PHY
181                    // is finished transmitting
182
183                    //Toggle the top LEDs
184                    warpmac_incrementLEDHigh();
185
186                    //Check if this is a new packet; only send it over Ethernet if it's new
187                    if(packet->header.seqNum != lastRxSeqNum) {
188                        shouldSend = 1;
189                        lastRxSeqNum = packet->header.seqNum;
190                    }
191                   
192                    //Starts the DMA transfer of the payload into the EMAC
193                    if(shouldSend) warpmac_prepPktToNetwork((void *)warpphy_getBuffAddr(pktBuf_rx)+NUM_HEADER_BYTES, (packet->header.length));
194
195                    //Blocks until the PHY is finished sending and enables the receiver
196                    warpmac_finishPhyXmit();
197
198                    //Waits until the DMA transfer is complete, then starts the EMAC
199                    if(shouldSend) warpmac_startPktToNetwork((packet->header.length));
200                }
201
202                if(state & PHYRXSTATUS_BAD){
203                    warpmac_incrementLEDLow();
204                }
205
206                break; //END PKTTYPE_DATA
207            default:
208                //Invalid packet type; ignore
209                break;
210        }
211    }//END rx.destAddr == myID
212    else {
213        state = warpmac_finishPhyRecv();
214    }
215    /**********************USER CODE ENDS HERE***************************/
216
217    //Return 0, indicating we didn't clear the PHY status bits (WARPMAC will handle it)
218    return 0;
219}
220
221///@brief Main function
222///
223///This function configures MAC parameters, enables the underlying frameworks, and then loops forever.
224int main()
225{
226    xil_printf("HALFMAC Client v16.1: AutoResponder-driven Acknowledgments\r\n");
227
228    //Assign the packet buffers in the PHY
229    // The auto responder can't transmit from buffer 0, so we use it for Rx packets
230    // The other assignments (DATA/ACK) are arbitrary; any buffer in [1,30] will work
231    pktBuf_rx = 1;
232    pktBuf_tx_DATA = 2;
233    pktBuf_tx_ACK = 3;
234
235    //Initialize the framework
236    // This function sets safe defaults for many parameters in the MAC/PHY frameworks
237    // Many of these can be changed with other warpmac_ and warpphy_ calls
238    //  or by customizing the warpmac.c/warpphy.c source
239    warpmac_init();
240
241    //Read Dip Switch value from FPGA board.
242    //This value will be used as an index into the routing table for other nodes
243    myID = (unsigned short int)warpmac_getMyId();
244    warpmac_rightHex(myID);
245
246    //Set the PHY for SISO using just the radio in slot 2
247    warpphy_setAntennaMode(TX_ANTMODE_SISO_ANTA, RX_ANTMODE_SISO_ANTA);
248
249    //Set the packet detection thresholds
250    warpphy_setEnergyDetThresh(7000);       //Min RSSI (in [0,16368])
251    warpphy_setAutoCorrDetParams(90, 0);    //Min auto-correlation (in [0,2047])
252    warpphy_setLongCorrThresh(8000);        //Min cross-correlation (in [0,45e3])
253   
254    //Rx buffer is where the EMAC will DMA Wireless payloads from
255    warpmac_setRxBuffers(&rxMacframe, pktBuf_rx);
256
257    //Tx buffer is where the EMAC will DMA Ethernet payloads to
258    warpmac_setPHYTxBuffer(pktBuf_tx_DATA);
259    warpmac_setEMACRxBuffer(pktBuf_tx_DATA);
260
261    //Connect the various user-level callbacks
262    warpmac_setCallback(EVENT_DATAFROMNETWORK, (void *)dataFromNetworkLayer_callback);
263    warpmac_setCallback(EVENT_PHYGOODHEADER, (void *)phyRx_goodHeader_callback);
264    warpmac_setCallback(EVENT_PHYBADHEADER, (void *)phyRx_badHeader_callback);
265    warpmac_setCallback(EVENT_UARTRX, (void *)uartRecv_callback);
266
267    //Set the default center frequency
268    warpphy_setChannel(GHZ_2, 4);
269
270    lastRxSeqNum = 0;
271   
272    Macframe templatePkt;
273   
274
275/************************************/
276/***** AUTO RESPONDER CONFIG *******/
277/************************************/
278    //WORKSHOP PSEUDOCODE: Note, autoresponder functions are not currently part of the API. They are
279    //documented separately at http://warp.rice.edu/trac/wiki/OFDM/MIMO/Docs/AutoResponse
280    //1) Use the PHY_AUTORESPONSE_MATCH_CONFIG macro to make sure that it is only engaged when a
281    //   received packet's destination address matches 'myID'
282    //      NOTE: Addresses are 2-bytes wide and are located at addr PKTHEADER_INDX_DSTADDR
283    //2) Use the PHY_AUTORESPONSE_MATCH_CONFIG macro to make sure that it is only engaged when a
284    //   received packet's type is a DATAPACKET
285
286/**********************USER CODE STARTS HERE***************************/
287    //Setup the PHY's autoResponse system
288   
289    unsigned int autoResp_matchCond;
290   
291    // For CSMA, it is configured to send pktBuf pktBuf_tx_ACK when a good DATA packet is received addressed to this node
292    //Match condition 0: received header's destination address is this node's address
293    autoResp_matchCond = PHY_AUTORESPONSE_MATCH_CONFIG(PKTHEADER_INDX_DSTADDR, 2, htons(NODEID_TO_ADDR(myID)));
294    mimo_ofdmTxRx_setMatch0(autoResp_matchCond);
295
296    //Match condition 1: received header's type is PKTTYPE_DATA
297    autoResp_matchCond = PHY_AUTORESPONSE_MATCH_CONFIG(PKTHEADER_INDX_TYPE, 1, PKTTYPE_DATA);
298    mimo_ofdmTxRx_setMatch1(autoResp_matchCond);
299/**********************USER CODE ENDS HERE***************************/
300
301    //Configure the header translator to use the Rx pkt's src address as the outgoing pkt's dst address
302    // Addresses are two bytes, so two entries in the header translator need to be overridden
303    // Except for these bytes, the ACK pktBuf's contents will be sent unaltered
304    // PHY_HEADERTRANSLATE_SET(templatePktBuf, byteAddrToOverwrite, srcPktBuf, srcByteAddr)
305    PHY_HEADERTRANSLATE_SET(pktBuf_tx_ACK, (PKTHEADER_INDX_DSTADDR+0), pktBuf_rx, (PKTHEADER_INDX_SRCADDR+0));
306    PHY_HEADERTRANSLATE_SET(pktBuf_tx_ACK, (PKTHEADER_INDX_DSTADDR+1), pktBuf_rx, (PKTHEADER_INDX_SRCADDR+1));
307
308    //Create a template ACK packet
309    templatePkt.header.fullRate = HDR_FULLRATE_QPSK;
310    templatePkt.header.codeRate = HDR_CODE_RATE_34;
311    templatePkt.header.length = 0;
312    templatePkt.header.srcAddr = (unsigned short)(NODEID_TO_ADDR(myID));
313    templatePkt.header.pktType = PKTTYPE_ACK;
314
315    //Copy the header down to the PHY's packet buffer
316    // This doesn't actually send anything; the autoResponse system will use this template when sending ACKs
317    warpmac_prepPhyForXmit(&templatePkt, pktBuf_tx_ACK);
318
319    //Action defitions come last; bad things might happen if an action is enabled (set non-zero) before the template pkt is ready.
320    //All actors are disabled during warpphy_init; only load non-zero configurations for actors you intend to use
321    autoResp_delay = 0;
322
323    //Action 0: send pkt from buf pktBuf_tx_ACK when match0 & match1 & goodPkt, using header translation
324    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));
325
326    //Write the configuration word to the PHY's autoResponder
327    mimo_ofdmTxRx_setAction0(autoResp_action);
328
329    //Enable Ethernet
330    warpmac_enableDataFromNetwork();
331
332    while(1)
333    {
334        //Poll the timer, PHY and user I/O forever; actual processing will happen via callbacks above
335        warpmac_pollPeripherals();
336    }
337
338    return;
339}
Note: See TracBrowser for help on using the repository browser.