root/ResearchApps/MAC/HOPMAC/hopMacClient.c
| Revision 997, 10.4 kB (checked in by chunter, 6 weeks ago) |
|---|
| Line | |
|---|---|
| 1 | /*! \file hopMacClient.c |
| 2 | \brief Hop MAC Workshop Exercise. |
| 3 | |
| 4 | @version 10 |
| 5 | @author Chris Hunter |
| 6 | |
| 7 | This exercise is an extension of the previous |
| 8 | HALFMAC exercise. In fact, you are welcome |
| 9 | top copy and paste the parts of the code you |
| 10 | completed in that exercise for the similar |
| 11 | tasks here. |
| 12 | |
| 13 | The twist in this lab is that the server |
| 14 | will periodically hop to a new part of the |
| 15 | spectrum. Before doing so, it will transmit |
| 16 | a special control packet (HOPPACKET) that |
| 17 | contains the destination frequency band. |
| 18 | |
| 19 | If the packet is missed, your receiver will |
| 20 | be stuck until the transmitter randomly hops |
| 21 | back onto the channel you were sitting at. |
| 22 | This can potentially be a very long time. |
| 23 | An advanced extension to this lab is to |
| 24 | scan for packets in various channels when |
| 25 | no good packet is received for a certain |
| 26 | amount of time. For our purposes, let this |
| 27 | timeout be around 200ms. |
| 28 | */ |
| 29 | |
| 30 | #include "warpmac.h" |
| 31 | #include "warpphy.h" |
| 32 | #include "hopMacClient.h" |
| 33 | #include "xparameters.h" |
| 34 | #include "string.h" |
| 35 | #include "errno.h" |
| 36 | #include "stdlib.h" |
| 37 | #include "stdio.h" |
| 38 | #include "xutil.h" |
| 39 | #include "ofdm_timer_regMacros.h" |
| 40 | |
| 41 | ///Routing table with agreed upon mapping between dipswitches and physical addresses |
| 42 | typedef struct { |
| 43 | unsigned char addr[6]; |
| 44 | } route; |
| 45 | |
| 46 | ///Instance of the routing table |
| 47 | route routeTable[16]; |
| 48 | |
| 49 | ///Byte array containing physical MAC address of this node |
| 50 | unsigned char myAddr[6]; |
| 51 | ///Index to the routing table that identifies this node |
| 52 | unsigned char myID; |
| 53 | |
| 54 | ///Buffer for holding a packet-to-xmit across multiple retransmissions |
| 55 | Macframe txBuffer; |
| 56 | ///Buffer to hold received packet |
| 57 | Macframe rxBuffer; |
| 58 | |
| 59 | unsigned char chan; |
| 60 | |
| 61 | ///Data packet with payload meant for Ethernet transmission |
| 62 | #define DATAPACKET 1 |
| 63 | ///Acknowledgement packet meant for halting retransmissions |
| 64 | #define ACKPACKET 0 |
| 65 | ///Control packet containing destination frequency band |
| 66 | #define HOPPACKET 2 |
| 67 | |
| 68 | /**********************DELETE FOR WORKSHOP***************************/ |
| 69 | /////////////////////SEEK MODE: OPTIONAL EXTENSION////////////////////////// |
| 70 | unsigned int waitTime = 200; //If a packet hasn't been received in the last 200 ms, exhaustively search the spectrum |
| 71 | unsigned char scanMode=0; //By default, the optional scan mode is disabled |
| 72 | void middle(){ |
| 73 | /*Disables the optional scan mode*/ |
| 74 | scanMode=0; |
| 75 | } |
| 76 | |
| 77 | void up(){ |
| 78 | /*Enables the optional scan mode*/ |
| 79 | scanMode=1; |
| 80 | warpmac_stopTimer(); |
| 81 | warpmac_setTimerVal(waitTime*40000); |
| 82 | warpmac_startTimer(DISABLECSMA); |
| 83 | } |
| 84 | |
| 85 | void left(){ |
| 86 | /*Increases the timeout to begin exhaustive scan*/ |
| 87 | waitTime=waitTime-10; |
| 88 | } |
| 89 | |
| 90 | void right(){ |
| 91 | /*Decreases the timeout to begin exhaustive scan*/ |
| 92 | waitTime=waitTime+10; |
| 93 | } |
| 94 | |
| 95 | unsigned char dispIndex = 0; |
| 96 | int timerExpire(){ |
| 97 | if(scanMode){ |
| 98 | chan = ((chan+1)%15); |
| 99 | if(chan==0) chan=1; |
| 100 | warpphy_setChannel(GHZ_2,chan); |
| 101 | warpmac_leftHex(chan); |
| 102 | warpmac_stopTimer(); |
| 103 | warpmac_setTimerVal(waitTime*40000); |
| 104 | warpmac_startTimer(DISABLECSMA); |
| 105 | } |
| 106 | } |
| 107 | ///////////////////////////////////////////////////////////////////////////// |
| 108 | /**********************DELETE FOR WORKSHOP***************************/ |
| 109 | |
| 110 | ///@brief Callback for the reception of Ethernet packets |
| 111 | /// |
| 112 | ///This function is called by the ethernet MAC drivers |
| 113 | ///when a packet is available to send. This function fills |
| 114 | ///the Macframe transmit buffer with the packet and sends |
| 115 | ///it over the OFDM link |
| 116 | ///@param length Length, in bytes, of received Ethernet frame |
| 117 | ///@param payload address of first byte in Ethernet payload. |
| 118 | void emacRx_callback(Xuint32 length, char* payload){ |
| 119 | |
| 120 | //Set the length of the Macfram |
| 121 | txBuffer.header.length = length; |
| 122 | //Define the type to be data |
| 123 | txBuffer.header.pktType = DATAPACKET; |
| 124 | //Set the modulation scheme for the packet's full-rate symbols |
| 125 | txBuffer.header.fullRate = QPSK; |
| 126 | //Copy in the packet's destination MAC address |
| 127 | //Hard-coded as the server (ID = 0) |
| 128 | memcpy(txBuffer.header.destAddr,routeTable[0].addr,6); |
| 129 | //Copy the header over to packet buffer 1 |
| 130 | warpmac_prepPhyForXmit(&txBuffer,1); |
| 131 | //Send packet buffer 1 |
| 132 | warpmac_startPhyXmit(1); |
| 133 | //Wait for it to finish and enable the receiver |
| 134 | warpmac_finishPhyXmit(); |
| 135 | |
| 136 | return 0; |
| 137 | } |
| 138 | |
| 139 | ///@brief Callback for the reception of bad wireless headers |
| 140 | /// |
| 141 | ///@param packet Pointer to received Macframe |
| 142 | void phyRx_badHeader_callback() { |
| 143 | warpmac_incrementLEDLow(); |
| 144 | } |
| 145 | |
| 146 | ///@brief Callback for the reception of good wireless headers |
| 147 | /// |
| 148 | ///This function then polls the PHY to determine if the entire packet passes checksum |
| 149 | ///thereby triggering the transmission of the ACK and the transmission of the received |
| 150 | ///data over Ethernet. |
| 151 | ///@param packet Pointer to received Macframe |
| 152 | void phyRx_goodHeader_callback(Macframe* packet){ |
| 153 | |
| 154 | /**********************DELETE FOR WORKSHOP***************************/ |
| 155 | /////////////////////SEEK MODE: OPTIONAL EXTENSION////////////////////////// |
| 156 | warpmac_stopTimer(); |
| 157 | warpmac_setTimerVal(waitTime*40000); |
| 158 | warpmac_startTimer(DISABLECSMA); |
| 159 | ///////////////////////////////////////////////////////////////////////////// |
| 160 | /**********************DELETE FOR WORKSHOP***************************/ |
| 161 | |
| 162 | //Pseudocode for workshop users: |
| 163 | //1) Instantiate a "Macframe" that will be an acknowledgement packet |
| 164 | //2) Instantiate a variable to keep track of the receiver's state. Default this state variable to "INCOMPLETE" |
| 165 | //3) Check the "pktType" of the "phyHeader" of the received "Macframe" |
| 166 | //If "HOPPACKET" |
| 167 | // 4) Animate the top two LEDs using the "warpmac_incrementLEDHigh" function |
| 168 | // 5) Switch to the channel located in "packet->header.reserved1" using the "warpphy_setChannel" function (make sure to stay in "GHZ_2") |
| 169 | //If "DATAPACKET" |
| 170 | // 4) Set the acknowledgment "Macframe" to length 0 (Header only... no payload) |
| 171 | // 5) Set the "pktType" of the "phyHeader" of the acknowledgment "Macframe" to "ACKPACKET" |
| 172 | // 6) Set full rate modulation order to "QPSK" |
| 173 | // 7) memcpy the 6 bytes of "myAddr" into the "srcAddr" field of the acknowledgment |
| 174 | // 8) memcpy the 6 bytes of "packet->header.srcAddr" into the "destAddr" field of the acknowledgment (to send it back to the source of the data) |
| 175 | // 9) Copy the acknowledgement over to packet buffer 2 using the "warpmac_prepPhyForXmit" function |
| 176 | // 10) Poll the state of the state of the receiver using "warpphy_pollRxStatus." Block until the state turns to either "GOODPACKET" or "BADPACKET" |
| 177 | // If "GOODPACKET" |
| 178 | // 11) Send the acknowledgment sitting in packet buffer 2 using the "warpmac_startPhyXmit" |
| 179 | // Note: Since we have pre-loaded the acknowledgment into the PHY transmitter, the ACK will go over-the-air within 20 microseconds |
| 180 | // after the source transmitter finished |
| 181 | // 12) Animate the top two LEDs to visualize this behavior using the "warpmac_incrementLEDHigh" function |
| 182 | // 13) Copy the received "Macframe" to Ethernet using "warpmac_prepEmacForXmit" |
| 183 | // 14) Start the Emac using "warpmac_startEmacXmit" |
| 184 | // If "BADPACKET" |
| 185 | // 11) Animate the bottom two LEDs to visualize this behavior using the "warpmac_incrementLEDLow" function |
| 186 | |
| 187 | /**********************DELETE FOR WORKSHOP***************************/ |
| 188 | Macframe ackPacket; |
| 189 | unsigned char state=INCOMPLETE; |
| 190 | |
| 191 | if(packet->header.pktType==HOPPACKET){ |
| 192 | //If HOPPACKET is received, jump to the channel in reserved1 of header |
| 193 | warpmac_incrementLEDHigh(); |
| 194 | warpphy_setChannel(GHZ_2,packet->header.reserved1); |
| 195 | chan = packet->header.reserved1; |
| 196 | warpmac_leftHex(chan); |
| 197 | } |
| 198 | |
| 199 | |
| 200 | if(packet->header.pktType==DATAPACKET){ |
| 201 | |
| 202 | if(warpmac_addressedToMe(packet)){ |
| 203 | |
| 204 | |
| 205 | ackPacket.header.length = 0; |
| 206 | ackPacket.header.pktType = ACKPACKET; |
| 207 | ackPacket.header.fullRate = QPSK; |
| 208 | memcpy(ackPacket.header.srcAddr,(unsigned char *)myAddr,6); |
| 209 | memcpy(ackPacket.header.destAddr,packet->header.srcAddr,6); |
| 210 | |
| 211 | //Copy the header over to packet buffer 2 |
| 212 | warpmac_prepPhyForXmit(&ackPacket,2); |
| 213 | |
| 214 | |
| 215 | while(state==INCOMPLETE){ |
| 216 | //Blocks until the PHY reports the received packet as either good or bad |
| 217 | state = warpphy_pollRxStatus(); |
| 218 | } |
| 219 | |
| 220 | if(state==GOODPACKET){ |
| 221 | //Send packet buffer 2 |
| 222 | warpmac_startPhyXmit(2); |
| 223 | warpmac_incrementLEDHigh(); |
| 224 | //Starts the DMA transfer of the payload into the EMAC |
| 225 | warpmac_prepEmacForXmit(packet); |
| 226 | //Blocks until the PHY is finished sending and enables the receiver |
| 227 | warpmac_finishPhyXmit(); |
| 228 | //Waits until the DMA transfer is complete, then starts the EMAC |
| 229 | warpmac_startEmacXmit(packet); |
| 230 | |
| 231 | } |
| 232 | |
| 233 | if(state==BADPACKET){ |
| 234 | //xil_printf("BAD Packet, good header\r\n"); |
| 235 | warpmac_incrementLEDLow(); |
| 236 | } |
| 237 | |
| 238 | } |
| 239 | |
| 240 | } |
| 241 | /**********************DELETE FOR WORKSHOP***************************/ |
| 242 | } |
| 243 | |
| 244 | ///@brief Main function |
| 245 | /// |
| 246 | ///This function configures MAC parameters, enables the underlying frameworks, and then loops forever. |
| 247 | int main(){ |
| 248 | xil_printf("Hopmac Client\r\n"); |
| 249 | //Initialize the framework |
| 250 | warpmac_init(); |
| 251 | |
| 252 | chan = 1; |
| 253 | |
| 254 | //Read Dip Switch value from FPGA board. |
| 255 | //This value will be used as an index into the routing table for other nodes |
| 256 | myID = warpmac_getMyId(); |
| 257 | |
| 258 | //Create an arbitrary address for this node |
| 259 | unsigned char tmpAddr[6] = {0x16,0x24,0x63,0x53,0xe2,0xc2+myID}; |
| 260 | |
| 261 | |
| 262 | memcpy((unsigned char *)myAddr,(unsigned char *)tmpAddr,6); |
| 263 | |
| 264 | //Fill an arbitrary routing table so that nodes know each others' addresses |
| 265 | unsigned char i; |
| 266 | for(i=0;i<16;i++){ |
| 267 | routeTable[i].addr[0] = myAddr[0]; |
| 268 | routeTable[i].addr[1] = myAddr[1]; |
| 269 | routeTable[i].addr[2] = myAddr[2]; |
| 270 | routeTable[i].addr[3] = myAddr[3]; |
| 271 | routeTable[i].addr[4] = myAddr[4]; |
| 272 | routeTable[i].addr[5] = myAddr[5]+i-myID; |
| 273 | } |
| 274 | |
| 275 | warpmac_setMacAddr((unsigned char *)(&myAddr)); |
| 276 | |
| 277 | |
| 278 | warpmac_setRxBuffer(&rxBuffer,0); |
| 279 | //Tx buffer is where the EMAC will DMA payloads to |
| 280 | warpmac_setTxBuffer(1); |
| 281 | |
| 282 | //Copy this node's MAC address into the Tx buffer's source address field |
| 283 | memcpy(txBuffer.header.srcAddr,(unsigned char *)myAddr,6); |
| 284 | |
| 285 | warpmac_setBadHeaderCallback((void *)phyRx_badHeader_callback); |
| 286 | warpmac_setGoodHeaderCallback((void *)phyRx_goodHeader_callback); |
| 287 | warpmac_setEmacCallback((void *)emacRx_callback); |
| 288 | |
| 289 | |
| 290 | /////////////////////SEEK MODE: OPTIONAL EXTENSION////////////////////////// |
| 291 | warpmac_setMiddleButtonCallback(middle); |
| 292 | warpmac_setUpButtonCallback(up); |
| 293 | warpmac_setLeftButtonCallback(left); |
| 294 | warpmac_setRightButtonCallback(right); |
| 295 | warpmac_setTimerCallback(timerExpire); |
| 296 | warpmac_setTimerVal(waitTime*40000); |
| 297 | warpmac_startTimer(DISABLECSMA); |
| 298 | ///////////////////////////////////////////////////////////////////////////// |
| 299 | |
| 300 | |
| 301 | //Set the default center frequency |
| 302 | warpphy_setChannel(GHZ_2, chan); |
| 303 | |
| 304 | warpmac_enableCSMA(); |
| 305 | warpmac_enableEthernet(); |
| 306 | |
| 307 | //Set the modulation scheme use for base rate (header) symbols |
| 308 | warpmac_setBaseRate(QPSK); |
| 309 | |
| 310 | while(1){ |
| 311 | warpmac_pollEthernet(); |
| 312 | } |
| 313 | |
| 314 | return; |
| 315 | } |
Note: See TracBrowser
for help on using the browser.