source: PlatformSupport/WARPMAC/warpmac.c

Last change on this file was 1713, checked in by murphpo, 12 years ago

Updating code for OFDM ref design v17 in ISE 13.4 tools

File size: 41.6 KB
RevLine 
[1713]1/* Version v17 */
[1598]2
[1203]3#include "warp_fpga_board.h"
[444]4#include "xparameters.h"
[665]5#include "xstatus.h"
6#include "errno.h"
[1164]7#include "xpseudo_asm_gcc.h"
[665]8#include "stddef.h"
[941]9#include "stdio.h"
10#include "string.h"
[1064]11#include "xuartlite.h"
12#include "xuartlite_l.h"
[444]13#include "xgpio.h"
[1712]14#include "stdlib.h"
[665]15#include "warpmac.h"
[603]16#include "radio_controller_basic.h"
17#include "radio_controller_ext.h"
18#include "radio_controller_adv.h"
[665]19#include "warpphy.h"
[1477]20#include "warpnet.h"
[592]21
[1712]22#include "util/ofdm_txrx_mimo_regMacros.h"
23#include "util/ofdm_agc_mimo_regMacros.h"
24#include "util/warp_timer_regMacros.h"
25#include "util/warp_userio.h"
26
[1379]27#include "xlltemac.h"
28#include "xllfifo_hw.h"
[1203]29#include "xdmacentral.h"
30#include "xdmacentral_l.h"
[1369]31
[1632]32#include "xtime_l.h"
33
[1491]34#define WARPMAC_SAFE_GOODHDR 0
35
[1379]36#define TEMAC_DEVICE_ID     XPAR_LLTEMAC_0_DEVICE_ID
37#define FIFO_DEVICE_ID      XPAR_LLFIFO_0_DEVICE_ID
38
39#ifdef WARP_FPGA_BOARD_V1_2
40
41#define ENET_LINK_SPEED     100
42
[1369]43#elif defined WARP_FPGA_BOARD_V2_2
44
45#include "warp_v4_userio.h"
[1203]46
[1712]47#define USERIO_BASEADDR XPAR_USERIO_BASEADDR
[1713]48#define ENET_LINK_SPEED     1000
[1379]49
[1203]50#endif
51
[978]52//Instantiates the Maccontrol control structure
[665]53Maccontrol controlStruct;
[592]54
[1208]55extern unsigned int activeRadios_Tx;
[1176]56
[978]57//Instantiates the general-purpose input-output peripheral driver
[941]58static XGpio GPIO_UserIO;
[489]59
[1064]60//Instantiates the UART driver instance
61static XUartLite UartLite;
62
[941]63static XDmaCentral DmaCentralInst;
64static XDmaCentral_Config *DMAConfigPtr;
[1379]65
[1203]66XLlTemac TemacInstance;
67XLlTemac_Config *MacCfgPtr;
[1379]68u32 EMAC_FIFO_BaseAddr;
[941]69
[978]70//Points to a user-provided Macframe where parsed header information will be copied to
[665]71Macframe* rxPacket;
[617]72
[941]73//Global variable for tracking active LED outputs
[1015]74unsigned int LEDHEX_Outputs;
75unsigned int ledStates;
76unsigned int leftHex;
77unsigned int rightHex;
[941]78
[978]79//"Low" LED states
[1015]80unsigned int ledStatesLow[2];
81unsigned char ledStatesIndexLow;
[978]82//"High" LED states
[1015]83unsigned int ledStatesHigh[2];
84unsigned char ledStatesIndexHigh;
[1169]85//Dip-switch state
[941]86unsigned char dipswState;
[1169]87//Debug GPIO state
[1164]88unsigned char debugGPIO;
89
[1015]90//Global variable to track SISO vs. MIMO mode
[1208]91unsigned char warpmac_TxMultiplexingMode;
[1015]92
[1221]93unsigned char pktGen_allow;
94unsigned int dummyPacketInterval;
95unsigned char startPktGeneration;
[1214]96unsigned int dummyPacketLength;
97
[543]98//These the addresses pointed to by these variables are set by the
99//user via the callback registration functions
[978]100
[444]101void (*usr_upbutton) ();
102void (*usr_leftbutton) ();
103void (*usr_middlebutton) ();
104void (*usr_rightbutton) ();
[941]105void (*usr_badHeaderCallback) ();
[1491]106int (*usr_goodHeaderCallback) ();
[941]107void (*usr_timerCallback) ();
[1214]108void (*usr_dataFromNetworkLayer) ();
[1379]109void (*usr_mgmtPkt) ();
[1064]110void (*usr_uartRecvCallback) ();
[978]111
[1379]112//Null handler, for callbacks the user doesn't re-assign
[941]113void nullCallback(void* param){};
[1712]114int nullCallback_i(void* param){return 0;};
[444]115
[665]116///@brief Initializes the framework and all hardware peripherals.
117///
118///This function sets reasonable default values for many of the parameters of the MAC, configures
[825]119///interrupts and exceptions, configures Ethernet, and finally initializes the custom peripherals
[665]120///such as the radio controller, the PHY, the packet detector, and the automatic gain control block.
[1011]121void warpmac_init() {
[946]122   
[1713]123    xil_printf("Initializing WARPMAC v17.0:\r\n");
[1203]124   
[1379]125    XStatus Status;
126
[1015]127    //Initialize global variables
[1221]128    startPktGeneration = 0;
[1214]129    dummyPacketLength = 1470;
[1164]130    debugGPIO = 0;
[1015]131    LEDHEX_Outputs = 0;
132    ledStates = 0;
133    leftHex = 0;
134    rightHex = 0;
135    ledStatesLow[0] = 1;
136    ledStatesLow[1] = 2;
137    ledStatesIndexLow = 0;
138    ledStatesHigh[0] = 4;
139    ledStatesHigh[1] = 8;
140    ledStatesIndexHigh = 0;
[1208]141    warpmac_TxMultiplexingMode = 0;
[1203]142   
[1379]143    //Assign a null handler to all the callbacks; the user will override these after initialization
[941]144    usr_upbutton = nullCallback;
145    usr_leftbutton = nullCallback;
146    usr_middlebutton = nullCallback;
147    usr_rightbutton = nullCallback;
148    usr_badHeaderCallback = nullCallback;
[1494]149    usr_goodHeaderCallback = nullCallback_i;
[941]150    usr_timerCallback = nullCallback;
[1379]151    usr_dataFromNetworkLayer = nullCallback;
152    usr_mgmtPkt = nullCallback;
[1064]153    usr_uartRecvCallback = nullCallback;
[941]154   
[978]155    //Initialize the PHY
[941]156    warpphy_init();
[1640]157
[978]158    /*********************MAC Parameters*************************/
[1224]159    //Sensible defaults; user can override
[665]160    controlStruct.maxReSend = 4;
[1176]161    controlStruct.currentCW = 0;
162    controlStruct.maxCW = 5;
[1379]163
164    controlStruct.pktBuf_phyRx = 0;
165    controlStruct.pktBuf_emacRx = 1;
[1494]166    controlStruct.dummyPacketMode = 0;
[1379]167   
168    warpphy_setBuffs(controlStruct.pktBuf_emacRx, controlStruct.pktBuf_phyRx);
[978]169    /************************************************************/
[1203]170
[1064]171    /************************UART*****************************/
172    XUartLite_Initialize(&UartLite, XPAR_UARTLITE_0_DEVICE_ID);
173    /************************************************************/
[1379]174
[978]175    /**************************DMA*******************************/
[941]176    //Lookup the DMA configuration information
177    DMAConfigPtr = XDmaCentral_LookupConfig(DMA_CTRL_DEVICE_ID);
178   
179    //Initialize the config struct
180    Status = XDmaCentral_CfgInitialize(&DmaCentralInst, DMAConfigPtr, DMAConfigPtr->BaseAddress);
[978]181    if (Status != XST_SUCCESS){
[1379]182        xil_printf("DMA CfgInitialize failed!\r\n");
[941]183        return;
184    }
185   
186    //Disable Interrupts
187    XDmaCentral_InterruptEnableSet(&DmaCentralInst, 0);
[1379]188    /************************************************************/
[1203]189   
[1379]190    /*******************Ethernet**********************************/
[1640]191    xil_printf("\tInitializing TEMAC...");
[1203]192    MacCfgPtr = XLlTemac_LookupConfig(TEMAC_DEVICE_ID);
193    Status = XLlTemac_CfgInitialize(&TemacInstance, MacCfgPtr, MacCfgPtr->BaseAddress);
194    if (Status != XST_SUCCESS)
195        xil_printf("EMAC init error\r\n");
196   
197    if (!XLlTemac_IsFifo(&TemacInstance))
198        xil_printf("EMAC hw config incorrect\r\n");
199   
[1379]200    EMAC_FIFO_BaseAddr = MacCfgPtr->LLDevBaseAddress;
[1203]201   
[1477]202    Status  = XLlTemac_ClearOptions(&TemacInstance, XTE_LENTYPE_ERR_OPTION | XTE_FLOW_CONTROL_OPTION | XTE_FCS_STRIP_OPTION);// | XTE_MULTICAST_OPTION);
[1203]203    Status |= XLlTemac_SetOptions(&TemacInstance, XTE_PROMISC_OPTION | XTE_MULTICAST_OPTION | XTE_BROADCAST_OPTION | XTE_RECEIVER_ENABLE_OPTION | XTE_TRANSMITTER_ENABLE_OPTION); //| XTE_JUMBO_OPTION
204    if (Status != XST_SUCCESS)
205        xil_printf("Error setting EMAC options\r\n, code %d", Status);
206   
[1379]207    // Make sure the TEMAC is ready
[1203]208    Status = XLlTemac_ReadReg(TemacInstance.Config.BaseAddress, XTE_RDY_OFFSET);
209    while ((Status & XTE_RDY_HARD_ACS_RDY_MASK) == 0)
210    {
211        Status = XLlTemac_ReadReg(TemacInstance.Config.BaseAddress, XTE_RDY_OFFSET);
212    }
213   
214    XLlTemac_SetOperatingSpeed(&TemacInstance, ENET_LINK_SPEED);
215    usleep(1 * 10000);
216   
217    XLlTemac_Start(&TemacInstance);
[1713]218    xil_printf("complete! - Link Speed %d\r\n", ENET_LINK_SPEED);
[1379]219    /************************************************************/
[1203]220
[1379]221#ifdef WARP_FPGA_BOARD_V1_2
222    /************************USER IO*****************************/
223    //Initialize the UserIO GPIO core
224    Status = XGpio_Initialize(&GPIO_UserIO, XPAR_USER_IO_DEVICE_ID);
225   
226    //We use both channels in the GPIO core- one for inputs, one for outputs
227    XGpio_SetDataDirection(&GPIO_UserIO, USERIO_CHAN_INPUTS, USERIO_MASK_INPUTS);
228    XGpio_SetDataDirection(&GPIO_UserIO, USERIO_CHAN_OUTPUTS, 0);
229   
230    //Make sure the LEDs are all off by default
231    XGpio_DiscreteClear(&GPIO_UserIO, USERIO_CHAN_OUTPUTS, USERIO_MASK_OUTPUTS);
232    /************************************************************/
233   
234#elif defined WARP_FPGA_BOARD_V2_2
235    /************************USER IO*****************************/
236    WarpV4_UserIO_NumberMode_LeftHex(USERIO_BASEADDR);
237    WarpV4_UserIO_NumberMode_MiddleHex(USERIO_BASEADDR);
238    WarpV4_UserIO_NumberMode_RightHex(USERIO_BASEADDR);
239    /************************************************************/
[1203]240#endif
[1369]241
[978]242    /************************************************************/
[941]243   
[1110]244    //Set the default Tx power to maximum
[1169]245    warpphy_setTxPower(0x3F);
[1203]246   
[941]247    //Manually call the UserIO ISR once to store the initial value of the buttons/switches
[978]248    //This is especially important for applications where the value of the DIP switch means something at boot
[1169]249    userIO_handler((void *)&GPIO_UserIO);
[1064]250   
[1182]251    //Set the backoff timer to pause during medium-busy events
252    // The user can either disable this with a similar call (using mode=TIMER_MODE_NOCARRIERSENSE)
253    // or set the carrier sense threshold so high it that it will never see "busy"
254    warp_timer_setMode(BACKOFF_TIMER, TIMER_MODE_CARRIERSENSE); 
[1203]255   
[1633]256    //In this design, we dedicate 1 of the 8 timers int the warp_timer core to polling user IO
257    //like the uart and push buttons. The rate of this poll is controlled by USERIO_POLLRATE.
[1177]258    warp_timer_setTimer(USERIO_TIMER, 0, USERIO_POLLRATE); 
259    warp_timer_setMode(USERIO_TIMER, TIMER_MODE_NOCARRIERSENSE);
260    warp_timer_start(USERIO_TIMER);
[1203]261   
262    return;
[444]263}
264
[1379]265///@brief Top-level polling function
[825]266///
[1379]267///This function polls each peripheral in the design (PHY, timer and Ethernet)
268///User applications should call this function frequently
269inline void warpmac_pollPeripherals() {
270    //This function polls the three main peripherals: the PHY, timer and EMAC
271    warpmac_pollPhy();
272    warpmac_pollTimer();
273    warpmac_pollDataSource();
[1169]274   
[728]275    return;
276}
[825]277
[1379]278///@brief Polls the OFDM PHY
[665]279///
[1379]280///Function checks the status of the PHY receiver
[1712]281//inline void warpmac_pollPhy() {
282void warpmac_pollPhy() {
283
284    //FIXME: CSMAMAC and this function race somehow; reproducible when nomac is Tx, csmamac is Rx
285    unsigned int status;
[941]286   
[1712]287    status = mimo_ofdmRx_getPktStatus();
288//  xil_printf("pollPhy status: 0x%x\r\n", status);
[1203]289   
[1712]290    if(status & (PHYRXSTATUS_HEADER & PHYRXSTATUS_GOOD))
291    {
292        phyRx_goodHeader_handler();
293        return;
294    }
295
296    if(status & PHYRXSTATUS_BAD)
297    {
298        phyRx_badHeader_handler();
299        return;
300    }
301
302    if(status > 0)
303    {
304        xil_printf("pollPHY: shouldn't happen!\r\n");
305        return;
306    }
307
308    return;
309/*
[1379]310    if(status & PHYRXSTATUS_HEADER & PHYRXSTATUS_GOOD) phyRx_goodHeader_handler();
311    else if(status & PHYRXSTATUS_BAD) phyRx_badHeader_handler(); //Either bad header or bad payload
312    else if(status & PHYRXSTATUS_PAYLOAD & PHYRXSTATUS_GOOD)
[1110]313    {
[1379]314        //This should never happen (good payload with no good header); reset if it does
315        warpphy_clearRxPktStatus();
316        xil_printf("warpmac_pollPhy Error: good pkt but no good hdr!\r\n");
[972]317    }
[1282]318    return;
[1712]319*/
[665]320}
[617]321
[1169]322///@brief  Handler for the timer peripheral.
[665]323///
[1169]324///The timer  handler gets called when a hardware timer set by the
[665]325///user expires. The user's callback is called upon the completion of this event
[1169]326inline void warpmac_pollTimer() {
[941]327   
[1164]328   
[1177]329    unsigned int timerStatus;
[1164]330   
[1177]331    timerStatus = warp_timer_getStatuses();
[1164]332   
[1203]333   
[1177]334    //We check the status of each of the timers, and call necessary callbacks
335    // The ifdef's below keep this funciton from wasiting time checking unused timers
336    // You can enable polling timers invididually by modifying warpmac.h
337#ifdef POLL_TIMER0
338    if((timerStatus & TIMER0_MASK & TIMER_STATUS_DONE_MASK) != 0){
339        warp_timer_resetDone(0);
340        usr_timerCallback(0);
[1164]341    }
[1177]342#endif
343#ifdef POLL_TIMER1
344    if((timerStatus & TIMER1_MASK & TIMER_STATUS_DONE_MASK) != 0){
345        warp_timer_resetDone(1);
346        usr_timerCallback(1);
[1164]347    }
[1177]348#endif
349#ifdef POLL_TIMER2
350    if((timerStatus & TIMER2_MASK & TIMER_STATUS_DONE_MASK) != 0){
351        warp_timer_resetDone(2);
352        usr_timerCallback(2);
[1164]353    }
[1177]354#endif
355#ifdef POLL_TIMER3
356    if((timerStatus & TIMER3_MASK & TIMER_STATUS_DONE_MASK) != 0){
357        warp_timer_resetDone(3);
358        usr_timerCallback(3);
359    }
360#endif
361#ifdef POLL_TIMER4
362    if((timerStatus & TIMER4_MASK & TIMER_STATUS_DONE_MASK) != 0){
363        warp_timer_resetDone(4);
364        usr_timerCallback(4);
365    }
366#endif
367#ifdef POLL_TIMER5
368    if((timerStatus & TIMER5_MASK & TIMER_STATUS_DONE_MASK) != 0){
369        warp_timer_resetDone(5);
370        usr_timerCallback(5);
371    }
372#endif
[1379]373   
374    //Timer 6 is dedicated for polling User I/O
[1177]375    if((timerStatus & TIMER6_MASK & TIMER_STATUS_DONE_MASK) != 0){
376        warp_timer_resetDone(USERIO_TIMER);
[1197]377       
[1177]378        //Call the UART callback
[1164]379        warpmac_uartRecvHandler(&UartLite);
[1197]380       
[1177]381        //Call the user I/O callback (buttons, switches, etc.)
[1169]382        userIO_handler(&GPIO_UserIO);
[1197]383       
[1177]384        //Reset and restart the user I/O polling timer
385        warp_timer_setTimer(USERIO_TIMER, 0, USERIO_POLLRATE);
386        warp_timer_setMode(USERIO_TIMER, TIMER_MODE_NOCARRIERSENSE);
387        warp_timer_start(USERIO_TIMER);
[1164]388    }
[1197]389   
[1379]390    //Timer 7 is dedicated to dummy packet generation
391    if((timerStatus & TIMER7_MASK & TIMER_STATUS_DONE_MASK) != 0){
[1221]392        warp_timer_resetDone(PKTGEN_TIMER);
393        //warpmac_incrementLEDLow();
394        pktGen_allow = 1;
[1477]395   
[1221]396        warp_timer_setTimer(PKTGEN_TIMER, 0, dummyPacketInterval*TIMERCLK_CYCLES_PER_USEC); 
397        warp_timer_setMode(PKTGEN_TIMER, TIMER_MODE_NOCARRIERSENSE);
398        warp_timer_start(PKTGEN_TIMER);
399    }
[1477]400
[1379]401    return;
402}
[1221]403
[1379]404///@brief Polls the Ethernet
405///
406///Function checks the status of the ping and pong Emac buffers
407///and calls the effective-ISR when either is filled.
408inline void warpmac_pollDataSource() {
[1221]409   
[1397]410    //If the user code has disabled new data (probably becuase they're still working on the previous packet)
411    // return immediately without actually polling anything. This allows the TEAMC and LLFIFO to buffer
412    // incoming packets, dropping them at the wire if too many arrive before the user is ready
413    if( controlStruct.enableDataFromNetwork == 0 )
414        return;
415   
[1379]416    //If we're in dummyPacket mode, and it's time to generate a new packet,
[1397]417    // call the user callback immediately, as if a packet had been received over the wire into pktBuf_emacRx
[1379]418    if(controlStruct.dummyPacketMode && startPktGeneration && pktGen_allow)
419    {
[1397]420        pktGen_allow = 0;
[1477]421//              xil_printf("dummy\r\n");
[1397]422        usr_dataFromNetworkLayer(dummyPacketLength, warpphy_getBuffAddr(controlStruct.pktBuf_emacRx)+NUM_HEADER_BYTES);
[1379]423    }
424   
[1491]425    //warpmac_setDebugGPIO(0x1);
[1397]426
427    //Two ways to check if there are packets in the LLFIFO:
428    // 1) Read the ISR register for XLLF_INT_RC_MASK (receive complete)
429    // 2) Read the RDFO register for a count of received packets in the FIFO
430    //Option 2 works well in testing
431    //if(XIo_In32(EMAC_FIFO_BaseAddr+XLLF_ISR_OFFSET) & XLLF_INT_RC_MASK)
432    if(XIo_In32(EMAC_FIFO_BaseAddr+XLLF_RDFO_OFFSET) > 0)
[1379]433    {
[1397]434        //FIXME: add LLFIFO and TEMAC error handling
435
436        //Clear the LLFIFO status bits
[1379]437        XIo_Out32(EMAC_FIFO_BaseAddr+XLLF_ISR_OFFSET, 0x0FFFFFFF);
438       
[1491]439        //warpmac_setDebugGPIO(0x3);
[1397]440
441        //Call the ethernet packet handler
442        emacRx_handler();
[1379]443    }
[1491]444    //warpmac_setDebugGPIO(0x0);
[1397]445
[834]446    return;
[665]447}
448
[1379]449///@brief "Good Header" handler for the PHY layer.
[665]450///
[1379]451///This function is the handler for the RX physical layer peripheral.
452///This function is only called if the packet header has no bit errors
453///(i.e., the packet header passes CRCs in the PHY). This handler will
454///be asserted *before* the packet is fully received. This function assumes
455///the user's callback will poll the PHY to determine if the packet is eventually
456///good or bad
457void phyRx_goodHeader_handler() {   
[1491]458
459//  warpmac_setDebugGPIO(0xF);
460   
[1379]461    //Copy the received packet's header into the rxPacket struct
462    memcpy((unsigned char *)(&(rxPacket->header)), (unsigned char *)warpphy_getBuffAddr(controlStruct.pktBuf_phyRx), (size_t)NUM_HEADER_BYTES);
463   
464    //Strip the header and checksum from the total number of bytes reported to user code
465    if(rxPacket->header.length == NUM_HEADER_BYTES) {
466        //Header-only packet (like an ACK) has 0 payload bytes
467        rxPacket->header.length = 0;
468    }
469    else {
470        //Other packets have payload bytes; subtract off header and 4-byte payload checksum lengths and (if coded) tail bytes
[1509]471        rxPacket->header.length = (rxPacket->header.length) - NUM_HEADER_BYTES - NUM_PAYLOAD_CRC_BYTES - NUM_PAYLOAD_TAIL_BYTES;
[1379]472    }
473   
474    //If the Rx packet is too big, ignore the payload
475    // This should never happen; the Tx code will never send a pkt bigger than Ethernet MTU
476    if(rxPacket->header.length>MY_XEM_MAX_FRAME_SIZE) {
477        rxPacket->header.length = 0;
478    }
479   
480    //Pass the received packet to the user handler
[1491]481    if(~usr_goodHeaderCallback(rxPacket)){
482        warpphy_clearRxPktStatus();
483    }
484#if WARPMAC_SAFE_GOODHDR
[1379]485    //Poll PHY to insure ISR does not quit too early
486    //User code probably does this too, but it is required to
487    unsigned char state = PHYRXSTATUS_INCOMPLETE;
488    while(state == PHYRXSTATUS_INCOMPLETE)
489    {
490        //Blocks until the PHY reports the received packet as either good or bad
491        state = mimo_ofdmRx_getPayloadStatus();
492    }
493   
494    //Clears every interrupt output of the PHY
495    warpphy_clearRxPktStatus();
[1491]496#endif
[1379]497   
[1516]498//      warpmac_setDebugGPIO(0x0,0xF);
[1491]499   
500//warpmac_setDebugGPIO(0x0);   
501   
[1379]502    return;
[543]503}
[478]504
[1379]505///@brief "Bad Header" handler for the PHY layer.
506///
507///This function is the handler for the RX physical layer peripheral.
508///This function is only called if the packet fails CRC. The received
509///packet is passed to the user's callback, and the PHY is reset.
510inline void phyRx_badHeader_handler() {
511    //Bad packets, by definition, have no payload bytes which can be trusted
512    // The user handler is called with no arguments, since there is no real packet data to process
513    // If the header happend to be good but the payload bad, the user should use the good header
514    // interrupt to process the header
515    usr_badHeaderCallback();
516   
517    //Clear the good/bad packet interrupts in the PHY to re-enable packet reception
518    warpphy_clearRxPktStatus();
519   
520    return;
[444]521}
522
[1379]523///@brief Handles a received Ethernet frame
[665]524///
[1379]525///This funciton handles a single received Ethernet frame
526///The calling function is responsible for first checking that a frame is ready to be received
527void emacRx_handler() {
[1477]528//xil_printf("emacRx handler\r\n");
[1379]529    unsigned short RxPktLength, RxPktEtherType;
530    int skipDataCallback = 0;
531    int mgmtFrame = 0;
532    void* pktBufPtr;
533    warpnetEthernetPktHeader* thePkt;
534
535    pktBufPtr = (void *)warpphy_getBuffAddr(controlStruct.pktBuf_emacRx)+NUM_HEADER_BYTES;
536
537    //Wait for the DMA to be idle
538    warpmac_waitForDMA();
539
540    //Set DMA to non-increment source, increment dest addresses
541    XDmaCentral_SetControl(&DmaCentralInst, XDMC_DMACR_DEST_INCR_MASK);
542
543    //Read the Rx packet length; the packet must be read from the FIFO immediately after this read
544    RxPktLength = XIo_In32(EMAC_FIFO_BaseAddr+XLLF_RLF_OFFSET);
545
[1491]546    //warpmac_setDebugGPIO(0x7);
[1379]547    //Transfer the Ethernet frame from the FIFO to the PHY buffer
548    XDmaCentral_Transfer(&DmaCentralInst,
549                        (u8 *)(EMAC_FIFO_BaseAddr+XLLF_RDFD_OFFSET),
550                        (u8 *)pktBufPtr,
551                        RxPktLength);
552
553    //Extract the EtherType field to determine if this is a management packet
554    thePkt = (warpnetEthernetPktHeader*)(pktBufPtr);
555    RxPktEtherType = thePkt->ethType;
[941]556   
[1379]557#ifdef WARPNET_ETHTYPE_SVR2NODE
558    if (RxPktEtherType == WARPNET_ETHTYPE_SVR2NODE) {
559        //The packet is a WARPnet packet
560        mgmtFrame = 1;
561        skipDataCallback = 1;
562    }
563#endif
564#ifdef WARPNET_ETHTYPE_NODE2SVR
565    if (RxPktEtherType == WARPNET_ETHTYPE_NODE2SVR) {
566        //The packet is a WARPnet packet from another node destined to the server; ignore it
567        mgmtFrame = 0;
568        skipDataCallback = 1;
569    }
570#endif
[1164]571   
[1379]572    if(mgmtFrame)
573    {
574        //Wait until the DMA transfer is done by checking the Status register
575        warpmac_waitForDMA();
576       
577        usr_mgmtPkt(RxPktLength, pktBufPtr);
578    }
[1397]579    else if( (skipDataCallback == 0) && (controlStruct.dummyPacketMode == 0))
[1379]580    {
581        //printBytes((unsigned char *)pktBufPtr, 24);
582
583        //This call does *not* wait for the DMA to finish, since the FIFO/DMA will be much faster than an OFDM PHY Tx
[1491]584        //warpmac_setDebugGPIO(0xF);
[1477]585//      xil_printf("Not dummy\r\n");
[1494]586//      xil_printf("Not dummy\r\n");
[1379]587        usr_dataFromNetworkLayer(RxPktLength, pktBufPtr);
588    }
589
590    return;
[444]591}
592
[1379]593inline void warpmac_waitForDMA()
594{
595
596    int RegValue;
597
598    //Wait until the DMA transfer is done by checking the Status register
599    do {RegValue = XDmaCentral_GetStatus(&DmaCentralInst);}
600    while ((RegValue & XDMC_DMASR_BUSY_MASK) == XDMC_DMASR_BUSY_MASK);
601
602    return;
603}
604
605///@brief This function stops the timer.
[665]606///
[1379]607///Additionally it will return the amount of time remaining before expiration.
608///@return Number of clock cycles remaining before expiration.
609inline void warpmac_clearTimer(unsigned char theTimer) {
610    warp_timer_pause(theTimer);
611    warp_timer_resetDone(theTimer);
[941]612   
[1379]613    return;
[543]614}
[444]615
[1379]616///@brief This function starts the timer in either a CSMA or non-CSMA mode.
[1645]617///@param theTimer ID of the hardware timer (in [0,7]) to start
[1646]618///@param mode TIMER_MODE_CARRIERSENSE if automatic carrier-sense pausing is desired. TIMER_MODE_NOCARRIERSENSE if received energy
[1379]619///is to be ignored.
620inline void warpmac_startTimer(unsigned char theTimer, unsigned char mode) {
621    warp_timer_setMode(theTimer, mode);
622    warp_timer_start(theTimer);
623}
624
[665]625///@brief Function is responsible for high-level MAC timing
626///
627///This function is used by user code, and in turn calls the other timer functions.
628///It is capable of initiating either a deterministic timeout, or a random backoff.
[1646]629///@param type TIMEOUT_TIMER for deterministic countdown, BACKOFF_TIMER for random exponential
[1379]630void warpmac_setTimer(int type) {
[1712]631    unsigned int numSlots;
[543]632    int myRandNum;
[1164]633   
[543]634    switch(type) {
[1177]635        case TIMEOUT_TIMER:
[1164]636           
[1177]637            //User a 1-cycle slot, so the numSlots argument is equal to the number of clock cycles
638            warp_timer_setTimer(TIMEOUT_TIMER, 0, controlStruct.timeout);
639            warp_timer_setMode(TIMEOUT_TIMER, TIMER_MODE_NOCARRIERSENSE); 
640            warp_timer_start(TIMEOUT_TIMER);
[1011]641            return;
[543]642            break;
[1177]643        case BACKOFF_TIMER:
[1169]644           
[1176]645            myRandNum = randNum(controlStruct.currentCW);
[1177]646            numSlots = myRandNum;
647           
[1176]648            if(controlStruct.currentCW < controlStruct.maxCW){
649                controlStruct.currentCW = controlStruct.currentCW + 1;
[543]650            }
[1177]651           
[1182]652            warp_timer_setTimer(BACKOFF_TIMER, controlStruct.slotTime, numSlots);
653            warp_timer_start(BACKOFF_TIMER);
[1203]654           
[1177]655            return;
[941]656            break;
[1379]657        default:
658            //Invalid timer ID; do nothing
659            return;
660            break;
[543]661    }
662}
[444]663
[1379]664///@brief Generates a uniform random value between [0,(2^(N+4) - 1)], where N is a positive integer
665///
666///Used internally by WARPMAC for random exponential backoffs.
667///@param N Window size for draw of uniform random value.
668inline unsigned int randNum(unsigned int N){
[941]669   
[1379]670    return ((unsigned int)rand() >> (32-(N+5)));
[941]671   
[665]672}
[543]673
[1379]674///@brief Returns a value corresponding to the instantaneous channel condition {busy or idle}
675///
676///@return 1 if medium is idle, 0 if medium is busy
677inline int warpmac_carrierSense() {
678    return ofdm_txrx_mimo_ReadReg_Rx_PktDet_idleForDifs();
[903]679}
680
[617]681
[1379]682///@brief Starts a DMA transfer to the EMAC FIFO
683///
684///This function does *not* block until the DMA finishes, so the user app can do other things
685///User code should call warpmac_startPktToNetwork() soon after calling this function
686///
687///@param thePkt Pointer to the packet data
688///@param length Number of bytes in the packet
689inline void warpmac_prepPktToNetwork(void* thePkt, unsigned int length) {
[617]690
[1477]691   
692    #if 0   
693    xil_printf("prepPktToNetwork\r\n");
694    #define NUMREAD 100
695    int i;
696    for(i=0;i<NUMREAD;i++){
697        xil_printf("0x%x, ",*((unsigned char*)thePkt+i)&0xFF);
698    }
699    xil_printf("\r\n");
700    #endif
701
702//  int i;
703//  for(i=0;i<length;i++){
704//  xil_printf("0x%x, ",*((unsigned char*)thePkt+i)&0xFF);
705//  }
706//  xil_printf("\r\n");
707
[1379]708    //Wait for the DMA to be idle
709    warpmac_waitForDMA();
[617]710
[1379]711    //Set DMA to increment src, non-increment dest addresses
712    XDmaCentral_SetControl(&DmaCentralInst, XDMC_DMACR_SOURCE_INCR_MASK);
[617]713
[1379]714    //Transfer the packet into the LLFIFO
715    XDmaCentral_Transfer(&DmaCentralInst, 
716                            (u8 *)(thePkt),
717                            (u8 *)(EMAC_FIFO_BaseAddr + XLLF_TDFD_OFFSET),
[1632]718                            length);
[1379]719    return;
[665]720}
[617]721
[1379]722///@brief Starts an Ethernet packet transmission
723///
724///Packet must have already been transferred using warpmac_prepPktToNetwork()
725///@param length Number of bytes in packet to send (must match length argument in previous warpmac_prepPktToNetwork call)
726inline void warpmac_startPktToNetwork(unsigned int length) {
[1477]727
728//xil_printf("startPktToNetwork\r\n");
729
[1379]730    //Wait for the DMA to finish
731    warpmac_waitForDMA();
[617]732
[1477]733
734   
[1379]735    //Write the length to the LL_FIFO; this write initiates the TEMAC transmission
[1632]736    XIo_Out32( (EMAC_FIFO_BaseAddr + XLLF_TLF_OFFSET), length);
[1379]737   
738    return;
[665]739}
[617]740
[1379]741///@brief Sets user callback function for various system events
742///
[1645]743///@param event ID of the event triggering the callback; one of EVENT_* values from warpmac.h
744///@param handler Function pointer for user-provided callback function
[1379]745void warpmac_setCallback(int event, void(*handler)()) {
[828]746
[1379]747    switch(event)
748    {
749        case EVENT_UPBUTTON:
750            usr_upbutton = handler;
751            break;
752        case EVENT_LEFTBUTTON:
753            usr_leftbutton = handler;
754            break;
755        case EVENT_RIGHTBUTTON:
756            usr_rightbutton = handler;
757            break;
758        case EVENT_MIDDLEBUTTON:
759            usr_middlebutton = handler;
760            break;
761        case EVENT_TIMER:
762            usr_timerCallback = handler;
763            break;
764        case EVENT_DATAFROMNETWORK:
765            usr_dataFromNetworkLayer = handler;
766            break;
767        case EVENT_MGMTPKT:
768            usr_mgmtPkt = handler;
769            break;
770        case EVENT_PHYGOODHEADER:
771            usr_goodHeaderCallback = handler;
772            break;
773        case EVENT_PHYBADHEADER:
774            usr_badHeaderCallback = handler;
775            break;
776        case EVENT_UARTRX:
777            usr_uartRecvCallback = handler;
778            break;
779        default:
780            //Invalid event ID; do nothing
781            break;
782    }
783   
784    return;
[825]785}
786
[665]787///@brief Sets the base rate modulation order
788///
[825]789///The base rate symbols (i.e. the header) must have an agreed upon rate between the transmitter
[665]790///and receiver. This function sets that rate.
[1645]791///@param rate BPSK, QPSK or QAM_16
[1379]792void warpmac_setBaseRate(unsigned char rate) {
[1208]793    //Update the base rate modulation in the PHY; leave the four full rate modulation selections unchanged
794    warpphy_set_modulation(rate, MOD_UNCHANGED, MOD_UNCHANGED, MOD_UNCHANGED, MOD_UNCHANGED);
[1537]795   
[1616]796    //Change these to _UNCODED if FEC is disabled
797    if(rate == BPSK) warpphy_setNumBaseRateSyms(NUM_BASERATE_SYMBOLS_BPSK_CODED);
798    else warpphy_setNumBaseRateSyms(NUM_BASERATE_SYMBOLS_QPSK_CODED);
[1537]799
800    return;
[444]801}
802
[1379]803///@brief Sets the PHY Tx and Rx antenna modes
804///
805///@param txMode One of TX_ANTMODE_* values defined in warpphy.h
806///@param rxMode One of RX_ANTMODE_* values defined in warpphy.h
[1208]807int warpmac_setAntennaMode(unsigned int txMode, unsigned int rxMode)
808{
809    //Update the global variables, used elsewhere to calculate PHY values
810    // (like numFullRate symbols) which depend on the current antenna configuration
[1226]811    if( (txMode & PHYMODE_SISO) || (txMode & PHYMODE_ALAMOUTI) )
[1208]812    {
813        warpmac_TxMultiplexingMode = 0;
814    }
815    else
816    {
817        warpmac_TxMultiplexingMode = 1;
818    }
[444]819
[1208]820    //Call the warpphy function to actually configure the PHY antenna mode
821    warpphy_setAntennaMode(txMode, rxMode);
822
823    return 0;
824}
[856]825///@brief Loads a header into the PHY, but does not immediately transmit
826///
827///This function performs the conversion from the packet structure to the byte array
[903]828///but does not send the packet over the air. This is used to "preload" and ACK
[941]829///into the PHY while the data packet is still being received. This extra
[856]830///pipelining saves on turn-around time.
831///@param packet Pointer to user's Macframe
[946]832///@param buffer Packet buffer to send from
[1379]833void warpmac_prepPhyForXmit(Macframe* packet, unsigned char buffer) {
[941]834   
[1226]835    unsigned short origLength;
[1379]836    if(packet->header.length == 0) {
837        //All-header packet, like an ACK, has only base-rate symbols
838        //Update the PHY packet length to consist of just the header
[1226]839        origLength = 0;
[856]840        packet->header.length = NUM_HEADER_BYTES;
841    }
[1226]842    else {
[1103]843        //Update the header's numBytes field to include the header, CRC and tail bytes
[1226]844        origLength = packet->header.length;
[1103]845        packet->header.length = packet->header.length + NUM_HEADER_BYTES + NUM_PAYLOAD_CRC_BYTES + NUM_PAYLOAD_TAIL_BYTES;
[856]846    }
[1203]847   
[856]848    //Copy the header to the PHY packet buffer, filling exactly NUM_HEADER_BYTES bytes
849    // The rest of the packet (its payload) will be copied by DMA later
[1015]850    memcpy( (void *) warpphy_getBuffAddr(buffer), (void *) packet, (size_t) NUM_HEADER_BYTES);
[941]851   
[856]852    //Revert the packet payload length so the user code doesn't see the MAC/PHY tweaking
[1226]853    packet->header.length = origLength;
[941]854   
[1012]855    return;
[903]856}
857
[856]858///@brief Sends the current txBuffer's content.
859///
[941]860///This function sends an existing Macframe over the air. This existing Macframe comes from the warpmac_prepPhyForXmit
[856]861///function.
[1379]862inline void warpmac_startPhyXmit(unsigned char buffer) {
[941]863   
[856]864    int txResult;
[941]865   
[856]866    //Hold the packet detecter in reset to prevent any interfering receptions
[1203]867    //  ofdm_pktDetector_mimo_WriteReg_pktDet_reset(PKTDET_BASEADDR, 1);
868   
[856]869    //Transmit the packet; WARPPHY disables the radio Rx, enables Tx, sends the packet, then re-enables radio Rx
[903]870    // TXBLOCK will cause this call to block until the transmission is finished
[1379]871    warpphy_setBuffs(buffer, controlStruct.pktBuf_phyRx);
[1477]872    controlStruct.pktBuf_phyTx = buffer;
873   
[941]874    txResult = warpphy_pktTx(TXNOBLOCK);
875   
[856]876    if(txResult != 0)
877    {
[1379]878        xil_printf("WARPMAC tried to Tx, but PHY was busy\r\n");
[856]879    }
[941]880   
[1012]881    return;
[903]882}
[856]883
[946]884///@brief Blocks on PHY transmission
885///
886///This function waits for the PHY to finish transmitting, then re-enables wireless reception and sets packet buffers back
887///to their default values.
[1379]888inline void warpmac_finishPhyXmit() {
[941]889    warpphy_waitForTx();
890}
[903]891
[1379]892///@brief Tells the PHY which piece of memory to receive to
893///
894///Also, it updates the global struct element Maccontrol#rxBuffIndex to keep track of that information*/
895inline void warpmac_setRxBuffers(Macframe* rxFrame, unsigned char phyRxBuff) {
[903]896
[1379]897    //Update the gloal Rx Macframe
898    rxPacket = rxFrame;
[903]899
[1379]900    //Update the PHY Rx buffer assignment
901    controlStruct.pktBuf_phyRx = phyRxBuff;
[1477]902//  warpphy_setBuffs(controlStruct.pktBuf_emacRx, controlStruct.pktBuf_phyRx);
903    warpphy_setBuffs(controlStruct.pktBuf_phyTx, controlStruct.pktBuf_phyRx);
[903]904
[1012]905    return;
[444]906}
907
[941]908///@brief Tells the PHY which piece of memory to send from
[1477]909inline void warpmac_setPHYTxBuffer(unsigned char txBuff) {
910    controlStruct.pktBuf_phyTx = txBuff;
[1379]911    warpphy_setBuffs(txBuff, controlStruct.pktBuf_phyRx);
[1012]912    return;
[444]913}
914
[1477]915///@brief Tells the PHY which piece of memory to send from
916inline void warpmac_setEMACRxBuffer(unsigned char emacRxBuff) {
917    controlStruct.pktBuf_emacRx = emacRxBuff;
918    return;
919}
920
[1176]921///@brief Decrements the remaining reSend counter for the given Macframe
[665]922///
[825]923///Also, it returns whether or not the counter has wrapped around the maximum
[665]924///number of retransmits
925///@param packet Pointer to user's Macframe
926///@return 0 if maximum number of retransmits has been reached, and 1 otherwise
[1176]927int warpmac_decrementRemainingReSend(Macframe* packet){
[444]928    int status = 1;
[1103]929   
[1176]930    unsigned char remainingReSend;
[1632]931    remainingReSend=(packet->header.remainingTx);
[1103]932   
[1232]933    if(remainingReSend>0){
[1176]934        remainingReSend--;
[444]935    }
[1103]936   
[1232]937    else{
938        status = 0; 
939    }
940
[1632]941    packet->header.remainingTx = remainingReSend;
[1232]942
[444]943    return status;
944}
945
[1176]946///@brief Resets the current contention window to the minimum
947///
948///Resets the current contention window to the minimum value. This is used
949///following the reception of an ACK in order to engage a minimum CW backoff period.
950void warpmac_resetCurrentCW(){
[1379]951    controlStruct.currentCW = 0;
[1176]952    return;
953}
954
[665]955///@brief Sets the maximum number of resends
956///
957///@param c Integer maximum number of resends
[1379]958inline void warpmac_setMaxResend(unsigned int c) {
959    controlStruct.maxReSend = c;
[444]960}
961
[665]962///@brief Sets the maximum contention window.
963///
964///@param c Maximum contention window
[1379]965inline void warpmac_setMaxCW(unsigned int c) {
966    controlStruct.maxCW = c;
[444]967}
968
[665]969///@brief Sets the amount of time the node is willing to wait for an acknowledgement.
970///
971///@param time Timeout duration (in microseconds)
[1379]972inline void warpmac_setTimeout(unsigned int time){
[1177]973    controlStruct.timeout = time * TIMERCLK_CYCLES_PER_USEC;
[444]974}
975
[665]976///@brief Sets the smallest backoff window.
977///
978///@param time Slot time duration (in microseconds)
[1379]979inline void warpmac_setSlotTime(unsigned int time){
[1177]980    controlStruct.slotTime = time * TIMERCLK_CYCLES_PER_USEC;
[444]981}
982
[665]983///@brief Returns a value corresponding to whether or not the node is in timeout.
984///
[1646]985///@return 1 if in TIMEOUT_TIMER, 0 otherwise
[1379]986inline int warpmac_inTimeout(){
[1177]987    return (0 != (warp_timer_getStatus(TIMEOUT_TIMER) & (TIMER_STATUS_DONE_MASK | TIMER_STATUS_RUNNING_MASK)));
[444]988}
989
[1265]990///@brief Returns a value corresponding to whether or not the node is in backoff.
991///
[1646]992///@return 1 if in BACKOFF_TIMER, 0 otherwise
[1379]993inline int warpmac_inBackoff(){
[1265]994    return (0 != (warp_timer_getStatus(BACKOFF_TIMER) & (TIMER_STATUS_DONE_MASK | TIMER_STATUS_RUNNING_MASK)));
995}
996
[1379]997///@brief Enables/disables carrier sensing in the PHY packet detector
998///
999///@param mode 1 enables CS, 0 disables CS
1000inline void warpmac_setCSMA(char mode) {
1001    if(mode)
1002        ofdm_txrx_mimo_WriteReg_Rx_CSMA_setThresh(THRESH_CARRIER_SENSE);
1003    else
1004        ofdm_txrx_mimo_WriteReg_Rx_CSMA_setThresh(16380);
[635]1005
1006    return;
1007}
[617]1008
[943]1009///@brief Raises a signal that is routed out to the debug header on the board
1010///
[1645]1011///@param val 4-bit input (per bit: 1=asserts output, 0=deasserts output)
1012///@param mask 4-bit mask of which bits to affect
[1491]1013inline void warpmac_setDebugGPIO(unsigned char val, unsigned char mask) {
1014
1015    debugGPIO = ((debugGPIO&~mask)|(mask&val));
[1712]1016    //XGpio_SetDataReg(XPAR_DEBUGOUTPUTS_BASEADDR, 1, debugGPIO);
[943]1017    return;
1018}
[834]1019
[1491]1020
1021
1022
[1379]1023///@brief Enable the Ethernet
1024inline void warpmac_enableDataFromNetwork() {
1025    controlStruct.enableDataFromNetwork = 1;
[834]1026    return;
[592]1027}
1028
[972]1029///@brief Disables the Ethernet
[1379]1030inline void warpmac_disableDataFromNetwork() {
1031    controlStruct.enableDataFromNetwork = 0;
[834]1032    return;
[592]1033}
[972]1034
[1282]1035
[1169]1036///@brief Blocks on PHY transmission and returns whether packet was good or bad
1037///
[1477]1038///This function waits for the PHY to finish receiving, then checks its status
[1169]1039inline char warpmac_finishPhyRecv(){
[1632]1040    XTime startTime,currTime;
[1282]1041    unsigned char state = PHYRXSTATUS_INCOMPLETE;
[1632]1042
1043//The running theory is that there is a bad state somewhere in the PHY
1044//That keeps a goodHeader from ever turning into a goodPayload or badPayload.
1045//I'm adding a watchdog timer in here to look for that state and purge the PHY.
1046//We should also notify the experiment that there was a corrupted trial so this dataPoint
1047//should be redone.
1048
1049    XTime_GetTime(&startTime);
1050       
1051
[1379]1052    while(state == PHYRXSTATUS_INCOMPLETE) {
[1169]1053        //Blocks until the PHY reports the received packet as either good or bad
1054        state = mimo_ofdmRx_getPayloadStatus();
[1632]1055
[1712]1056//      XTime_GetTime(&currTime);
1057//      if(((currTime>>10)-(startTime>>10))>=(234375*1)){
1058//          return 2;
1059//      }
[1632]1060
[1169]1061    }
1062    return state;
1063}
1064
[1632]1065
[1064]1066//void warpmac_uartRecvHandler(void *CallBackRef, unsigned int EventData)
1067void warpmac_uartRecvHandler(void *CallBackRef)
1068{
1069    XUartLite *InstancePtr = CallBackRef;
1070   
1071    unsigned int uartIntStatus;
1072    unsigned char receivedByte;
1073   
[1712]1074    uartIntStatus = XUartLite_ReadReg(InstancePtr->RegBaseAddress, XUL_STATUS_REG_OFFSET);
[1203]1075   
[1064]1076    if( (uartIntStatus & (XUL_SR_RX_FIFO_FULL | XUL_SR_RX_FIFO_VALID_DATA)) != 0)
1077    {
1078        receivedByte = XUartLite_RecvByte(InstancePtr->RegBaseAddress);
1079       
1080        //Call the user callback, passing the byte that was received
1081        usr_uartRecvCallback(receivedByte);
1082    }
[1203]1083   
[1064]1084    return;
1085}
1086
[1379]1087//**************************//
1088// Dummy Packet Mode Config //
1089//**************************//
1090inline void warpmac_setDummyPacketMode(char mode) {
[1477]1091    if(mode){
1092        xil_printf("Dummy Packet Mode Enabled\r\n");
[1379]1093        controlStruct.dummyPacketMode = 1;
[1477]1094        }
[1379]1095    else
[1477]1096        {
1097        xil_printf("Dummy Packet Mode Disabled\r\n");
[1379]1098        controlStruct.dummyPacketMode = 0;
[1477]1099        }
[1379]1100    return;
[1103]1101}
[1164]1102
[1379]1103void warpmac_startPacketGeneration(unsigned int length, unsigned int interval) {
[1477]1104
[1282]1105    startPktGeneration = 1;
[1221]1106    dummyPacketLength = length;
1107    dummyPacketInterval = interval;
1108   
1109    warp_timer_setTimer(PKTGEN_TIMER, 0, dummyPacketInterval*TIMERCLK_CYCLES_PER_USEC); 
1110    warp_timer_setMode(PKTGEN_TIMER, TIMER_MODE_NOCARRIERSENSE);
1111    warp_timer_start(PKTGEN_TIMER);
[1379]1112    return;
[1221]1113}
[1203]1114
[1379]1115void warpmac_stopPacketGeneration() {
[1221]1116    startPktGeneration = 0;
1117   
1118    warp_timer_pause(PKTGEN_TIMER);
1119    warp_timer_resetDone(PKTGEN_TIMER);
1120}
1121
[1369]1122///@brief Reads the value from the user dip switches for use as node identification.
1123///
1124///@return Value currently set on dip switches of the WARP board
[1379]1125int warpmac_getMyId() {
1126
1127    //dipswState is updated automatically by the User I/O handler
[1369]1128    return dipswState;
1129}
[1214]1130
[1379]1131inline void printBytes(unsigned char* data, int length)
1132{
1133    int i;
[1369]1134
[1379]1135    xil_printf("Data (hex, %d bytes):\r\n", length);
1136
1137    for(i=0; i<length; i++)
1138        xil_printf("%02x ", data[i]);
1139
1140    xil_printf("\r\n");
1141    return;
1142}
1143
1144
1145//**********START***********//
1146// FPGA Board Specific Code //
1147//**************************//
[1203]1148#ifdef WARP_FPGA_BOARD_V1_2
[1369]1149///@brief  Handler for the User I/O.
1150///
1151///This is called by the User I/O polling from one of the timers.
1152///The various user callbacks are executed, depending upon which button was depressed. Additionally,
1153///the board's dip switches also trigger this handler, though the framework does not currently call user
1154///code in this event. We assume that dipswitches are currently only used for beginning-of-time
1155///state assignments.
1156void userIO_handler(void *InstancePtr){
1157   
1158    static unsigned int previousAssertedInputs;
1159    unsigned int assertedInputs;
1160    unsigned int newAssertedInputs;
1161   
1162    //Re-interpret the generic input pointer as a GPIO driver instance
1163    XGpio *GpioPtr = (XGpio *)InstancePtr;
1164   
1165    //Disable the GPIO core's interrupt output
1166    //XGpio_InterruptDisable(GpioPtr, USERIO_CHAN_INPUTS);
1167   
1168    //Read the GPIO inputs; each 1 is a currently-asserted input bit
1169    assertedInputs = XGpio_DiscreteRead(&GPIO_UserIO, USERIO_CHAN_INPUTS) & USERIO_MASK_INPUTS;
1170   
1171    //XOR the current active bits with the previously active bits
1172    newAssertedInputs = (assertedInputs ^ previousAssertedInputs) & assertedInputs;
1173    previousAssertedInputs = assertedInputs;
1174   
1175    //Check whether push buttons or DIP switch triggered the interrupt
1176    // We assume a user callback per button, and another for the DIP switch
1177    if(newAssertedInputs & USERIO_MASK_PBC) usr_middlebutton();
1178    if(newAssertedInputs & USERIO_MASK_PBR) usr_rightbutton();
1179    if(newAssertedInputs & USERIO_MASK_PBL) usr_leftbutton();
1180    if(newAssertedInputs & USERIO_MASK_PBU) usr_upbutton();
1181    if(newAssertedInputs & USERIO_MASK_DIPSW) {
1182        dipswState = USERIO_MAP_DIPSW(assertedInputs); 
1183    }
1184   
1185    return;
1186}
1187
[1477]1188///@brief Alternates the bottom two LEDs on the WARP board.
[1369]1189void warpmac_incrementLEDLow(){
1190   
1191   
1192    //Update the global variable we use to track which LED/segments are currently lit
1193    // The xps_gpio core doesn't allow outputs to be read from code, so we have to track this internally
1194    LEDHEX_Outputs = (USERIO_MAP_LEDS( (ledStatesLow[ledStatesIndexLow]|ledStatesHigh[ledStatesIndexHigh])) | USERIO_MAP_DISPR(rightHex) | USERIO_MAP_DISPL(leftHex));
1195   
1196   
1197    XGpio_DiscreteSet(&GPIO_UserIO, USERIO_CHAN_OUTPUTS, LEDHEX_Outputs);
1198    ledStatesIndexLow = (ledStatesIndexLow+1)%2;
1199}
1200
1201
[1477]1202///@brief Alternates the top two LEDs on the WARP board.
[1369]1203void warpmac_incrementLEDHigh(){
1204   
1205    //Update the global variable we use to track which LED/segments are currently lit
1206    // The xps_gpio core doesn't allow outputs to be read from code, so we have to track this internally
1207    LEDHEX_Outputs = (USERIO_MAP_LEDS( (ledStatesLow[ledStatesIndexLow]|ledStatesHigh[ledStatesIndexHigh])) | USERIO_MAP_DISPR(rightHex) | USERIO_MAP_DISPL(leftHex));
1208   
1209    XGpio_DiscreteSet(&GPIO_UserIO, USERIO_CHAN_OUTPUTS, LEDHEX_Outputs);
1210   
1211    ledStatesIndexHigh = (ledStatesIndexHigh+1)%2;
1212}
1213
[1203]1214///@brief Maps character to the seven segment display
1215///
1216///@param x Input character
1217///@return Corresponding value that can be written to the GPIO connected to the Hex displays
1218unsigned char sevenSegmentMap(unsigned char x){
1219    switch(x)
1220    {
1221        case(0x0) : return 0x007E;
1222        case(0x1) : return 0x0030;
1223        case(0x2) : return 0x006D;
1224        case(0x3) : return 0x0079;
1225        case(0x4) : return 0x0033;
1226        case(0x5) : return 0x005B;
1227        case(0x6) : return 0x005F;
1228        case(0x7) : return 0x0070;
1229        case(0x8) : return 0x007F;
1230        case(0x9) : return 0x007B;
1231           
1232        case(0xA) : return 0x0077;
1233        case(0xB) : return 0x007F;
1234        case(0xC) : return 0x004E;
1235        case(0xD) : return 0x007E;
1236        case(0xE) : return 0x004F;
1237        case(0xF) : return 0x0047;
1238        default : return 0x0000;
1239    }
1240}
1241
1242///@brief Displays the input character on the left hex display
1243///
1244///@param x Character to display
1245void warpmac_leftHex(unsigned char x){
1246   
1247   
1248    leftHex = sevenSegmentMap(x);
1249   
1250    //Update the global variable we use to track which LED/segments are currently lit
1251    // The xps_gpio core doesn't allow outputs to be read from code, so we have to track this internally
1252    LEDHEX_Outputs = (USERIO_MAP_LEDS( (ledStatesLow[ledStatesIndexLow]|ledStatesHigh[ledStatesIndexHigh])) | USERIO_MAP_DISPR(rightHex) | USERIO_MAP_DISPL(leftHex));
1253   
1254   
1255    XGpio_DiscreteSet(&GPIO_UserIO, USERIO_CHAN_OUTPUTS, LEDHEX_Outputs);
1256   
1257    return;
1258}
1259
1260///@brief Displays the input character on the right hex display
1261///
1262///@param x Character to display
1263void warpmac_rightHex(unsigned char x){
1264   
1265    rightHex = sevenSegmentMap(x); 
1266    //Update the global variable we use to track which LED/segments are currently lit
1267    // The xps_gpio core doesn't allow outputs to be read from code, so we have to track this internally
1268    LEDHEX_Outputs = (USERIO_MAP_LEDS( (ledStatesLow[ledStatesIndexLow]|ledStatesHigh[ledStatesIndexHigh])) | USERIO_MAP_DISPR(rightHex) | USERIO_MAP_DISPL(leftHex));
1269    XGpio_DiscreteSet(&GPIO_UserIO, USERIO_CHAN_OUTPUTS, LEDHEX_Outputs);
1270    return;
1271}
1272
[1369]1273#elif defined WARP_FPGA_BOARD_V2_2
1274///@brief  Handler for the User I/O.
1275///
1276///This is called by the User I/O polling from one of the timers.
1277///The various user callbacks are executed, depending upon which button was depressed. Additionally,
1278///the board's dip switches also trigger this handler, though the framework does not currently call user
1279///code in this event. We assume that dipswitches are currently only used for beginning-of-time
1280///state assignments.
1281void userIO_handler(void *InstancePtr){
1282   
1283    static unsigned int previousAssertedInputs;
1284    unsigned int assertedInputs;
1285    unsigned int newAssertedInputs;
1286   
1287    //Read the GPIO inputs; each 1 is a currently-asserted input bit
1288    assertedInputs = WarpV4_UserIO_PushB(USERIO_BASEADDR) | (WarpV4_UserIO_DipSw(USERIO_BASEADDR) << 4);
1289   
1290    //XOR the current active bits with the previously active bits
1291    newAssertedInputs = (assertedInputs ^ previousAssertedInputs) & assertedInputs;
1292    previousAssertedInputs = assertedInputs;
1293   
1294    //Check whether push buttons or DIP switch triggered the interrupt
1295    // We assume a user callback per button, and another for the DIP switch
1296    if(newAssertedInputs & USERIO_MASK_PBC) usr_middlebutton();
1297    if(newAssertedInputs & USERIO_MASK_PBR) usr_rightbutton();
1298    if(newAssertedInputs & USERIO_MASK_PBL) usr_leftbutton();
1299    if(newAssertedInputs & USERIO_MASK_PBU) usr_upbutton();
1300    if(newAssertedInputs & USERIO_MASK_DIPSW) {
1301        dipswState = WarpV4_UserIO_DipSw(USERIO_BASEADDR);
[1203]1302    }
[1369]1303   
1304    return;
[1203]1305}
1306
[1369]1307///@brief Alternates the bottom two LEDs on the WARP board.
1308void warpmac_incrementLEDLow(){
1309   
[1712]1310    WarpV4_UserIO_Leds(USERIO_BASEADDR, (ledStatesLow[ledStatesIndexLow] | ledStatesHigh[ledStatesIndexHigh]));
[1369]1311
1312    ledStatesIndexLow = (ledStatesIndexLow+1)%2;
[1203]1313}
1314
[1369]1315///@brief Alternates the top two LEDs on the WARP board.
1316void warpmac_incrementLEDHigh(){
1317   
[1712]1318    WarpV4_UserIO_Leds(USERIO_BASEADDR, (ledStatesLow[ledStatesIndexLow] | ledStatesHigh[ledStatesIndexHigh]));
[1369]1319   
1320    ledStatesIndexHigh = (ledStatesIndexHigh+1)%2;
1321}
[1203]1322
[1369]1323void warpmac_leftHex(unsigned char x){
1324   
1325    WarpV4_UserIO_WriteNumber_LeftHex(USERIO_BASEADDR, x, 0);
1326    return;
[1203]1327}
1328
[1369]1329void warpmac_middleHex(unsigned char x){
1330   
1331    WarpV4_UserIO_WriteNumber_MiddleHex(USERIO_BASEADDR, x, 0);
1332    return;
[1203]1333}
1334
[1369]1335void warpmac_rightHex(unsigned char x){
1336   
1337    WarpV4_UserIO_WriteNumber_RightHex(USERIO_BASEADDR, x, 0);
1338    return;
[1203]1339}
1340#endif
[1379]1341//**************************//
1342// FPGA Board Specific Code //
1343//***********END************//
Note: See TracBrowser for help on using the repository browser.