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
Line 
1/* Version v17 */
2
3#include "warp_fpga_board.h"
4#include "xparameters.h"
5#include "xstatus.h"
6#include "errno.h"
7#include "xpseudo_asm_gcc.h"
8#include "stddef.h"
9#include "stdio.h"
10#include "string.h"
11#include "xuartlite.h"
12#include "xuartlite_l.h"
13#include "xgpio.h"
14#include "stdlib.h"
15#include "warpmac.h"
16#include "radio_controller_basic.h"
17#include "radio_controller_ext.h"
18#include "radio_controller_adv.h"
19#include "warpphy.h"
20#include "warpnet.h"
21
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
27#include "xlltemac.h"
28#include "xllfifo_hw.h"
29#include "xdmacentral.h"
30#include "xdmacentral_l.h"
31
32#include "xtime_l.h"
33
34#define WARPMAC_SAFE_GOODHDR 0
35
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
43#elif defined WARP_FPGA_BOARD_V2_2
44
45#include "warp_v4_userio.h"
46
47#define USERIO_BASEADDR XPAR_USERIO_BASEADDR
48#define ENET_LINK_SPEED     1000
49
50#endif
51
52//Instantiates the Maccontrol control structure
53Maccontrol controlStruct;
54
55extern unsigned int activeRadios_Tx;
56
57//Instantiates the general-purpose input-output peripheral driver
58static XGpio GPIO_UserIO;
59
60//Instantiates the UART driver instance
61static XUartLite UartLite;
62
63static XDmaCentral DmaCentralInst;
64static XDmaCentral_Config *DMAConfigPtr;
65
66XLlTemac TemacInstance;
67XLlTemac_Config *MacCfgPtr;
68u32 EMAC_FIFO_BaseAddr;
69
70//Points to a user-provided Macframe where parsed header information will be copied to
71Macframe* rxPacket;
72
73//Global variable for tracking active LED outputs
74unsigned int LEDHEX_Outputs;
75unsigned int ledStates;
76unsigned int leftHex;
77unsigned int rightHex;
78
79//"Low" LED states
80unsigned int ledStatesLow[2];
81unsigned char ledStatesIndexLow;
82//"High" LED states
83unsigned int ledStatesHigh[2];
84unsigned char ledStatesIndexHigh;
85//Dip-switch state
86unsigned char dipswState;
87//Debug GPIO state
88unsigned char debugGPIO;
89
90//Global variable to track SISO vs. MIMO mode
91unsigned char warpmac_TxMultiplexingMode;
92
93unsigned char pktGen_allow;
94unsigned int dummyPacketInterval;
95unsigned char startPktGeneration;
96unsigned int dummyPacketLength;
97
98//These the addresses pointed to by these variables are set by the
99//user via the callback registration functions
100
101void (*usr_upbutton) ();
102void (*usr_leftbutton) ();
103void (*usr_middlebutton) ();
104void (*usr_rightbutton) ();
105void (*usr_badHeaderCallback) ();
106int (*usr_goodHeaderCallback) ();
107void (*usr_timerCallback) ();
108void (*usr_dataFromNetworkLayer) ();
109void (*usr_mgmtPkt) ();
110void (*usr_uartRecvCallback) ();
111
112//Null handler, for callbacks the user doesn't re-assign
113void nullCallback(void* param){};
114int nullCallback_i(void* param){return 0;};
115
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
119///interrupts and exceptions, configures Ethernet, and finally initializes the custom peripherals
120///such as the radio controller, the PHY, the packet detector, and the automatic gain control block.
121void warpmac_init() {
122   
123    xil_printf("Initializing WARPMAC v17.0:\r\n");
124   
125    XStatus Status;
126
127    //Initialize global variables
128    startPktGeneration = 0;
129    dummyPacketLength = 1470;
130    debugGPIO = 0;
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;
141    warpmac_TxMultiplexingMode = 0;
142   
143    //Assign a null handler to all the callbacks; the user will override these after initialization
144    usr_upbutton = nullCallback;
145    usr_leftbutton = nullCallback;
146    usr_middlebutton = nullCallback;
147    usr_rightbutton = nullCallback;
148    usr_badHeaderCallback = nullCallback;
149    usr_goodHeaderCallback = nullCallback_i;
150    usr_timerCallback = nullCallback;
151    usr_dataFromNetworkLayer = nullCallback;
152    usr_mgmtPkt = nullCallback;
153    usr_uartRecvCallback = nullCallback;
154   
155    //Initialize the PHY
156    warpphy_init();
157
158    /*********************MAC Parameters*************************/
159    //Sensible defaults; user can override
160    controlStruct.maxReSend = 4;
161    controlStruct.currentCW = 0;
162    controlStruct.maxCW = 5;
163
164    controlStruct.pktBuf_phyRx = 0;
165    controlStruct.pktBuf_emacRx = 1;
166    controlStruct.dummyPacketMode = 0;
167   
168    warpphy_setBuffs(controlStruct.pktBuf_emacRx, controlStruct.pktBuf_phyRx);
169    /************************************************************/
170
171    /************************UART*****************************/
172    XUartLite_Initialize(&UartLite, XPAR_UARTLITE_0_DEVICE_ID);
173    /************************************************************/
174
175    /**************************DMA*******************************/
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);
181    if (Status != XST_SUCCESS){
182        xil_printf("DMA CfgInitialize failed!\r\n");
183        return;
184    }
185   
186    //Disable Interrupts
187    XDmaCentral_InterruptEnableSet(&DmaCentralInst, 0);
188    /************************************************************/
189   
190    /*******************Ethernet**********************************/
191    xil_printf("\tInitializing TEMAC...");
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   
200    EMAC_FIFO_BaseAddr = MacCfgPtr->LLDevBaseAddress;
201   
202    Status  = XLlTemac_ClearOptions(&TemacInstance, XTE_LENTYPE_ERR_OPTION | XTE_FLOW_CONTROL_OPTION | XTE_FCS_STRIP_OPTION);// | XTE_MULTICAST_OPTION);
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   
207    // Make sure the TEMAC is ready
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);
218    xil_printf("complete! - Link Speed %d\r\n", ENET_LINK_SPEED);
219    /************************************************************/
220
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    /************************************************************/
240#endif
241
242    /************************************************************/
243   
244    //Set the default Tx power to maximum
245    warpphy_setTxPower(0x3F);
246   
247    //Manually call the UserIO ISR once to store the initial value of the buttons/switches
248    //This is especially important for applications where the value of the DIP switch means something at boot
249    userIO_handler((void *)&GPIO_UserIO);
250   
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); 
255   
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.
258    warp_timer_setTimer(USERIO_TIMER, 0, USERIO_POLLRATE); 
259    warp_timer_setMode(USERIO_TIMER, TIMER_MODE_NOCARRIERSENSE);
260    warp_timer_start(USERIO_TIMER);
261   
262    return;
263}
264
265///@brief Top-level polling function
266///
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();
274   
275    return;
276}
277
278///@brief Polls the OFDM PHY
279///
280///Function checks the status of the PHY receiver
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;
286   
287    status = mimo_ofdmRx_getPktStatus();
288//  xil_printf("pollPhy status: 0x%x\r\n", status);
289   
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/*
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)
313    {
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");
317    }
318    return;
319*/
320}
321
322///@brief  Handler for the timer peripheral.
323///
324///The timer  handler gets called when a hardware timer set by the
325///user expires. The user's callback is called upon the completion of this event
326inline void warpmac_pollTimer() {
327   
328   
329    unsigned int timerStatus;
330   
331    timerStatus = warp_timer_getStatuses();
332   
333   
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);
341    }
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);
347    }
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);
353    }
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
373   
374    //Timer 6 is dedicated for polling User I/O
375    if((timerStatus & TIMER6_MASK & TIMER_STATUS_DONE_MASK) != 0){
376        warp_timer_resetDone(USERIO_TIMER);
377       
378        //Call the UART callback
379        warpmac_uartRecvHandler(&UartLite);
380       
381        //Call the user I/O callback (buttons, switches, etc.)
382        userIO_handler(&GPIO_UserIO);
383       
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);
388    }
389   
390    //Timer 7 is dedicated to dummy packet generation
391    if((timerStatus & TIMER7_MASK & TIMER_STATUS_DONE_MASK) != 0){
392        warp_timer_resetDone(PKTGEN_TIMER);
393        //warpmac_incrementLEDLow();
394        pktGen_allow = 1;
395   
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    }
400
401    return;
402}
403
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() {
409   
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   
416    //If we're in dummyPacket mode, and it's time to generate a new packet,
417    // call the user callback immediately, as if a packet had been received over the wire into pktBuf_emacRx
418    if(controlStruct.dummyPacketMode && startPktGeneration && pktGen_allow)
419    {
420        pktGen_allow = 0;
421//              xil_printf("dummy\r\n");
422        usr_dataFromNetworkLayer(dummyPacketLength, warpphy_getBuffAddr(controlStruct.pktBuf_emacRx)+NUM_HEADER_BYTES);
423    }
424   
425    //warpmac_setDebugGPIO(0x1);
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)
433    {
434        //FIXME: add LLFIFO and TEMAC error handling
435
436        //Clear the LLFIFO status bits
437        XIo_Out32(EMAC_FIFO_BaseAddr+XLLF_ISR_OFFSET, 0x0FFFFFFF);
438       
439        //warpmac_setDebugGPIO(0x3);
440
441        //Call the ethernet packet handler
442        emacRx_handler();
443    }
444    //warpmac_setDebugGPIO(0x0);
445
446    return;
447}
448
449///@brief "Good Header" handler for the PHY layer.
450///
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() {   
458
459//  warpmac_setDebugGPIO(0xF);
460   
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
471        rxPacket->header.length = (rxPacket->header.length) - NUM_HEADER_BYTES - NUM_PAYLOAD_CRC_BYTES - NUM_PAYLOAD_TAIL_BYTES;
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
481    if(~usr_goodHeaderCallback(rxPacket)){
482        warpphy_clearRxPktStatus();
483    }
484#if WARPMAC_SAFE_GOODHDR
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();
496#endif
497   
498//      warpmac_setDebugGPIO(0x0,0xF);
499   
500//warpmac_setDebugGPIO(0x0);   
501   
502    return;
503}
504
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;
521}
522
523///@brief Handles a received Ethernet frame
524///
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() {
528//xil_printf("emacRx handler\r\n");
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
546    //warpmac_setDebugGPIO(0x7);
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;
556   
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
571   
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    }
579    else if( (skipDataCallback == 0) && (controlStruct.dummyPacketMode == 0))
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
584        //warpmac_setDebugGPIO(0xF);
585//      xil_printf("Not dummy\r\n");
586//      xil_printf("Not dummy\r\n");
587        usr_dataFromNetworkLayer(RxPktLength, pktBufPtr);
588    }
589
590    return;
591}
592
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.
606///
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);
612   
613    return;
614}
615
616///@brief This function starts the timer in either a CSMA or non-CSMA mode.
617///@param theTimer ID of the hardware timer (in [0,7]) to start
618///@param mode TIMER_MODE_CARRIERSENSE if automatic carrier-sense pausing is desired. TIMER_MODE_NOCARRIERSENSE if received energy
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
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.
629///@param type TIMEOUT_TIMER for deterministic countdown, BACKOFF_TIMER for random exponential
630void warpmac_setTimer(int type) {
631    unsigned int numSlots;
632    int myRandNum;
633   
634    switch(type) {
635        case TIMEOUT_TIMER:
636           
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);
641            return;
642            break;
643        case BACKOFF_TIMER:
644           
645            myRandNum = randNum(controlStruct.currentCW);
646            numSlots = myRandNum;
647           
648            if(controlStruct.currentCW < controlStruct.maxCW){
649                controlStruct.currentCW = controlStruct.currentCW + 1;
650            }
651           
652            warp_timer_setTimer(BACKOFF_TIMER, controlStruct.slotTime, numSlots);
653            warp_timer_start(BACKOFF_TIMER);
654           
655            return;
656            break;
657        default:
658            //Invalid timer ID; do nothing
659            return;
660            break;
661    }
662}
663
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){
669   
670    return ((unsigned int)rand() >> (32-(N+5)));
671   
672}
673
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();
679}
680
681
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) {
690
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
708    //Wait for the DMA to be idle
709    warpmac_waitForDMA();
710
711    //Set DMA to increment src, non-increment dest addresses
712    XDmaCentral_SetControl(&DmaCentralInst, XDMC_DMACR_SOURCE_INCR_MASK);
713
714    //Transfer the packet into the LLFIFO
715    XDmaCentral_Transfer(&DmaCentralInst, 
716                            (u8 *)(thePkt),
717                            (u8 *)(EMAC_FIFO_BaseAddr + XLLF_TDFD_OFFSET),
718                            length);
719    return;
720}
721
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) {
727
728//xil_printf("startPktToNetwork\r\n");
729
730    //Wait for the DMA to finish
731    warpmac_waitForDMA();
732
733
734   
735    //Write the length to the LL_FIFO; this write initiates the TEMAC transmission
736    XIo_Out32( (EMAC_FIFO_BaseAddr + XLLF_TLF_OFFSET), length);
737   
738    return;
739}
740
741///@brief Sets user callback function for various system events
742///
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
745void warpmac_setCallback(int event, void(*handler)()) {
746
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;
785}
786
787///@brief Sets the base rate modulation order
788///
789///The base rate symbols (i.e. the header) must have an agreed upon rate between the transmitter
790///and receiver. This function sets that rate.
791///@param rate BPSK, QPSK or QAM_16
792void warpmac_setBaseRate(unsigned char rate) {
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);
795   
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);
799
800    return;
801}
802
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
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
811    if( (txMode & PHYMODE_SISO) || (txMode & PHYMODE_ALAMOUTI) )
812    {
813        warpmac_TxMultiplexingMode = 0;
814    }
815    else
816    {
817        warpmac_TxMultiplexingMode = 1;
818    }
819
820    //Call the warpphy function to actually configure the PHY antenna mode
821    warpphy_setAntennaMode(txMode, rxMode);
822
823    return 0;
824}
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
828///but does not send the packet over the air. This is used to "preload" and ACK
829///into the PHY while the data packet is still being received. This extra
830///pipelining saves on turn-around time.
831///@param packet Pointer to user's Macframe
832///@param buffer Packet buffer to send from
833void warpmac_prepPhyForXmit(Macframe* packet, unsigned char buffer) {
834   
835    unsigned short origLength;
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
839        origLength = 0;
840        packet->header.length = NUM_HEADER_BYTES;
841    }
842    else {
843        //Update the header's numBytes field to include the header, CRC and tail bytes
844        origLength = packet->header.length;
845        packet->header.length = packet->header.length + NUM_HEADER_BYTES + NUM_PAYLOAD_CRC_BYTES + NUM_PAYLOAD_TAIL_BYTES;
846    }
847   
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
850    memcpy( (void *) warpphy_getBuffAddr(buffer), (void *) packet, (size_t) NUM_HEADER_BYTES);
851   
852    //Revert the packet payload length so the user code doesn't see the MAC/PHY tweaking
853    packet->header.length = origLength;
854   
855    return;
856}
857
858///@brief Sends the current txBuffer's content.
859///
860///This function sends an existing Macframe over the air. This existing Macframe comes from the warpmac_prepPhyForXmit
861///function.
862inline void warpmac_startPhyXmit(unsigned char buffer) {
863   
864    int txResult;
865   
866    //Hold the packet detecter in reset to prevent any interfering receptions
867    //  ofdm_pktDetector_mimo_WriteReg_pktDet_reset(PKTDET_BASEADDR, 1);
868   
869    //Transmit the packet; WARPPHY disables the radio Rx, enables Tx, sends the packet, then re-enables radio Rx
870    // TXBLOCK will cause this call to block until the transmission is finished
871    warpphy_setBuffs(buffer, controlStruct.pktBuf_phyRx);
872    controlStruct.pktBuf_phyTx = buffer;
873   
874    txResult = warpphy_pktTx(TXNOBLOCK);
875   
876    if(txResult != 0)
877    {
878        xil_printf("WARPMAC tried to Tx, but PHY was busy\r\n");
879    }
880   
881    return;
882}
883
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.
888inline void warpmac_finishPhyXmit() {
889    warpphy_waitForTx();
890}
891
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) {
896
897    //Update the gloal Rx Macframe
898    rxPacket = rxFrame;
899
900    //Update the PHY Rx buffer assignment
901    controlStruct.pktBuf_phyRx = phyRxBuff;
902//  warpphy_setBuffs(controlStruct.pktBuf_emacRx, controlStruct.pktBuf_phyRx);
903    warpphy_setBuffs(controlStruct.pktBuf_phyTx, controlStruct.pktBuf_phyRx);
904
905    return;
906}
907
908///@brief Tells the PHY which piece of memory to send from
909inline void warpmac_setPHYTxBuffer(unsigned char txBuff) {
910    controlStruct.pktBuf_phyTx = txBuff;
911    warpphy_setBuffs(txBuff, controlStruct.pktBuf_phyRx);
912    return;
913}
914
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
921///@brief Decrements the remaining reSend counter for the given Macframe
922///
923///Also, it returns whether or not the counter has wrapped around the maximum
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
927int warpmac_decrementRemainingReSend(Macframe* packet){
928    int status = 1;
929   
930    unsigned char remainingReSend;
931    remainingReSend=(packet->header.remainingTx);
932   
933    if(remainingReSend>0){
934        remainingReSend--;
935    }
936   
937    else{
938        status = 0; 
939    }
940
941    packet->header.remainingTx = remainingReSend;
942
943    return status;
944}
945
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(){
951    controlStruct.currentCW = 0;
952    return;
953}
954
955///@brief Sets the maximum number of resends
956///
957///@param c Integer maximum number of resends
958inline void warpmac_setMaxResend(unsigned int c) {
959    controlStruct.maxReSend = c;
960}
961
962///@brief Sets the maximum contention window.
963///
964///@param c Maximum contention window
965inline void warpmac_setMaxCW(unsigned int c) {
966    controlStruct.maxCW = c;
967}
968
969///@brief Sets the amount of time the node is willing to wait for an acknowledgement.
970///
971///@param time Timeout duration (in microseconds)
972inline void warpmac_setTimeout(unsigned int time){
973    controlStruct.timeout = time * TIMERCLK_CYCLES_PER_USEC;
974}
975
976///@brief Sets the smallest backoff window.
977///
978///@param time Slot time duration (in microseconds)
979inline void warpmac_setSlotTime(unsigned int time){
980    controlStruct.slotTime = time * TIMERCLK_CYCLES_PER_USEC;
981}
982
983///@brief Returns a value corresponding to whether or not the node is in timeout.
984///
985///@return 1 if in TIMEOUT_TIMER, 0 otherwise
986inline int warpmac_inTimeout(){
987    return (0 != (warp_timer_getStatus(TIMEOUT_TIMER) & (TIMER_STATUS_DONE_MASK | TIMER_STATUS_RUNNING_MASK)));
988}
989
990///@brief Returns a value corresponding to whether or not the node is in backoff.
991///
992///@return 1 if in BACKOFF_TIMER, 0 otherwise
993inline int warpmac_inBackoff(){
994    return (0 != (warp_timer_getStatus(BACKOFF_TIMER) & (TIMER_STATUS_DONE_MASK | TIMER_STATUS_RUNNING_MASK)));
995}
996
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);
1005
1006    return;
1007}
1008
1009///@brief Raises a signal that is routed out to the debug header on the board
1010///
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
1013inline void warpmac_setDebugGPIO(unsigned char val, unsigned char mask) {
1014
1015    debugGPIO = ((debugGPIO&~mask)|(mask&val));
1016    //XGpio_SetDataReg(XPAR_DEBUGOUTPUTS_BASEADDR, 1, debugGPIO);
1017    return;
1018}
1019
1020
1021
1022
1023///@brief Enable the Ethernet
1024inline void warpmac_enableDataFromNetwork() {
1025    controlStruct.enableDataFromNetwork = 1;
1026    return;
1027}
1028
1029///@brief Disables the Ethernet
1030inline void warpmac_disableDataFromNetwork() {
1031    controlStruct.enableDataFromNetwork = 0;
1032    return;
1033}
1034
1035
1036///@brief Blocks on PHY transmission and returns whether packet was good or bad
1037///
1038///This function waits for the PHY to finish receiving, then checks its status
1039inline char warpmac_finishPhyRecv(){
1040    XTime startTime,currTime;
1041    unsigned char state = PHYRXSTATUS_INCOMPLETE;
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
1052    while(state == PHYRXSTATUS_INCOMPLETE) {
1053        //Blocks until the PHY reports the received packet as either good or bad
1054        state = mimo_ofdmRx_getPayloadStatus();
1055
1056//      XTime_GetTime(&currTime);
1057//      if(((currTime>>10)-(startTime>>10))>=(234375*1)){
1058//          return 2;
1059//      }
1060
1061    }
1062    return state;
1063}
1064
1065
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   
1074    uartIntStatus = XUartLite_ReadReg(InstancePtr->RegBaseAddress, XUL_STATUS_REG_OFFSET);
1075   
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    }
1083   
1084    return;
1085}
1086
1087//**************************//
1088// Dummy Packet Mode Config //
1089//**************************//
1090inline void warpmac_setDummyPacketMode(char mode) {
1091    if(mode){
1092        xil_printf("Dummy Packet Mode Enabled\r\n");
1093        controlStruct.dummyPacketMode = 1;
1094        }
1095    else
1096        {
1097        xil_printf("Dummy Packet Mode Disabled\r\n");
1098        controlStruct.dummyPacketMode = 0;
1099        }
1100    return;
1101}
1102
1103void warpmac_startPacketGeneration(unsigned int length, unsigned int interval) {
1104
1105    startPktGeneration = 1;
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);
1112    return;
1113}
1114
1115void warpmac_stopPacketGeneration() {
1116    startPktGeneration = 0;
1117   
1118    warp_timer_pause(PKTGEN_TIMER);
1119    warp_timer_resetDone(PKTGEN_TIMER);
1120}
1121
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
1125int warpmac_getMyId() {
1126
1127    //dipswState is updated automatically by the User I/O handler
1128    return dipswState;
1129}
1130
1131inline void printBytes(unsigned char* data, int length)
1132{
1133    int i;
1134
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//**************************//
1148#ifdef WARP_FPGA_BOARD_V1_2
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
1188///@brief Alternates the bottom two LEDs on the WARP board.
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
1202///@brief Alternates the top two LEDs on the WARP board.
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
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
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);
1302    }
1303   
1304    return;
1305}
1306
1307///@brief Alternates the bottom two LEDs on the WARP board.
1308void warpmac_incrementLEDLow(){
1309   
1310    WarpV4_UserIO_Leds(USERIO_BASEADDR, (ledStatesLow[ledStatesIndexLow] | ledStatesHigh[ledStatesIndexHigh]));
1311
1312    ledStatesIndexLow = (ledStatesIndexLow+1)%2;
1313}
1314
1315///@brief Alternates the top two LEDs on the WARP board.
1316void warpmac_incrementLEDHigh(){
1317   
1318    WarpV4_UserIO_Leds(USERIO_BASEADDR, (ledStatesLow[ledStatesIndexLow] | ledStatesHigh[ledStatesIndexHigh]));
1319   
1320    ledStatesIndexHigh = (ledStatesIndexHigh+1)%2;
1321}
1322
1323void warpmac_leftHex(unsigned char x){
1324   
1325    WarpV4_UserIO_WriteNumber_LeftHex(USERIO_BASEADDR, x, 0);
1326    return;
1327}
1328
1329void warpmac_middleHex(unsigned char x){
1330   
1331    WarpV4_UserIO_WriteNumber_MiddleHex(USERIO_BASEADDR, x, 0);
1332    return;
1333}
1334
1335void warpmac_rightHex(unsigned char x){
1336   
1337    WarpV4_UserIO_WriteNumber_RightHex(USERIO_BASEADDR, x, 0);
1338    return;
1339}
1340#endif
1341//**************************//
1342// FPGA Board Specific Code //
1343//***********END************//
Note: See TracBrowser for help on using the repository browser.