[676] | 1 | /*! \file csmaMac.c |
---|
[941] | 2 | \brief Carrier-Sensing Random Access MAC. |
---|
[1453] | 3 | |
---|
[1816] | 4 | @version 18.0 |
---|
[1215] | 5 | @author Chris Hunter and Patrick Murphy |
---|
[1169] | 6 | |
---|
[941] | 7 | The csmaMac is a modified ALOHA MAC that |
---|
| 8 | serves as an example for novel MAC |
---|
| 9 | development. Nodes transmit whenever |
---|
| 10 | they have information to transmit, and only |
---|
| 11 | move on to the next packet once the original |
---|
| 12 | transmit is acknowledged (ACKed). If no ACK |
---|
| 13 | is received, a collision is inferred and the |
---|
| 14 | packet is re-transmitted. |
---|
[1453] | 15 | |
---|
[941] | 16 | By default, the MAC also implements carrier- |
---|
| 17 | sensing multiple-access with collision- |
---|
| 18 | avoidance (CSMA-CA). This functionality is |
---|
| 19 | built into hardware peripherals in the project |
---|
| 20 | so very little software state is affected. |
---|
[1453] | 21 | |
---|
[941] | 22 | In its current state, the project acts as |
---|
[1712] | 23 | a true Ethernet MAC-level wireless bridge. |
---|
| 24 | Any Ethernet activity that appears on one |
---|
[941] | 25 | WARP will be sent to another via the custom |
---|
| 26 | wireless link. |
---|
[1453] | 27 | |
---|
[1215] | 28 | Also, the current versions supports hardware-triggered |
---|
| 29 | ACK transmissions. This reduces the turn-around time |
---|
| 30 | as well as reduces the jitter on the start time of the ACK |
---|
[1712] | 31 | relative to the start time of the preceding DATA. |
---|
[1215] | 32 | |
---|
[941] | 33 | */ |
---|
[594] | 34 | #include "warpmac.h" |
---|
[676] | 35 | #include "warpphy.h" |
---|
[824] | 36 | #include "csmaMac.h" |
---|
[1712] | 37 | #include "util/ascii_characters.h" |
---|
| 38 | #include "util/ofdm_txrx_mimo_regMacros.h" |
---|
| 39 | #include "util/ofdm_agc_mimo_regMacros.h" |
---|
| 40 | |
---|
| 41 | #include "stdio.h" |
---|
[594] | 42 | #include "xparameters.h" |
---|
[1890] | 43 | #include "warp_hw_ver.h" |
---|
[594] | 44 | |
---|
[1223] | 45 | Macframe templatePkt; |
---|
| 46 | |
---|
| 47 | unsigned int autoResp_matchCond; |
---|
| 48 | unsigned int autoResp_action; |
---|
| 49 | unsigned char pktBuf_tx_ACK; |
---|
| 50 | unsigned char pktBuf_tx_DATA; |
---|
| 51 | unsigned char pktBuf_rx; |
---|
| 52 | |
---|
[1639] | 53 | unsigned short pktDet_AC_corr, pktDet_AC_energy, pktDet_RSSI_thresh; |
---|
| 54 | char debug_goodHdrPrint; |
---|
| 55 | |
---|
[1110] | 56 | //Arrays to track pkt sequence numbers for each partner node |
---|
| 57 | unsigned char rxSequences[16]; |
---|
| 58 | unsigned char txSequences[16]; |
---|
| 59 | |
---|
[1174] | 60 | unsigned char maximumReSend; |
---|
| 61 | |
---|
[1579] | 62 | ///ID of this node |
---|
[1215] | 63 | unsigned short int myID; |
---|
[594] | 64 | |
---|
[1063] | 65 | ///Full rate modulation selection; QPSK by default |
---|
| 66 | unsigned int pktFullRate; |
---|
| 67 | |
---|
[1617] | 68 | //Payload code rate selection |
---|
[1110] | 69 | unsigned int pktCodeRate; |
---|
| 70 | |
---|
[679] | 71 | ///Buffer for holding a packet-to-xmit across multiple retransmissions |
---|
[1380] | 72 | Macframe txMacframe; |
---|
[679] | 73 | ///Buffer to hold received packet |
---|
[1380] | 74 | Macframe rxMacframe; |
---|
[594] | 75 | |
---|
[987] | 76 | ///Current 802.11 channel |
---|
[1063] | 77 | unsigned char chan; |
---|
[941] | 78 | |
---|
[1169] | 79 | //Define handy macros for CSMA MAC packet types |
---|
[679] | 80 | ///Data packet with payload meant for Ethernet transmission |
---|
[1579] | 81 | #define PKTTYPE_DATA 1 |
---|
[990] | 82 | ///Acknowledgement packet meant for halting retransmissions |
---|
[1579] | 83 | #define PKTTYPE_ACK 0 |
---|
[594] | 84 | |
---|
[906] | 85 | ///@brief Callback for the depression of the left push button |
---|
| 86 | /// |
---|
[1169] | 87 | ///This function is empty by default |
---|
[1380] | 88 | void leftButton() { |
---|
[906] | 89 | } |
---|
| 90 | |
---|
| 91 | ///@brief Callback for the depression of the right push button |
---|
| 92 | /// |
---|
[1169] | 93 | ///This button switched between different fullrate modulation orders |
---|
[1380] | 94 | void rightButton() { |
---|
[1169] | 95 | switch(pktFullRate){ |
---|
| 96 | case HDR_FULLRATE_BPSK: |
---|
| 97 | pktFullRate = HDR_FULLRATE_QPSK; |
---|
[1171] | 98 | xil_printf("QPSK\r\n"); |
---|
[1169] | 99 | break; |
---|
| 100 | case HDR_FULLRATE_QPSK: |
---|
| 101 | pktFullRate = HDR_FULLRATE_QAM_16; |
---|
[1171] | 102 | xil_printf("16-QAM\r\n"); |
---|
[1169] | 103 | break; |
---|
| 104 | case HDR_FULLRATE_QAM_16: |
---|
| 105 | pktFullRate = HDR_FULLRATE_QAM_64; |
---|
[1171] | 106 | xil_printf("64-QAM\r\n"); |
---|
[1169] | 107 | break; |
---|
| 108 | case HDR_FULLRATE_QAM_64: |
---|
| 109 | pktFullRate = HDR_FULLRATE_BPSK; |
---|
[1171] | 110 | xil_printf("BPSK\r\n"); |
---|
[1169] | 111 | break; |
---|
| 112 | } |
---|
[906] | 113 | } |
---|
| 114 | |
---|
| 115 | ///@brief Callback for the depression of the up push button |
---|
| 116 | /// |
---|
[1063] | 117 | ///This button increments the 2.4GHz channel being used; only valid channels (in [1,14]) will be used |
---|
[1380] | 118 | void upButton() { |
---|
[1063] | 119 | unsigned int newFreq; |
---|
[1453] | 120 | |
---|
[1169] | 121 | chan = (chan > 13) ? 14 : chan+1; |
---|
[1063] | 122 | newFreq = warpphy_setChannel(GHZ_2, chan); |
---|
[906] | 123 | warpmac_leftHex(chan); |
---|
[1453] | 124 | |
---|
[1169] | 125 | xil_printf("New Frequency %d\r\n", newFreq); |
---|
[906] | 126 | } |
---|
| 127 | |
---|
| 128 | ///@brief Callback for the depression of the middle push button |
---|
| 129 | /// |
---|
[1063] | 130 | ///This button decrements the 2.4GHz channel being used; only valid channels (in [1,14]) will be used |
---|
[1380] | 131 | void middleButton(){ |
---|
[1063] | 132 | unsigned int newFreq; |
---|
[1453] | 133 | |
---|
[1169] | 134 | chan = (chan < 2) ? 1 : chan-1; |
---|
| 135 | newFreq = warpphy_setChannel(GHZ_2, chan); |
---|
[906] | 136 | warpmac_leftHex(chan); |
---|
[1453] | 137 | |
---|
[1169] | 138 | xil_printf("New Frequency %d\r\n", newFreq); |
---|
[906] | 139 | } |
---|
| 140 | |
---|
[1169] | 141 | |
---|
| 142 | ///@brief Callback for the reception of UART bytes |
---|
| 143 | ///@param uartByte ASCII byte received from UART |
---|
| 144 | /// |
---|
| 145 | ///Provides the user with the bytes that was received over the serial port. This is useful for configuring |
---|
| 146 | ///PHY and MAC parameters in real time on a board. |
---|
[1063] | 147 | void uartRecv_callback(unsigned char uartByte) |
---|
| 148 | { |
---|
| 149 | if(uartByte != 0x0) |
---|
| 150 | { |
---|
| 151 | xil_printf("(%c)\t", uartByte); |
---|
[1453] | 152 | |
---|
[1063] | 153 | switch(uartByte) |
---|
| 154 | { |
---|
| 155 | case ASCII_1: |
---|
[1110] | 156 | pktFullRate = HDR_FULLRATE_BPSK; |
---|
[1063] | 157 | xil_printf("Tx Full Rate = BPSK\r\n"); |
---|
[1169] | 158 | break; |
---|
[1453] | 159 | |
---|
[1063] | 160 | case ASCII_2: |
---|
[1110] | 161 | pktFullRate = HDR_FULLRATE_QPSK; |
---|
[1063] | 162 | xil_printf("Tx Full Rate = QPSK\r\n"); |
---|
[1169] | 163 | break; |
---|
[1453] | 164 | |
---|
[1063] | 165 | case ASCII_4: |
---|
[1110] | 166 | pktFullRate = HDR_FULLRATE_QAM_16; |
---|
[1063] | 167 | xil_printf("Tx Full Rate = 16-QAM\r\n"); |
---|
[1169] | 168 | break; |
---|
[1453] | 169 | |
---|
[1063] | 170 | case ASCII_6: |
---|
[1110] | 171 | pktFullRate = HDR_FULLRATE_QAM_64; |
---|
[1063] | 172 | xil_printf("Tx Full Rate = 64-QAM\r\n"); |
---|
[1164] | 173 | break; |
---|
[1617] | 174 | |
---|
| 175 | case ASCII_7: |
---|
| 176 | pktCodeRate = HDR_CODE_RATE_12; |
---|
| 177 | xil_printf("Coding Rate = 1/2\r\n"); |
---|
| 178 | break; |
---|
| 179 | case ASCII_8: |
---|
| 180 | pktCodeRate = HDR_CODE_RATE_23; |
---|
| 181 | xil_printf("Coding Rate = 2/3\r\n"); |
---|
| 182 | break; |
---|
| 183 | case ASCII_9: |
---|
| 184 | pktCodeRate = HDR_CODE_RATE_34; |
---|
| 185 | xil_printf("Coding Rate = 3/4\r\n"); |
---|
| 186 | break; |
---|
| 187 | case ASCII_0: |
---|
| 188 | pktCodeRate = HDR_CODE_RATE_NONE; |
---|
| 189 | xil_printf("Coding Rate = 1 (no coding)\r\n"); |
---|
| 190 | break; |
---|
[1171] | 191 | case ASCII_F: |
---|
| 192 | if(chan<14) chan++; |
---|
| 193 | warpphy_setChannel(GHZ_2, chan); |
---|
| 194 | xil_printf("Current channel: %d\r\n",chan); |
---|
| 195 | break; |
---|
| 196 | case ASCII_f: |
---|
| 197 | if(chan>1) chan--; |
---|
| 198 | warpphy_setChannel(GHZ_2, chan); |
---|
| 199 | xil_printf("Current channel: %d\r\n",chan); |
---|
| 200 | break; |
---|
[1639] | 201 | |
---|
[1171] | 202 | case ASCII_C: |
---|
[1639] | 203 | pktDet_AC_corr = (pktDet_AC_corr < 250) ? (pktDet_AC_corr+5) : 255; |
---|
| 204 | xil_printf("AutoCorr_corr: %d\tAutoCorr_energy: %d\r\n", pktDet_AC_corr, pktDet_AC_energy); |
---|
| 205 | warpphy_setAutoCorrDetParams(pktDet_AC_corr, pktDet_AC_energy); |
---|
[1171] | 206 | break; |
---|
| 207 | case ASCII_c: |
---|
[1639] | 208 | pktDet_AC_corr = (pktDet_AC_corr > 4) ? (pktDet_AC_corr-5) : 0; |
---|
| 209 | xil_printf("AutoCorr_corr: %d\tAutoCorr_energy: %d\r\n", pktDet_AC_corr, pktDet_AC_energy); |
---|
| 210 | warpphy_setAutoCorrDetParams(pktDet_AC_corr, pktDet_AC_energy); |
---|
[1171] | 211 | break; |
---|
[1639] | 212 | |
---|
| 213 | case ASCII_E: |
---|
| 214 | pktDet_AC_energy = (pktDet_AC_energy<2047) ? (pktDet_AC_energy+1) : 2047; |
---|
| 215 | xil_printf("AutoCorr_corr: %d\tAutoCorr_energy: %d\r\n", pktDet_AC_corr, pktDet_AC_energy); |
---|
| 216 | warpphy_setAutoCorrDetParams(pktDet_AC_corr, pktDet_AC_energy); |
---|
[1171] | 217 | break; |
---|
[1639] | 218 | case ASCII_e: |
---|
| 219 | pktDet_AC_energy = (pktDet_AC_energy>0) ? (pktDet_AC_energy-1) : 0; |
---|
| 220 | xil_printf("AutoCorr_corr: %d\tAutoCorr_energy: %d\r\n", pktDet_AC_corr, pktDet_AC_energy); |
---|
| 221 | warpphy_setAutoCorrDetParams(pktDet_AC_corr, pktDet_AC_energy); |
---|
[1171] | 222 | break; |
---|
[1639] | 223 | |
---|
| 224 | case ASCII_R: |
---|
| 225 | pktDet_RSSI_thresh += 100; |
---|
| 226 | xil_printf("RSSI_thresh: %d\r\n", pktDet_RSSI_thresh); |
---|
| 227 | warpphy_setEnergyDetThresh(pktDet_RSSI_thresh); |
---|
[1396] | 228 | break; |
---|
| 229 | |
---|
[1639] | 230 | case ASCII_r: |
---|
| 231 | pktDet_RSSI_thresh -= 100; |
---|
| 232 | xil_printf("RSSI_thresh: %d\r\n", pktDet_RSSI_thresh); |
---|
| 233 | warpphy_setEnergyDetThresh(pktDet_RSSI_thresh); |
---|
[1396] | 234 | break; |
---|
[1639] | 235 | case ASCII_A: |
---|
[1712] | 236 | xil_printf("Debug good header print ON\r\n"); |
---|
[1639] | 237 | debug_goodHdrPrint = 1; |
---|
[1396] | 238 | break; |
---|
[1639] | 239 | case ASCII_a: |
---|
[1712] | 240 | xil_printf("Debug good header print OFF\r\n"); |
---|
[1639] | 241 | debug_goodHdrPrint = 0; |
---|
[1396] | 242 | break; |
---|
[1639] | 243 | |
---|
[1063] | 244 | default: |
---|
| 245 | xil_printf("Undefined command\r\n"); |
---|
[1169] | 246 | break; |
---|
[1063] | 247 | } |
---|
| 248 | } |
---|
[1453] | 249 | |
---|
[1063] | 250 | return; |
---|
| 251 | } |
---|
[679] | 252 | ///@brief Callback for the expiration of timers |
---|
| 253 | /// |
---|
[1648] | 254 | ///This function is responsible for handling TIMEOUT_TIMER and BACKOFF_TIMER. |
---|
[679] | 255 | ///The job responsibilities of this function are to: |
---|
[1648] | 256 | ///-increase the contention window upon the expiration of a TIMEOUT_TIMER |
---|
| 257 | ///-initiate a BACKOFF_TIMER timer upon the expiration of a TIMEOUT_TIMER |
---|
| 258 | ///-retransmit a packet upon the expiration of a BACKOFF_TIMER |
---|
| 259 | ///@param timerType TIMEOUT_TIMER or BACKOFF_TIMER |
---|
[1579] | 260 | void timer_callback(unsigned char timerType) { |
---|
| 261 | |
---|
| 262 | switch(timerType) { |
---|
[1178] | 263 | case TIMEOUT_TIMER: |
---|
| 264 | warpmac_setTimer(BACKOFF_TIMER); |
---|
[1169] | 265 | break; |
---|
[1579] | 266 | |
---|
[1178] | 267 | case BACKOFF_TIMER: |
---|
[1634] | 268 | if(txMacframe.header.remainingTx) { |
---|
[1579] | 269 | //Copy the header over to the Tx packet buffer |
---|
[1380] | 270 | warpmac_prepPhyForXmit(&txMacframe, pktBuf_tx_DATA); |
---|
| 271 | |
---|
[1579] | 272 | //Send from the Tx packet buffer |
---|
[1223] | 273 | warpmac_startPhyXmit(pktBuf_tx_DATA); |
---|
[1816] | 274 | warpmac_leftHex(0xF & (txMacframe.header.remainingTx)); |
---|
[1380] | 275 | //Wait for it to finish |
---|
[1174] | 276 | warpmac_finishPhyXmit(); |
---|
[1380] | 277 | |
---|
[1174] | 278 | //Start a timeout timer |
---|
[1178] | 279 | warpmac_setTimer(TIMEOUT_TIMER); |
---|
[1380] | 280 | warpmac_decrementRemainingReSend(&txMacframe); |
---|
[1174] | 281 | } |
---|
[1579] | 282 | else { |
---|
| 283 | //Either the packet has been sent the max number of times, or |
---|
| 284 | // we just got an ACK and need to backoff before starting with a new packet |
---|
| 285 | warpmac_enableDataFromNetwork(); |
---|
| 286 | } |
---|
| 287 | break; //END BACKOFF_TIMER |
---|
[594] | 288 | } |
---|
| 289 | } |
---|
| 290 | |
---|
[795] | 291 | |
---|
[679] | 292 | ///@brief Callback for the reception of Ethernet packets |
---|
| 293 | /// |
---|
| 294 | ///This function is called by the ethernet MAC drivers |
---|
| 295 | ///when a packet is available to send. This function fills |
---|
| 296 | ///the Macframe transmit buffer with the packet and sends |
---|
| 297 | ///it over the OFDM link |
---|
[1647] | 298 | ///@param length Length, in bytes, of received payload (Ethernet or dummy payload length) |
---|
| 299 | ///@param payload Pointer to first byte of received payload (first byte of Ethernet or dummy payload) |
---|
[1215] | 300 | void dataFromNetworkLayer_callback(Xuint32 length, char* payload){ |
---|
[1110] | 301 | unsigned char destNode; |
---|
[1453] | 302 | |
---|
[1579] | 303 | //Reset the contention window to its minimum |
---|
| 304 | warpmac_resetCurrentCW(); |
---|
[1453] | 305 | |
---|
[1579] | 306 | //Disable further Ethernet packets (will be re-enabled after this packet is ACK'd or dropped) |
---|
[1215] | 307 | warpmac_disableDataFromNetwork(); |
---|
[1579] | 308 | |
---|
| 309 | //Update the Tx packet header with this packet's values |
---|
[1380] | 310 | txMacframe.header.length = length; |
---|
[1579] | 311 | txMacframe.header.pktType = PKTTYPE_DATA; |
---|
[1453] | 312 | |
---|
[736] | 313 | //Set the modulation scheme for the packet's full-rate symbols |
---|
[1380] | 314 | txMacframe.header.fullRate = pktFullRate; |
---|
[1453] | 315 | |
---|
[1110] | 316 | //Set the code rate for the packet's payload |
---|
[1380] | 317 | txMacframe.header.codeRate = pktCodeRate; |
---|
[1453] | 318 | |
---|
[1110] | 319 | //For now, assume our destination is our opposite ID (all traffic is 0 <-> 1) |
---|
| 320 | destNode = (myID+1)%2; |
---|
[1453] | 321 | |
---|
[1579] | 322 | //Copy in the packet's destination MAC address |
---|
| 323 | txMacframe.header.destAddr = (unsigned short int)(NODEID_TO_ADDR(destNode)); |
---|
| 324 | |
---|
[1110] | 325 | //Use the next sequence number for this node (top four bits) and resend count of 0 (bottom four bits) |
---|
[1325] | 326 | txSequences[destNode] = (txSequences[destNode] + 1) % 256; |
---|
[1380] | 327 | txMacframe.header.seqNum = txSequences[destNode]; |
---|
[1453] | 328 | |
---|
[1579] | 329 | //Set the remaining Tx counter to the maximum numeber of transmissions |
---|
[1634] | 330 | txMacframe.header.remainingTx = (maximumReSend+1); |
---|
[1453] | 331 | |
---|
[1579] | 332 | if(warpmac_carrierSense()) { |
---|
[1281] | 333 | //If the modium is idle: |
---|
| 334 | |
---|
[1579] | 335 | //Copy the header to the Tx packet buffer |
---|
[1380] | 336 | warpmac_prepPhyForXmit(&txMacframe, pktBuf_tx_DATA); |
---|
[1281] | 337 | |
---|
| 338 | //Transmit the packet |
---|
[1223] | 339 | warpmac_startPhyXmit(pktBuf_tx_DATA); |
---|
[1816] | 340 | warpmac_leftHex(0xF & (txMacframe.header.remainingTx)); |
---|
[1490] | 341 | |
---|
[1281] | 342 | //Wait for it to finish |
---|
[941] | 343 | warpmac_finishPhyXmit(); |
---|
[1281] | 344 | |
---|
[941] | 345 | //Start a timeout timer |
---|
[1178] | 346 | warpmac_setTimer(TIMEOUT_TIMER); |
---|
[1380] | 347 | warpmac_decrementRemainingReSend(&txMacframe); |
---|
[594] | 348 | } |
---|
[1579] | 349 | else { |
---|
[1281] | 350 | //Medium was busy; start a backoff timer |
---|
[1178] | 351 | warpmac_setTimer(BACKOFF_TIMER); |
---|
[594] | 352 | } |
---|
[1453] | 353 | |
---|
[1082] | 354 | return; |
---|
[594] | 355 | } |
---|
| 356 | |
---|
[941] | 357 | ///@brief Callback for the reception of bad wireless headers |
---|
[954] | 358 | void phyRx_badHeader_callback() { |
---|
[1579] | 359 | |
---|
| 360 | //Don't do anything with the packet (it had errors, and can't be trusted) |
---|
| 361 | |
---|
| 362 | //Increment the bottom LEDs |
---|
[594] | 363 | warpmac_incrementLEDLow(); |
---|
[1453] | 364 | |
---|
[1063] | 365 | return; |
---|
[594] | 366 | } |
---|
| 367 | |
---|
[855] | 368 | ///@brief Callback for the reception of good wireless headers |
---|
[679] | 369 | /// |
---|
[946] | 370 | ///This function then polls the PHY to determine if the entire packet passes checksum |
---|
| 371 | ///thereby triggering the transmission of the ACK and the transmission of the received |
---|
| 372 | ///data over Ethernet. |
---|
[679] | 373 | ///@param packet Pointer to received Macframe |
---|
[1579] | 374 | int phyRx_goodHeader_callback(Macframe* packet){ |
---|
[1453] | 375 | |
---|
[1281] | 376 | unsigned char state = PHYRXSTATUS_INCOMPLETE; |
---|
[1110] | 377 | unsigned char srcNode; |
---|
| 378 | unsigned char shouldSend = 0; |
---|
[1453] | 379 | |
---|
[1639] | 380 | if(debug_goodHdrPrint) { |
---|
| 381 | xil_printf("GH: RSSI=%4d\tAGC=%d/%2d\r\n", |
---|
| 382 | ofdm_txrx_mimo_ReadReg_Rx_PktDet_midPktRSSI_antA(), |
---|
| 383 | OFDM_AGC_MIMO_ReadReg_GRF_A(0), |
---|
| 384 | OFDM_AGC_MIMO_ReadReg_GBB_A(0)); |
---|
| 385 | } |
---|
| 386 | |
---|
[1325] | 387 | //Calculate the node ID from the packet's source MAC address |
---|
[1281] | 388 | srcNode = ADDR_TO_NODEID( (packet->header.srcAddr) ); |
---|
[1453] | 389 | |
---|
[984] | 390 | //If the packet is addressed to this node |
---|
[1579] | 391 | if( packet->header.destAddr == (NODEID_TO_ADDR(myID)) ) { |
---|
[1453] | 392 | |
---|
[1579] | 393 | switch(packet->header.pktType) { |
---|
[1281] | 394 | //If received packet is data |
---|
[1579] | 395 | case PKTTYPE_DATA: |
---|
[984] | 396 | //At this point, we have pre-loaded the PHY transmitter with the ACK in hoping that |
---|
| 397 | //the packet passes checksum. Now we wait for the state of the received to packet |
---|
[1281] | 398 | //to move from PHYRXSTATUS_INCOMPLETE to either PHYRXSTATUS_GOOD or PHYRXSTATUS_BAD |
---|
[1215] | 399 | |
---|
[1579] | 400 | //Poll the PHY until the payload is declared good or bad |
---|
[1215] | 401 | state = warpmac_finishPhyRecv(); |
---|
[1453] | 402 | |
---|
[1281] | 403 | if(state & PHYRXSTATUS_GOOD){ |
---|
[1235] | 404 | //The auto-reponder will send the pre-programmed ACK automatically |
---|
[1579] | 405 | //User code only needs to update its stats, then check to see the PHY is finished transmitting |
---|
[1235] | 406 | |
---|
| 407 | //Toggle the top LEDs |
---|
[1220] | 408 | warpmac_incrementLEDHigh(); |
---|
[1453] | 409 | |
---|
[1281] | 410 | //Update the right-hex display with the current sequence number |
---|
[1816] | 411 | //warpmac_leftHex(0xF & (packet->header.seqNum)); |
---|
[1453] | 412 | |
---|
[1110] | 413 | //Check if the last received seq number for this partner node matches this received pkt |
---|
| 414 | // If not, record the new number and allow the pkt to be forwarded over the wire |
---|
[1579] | 415 | if(rxSequences[srcNode] != (packet->header.seqNum)) |
---|
[1281] | 416 | { |
---|
| 417 | //Not a duplicate packet; update this partner's last-known sequence number |
---|
[1235] | 418 | rxSequences[srcNode] = (packet->header.seqNum); |
---|
| 419 | shouldSend = 1; |
---|
[1453] | 420 | } |
---|
| 421 | |
---|
[941] | 422 | //Starts the DMA transfer of the payload into the EMAC |
---|
[1380] | 423 | if(shouldSend) warpmac_prepPktToNetwork((void *)warpphy_getBuffAddr(pktBuf_rx)+NUM_HEADER_BYTES, (packet->header.length)); |
---|
[1453] | 424 | |
---|
[941] | 425 | //Blocks until the PHY is finished sending and enables the receiver |
---|
| 426 | warpmac_finishPhyXmit(); |
---|
[1453] | 427 | |
---|
[941] | 428 | //Waits until the DMA transfer is complete, then starts the EMAC |
---|
[1380] | 429 | if(shouldSend) warpmac_startPktToNetwork((packet->header.length)); |
---|
[941] | 430 | } |
---|
[1453] | 431 | |
---|
[1579] | 432 | if(state & PHYRXSTATUS_BAD) { |
---|
[941] | 433 | warpmac_incrementLEDLow(); |
---|
| 434 | } |
---|
[1453] | 435 | |
---|
[1579] | 436 | break; //END PKTTYPE_DATA |
---|
[1453] | 437 | |
---|
[1579] | 438 | case PKTTYPE_ACK: |
---|
[984] | 439 | //Clear the TIMEOUT and enable Ethernet |
---|
[1579] | 440 | if(warpmac_inTimeout()) { |
---|
[1220] | 441 | warpmac_incrementLEDHigh(); |
---|
[1223] | 442 | |
---|
[1281] | 443 | //Clear the timeout timer, set when we transmitted the data packet |
---|
[1178] | 444 | warpmac_clearTimer(TIMEOUT_TIMER); |
---|
[1281] | 445 | |
---|
| 446 | //Clear the remaining transmit count to assure this packet won't be re-transmitted |
---|
[1634] | 447 | txMacframe.header.remainingTx = 0; |
---|
[1453] | 448 | |
---|
[1281] | 449 | //Start a backoff, to gaurantee a random time before attempting to transmit again |
---|
[1399] | 450 | warpmac_setTimer(BACKOFF_TIMER); |
---|
[1396] | 451 | |
---|
| 452 | //Re-enable EMAC polling immediately (for testing; using the post-ACK backoff is better for real use) |
---|
[1579] | 453 | //warpmac_enableDataFromNetwork(); |
---|
[594] | 454 | } |
---|
[1579] | 455 | else { |
---|
| 456 | //Got an unexpected ACK; ignore it |
---|
| 457 | } |
---|
[1453] | 458 | |
---|
[1579] | 459 | break; //END PKTTYPE_ACK |
---|
[594] | 460 | } |
---|
| 461 | } |
---|
[1636] | 462 | else { |
---|
| 463 | state = warpmac_finishPhyRecv(); |
---|
| 464 | } |
---|
[1579] | 465 | //Return 0, indicating we didn't clear the PHY status bits (WARPMAC will handle it) |
---|
| 466 | return 0; |
---|
[594] | 467 | } |
---|
| 468 | |
---|
[679] | 469 | ///@brief Main function |
---|
| 470 | /// |
---|
| 471 | ///This function configures MAC parameters, enables the underlying frameworks, and then loops forever. |
---|
[1453] | 472 | int main(){ |
---|
[1890] | 473 | print("\fReference Design v18 CSMAMAC\r\n"); |
---|
[1453] | 474 | |
---|
[1063] | 475 | //Initialize global variables |
---|
[1816] | 476 | chan = 11; |
---|
[1453] | 477 | |
---|
[1235] | 478 | //Assign the packet buffers in the PHY |
---|
| 479 | // The auto responder can't transmit from buffer 0, so we use it for Rx packets |
---|
| 480 | // The other assignments (DATA/ACK) are arbitrary; any buffer in [1,30] will work |
---|
[1579] | 481 | pktBuf_rx = 1; |
---|
| 482 | pktBuf_tx_DATA = 2; |
---|
| 483 | pktBuf_tx_ACK = 3; |
---|
[1235] | 484 | |
---|
[1063] | 485 | //Set the full-rate modulation to QPSK by default |
---|
[1816] | 486 | // pktFullRate = HDR_FULLRATE_QAM_16; |
---|
| 487 | pktFullRate = HDR_FULLRATE_QPSK; |
---|
[1453] | 488 | |
---|
[1617] | 489 | //Set the payload coding rate to 3/4 rate by default |
---|
| 490 | pktCodeRate = HDR_CODE_RATE_34; |
---|
[1453] | 491 | |
---|
[1281] | 492 | //Initialize the MAC/PHY frameworks |
---|
[941] | 493 | warpmac_init(); |
---|
[1174] | 494 | maximumReSend = 8; |
---|
| 495 | warpmac_setMaxResend(maximumReSend); |
---|
[941] | 496 | warpmac_setMaxCW(5); |
---|
[1617] | 497 | warpmac_setTimeout(120); |
---|
[1281] | 498 | warpmac_setSlotTime(22); |
---|
[1215] | 499 | |
---|
[1281] | 500 | //Read Dip Switch value from FPGA board. |
---|
| 501 | //This value will be used as an index into the routing table for other nodes |
---|
| 502 | myID = (unsigned short int)warpmac_getMyId(); |
---|
[1380] | 503 | warpmac_rightHex(myID); |
---|
[1453] | 504 | |
---|
[1235] | 505 | //Configure the PHY and radios for single antenna (SISO) mode |
---|
[1579] | 506 | warpphy_setAntennaMode(TX_ANTMODE_SISO_ANTA, RX_ANTMODE_SISO_ANTA); |
---|
[1634] | 507 | //warpphy_setAntennaMode(TX_ANTMODE_MULTPLX, RX_ANTMODE_MULTPLX); |
---|
[1579] | 508 | //warpphy_setAntennaMode(TX_ANTMODE_ALAMOUTI_ANTA, RX_ANTMODE_ALAMOUTI_ANTA); |
---|
[1453] | 509 | |
---|
[1816] | 510 | #ifdef WARP_HW_VER_v3 |
---|
| 511 | //Set the OFDM Rx detection thresholds |
---|
| 512 | warpphy_setCarrierSenseThresh(4000); //Carrier sense thresh (in [0,16368]) |
---|
| 513 | warpphy_setEnergyDetThresh(6500); //Min RSSI (in [0,16368]) |
---|
| 514 | warpphy_setAutoCorrDetParams(50, 20); //Min auto-correlation (UFix8_7) and min energy (UFix16_8) |
---|
| 515 | warpphy_setLongCorrThresh(10000); //Min cross-correlation (in [0,45e3]) |
---|
| 516 | |
---|
| 517 | //Set the default Tx gain (in [0,63]) |
---|
| 518 | warpphy_setTxPower(50); |
---|
| 519 | #else |
---|
| 520 | //Set the OFDM Rx detection thresholds (copied from OFDM ref des v17 for now) |
---|
| 521 | warpphy_setCarrierSenseThresh(12000); //Carrier sense thresh (in [0,16368]) |
---|
| 522 | warpphy_setEnergyDetThresh(7000); //Min RSSI (in [0,16368]) |
---|
| 523 | warpphy_setAutoCorrDetParams(90, 20); //Min auto-correlation (UFix8_7) and min energy (UFix16_8) |
---|
[1636] | 524 | warpphy_setLongCorrThresh(8000); //Min cross-correlation (in [0,45e3]) |
---|
[1816] | 525 | |
---|
| 526 | //Set the default Tx gain (in [0,63]) |
---|
| 527 | warpphy_setTxPower(55); |
---|
| 528 | #endif |
---|
| 529 | |
---|
| 530 | //Set the default center frequency |
---|
| 531 | warpphy_setChannel(GHZ_2, 11); |
---|
[1617] | 532 | |
---|
[1816] | 533 | |
---|
[986] | 534 | //Rx buffer is where the EMAC will DMA Wireless payloads from |
---|
[1380] | 535 | warpmac_setRxBuffers(&rxMacframe, pktBuf_rx); |
---|
| 536 | |
---|
[986] | 537 | //Tx buffer is where the EMAC will DMA Ethernet payloads to |
---|
[1380] | 538 | warpmac_setPHYTxBuffer(pktBuf_tx_DATA); |
---|
[1579] | 539 | warpmac_setEMACRxBuffer(pktBuf_tx_DATA); |
---|
[1453] | 540 | |
---|
[1281] | 541 | //Set the modulation scheme use for base rate (header) symbols |
---|
| 542 | warpmac_setBaseRate(QPSK); |
---|
| 543 | |
---|
[814] | 544 | //Copy this node's MAC address into the Tx buffer's source address field |
---|
[1380] | 545 | txMacframe.header.srcAddr = (unsigned short int)(NODEID_TO_ADDR(myID)); |
---|
[1453] | 546 | |
---|
[986] | 547 | //Register callbacks |
---|
[1380] | 548 | warpmac_setCallback(EVENT_UPBUTTON, (void *)upButton); |
---|
| 549 | warpmac_setCallback(EVENT_LEFTBUTTON, (void *)leftButton); |
---|
| 550 | warpmac_setCallback(EVENT_RIGHTBUTTON, (void *)rightButton); |
---|
| 551 | warpmac_setCallback(EVENT_MIDDLEBUTTON, (void *)middleButton); |
---|
| 552 | warpmac_setCallback(EVENT_TIMER, (void *)timer_callback); |
---|
| 553 | warpmac_setCallback(EVENT_DATAFROMNETWORK, (void *)dataFromNetworkLayer_callback); |
---|
| 554 | warpmac_setCallback(EVENT_PHYGOODHEADER, (void *)phyRx_goodHeader_callback); |
---|
| 555 | warpmac_setCallback(EVENT_PHYBADHEADER, (void *)phyRx_badHeader_callback); |
---|
| 556 | warpmac_setCallback(EVENT_UARTRX, (void *)uartRecv_callback); |
---|
[1215] | 557 | |
---|
[814] | 558 | //Set the default center frequency |
---|
[941] | 559 | warpphy_setChannel(GHZ_2, chan); |
---|
[1453] | 560 | |
---|
[986] | 561 | //Enable carrier sensing |
---|
[1380] | 562 | warpmac_setCSMA(1); |
---|
[1453] | 563 | |
---|
[1223] | 564 | /******** START autoResponse setup *******/ |
---|
| 565 | //Setup the PHY's autoResponse system |
---|
[1281] | 566 | // For CSMA, it is configured to send pktBuf pktBuf_tx_ACK when a good DATA packet is received addressed to this node |
---|
[1453] | 567 | |
---|
[1281] | 568 | //Match condition 0: received header's destination address is this node's address |
---|
| 569 | autoResp_matchCond = PHY_AUTORESPONSE_MATCH_CONFIG(PKTHEADER_INDX_DSTADDR, 2, htons(NODEID_TO_ADDR(myID))); |
---|
[1223] | 570 | mimo_ofdmTxRx_setMatch0(autoResp_matchCond); |
---|
| 571 | |
---|
[1453] | 572 | //Match condition 1: received header's type is DATA |
---|
[1579] | 573 | autoResp_matchCond = PHY_AUTORESPONSE_MATCH_CONFIG(PKTHEADER_INDX_TYPE, 1, PKTTYPE_DATA); |
---|
[1223] | 574 | mimo_ofdmTxRx_setMatch1(autoResp_matchCond); |
---|
[1453] | 575 | |
---|
[1223] | 576 | //Configure the header translator to use the Rx pkt's src address as the outgoing pkt's dst address |
---|
| 577 | // Addresses are two bytes, so two entries in the header translator need to be overridden |
---|
| 578 | // Except for these bytes, the ACK pktBuf's contents will be sent unaltered |
---|
| 579 | // PHY_HEADERTRANSLATE_SET(templatePktBuf, byteAddrToOverwrite, srcPktBuf, srcByteAddr) |
---|
| 580 | PHY_HEADERTRANSLATE_SET(pktBuf_tx_ACK, (PKTHEADER_INDX_DSTADDR+0), pktBuf_rx, (PKTHEADER_INDX_SRCADDR+0)); |
---|
| 581 | PHY_HEADERTRANSLATE_SET(pktBuf_tx_ACK, (PKTHEADER_INDX_DSTADDR+1), pktBuf_rx, (PKTHEADER_INDX_SRCADDR+1)); |
---|
[1220] | 582 | |
---|
[1223] | 583 | //Create a template ACK packet |
---|
| 584 | templatePkt.header.fullRate = pktFullRate; |
---|
| 585 | templatePkt.header.codeRate = pktCodeRate; |
---|
| 586 | templatePkt.header.length = 0; |
---|
[1281] | 587 | templatePkt.header.srcAddr = (unsigned short)(NODEID_TO_ADDR(myID)); |
---|
[1579] | 588 | templatePkt.header.pktType = PKTTYPE_ACK; |
---|
[1453] | 589 | |
---|
[1223] | 590 | //Copy the header down to the PHY's packet buffer |
---|
| 591 | // This doesn't actually send anything; the autoResponse system will use this template when sending ACKs |
---|
| 592 | warpmac_prepPhyForXmit(&templatePkt, pktBuf_tx_ACK); |
---|
| 593 | |
---|
[1281] | 594 | //Action defitions come last; bad things might happen if an action is enabled (set non-zero) before the template pkt is ready. |
---|
| 595 | //All actors are disabled during warpphy_init; only load non-zero configurations for actors you intend to use |
---|
[1223] | 596 | |
---|
[1235] | 597 | //Action 0: send pkt from buf pktBuf_tx_ACK when match0 & match1 & goodPkt, using header translation |
---|
[1281] | 598 | autoResp_action = PHY_AUTORESPONSE_TXACTION_CONFIG(pktBuf_tx_ACK, PHY_AUTORESPONSE_ACT_TRANS_HDR, 0, (PHY_AUTORESPONSE_REQ_MATCH0 | PHY_AUTORESPONSE_REQ_MATCH1 | PHY_AUTORESPONSE_REQ_GOODHDR | PHY_AUTORESPONSE_REQ_GOODPKT)); |
---|
[1223] | 599 | mimo_ofdmTxRx_setAction0(autoResp_action); |
---|
| 600 | /******* END autoResponse setup ******/ |
---|
[1453] | 601 | |
---|
[1223] | 602 | //Listen for new packets to send (either from Ethernet or local dummy packets) |
---|
| 603 | warpmac_enableDataFromNetwork(); |
---|
[1453] | 604 | |
---|
[1171] | 605 | xil_printf("Beginning main loop\r\n"); |
---|
[1453] | 606 | |
---|
[1639] | 607 | |
---|
| 608 | /******* DEBUG STUFF *******/ |
---|
| 609 | debug_goodHdrPrint = 0; |
---|
| 610 | |
---|
[1281] | 611 | while(1) |
---|
| 612 | { |
---|
| 613 | //Poll the timer, PHY and user I/O forever; actual processing will happen via callbacks above |
---|
[1164] | 614 | warpmac_pollPeripherals(); |
---|
[731] | 615 | } |
---|
[1453] | 616 | |
---|
[1712] | 617 | return 0; |
---|
[594] | 618 | } |
---|