source: PlatformSupport/WARPMAC/warpphy.c

Last change on this file was 1712, checked in by murphpo, 7 years ago

Updating code for OFDM ref design v17 in ISE 13.4 tools

File size: 57.3 KB
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 15.22
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 "warp_fpga_board.h"
14#include "xparameters.h"
15
16//Header for WARPPHY Interface
17#include "warpphy.h"
18
19//Header for WARPMAC framework (required for some global values)
20#include "warpmac.h"
21
22// These header files define some macros for reading/writing registers in the Sysgen-designed cores
23// This layer of macros keep this code independent from the name of the sysgen core
24//  (sysgen defines its register names as a function of the .mdl file name)
25#include "util/ofdm_txrx_mimo_regMacros.h"
26#include "util/ofdm_agc_mimo_regMacros.h"
27#include "util/warp_timer_regMacros.h"
28#include "util/warp_userio.h"
29
30//Headers for other WARP peripheral cores
31#include "EEPROM.h"
32#include "radio_controller_basic.h"
33#include "radio_controller_ext.h"
34#include "radio_controller_adv.h"
35#include "radio_controller_5ghz.h"
36
37//Other standard header files
38#include <sleep.h>
39#include <stdio.h>
40#include <string.h>
41
42//********Globals********
43int agc_targetRxPowerOut;
44int agc_noisePowerEstimate;
45
46unsigned char baseRateMod;
47unsigned int numTrainingSyms;
48unsigned int ofdmRx_pktDetDly;
49unsigned int numBaseRate;
50unsigned char txGain;
51unsigned char RxSoftDecodingEn;
52unsigned short pktDet_corrCounterLoad;
53unsigned char pktDet_corrWindowStart;
54unsigned char pktDet_corrWindowEnd;
55
56unsigned int pktDet_energyThresh;
57unsigned int pktDet_carrierSenseThresh;
58unsigned char pktDet_threshMinDur;
59
60unsigned int warpphy_txAntMode;
61unsigned int warpphy_rxAntMode;
62unsigned int activeRadios_Tx, activeRadios_Rx;
63unsigned int activePHYStatusBits;
64unsigned short longCorrThresh;
65unsigned int afScaling;
66
67unsigned short pktDetCFOsampCount;
68
69unsigned int RxFFT_Window_Offset;
70unsigned int txScaling_preamble;
71unsigned int txScaling_payload;
72
73unsigned int agcIIR_g, agcIIR_fb;
74
75
76/////////////////////////////////
77
78///@brief Initializes the OFDM PHY core
79///The OFDM PHY and radio controller cores have many options which must be configured before they can
80///be used over the air. This funciton configures these cores with sensible defaults.
81int warpphy_init(){
82    unsigned int i;
83    xil_printf("  Initializing WARPPHY:\r\n");
84
85    //Set the default antenna configuration
86    warpphy_txAntMode = TX_ANTMODE_SISO_ANTA;
87    warpphy_rxAntMode = RX_ANTMODE_SISO_ANTA;
88    activePHYStatusBits = DEFAULT_STATUSBITS;
89
90    //Hold the PHY in reset until everything it setup; the reset does not initialize the PHY's registers
91    mimo_ofdmTx_disable();
92    mimo_ofdmRx_disable();
93   
94    //Initialize global variables
95    longCorrThresh = 9000;//3500; //2750
96   
97    afScaling = 2944;//6656;
98
99    //AGC target output power, in units of dBv (voltage at MAX2829 output)
100    agc_targetRxPowerOut = -12;
101
102    //AGC noise power estimate, in dBm
103    agc_noisePowerEstimate = -95;
104
105    //Base-rate modulation scheme; should be QPSK
106    baseRateMod = QPSK;
107
108    //Number of training symbol periods (all on 1 antenna for SISO, split across antennas for MIMO)
109    numTrainingSyms = NUM_TRAINING_SYMBOLS;
110
111    //Number of base rate OFDM symbols; every node must agree on this number ahead of time
112    // IF FEC is enabled, the base rate symbols are always encoded at rate 1/2, so a 24-byte
113    // header at QPSK occupies 4 symbols (instead of 2 when uncoded)
114    numBaseRate = NUM_BASERATE_SYMBOLS;
115
116    //Packet detection delay, in sys_clk cycles
117    // The Rx PHY waits this long before searching for correlation peaks
118    ofdmRx_pktDetDly = 124;
119
120    //Tx RF gain (6-bit value in [0,63])
121    txGain = 0x3f;
122
123    //Tx scaling values; both are interpreted as UFix16_13 values
124    // The ratio of preamble/payload values should be approx 1/4
125    // Increasing these values will increase Tx power at the expense of clipping
126    txScaling_preamble = 3072;
127    txScaling_payload  = 12288;
128   
129    //Packet detector parameters
130    // Energy threshold - X/16 = RSSI
131    pktDet_energyThresh = 8000;
132
133    //Carrier sensing threshold - 8192/16 = RSSI of 512 (approx -65dBm Rx power)
134    pktDet_carrierSenseThresh = 8192;
135   
136    //Minimum duration of energy-above-energyThresh required to assert a packet detection
137    pktDet_threshMinDur = 24;
138   
139    //Define the FFT start offset (FFT will use (15 - offset) samples of cyclic prefix to handle synchronization
140    RxFFT_Window_Offset = INIT_RXFFTOFSET;
141
142    //Set some magic numbers for the CFO correction calculations; these are only used for pre-correcting CFO in DF mode
143    warpphy_setPilotCFOCorrection(0x8025AEE6);
144    warpphy_setCoarseCFOCorrection(30533);
145
146    /*****************Radio Setup******************/
147    xil_printf("\tInitializing Radio Transmitter...\r\n");
148   
149    //The second argument sets the clock ratio in the radio controller's SPI controller
150    // 1 is good for a 40MHz bus
151    // 2 is the right value for an 80MHz bus
152    WarpRadio_v1_Reset((unsigned int *)XPAR_RADIO_CONTROLLER_0_BASEADDR, 1);
153   
154    xil_printf("\tStarting TxDCO correction...\r\n");
155
156    //Apply the stored TX DC offset correction values for each radio
157    warpphy_applyTxDCOCalibration(FIRST_RADIO);
158    warpphy_applyTxDCOCalibration(SECOND_RADIO);
159   
160    //Configure some MAX2829 Tx parameters for good wideband performance
161
162    //Disable software control of the TxEn/RxEn signals; the PHY will control these
163    WarpRadio_v1_RxEnSoftControlDisable(BOTH_RADIOS);
164    WarpRadio_v1_TxEnSoftControlDisable(BOTH_RADIOS);
165   
166    //Set Tx bandwidth - 0x1 = 24MHz (minimum)
167    WarpRadio_v1_TxLpfCornFreqCoarseAdj(0x1, BOTH_RADIOS);
168   
169    //Enable hardware control of Tx gains (handled by the radio controller Tx state machine)
170    WarpRadio_v1_SoftwareTxGainControl(0, BOTH_RADIOS);
171   
172    //Four arguments: dly_TxEn, dly_TxStart, dly_GainRampEn, dly_PowerAmpEn, each in units of bus clock cycles
173    WarpRadio_v1_SetTxTiming(BOTH_RADIOS, 0, 200, 100, 0);
174
175    //Three arguments: targetGain, gainStep, stepInterval; max targetGain is 0x3F
176    WarpRadio_v1_SetTxGainTiming(BOTH_RADIOS, txGain, 0xF, 1);
177   
178    //Set the MAX2829 Tx baseband gain; 0x3 is max gain
179    WarpRadio_v1_BaseBandTxGain(0x3, BOTH_RADIOS);
180   
181    xil_printf("\tInitializing Radio Receiver...");
182
183    //Enable hardware AGC control of receive gains & RxHP
184    WarpRadio_v1_RxHpSoftControlDisable(BOTH_RADIOS);
185    WarpRadio_v1_SoftwareRxGainControl(0, BOTH_RADIOS);
186
187    //Set bandwith with RxHP=0; RxHighPassCornerFreq(0) is critical for good performance
188    WarpRadio_v1_RxHighPassCornerFreq(0, BOTH_RADIOS);
189   
190    //Set Rx bandwidth; 0x0 = 15MHz (minimum)
191    WarpRadio_v1_RxLpfCornFreqCoarseAdj(0, BOTH_RADIOS);
192   
193    xil_printf("complete!\r\n");
194    /**********************************************************/
195   
196    /*******************Packet Detector************************/
197    xil_printf("\tInitializing Packet Detection...");
198
199    //Assert the packet detection output reset
200    ofdm_txrx_mimo_WriteReg_Rx_PktDet_ignoreDet(1);
201
202    //Set the RSSI clock ratio; 0=sys_clk/4; 1=sys_clk/8
203    ofdm_txrx_mimo_WriteReg_Rx_PktDet_setRSSIclkRatio(0);
204
205    //Set the minimum energy duration
206    ofdm_txrx_mimo_WriteReg_Rx_PktDet_setMinDuration(pktDet_threshMinDur);
207   
208    //Enable the carrier-sensing block's IDLE output (the timer can choose to use or ignore it)
209    ofdm_txrx_mimo_WriteReg_Rx_CSMA_enableIdle(1);
210   
211    //Hold the packet detector's running sum in reset
212    ofdm_txrx_mimo_WriteReg_Rx_PktDet_resetSum(1);
213   
214    //Configure the packet detector's antenna masks (1=antA, 2=antB, 3=both)
215    ofdm_txrx_mimo_WriteReg_Rx_PktDet_setMask(PKTDET_MASK_ANTA);
216   
217    //Set the packet detector's logic mode for the two antenna ports; 0 = AND, 1 = OR
218    ofdm_txrx_mimo_WriteReg_Rx_PktDet_setMode(1);
219   
220    //Set the running sum length; 16 is a good default
221    ofdm_txrx_mimo_WriteReg_Rx_PktDet_setAvgLen(PKTDET_RSSI_SUMLEN);
222   
223    //Set the detector's energy threshold; this value must be scaled relative to the sum-length
224    ofdm_txrx_mimo_WriteReg_Rx_PktDet_setThresh(pktDet_energyThresh);
225   
226    //Set the carrier sensing threshold to a very high level, disabling it by default
227    ofdm_txrx_mimo_WriteReg_Rx_CSMA_setThresh(CSMA_DISABLED_THRESH);
228
229    //Set the DIFS period; this is the require IDLE time before the IDLE output will assert
230    // Units are sys_clk/4 cycles (10MHz), so 300 = 30us
231    // This delay must exceed the TxDATA->TxACK turn around time (currently 23us)
232    ofdm_txrx_mimo_WriteReg_Rx_PktDet_setDIFSPeriod(300);
233   
234    //Deassert the running sum reset; the sum will run continuously after this
235    ofdm_txrx_mimo_WriteReg_Rx_PktDet_resetSum(0);
236   
237    //Set thresholds for the autoCorrelation detector
238    //CorrThresh (UFix8_7): 0.7 ≈ 90
239    //MinPoiwer (UFix12_0); 2048 is theoretical max, 100-300 is more realistic, 0 works too
240    ofdm_txrx_mimo_WriteReg_Rx_PktDetCorr_params(90, 0);
241
242    //Enable both the RSSI and autoCorrelation packet detectors
243    ofdm_txrx_mimo_WriteReg_Rx_PktDet_rssiDetEn(1);
244    ofdm_txrx_mimo_WriteReg_Rx_PktDet_corrDetEn(1);
245   
246    //Deassert the packet detection output reset; packet detection events will start after this
247    ofdm_txrx_mimo_WriteReg_Rx_PktDet_ignoreDet(0);
248   
249    xil_printf("complete!\r\n");
250    /**********************************************************/
251   
252    /*************************PHY******************************/
253
254    xil_printf("\tInitializing OFDM Transmitter...");
255   
256    //Clear all the match and action blocks in the auto response system
257    mimo_ofdmTxRx_setAction0(0);
258    mimo_ofdmTxRx_setAction1(0);
259    mimo_ofdmTxRx_setAction2(0);
260    mimo_ofdmTxRx_setAction3(0);
261    mimo_ofdmTxRx_setAction4(0);
262    mimo_ofdmTxRx_setAction5(0);
263    mimo_ofdmTxRx_setMatch0(0);
264    mimo_ofdmTxRx_setMatch1(0);
265    mimo_ofdmTxRx_setMatch2(0);
266    mimo_ofdmTxRx_setMatch3(0);
267    mimo_ofdmTxRx_setMatch4(0);
268    mimo_ofdmTxRx_setMatch5(0);
269
270    //Fill in the header translator with non-translating values by default
271    // This will "overwrite" the header with the same pktbuf/byte combos as the template buffer
272    // User code will override some entries here to implement a protocol
273    for(i=0; i<(32*32); i++)
274    {
275        //Each entry is a 10-bit number of {srcBuf[4:0], srcByteAddr[4:0]}
276        XIo_Out32(XPAR_OFDM_TXRX_MIMO_PLBW_0_MEMMAP_TXHEADERTRANSLATE+i*sizeof(int), (i & 0x3FF));
277    }
278   
279    //Set the AF scaling
280    mimo_ofdmRx_setAFTxScaling(afScaling);
281   
282    //Set the minimum magnitude for channels to use their pilots
283    mimo_ofdmRx_setPilotCalcParams(0xFFF); //MinMag as UFix12_12 (41 ~= 0.01)
284   
285    //Configure the FFT scaling values in the PHY Tx and Rx
286    // 6-bits each, 6LSB are Tx scaling; 6LSB+6 are Rx scaling
287    mimo_ofdmTxRx_setFFTScaling((unsigned int)((
288                                (16*RX_FFT_SCALING_STAGE1 + 4*RX_FFT_SCALING_STAGE2 + 1*RX_FFT_SCALING_STAGE3)<<6 ) | 
289                                (16*TX_FFT_SCALING_STAGE1 + 4*TX_FFT_SCALING_STAGE2 + 1*TX_FFT_SCALING_STAGE3)));
290   
291    //Subcarrier indicies for pilot tones - the values here must line up with zeros in the modulation setup for each subcarrier
292    // Subcarriers [-21,-7,7,21] are the default, matching the 802.11a spec
293    mimo_ofdmTx_setPilotIndcies((7 + ((64-21)<<8) + ((64-7)<<16) + ((21)<<24) ));
294   
295    //Pilot tone values are Fix16_15, so
296    // Pilot 1 should be negative, pilot 2 should be positive
297    // 0x7FFF is +1, 0x8000 is -1
298    // 0xA57D is ~-0.707, 0x5A82 is ~+0.707
299    mimo_ofdmTxRx_setPilotValues( (0xA57D) + (0x5A82 << 16));
300   
301    //2 values in this write: number of training symbols and number of base rate symbols
302    // The Tx/Rx nodes must agree on these values ahead of time
303    warpphy_setTxNumSyms(numBaseRate, numTrainingSyms);
304    warpphy_setRxNumSyms(numBaseRate, numTrainingSyms);
305   
306    //Scaling constant for the transmitted preamble; helps normalize the amplitude of the stored preamble and actual IFFT output
307    mimo_ofdmTx_setTxScaling(txScaling_preamble, txScaling_payload);
308
309    //Configure various options in the Tx PHY
310    mimo_ofdmTx_setControlBits (
311                                (3 << 4) | //Preamble shift for antenna B
312                                ((0&0x3F) << 20) | //Cyclic shift
313                                TX_PILOT_SCRAMBLING | //Pseudo-random scrambling of pilot tones
314                                TX_SOFTWARE_TXEN | //Use the PHY TxStart register to start the overall PHY/radio Tx state machine
315                                //TX_RANDOM_PAYLOAD | //Use random payload bytes (user must still provide valid header!)
316                                //TX_ALWAYS_USE_PRECFO | //Always apply Tx CFO, even if the packet isn't triggered by auto responders
317                                //TX_DISABLE_ANTB_PREAMBLE | //Disables preamble on antenna B
318                                0
319                                );
320   
321    //Shift antenna B preambles by -3 samples
322    warpphy_setAntBPreambleShift(13);
323
324    xil_printf("complete!\r\n");
325   
326    xil_printf("\tInitializing OFDM Receiver...");
327
328    //Configure the FEC blocks
329    // (CodingEn, SoftDecodingEn, ZeroTailEn, QPSK_Scaling, 16QAM_Scaling)
330    mimo_ofdmTxRx_setFECoptions(1, 1, 0, 6, 16);
331   
332    //Configures the default number of samples of the cyclic prefix to use for synchronization offset tolerance
333    // Larger values here reduce multipath tolerance
334    mimo_ofdmRx_setFFTWindowOffset(INIT_RXFFTOFSET);
335   
336    //Scaling value is a 32-bit value, composed of two UFix16_11 values
337    // So 0x08000800 scales A/B by exactly 1
338    // This value is dependent on the number of training symbols
339    // For SISO mode and numTraining=2, use 0x10001000 (the default)
340    mimo_ofdmRx_setRxScaling(0x10001000); 
341   
342    //Long correlator parameters (for packet detection confirmation and symbol timing)
343    // Top 16-bits are long-correlation threshold; 3000 works well over-the-air
344    // Bottom 16-bits are sample index corresponding to the long correlation event
345    //  (basically a magic number that aligns the Rx PHY state machine with the incoming packet)
346
347    warpphy_setLongCorrThresh(longCorrThresh);
348   
349    //The correlator only accepts peaks inside a window relative to the energy detection event
350    // Adjust the Start/End values below to grow/shrink the window as needed
351    pktDet_corrWindowStart = 90-32;
352    pktDet_corrWindowEnd = 180+32;
353
354    pktDet_corrCounterLoad = 251;//232;
355    pktDetCFOsampCount = 255;
356    mimo_ofdmRx_setLongCorrParams(((pktDet_corrCounterLoad & 0x00FF)    << 0 ) | \
357                                  ((pktDetCFOsampCount  & 0x00FF)   << 8 ) | \
358                                  ((pktDet_corrWindowStart & 0xFF)  << 16 ) | \
359                                  ((pktDet_corrWindowEnd & 0xFF)    << 24 )); //corr window start/end
360
361    //Sets the delay between the pkt detection assertion and the PHY searching for correlation peaks
362    mimo_ofdmRx_setPktDetDly(ofdmRx_pktDetDly);
363    mimo_ofdmRx_setCFOCalcDly(0);
364    mimo_ofdmRx_setCFOMaxDiff(255); //UFix8_8 - 0.15 * 256 ≈ 38
365
366    warpphy_setPreCFOoptions( (PRECFO_USECOARSE | PRECFO_USEPILOTS) );
367   
368    //Bottom 8 bits are the number of header bytes per packet; nodes must agree on this at build time
369    //  bits[7:0]: number of header bytes (bytes in base-rate symbols)
370    //Three more 8-bit values are stored here - each is an index of a byte in the header:
371    //  bits[15:8]: less-significant byte of pkt length
372    //  bits[23:16]: more-significant byte of pkt length
373    //  bits[31:24]: dynamic modulation masks
374    //  mimo_ofdmRx_setByteNums( (unsigned int)(NUM_HEADER_BYTES + (2<<8) + (3<<16) + (0<<24) ));
375    mimo_ofdmRx_setByteNums( (unsigned int)(NUM_HEADER_BYTES + (3<<8) + (2<<16) + (0<<24) ));
376   
377    //Configure some sane defaults in the Rx PHY
378    mimo_ofdmRx_setOptions
379    (
380        RESET_BER | //Hold the BER meter in reset
381        REQ_LONG_CORR | //Require long correlation for packet detection
382        //RSSI_GAIN_ADJ | //Compensate RSSI input to pkt detector for RF gain changes
383        //BYPASS_CARR_REC | //Hold the Rx DDS in reset (ignoring any coarse CFO estimate)
384        COARSE_CFO_EN | //Enable coarse CFO estimation
385        TX_DISABLE_PKTDET | //Ignore packet detection during Tx
386        SIMPLE_DYN_MOD_EN | //Use the header's fullRate field for demodulation
387        RESET_ON_BAD_HDR | //Reset Rx PHY if header fails CRC
388        RECORD_CHAN_ESTS | //Enable the channel estimate recording buffer
389        RECORD_CHAN_ESTMAGS | //Enable the channel estimate recording buffer
390        //CHANMAG_MASKING_EN | //Enable channel magnitude masking
391        0,
392        activePHYStatusBits
393    );
394   
395    //Set the modulation masks to sane defaults
396    // 0xF enables dynamic modulation for that path
397    warpphy_set_modulation(baseRateMod, 0xF, 0xF, 0xF, 0xF);
398
399    //Set the antenna modes to SISO by default
400    warpphy_setAntennaMode(TX_ANTMODE_SISO_ANTA, RX_ANTMODE_SISO_ANTA);
401   
402    warpphy_setNumTrainingSyms(NUM_TRAINING_SYMBOLS);
403
404    //Set min chanest magnitudes (UFix16_15 values; set to zero to effectively disable)
405    warpphy_setChanEstMinMags(0);
406   
407    //Set AF blanking interval (set to zeros to disable)
408    warpphy_setAFblanking(0, 0);
409   
410    XIo_Out32(XPAR_OFDM_TXRX_MIMO_PLBW_0_MEMMAP_RX_FIXEDPKTLEN, 0);
411   
412    xil_printf("complete!\r\n");
413    /**********************************************************/
414   
415    /***************************AGC****************************/
416    xil_printf("\tInitializing AGC...");
417    //agcIIR_fb = 0x20990; //20kHz cutoff, Fix18_17
418    //agcIIR_g =  0x1fb38; //20kHz cutoff, UFix18_17
419    agcIIR_fb = 0x20000; //0kHz cutoff, Fix18_17
420    agcIIR_g =  0x20000; //0kHz cutoff, UFix18_17
421    ofdm_AGC_Initialize(agc_noisePowerEstimate);
422    ofdm_AGC_setNoiseEstimate(agc_noisePowerEstimate);
423
424    ofdm_AGC_SetDCO(0x6); //enable both subtraction and IIR filter
425   
426    ofdm_AGC_SetTarget(agc_targetRxPowerOut);
427    ofdm_AGC_Reset();
428
429    XIo_Out32(XPAR_OFDM_AGC_MIMO_PLBW_0_MEMMAP_DCO_IIR_COEF_FB, agcIIR_fb);
430    XIo_Out32(XPAR_OFDM_AGC_MIMO_PLBW_0_MEMMAP_DCO_IIR_COEF_GAIN, agcIIR_g);
431   
432    xil_printf("complete!\r\n");
433    /**********************************************************/
434   
435    /**************************Timer***************************/
436    //Initialize the timer hardware; the individual timers will get setup in WARPMAC
437    warp_timer_init();
438    /**********************************************************/
439   
440    //Finally enable the PHY
441    mimo_ofdmTx_enable();
442    mimo_ofdmRx_enable();
443   
444    return 0;
445}
446
447///@brief Clears any pending Rx pkt status in the PHY. Was warpphy_pktAck() in previous versions.
448///
449///The Rx PHY blocks after asserting either its good or bad packet status bits. The bits
450///are cleared by asserting then de-asserting a register bit per status bit. This funciton clears
451///both good and bad pkt bits; there is no harm in clearing a status bit that isn't actually asserted.
452void warpphy_clearRxPktStatus(){
453   
454    //The TxRx_Interrupt_PktBuf_Ctrl register has many bits.
455    // bits[2:0] are the Rx status enables
456    // bits[6:4] are the Rx status resets
457    // bit[3] and bit[7] are used for the TxDone status and are preserved here
458    ofdm_txrx_mimo_WriteReg_TxRx_Interrupt_PktBuf_Ctrl(OFDM_BASEADDR, ofdm_txrx_mimo_ReadReg_TxRx_Interrupt_PktBuf_Ctrl(OFDM_BASEADDR) | DEFAULT_STATUSBITRESETS);
459    ofdm_txrx_mimo_WriteReg_TxRx_Interrupt_PktBuf_Ctrl(OFDM_BASEADDR, ofdm_txrx_mimo_ReadReg_TxRx_Interrupt_PktBuf_Ctrl(OFDM_BASEADDR) &  ~DEFAULT_STATUSBITRESETS);
460
461    return;
462}
463
464///@brief Releases the OFDM Rx PHY master reset
465///
466///De-asserting RX_GLOBAL_RESET allows the Rx PHY to begin processing packets.
467void mimo_ofdmRx_enable(){
468   
469    //Clear any stale interrupts; this should never really be required
470    warpphy_clearRxPktStatus();
471   
472    //De-asert the global reset
473    ofdm_txrx_mimo_WriteReg_Rx_ControlBits(OFDM_BASEADDR, ofdm_txrx_mimo_ReadReg_Rx_ControlBits(OFDM_BASEADDR) & ~RX_GLOBAL_RESET);
474   
475    return;
476}
477
478///@brief Holds the OFDM Rx PHY in reset
479///
480///Asserting the RX_GLOBAL_RESET bit clears nearly all the state in the OFDM Rx. Configuration registers are not cleared.
481void mimo_ofdmRx_disable(){
482   
483    //Assert the global reset
484    ofdm_txrx_mimo_WriteReg_Rx_ControlBits(OFDM_BASEADDR, ofdm_txrx_mimo_ReadReg_Rx_ControlBits(OFDM_BASEADDR) | RX_GLOBAL_RESET);
485
486    //Clear any stale interrupts; this should never really be required
487    warpphy_clearRxPktStatus();
488   
489    return;
490}
491
492///@brief Configures options in the Rx PHY
493///
494///@param someOptions 32-bit options value, composed on bitwise OR'd values from warpphy.h
495///@param blockingStatusBits Configures which PHY Rx events block future receptions (good/bad header/payload)
496void mimo_ofdmRx_setOptions(unsigned int someOptions, unsigned int blockingStatusBits){
497   
498    //Write the full controlBits register
499    ofdm_txrx_mimo_WriteReg_Rx_ControlBits(OFDM_BASEADDR, someOptions);
500   
501    //The interrupt control bits are in the Interrupt_PktBuf_Ctrl register - bits[7:4]
502    //Clear the interrupt control bits
503    ofdm_txrx_mimo_WriteReg_TxRx_Interrupt_PktBuf_Ctrl(OFDM_BASEADDR, ofdm_txrx_mimo_ReadReg_TxRx_Interrupt_PktBuf_Ctrl(OFDM_BASEADDR) & 0xFFFFFF00);
504   
505    //Write just the interrupt control bits
506    ofdm_txrx_mimo_WriteReg_TxRx_Interrupt_PktBuf_Ctrl(OFDM_BASEADDR, ofdm_txrx_mimo_ReadReg_TxRx_Interrupt_PktBuf_Ctrl(OFDM_BASEADDR) | (ALL_STATUSBITS_ENABLE & blockingStatusBits));
507   
508    return;
509}
510
511///@brief Returns the current value of the Rx PHY configuration register
512///
513/// Returns the value of the OFDM Rx ControlBits register. Use the bit masks from warpphy.h to decode the indivitual bits.
514unsigned int mimo_ofdmRx_getOptions(){
515   
516    return ofdm_txrx_mimo_ReadReg_Rx_ControlBits(OFDM_BASEADDR);
517}
518
519
520///@brief Holds the OFDM Tx in reset
521///
522/// Holds the OFDM Tx in reset; this prevents any state changes in the Tx PHY. Configuration registers are not affected.
523void mimo_ofdmTx_disable(){
524   
525    //Assert the OFDM Tx master reset and pktDone reset
526    ofdm_txrx_mimo_WriteReg_Tx_Start_Reset_Control(OFDM_BASEADDR, TX_MASTER_RESET);
527   
528    return;
529}
530
531///@brief Releases the OFDM Tx reset
532///
533/// Releases the OFDM Tx reset
534void mimo_ofdmTx_enable(){
535   
536    //Assert then clear the OFDM Tx master reset and pktDone reset
537    ofdm_txrx_mimo_WriteReg_Tx_Start_Reset_Control(OFDM_BASEADDR, TX_MASTER_RESET);
538    ofdm_txrx_mimo_WriteReg_Tx_Start_Reset_Control(OFDM_BASEADDR, 0x0);
539   
540    return;
541}
542
543
544///@brief Initiates the transmission of a packet
545///
546///Starts the transmission of a packet from the OFDM Tx PHY. If blocking is enabled, this function returns only
547///after the transmission finishes. In this mode, the radio receiver is automatically re-enabled. If blocking is disabled,
548///the receiver must be re-enabled in user code later.
549///
550///@param block DEPRECATED Selects whether this funciton blocks until the transmission finishes; use TXBLOCK or TXNOBLOCK
551inline int warpphy_pktTx(unsigned int block){
552   
553   
554    /* Should there be a check here whether the Rx PHY is receiving a packet?
555     And what should happen if it is? It's sort of carrier sensing, but if
556     CSMA is disabled, should the Tx pkt be discarded, or held until the Rx
557     is no longer busy...
558     */
559   
560    //Pulse the PHY's TxEn register bit. This will propogate to the radio bridge to activate
561    // the radio controller's Tx state machine for whatever radio is enabled (by setAntennaMode() )
562    mimo_ofdmTx_setStartTx(1);
563    mimo_ofdmTx_setStartTx(0);
564   
565    //Sleep long enough for the PHY to start transmitting; depends on second argument to SetTxTiming
566    usleep(6);
567   
568    //Return successfully
569    return 0;
570}
571
572///@brief Polls PHY transmitter and re-enables reception upon completion
573///
574///This function blocks until the transmitter is complete and then re-enables
575///reception by enabing the radio receiver and enabling packet detection.
576int warpphy_waitForTx(){
577
578    //warpmac_setDebugGPIO(0xF);
579
580    //Poll the PHY transmitter until it's finished transmitting
581    while(ofdm_txrx_mimo_ReadReg_Tx_PktRunning(OFDM_BASEADDR) & OFDM_TX_BUSY) {
582        //warpmac_incrementLEDLow();
583    }
584
585    //Workaround for very rare PHY race condition, where a goodHeader event occurred immediately
586    // before the transmission
587    warpphy_clearRxPktStatus();
588
589    return 0;
590}
591
592
593///@brief Sets the packet buffer indicies for the OFDM Tx and Rx PHY.
594///
595///The PLB_BRAM used a the PHY packet buffer is large enough to hold many PHY packets.
596///This BRAM is divided into many sub-buffers; the PHY can be set to use any sub-buffer for Tx or Rx.
597///
598///@param txBufOffset 6-bit integer selecting the sub-buffer for the PHY Tx
599///@param rxBufOffset 6-bit integer selecting the sub-buffer for the PHY Rx
600void warpphy_setBuffs(unsigned char txBufOffset, unsigned char rxBufOffset){
601   
602    //TxRx_Interrupt_PktBuf_Ctrl[21:16] compose the Rx buffer offset
603    //TxRx_Interrupt_PktBuf_Ctrl[13:8]  compose the Tx buffer offset
604
605    //First, zero out the current pkt buff offsets
606    //Preserve the bottom 8 bits of the register (used for interrupt control)
607    ofdm_txrx_mimo_WriteReg_TxRx_Interrupt_PktBuf_Ctrl(OFDM_BASEADDR, ofdm_txrx_mimo_ReadReg_TxRx_Interrupt_PktBuf_Ctrl(OFDM_BASEADDR) & 0x000000FF);
608   
609    //Then write the new pkt buff offsets
610    ofdm_txrx_mimo_WriteReg_TxRx_Interrupt_PktBuf_Ctrl(OFDM_BASEADDR,
611        ofdm_txrx_mimo_ReadReg_TxRx_Interrupt_PktBuf_Ctrl(OFDM_BASEADDR) |
612        ( (txBufOffset & 0x3F) << 8 ) |
613        ( (rxBufOffset & 0x3F) << 16 )
614    );
615
616    return;
617}
618
619void warpphy_AFrecordEnable(unsigned char recordEn)
620{
621    if(recordEn)
622    {
623        mimo_ofdmRx_setOptions(mimo_ofdmRx_getOptions() | AF_SAVEWAVEFORM, activePHYStatusBits);
624    }
625    else
626    {
627        mimo_ofdmRx_setOptions(mimo_ofdmRx_getOptions() & ~(AF_SAVEWAVEFORM), activePHYStatusBits);
628    }
629   
630    return;
631}
632
633///@brief Configures the PHY for the chosen antenna modes (SISO, Alamouti, multiplexing, etc.)
634///
635///@param txMode Constant (defined in warphphy.h) specifying the Tx antenna mode
636///@param rxMode Constant (defined in warphphy.h) specifying the Rx antenna mode
637int warpphy_setAntennaMode(unsigned int txMode, unsigned int rxMode)
638{
639    //Reset the Tx and Rx PHYs during this reconfiguration
640    // This will interrupt any active Tx/Rx events but won't clear any registers
641    mimo_ofdmRx_disable();
642    mimo_ofdmTx_disable();
643   
644    //Tx configuration
645    if(txMode != ANTMODE_UNCHANGED)
646    {
647        //Update the gloabl variable (used throughout to calculate "magic" numbers for the PHY)
648        warpphy_txAntMode = txMode;
649
650        //Take software control and disable both radio's Tx paths
651        // The correct radios will be re-enabled below
652        WarpRadio_v1_TxEnSoftControlEnable(BOTH_RADIOS);
653        WarpRadio_v1_TxRxDisable(BOTH_RADIOS);
654
655        //Enable hardware Tx control of either or both radios
656        switch(txMode & ANTMODE_MASK_ANTSEL)
657        {
658            case ANTMODE_ANTSEL_RADA:
659                activeRadios_Tx = FIRST_RADIO;
660                WarpRadio_v1_TxEnSoftControlDisable(FIRST_RADIO);
661                break;
662               
663            case ANTMODE_ANTSEL_RADB:
664                activeRadios_Tx = SECOND_RADIO;
665                WarpRadio_v1_TxEnSoftControlDisable(SECOND_RADIO);
666                break;
667               
668            case ANTMODE_ANTSEL_BOTHRADS:
669                activeRadios_Tx = BOTH_RADIOS;
670                WarpRadio_v1_TxEnSoftControlDisable(BOTH_RADIOS);
671                break;
672
673            default:
674                xil_printf("Invalid Tx antenna mode!\r\n");
675                return -1;
676                break;
677        }
678
679        //Configure the PHY's Tx mode
680        switch(txMode & ANTMODE_MASK_PHYMODE)
681        {
682            case PHYMODE_SISO:
683                //Set SISO mode, disable MIMO modes in the Tx PHY registers
684                mimo_ofdmTx_setControlBits(mimo_ofdmTx_getOptions() & ~(TX_ALAMOUTI_MODE) );
685                mimo_ofdmTx_setControlBits(mimo_ofdmTx_getOptions() | TX_SISO_MODE);
686                break;
687               
688            case PHYMODE_2X2MULT:
689                //Disable SISO/Alamouti modes in the Tx PHY registers
690                mimo_ofdmTx_setControlBits(mimo_ofdmTx_getOptions() & ~(TX_SISO_MODE | TX_ALAMOUTI_MODE) );
691                break;
692
693            case PHYMODE_ALAMOUTI:
694                //Set Alamouti mode, disable SISO mode in the Tx PHY registers
695                mimo_ofdmTx_setControlBits(mimo_ofdmTx_getOptions() & ~(TX_SISO_MODE) );
696                mimo_ofdmTx_setControlBits(mimo_ofdmTx_getOptions() | TX_ALAMOUTI_MODE);
697                break;
698
699            default:
700                xil_printf("Invalid Tx PHY mode!\r\n");
701                return -1;
702                break;
703        }
704
705        //Configure the PHY's Tx antenna configuration
706        switch(txMode & ANTMODE_MASK_PHYANTCFG)
707        {
708            case PHYANTCFG_TX_NORMAL:
709                mimo_ofdmTx_setControlBits(mimo_ofdmTx_getOptions() & ~(TX_SWAP_ANTENNAS) );
710                break;
711
712            case PHYANTCFG_TX_SWAPPED:
713                mimo_ofdmTx_setControlBits(mimo_ofdmTx_getOptions() | TX_SWAP_ANTENNAS);
714                break;
715
716            default:
717                xil_printf("Invalid Tx PHYANT mode!\r\n");
718                return -1;
719                break;
720        }
721    }
722
723    if(rxMode != ANTMODE_UNCHANGED)
724    {
725        //Update the gloabl variable (used throughout to calculate "magic" numbers for the PHY)
726        warpphy_rxAntMode = rxMode;
727
728        //Take software control and disable both radio's Rx paths
729        // The correct radios will be re-enabled below
730        WarpRadio_v1_RxEnSoftControlEnable(BOTH_RADIOS);
731        WarpRadio_v1_TxRxDisable(BOTH_RADIOS);
732   
733        //Enable hardware Rx control of either or both radios
734        switch(rxMode & ANTMODE_MASK_ANTSEL)
735        {
736            case ANTMODE_ANTSEL_RADA:
737                activeRadios_Rx = FIRST_RADIO;
738                WarpRadio_v1_RxEnSoftControlDisable(FIRST_RADIO);
739                ofdm_txrx_mimo_WriteReg_Rx_PktDet_setMask(PKTDET_MASK_ANTA);
740                break;
741               
742            case ANTMODE_ANTSEL_RADB:
743                activeRadios_Rx = SECOND_RADIO;
744                WarpRadio_v1_RxEnSoftControlDisable(SECOND_RADIO);
745                ofdm_txrx_mimo_WriteReg_Rx_PktDet_setMask(PKTDET_MASK_ANTB);
746                break;
747               
748            case ANTMODE_ANTSEL_BOTHRADS:
749                activeRadios_Rx = BOTH_RADIOS;
750                WarpRadio_v1_RxEnSoftControlDisable(BOTH_RADIOS);
751                ofdm_txrx_mimo_WriteReg_Rx_PktDet_setMask(PKTDET_MASK_ANTA | PKTDET_MASK_ANTB);
752                break;
753               
754            default:
755                xil_printf("Invalid Rx antenna mode!\r\n");
756                return -1;
757                break;
758        }
759       
760       
761        //Configure the PHY's Rx mode
762        switch(rxMode & ANTMODE_MASK_PHYMODE)
763        {
764            case PHYMODE_SISO:
765                //Set SISO mode, disable MIMO modes in the Rx PHY registers
766                mimo_ofdmRx_setOptions(mimo_ofdmRx_getOptions() & ~(RX_ALAMOUTI_MODE), activePHYStatusBits);
767                mimo_ofdmRx_setOptions(mimo_ofdmRx_getOptions() | RX_SISO_MODE, activePHYStatusBits);
768                mimo_ofdmRx_setRxScaling(0x10001000); 
769                break;
770               
771            case PHYMODE_2X2MULT:
772                //Disable SISO/Alamouti modes in the Rx PHY registers
773                mimo_ofdmRx_setOptions(mimo_ofdmRx_getOptions() & ~(RX_ALAMOUTI_MODE | RX_SISO_MODE), activePHYStatusBits);
774                mimo_ofdmRx_setRxScaling(0x08000800); 
775                break;
776               
777            case PHYMODE_ALAMOUTI:
778                //Set Alamouti mode, disable SISO mode in the Rx PHY registers
779                mimo_ofdmRx_setOptions(mimo_ofdmRx_getOptions() & ~(RX_SISO_MODE), activePHYStatusBits);
780                mimo_ofdmRx_setOptions(mimo_ofdmRx_getOptions() |  RX_ALAMOUTI_MODE, activePHYStatusBits);
781                mimo_ofdmRx_setRxScaling(0x08000800); 
782                break;
783               
784            default:
785                xil_printf("Invalid Rx PHY mode!\r\n");
786                return -1;
787                break;
788        }
789       
790        //Configure the PHY's Rx antenna configuration
791        switch(rxMode & ANTMODE_MASK_PHYANTCFG)
792        {
793            case PHYANTCFG_RX_NORMAL:
794                mimo_ofdmRx_setOptions(mimo_ofdmRx_getOptions() & ~(SISO_ON_ANTB | SWITCHING_DIV_EN), activePHYStatusBits);
795                break;
796               
797            case PHYANTCFG_RX_SWAPPED:
798                mimo_ofdmRx_setOptions(mimo_ofdmRx_getOptions() & ~(SWITCHING_DIV_EN), activePHYStatusBits);
799                mimo_ofdmRx_setOptions(mimo_ofdmRx_getOptions() | SISO_ON_ANTB, activePHYStatusBits);
800                break;
801               
802            case PHYANTCFG_RX_SELDIV:
803                mimo_ofdmRx_setOptions(mimo_ofdmRx_getOptions() & ~(SISO_ON_ANTB), activePHYStatusBits);
804                mimo_ofdmRx_setOptions(mimo_ofdmRx_getOptions() | SWITCHING_DIV_EN, activePHYStatusBits);
805                break;
806               
807            default:
808                xil_printf("Invalid Rx PHYANT mode!\r\n");
809                return -1;
810                break;
811               
812        }
813    }
814
815    //Finally, re-enbale the PHY Tx/Rx subsystems
816    mimo_ofdmRx_enable();
817    mimo_ofdmTx_enable();
818
819    //Pulse the PHY's RxEn register to re-enable receive paths on the active radios
820    // This must occur after calling ofdmRx_enable, as this register's output is ignored while the Rx PHY is in reset
821    mimo_ofdmRx_setOptions(mimo_ofdmRx_getOptions() | PHY_RADIO_RXEN, activePHYStatusBits);
822    mimo_ofdmRx_setOptions(mimo_ofdmRx_getOptions() & ~(PHY_RADIO_RXEN), activePHYStatusBits);
823   
824    return 0;
825}
826
827///@brief Fast and dangerous way of switching TX PHY mode... note... this function cannot change physical radios
828///
829///@param txMode Constant (defined in warphphy.h) specifying the Tx antenna mode
830int warpphy_setTxAntennaSwap(unsigned int txMode)
831{
832    //Tx configuration
833    if(txMode != ANTMODE_UNCHANGED)
834    {
835        //Update the gloabl variable (used throughout to calculate "magic" numbers for the PHY)
836        warpphy_txAntMode = txMode;
837       
838        //Configure the PHY's Tx antenna configuration
839        switch(txMode & ANTMODE_MASK_PHYANTCFG)
840        {
841            case PHYANTCFG_TX_NORMAL:
842                mimo_ofdmTx_setControlBits(mimo_ofdmTx_getOptions() & ~(TX_SWAP_ANTENNAS) );
843                break;
844               
845            case PHYANTCFG_TX_SWAPPED:
846                mimo_ofdmTx_setControlBits(mimo_ofdmTx_getOptions() | TX_SWAP_ANTENNAS);
847                break;
848               
849            default:
850                xil_printf("Invalid Tx PHYANT mode!\r\n");
851                return -1;
852                break;
853        }
854    }
855       
856    return 0;
857}
858
859inline void warpphy_clearAutoResponseFlag(unsigned char flagID){
860
861    switch(flagID)
862    {
863        case AUTORESP_FLAGID_A:
864            ofdm_txrx_mimo_WriteReg_Rx_ControlBits(OFDM_BASEADDR, ofdm_txrx_mimo_ReadReg_Rx_ControlBits(OFDM_BASEADDR) | (AUTORESP_FLAGA_RST));
865            ofdm_txrx_mimo_WriteReg_Rx_ControlBits(OFDM_BASEADDR, ofdm_txrx_mimo_ReadReg_Rx_ControlBits(OFDM_BASEADDR) & ~(AUTORESP_FLAGA_RST));
866            break;
867        case AUTORESP_FLAGID_B:
868            ofdm_txrx_mimo_WriteReg_Rx_ControlBits(OFDM_BASEADDR, ofdm_txrx_mimo_ReadReg_Rx_ControlBits(OFDM_BASEADDR) | (AUTORESP_FLAGB_RST));
869            ofdm_txrx_mimo_WriteReg_Rx_ControlBits(OFDM_BASEADDR, ofdm_txrx_mimo_ReadReg_Rx_ControlBits(OFDM_BASEADDR) & ~(AUTORESP_FLAGB_RST));
870            break;
871    }
872
873    return;
874}
875
876///@brief Sets the number of training symbol periods used per packet
877///
878///Configures the number of training symbols which are transmitted with each packet. The Tx and Rx nodes must be
879///configured for the same number. In SISO mode, the single channel is trained c times. In MIMO mode, each channel
880///is trained c/2 times
881///
882///@param numTraining number of training periods; must be even
883void warpphy_setNumTrainingSyms(unsigned int numTraining){
884    //Update the global variable; used each time a packet is transmitted
885    numTrainingSyms = numTraining;
886   
887    //Configure the PHY
888    warpphy_setTxNumSyms(numBaseRate, numTrainingSyms);
889    warpphy_setRxNumSyms(numBaseRate, numTrainingSyms);
890}
891
892void warpphy_setNumBaseRateSyms(unsigned int numSyms){
893    //Update the global variable; used each time a packet is transmitted
894    numBaseRate = numSyms;
895   
896    //Configure the PHY
897    warpphy_setTxNumSyms(numBaseRate, numTrainingSyms);
898    warpphy_setRxNumSyms(numBaseRate, numTrainingSyms);
899}
900
901///@brief Configure the flexible modulation/demodulation in the OFDM PHY
902///
903///The OFDM PHY supports flexible modulation, allowing any combination of schemes per subcarrier
904///Currently this code supports simple dynamic modulation, with 48 of 64 subcarriers assigned to carry data, 4 for pilots and 12 empty.
905///The modulation scheme in the 48 data subcarriers is set by this funciton.
906///NOTE: When FEC is enabled the modulation rate of all data bearing subcarriers must be the same and one of BPSK/QPSK/16-QAM
907///
908///@param baseRate Modulation scheme for base rate symbols
909///@param TxAntAFullRate Modulation scheme for Tx full rate symbols on antenna A
910///@param TxAntBFullRate Modulation scheme for Tx full rate symbols on antenna B
911///@param RxAntAFullRate Modulation scheme for Rx full rate symbols on antenna A
912///@param RxAntBFullRate Modulation scheme for Rx full rate symbols on antenna B
913void warpphy_set_modulation(unsigned char baseRate, unsigned char TxAntAFullRate, unsigned char TxAntBFullRate, unsigned char RxAntAFullRate, unsigned char RxAntBFullRate)
914{
915    unsigned int modIndex;
916
917    //Define the standard subcarrier mapping - 48 used for data (0xF here), 4 pilots & 12 unused (0x0 here)
918    // The vector contains 192 elements:
919    //    0:63 - Antenna A full rate masks for subcarriers [0,1,2,...31,-31,-30,...-1]
920    //  64:127 - Antenna B full rate masks for subcarriers [0,1,2,...31,-31,-30,...-1]
921    // 128:191 - Base rate masks for subcarriers [0,1,2,...31,-31,-30,...-1]
922    //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
923    unsigned char modMasks[192] = {
924            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,
925            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,
926            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
927    };
928
929    //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 )
930    if(TxAntAFullRate != MOD_UNCHANGED)
931    {
932        //Configure Tx antenna A full rate
933        for(modIndex=0; modIndex<64; modIndex++)
934        {
935            XIo_Out32(XPAR_OFDM_TXRX_MIMO_PLBW_0_MEMMAP_TXMODULATION+(modIndex*sizeof(int)), modMasks[modIndex] & TxAntAFullRate);
936        }
937    }
938
939    if(TxAntBFullRate != MOD_UNCHANGED)
940    {
941        //Configure Tx antenna B full rate
942        for(modIndex=64; modIndex<128; modIndex++)
943        {
944            XIo_Out32(XPAR_OFDM_TXRX_MIMO_PLBW_0_MEMMAP_TXMODULATION+(modIndex*sizeof(int)), modMasks[modIndex] & TxAntBFullRate);
945        }
946    }
947   
948    if(RxAntAFullRate != MOD_UNCHANGED)
949    {
950        //Configure Rx antenna A full rate
951        for(modIndex=0; modIndex<64; modIndex++)
952        {
953            XIo_Out32(XPAR_OFDM_TXRX_MIMO_PLBW_0_MEMMAP_RXMODULATION+(modIndex*sizeof(int)), modMasks[modIndex] & RxAntAFullRate);
954        }
955    }
956
957    if(RxAntBFullRate != MOD_UNCHANGED)
958    {
959        //Configure Rx antenna B full rate
960        for(modIndex=64; modIndex<128; modIndex++)
961        {
962            XIo_Out32(XPAR_OFDM_TXRX_MIMO_PLBW_0_MEMMAP_RXMODULATION+(modIndex*sizeof(int)), modMasks[modIndex] & RxAntBFullRate);
963        }
964    }
965   
966    //Update the global baseRate modulation variable
967    if(baseRate != MOD_UNCHANGED)
968    {
969        baseRateMod = baseRate;
970   
971        //Configure the Tx and Rx base rate
972        for(modIndex=128; modIndex<192; modIndex++)
973        {
974            XIo_Out32(XPAR_OFDM_TXRX_MIMO_PLBW_0_MEMMAP_TXMODULATION+(modIndex*sizeof(int)), modMasks[modIndex] & baseRate);
975            XIo_Out32(XPAR_OFDM_TXRX_MIMO_PLBW_0_MEMMAP_RXMODULATION+(modIndex*sizeof(int)), modMasks[modIndex] & baseRate);
976        }
977    }
978
979    return;
980}
981
982///@brief Set the center frequency of the radio transceivers
983///@param band Selects 2.4GHz or 5GHz bands (using GHZ_2 or GHZ_5)
984///@param chan Selects the channel number in the chosen band
985///@return Returns -1 if an invalid band or channel was specified; otherwise returns the new center frequency in MHz
986int warpphy_setChannel(unsigned char band, unsigned int chan){
987    int newFreq = -1;
988   
989    if (band == GHZ_2){
990        newFreq = WarpRadio_v1_SetCenterFreq2GHz(chan, FIRST_RADIO | SECOND_RADIO);
991    }
992    if (band == GHZ_5){
993        newFreq = WarpRadio_v1_SetCenterFreq5GHz(chan, FIRST_RADIO | SECOND_RADIO);
994    }
995       
996    return newFreq;
997}
998
999///@brief Set the center frequency of the radio transceivers independently
1000///@param antA_band Selects 2.4GHz or 5GHz bands (using GHZ_2 or GHZ_5) for antenna A
1001///@param antB_band Selects 2.4GHz or 5GHz bands (using GHZ_2 or GHZ_5) for antenna B
1002///@param antA_chan Selects the channel number in the chosen band for antenna A
1003///@param antB_chan Selects the channel number in the chosen band for antenna B
1004///@return Returns -1 if an invalid band or channel was specified; otherwise returns the new center frequency for antenna A in MHz
1005int warpphy_setSeparateChannels(unsigned char antA_band, unsigned int antA_chan, unsigned char antB_band, unsigned int antB_chan){
1006
1007    int newFreq_A = -1;
1008    int newFreq_B = -1;
1009   
1010    if (antA_band == GHZ_2)
1011        newFreq_A = WarpRadio_v1_SetCenterFreq2GHz(antA_chan, FIRST_RADIO);
1012    if (antB_band == GHZ_2)
1013        newFreq_B = WarpRadio_v1_SetCenterFreq2GHz(antB_chan, SECOND_RADIO);
1014    if (antA_band == GHZ_5)
1015        newFreq_A = WarpRadio_v1_SetCenterFreq5GHz(antA_chan, FIRST_RADIO);
1016    if (antB_band == GHZ_5)
1017        newFreq_B = WarpRadio_v1_SetCenterFreq5GHz(antB_chan, SECOND_RADIO);
1018    if(newFreq_A == -1 || newFreq_B == -1)
1019        return -1;
1020    else
1021        return newFreq_A;
1022}
1023
1024///@brief Applies TX DC offset calibration to the specified radios; the calibration values are stored in the radio's EEPROM
1025///@param radioSelection OR'd combinaton of RADIOx_ADDR values, specifying which radios to update
1026///@return Returns -1 if an EEPROM error occurs; returns 0 if successful
1027int warpphy_applyTxDCOCalibration(unsigned int radioSelection)
1028{
1029    int eepromStatus = 0;
1030    short calReadback = 0;
1031    signed short best_I, best_Q;
1032    unsigned char radioNum;
1033    Xuint8 memory[8], version, revision, valid;
1034    Xuint16 serial;
1035
1036    //Radio selection will be 0x11111111, 0x22222222, 0x44444444 or 0x88888888
1037    // corresponding to radios in slots 1, 2, 3 or 4
1038    // We need the slot number to initialize the EEPROM
1039    radioNum = (radioSelection & 0xF) == 1 ? 1 : ( (radioSelection & 0xF) == 2 ? 2 : ( (radioSelection & 0xF) == 4 ? 3 : 4 ) );
1040//  xil_printf("Applying TxDCO correction for radio %d\r\n", radioNum);
1041
1042    //Mimic the radio test code, in hopes of a more stable EEPROM read...
1043    //Choose the EEPROM on the selected radio board; second arg is [0,1,2,3,4] for [FPGA, radio1, radio2, radio3, radio4]
1044    eepromStatus = WarpEEPROM_EEPROMSelect((unsigned int *)XPAR_EEPROM_CONTROLLER_MEM0_BASEADDR, 0);
1045    if(eepromStatus != 0)
1046    {
1047        xil_printf("EEPROM Select Failed!\r\n");
1048        return -1;
1049    }
1050   
1051    //Initialize the EEPROM controller
1052    eepromStatus = WarpEEPROM_Initialize((unsigned int *)XPAR_EEPROM_CONTROLLER_MEM0_BASEADDR);
1053    if(eepromStatus != 0)
1054    {
1055        xil_printf("EEPROM Init Returned %x\r\n", eepromStatus);
1056        xil_printf("EEPROM Init Failed!\r\n");
1057        return -1;
1058    }
1059
1060    //Select the EEPROM on the current radio board
1061    eepromStatus = WarpEEPROM_EEPROMSelect((unsigned int*)XPAR_EEPROM_CONTROLLER_MEM0_BASEADDR, radioNum);
1062
1063    if(eepromStatus != 0)
1064    {
1065        xil_printf("TxDCO: EEPROM error\r\n");
1066        return -1;
1067    }
1068   
1069    //Read the first page from the EERPOM
1070    WarpEEPROM_ReadMem((unsigned int*)XPAR_EEPROM_CONTROLLER_MEM0_BASEADDR, 0, 0, memory);
1071    version = (memory[0] & 0xE0) >> 5;
1072    revision = (memory[1] & 0xE0) >> 5;
1073    valid = memory[1] & 0x1F;
1074
1075//  xil_printf("\r\n\r\nEEPROM Values for Radio Board in Slot %d\r\n", radioNum);
1076
1077//  xil_printf("    WARP Radio Board Version %d.%d\r\n", version, revision);
1078
1079    serial = WarpEEPROM_ReadWARPSerial((unsigned int*)XPAR_EEPROM_CONTROLLER_MEM0_BASEADDR);
1080
1081//  xil_printf("    Serial Number (WARP): WR-a-%05d\r\n", serial);
1082
1083    WarpEEPROM_ReadDSSerial((unsigned int*)XPAR_EEPROM_CONTROLLER_MEM0_BASEADDR, memory);
1084//  print("    EEPROM Hard-wired Serial Number: ");
1085//  for(i=1;i<7;i++)
1086//      xil_printf(" %x",memory[7-i]);
1087//  xil_printf("\r\n\r\n");
1088    //Read the Tx DCO values
1089    calReadback = WarpEEPROM_ReadRadioCal((unsigned int*)XPAR_EEPROM_CONTROLLER_MEM0_BASEADDR, 2, 1);
1090   
1091    //Scale the stored values
1092    best_I = (signed short)(((signed char)(calReadback & 0xFF))<<1);
1093    best_Q = (signed short)(((signed char)((calReadback>>8) & 0xFF))<<1);
1094   
1095    xil_printf("\t\tTxDCO values for radio %d - I: %d\tQ: %d\r\n", radioNum, best_I, best_Q);
1096   
1097    //Finally, write the Tx DCO values to the DAC
1098    WarpRadio_v1_DACOffsetAdj(ICHAN, best_I, radioSelection);
1099    WarpRadio_v1_DACOffsetAdj(QCHAN, best_Q, radioSelection);
1100   
1101    return 0;
1102}
1103
1104
1105/******* AGC core control functions ********/
1106
1107unsigned int warpphy_returnGainsDB(){
1108/*  int rfGain;
1109    switch(warpphy_returnAGCgainRF(antenna)){
1110        case 0:
1111            rfGain=1;
1112        break;
1113        case 1:
1114            rfGain=16;
1115        break;
1116        case 2:
1117            rfGain=31.5;
1118        break;
1119    }
1120    xil_printf("BBGAIN %d\r\n",(warpphy_returnAGCgainBB(antenna)<<1));
1121    return ((warpphy_returnAGCgainBB(antenna)<<1) + rfGain);
1122*/
1123
1124unsigned int rfGain,bbGain,gainDB,rfGainDB,bbGainDB;
1125unsigned int agcGains;
1126   
1127
1128        agcGains = ofdm_AGC_GetGains();
1129        rfGain = agcGains&0x3;
1130        bbGain = (agcGains>>2)&0x1F;
1131       
1132        switch(rfGain){
1133        case 0:
1134            rfGainDB=1;
1135        break;
1136        case 1:
1137            rfGainDB=1;
1138        break;
1139        case 2:
1140            rfGainDB=16;
1141        break;
1142        case 3:
1143            rfGainDB=32; //really 31.5...
1144        break;
1145    }
1146   
1147    bbGainDB=bbGain<<1;
1148    gainDB = bbGainDB + rfGainDB;
1149       return gainDB;
1150
1151   
1152   
1153   
1154}
1155
1156
1157
1158
1159inline void ofdm_AGC_SetDCO(unsigned int AGCstate){
1160
1161    // register bits:
1162    // [1:0]- DCO mode
1163    //   0x0=bypass DCO correction entirely
1164    //   0x1=bypass IIR filter, allow subtraction
1165    //   0x2=enable IIR filter, allow subtraction
1166    // [2]- enable subtraction (only has effect if [1:0] != 0)
1167    // Valid values:
1168    // [1 1 0]=0x6: Enable filter, use subtraction
1169    OFDM_AGC_MIMO_WriteReg_Bits(XPAR_OFDM_AGC_MIMO_OPBW_0_BASEADDR, (AGCstate & 0x7));
1170   
1171    return;
1172}
1173
1174void ofdm_AGC_Reset(){
1175   
1176    // Cycle the agc's software reset port
1177   
1178    OFDM_AGC_MIMO_WriteReg_SRESET_IN(XPAR_OFDM_AGC_MIMO_OPBW_0_BASEADDR, 1);
1179    usleep(10);
1180    OFDM_AGC_MIMO_WriteReg_SRESET_IN(XPAR_OFDM_AGC_MIMO_OPBW_0_BASEADDR, 0);
1181    usleep(100);
1182   
1183    return;
1184}
1185
1186
1187void ofdm_AGC_MasterReset(){
1188   
1189    // Cycle the master reset register in the AGC and enable it
1190   
1191    OFDM_AGC_MIMO_WriteReg_AGC_EN(XPAR_OFDM_AGC_MIMO_OPBW_0_BASEADDR, 0);
1192    usleep(10);
1193    OFDM_AGC_MIMO_WriteReg_MRESET_IN(XPAR_OFDM_AGC_MIMO_OPBW_0_BASEADDR, 0);
1194    usleep(10);
1195    OFDM_AGC_MIMO_WriteReg_MRESET_IN(XPAR_OFDM_AGC_MIMO_OPBW_0_BASEADDR, 1);
1196    usleep(10);
1197    OFDM_AGC_MIMO_WriteReg_MRESET_IN(XPAR_OFDM_AGC_MIMO_OPBW_0_BASEADDR, 0);
1198    usleep(10);
1199    OFDM_AGC_MIMO_WriteReg_AGC_EN(XPAR_OFDM_AGC_MIMO_OPBW_0_BASEADDR, 1);
1200   
1201    return;
1202}
1203
1204void ofdm_AGC_Initialize(int noise_estimate){
1205   
1206    int g_bbset = 0;
1207   
1208    // First set all standard parameters
1209   
1210    // Turn off both resets and the master enable
1211    OFDM_AGC_MIMO_WriteReg_AGC_EN(XPAR_OFDM_AGC_MIMO_OPBW_0_BASEADDR, 0);
1212    OFDM_AGC_MIMO_WriteReg_SRESET_IN(XPAR_OFDM_AGC_MIMO_OPBW_0_BASEADDR, 0);
1213    OFDM_AGC_MIMO_WriteReg_MRESET_IN(XPAR_OFDM_AGC_MIMO_OPBW_0_BASEADDR, 0);
1214   
1215    // An adjustment parameter
1216    OFDM_AGC_MIMO_WriteReg_ADJ(XPAR_OFDM_AGC_MIMO_OPBW_0_BASEADDR, 8);
1217   
1218    // Timing for the DC-offset correction
1219//  OFDM_AGC_MIMO_WriteReg_DCO_Timing(XPAR_OFDM_AGC_MIMO_OPBW_0_BASEADDR, 0x46403003); //as used through v21
1220    OFDM_AGC_MIMO_WriteReg_DCO_Timing(XPAR_OFDM_AGC_MIMO_OPBW_0_BASEADDR, 0x463C2C03); //
1221   
1222    // Initial baseband gain setting
1223    OFDM_AGC_MIMO_WriteReg_GBB_init(XPAR_OFDM_AGC_MIMO_OPBW_0_BASEADDR, 52);
1224   
1225    // RF gain AGCstate thresholds
1226    OFDM_AGC_MIMO_WriteReg_Thresholds(XPAR_OFDM_AGC_MIMO_OPBW_0_BASEADDR, 
1227        ((AGC_THRESH_1&0xFF)<<16) +
1228        ((AGC_THRESH_2&0xFF)<<8) + 
1229         (AGC_THRESH_3&0xFF)
1230    );
1231   
1232    // Overall AGC timing
1233//  OFDM_AGC_MIMO_WriteReg_Timing(XPAR_OFDM_AGC_MIMO_OPBW_0_BASEADDR, 0x9A962A28);//0x826E3C0A;
1234//  OFDM_AGC_MIMO_WriteReg_Timing(XPAR_OFDM_AGC_MIMO_OPBW_0_BASEADDR, 0xAA962A28);//added time between GBB change and AGC_DONE (pom 2010-06-19)
1235//  OFDM_AGC_MIMO_WriteReg_Timing(XPAR_OFDM_AGC_MIMO_OPBW_0_BASEADDR, 0xEAC65A58);
1236    OFDM_AGC_MIMO_WriteReg_Timing(XPAR_OFDM_AGC_MIMO_OPBW_0_BASEADDR, 0xFAC62A28);//delayed I/Q sensitive steps by 12 samples for new Rx filter latency
1237   
1238    // vIQ and RSSI average lengths
1239    OFDM_AGC_MIMO_WriteReg_AVG_LEN(XPAR_OFDM_AGC_MIMO_OPBW_0_BASEADDR, 0x10F); //103
1240   
1241    // Disable DCO, disable DCO subtraction
1242    OFDM_AGC_MIMO_WriteReg_Bits(XPAR_OFDM_AGC_MIMO_OPBW_0_BASEADDR, 0x0);
1243   
1244    // Compute and set the initial g_BB gain value from the noise estimate
1245    // The initial g_bb sets noise to -19 db, assuming 32 db RF gain
1246   
1247    g_bbset = -19 - 32 - noise_estimate;
1248    OFDM_AGC_MIMO_WriteReg_GBB_init(XPAR_OFDM_AGC_MIMO_OPBW_0_BASEADDR, g_bbset);
1249   
1250    // Perform a master reset
1251    ofdm_AGC_MasterReset();
1252   
1253    // Agc is now reset and enabled, ready to go!
1254    return;
1255}
1256
1257
1258void ofdm_AGC_setNoiseEstimate(int noise_estimate){
1259    int g_bbset;
1260   
1261    g_bbset = -19 - 32 - noise_estimate;
1262   
1263    OFDM_AGC_MIMO_WriteReg_GBB_init(XPAR_OFDM_AGC_MIMO_OPBW_0_BASEADDR, g_bbset);
1264   
1265    return;
1266}
1267
1268unsigned int ofdm_AGC_GetGains(void){
1269   
1270    unsigned int gBB_A, gRF_A, gBB_B, gRF_B, gains;
1271   
1272    // Get the gains from the registers
1273    gBB_A = OFDM_AGC_MIMO_ReadReg_GBB_A(XPAR_OFDM_AGC_MIMO_OPBW_0_BASEADDR);
1274    gRF_A = OFDM_AGC_MIMO_ReadReg_GRF_A(XPAR_OFDM_AGC_MIMO_OPBW_0_BASEADDR);
1275   
1276    gBB_B = OFDM_AGC_MIMO_ReadReg_GBB_B(XPAR_OFDM_AGC_MIMO_OPBW_0_BASEADDR);
1277    gRF_B = OFDM_AGC_MIMO_ReadReg_GRF_B(XPAR_OFDM_AGC_MIMO_OPBW_0_BASEADDR);
1278   
1279    // First concatenate the two radios together, into the gRF register
1280    // 2 lowest bits are RF, 5 higher bits are BB, last bit is unused
1281    // Multiply by 2^2, shift gBB right by 2 bits
1282   
1283    gRF_A = gRF_A + (gBB_A * 4);
1284    gRF_B = gRF_B + (gBB_B * 4);
1285   
1286    // Multiply by 2^8 shift gRF right by 8 bits
1287    gains = gRF_A + (gRF_B * 256);
1288   
1289    // Returns hi[0 gBB_B g_RF_B | 0 g_BB_A g_RF_A]lo
1290    return gains;
1291}
1292
1293void ofdm_AGC_SetTarget(unsigned int target){
1294    OFDM_AGC_MIMO_WriteReg_T_dB(XPAR_OFDM_AGC_MIMO_OPBW_0_BASEADDR, target);
1295    return;
1296}
1297/******* END AGC core control functions ********/
1298
1299
1300
1301/******* WARP Timer core control functions *******/
1302void warp_timer_start(unsigned char timer) {
1303    warp_timer_WriteReg_control(warp_timer_ReadReg_control() | (TIMER_MASK_CALC(timer) & TIMER_CONTROL_START_MASK));
1304    warp_timer_WriteReg_control(warp_timer_ReadReg_control() & ~(TIMER_MASK_CALC(timer) & TIMER_CONTROL_START_MASK));
1305}
1306
1307void warp_timer_pause(unsigned char timer) {
1308    warp_timer_WriteReg_control(warp_timer_ReadReg_control() | (TIMER_MASK_CALC(timer) & TIMER_CONTROL_PAUSE_MASK));
1309}
1310
1311void warp_timer_resume(unsigned char timer) {
1312    warp_timer_WriteReg_control(warp_timer_ReadReg_control() & ~(TIMER_MASK_CALC(timer) & TIMER_CONTROL_PAUSE_MASK));
1313}
1314
1315void warp_timer_setMode(unsigned char timer, unsigned char mode) {
1316    if(mode == 1)
1317        warp_timer_WriteReg_control(warp_timer_ReadReg_control() | (TIMER_MASK_CALC(timer) & TIMER_CONTROL_MODE_MASK));
1318    else
1319        warp_timer_WriteReg_control(warp_timer_ReadReg_control() & ~(TIMER_MASK_CALC(timer) & TIMER_CONTROL_MODE_MASK));
1320}
1321
1322void warp_timer_resetDone(unsigned char timer) {
1323    warp_timer_WriteReg_control(warp_timer_ReadReg_control() | (TIMER_MASK_CALC(timer) & TIMER_CONTROL_RESETDONE_MASK));
1324    warp_timer_WriteReg_control(warp_timer_ReadReg_control() & ~(TIMER_MASK_CALC(timer) & TIMER_CONTROL_RESETDONE_MASK));
1325}
1326
1327void warp_timer_resetAllDoneStatus() {
1328    warp_timer_WriteReg_control(warp_timer_ReadReg_control() | (TIMER_CONTROL_RESETDONE_MASK));
1329    warp_timer_WriteReg_control(warp_timer_ReadReg_control() & ~(TIMER_CONTROL_RESETDONE_MASK));
1330}
1331
1332void warp_timer_setTimer(unsigned char timer, unsigned int slotTime, unsigned int slotCount) {
1333    switch(timer) {
1334    case 0:
1335        XIo_Out32(XPAR_WARP_TIMER_PLBW_0_MEMMAP_TIMER0_SLOTCOUNT, (Xuint32)(slotCount));
1336        XIo_Out32(XPAR_WARP_TIMER_PLBW_0_MEMMAP_TIMERS01_SLOTTIME, ( (XIo_In32(XPAR_WARP_TIMER_PLBW_0_MEMMAP_TIMERS01_SLOTTIME) & 0xFFFF0000) | slotTime) );
1337        return;
1338    case 1:
1339        XIo_Out32(XPAR_WARP_TIMER_PLBW_0_MEMMAP_TIMER1_SLOTCOUNT, (Xuint32)(slotCount));
1340        XIo_Out32(XPAR_WARP_TIMER_PLBW_0_MEMMAP_TIMERS01_SLOTTIME, ( (XIo_In32(XPAR_WARP_TIMER_PLBW_0_MEMMAP_TIMERS01_SLOTTIME) & 0x0000FFFF) | (slotTime<<16) ) ); 
1341        return;
1342    case 2:
1343        XIo_Out32(XPAR_WARP_TIMER_PLBW_0_MEMMAP_TIMER2_SLOTCOUNT, (Xuint32)(slotCount));
1344        XIo_Out32(XPAR_WARP_TIMER_PLBW_0_MEMMAP_TIMERS23_SLOTTIME, ( (XIo_In32(XPAR_WARP_TIMER_PLBW_0_MEMMAP_TIMERS23_SLOTTIME) & 0xFFFF0000) | slotTime) );
1345        return;
1346    case 3:
1347        XIo_Out32(XPAR_WARP_TIMER_PLBW_0_MEMMAP_TIMER3_SLOTCOUNT, (Xuint32)(slotCount));
1348        XIo_Out32(XPAR_WARP_TIMER_PLBW_0_MEMMAP_TIMERS23_SLOTTIME, ( (XIo_In32(XPAR_WARP_TIMER_PLBW_0_MEMMAP_TIMERS23_SLOTTIME) & 0x0000FFFF) | (slotTime<<16) ) );
1349        return;
1350    case 4:
1351        XIo_Out32(XPAR_WARP_TIMER_PLBW_0_MEMMAP_TIMER4_SLOTCOUNT, (Xuint32)(slotCount));
1352        XIo_Out32(XPAR_WARP_TIMER_PLBW_0_MEMMAP_TIMERS45_SLOTTIME, ( (XIo_In32(XPAR_WARP_TIMER_PLBW_0_MEMMAP_TIMERS45_SLOTTIME) & 0xFFFF0000) | slotTime) );
1353        return;
1354    case 5:
1355        XIo_Out32(XPAR_WARP_TIMER_PLBW_0_MEMMAP_TIMER5_SLOTCOUNT, (Xuint32)(slotCount));
1356        XIo_Out32(XPAR_WARP_TIMER_PLBW_0_MEMMAP_TIMERS45_SLOTTIME, ( (XIo_In32(XPAR_WARP_TIMER_PLBW_0_MEMMAP_TIMERS45_SLOTTIME) & 0x0000FFFF) | (slotTime<<16) ) );
1357        return;
1358    case 6:
1359        XIo_Out32(XPAR_WARP_TIMER_PLBW_0_MEMMAP_TIMER6_SLOTCOUNT, (Xuint32)(slotCount));
1360        XIo_Out32(XPAR_WARP_TIMER_PLBW_0_MEMMAP_TIMERS67_SLOTTIME, ( (XIo_In32(XPAR_WARP_TIMER_PLBW_0_MEMMAP_TIMERS67_SLOTTIME) & 0xFFFF0000) | slotTime) );
1361        return;
1362    case 7:
1363        XIo_Out32(XPAR_WARP_TIMER_PLBW_0_MEMMAP_TIMER7_SLOTCOUNT, (Xuint32)(slotCount));
1364        XIo_Out32(XPAR_WARP_TIMER_PLBW_0_MEMMAP_TIMERS67_SLOTTIME, ( (XIo_In32(XPAR_WARP_TIMER_PLBW_0_MEMMAP_TIMERS67_SLOTTIME) & 0x0000FFFF) | (slotTime<<16) ) );
1365        return;
1366    default:
1367        return;
1368    }
1369}
1370
1371unsigned char warp_timer_getStatus(unsigned char timer) {
1372    return (XIo_In32(XPAR_WARP_TIMER_PLBW_0_MEMMAP_TIMER_STATUS) >> (timer*4)) & 0xf;
1373}
1374
1375unsigned char warp_timer_isDone(unsigned char timer) {
1376    return (XIo_In32(XPAR_WARP_TIMER_PLBW_0_MEMMAP_TIMER_STATUS) & TIMER_MASK_CALC(timer) & TIMER_STATUS_DONE_MASK) != 0;
1377}
1378
1379unsigned char warp_timer_isActive(unsigned char timer) {
1380    return (XIo_In32(XPAR_WARP_TIMER_PLBW_0_MEMMAP_TIMER_STATUS) & TIMER_MASK_CALC(timer) & TIMER_STATUS_RUNNING_MASK) != 0;
1381}
1382
1383unsigned char warp_timer_isPaused(unsigned char timer) {
1384    return (XIo_In32(XPAR_WARP_TIMER_PLBW_0_MEMMAP_TIMER_STATUS) & TIMER_MASK_CALC(timer) & TIMER_STATUS_PASUED_MASK) != 0;
1385}
1386
1387unsigned int warp_timer_getStatuses() {
1388    return XIo_In32(XPAR_WARP_TIMER_PLBW_0_MEMMAP_TIMER_STATUS);
1389}
1390
1391unsigned char warp_timer_getDoneStatus() {
1392    return (XIo_In32(XPAR_WARP_TIMER_PLBW_0_MEMMAP_TIMER_STATUS) & TIMER_STATUS_DONE_MASK);
1393}
1394
1395void warp_timer_init(){
1396    //Clear all start/pause/mode/donereset bits
1397    XIo_Out32(XPAR_WARP_TIMER_PLBW_0_MEMMAP_TIMER_CONTROL, 0);
1398
1399    //Set sane values for the slot times and slot counts
1400    warp_timer_setTimer(0, 500, 32);
1401    warp_timer_setTimer(1, 500, 32);
1402    warp_timer_setTimer(2, 500, 32);
1403    warp_timer_setTimer(3, 500, 32);
1404    warp_timer_setTimer(4, 500, 32);
1405    warp_timer_setTimer(5, 500, 32);
1406    warp_timer_setTimer(6, 500, 32);
1407    warp_timer_setTimer(7, 500, 32);
1408
1409    //Clear any stale timer-done status bits
1410    warp_timer_resetAllDoneStatus();
1411    return;
1412}
1413/******* END WARP Timer core control functions *******/
1414
1415///@brief Set the transmit power (via the radio's RF VGA)
1416///@param txPwr Desired transmit power; must be integer in [0,63]
1417///@return Returns -1 if an invalid power is requested; 0 on success
1418int warpphy_setTxPower(unsigned char txPwr)
1419{
1420    if(txPwr > 63)
1421        return -1;
1422    else
1423        WarpRadio_v1_SetTxGainTiming(FIRST_RADIO | SECOND_RADIO, (0x3F & txPwr), 0xF, 1);
1424
1425    return 0;
1426}
1427
1428void warpphy_setAutoCorrDetParams(unsigned short corrThresh, unsigned short energyThresh) {
1429    ofdm_txrx_mimo_WriteReg_Rx_PktDetCorr_params(corrThresh, energyThresh);
1430    return;
1431}
1432
1433void warpphy_setLongCorrThresh(unsigned short thresh) {
1434    pktDet_carrierSenseThresh = thresh;
1435    XIo_Out32(XPAR_OFDM_TXRX_MIMO_PLBW_0_MEMMAP_RX_PKTDET_LONGCORR_THRESHOLDS, thresh);
1436}
1437
1438void warpphy_setCarrierSenseThresh(unsigned short thresh) {
1439    longCorrThresh = thresh;
1440    ofdm_txrx_mimo_WriteReg_Rx_CSMA_setThresh(pktDet_carrierSenseThresh);
1441}
1442
1443void warpphy_setEnergyDetThresh(unsigned short thresh) {
1444    pktDet_energyThresh = thresh;
1445    ofdm_txrx_mimo_WriteReg_Rx_PktDet_setThresh(thresh);
1446}
1447
1448
1449void warpphy_setAntBPreambleShift(unsigned char shift)
1450{
1451    mimo_ofdmTx_setControlBits( (mimo_ofdmTx_getOptions() & ~(0xF0)) | ((shift&0xF)<<4) );
1452}
1453
1454/*********************************************************************/
1455/* A whole bunch of debugging functions - these will go away someday */
1456/*********************************************************************/
1457
1458#if INCLUDE_WARPPHY_DEBUG_FUNCTIONS
1459
1460void warpphy_incrementTxScaling(int incr_preamble, int incr_payload)
1461{
1462    txScaling_preamble += incr_preamble;
1463    txScaling_payload += incr_payload;
1464    mimo_ofdmTx_setTxScaling(txScaling_preamble, txScaling_payload);
1465    xil_printf("TxScaling: Preamble = %d\tPayload = %d\r\n", txScaling_preamble, txScaling_payload);
1466    return;
1467}
1468
1469
1470void warpphy_setPktDlyPlus(){
1471    ofdmRx_pktDetDly++;
1472    xil_printf("+ofdmRx_pktDetDly = %d\r\n", ofdmRx_pktDetDly);
1473    mimo_ofdmRx_setPktDetDly(ofdmRx_pktDetDly);
1474}
1475void warpphy_setPktDlyMinus(){
1476    ofdmRx_pktDetDly--;
1477    xil_printf("-ofdmRx_pktDetDly = %d\r\n", ofdmRx_pktDetDly);
1478    mimo_ofdmRx_setPktDetDly(ofdmRx_pktDetDly);
1479}
1480
1481/*********************/
1482/* Other PHY options */
1483/*********************/
1484
1485void warpphy_set_FFTOffset_Plus(){
1486    RxFFT_Window_Offset++;
1487    mimo_ofdmRx_setFFTWindowOffset(RxFFT_Window_Offset);
1488    xil_printf("Rx FFT Offset: %d\r\n", RxFFT_Window_Offset);
1489}
1490
1491void warpphy_set_FFTOffset_Minus(){
1492    RxFFT_Window_Offset--;
1493    mimo_ofdmRx_setFFTWindowOffset(RxFFT_Window_Offset);
1494    xil_printf("Rx FFT Offset: %d\r\n", RxFFT_Window_Offset);
1495}
1496
1497void warpphy_setNoiseTargetPlus(){
1498    agc_noisePowerEstimate++;
1499    xil_printf("+Noise Estimate = %d\r\n", agc_noisePowerEstimate);
1500    ofdm_AGC_setNoiseEstimate(agc_noisePowerEstimate);
1501}
1502
1503void warpphy_setNoiseTargetMinus(){
1504    agc_noisePowerEstimate--;
1505    xil_printf("-Noise Estimate = %d\r\n", agc_noisePowerEstimate);
1506    ofdm_AGC_setNoiseEstimate(agc_noisePowerEstimate);
1507}
1508
1509void warpphy_setTargetPlus(){
1510    agc_targetRxPowerOut++;
1511    xil_printf("+agc_targetRxPowerOut = %d\r\n", agc_targetRxPowerOut);
1512    ofdm_AGC_SetTarget(agc_targetRxPowerOut);
1513}
1514
1515void warpphy_setTargetMinus(){
1516    agc_targetRxPowerOut--;
1517    xil_printf("-agc_targetRxPowerOut = %d\r\n", agc_targetRxPowerOut);
1518    ofdm_AGC_SetTarget(agc_targetRxPowerOut);
1519}
1520
1521void warpphy_setPktDetPlus(unsigned int offset){
1522    pktDet_energyThresh=pktDet_energyThresh+offset;
1523    //ofdm_pktDetector_mimo_WriteReg_pktDet_avgThresh(PKTDET_BASEADDR, pktDet_energyThresh);
1524    ofdm_txrx_mimo_WriteReg_Rx_PktDet_setThresh(pktDet_energyThresh);
1525    xil_printf("pktDet_energyThresh = %d\r\n",pktDet_energyThresh);
1526}
1527
1528void warpphy_setPktDetMinus(unsigned int offset){
1529    pktDet_energyThresh=pktDet_energyThresh-offset;
1530    //ofdm_pktDetector_mimo_WriteReg_pktDet_avgThresh(PKTDET_BASEADDR, pktDet_energyThresh);
1531    ofdm_txrx_mimo_WriteReg_Rx_PktDet_setThresh(pktDet_energyThresh);
1532   
1533    xil_printf("pktDet_energyThresh = %d\r\n",pktDet_energyThresh);
1534}
1535
1536void warpphy_setPktDetMinDurPlus(unsigned int offset){
1537    pktDet_threshMinDur = pktDet_threshMinDur + offset;
1538
1539    ofdm_txrx_mimo_WriteReg_Rx_PktDet_setMinDuration(pktDet_threshMinDur);
1540    xil_printf("Minimum Duration = %d\r\n", pktDet_threshMinDur);
1541}
1542
1543void warpphy_setPktDetMinDurMinus(unsigned int offset){
1544    pktDet_threshMinDur = pktDet_threshMinDur - offset;
1545   
1546    ofdm_txrx_mimo_WriteReg_Rx_PktDet_setMinDuration(pktDet_threshMinDur);
1547    xil_printf("Minimum Duration = %d\r\n", pktDet_threshMinDur);
1548}
1549
1550void warpphy_setCSMAPlus(unsigned int offset){
1551    pktDet_carrierSenseThresh = pktDet_carrierSenseThresh + offset;
1552
1553    ofdm_txrx_mimo_WriteReg_Rx_CSMA_setThresh(pktDet_carrierSenseThresh);
1554    xil_printf("Carrier Sense Thresh = %d\r\n", pktDet_carrierSenseThresh);
1555}
1556
1557void warpphy_setCSMAMinus(unsigned int offset){
1558    pktDet_carrierSenseThresh = pktDet_carrierSenseThresh - offset;
1559   
1560    ofdm_txrx_mimo_WriteReg_Rx_CSMA_setThresh(pktDet_carrierSenseThresh);
1561    xil_printf("Carrier Sense Thresh = %d\r\n", pktDet_carrierSenseThresh);
1562}
1563
1564void warpphy_setGainPlus(unsigned int offset){
1565    txGain=txGain+offset;
1566    WarpRadio_v1_SetTxGainTiming(FIRST_RADIO | SECOND_RADIO, txGain, 0xF, 2);
1567    xil_printf("TxGain = %x\r\n",txGain);
1568}
1569
1570void warpphy_setGainMinus(unsigned int offset){
1571    txGain=txGain-offset;
1572    WarpRadio_v1_SetTxGainTiming(FIRST_RADIO | SECOND_RADIO, txGain, 0xF, 2);
1573    xil_printf("TxGain = %x\r\n",txGain);
1574}
1575
1576
1577#endif
1578
Note: See TracBrowser for help on using the repository browser.