source: PlatformSupport/WARPMAC/warp_v3/warpmac.c

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