source: ResearchApps/MAC/Workshop_MACs/HALFMAC_client_sw/halfmac_client_sw.c

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

fixing bug in halfMac_sw

  • Property svn:executable set to *
File size: 10.0 KB
Line 
1/*! \file halfmac_client_sw.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 directly by software using
12 the transmission mechanisms in the WARPMAC framework.
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_sw.h"
25#include "string.h"
26#include "errno.h"
27#include "stdlib.h"
28#include "stdio.h"
29
30
31//Define handy macros for CSMA MAC packet types
32///Data packet with payload meant for Ethernet transmission
33#define PKTTYPE_DATA 1
34///Acknowledgement packet meant for halting retransmissions
35#define PKTTYPE_ACK 0
36
37///Buffer for holding a packet-to-xmit across multiple retransmissions
38Macframe txMacframe;
39///Buffer to hold received packet
40Macframe rxMacframe;
41
42unsigned short int myID;
43unsigned char pktBuf_tx_ACK;
44unsigned char pktBuf_tx_DATA;
45unsigned char pktBuf_rx;
46
47//Variable to keep track of the sequence number of the last error-free packet received
48// This prevents duplicate packets from being sent via Ethernet, which confuses apps
49unsigned int lastRxSeqNum;
50
51///@brief Callback for the reception of Ethernet packets
52///
53///This function is called by the ethernet MAC drivers
54///when a packet is available to send. This function fills
55///the Macframe transmit buffer with the packet and sends
56///it over the OFDM link
57///@param length Length, in bytes, of received Ethernet frame
58///@param payload address of first byte in Ethernet payload.
59void dataFromNetworkLayer_callback(Xuint32 length, char* payload)
60{
61
62    //Note: This code is virtually identical to the code used previously in the noMac workshop exercise.
63    //It does not fully implement the halfmac_server's transmission states (e.g. no retransmission, no carrier sensing,
64    //no binary exponential backoff).
65
66    //Set the length field in the header
67    txMacframe.header.length = length;
68    //Set the type to be a data packet
69    txMacframe.header.pktType = PKTTYPE_DATA;
70    //Copy in the packet's destination MAC address
71    txMacframe.header.destAddr = (unsigned short int)(NODEID_TO_ADDR(0));
72    //Set the modulation scheme for the packet's full-rate symbols
73    txMacframe.header.fullRate = HDR_FULLRATE_QPSK;
74    //Set the payload coding rate
75    txMacframe.header.codeRate = HDR_CODE_RATE_34;
76    //Copy the header over to the PHY's transmit packet buffer
77    warpmac_prepPhyForXmit(&txMacframe, pktBuf_tx_DATA);
78    //Send packet buffer pktBuf_tx_DATA
79    warpmac_startPhyXmit(pktBuf_tx_DATA);
80    //Wait for it to finish and enable the receiver
81    warpmac_finishPhyXmit();
82}
83
84///@brief Callback for the reception of bad wireless headers
85///
86///@param packet Pointer to received Macframe
87void phyRx_badHeader_callback()
88{
89    warpmac_incrementLEDLow();
90}
91
92///@brief Callback for the reception of good wireless headers
93///
94///This function then polls the PHY to determine if the entire packet passes checksum
95///thereby triggering the transmission of the received data over Ethernet.
96///@param packet Pointer to received Macframe
97int phyRx_goodHeader_callback(Macframe* packet){
98
99//WORKSHOP PSEUDOCODE:
100//1) Instantiate an unsigned char variable to monitor the OFDM receiver's state. Default this state variable to "PHYRXSTATUS_INCOMPLETE"
101//2) Instantiate a new Macframe to represent the acknowledgment packet you send if the payload of received packet is error-free
102//3) Check the 'destAddr' element in the 'header' struct of the 'packet' Macframe. Only proceed if this value matches 'myID'
103//          Note: myID is a global that is assigned in main(), based on your node's DIP switch setting at boot
104//4) Check the 'pktType' field of the header.
105//  If 'PKTTYPE_DATA'
106//      5) Fill in the Macframe you created at the top of this function. You must fill in the following fields:
107//          - 'length' should be 0 (i.e. there is no payload present in an ACK packet)
108//          - 'pktType' should be 'ACKPACKET' in order to differentiate this packet from data frames
109//          - 'fullRate' should be 'HDR_FULLRATE_QPSK' (the ACK has no full-rate payload, but this field msut still have a valid value)
110//          - 'codeRate' should be 'HDR_CODE_RATE_34' (the ACK has no coded payload, but this field msut still have a valid value)
111//          - 'srcAddr' should be set to your node's ID (myID)
112//          - 'destAddr' should be set to the 'srcAddr' of the received packet
113//      6) Copy the ACK into the 'pktBuf_tx_ACK' PHY buffer using "warpmac_prepPhyForXmit"
114//      7) Poll the state of the state of the receiver using "warpmac_finishPhyRecv." Block until the state turns to either "PHYRXSTATUS_GOOD" or "PHYRXSTATUS_BAD"
115//      If "GOODPACKET"
116//          9a) Send the ACK using 'warpmac_startPhyXmit'
117//          10a) Animate the top two LEDs to visualize this behavior using the "warpmac_incrementLEDHigh" function
118//          11a) Using the received packet header's sequence number, check if this is a duplicate packet that you have already transmitted via Ethernet. If not:
119//                Copy the received "Macframe" to the Ethernet MAC (Emac) using "warpmac_prepPktToNetwork"
120//                  Note: The first argument of this function is the beginning of the packet that you want sent over the wire.
121//                        This does NOT include all of the extra wireless MAC header information of the packet. The first byte
122//                         of the payload is located at (void *)warpphy_getBuffAddr(pktBuf_rx)+NUM_HEADER_BYTES,
123//                        where pktBuf_rx is an already defined global in this file (noMac.c) that specifies the location of
124//                        the Macframe in the PHY.
125//          12a) Wait for the ACK to finish sending with "warpmac_finishPhyXmit"
126//          13a) Start the Emac using "warpmac_startPktToNetwork"
127//              Note: The only argument to this function is the length (in bytes) of the packet to be sent. This length is stored in the
128//              the 'length' field of the 'header' struct belonging to the 'packet' Macframe (i.e. packet->header.length).
129//      If "BADPACKET"
130//          9b) Animate the bottom two LEDs to visualize this behavior using the "warpmac_incrementLEDLow" function
131
132
133/**********************USER CODE STARTS HERE***************************/
134    unsigned char state = PHYRXSTATUS_INCOMPLETE;
135    Macframe ackPacket;
136    char shouldSend = 0;
137
138    //If the packet is addressed to this node
139    if( packet->header.destAddr == (NODEID_TO_ADDR(myID)) )
140    {
141        switch(packet->header.pktType) {
142            //If received packet is data
143            case PKTTYPE_DATA:
144
145                //Fill in the ACK header
146                ackPacket.header.length = 0;
147                ackPacket.header.pktType = PKTTYPE_ACK;
148                ackPacket.header.fullRate = HDR_FULLRATE_QPSK;
149                ackPacket.header.codeRate = HDR_CODE_RATE_34;
150                ackPacket.header.srcAddr = NODEID_TO_ADDR(myID);
151                ackPacket.header.destAddr = packet->header.srcAddr;
152
153                //Copy the header over to packet pktBuf_tx_ACK
154                warpmac_prepPhyForXmit(&ackPacket, pktBuf_tx_ACK);
155
156                //Blocks until the PHY declares the payload good or bad
157                state = warpmac_finishPhyRecv();
158
159                if(state & PHYRXSTATUS_GOOD) {
160                    warpmac_startPhyXmit(pktBuf_tx_ACK);
161
162                    //Toggle the top LEDs
163                    warpmac_incrementLEDHigh();
164
165                    //Check if this is a new packet; only send it over Ethernet if it's new
166                    if(packet->header.seqNum != lastRxSeqNum) {
167                        shouldSend = 1;
168                        lastRxSeqNum = packet->header.seqNum;
169                    }
170                   
171                    //Starts the DMA transfer of the payload into the EMAC
172                    if(shouldSend) warpmac_prepPktToNetwork((void *)warpphy_getBuffAddr(pktBuf_rx)+NUM_HEADER_BYTES, (packet->header.length));
173
174                    //Blocks until the PHY is finished sending and enables the receiver
175                    warpmac_finishPhyXmit();
176
177                    //Waits until the DMA transfer is complete, then starts the EMAC
178                    if(shouldSend) warpmac_startPktToNetwork((packet->header.length));
179                }
180
181                if(state & PHYRXSTATUS_BAD) {
182                    warpmac_incrementLEDLow();
183                }
184
185                break; //END PKTTYPE_DATA
186            default:
187                //Invalid packet type; ignore this reception
188                break;
189        }
190    }//END rx.destAddr == myID
191    else {
192        state = warpmac_finishPhyRecv();
193    }
194    /**********************USER CODE ENDS HERE***************************/
195
196    //Return 0, indicating we didn't clear the PHY status bits (WARPMAC will handle it)
197    return 0;
198}
199
200///@brief Main function
201///
202///This function configures MAC parameters, enables the underlying frameworks, and then loops forever.
203int main()
204{
205    xil_printf("HALFMAC Client v16.1: Software-driven Acknowledgments\r\n");
206
207
208    //Assign the packet buffers in the PHY
209    pktBuf_rx = 1;
210    pktBuf_tx_DATA = 2;
211    pktBuf_tx_ACK = 3;
212
213    //Initialize the framework
214    // This function sets safe defaults for many parameters in the MAC/PHY frameworks
215    // Many of these can be changed with other warpmac_ and warpphy_ calls
216    //  or by customizing the warpmac.c/warpphy.c source
217    warpmac_init();
218
219    //Read Dip Switch value from FPGA board.
220    //This value will be used as an index into the routing table for other nodes
221    myID = (unsigned short int)warpmac_getMyId();
222    warpmac_rightHex(myID);
223
224    //Set the PHY for SISO using just the radio in slot 2
225    warpphy_setAntennaMode(TX_ANTMODE_SISO_ANTA, RX_ANTMODE_SISO_ANTA);
226
227    //Set the packet detection thresholds
228    warpphy_setEnergyDetThresh(7000);       //Min RSSI (in [0,16368])
229    warpphy_setAutoCorrDetParams(90, 0);    //Min auto-correlation (in [0,2047])
230    warpphy_setLongCorrThresh(8000);        //Min cross-correlation (in [0,45e3])
231   
232    //Rx buffer is where the EMAC will DMA Wireless payloads from
233    warpmac_setRxBuffers(&rxMacframe, pktBuf_rx);
234
235    //Tx buffer is where the EMAC will DMA Ethernet payloads to
236    warpmac_setPHYTxBuffer(pktBuf_tx_DATA);
237    warpmac_setEMACRxBuffer(pktBuf_tx_DATA);
238
239    //Connect the various user-level callbacks
240    warpmac_setCallback(EVENT_DATAFROMNETWORK, (void *)dataFromNetworkLayer_callback);
241    warpmac_setCallback(EVENT_PHYGOODHEADER, (void *)phyRx_goodHeader_callback);
242    warpmac_setCallback(EVENT_PHYBADHEADER, (void *)phyRx_badHeader_callback);
243
244    //Set the default center frequency
245    warpphy_setChannel(GHZ_2, 4);
246
247    lastRxSeqNum = 0;
248
249    //Enable Ethernet
250    warpmac_enableDataFromNetwork();
251
252    while(1)
253    {
254        //Poll the timer, PHY and user I/O forever; actual processing will happen via callbacks above
255        warpmac_pollPeripherals();
256    }
257
258    return;
259}
Note: See TracBrowser for help on using the repository browser.