root/PlatformSupport/WARPMAC/warpmac.c

Revision 1101, 46.1 kB (checked in by murphpo, 2 days ago)

updated warpmac/warpphy with more warpnet demo changes

Line 
1/*! \file warpmac.c
2 \brief This framework allows for custom MAC implementations on WARP.
3 
4 @version 10
5 @author Chris Hunter and Patrick Murphy
6 
7 This code is a collection of high-level and low-level functions to enable custom MAC layers on warp.
8 At the highest level, these functions provide many MAC commonalities like carrier sensing and random
9 exponential backoffs. At the lowest level, these functions wrap around hardware drivers to provide
10 give user code access to features of the PHY, radio controller, and many other peripherals.
11 */
12
13#include "xparameters.h"
14#include "xstatus.h"
15#include "errno.h"
16#include "xexception_l.h"
17#include "stddef.h"
18#include "stdio.h"
19#include "string.h"
20#include "xdmacentral.h"
21#include "xdmacentral_l.h"
22#include "xemaclite.h"
23#include "xemaclite_l.h"
24#include "xuartlite.h"
25#include "xuartlite_l.h"
26#include "xintc.h"
27#include "xgpio.h"
28#include "warpmac.h"
29#include "ofdm_txrx_mimo_regMacros.h"
30#include "ofdm_agc_mimo_regMacros.h"
31#include "ofdm_pktdetector_mimo_regMacros.h"
32#include "warp_timer_regMacros.h"
33#include "radio_controller_basic.h"
34#include "radio_controller_ext.h"
35#include "radio_controller_adv.h"
36#include "warp_userio.h"
37#include "warpphy.h"
38#include "warpnet.h"
39
40//Instantiates the Maccontrol control structure
41Maccontrol controlStruct;
42
43unsigned char timerIntStatus;
44
45//Instantiates the general-purpose input-output peripheral driver
46static XGpio GPIO_UserIO;
47
48//Instantiates the Xilinx interrupt controller peripheral driver
49static XIntc Intc;
50
51//Instantiates the UART driver instance
52static XUartLite UartLite;
53unsigned char ReceiveBuffer[16];
54
55//Instantiates Ethernet MAC lite
56static XEmacLite EmacLiteInstance;   /* Instance of the EmacLite */
57static XEmacLite_Config *EmacLiteConfigPtr;
58unsigned char currentEmacBuff;
59
60//Instantiates central DMA controller
61static XDmaCentral DmaCentralInst;
62static XDmaCentral_Config *DMAConfigPtr;
63
64//Points to a user-provided Macframe where parsed header information will be copied to
65Macframe* rxPacket;
66//Points to a user-provided Macframe where parsed header information will be copied from
67Macframe* txPacket;
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
84//Global variable to track SISO vs. MIMO mode
85unsigned char warpmac_sisoMode;
86
87//These the addresses pointed to by these variables are set by the
88//user via the callback registration functions
89
90void (*usr_upbutton) ();
91void (*usr_leftbutton) ();
92void (*usr_middlebutton) ();
93void (*usr_rightbutton) ();
94void (*usr_badHeaderCallback) ();
95void (*usr_goodHeaderCallback) ();
96void (*usr_timerCallback) ();
97void (*usr_emacCallback) ();
98void (*usr_uartRecvCallback) ();
99void (*usr_rxDoneCallback) ();
100
101//Null handler. Catches calls if user fails to attach callbacks.
102void nullCallback(void* param){};
103
104///@brief Initializes the framework and all hardware peripherals.
105///
106///This function sets reasonable default values for many of the parameters of the MAC, configures
107///interrupts and exceptions, configures Ethernet, and finally initializes the custom peripherals
108///such as the radio controller, the PHY, the packet detector, and the automatic gain control block.
109void warpmac_init() {
110       
111        xil_printf("Initializing WARPMAC v10:\r\n");
112
113        //Initialize global variables
114        LEDHEX_Outputs = 0;
115        ledStates = 0;
116        leftHex = 0;
117        rightHex = 0;
118        ledStatesLow[0] = 1;
119        ledStatesLow[1] = 2;
120        ledStatesIndexLow = 0;
121        ledStatesHigh[0] = 4;
122        ledStatesHigh[1] = 8;
123        ledStatesIndexHigh = 0;
124        warpmac_sisoMode = 1;
125
126        XStatus Status;
127       
128        //Assign a null handler to all the interrupts; the user can re-define these later if desired
129        usr_upbutton = nullCallback;
130        usr_leftbutton = nullCallback;
131        usr_middlebutton = nullCallback;
132        usr_rightbutton = nullCallback;
133        usr_badHeaderCallback = nullCallback;
134        usr_goodHeaderCallback = nullCallback;
135        usr_timerCallback = nullCallback;
136        usr_uartRecvCallback = nullCallback;
137        usr_rxDoneCallback = nullCallback;
138       
139        //Initialize the PHY
140        warpphy_init();
141       
142        /*********************MAC Parameters*************************/
143        xil_printf("    Initializing controlStruct...");
144        controlStruct.maxReSend = 4;
145        controlStruct.currBackoff = 0;
146        controlStruct.maxBackoff = 5;
147        controlStruct.rxBuffIndex = 2;
148        warpphy_setBuffs(controlStruct.txBuffIndex, controlStruct.rxBuffIndex);
149        xil_printf("complete!\r\n");
150        /************************************************************/
151       
152        /************************UART*****************************/
153        XUartLite_Initialize(&UartLite, XPAR_UARTLITE_0_DEVICE_ID);
154//    XUartLite_SetSendHandler(&UartLite, warpmac_uartSendHandler, &UartLite);
155//  XUartLite_SetRecvHandler(&UartLite, warpmac_uartRecvHandler, &UartLite);
156
157    XUartLite_EnableInterrupt(&UartLite);
158        /************************************************************/
159
160        /************************USER IO*****************************/
161        xil_printf("    Initializing UserIO...");
162        //Initialize the UserIO GPIO core
163        Status = XGpio_Initialize(&GPIO_UserIO, XPAR_USER_IO_DEVICE_ID);
164       
165        //We use both channels in the GPIO core- one for inputs, one for outputs
166        XGpio_SetDataDirection(&GPIO_UserIO, USERIO_CHAN_INPUTS, USERIO_MASK_INPUTS);
167        XGpio_SetDataDirection(&GPIO_UserIO, USERIO_CHAN_OUTPUTS, 0);
168       
169        //Make sure the LEDs are all off by default
170        XGpio_DiscreteClear(&GPIO_UserIO, USERIO_CHAN_OUTPUTS, USERIO_MASK_OUTPUTS);
171       
172        //Configure & enable the GPIO interrupt output
173        // The interrupt is only enabled for the GPIO input channel
174    XGpio_InterruptEnable(&GPIO_UserIO, USERIO_CHAN_INPUTS);
175    XGpio_InterruptGlobalEnable(&GPIO_UserIO);
176        xil_printf("complete!\r\n");
177        /************************************************************/
178       
179        /***********************Interrupts***************************/
180        xil_printf("    Initializing Interrupts...");
181        //Initialize the interrupt controller
182        XIntc_Initialize(&Intc, INTC_DEVICE_ID);
183        XIntc_SetIntrSvcOption(XPAR_XPS_INTC_0_BASEADDR,XIN_SVC_ALL_ISRS_OPTION);
184       
185        //Connect the interrupt controller to the interrupt handlers
186        XIntc_Connect(&Intc, XPAR_XPS_INTC_0_OFDM_TXRX_MIMO_PLBW_0_RX_INT_BADPKT_INTR,(XInterruptHandler)phyRx_badHeader_int_handler, NULL); //Workaround... bad PHY state
187        XIntc_Connect(&Intc, XPAR_XPS_INTC_0_USER_IO_IP2INTC_IRPT_INTR, (XInterruptHandler)userIO_int_handler, &GPIO_UserIO);
188        XIntc_Connect(&Intc, XPAR_XPS_INTC_0_OFDM_TXRX_MIMO_PLBW_0_RX_INT_BADHEADER_INTR,(XInterruptHandler)phyRx_badHeader_int_handler, NULL);
189        XIntc_Connect(&Intc, XPAR_XPS_INTC_0_OFDM_TXRX_MIMO_PLBW_0_RX_INT_GOODHEADER_INTR,(XInterruptHandler)phyRx_goodHeader_int_handler, NULL);
190        XIntc_Connect(&Intc, XPAR_XPS_INTC_0_WARP_TIMER_PLBW_0_TIMEREXPIRE_INTR,(XInterruptHandler)timer_int_handler, NULL);
191        XIntc_Connect(&Intc, XPAR_XPS_INTC_0_RS232_INTERRUPT_INTR, (XInterruptHandler)warpmac_uartRecvHandler, (void *)&UartLite);
192
193        xil_printf("complete!\r\n");
194        /************************************************************/
195       
196        /*************************Ethernet***************************/
197        xil_printf("    Initializing Ethernet...");
198        //Initialize the EMAC config struct
199        EmacLiteConfigPtr = XEmacLite_LookupConfig(EMACLITE_DEVICE_ID);
200        if (EmacLiteConfigPtr == NULL){
201                ErrorTrap("EMAClite LookupConfig failed!\r\n");
202                return;
203        }
204       
205        Status = XEmacLite_CfgInitialize(&EmacLiteInstance, EmacLiteConfigPtr, EmacLiteConfigPtr->BaseAddress);
206        if (Status != XST_SUCCESS){
207                ErrorTrap("EMAClite CfgInitialize failed!\r\n");
208                return;
209        }
210
211        XEmacLite_FlushReceive(&EmacLiteInstance);
212        currentEmacBuff = PING;
213        xil_printf("complete!\r\n");
214        /************************************************************/
215       
216        /**************************DMA*******************************/
217        //Lookup the DMA configuration information
218        DMAConfigPtr = XDmaCentral_LookupConfig(DMA_CTRL_DEVICE_ID);
219       
220        //Initialize the config struct
221        Status = XDmaCentral_CfgInitialize(&DmaCentralInst, DMAConfigPtr, DMAConfigPtr->BaseAddress);
222        if (Status != XST_SUCCESS){
223                ErrorTrap("DMA CfgInitialize failed!\r\n");
224                return;
225        }
226       
227        //Set the DMA addressing options
228        // XDMC_DMACR_SOURCE_INCR_MASK - increment src address on each beat
229        // XDMC_DMACR_DEST_INCR_MASK - increment dst address on each beat
230        XDmaCentral_SetControl(&DmaCentralInst, XDMC_DMACR_SOURCE_INCR_MASK | XDMC_DMACR_DEST_INCR_MASK);
231        /************************************************************/
232       
233        /*************************Ethernet***************************/
234        //Start the interrupt controller and enable the interrupts
235        XIntc_Start(&Intc, XIN_REAL_MODE);
236        XIntc_Enable(&Intc, XPAR_XPS_INTC_0_OFDM_TXRX_MIMO_PLBW_0_RX_INT_BADPKT_INTR);
237        XIntc_Enable(&Intc, XPAR_XPS_INTC_0_OFDM_TXRX_MIMO_PLBW_0_RX_INT_BADHEADER_INTR);
238        XIntc_Enable(&Intc, XPAR_XPS_INTC_0_OFDM_TXRX_MIMO_PLBW_0_RX_INT_GOODHEADER_INTR);
239    XIntc_Enable(&Intc, XPAR_XPS_INTC_0_USER_IO_IP2INTC_IRPT_INTR);
240        XIntc_Enable(&Intc, XPAR_XPS_INTC_0_WARP_TIMER_PLBW_0_TIMEREXPIRE_INTR);
241        XIntc_Enable(&Intc, XPAR_XPS_INTC_0_RS232_INTERRUPT_INTR);
242        /************************************************************/
243       
244        /************************Exceptions**************************/
245        xil_printf("    Enabling Exceptions...");
246        XExc_Init();
247        XExc_RegisterHandler(XEXC_ID_NON_CRITICAL_INT,(XExceptionHandler)XIntc_InterruptHandler,&Intc);
248        XExc_mEnableExceptions(XEXC_NON_CRITICAL);
249        xil_printf("complete!\r\n");
250        /************************************************************/
251       
252        /*********************Final EMAC/DMA*************************/
253        //Clear any stale EMAC interrupts
254        XEmacLite_FlushReceive(&EmacLiteInstance);
255        //Disable the EMAC interrupt output
256        XEmacLite_DisableInterrupts(&EmacLiteInstance);
257        //Disable Interrupts
258        XDmaCentral_InterruptEnableSet(&DmaCentralInst, 0);
259        /************************************************************/
260       
261       
262        //Manually call the UserIO ISR once to store the initial value of the buttons/switches
263        //This is especially important for applications where the value of the DIP switch means something at boot
264        userIO_int_handler((void *)&GPIO_UserIO);
265       
266}
267
268///@brief "Good Header" Interrupt handler for the PHY layer.
269///
270///This function is the ISR for the RX physical layer peripheral.
271///This function is only called if the packet header has no bit errors
272///(i.e., the packet header passes CRCs in the PHY). This interrupt will
273///be asserted *before* the packet is fully received. This function assumes
274///the user's callback will poll the PHY to determine if the packet is eventually
275///good or bad
276void phyRx_goodHeader_int_handler() {   
277        unsigned int numPayloadBytes;
278        int length;
279       
280        //Copy the received packet's header into the rxPacket struct
281        memcpy((unsigned char *)(&(rxPacket->header)), (unsigned char *)warpphy_getBuffAddr(controlStruct.rxBuffIndex), (size_t)NUM_HEADER_BYTES);
282       
283        //Strip the header and checksum from the total number of bytes reported to user code
284        if(rxPacket->header.length == NUM_HEADER_BYTES){
285                //Header-only packet (like an ACK) has 0 payload bytes
286                rxPacket->header.length = 0;
287        }
288        else{
289                //Other packets have payload bytes; subtract off header and 4-byte payload checksum lengths
290                rxPacket->header.length = rxPacket->header.length - NUM_HEADER_BYTES - 4;
291        }
292       
293        //If the Rx packet is too big, ignore the payload
294        // This should never happen; the Tx code will never send a pkt bigger than Ethernet MTU
295        if(rxPacket->header.length>MY_XEM_MAX_FRAME_SIZE){
296                rxPacket->header.length = 0;
297        }
298       
299        //Pass the received packet to the user handler
300        usr_goodHeaderCallback(rxPacket);
301       
302        unsigned char state = INCOMPLETE;
303        //Poll PHY to insure ISR does not quit too early
304                                while(state==INCOMPLETE){
305                                        //Blocks until the PHY reports the received packet as either good or bad
306                                        state = warpphy_pollRxStatus();
307                                }
308                               
309        //Clears every interrupt output of the PHY
310        warpphy_clearRxInterrupts();
311        XIntc_Acknowledge(&Intc,XPAR_XPS_INTC_0_OFDM_TXRX_MIMO_PLBW_0_RX_INT_GOODHEADER_INTR);
312
313        //Call the user function after everything is done receiving the packet
314        usr_rxDoneCallback();
315
316        return;
317}
318
319///@brief "Bad" Interrupt handler for the PHY layer.
320///
321///This function is the ISR for the RX physical layer peripheral.
322///This function is only called if the packet fails CRC. The received
323///packet is passed to the user's callback, and the PHY is reset.
324void phyRx_badHeader_int_handler(){
325        //Bad packets, by definition, have no payload bytes which can be trusted
326        // The user handler is called with no arguments, since there is no real packet data to process
327        // If the header happend to be good but the payload bad, the user should use the good header
328        // interrupt to process the header
329        usr_badHeaderCallback();
330       
331        //Clear the good/bad packet interrupts in the PHY to re-enable packet reception
332        warpphy_clearRxInterrupts();
333       
334        XIntc_Acknowledge(&Intc,XPAR_XPS_INTC_0_OFDM_TXRX_MIMO_PLBW_0_RX_INT_BADHEADER_INTR);
335
336        //Call the user function after everything is done receiving the packet
337        usr_rxDoneCallback();
338
339        return;
340}
341
342
343///@brief Handles the reception of packets from the emac core.
344///
345///This function is the ISR for the EMAC. It starts a DMA transfer
346///of the payload into the PHY's packet buffer and calls the user's
347///callback to further processing.
348///Note: The function name is a bit of a misnomer with this release
349///of the reference design. Interrupts have been removed for performance
350///reasons. However, in the interest of symmetry and legacy, the
351///"int_handler" moniker is left in place.
352void emacRx_int_handler(void *CallBackRef){
353        XIntc_Acknowledge(&Intc,XPAR_XPS_INTC_0_ETHERNET_MAC_IP2INTC_IRPT_INTR);
354       
355        int waitForDMA = 0;
356       
357        XEmacLite *EmacLiteInstPtr;
358        unsigned int RxPktBaseAddress,RxPktBaseAddressPing,RxPktBaseAddressPong;
359        unsigned int StatusRegister,StatusRegister2;
360        unsigned short RxPktLength, RxPktLengthType;
361       
362        //Convert the arg to something useful
363        EmacLiteInstPtr = (XEmacLite *)CallBackRef;
364       
365        //Lookup which EMAC Rx pkt buffer has the new packet
366        RxPktBaseAddressPing = (EmacLiteInstPtr)->EmacLiteConfig.BaseAddress;
367        StatusRegister = XEmacLite_mGetRxStatus(RxPktBaseAddressPing);
368       
369        if ((currentEmacBuff==PING) && ((StatusRegister & XEL_RSR_RECV_DONE_MASK) == XEL_RSR_RECV_DONE_MASK)) {
370                RxPktBaseAddress = RxPktBaseAddressPing;
371                StatusRegister &= ~XEL_RSR_RECV_DONE_MASK;
372                XEmacLite_mSetRxStatus(RxPktBaseAddress, StatusRegister);
373                currentEmacBuff = PONG;
374        }
375       
376        else{
377               
378                RxPktBaseAddressPong = RxPktBaseAddressPing + XEL_BUFFER_OFFSET;
379                StatusRegister2 = XEmacLite_mGetRxStatus(RxPktBaseAddressPong);
380               
381                if ((currentEmacBuff==PONG)&&((StatusRegister2 & XEL_RSR_RECV_DONE_MASK) == XEL_RSR_RECV_DONE_MASK)) {
382                        RxPktBaseAddress = RxPktBaseAddressPong;
383                        StatusRegister2 &= ~XEL_RSR_RECV_DONE_MASK;
384                        XEmacLite_mSetRxStatus(RxPktBaseAddress, StatusRegister2);
385                        currentEmacBuff= PING;
386                }
387               
388                else{
389                        //Out of sync... should be corrected next packet
390                }
391               
392               
393        }
394       
395        //From here on out, RxPktBaseAddress is used... it is either PING or PONG
396       
397
398       
399       
400        //Extract the EtherType field (bytes[12:13]) from the received frame
401        RxPktLengthType = XEmacLite_mGetReceiveDataLength(RxPktBaseAddress);
402       
403        //Some Ethernet frames use bytes[12:13] for length; others use it for type
404        // If the field is > 0x600, it's a type; otherwise it's a length
405        // See http://en.wikipedia.org/wiki/Ethernet_II_framing for details
406        // The code below is borrowed from xemaclite.c
407        if (RxPktLengthType > XEL_MAX_FRAME_SIZE){      //length field is type, not length
408                if (RxPktLengthType == XEL_ETHER_PROTO_TYPE_IP){
409                        //The packet is a an IP Packet
410                        // Calculate the length based on the IP header's length field
411                        RxPktLength = ((XEmacLite_mReadReg((RxPktBaseAddress),
412                                                                                           XEL_HEADER_IP_LENGTH_OFFSET +
413                                                                                           XEL_RXBUFF_OFFSET) >>
414                                                        XEL_HEADER_SHIFT) & (
415                                                                                                 XEL_RPLR_LENGTH_MASK_HI |
416                                                                                                 XEL_RPLR_LENGTH_MASK_LO));
417                       
418                        RxPktLength += XEL_HEADER_SIZE + XEL_FCS_SIZE;
419                }
420               
421                else if (RxPktLengthType == XEL_ETHER_PROTO_TYPE_ARP){
422                        //The packet is an ARP Packet
423                        // Update the length (every ARP pkt is the same length)
424                        RxPktLength = XEL_ARP_PACKET_SIZE + XEL_HEADER_SIZE + XEL_FCS_SIZE;
425                }
426               
427#ifdef WARPNET_ETHTYPE_SVR2NODE
428                else if (RxPktLengthType == WARPNET_ETHTYPE_SVR2NODE){
429                        //The packet is a WARPnet packet
430                        waitForDMA = 1;
431                        warpnetEthernetPktHeader* thePkt;
432                        thePkt = (warpnetEthernetPktHeader*)(RxPktBaseAddress+XEL_RXBUFF_OFFSET);
433                        RxPktLength = thePkt->pktLength;
434                        //xil_printf("Got a WARPnet pkt on ethernet: %d bytes\r\n", RxPktLength);
435                }
436#endif
437                else{
438                        //Type is something else (non-IP, non-ARP)
439                        //Punt on extracting the length here; tell the user
440                        // it's the full MTU and let them handle it
441                        //xil_printf("Got an unknown ethernetType: %x\r\n", RxPktLength);
442                        RxPktLength = XEL_MAX_FRAME_SIZE;
443                }
444        }
445        else {  //Ethernet frame length field really is length
446               
447                //Use the length in the frame, plus the header and trailer
448                RxPktLength = RxPktLengthType + XEL_HEADER_SIZE + XEL_FCS_SIZE;
449        }
450       
451        //Initiate the DMA transfer from EMAC rx buffer to OFDM PHY pkt buffer
452        if(XDmaCentral_GetStatus(&DmaCentralInst) & XDMC_DMASR_BUSY_MASK == XDMC_DMASR_BUSY_MASK) {
453                //DMA is busy cooking on something... just drop the packet
454                return;
455        }
456       
457        //Start the DMA
458        XDmaCentral_Transfer(&DmaCentralInst, (u8 *)RxPktBaseAddress+XEL_RXBUFF_OFFSET, (u8 *)warpphy_getBuffAddr(controlStruct.txBuffIndex)+NUM_HEADER_BYTES, RxPktLength);
459       
460        if(waitForDMA)
461        {
462                u32 RegValue;
463                //Wait until the DMA transfer is done by checking the Status register
464                do {
465                        RegValue = XDmaCentral_GetStatus(&DmaCentralInst);
466                }
467                while ((RegValue & XDMC_DMASR_BUSY_MASK) == XDMC_DMASR_BUSY_MASK);
468        }
469       
470        //else...
471        //This is a bit fast and loose. The DMA transfer does not block, which means the payload will not be completely copied into the PHY before the user's
472        //callback is executed. However, the PHY is much slower than a DMA transfer. Therefore, even if it begins transmitting, the DMA will write the last bytes
473        //before the PHY even gets to them.
474       
475        usr_emacCallback(RxPktLength,warpphy_getBuffAddr(controlStruct.txBuffIndex)+NUM_HEADER_BYTES);
476       
477        return;
478}
479
480///@brief ErrorTrap
481///This is a wrapper around a print statement. The purpose of this function is provide
482///a single line to comment in or out to disable or enable debug messages.
483void ErrorTrap(char *Message){
484        xil_printf("%s\r\n", Message);
485        return;
486}
487
488///@brief Interrupt handler for the User I/O.
489///
490///This is a low-priority interrupt because it is primarily used for debugging purposes.
491///The various user callbacks are executed, depending upon which button was depressed. Additionally,
492///the board's dip switches also trigger this ISR, though the framework does not currently call user
493///code in this event. We assume that dipswitches are currently only used for beginning-of-time
494///state assignments. This will change in future releases.
495void userIO_int_handler(void *InstancePtr){
496       
497        static unsigned int previousAssertedInputs;
498        unsigned int assertedInputs;
499        unsigned int newAssertedInputs;
500       
501        //Re-interpret the generic input pointer as a GPIO driver instance
502    XGpio *GpioPtr = (XGpio *)InstancePtr;
503       
504        //Disable the GPIO core's interrupt output
505    XGpio_InterruptDisable(GpioPtr, USERIO_CHAN_INPUTS);
506       
507        //Read the GPIO inputs; each 1 is a currently-asserted input bit
508        assertedInputs = XGpio_DiscreteRead(&GPIO_UserIO, USERIO_CHAN_INPUTS) & USERIO_MASK_INPUTS;
509       
510        //XOR the current active bits with the previously active bits
511        newAssertedInputs = (assertedInputs ^ previousAssertedInputs) & assertedInputs;
512        previousAssertedInputs = assertedInputs;
513       
514        //Check whether push buttons or DIP switch triggered the interrupt
515        // We assume a user callback per button, and another for the DIP switch
516        if(newAssertedInputs & USERIO_MASK_PBC) usr_middlebutton();
517        if(newAssertedInputs & USERIO_MASK_PBR) usr_rightbutton();
518        if(newAssertedInputs & USERIO_MASK_PBL) usr_leftbutton();
519        if(newAssertedInputs & USERIO_MASK_PBU) usr_upbutton();
520        if(newAssertedInputs & USERIO_MASK_DIPSW) {
521                dipswState = USERIO_MAP_DIPSW(assertedInputs);
522        }
523       
524        //Clear, acknowledge and re-enable the GPIO interrupt output
525        XGpio_InterruptClear(GpioPtr, USERIO_CHAN_INPUTS);
526        XIntc_Acknowledge(&Intc, XPAR_XPS_INTC_0_USER_IO_IP2INTC_IRPT_INTR);
527        XGpio_InterruptEnable(GpioPtr, USERIO_CHAN_INPUTS);
528        return;
529}
530
531///@brief Interrupt handler for the timer peripheral.
532///
533///The timer interrupt handler gets called when a hardware timer set by the
534///user expires. The user's callback is called upon the completion of this event
535void timer_int_handler() {
536        timerIntStatus = warp_timer_getInterrupts();
537        warp_timer_resetInterrupts();
538       
539        //Call User Function
540        usr_timerCallback(controlStruct.timerType);
541       
542        XIntc_Acknowledge(&Intc,XPAR_XPS_INTC_0_WARP_TIMER_PLBW_0_TIMEREXPIRE_INTR);
543        return;
544}
545
546///@brief This function stops the timer.
547///
548///Additionally it will return the amount of time remaining before expiration.
549///@return Number of clock cycles remaining before expiration.
550int warpmac_clearTimer(){
551        int time;
552        time = warp_timer_timeLeft(0);
553        warp_timer_stop(0);
554        controlStruct.currBackoff=0;
555        return time;
556}
557
558///@brief This function sets the timer to countdown for a given number of clock cycles.
559///@param clocks Number of 40MHz clock cycles to countdown from
560void warpmac_setTimerVal(Xuint32 clocks){
561        //Additional factor of two comes into play due to the fact that we moved the core to the 80MHz PLB when it used to be on the 40MHz OPB
562        warp_timer_setVal(0, 2*clocks);
563}
564
565///@brief This function starts the timer in either a CSMA or non-CSMA mode.
566///@param mode #ENABLECSMA if automatic carrier-sense pausing is desired. #DISABLECSMA if received energy
567///is to be ignored.
568void warpmac_startTimer(unsigned char mode){
569        warp_timer_setMode(0,mode);
570        warp_timer_start(0);
571}
572
573///@brief Generates a uniform random value between [0,(2^N - 1)], where N is a positive integer
574///
575///Used internally by WARPMAC for random exponential backoffs.
576///@param N Window size for draw of uniform random value.
577unsigned int randNum(unsigned int N){
578       
579        if(N<6) return ((unsigned int) rand()) >> (32-(N+4)); //N+6
580        else return ((unsigned int) rand()) >> (32-(10)); //N+6
581       
582}
583
584///@brief Returns a value corresponding to the instantaneous channel condition {busy or idle}
585///
586///@return 1 if medium is idle, 0 if medium is busy
587unsigned int warpmac_carrierSense(){
588       
589        /* Two reasons for declaring the medium busy:
590         1: The Rx PHY is actively receiving a packet.
591         This only happens if packet detection and AGC already triggered, and a
592         good/bad pkt interrupt will soon be asserted
593         2: The packet detector indicates the average RSSI has exceeded the carrier sense
594         threshold sometime in the last DIFS period
595         */
596        return ofdm_pktDetector_mimo_ReadReg_pktDet_idleDifs(PKTDET_BASEADDR) && !(0x80000000 & ofdm_txrx_mimo_ReadReg_Rx_packet_done(OFDM_BASEADDR));
597}
598
599///@brief Function is responsible for high-level MAC timing
600///
601///This function is used by user code, and in turn calls the other timer functions.
602///It is capable of initiating either a deterministic timeout, or a random backoff.
603///@param type #TIMEOUT for deterministic countdown, #BACKOFF for random exponential
604void warpmac_setTimer(int type){
605        unsigned int setTime;
606        int myRandNum;
607        int retval;
608        switch(type) {
609                case TIMEOUT:
610                        controlStruct.timerType=TIMEOUT;
611                        setTime = controlStruct.timeout*40;
612                        warpmac_setTimerVal(setTime);
613                        warpmac_startTimer(DISABLECSMA);
614                        return;
615                        break;
616                case BACKOFF:
617                        controlStruct.timerType=BACKOFF;
618                        myRandNum = randNum(controlStruct.currBackoff);
619                        setTime = myRandNum*controlStruct.slotTime*40;
620                        if(controlStruct.currBackoff < controlStruct.maxBackoff){
621                                controlStruct.currBackoff = controlStruct.currBackoff + 1;
622                        }
623                        /* Set the reset value of the timer (seconds * 40,000,000) */
624                        if(setTime != 0){
625                                warpmac_setTimerVal(setTime);
626                                warpmac_startTimer(ENABLECSMA);
627                                return;
628                        }
629                        if(setTime == 0){
630                                usr_timerCallback(controlStruct.timerType);
631                        }
632                        break;
633                       
634        }
635}
636
637///@brief Pushes the given Macframe over ethernet - must come after warpmac_prepEmacForXmit
638///@param packet Pointer to user's Macframe
639///@return #XST_FAILURE or #XST_SUCCESS
640int warpmac_startEmacXmit(Macframe* packet){
641        u32 RegValue;
642        /*
643         * Wait until the DMA transfer is done by checking the Status register
644         */
645        do {
646                RegValue = XDmaCentral_GetStatus(&DmaCentralInst);
647        }
648        while ((RegValue & XDMC_DMASR_BUSY_MASK) == XDMC_DMASR_BUSY_MASK);
649       
650       
651        /*
652         * If Bus error occurs, return Failure.
653         */
654        if (RegValue &  (XDMC_DMASR_BUS_ERROR_MASK)) {
655                //      warpmac_incrementLEDLow();
656                return XST_FAILURE;
657        }
658       
659        //EMAC should have a complete packet; start the wired Tx
660        u32 Register;
661        //Copy back into emac;
662        u32 BaseAddress;
663       
664        /*
665         * Determine the expected TX buffer address
666         */
667        BaseAddress = XEmacLite_mNextTransmitAddr((XEmacLite *)&EmacLiteInstance);
668       
669        /*
670         * Determine if the expected buffer address is empty
671         */
672        Register = XEmacLite_mGetTxStatus(BaseAddress);
673       
674        /*
675         * If the expected buffer is available, fill it with the provided data
676         * Align if necessary.
677         */
678        if (XEmacLite_mIsTxDone(BaseAddress)==TRUE) {
679               
680                /*
681                 * Switch to next buffer if configured
682                 */
683                if (EmacLiteInstance.EmacLiteConfig.TxPingPong != 0) {
684                        EmacLiteInstance.NextTxBufferToUse ^= XEL_BUFFER_OFFSET;
685                }
686               
687                unsigned int length;
688                length = (packet->header.length)-4;
689                /*
690                 * The frame is in the buffer, now send it
691                 */
692                XEmacLite_mWriteReg(BaseAddress, XEL_TPLR_OFFSET,
693                                                        (length & (XEL_TPLR_LENGTH_MASK_HI |
694                                                                           XEL_TPLR_LENGTH_MASK_LO)));
695               
696                /*
697                 * Update the Tx Status Register to indicate that there is a
698                 * frame to send.
699                 * If the interrupts are enabled then set the
700                 * XEL_TSR_XMIT_ACTIVE_MASK flag which is used by the interrupt
701                 * handler to call the callback function provided by the user
702                 * to indicate that the frame has been transmitted.
703                 */
704                Register = XEmacLite_mGetTxStatus(BaseAddress);
705                Register |= XEL_TSR_XMIT_BUSY_MASK;
706                if ((Register & XEL_TSR_XMIT_IE_MASK) != 0) {
707                        Register |= XEL_TSR_XMIT_ACTIVE_MASK;
708                }
709                XEmacLite_mSetTxStatus(BaseAddress, Register);
710        }
711        return XST_SUCCESS;
712}
713
714int warpmac_sendRawEthernetPacket(void* packet, unsigned int numBytes)
715{
716        u32 emacTxBufAddr, RegValue;
717
718        emacTxBufAddr = XEmacLite_mNextTransmitAddr(&EmacLiteInstance);
719       
720        RegValue = XDmaCentral_GetStatus(&DmaCentralInst);
721       
722        //If Bus error occurs, return Failure.
723        if (RegValue &  (XDMC_DMASR_BUS_ERROR_MASK)) {
724                ErrorTrap("DMA threw bus error!\r\n");
725                return XST_FAILURE;
726        }
727
728        XDmaCentral_Transfer(&DmaCentralInst, (u8 *)(packet), (u8 *)emacTxBufAddr, (numBytes));
729       
730        //Wait until the DMA transfer is done by checking the Status register
731        do {
732                RegValue = XDmaCentral_GetStatus(&DmaCentralInst);
733        }
734        while ((RegValue & XDMC_DMASR_BUSY_MASK) == XDMC_DMASR_BUSY_MASK);
735       
736        /*
737         * If Bus error occurs, return Failure.
738         */
739        if (RegValue &  (XDMC_DMASR_BUS_ERROR_MASK)) {
740                //      warpmac_incrementLEDLow();
741                xil_printf("warpmac_sendRawEthernetPacket failed: XDMC_DMASR_BUS_ERROR_MASK\r\n");
742                return XST_FAILURE;
743        }
744       
745        //EMAC should have a complete packet; start the wired Tx
746        u32 Register;
747        //Copy back into emac;
748        u32 BaseAddress;
749       
750        Register = XEmacLite_mGetTxStatus(emacTxBufAddr);
751       
752        //Wait for the EMAC to be ready
753        while(XEmacLite_mIsTxDone(emacTxBufAddr)!=TRUE) {}
754
755        //Switch to next buffer if configured
756        if (EmacLiteInstance.EmacLiteConfig.TxPingPong != 0) {
757                EmacLiteInstance.NextTxBufferToUse ^= XEL_BUFFER_OFFSET;
758        }
759       
760        //The frame is in the buffer, now send it
761        XEmacLite_mWriteReg(emacTxBufAddr, XEL_TPLR_OFFSET,
762                                                ( (numBytes+4) & (XEL_TPLR_LENGTH_MASK_HI |
763                                                                   XEL_TPLR_LENGTH_MASK_LO)));
764       
765        /*
766         * Update the Tx Status Register to indicate that there is a
767         * frame to send.
768         * If the interrupts are enabled then set the
769         * XEL_TSR_XMIT_ACTIVE_MASK flag which is used by the interrupt
770         * handler to call the callback function provided by the user
771         * to indicate that the frame has been transmitted.
772         */
773        Register = XEmacLite_mGetTxStatus(emacTxBufAddr);
774        Register |= XEL_TSR_XMIT_BUSY_MASK;
775        if ((Register & XEL_TSR_XMIT_IE_MASK) != 0) {
776                Register |= XEL_TSR_XMIT_ACTIVE_MASK;
777        }
778        XEmacLite_mSetTxStatus(emacTxBufAddr, Register);
779
780        return XST_SUCCESS;
781}
782
783///@brief Starts a DMA transfer from the RX PHY to the EMAC for Ethernet transmission
784///@param packet Pointer to user's Macframe
785void warpmac_prepEmacForXmit(Macframe* packet){
786        unsigned int length;
787        length = (packet->header.length)-4;
788        u32 BaseAddress,RegValue;
789        BaseAddress = XEmacLite_mNextTransmitAddr(&EmacLiteInstance);
790       
791       
792        RegValue = XDmaCentral_GetStatus(&DmaCentralInst);
793       
794        /*
795         * If Bus error occurs, return Failure.
796         */
797        if (RegValue &  (XDMC_DMASR_BUS_ERROR_MASK)) {
798                ErrorTrap("Bus Error\r\n");
799        }
800        XDmaCentral_Transfer(&DmaCentralInst, (u8 *)(warpphy_getBuffAddr(controlStruct.rxBuffIndex)+NUM_HEADER_BYTES), (u8 *)BaseAddress, length);
801       
802}
803
804///@brief Attaches user callback to up button
805///@param handler pointer to user's callback
806void warpmac_setUpButtonCallback(void(*handler)()){
807        usr_upbutton = handler;
808}
809
810///@brief Attaches user callback to left button
811///@param handler pointer to user's callback
812void warpmac_setLeftButtonCallback(void(*handler)()){
813        usr_leftbutton = handler;
814}
815
816///@brief Attaches user callback to right button
817///@param handler pointer to user's callback
818void warpmac_setRightButtonCallback(void(*handler)()){
819        usr_rightbutton = handler;
820}
821
822///@brief Attaches user callback to middle button
823///@param handler pointer to user's callback
824void warpmac_setMiddleButtonCallback(void(*handler)()){
825        usr_middlebutton = handler;
826}
827
828///@brief Attaches user callback to timer
829///@param handler pointer to user's callback
830void warpmac_setTimerCallback(void(*handler)()){
831        usr_timerCallback = handler;
832}
833
834
835///@brief Attaches user callback to the Emac
836///@param handler pointer to user's callback
837void warpmac_setEmacCallback(void(*handler)()){
838        usr_emacCallback = handler;
839}
840
841
842///@brief Attaches user callback to PHY's good header interrupt
843///@param handler pointer to user's callback
844void warpmac_setGoodHeaderCallback(void(*handler)()){
845        usr_goodHeaderCallback = handler;
846}
847
848///@brief Attaches user callback to PHY's bad packet interrupt
849///@param handler pointer to user's callback
850void warpmac_setBadHeaderCallback(void(*handler)()){
851        usr_badHeaderCallback = handler;
852}
853
854void warpmac_setRxDoneCallback(void(*handler)()){
855        usr_rxDoneCallback = handler;
856}
857
858///@brief Alternates the bottom two LEDs on the WARP board.
859void warpmac_incrementLEDLow(){
860       
861       
862        //Update the global variable we use to track which LED/segments are currently lit
863        // The xps_gpio core doesn't allow outputs to be read from code, so we have to track this internally
864        LEDHEX_Outputs = (USERIO_MAP_LEDS( (ledStatesLow[ledStatesIndexLow]|ledStatesHigh[ledStatesIndexHigh])) | USERIO_MAP_DISPR(rightHex) | USERIO_MAP_DISPL(leftHex));
865       
866       
867        XGpio_DiscreteSet(&GPIO_UserIO, USERIO_CHAN_OUTPUTS, LEDHEX_Outputs);
868        ledStatesIndexLow = (ledStatesIndexLow+1)%2;
869}
870
871
872///@brief Alternates the top two LEDs on the WARP board.
873void warpmac_incrementLEDHigh(){
874       
875        //Update the global variable we use to track which LED/segments are currently lit
876        // The xps_gpio core doesn't allow outputs to be read from code, so we have to track this internally
877        LEDHEX_Outputs = (USERIO_MAP_LEDS( (ledStatesLow[ledStatesIndexLow]|ledStatesHigh[ledStatesIndexHigh])) | USERIO_MAP_DISPR(rightHex) | USERIO_MAP_DISPL(leftHex));
878       
879        XGpio_DiscreteSet(&am