root/PlatformSupport/WARPMAC/warpphy.c

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

updated warpmac/warpphy with more warpnet demo changes

Line 
1/*! \file warpphy.c
2 \brief Provide PHY-specific functions for interfacing WARPMAC (and MAC code) to the OFDM PHY peripherals
3 
4 @version 10
5 @author Chris Hunter & Patrick Murphy
6 
7 Many of the register names and bit assignments in this file depend on the design of the OFDM PHY. You must
8 use matching versions of WARPMAC, WARPPHY and ofdm_txrx_mimo. Refer to the wireless reference designs for
9 known-good combinations of versions.
10 */
11
12//XPS-generated header with peripheral parameters
13#include "xparameters.h"
14
15//Header for WARPPHY Interface
16#include "warpphy.h"
17
18//Header for WARPMAC framework (required for some global values)
19#include "warpmac.h"
20
21//These are used for 10.1 PLB46-based designs
22// These macros map the old sysgen2opb register access macros to the new PLB46 export macros
23#include "ofdm_txrx_mimo_regMacros.h"
24#include "ofdm_agc_mimo_regMacros.h"
25#include "ofdm_pktdetector_mimo_regMacros.h"
26#include "warp_timer_regMacros.h"
27
28//Headers for other WARP peripheral cores
29#include "EEPROM.h"
30#include "radio_controller_basic.h"
31#include "radio_controller_ext.h"
32#include "radio_controller_adv.h"
33#include "radio_controller_5ghz.h"
34
35//Other standard header files
36#include <stdio.h>
37#include <string.h>
38
39//********Globals********
40int agctarget;
41int agcnoiseEst;
42unsigned int warpphy_sisoMode;
43unsigned char baseRateMod;
44unsigned int numTrainingSyms;
45unsigned int pktDly;
46unsigned char globalReset;
47unsigned int numBaseRate;
48unsigned char txGain;
49
50unsigned int pktdetthresh = 9000;
51unsigned int csmathresh = 4000;
52
53unsigned int bothRadios = FIRST_RADIO | SECOND_RADIO;
54unsigned int activeRadio, lastActiveRadio;
55
56unsigned int A_KPval;
57unsigned int B_KIval;
58unsigned int B_KPval;
59unsigned int PN_KVal;
60unsigned int RxFFT_Window_Offset;
61/////////////////////////////////
62
63///@brief Initializes the OFDM PHY core
64///The OFDM PHY and radio controller cores have many options which must be configured before they can
65///be used over the air. This funciton configures these cores with sensible defaults.
66int warpphy_init(){
67
68        xil_printf("  Initializing WARPPHY:\r\n");
69
70        //Initialize global variables
71        agctarget = -15;
72        agcnoiseEst = -95;
73        warpphy_sisoMode = 1;
74        baseRateMod = QPSK;
75        numTrainingSyms = 2;
76        pktDly = 58;
77        globalReset = 0;
78        numBaseRate = 2;
79        txGain = 0x3f;
80
81        pktdetthresh = 9000;
82        csmathresh = 4000;
83
84        activeRadio = FIRST_RADIO;     
85
86        A_KPval = INIT_A_KPVAL;
87        B_KIval = INIT_B_KIVAL;
88        B_KPval = INIT_B_KPVAL;
89        PN_KVal = INIT_PN_KVAL;
90        RxFFT_Window_Offset = INIT_RXFFTOFSET;
91
92        /*****************EEPROM Setup******************/
93/*
94        int eepromStatus;
95        unsigned int calReadback;
96        Xuint8 memory[8], version, revision, valid, MAC[6], i;
97        Xuint16 serial;
98        //Extract the various numbers from the EEPROM bytes
99        version = (memory[0] & 0xE0) >> 5;
100        revision = (memory[1] & 0xE0) >> 5;
101        valid = memory[1] & 0x1F;
102
103        //Choose the EEPROM on the selected radio board; second arg is [0,1,2,3,4] for [FPGA, radio1, radio2, radio3, radio4]
104        eepromStatus = WarpEEPROM_EEPROMSelect((unsigned int *)XPAR_EEPROM_0_MEM0_BASEADDR, 0);
105
106        if(eepromStatus != 0)
107        {
108                xil_printf("EEPROM Select Failed!\r\n");
109                return;
110        }
111
112        //Initialize the EEPROM controller
113        eepromStatus = WarpEEPROM_Initialize((unsigned int *)XPAR_EEPROM_0_MEM0_BASEADDR);
114        if(eepromStatus != 0)
115        {
116                xil_printf("EEPROM Init Returned %x\r\n", eepromStatus);
117                xil_printf("EEPROM Init Failed!\r\n");
118                return;
119        }
120
121        eepromStatus = WarpEEPROM_EEPROMSelect((unsigned int*)XPAR_EEPROM_0_MEM0_BASEADDR, 2);
122        usleep(100);
123
124        //Read the first page from the EERPOM
125        WarpEEPROM_ReadMem((unsigned int*)XPAR_EEPROM_0_MEM0_BASEADDR, 0, 0, memory);
126
127        xil_printf("\r\n\r\nEEPROM Values for Radio Board in Slot %d\r\n", 2);
128
129        xil_printf("    WARP Radio Board Version %d.%d\r\n", version, revision);
130
131        serial = WarpEEPROM_ReadWARPSerial((unsigned int*)XPAR_EEPROM_0_MEM0_BASEADDR);
132
133        xil_printf("    Serial Number (WARP): WR-a-%05d\r\n", serial);
134
135        WarpEEPROM_ReadDSSerial((unsigned int*)XPAR_EEPROM_0_MEM0_BASEADDR, memory);
136        print("    EEPROM Hard-wired Serial Number: ");
137        for(i=1;i<7;i++)
138                xil_printf(" %x",memory[7-i]);
139
140        calReadback = WarpEEPROM_ReadRadioCal((unsigned int*)XPAR_EEPROM_0_MEM0_BASEADDR, 2, 1);
141        xil_printf("\r\n  Current TxDCO Values: I: %d Q: %d\r\n", (signed short)(((signed char)(calReadback & 0xFF))<<1), (signed short)(((signed char)((calReadback>>8) & 0xFF))<<1));
142*/
143
144        /*****************END EEPROM Setup*************/
145
146
147        /*****************Radio Setup******************/
148        xil_printf("    Initializing Radio Transmitter...\r\n");
149       
150        //The second argument sets the clock ratio in the radio controller's SPI controller
151        // 2 is the right value for an 80MHz bus
152        // 1 is good for a 40MHz bus
153        WarpRadio_v1_Reset((unsigned int *)XPAR_RADIO_CONTROLLER_0_BASEADDR, 1);
154       
155        xil_printf("    Starting TxDCO...\r\n");
156
157        //Apply the stored TX DC offset correction values for each radio
158        warpphy_applyTxDCOCalibration(FIRST_RADIO);
159        warpphy_applyTxDCOCalibration(SECOND_RADIO);
160       
161        //Set Tx bandwidth - 0x1 = 24MHz (minimum)
162        WarpRadio_v1_TxLpfCornFreqCoarseAdj(0x1, FIRST_RADIO | SECOND_RADIO);
163       
164        //Enable hardware control of Tx gains (handled by the radio controller Tx state machine)
165        WarpRadio_v1_SoftwareTxGainControl(0, FIRST_RADIO | SECOND_RADIO);
166       
167        //Four arguments: dly_TxEn, dly_TxStart, dly_GainRampEn, dly_PowerAmpEn, each in units of bus clock cycles
168        WarpRadio_v1_SetTxTiming(FIRST_RADIO | SECOND_RADIO, 0, 250, 100, 0);
169       
170        //Three arguments: targetGain, gainStep, stepInterval; max targetGain is 0x3F
171        WarpRadio_v1_SetTxGainTiming(FIRST_RADIO | SECOND_RADIO, 0x3F, 0xF, 1);
172       
173        //0x3 is max gain
174        WarpRadio_v1_BaseBandTxGain(0x3, FIRST_RADIO | SECOND_RADIO);
175       
176        xil_printf("    complete!\r\n");
177       
178        xil_printf("    Initializing Radio Receiver...");
179
180        //Enable hardware AGC control of receive gains & RxHP
181        WarpRadio_v1_RxHpSoftControlDisable(FIRST_RADIO | SECOND_RADIO);
182        WarpRadio_v1_SoftwareRxGainControl(0, FIRST_RADIO | SECOND_RADIO);
183
184        /*
185         //Bypass AGC - contorl Rx gain via software
186         WarpRadio_v1_RxHpSoftControlEnable(FIRST_RADIO | SECOND_RADIO);
187         WarpRadio_v1_SoftwareRxGainControl(1, FIRST_RADIO | SECOND_RADIO);
188         
189         WarpRadio_v1_RxLNAGainControl(0x2, FIRST_RADIO | SECOND_RADIO);
190         WarpRadio_v1_RxVGAGainControl(0x10, FIRST_RADIO | SECOND_RADIO);
191        */
192       
193        //Set bandwith with RxHP=0; RxHighPassCornerFreq(0) is critical for good performance
194        WarpRadio_v1_RxHighPassCornerFreq(0, FIRST_RADIO | SECOND_RADIO);
195       
196        //Set Rx bandwidth; 0x0 = 15MHz (minimum); 0x1 = 19MHz
197        WarpRadio_v1_RxLpfCornFreqCoarseAdj(1, FIRST_RADIO | SECOND_RADIO);
198       
199        //Enable the new auto tx->rx switching mode
200        WarpRadio_v1_AutoTxRxSwitch(1, FIRST_RADIO | SECOND_RADIO);
201       
202        xil_printf("complete!\r\n");
203        /**********************************************************/
204       
205        /*************************PHY******************************/
206        //Disable processing in the Tx PHY to prevent any accidental transmissions during setup
207        mimo_ofdmTx_disable();
208        //Disable processing in the Rx PHY to prevent any accidental receptions during setup
209        mimo_ofdmRx_disable();
210
211        xil_printf("    Initializing OFDM Transmitter...");
212       
213        //Configure the FFT scaling values in the PHY Tx and Rx
214        mimo_ofdmTxRx_setFFTScaling((unsigned int)(((16*RX_FFT_SCALING_STAGE1 + 4*RX_FFT_SCALING_STAGE2 + 1*RX_FFT_SCALING_STAGE3)<<6 ) | (16*TX_FFT_SCALING_STAGE1 + 4*TX_FFT_SCALING_STAGE2 + 1*TX_FFT_SCALING_STAGE3)));
215       
216        //Subcarrier indicies for pilot tones - the values here must line up with zeros in the modulation setup for each subcarrier
217        // Subcarriers [-21,-7,7,21] are the default, matching the 802.11a spec
218        mimo_ofdmTx_setPilot1Index((7 + ((64-7)<<16) ));
219        mimo_ofdmTx_setPilot2Index((21 + ((64-21)<<16)));
220       
221        //Pilot tone values are Fix16_15, so
222        // 0x7FFF is +1, 0x8000 is -1
223        // 0xA57D is ~-0.707, 0x5A82 is ~+0.707
224        mimo_ofdmTx_setPilot1Value(0xA57D);
225        mimo_ofdmTx_setPilot2Value(0x5A82);
226       
227        //3 values in this write: number of training symbols, number of base rate symbols and number of full rate symbols
228        //The number of full rate symbols is updated with each packet transmission, so it's set to a sensible non-zero value here
229        warpphy_setNumSyms(numTrainingSyms + (numBaseRate*256) + (40*65536));
230       
231        //Scaling constant for the transmitted preamble; helps normalize the amplitude of the stored preamble and actual IFFT output
232        mimo_ofdmTx_setPreambleScaling(18350);
233
234        //Configure various options in the Tx PHY
235        mimo_ofdmTx_setControlBits (
236                                                                (2 << 4) | //Preamble shift for antenna B
237                                                                (TX_SISO_MODE * warpphy_sisoMode) | //SISO mode
238                                                                TX_PILOT_SCRAMBLING | //Pseudo-random scrambling of pilot tones
239                                                                //TX_DISABLE_ANTB_PREAMBLE | //Disables preamble on antenna B
240                                                                //TX_SISO_ON_ANTB | //Uses antenna B for SISO mode
241                                                                0
242                                                                );
243       
244        xil_printf("complete!\r\n");
245       
246        //Finally enable the transmitter; it won't actually do anything until user code transmits a packet
247        mimo_ofdmTx_enable();
248       
249        xil_printf("    Initializing OFDM Receiver...");
250
251        //Configures the default number of samples of the cyclic prefix to use for synchronization offset tolerance
252        // Larger values here reduce multipath tolerance
253        mimo_ofdmRx_setFFTWindowOffset(INIT_RXFFTOFSET);
254       
255        //Scaling value is a 32-bit value, composed of two UFix16_11 values
256        // So 0x08000800 scales A/B by exactly 1
257        // This value is dependent on the number of training symbols
258        // For SISO mode and numTraining=2, use 0x10001000 (the default)
259        mimo_ofdmRx_setRxScaling(0x10001000);
260       
261        //Long correlator parameters (for packet detection confirmation and symbol timing)
262        mimo_ofdmRx_setLongCorrParams(251-16-3  + (3000*65536));
263       
264        mimo_ofdmRx_setPktDetDly(50);
265        mimo_ofdmRx_setNumOFDMSyms(numTrainingSyms + (numBaseRate<<16));
266       
267        //Bottom 8 bits are the number of header bytes per packet; nodes must agree on this at build time
268        //      bits[7:0]: number of header bytes (bytes in base-rate symbols)
269        //Three more 8-bit values are stored here - each is an index of a byte in the header:
270        //      bits[15:8]: less-significant byte of pkt length
271        //      bits[23:16]: more-significant byte of pkt length
272        //      bits[31:24]: dynamic modulation masks
273        //      mimo_ofdmRx_setByteNums( (unsigned int)(NUM_HEADER_BYTES + (2<<8) + (3<<16) + (0<<24) ));
274        mimo_ofdmRx_setByteNums( (unsigned int)(NUM_HEADER_BYTES + (3<<8) + (2<<16) + (0<<24) ));
275       
276        //Set filter coefficients for the CFO and phase noise tracking systems
277        mimo_ofdmRx_setCFO_B_KI(INIT_B_KIVAL);
278        mimo_ofdmRx_setCFO_B_KP(INIT_B_KPVAL);
279        mimo_ofdmRx_setPNTrack_K(INIT_PN_KVAL);
280       
281        //Configure a bunch of options in the Rx PHY
282        mimo_ofdmRx_setOptions
283        (
284                //RESET_BER |
285                REQ_LONG_CORR |
286                //BIG_PKTBUF_MODE |
287                DYNAMC_PKT_LENGTHS |
288                REQ_TWO_LONG_CORR |
289                REQ_SHORT_CORR |
290                (RX_SISO_MODE * warpphy_sisoMode) |
291                CFO_USE_LONGCORR |
292                DEBUG_CFO_OUTSEL |
293                COARSE_CFO_EN | //Enable coarse CFO estimation
294                USE_PILOT_ARCTAN |
295                //SWITCHING_DIV_EN | //Enable switching diversity at the receiver
296                SIMPLE_DYN_MOD_EN |
297                EXT_PKT_DETECT |
298                //SISO_ON_ANTB | //Receive SISO stream on second radio
299                //INT_PKT_DETECT |
300                //EQ_BYPASS_DIVISION |
301                RESET_ON_BAD_HDR | //Reset Rx PHY if header fails CRC
302                0,
303                DEFAULT_INTERRUPTS
304         );
305       
306        //Finally enable the Rx PHY
307        mimo_ofdmRx_enable();
308       
309        //Set the modulation schemes (baseRate, antA_fullRate, antB_fullRate):
310        // By default, we're in SISO mode, so antenna B gets 0 bits
311        // 0xF enables dynamic modulation for antenna A (0xF gets AND'd with the header's full-rate field)
312        warpphy_set_modulation(baseRateMod, 0xF, 0x0);
313       
314        //If you disable dynamic modulation, replace 0xF with an actual modulation scheme:
315        //warpphy_set_modulation(QPSK, QPSK, 0x0);
316       
317        xil_printf("complete!\r\n");
318        /**********************************************************/
319       
320        /***************************AGC****************************/
321        xil_printf("    Initializing AGC...");
322        ofdm_AGC_Initialize(agcnoiseEst);
323        ofdm_AGC_setNoiseEstimate(agcnoiseEst);
324        ofdm_AGC_SetDCO(1);
325        ofdm_AGC_SetTarget(agctarget);
326        ofdm_AGC_Reset();
327        xil_printf("complete!\r\n");
328        /**********************************************************/
329       
330        /*******************Packet Detector************************/
331        xil_printf("    Initializing Packet Detection...");
332        ofdm_pktDetector_mimo_WriteReg_csma_enableBusy(PKTDET_BASEADDR, 1);
333        ofdm_pktDetector_mimo_WriteReg_csma_enableIdle(PKTDET_BASEADDR, 1);
334        ofdm_pktDetector_mimo_WriteReg_pktDet_masterReset(PKTDET_BASEADDR, 1);
335        //              ofdm_pktDetector_mimo_WriteReg_pktDet_detectionMask(PKTDET_BASEADDR, 2); //2 = radio slot 3
336        ofdm_pktDetector_mimo_WriteReg_pktDet_detectionMask(PKTDET_BASEADDR, 1); //1 = radio slot 2
337        ofdm_pktDetector_mimo_WriteReg_pktDet_detectionMode(PKTDET_BASEADDR, 1); //0 = AND, 1 = OR
338        ofdm_pktDetector_mimo_WriteReg_pktDet_resetDuration(PKTDET_BASEADDR, 32);
339        ofdm_pktDetector_mimo_WriteReg_pktDet_avgLen(PKTDET_BASEADDR, 16);
340        ofdm_pktDetector_mimo_WriteReg_pktDet_avgThresh(PKTDET_BASEADDR, pktdetthresh); //7000
341        ofdm_pktDetector_mimo_WriteReg_csma_avgThresh(PKTDET_BASEADDR, 16000);
342        ofdm_pktDetector_mimo_WriteReg_csma_difsPeriod(PKTDET_BASEADDR, 1000); //625
343        ofdm_pktDetector_mimo_WriteReg_pktDet_masterReset(PKTDET_BASEADDR, 0);
344        ofdm_pktDetector_mimo_WriteReg_pktDet_reset(PKTDET_BASEADDR, 0);
345        xil_printf("complete!\r\n");
346        /**********************************************************/
347       
348        /**************************Timer***************************/
349        warp_timer_init();
350        /**********************************************************/
351       
352        //Finally, enable the Rx paths in the radios
353        WarpRadio_v1_RxEnable(activeRadio);
354       
355        warpphy_enableSisoMode();
356        warpphy_setNumTrainingSyms(2);
357        return 0;
358}
359
360///@brief Clears any pending Rx interrupts in the PHY. Was warpphy_pktAck() in previous versions.
361///
362///The Rx PHY blocks after asserting either its good or bad packet interrupt output. The interrupts
363///are cleared by asserting then de-asserting a register bit per interrupt. This funciton clears
364///both interrupts; there is no harm in clearing an interrupt that isn't actually asserted.
365void warpphy_clearRxInterrupts(){
366       
367        //The TxRx_Interrupt_PktBuf_Ctrl register has many bits.
368        // bits[2:0] are the Rx interrupt enables
369        // bits[6:4] are the Rx interrupt resets
370        // bit[3] and bit[7] are used for the TxDone interrupt and are preserved here
371        ofdm_txrx_mimo_WriteReg_TxRx_Interrupt_PktBuf_Ctrl(OFDM_BASEADDR, ofdm_txrx_mimo_ReadReg_TxRx_Interrupt_PktBuf_Ctrl(OFDM_BASEADDR) | DEFAULT_INTERRUPTRESETS);
372        ofdm_txrx_mimo_WriteReg_TxRx_Interrupt_PktBuf_Ctrl(OFDM_BASEADDR, ofdm_txrx_mimo_ReadReg_TxRx_Interrupt_PktBuf_Ctrl(OFDM_BASEADDR) &  ~DEFAULT_INTERRUPTRESETS);
373
374        return;
375}
376
377///@brief Releases the OFDM Rx PHY master reset
378///
379///De-asserting RX_GLOBAL_RESET allows the Rx PHY to begin processing packets.
380void mimo_ofdmRx_enable(){
381       
382        //Clear any stale interrupts; this should never really be required
383        warpphy_clearRxInterrupts();
384       
385        //De-asert the global reset
386        ofdm_txrx_mimo_WriteReg_Rx_ControlBits(OFDM_BASEADDR, ofdm_txrx_mimo_ReadReg_Rx_ControlBits(OFDM_BASEADDR) & ~RX_GLOBAL_RESET);
387       
388        return;
389}
390
391///@brief Holds the OFDM Rx PHY in reset
392///
393///Asserting the RX_GLOBAL_RESET bit clears nearly all the state in the OFDM Rx. Configuration registers are not cleared.
394void mimo_ofdmRx_disable(){
395       
396        //Assert the global reset
397        ofdm_txrx_mimo_WriteReg_Rx_ControlBits(OFDM_BASEADDR, ofdm_txrx_mimo_ReadReg_Rx_ControlBits(OFDM_BASEADDR) | RX_GLOBAL_RESET);
398
399        //Clear any stale interrupts; this should never really be required
400        warpphy_clearRxInterrupts();
401       
402        return;
403}
404
405///@brief Configures options in the Rx PHY
406///
407///@param someOptions 32-bit options value, composed on bitwise OR'd values from warpphy.h
408///@param intType Selects whether to interrupt on good or bad packets. Bitwise OR'd combination of INTR_BAD_PKTS and  INTR_GOOD_PKTS
409void mimo_ofdmRx_setOptions(unsigned int someOptions, unsigned int intType){
410       
411        //Write the full controlBits register
412        ofdm_txrx_mimo_WriteReg_Rx_ControlBits(OFDM_BASEADDR, someOptions);
413       
414        //The interrupt control bits are in the Interrupt_PktBuf_Ctrl register - bits[7:4]
415        //Clear the interrupt control bits
416        ofdm_txrx_mimo_WriteReg_TxRx_Interrupt_PktBuf_Ctrl(OFDM_BASEADDR, ofdm_txrx_mimo_ReadReg_TxRx_Interrupt_PktBuf_Ctrl(OFDM_BASEADDR) & 0xFFFFFF00);
417       
418        //Write just the interrupt control bits
419        ofdm_txrx_mimo_WriteReg_TxRx_Interrupt_PktBuf_Ctrl(OFDM_BASEADDR, ofdm_txrx_mimo_ReadReg_TxRx_Interrupt_PktBuf_Ctrl(OFDM_BASEADDR) | (ALL_INTERRUPT_ENABLE & intType));
420       
421        return;
422}
423
424///@brief Returns the current value of the Rx PHY configuration register
425///
426/// Returns the value of the OFDM Rx ControlBits register. Use the bit masks from warpphy.h to decode the indivitual bits.
427unsigned int mimo_ofdmRx_getOptions(){
428       
429        return ofdm_txrx_mimo_ReadReg_Rx_ControlBits(OFDM_BASEADDR);
430}
431
432
433///@brief Holds the OFDM Tx in reset
434///
435/// Holds the OFDM Tx in reset; this prevents any state changes in the Tx PHY. Configuration registers are not affected.
436void mimo_ofdmTx_disable(){
437       
438        //Assert the OFDM Tx master reset and pktDone reset
439        ofdm_txrx_mimo_WriteReg_Tx_Start_Reset_Control(OFDM_BASEADDR, 0x1 | 0x4);
440       
441        return;
442}
443
444///@brief Releases the OFDM Tx reset
445///
446/// Releases the OFDM Tx reset
447void mimo_ofdmTx_enable(){
448       
449        //Assert then clear the OFDM Tx master reset and pktDone reset
450        ofdm_txrx_mimo_WriteReg_Tx_Start_Reset_Control(OFDM_BASEADDR, 0x1 | 0x4);
451        ofdm_txrx_mimo_WriteReg_Tx_Start_Reset_Control(OFDM_BASEADDR, 0x0);
452       
453        return;
454}
455
456
457///@brief Initiates the transmission of a packet
458///
459///Starts the transmission of a packet from the OFDM Tx PHY. If blocking is enabled, this function returns only
460///after the transmission finishes. In this mode, the radio receiver is automatically re-enabled. If blocking is disabled,
461///the receiver must be re-enabled in user code later.
462///
463///@param block Selects whether this funciton blocks until the transmission finishes; use TXBLOCK or TXNOBLOCK
464///@param radio Selects which radios are enabled for the transmission
465int warpphy_pktTx(unsigned int block){
466       
467        //First checks whether the Tx PHY is already transmitting a packet
468        //If so, give up and return
469        if(ofdm_txrx_mimo_ReadReg_Tx_PktRunning(OFDM_BASEADDR) == 1)
470        {
471                //Tx PHY was already busy sending a packet, which should be impossible
472                xil_printf("Tx PHY was already transmitting! Failing...\r\n");
473               
474                // Return with a failure
475                return 1;
476        }
477       
478        /* Should there be a check here whether the Rx PHY is receiving a packet?
479         And what should happen if it is? It's sort of carrier sensing, but if
480         CSMA is disabled, should the Tx pkt be discarded, or held until the Rx
481         is no longer busy...
482         */
483        WarpRadio_v1_QuickTxEnable(activeRadio);
484
485/*      usleep(6);//Sleep long enough for the PHY to start transmitting; depends on second argument to SetTxTiming
486       
487        //If the user requested blocking, wait here until the PHY is done, then re-enable the radio Rx
488        // Otherwise, return immediately - NOTE! in this mode, the user must re-enable the radio Rx at some point
489        if(block == TXBLOCK)
490        {
491                //Do nothing while the Tx PHY is still busy
492                while(ofdm_txrx_mimo_ReadReg_Tx_PktRunning(OFDM_BASEADDR) == 1) {}
493               
494                //Re-enable the radio receiver
495                WarpRadio_v1_RxEnable(activeRadio);
496        }
497*/     
498        //Return successfully
499        return 0;
500}
501
502///@brief Polls PHY transmitter and re-enables reception upon completion
503///
504///This function blocks until the transmitter is complete and then re-enables
505///reception by enabing the radio receiver and enabling packet detection.
506int warpphy_waitForTx(){
507
508        //Poll the PHY transmitter until it's finished transmitting
509        while(ofdm_txrx_mimo_ReadReg_Tx_PktRunning(OFDM_BASEADDR) == 1) {}
510
511        //Re-enable the radio receiver
512//      WarpRadio_v1_RxEnable(activeRadio); //Handled automatically by the radio controller now
513
514        //Re-enable packet detection
515//      ofdm_pktDetector_mimo_WriteReg_pktDet_reset(PKTDET_BASEADDR, 0);//Handled automatically by the radio controller now
516
517        return 0;
518}
519
520
521///@brief Sets the packet buffer indicies for the OFDM Tx and Rx PHY.
522///
523///The PLB_BRAM used a the PHY packet buffer is large enough to hold many PHY packets.
524///This BRAM is divided into many sub-buffers; the PHY can be set to use any sub-buffer for Tx or Rx.
525///
526///@param txBufOffset 6-bit integer selecting the sub-buffer for the PHY Tx
527///@param rxBufOffset 6-bit integer selecting the sub-buffer for the PHY Rx
528void warpphy_setBuffs(unsigned char txBufOffset, unsigned char rxBufOffset){
529       
530        //TxRx_Interrupt_PktBuf_Ctrl[21:16] compose the Rx buffer offset
531        //TxRx_Interrupt_PktBuf_Ctrl[13:8]  compose the Tx buffer offset
532
533        //First, zero out the current pkt buff offsets
534        //Preserve the bottom 8 bits of the register (used for interrupt control)
535        ofdm_txrx_mimo_WriteReg_TxRx_Interrupt_PktBuf_Ctrl(OFDM_BASEADDR, ofdm_txrx_mimo_ReadReg_TxRx_Interrupt_PktBuf_Ctrl(OFDM_BASEADDR) & 0x000000FF);
536       
537        //Then write the new pkt buff offsets
538        ofdm_txrx_mimo_WriteReg_TxRx_Interrupt_PktBuf_Ctrl(OFDM_BASEADDR,
539                ofdm_txrx_mimo_ReadReg_TxRx_Interrupt_PktBuf_Ctrl(OFDM_BASEADDR) |
540                ( (txBufOffset & 0x3F) << 8 ) |
541                ( (rxBufOffset & 0x3F) << 16 )
542        );
543
544        return;
545}
546
547///@brief Configures the PHY for SISO mode
548void warpphy_enableSisoMode(){
549       
550        //Disable the TxRx paths during the switch
551        WarpRadio_v1_TxRxDisable(FIRST_RADIO | SECOND_RADIO);
552
553        //Update the global variable
554        warpphy_sisoMode = 1;
555       
556        //Disable full-rate modulation for second anteanna
557        warpphy_set_modulation(baseRateMod, 0xF, 0);
558
559        //Enable only one radio
560        activeRadio = FIRST_RADIO;
561       
562        //Set SISO mode in the Tx and Rx PHY registers
563        mimo_ofdmTx_setControlBits(mimo_ofdmTx_getOptions() | TX_SISO_MODE);
564        mimo_ofdmRx_setOptions(mimo_ofdmRx_getOptions() | RX_SISO_MODE, DEFAULT_INTERRUPTS);
565
566        //Re-enable reception on just the first radio
567        WarpRadio_v1_RxEnable(activeRadio);
568       
569        return;
570}
571
572///@brief Configures the PHY for MIMO mode
573void warpphy_enableMimoMode(){
574
575        //Disable the TxRx paths during the switch
576        WarpRadio_v1_TxRxDisable(FIRST_RADIO | SECOND_RADIO);
577
578        //Update the global variable
579        warpphy_sisoMode = 0;
580       
581        //Enable full-rate modulation for both anteannas
582        warpphy_set_modulation(baseRateMod, 0xF, 0xF);
583
584        //Enable both radios
585        activeRadio = FIRST_RADIO | SECOND_RADIO;
586       
587        //Un-set SISO mode in the Tx and Rx PHY registers
588        mimo_ofdmTx_setControlBits(mimo_ofdmTx_getOptions() & (~TX_SISO_MODE));
589        mimo_ofdmRx_setOptions(mimo_ofdmRx_getOptions() & (~RX_SISO_MODE),  DEFAULT_INTERRUPTS);
590
591        //Re-enable reception on both radios
592        WarpRadio_v1_RxEnable(activeRadio);
593
594        return;
595}
596
597///@brief Configures the TX PHY for MISO mode
598void warpphy_enableMisoMode(){
599        WarpRadio_v1_TxRxDisable(FIRST_RADIO | SECOND_RADIO);
600        warpphy_sisoMode = 0;
601        lastActiveRadio = activeRadio;
602        activeRadio = FIRST_RADIO | SECOND_RADIO;
603        mimo_ofdmTx_setControlBits(mimo_ofdmTx_getOptions() & (~TX_SISO_MODE));
604        WarpRadio_v1_RxEnable(activeRadio);
605}
606
607///@brief Configures the TX PHY for SISO mode
608void warpphy_disableMisoMode(){
609        WarpRadio_v1_TxRxDisable(FIRST_RADIO | SECOND_RADIO);
610        warpphy_sisoMode = 1;
611        activeRadio = lastActiveRadio;
612        mimo_ofdmTx_setControlBits(mimo_ofdmTx_getOptions() | TX_SISO_MODE);
613        WarpRadio_v1_RxEnable(activeRadio);
614}
615
616///@brief Sets the number of training symbol periods used per packet
617///
618///Configures the number of training symbols which are transmitted with each packet. The Tx and Rx nodes must be
619///configured for the same number. In SISO mode, the single channel is trained c times. In MIMO mode, each channel
620///is trained c/2 times
621///
622///@param c number of training periods; must be even
623void warpphy_setNumTrainingSyms(unsigned int c){
624        //Update the global variable; use each time a packet is transmitted
625        numTrainingSyms = c;
626       
627        //Configure the receiver
628        mimo_ofdmRx_setNumOFDMSyms(numTrainingSyms + (numBaseRate<<16));
629}
630
631///@brief Configure the flexible modulation/demodulation in the OFDM PHY
632///
633///The OFDM PHY supports flexible modulation, allowing any combination of schemes per subcarrier
634///Currently this code supports simple dynamic modulation, with 48 of 64 subcarriers assigned to carry data, 4 for pilots and 12 empty.
635///The modulation scheme in the 48 data subcarriers is set by this funciton.
636///
637///@param baseRate Modulation scheme for base rate symbols
638///@param antAFullRate Modulation scheme for full rate symbols on antenna A
639///@param antBFullRate Modulation scheme for full rate symbols on antenna B
640void warpphy_set_modulation(unsigned char baseRate, unsigned char antAFullRate, unsigned char antBFullRate)
641{
642        unsigned int modIndex;
643
644        //Update the global baseRate modulation variable
645        baseRateMod = baseRate;
646       
647        //Define the standard subcarrier mapping - 48 used for data (0xF here), 4 pilots & 12 unused (0x0 here)
648        // The vector contains 192 elements:
649        //    0:63 - Antenna A full rate masks for subcarriers [0,1,2,...31,-31,-30,...-1]
650        //  64:127 - Antenna B full rate masks for subcarriers [0,1,2,...31,-31,-30,...-1]
651        // 128:191 - Base rate masks for subcarriers [0,1,2,...31,-31,-30,...-1]
652        //The default masks are 3 copies of the same 64-length vector; yes, it's inefficient, but this scheme maintains flexibility in changing the mapping per antenna
653        unsigned char modMasks[192] = {
654                        0x0, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0x0, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0x0, 0xF, 0xF, 0xF, 0xF, 0xF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xF, 0xF, 0xF, 0xF, 0xF, 0x0, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0x0, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF,
655                        0x0, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0x0, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0x0, 0xF, 0xF, 0xF, 0xF, 0xF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xF, 0xF, 0xF, 0xF, 0xF, 0x0, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0x0, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF,
656                        0x0, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0x0, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0x0, 0xF, 0xF, 0xF, 0xF, 0xF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xF, 0xF, 0xF, 0xF, 0xF, 0x0, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0x0, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF
657        };
658
659        //The PHY's shared memories for modulation masks have 192 4-bit entries; each entry's address is 4-byte aligned (hence the *sizeof(int) below )
660        //Configure Tx and Rx antenna A full rate
661         for(modIndex=0; modIndex<64; modIndex++)
662         {
663                XIo_Out32(XPAR_OFDM_TXRX_MIMO_PLBW_0_MEMMAP_TXMODULATION+(modIndex*sizeof(int)), modMasks[modIndex] & antAFullRate);
664                XIo_Out32(XPAR_OFDM_TXRX_MIMO_PLBW_0_MEMMAP_RXMODULATION+(modIndex*sizeof(int)), modMasks[modIndex] & antAFullRate);
665         }
666
667         //Configure Tx and Rx antenna B full rate
668         for(modIndex=64; modIndex<128; modIndex++)
669         {
670                XIo_Out32(XPAR_OFDM_TXRX_MIMO_PLBW_0_MEMMAP_TXMODULATION+(modIndex*sizeof(int)), modMasks[modIndex] & antBFullRate);
671                XIo_Out32(XPAR_OFDM_TXRX_MIMO_PLBW_0_MEMMAP_RXMODULATION+(modIndex*sizeof(int)), modMasks[modIndex] & antBFullRate);
672         }
673         
674         //Configure the Tx and Rx base rate
675         for(modIndex=128; modIndex<192; modIndex++)
676         {
677                XIo_Out32(XPAR_OFDM_TXRX_MIMO_PLBW_0_MEMMAP_TXMODULATION+(modIndex*sizeof(int)), modMasks[modIndex] & baseRate);
678                XIo_Out32(XPAR_OFDM_TXRX_MIMO_PLBW_0_MEMMAP_RXMODULATION+(modIndex*sizeof(int)), modMasks[modIndex] & baseRate);
679         }
680
681        return;
682}
683
684///@brief Selects which antenna is used when the PHY is in SISO mode
685///
686/// The OFDM PHY can use either antenna when in SISO mode. By default, antenna A is used.
687///
688///@param anteSel 0: use Antenna A, 1: use Antenna B
689void warpphy_setSISOAntenna(unsigned char antSel)
690{
691       
692        if(warpphy_sisoMode != 1) return; //Not valid if using MIMO mode
693        if(mimo_ofdmRx_getOptions()  & SWITCHING_DIV_EN) return; //Not valid if using switching diversity
694       
695        if(antSel == 0) //choose radio in slot 2
696        {
697                //Temporarily disable packet detections
698                ofdm_pktDetector_mimo_WriteReg_pktDet_reset(PKTDET_BASEADDR, 1);
699               
700                activeRadio = FIRST_RADIO;
701               
702                //Switch the pkt detector to listen to just radio #2
703                ofdm_pktDetector_mimo_WriteReg_pktDet_detectionMask(PKTDET_BASEADDR, 1);
704               
705                //Disable antB selection in the PHY
706                mimo_ofdmTx_setControlBits(mimo_ofdmTx_getOptions() & (~TX_SISO_ON_ANTB) );
707                mimo_ofdmRx_setOptions(mimo_ofdmRx_getOptions() & (~SISO_ON_ANTB),  DEFAULT_INTERRUPTS);
708               
709                //Turn packet detection back on
710                ofdm_pktDetector_mimo_WriteReg_pktDet_reset(PKTDET_BASEADDR, 0);
711                WarpRadio_v1_RxEnable(activeRadio);
712        }
713        else if(antSel == 1) //chose radio in slot 3
714        {
715                //Temporarily disable packet detections
716                ofdm_pktDetector_mimo_WriteReg_pktDet_reset(PKTDET_BASEADDR, 1);
717               
718                activeRadio = SECOND_RADIO;
719               
720                //Switch the pkt detector to listen to just radio #3
721                ofdm_pktDetector_mimo_WriteReg_pktDet_detectionMask(PKTDET_BASEADDR, 2);
722               
723                //Disable antB selection in the PHY
724                mimo_ofdmTx_setControlBits(mimo_ofdmTx_getOptions() | (TX_SISO_ON_ANTB) );
725                mimo_ofdmRx_setOptions(mimo_ofdmRx_getOptions() | (SISO_ON_ANTB),    DEFAULT_INTERRUPTS);
726               
727                //Turn packet detection back on
728                ofdm_pktDetector_mimo_WriteReg_pktDet_reset(PKTDET_BASEADDR, 0);
729                WarpRadio_v1_RxEnable(activeRadio);
730        }
731       
732        return;
733}
734
735///@brief Set the transmit power (via the radio's RF VGA)
736///@param txPwr Desired transmit power; must be integer in [0,63]
737///@return Returns -1 if an invalid power is requested; 0 on success
738int warpphy_setTxPower(unsigned char txPwr)
739{
740        if(txPwr > 63)
741                return -1;
742        else
743                WarpRadio_v1_SetTxGainTiming(FIRST_RADIO | SECOND_RADIO, 0x3F&txPwr, 0xF, 1);
744
745        return 0;
746}
747
748///@brief Set the center frequency of the radio transceivers
749///@param band Selects 2.4GHz or 5GHz bands (using GHZ_2 or GHZ_5)
750///@param c Selects the channel number in the chosen band
751///@return Returns -1 if an invalid band or channel was specified; otherwise returns the new center frequency in MHz
752int warpphy_setChannel(unsigned char band, unsigned int c){
753
754        int newFreq = -1;
755       
756       
757        if (band == GHZ_2){
758
759                newFreq = WarpRadio_v1_SetCenterFreq2GHz(c, FIRST_RADIO | SECOND_RADIO);
760        }
761        if (band == GHZ_5){
762                newFreq = WarpRadio_v1_SetCenterFreq5GHz(c, FIRST_RADIO | SECOND_RADIO);
763        }
764               
765        return newFreq;
766}
767
768///@brief Set the center frequency of the radio transceivers independently
769///@param antA_band Selects 2.4GHz or 5GHz bands (using GHZ_2 or GHZ_5) for antenna A
770///@param antB_band Selects 2.4GHz or 5GHz bands (using GHZ_2 or GHZ_5) for antenna B
771///@param antA_chan Selects the channel number in the chosen band for antenna A
772///@param antB_chan Selects the channel number in the chosen band for antenna B
773///@return Returns -1 if an invalid band or channel was specified; otherwise returns the new center frequency for antenna A in MHz
774int warpphy_setSeparateChannels(unsigned char antA_band, unsigned int antA_chan, unsigned char antB_band, unsigned int antB_chan){
775
776        int newFreq_A = -1;
777        int newFreq_B = -1;
778       
779        if (antA_band == GHZ_2)
780                newFreq_A = WarpRadio_v1_SetCenterFreq2GHz(antA_chan, FIRST_RADIO);
781
782        if (antB_band == GHZ_2)
783                newFreq_B = WarpRadio_v1_SetCenterFreq2GHz(antB_chan, SECOND_RADIO);
784
785        if (antA_band == GHZ_5)
786                newFreq_A = WarpRadio_v1_SetCenterFreq5GHz(antA_chan, FIRST_RADIO);
787
788        if (antB_band == GHZ_5)
789                newFreq_B = WarpRadio_v1_SetCenterFreq5GHz(antB_chan, SECOND_RADIO);
790       
791        if(newFreq_A == -1 || newFreq_B == -1)
792                return -1;
793        else
794                return newFreq_A;
795
796}
797
798/*********************************************************************/
799/* A whole bunch of debugging functions - these will go away someday */
800/*********************************************************************/
801
802void warpphy_setPktDlyPlus(){
803        pktDly++;
804        xil_printf("+PktDly = %d\r\n",pktDly);
805        mimo_ofdmRx_setPktDetDly(pktDly);
806}
807void warpphy_setPktDlyMinus(){
808        pktDly--;
809        xil_printf("-PktDly = %d\r\n",pktDly);
810        mimo_ofdmRx_setPktDetDly(pktDly);
811}
812
813/****************************/
814/* Phase noise tracking */
815/****************************/
816void warpphy_set_PN_KPlus(unsigned int increment){
817        PN_KVal=PN_KVal+increment;
818        mimo_ofdmRx_setPNTrack_K(PN_KVal);
819        xil_printf("K: %x\r\n", PN_KVal);
820}
821
822void warpphy_set_PN_KMinus(unsigned int decrement){
823        PN_KVal=PN_KVal-decrement;
824        mimo_ofdmRx_setPNTrack_K(PN_KVal);
825        xil_printf("K: %x\r\n", PN_KVal);
826}
827
828/*****************/
829/* CFO Constants */
830/*****************/
831
832void print_CFO_constants ()
833{
834        xil_printf("AK: %x\tBP: %x\tBI: %x\r\n", A_KPval, B_KPval, B_KIval);
835}
836
837void warpphy_set_B_KPPlus(unsigned int increment){
838        B_KPval=B_KPval+increment;
839        mimo_ofdmRx_setCFO_B_KP(B_KPval);
840        print_CFO_constants();
841}
842
843void warpphy_set_B_KPMinus(unsigned int decrement){
844        B_KPval=B_KPval-decrement;
845        mimo_ofdmRx_setCFO_B_KP(B_KPval);
846        print_CFO_constants();
847}
848
849void warpphy_set_B_KIPlus(unsigned int increment){
850        B_KIval=B_KIval+increment;
851        mimo_ofdmRx_setCFO_B_KI(B_KIval);
852        print_CFO_constants();
853}
854
855void warpphy_set_B_KIMinus(unsigned int decrement){
856        B_KIval=B_KIval-decrement;
857        mimo_ofdmRx_setCFO_B_KI(B_KIval);
858        print_CFO_constants();
859}
860
861void warpphy_set_CFODebugOutput(unsigned char outputSel){
862       
863        if(outputSel)
864                ofdm_txrx_mimo_WriteReg_Rx_ControlBits(OFDM_BASEADDR, ofdm_txrx_mimo_ReadReg_Rx_ControlBits(OFDM_BASEADDR) | DEBUG_CFO_OUTSEL);
865        else
866    Â