moving targets/ARCH to sdr/
This commit is contained in:
@@ -0,0 +1,420 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/if_packet.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/ether.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
/** @addtogroup _LMSSDR_PHY_RF_INTERFACE_
|
||||
* @{
|
||||
*/
|
||||
#include <lime/LimeSuite.h>
|
||||
#include <lime/LMS7002M.h>
|
||||
#include <lime/LMS7002M_RegistersMap.h>
|
||||
#include "common_lib.h"
|
||||
|
||||
lms_device_t* lms_device;
|
||||
lms_stream_t rx_stream;
|
||||
lms_stream_t tx_stream;
|
||||
|
||||
/* We have a strange behavior when we just start reading
|
||||
* from the device (inconsistent values of the timestamp).
|
||||
* A quick solution is to discard the very first read packet
|
||||
* after a "start".
|
||||
* The following global variable "first_rx" serves that purpose.
|
||||
*/
|
||||
static int first_rx = 0;
|
||||
|
||||
#define RXDCLENGTH 4096
|
||||
#define NUMBUFF 32
|
||||
|
||||
using namespace lime;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
int write_output(const char *fname,const char *vname,void *data,int length,int dec,char format);
|
||||
}
|
||||
|
||||
/*! \brief Called to send samples to the LMSSDR RF target
|
||||
\param device pointer to the device structure specific to the RF hardware target
|
||||
\param timestamp The timestamp at whicch the first sample MUST be sent
|
||||
\param buff Buffer which holds the samples
|
||||
\param nsamps number of samples to be sent
|
||||
\param antenna_id index of the antenna
|
||||
\param flags Ignored for the moment
|
||||
\returns 0 on success
|
||||
*/
|
||||
int trx_lms_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int antenna_id, int flags) {
|
||||
|
||||
|
||||
lms_stream_meta_t meta;
|
||||
meta.waitForTimestamp = true;
|
||||
meta.flushPartialPacket = false;
|
||||
meta.timestamp = timestamp;
|
||||
|
||||
|
||||
return LMS_SendStream(&tx_stream,(const void*)buff[0],nsamps,&meta,30);
|
||||
}
|
||||
|
||||
/*! \brief Receive samples from hardware.
|
||||
* Read \ref nsamps samples from each channel to buffers. buff[0] is the array for
|
||||
* the first channel. *ptimestamp is the time at which the first sample
|
||||
* was received.
|
||||
* \param device the hardware to use
|
||||
* \param[out] ptimestamp the time at which the first sample was received.
|
||||
* \param[out] buff An array of pointers to buffers for received samples. The buffers must be large enough to hold the number of samples \ref nsamps.
|
||||
* \param nsamps Number of samples. One sample is 2 byte I + 2 byte Q => 4 byte.
|
||||
* \param antenna_id Index of antenna port
|
||||
* \returns number of samples read
|
||||
*/
|
||||
int trx_lms_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int antenna_id) {
|
||||
|
||||
lms_stream_meta_t meta;
|
||||
meta.waitForTimestamp = false;
|
||||
meta.flushPartialPacket = false;
|
||||
|
||||
int ret;
|
||||
if (first_rx == 1) {
|
||||
first_rx = 0;
|
||||
ret = LMS_RecvStream(&rx_stream,buff[0],nsamps,&meta,50);
|
||||
}
|
||||
ret = LMS_RecvStream(&rx_stream,buff[0],nsamps,&meta,50);
|
||||
*ptimestamp = meta.timestamp;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*! \brief set RX gain offset from calibration table
|
||||
* \param openair0_cfg RF frontend parameters set by application
|
||||
* \param chain_index RF chain ID
|
||||
*/
|
||||
void set_rx_gain_offset(openair0_config_t *openair0_cfg, int chain_index) {
|
||||
|
||||
int i=0;
|
||||
// loop through calibration table to find best adjustment factor for RX frequency
|
||||
double min_diff = 6e9,diff;
|
||||
|
||||
while (openair0_cfg->rx_gain_calib_table[i].freq>0) {
|
||||
diff = fabs(openair0_cfg->rx_freq[chain_index] - openair0_cfg->rx_gain_calib_table[i].freq);
|
||||
printf("cal %d: freq %f, offset %f, diff %f\n",
|
||||
i,
|
||||
openair0_cfg->rx_gain_calib_table[i].freq,
|
||||
openair0_cfg->rx_gain_calib_table[i].offset,diff);
|
||||
if (min_diff > diff) {
|
||||
min_diff = diff;
|
||||
openair0_cfg->rx_gain_offset[chain_index] = openair0_cfg->rx_gain_calib_table[i].offset;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*! \brief Set Gains (TX/RX) on LMSSDR
|
||||
* \param device the hardware to use
|
||||
* \param openair0_cfg openair0 Config structure
|
||||
* \returns 0 in success, -1 on error
|
||||
*/
|
||||
int trx_lms_set_gains(openair0_device* device, openair0_config_t *openair0_cfg) {
|
||||
int ret = 0;
|
||||
|
||||
if (openair0_cfg->rx_gain[0] > 70+openair0_cfg->rx_gain_offset[0]) {
|
||||
printf("[LMS] Reduce RX Gain 0 by %f dB\n",openair0_cfg->rx_gain[0]-openair0_cfg->rx_gain_offset[0]-70);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
LMS_SetGaindB(lms_device, LMS_CH_TX, 0, openair0_cfg->tx_gain[0]);
|
||||
LMS_SetGaindB(lms_device, LMS_CH_RX, 0, openair0_cfg->rx_gain[0]-openair0_cfg->rx_gain_offset[0]);
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/*! \brief Start LMSSDR
|
||||
* \param device the hardware to use
|
||||
* \returns 0 on success
|
||||
*/
|
||||
int trx_lms_start(openair0_device *device){
|
||||
|
||||
lms_info_str_t list[16]={0};
|
||||
|
||||
int n= LMS_GetDeviceList(list);
|
||||
|
||||
if (n <= 0) {
|
||||
fprintf(stderr, "No LimeSDR board found: %s\n", n < 0?LMS_GetLastErrorMessage():"");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Connecting to device: %s\n",list[0]);
|
||||
if (LMS_Open(&lms_device,list[0],NULL)<0) {
|
||||
fprintf(stderr, "Can't open device port: %s\n",LMS_GetLastErrorMessage());
|
||||
return -1;
|
||||
}
|
||||
|
||||
LMS_Init(lms_device);
|
||||
LMS_EnableCache(lms_device,false);
|
||||
|
||||
if (LMS_LoadConfig(lms_device,device->openair0_cfg[0].configFilename) != 0)
|
||||
{
|
||||
printf("Failed to load configuration file %s\n%s",device->openair0_cfg[0].configFilename,LMS_GetLastErrorMessage());
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* LMS_EnableChannel(lms_device,LMS_CH_RX,0,true);
|
||||
LMS_EnableChannel(lms_device,LMS_CH_TX,0,true);
|
||||
if (device->openair0_cfg->rx_num_channels == 2)
|
||||
{
|
||||
LMS_EnableChannel(lms_device,LMS_CH_RX,1,true);
|
||||
LMS_EnableChannel(lms_device,LMS_CH_TX,1,true);
|
||||
} */
|
||||
LMS_VCTCXOWrite(lms_device, 129);
|
||||
|
||||
if (LMS_SetSampleRate(lms_device,device->openair0_cfg->sample_rate,2)!=0)
|
||||
{
|
||||
fprintf(stderr, "Failed to set sample rate %s\n",LMS_GetLastErrorMessage());
|
||||
return -1;
|
||||
}
|
||||
printf("Set sample rate %f MHz\n",device->openair0_cfg->sample_rate/1e6);
|
||||
|
||||
if (LMS_SetLOFrequency(lms_device,LMS_CH_RX, 0, device->openair0_cfg[0].rx_freq[0])!=0)
|
||||
{
|
||||
fprintf(stderr, "Failed to Set Rx frequency: %s\n", LMS_GetLastErrorMessage());
|
||||
return -1;
|
||||
}
|
||||
if (LMS_SetLOFrequency(lms_device,LMS_CH_TX, 0,device->openair0_cfg[0].tx_freq[0])!=0)
|
||||
{
|
||||
fprintf(stderr, "Failed to Set Tx frequency: %s\n", LMS_GetLastErrorMessage());
|
||||
return -1;
|
||||
}
|
||||
printf("Set TX frequency %f MHz\n",device->openair0_cfg[0].tx_freq[0]/1e6);
|
||||
|
||||
/*
|
||||
printf("Override antenna settings to: RX1_H, TXA_2");
|
||||
LMS_SetAntenna(lms_device, LMS_CH_RX, 0, 1);
|
||||
LMS_SetAntenna(lms_device, LMS_CH_TX, 0, 2);
|
||||
*/
|
||||
|
||||
|
||||
for (int i = 0; i< device->openair0_cfg->rx_num_channels; i++)
|
||||
{
|
||||
if (LMS_SetLPFBW(lms_device,LMS_CH_RX,i,device->openair0_cfg->rx_bw)!=0)
|
||||
printf("RX ch:%d filter calibration failed, bw:%fMHz\n%s\n",i,device->openair0_cfg->rx_bw/1e6,LMS_GetLastErrorMessage());
|
||||
if (LMS_SetLPFBW(lms_device,LMS_CH_TX,i,device->openair0_cfg->tx_bw)!=0)
|
||||
printf("TX ch:%d filter calibration failed, bw:%fMHz\n%s\n",i,device->openair0_cfg->tx_bw/1e6,LMS_GetLastErrorMessage());
|
||||
|
||||
if (LMS_Calibrate(lms_device,LMS_CH_RX,i,device->openair0_cfg->rx_bw,0)!=0)
|
||||
printf("RX ch:%d calibration failed, bw:%f MHz\n%s\n",i,device->openair0_cfg->rx_bw/1e6,LMS_GetLastErrorMessage());
|
||||
if (LMS_Calibrate(lms_device,LMS_CH_TX,i,device->openair0_cfg->tx_bw,0)!=0)
|
||||
printf("TX ch:%d calibration failed, bw:%fMHz\n%s\n",i,device->openair0_cfg->tx_bw/1e6,LMS_GetLastErrorMessage());
|
||||
}
|
||||
|
||||
|
||||
first_rx = 1;
|
||||
|
||||
rx_stream.channel = 0;
|
||||
rx_stream.fifoSize = 256*1024;
|
||||
rx_stream.throughputVsLatency = 0.1;
|
||||
rx_stream.dataFmt = lms_stream_t::LMS_FMT_I12;
|
||||
rx_stream.isTx = false;
|
||||
if (LMS_SetupStream(lms_device, &rx_stream)!=0)
|
||||
printf("RX stream setup failed %s\n",LMS_GetLastErrorMessage());
|
||||
tx_stream.channel = 0;
|
||||
tx_stream.fifoSize = 256*1024;
|
||||
tx_stream.throughputVsLatency = 0.1;
|
||||
tx_stream.dataFmt = lms_stream_t::LMS_FMT_I12;
|
||||
tx_stream.isTx = true;
|
||||
|
||||
trx_lms_set_gains(device, device->openair0_cfg);
|
||||
|
||||
if (LMS_SetupStream(lms_device, &tx_stream)!=0)
|
||||
printf("TX stream setup failed %s\n",LMS_GetLastErrorMessage());
|
||||
|
||||
printf("SR: %.3f MHz\n", (float)device->openair0_cfg->sample_rate / 1e6);
|
||||
|
||||
|
||||
printf("SR: %.3f MHz\n", (float)device->openair0_cfg->sample_rate / 1e6);
|
||||
|
||||
if (LMS_StartStream(&rx_stream)!=0)
|
||||
printf("Failed to start TX stream %s\n",LMS_GetLastErrorMessage());
|
||||
if (LMS_StartStream(&tx_stream)!=0)
|
||||
printf("Failed to start Rx stream %s\n",LMS_GetLastErrorMessage());
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief Stop LMSSDR
|
||||
* \param card Index of the RF card to use
|
||||
* \returns 0 on success
|
||||
*/
|
||||
int trx_lms_stop(openair0_device *device) {
|
||||
LMS_StopStream(&rx_stream);
|
||||
LMS_StopStream(&tx_stream);
|
||||
LMS_DestroyStream(lms_device,&rx_stream);
|
||||
LMS_DestroyStream(lms_device,&tx_stream);
|
||||
LMS_Close(lms_device);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief Set frequencies (TX/RX)
|
||||
* \param device the hardware to use
|
||||
* \param openair0_cfg openair0 Config structure (ignored. It is there to comply with RF common API)
|
||||
* \param exmimo_dump_config (ignored)
|
||||
* \returns 0 in success
|
||||
*/
|
||||
int trx_lms_set_freq(openair0_device* device, openair0_config_t *openair0_cfg,int exmimo_dump_config) {
|
||||
//Control port must be connected
|
||||
LMS_SetLOFrequency(lms_device,LMS_CH_TX,0,openair0_cfg->tx_freq[0]);
|
||||
LMS_SetLOFrequency(lms_device,LMS_CH_RX,0,openair0_cfg->rx_freq[0]);
|
||||
printf ("[LMS] rx frequency:%f;\n",openair0_cfg->rx_freq[0]/1e6);
|
||||
set_rx_gain_offset(openair0_cfg,0);
|
||||
return(0);
|
||||
|
||||
}
|
||||
|
||||
// 31 = 19 dB => 105 dB total gain @ 2.6 GHz
|
||||
/*! \brief calibration table for LMSSDR */
|
||||
// V1.2 board
|
||||
rx_gain_calib_table_t calib_table_lmssdr_1v2[] = {
|
||||
{3500000000.0,44.0}, // on L PAD
|
||||
{2660000000.0,55.0}, // on L PAD
|
||||
{2300000000.0,54.0}, // on L PAD
|
||||
{1880000000.0,54.0}, // on L PAD
|
||||
{816000000.0,79.0}, // on W PAD
|
||||
{-1,0}};
|
||||
// V1.4 board
|
||||
rx_gain_calib_table_t calib_table_lmssdr[] = {
|
||||
{3500000000.0,44.0}, // on H PAD
|
||||
{2660000000.0,55.0}, // on H PAD
|
||||
{2300000000.0,54.0}, // on H PAD
|
||||
{1880000000.0,54.0}, // on H PAD
|
||||
{816000000.0,79.0}, // on L PAD
|
||||
{-1,0}};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*! \brief Get LMSSDR Statistics
|
||||
* \param device the hardware to use
|
||||
* \returns 0 in success
|
||||
*/
|
||||
|
||||
int trx_lms_get_stats(openair0_device* device) {
|
||||
|
||||
return(0);
|
||||
|
||||
}
|
||||
|
||||
/*! \brief Reset LMSSDR Statistics
|
||||
* \param device the hardware to use
|
||||
* \returns 0 in success
|
||||
*/
|
||||
int trx_lms_reset_stats(openair0_device* device) {
|
||||
|
||||
return(0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Terminate operation of the LMSSDR transceiver -- free all associated resources
|
||||
* \param device the hardware to use
|
||||
*/
|
||||
void trx_lms_end(openair0_device *device) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
int trx_lms_write_init(openair0_device *device)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
extern "C" {
|
||||
/*! \brief Initialize Openair LMSSDR target. It returns 0 if OK
|
||||
* \param device the hardware to use
|
||||
* \param openair0_cfg RF frontend parameters set by application
|
||||
*/
|
||||
int device_init(openair0_device *device, openair0_config_t *openair0_cfg){
|
||||
|
||||
device->type=LMSSDR_DEV;
|
||||
|
||||
printf("LMSSDR: Initializing openair0_device for %s ...\n", ((device->host_type == RAU_HOST) ? "RAU": "RRU"));
|
||||
|
||||
switch ((int)openair0_cfg[0].sample_rate) {
|
||||
case 30720000:
|
||||
// from usrp_time_offset
|
||||
openair0_cfg[0].samples_per_packet = 2048;
|
||||
openair0_cfg[0].tx_sample_advance = 40;
|
||||
openair0_cfg[0].tx_bw = 30.72e6;
|
||||
openair0_cfg[0].rx_bw = 30.72e6;
|
||||
break;
|
||||
case 15360000:
|
||||
openair0_cfg[0].samples_per_packet = 2048;
|
||||
openair0_cfg[0].tx_sample_advance = 50; /* TODO: to be refined */
|
||||
openair0_cfg[0].tx_bw = 15.36e6;
|
||||
openair0_cfg[0].rx_bw = 15.36e6;
|
||||
break;
|
||||
case 7680000:
|
||||
openair0_cfg[0].samples_per_packet = 1024;
|
||||
openair0_cfg[0].tx_sample_advance = 50;
|
||||
openair0_cfg[0].tx_bw = 5.0e6;
|
||||
openair0_cfg[0].rx_bw = 5.0e6;
|
||||
break;
|
||||
case 1920000:
|
||||
openair0_cfg[0].samples_per_packet = 256;
|
||||
openair0_cfg[0].tx_sample_advance = 10;
|
||||
openair0_cfg[0].tx_bw = 1.25e6;
|
||||
openair0_cfg[0].rx_bw = 1.25e6;
|
||||
break;
|
||||
default:
|
||||
printf("Error: unknown sampling rate %f\n",openair0_cfg[0].sample_rate);
|
||||
exit(-1);
|
||||
break;
|
||||
}
|
||||
|
||||
openair0_cfg[0].rx_gain_calib_table = calib_table_lmssdr;
|
||||
set_rx_gain_offset(openair0_cfg,0);
|
||||
|
||||
device->Mod_id = 1;
|
||||
device->trx_start_func = trx_lms_start;
|
||||
device->trx_write_func = trx_lms_write;
|
||||
device->trx_read_func = trx_lms_read;
|
||||
device->trx_get_stats_func = trx_lms_get_stats;
|
||||
device->trx_reset_stats_func = trx_lms_reset_stats;
|
||||
device->trx_end_func = trx_lms_end;
|
||||
device->trx_stop_func = trx_lms_stop;
|
||||
device->trx_set_freq_func = trx_lms_set_freq;
|
||||
device->trx_set_gains_func = trx_lms_set_gains;
|
||||
device->trx_write_init = trx_lms_write_init;
|
||||
|
||||
device->openair0_cfg = openair0_cfg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/*@}*/
|
||||
@@ -0,0 +1,715 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/** sodera_lib.c
|
||||
*
|
||||
* Author: Raymond Knopp
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <complex>
|
||||
#include <fstream>
|
||||
#include <cmath>
|
||||
|
||||
#include "common_lib.h"
|
||||
|
||||
#include "lmsComms.h"
|
||||
#include "LMS7002M.h"
|
||||
#include "Si5351C.h"
|
||||
#include "LMS_StreamBoard.h"
|
||||
|
||||
#ifdef __SSE4_1__
|
||||
# include <smmintrin.h>
|
||||
#endif
|
||||
|
||||
#ifdef __AVX2__
|
||||
# include <immintrin.h>
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
int num_devices=0;
|
||||
/*These items configure the underlying asynch stream used by the the sync interface.
|
||||
*/
|
||||
|
||||
#define BUFFERSIZE 4096
|
||||
#define BUFFERSCOUNT 32
|
||||
typedef struct
|
||||
{
|
||||
|
||||
// --------------------------------
|
||||
// variables for SoDeRa configuration
|
||||
// --------------------------------
|
||||
|
||||
LMScomms Port;
|
||||
Si5351C Si;
|
||||
LMS7002M lmsControl;
|
||||
LMS_StreamBoard *lmsStream;
|
||||
|
||||
char buffers_rx[BUFFERSIZE*BUFFERSCOUNT];
|
||||
int handles[BUFFERSCOUNT];
|
||||
int current_handle;
|
||||
int samples_left_buffer;
|
||||
|
||||
double sample_rate;
|
||||
// time offset between transmiter timestamp and receiver timestamp;
|
||||
double tdiff;
|
||||
|
||||
int channelscount;
|
||||
// --------------------------------
|
||||
// Debug and output control
|
||||
// --------------------------------
|
||||
int num_underflows;
|
||||
int num_overflows;
|
||||
int num_seq_errors;
|
||||
|
||||
int64_t tx_count;
|
||||
int64_t rx_count;
|
||||
openair0_timestamp rx_timestamp;
|
||||
|
||||
} sodera_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t reserved[8];
|
||||
uint64_t counter;
|
||||
char data[4080];
|
||||
} StreamPacket_t;
|
||||
|
||||
sodera_t sodera_state;
|
||||
|
||||
enum STATUS {
|
||||
SUCCESS,
|
||||
FAILURE
|
||||
};
|
||||
|
||||
STATUS SPI_write(LMScomms* dataPort, uint16_t address, uint16_t data)
|
||||
{
|
||||
assert(dataPort != nullptr);
|
||||
LMScomms::GenericPacket ctrPkt;
|
||||
ctrPkt.cmd = CMD_BRDSPI_WR;
|
||||
ctrPkt.outBuffer.push_back((address >> 8) & 0xFF);
|
||||
ctrPkt.outBuffer.push_back(address & 0xFF);
|
||||
ctrPkt.outBuffer.push_back((data >> 8) & 0xFF);
|
||||
ctrPkt.outBuffer.push_back(data & 0xFF);
|
||||
dataPort->TransferPacket(ctrPkt);
|
||||
return ctrPkt.status == 1 ? SUCCESS : FAILURE;
|
||||
}
|
||||
|
||||
uint16_t SPI_read(LMScomms* dataPort, uint16_t address)
|
||||
{
|
||||
assert(dataPort != nullptr);
|
||||
LMScomms::GenericPacket ctrPkt;
|
||||
ctrPkt.cmd = CMD_BRDSPI_RD;
|
||||
ctrPkt.outBuffer.push_back((address >> 8) & 0xFF);
|
||||
ctrPkt.outBuffer.push_back(address & 0xFF);
|
||||
dataPort->TransferPacket(ctrPkt);
|
||||
if (ctrPkt.inBuffer.size() > 4)
|
||||
return ctrPkt.inBuffer[2] * 256 + ctrPkt.inBuffer[3];
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int trx_sodera_start(openair0_device *device)
|
||||
{
|
||||
sodera_t *s = (sodera_t*)device->priv;
|
||||
|
||||
|
||||
// init recv and send streaming
|
||||
|
||||
printf("Starting LMS Streaming\n");
|
||||
s->rx_count = 0;
|
||||
s->tx_count = 0;
|
||||
s->rx_timestamp = 0;
|
||||
s->current_handle = 0;
|
||||
|
||||
// switch off RX
|
||||
uint16_t regVal = SPI_read(&s->Port,0x0005);
|
||||
SPI_write(&s->Port,0x0005,regVal & ~0x6);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// USB FIFO reset
|
||||
LMScomms::GenericPacket ctrPkt;
|
||||
ctrPkt.cmd = CMD_USB_FIFO_RST;
|
||||
ctrPkt.outBuffer.push_back(0x01);
|
||||
s->Port.TransferPacket(ctrPkt);
|
||||
ctrPkt.outBuffer[0]=0x00;
|
||||
s->Port.TransferPacket(ctrPkt);
|
||||
|
||||
regVal = SPI_read(&s->Port,0x0005);
|
||||
// provide timestamp, set streamTXEN, set TX/RX enable
|
||||
SPI_write(&s->Port,0x0005,(regVal & ~0x20) | 0x6);
|
||||
|
||||
|
||||
if (s->channelscount==2) {
|
||||
SPI_write(&s->Port,0x0001,0x0003);
|
||||
SPI_write(&s->Port,0x0007,0x000A);
|
||||
}
|
||||
else {
|
||||
SPI_write(&s->Port,0x0001,0x0001);
|
||||
SPI_write(&s->Port,0x0007,0x0008);
|
||||
}
|
||||
|
||||
|
||||
for (int i=0; i< BUFFERSCOUNT ; i++)
|
||||
s->handles[i] = s->Port.BeginDataReading(&s->buffers_rx[i*BUFFERSIZE],BUFFERSIZE);
|
||||
printf("Armed %d transfers\n",BUFFERSCOUNT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void trx_sodera_end(openair0_device *device)
|
||||
{
|
||||
sodera_t *s = (sodera_t*)device->priv;
|
||||
|
||||
|
||||
// stop TX/RX if they were active
|
||||
uint16_t regVal = SPI_read(&s->Port,0x0005);
|
||||
SPI_write(&s->Port,0x0005,regVal & ~0x6);
|
||||
|
||||
}
|
||||
|
||||
static int trx_sodera_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int cc, int flags)
|
||||
{
|
||||
sodera_t *s = (sodera_t*)device->priv;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define DEBUG_READ 1
|
||||
|
||||
static int trx_sodera_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int cc)
|
||||
{
|
||||
sodera_t *s = (sodera_t*)device->priv;
|
||||
int samples_received=0,i,j;
|
||||
int nsamps2; // aligned to upper 32 or 16 byte boundary
|
||||
StreamPacket_t *p;
|
||||
int16_t sampleI,sampleQ;
|
||||
char *pktStart;
|
||||
int offset = 0;
|
||||
int num_p;
|
||||
int ind=0;
|
||||
int buffsize;
|
||||
int spp;
|
||||
int bufindex;
|
||||
|
||||
// this assumes that each request is of size 4096 bytes (spp = 4080/4/channelscount)
|
||||
spp = sizeof(p->data)>>2; // spp = size of payload in samples
|
||||
spp /= s->channelscount;
|
||||
|
||||
#ifdef DEBUG_READ
|
||||
printf("\nIn trx_read\n");
|
||||
printf("s->current_handle %d\n", s->current_handle);
|
||||
printf("s->samples_left_buffer %d\n",s->samples_left_buffer);
|
||||
#endif
|
||||
// first get rid of remaining samples
|
||||
if (s->samples_left_buffer > 0) {
|
||||
buffsize = min(s->samples_left_buffer,nsamps);
|
||||
pktStart = ((StreamPacket_t*)&s->buffers_rx[s->current_handle*BUFFERSIZE])->data;
|
||||
pktStart += (spp-s->samples_left_buffer);
|
||||
const int stepSize = s->channelscount * 3;
|
||||
|
||||
for (int b=0;b<buffsize<<2;b+=stepSize) {
|
||||
for (int ch=0;ch<s->channelscount;ch++) {
|
||||
// I sample
|
||||
sampleI = (pktStart[b + 1 + 3*ch]&0x0F)<<8;
|
||||
sampleI |= (pktStart[b + 3*ch]&0xFF);
|
||||
sampleI = (sampleI<<4)>>4;
|
||||
// Q sample
|
||||
sampleQ = (pktStart[b + 2 + 3*ch]&0x0F)<<8;
|
||||
sampleQ |= (pktStart[b + 1 + 3*ch]&0xFF);
|
||||
sampleQ = (sampleQ<<4)>>4;
|
||||
((uint32_t*)buff[ch])[ind] = ((uint32_t)sampleI) | (((uint32_t)sampleQ)<<16);
|
||||
}
|
||||
ind++;
|
||||
}
|
||||
}
|
||||
if (ind == nsamps) {
|
||||
s->samples_left_buffer -= nsamps;
|
||||
s->rx_count += nsamps;
|
||||
*ptimestamp = s->rx_timestamp;
|
||||
s->rx_timestamp+=nsamps;
|
||||
|
||||
return(nsamps);
|
||||
}
|
||||
else {
|
||||
s->samples_left_buffer = 0;
|
||||
nsamps -= ind;
|
||||
samples_received = ind;
|
||||
}
|
||||
|
||||
// This is for the left-over part => READ from USB
|
||||
|
||||
|
||||
|
||||
num_p = nsamps / spp;
|
||||
if ((nsamps%spp) > 0)
|
||||
num_p++;
|
||||
s->samples_left_buffer = (num_p*spp)-nsamps;
|
||||
|
||||
|
||||
#ifdef DEBUG_READ
|
||||
printf("num_p %d\n",num_p);
|
||||
#endif
|
||||
const int stepSize = s->channelscount * 3;
|
||||
|
||||
for (i=0;i<num_p;i++) {
|
||||
|
||||
bufindex = (s->current_handle+i)&(BUFFERSCOUNT-1);
|
||||
if (s->Port.WaitForReading(s->handles[bufindex],1000) == false) {
|
||||
printf("[recv] Error: request %d samples (%d/%d) WaitForReading timed out\n",nsamps,bufindex,num_p);
|
||||
*ptimestamp = s->rx_timestamp;
|
||||
s->rx_timestamp+=samples_received;
|
||||
return(samples_received);
|
||||
}
|
||||
long bytesToRead=BUFFERSIZE;
|
||||
if (s->Port.FinishDataReading(&s->buffers_rx[bufindex*BUFFERSIZE],bytesToRead,s->handles[bufindex]) != BUFFERSIZE) {
|
||||
printf("[recv] Error: request %d samples (%d/%d) WaitForReading timed out\n",nsamps,bufindex,num_p);
|
||||
*ptimestamp = s->rx_timestamp;
|
||||
s->rx_timestamp+=samples_received;
|
||||
return(samples_received);
|
||||
}
|
||||
|
||||
p = (StreamPacket_t*)&s->buffers_rx[bufindex*BUFFERSIZE];
|
||||
// handle timestamp
|
||||
if ((i==0) & (ind==0)) { // grab the timestamp from HW
|
||||
*ptimestamp = p->counter;
|
||||
s->rx_timestamp = p->counter+nsamps; // for next time
|
||||
#ifdef DEBUG_READ
|
||||
printf("RX timestamp %d\n",s->rx_timestamp);
|
||||
#endif
|
||||
}
|
||||
else { // check the timestamp
|
||||
if (i==0) {
|
||||
if ((s->rx_timestamp + ind) != p->counter) {
|
||||
printf("Error, RX timestamp error, got %llu, should be %llu\n",p->counter,s->rx_timestamp+ind);
|
||||
return(ind);
|
||||
}
|
||||
}
|
||||
*ptimestamp = s->rx_timestamp;
|
||||
s->rx_timestamp+=nsamps;
|
||||
}
|
||||
pktStart = p->data;
|
||||
for (uint16_t b=0;b<sizeof(p->data);b+=stepSize) {
|
||||
for (int ch=0;ch < s->channelscount;ch++) {
|
||||
// I sample
|
||||
sampleI = (pktStart[b + 1 + 3*ch]&0x0F)<<8;
|
||||
sampleI |= (pktStart[b + 3*ch]&0xFF);
|
||||
sampleI = (sampleI<<4)>>4;
|
||||
// Q sample
|
||||
sampleQ = (pktStart[b + 2 + 3*ch]&0x0F)<<8;
|
||||
sampleQ |= (pktStart[b + 1 + 3*ch]&0xFF);
|
||||
sampleQ = (sampleQ<<4)>>4;
|
||||
((uint32_t*)buff[ch])[ind] = ((uint32_t)sampleI) | (((uint32_t)sampleQ)<<16);
|
||||
}
|
||||
ind++;
|
||||
}
|
||||
samples_received+=spp;
|
||||
// schedule a new transmission for this index
|
||||
s->handles[bufindex] = s->Port.BeginDataReading(&s->buffers_rx[bufindex*BUFFERSIZE],BUFFERSIZE);
|
||||
s->current_handle=(s->current_handle+1)&(BUFFERSCOUNT-1);
|
||||
}
|
||||
|
||||
//handle the error code
|
||||
|
||||
s->rx_count += samples_received;
|
||||
// s->rx_timestamp = s->rx_md.time_spec.to_ticks(s->sample_rate);
|
||||
|
||||
return samples_received;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static bool is_equal(double a, double b)
|
||||
{
|
||||
return fabs(a-b) < 1e-6;
|
||||
}
|
||||
|
||||
int trx_sodera_set_freq(openair0_device* device, openair0_config_t *openair0_cfg, int dummy) {
|
||||
|
||||
sodera_t *s = (sodera_t*)device->priv;
|
||||
|
||||
// s->usrp->set_tx_freq(openair0_cfg[0].tx_freq[0]);
|
||||
// s->usrp->set_rx_freq(openair0_cfg[0].rx_freq[0]);
|
||||
|
||||
return(0);
|
||||
|
||||
}
|
||||
|
||||
int openair0_set_rx_frequencies(openair0_device* device, openair0_config_t *openair0_cfg) {
|
||||
|
||||
sodera_t *s = (sodera_t*)device->priv;
|
||||
static int first_call=1;
|
||||
static double rf_freq,diff;
|
||||
|
||||
// uhd::tune_request_t rx_tune_req(openair0_cfg[0].rx_freq[0]);
|
||||
|
||||
// rx_tune_req.rf_freq_policy = uhd::tune_request_t::POLICY_MANUAL;
|
||||
// rx_tune_req.rf_freq = openair0_cfg[0].rx_freq[0];
|
||||
// rf_freq=openair0_cfg[0].rx_freq[0];
|
||||
// s->usrp->set_rx_freq(rx_tune_req);
|
||||
|
||||
return(0);
|
||||
|
||||
}
|
||||
|
||||
int trx_sodera_set_gains(openair0_device* device,
|
||||
openair0_config_t *openair0_cfg) {
|
||||
|
||||
sodera_t *s = (sodera_t*)device->priv;
|
||||
|
||||
// s->usrp->set_tx_gain(openair0_cfg[0].tx_gain[0]);
|
||||
// ::uhd::gain_range_t gain_range = s->usrp->get_rx_gain_range(0);
|
||||
// limit to maximum gain
|
||||
/* if (openair0_cfg[0].rx_gain[0]-openair0_cfg[0].rx_gain_offset[0] > gain_range.stop()) {
|
||||
|
||||
printf("RX Gain 0 too high, reduce by %f dB\n",
|
||||
openair0_cfg[0].rx_gain[0]-openair0_cfg[0].rx_gain_offset[0] - gain_range.stop());
|
||||
exit(-1);
|
||||
}
|
||||
s->usrp->set_rx_gain(openair0_cfg[0].rx_gain[0]-openair0_cfg[0].rx_gain_offset[0]);
|
||||
printf("Setting SODERA RX gain to %f (rx_gain %f,gain_range.stop() %f)\n", openair0_cfg[0].rx_gain[0]-openair0_cfg[0].rx_gain_offset[0],openair0_cfg[0].rx_gain[0],gain_range.stop());
|
||||
*/
|
||||
return(0);
|
||||
}
|
||||
|
||||
int trx_sodera_stop(int card) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
rx_gain_calib_table_t calib_table_sodera[] = {
|
||||
{3500000000.0,44.0},
|
||||
{2660000000.0,49.0},
|
||||
{2300000000.0,50.0},
|
||||
{1880000000.0,53.0},
|
||||
{816000000.0,58.0},
|
||||
{-1,0}};
|
||||
|
||||
void set_rx_gain_offset(openair0_config_t *openair0_cfg, int chain_index,int bw_gain_adjust) {
|
||||
|
||||
int i=0;
|
||||
// loop through calibration table to find best adjustment factor for RX frequency
|
||||
double min_diff = 6e9,diff,gain_adj=0.0;
|
||||
if (bw_gain_adjust==1) {
|
||||
switch ((int)openair0_cfg[0].sample_rate) {
|
||||
case 30720000:
|
||||
break;
|
||||
case 23040000:
|
||||
gain_adj=1.25;
|
||||
break;
|
||||
case 15360000:
|
||||
gain_adj=3.0;
|
||||
break;
|
||||
case 7680000:
|
||||
gain_adj=6.0;
|
||||
break;
|
||||
case 3840000:
|
||||
gain_adj=9.0;
|
||||
break;
|
||||
case 1920000:
|
||||
gain_adj=12.0;
|
||||
break;
|
||||
default:
|
||||
printf("unknown sampling rate %d\n",(int)openair0_cfg[0].sample_rate);
|
||||
exit(-1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (openair0_cfg->rx_gain_calib_table[i].freq>0) {
|
||||
diff = fabs(openair0_cfg->rx_freq[chain_index] - openair0_cfg->rx_gain_calib_table[i].freq);
|
||||
printf("cal %d: freq %f, offset %f, diff %f\n",
|
||||
i,
|
||||
openair0_cfg->rx_gain_calib_table[i].freq,
|
||||
openair0_cfg->rx_gain_calib_table[i].offset,diff);
|
||||
if (min_diff > diff) {
|
||||
min_diff = diff;
|
||||
openair0_cfg->rx_gain_offset[chain_index] = openair0_cfg->rx_gain_calib_table[i].offset+gain_adj;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
int trx_sodera_get_stats(openair0_device* device) {
|
||||
|
||||
return(0);
|
||||
|
||||
}
|
||||
int trx_sodera_reset_stats(openair0_device* device) {
|
||||
|
||||
return(0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
int openair0_dev_init_sodera(openair0_device* device, openair0_config_t *openair0_cfg)
|
||||
{
|
||||
|
||||
sodera_t *s=&sodera_state;
|
||||
|
||||
size_t i;
|
||||
|
||||
// Initialize SODERA device
|
||||
s->Port.RefreshDeviceList();
|
||||
vector<string> deviceNames=s->Port.GetDeviceList();
|
||||
|
||||
if (deviceNames.size() == 1) {
|
||||
if (s->Port.Open(0) != IConnection::SUCCESS) {
|
||||
printf("Cannot open SoDeRa\n");
|
||||
exit(-1);
|
||||
}
|
||||
LMSinfo devInfo = s->Port.GetInfo();
|
||||
printf("Device %s, HW: %d, FW: %d, Protocol %d\n",
|
||||
GetDeviceName(devInfo.device),
|
||||
(int)devInfo.hardware,
|
||||
(int)devInfo.firmware,
|
||||
(int)devInfo.protocol);
|
||||
|
||||
printf("Configuring Si5351C\n");
|
||||
s->Si.Initialize(&s->Port);
|
||||
s->Si.SetPLL(0, 25000000, 0);
|
||||
s->Si.SetPLL(1, 25000000, 0);
|
||||
s->Si.SetClock(0, 27000000, true, false);
|
||||
s->Si.SetClock(1, 27000000, true, false);
|
||||
for (int i = 2; i < 8; ++i)
|
||||
s->Si.SetClock(i, 27000000, false, false);
|
||||
Si5351C::Status status = s->Si.ConfigureClocks();
|
||||
if (status != Si5351C::SUCCESS)
|
||||
{
|
||||
printf("Failed to configure Si5351C");
|
||||
exit(-1);
|
||||
}
|
||||
status = s->Si.UploadConfiguration();
|
||||
if (status != Si5351C::SUCCESS)
|
||||
printf("Failed to upload Si5351C configuration");
|
||||
|
||||
|
||||
printf("Configuring LMS7002\n");
|
||||
|
||||
int bw_gain_adjust=0;
|
||||
|
||||
|
||||
openair0_cfg[0].rx_gain_calib_table = calib_table_sodera;
|
||||
|
||||
switch ((int)openair0_cfg[0].sample_rate) {
|
||||
case 30720000:
|
||||
// from usrp_time_offset
|
||||
openair0_cfg[0].samples_per_packet = 2048;
|
||||
openair0_cfg[0].tx_sample_advance = 15;
|
||||
openair0_cfg[0].tx_bw = 20e6;
|
||||
openair0_cfg[0].rx_bw = 20e6;
|
||||
openair0_cfg[0].tx_scheduling_advance = 8*openair0_cfg[0].samples_per_packet;
|
||||
break;
|
||||
case 15360000:
|
||||
openair0_cfg[0].samples_per_packet = 2048;
|
||||
openair0_cfg[0].tx_sample_advance = 45;
|
||||
openair0_cfg[0].tx_bw = 10e6;
|
||||
openair0_cfg[0].rx_bw = 10e6;
|
||||
openair0_cfg[0].tx_scheduling_advance = 5*openair0_cfg[0].samples_per_packet;
|
||||
break;
|
||||
case 7680000:
|
||||
openair0_cfg[0].samples_per_packet = 1024;
|
||||
openair0_cfg[0].tx_sample_advance = 50;
|
||||
openair0_cfg[0].tx_bw = 5e6;
|
||||
openair0_cfg[0].rx_bw = 5e6;
|
||||
openair0_cfg[0].tx_scheduling_advance = 5*openair0_cfg[0].samples_per_packet;
|
||||
break;
|
||||
case 1920000:
|
||||
openair0_cfg[0].samples_per_packet = 256;
|
||||
openair0_cfg[0].tx_sample_advance = 50;
|
||||
openair0_cfg[0].tx_bw = 1.25e6;
|
||||
openair0_cfg[0].rx_bw = 1.25e6;
|
||||
openair0_cfg[0].tx_scheduling_advance = 8*openair0_cfg[0].samples_per_packet;
|
||||
break;
|
||||
default:
|
||||
printf("Error: unknown sampling rate %f\n",openair0_cfg[0].sample_rate);
|
||||
exit(-1);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
s->lmsControl = LMS7002M(&s->Port);
|
||||
|
||||
liblms7_status opStatus;
|
||||
s->lmsControl.ResetChip();
|
||||
opStatus = s->lmsControl.LoadConfig(openair0_cfg[0].configFilename);
|
||||
|
||||
if (opStatus != LIBLMS7_SUCCESS) {
|
||||
printf("Failed to load configuration file %s\n",openair0_cfg[0].configFilename);
|
||||
exit(-1);
|
||||
}
|
||||
opStatus = s->lmsControl.UploadAll();
|
||||
|
||||
if (opStatus != LIBLMS7_SUCCESS) {
|
||||
printf("Failed to upload configuration file\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
opStatus = s->lmsControl.SetFrequencySX(LMS7002M::Tx, openair0_cfg[0].tx_freq[0]/1e6,30.72);
|
||||
|
||||
if (opStatus != LIBLMS7_SUCCESS) {
|
||||
printf("Cannot set TX frequency %f MHz\n",openair0_cfg[0].tx_freq[0]/1e6);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
opStatus = s->lmsControl.SetFrequencySX(LMS7002M::Rx, openair0_cfg[0].rx_freq[0]/1e6,30.72);
|
||||
|
||||
if (opStatus != LIBLMS7_SUCCESS) {
|
||||
printf("Cannot set RX frequency %f MHz\n",openair0_cfg[0].rx_freq[0]/1e6);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// this makes RX/TX sampling rates equal
|
||||
opStatus = s->lmsControl.Modify_SPI_Reg_bits(EN_ADCCLKH_CLKGN,0);
|
||||
if (opStatus != LIBLMS7_SUCCESS) {
|
||||
printf("Cannot modify SPI (EN_ADCCLKH_CLKGN)\n");
|
||||
exit(-1);
|
||||
}
|
||||
opStatus = s->lmsControl.Modify_SPI_Reg_bits(CLKH_OV_CLKL_CGEN,2);
|
||||
if (opStatus != LIBLMS7_SUCCESS) {
|
||||
printf("Cannot modify SPI (CLKH_OV_CLKL_CGEN)\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
const float cgen_freq_MHz = 245.76;
|
||||
const int interpolation = 0; // real interpolation = 2
|
||||
const int decimation = 0; // real decimation = 2
|
||||
opStatus = s->lmsControl.SetInterfaceFrequency(cgen_freq_MHz,interpolation,decimation);
|
||||
if (opStatus != LIBLMS7_SUCCESS) {
|
||||
printf("Cannot SetInterfaceFrequency (%f,%d,%d)\n",cgen_freq_MHz,interpolation,decimation);
|
||||
exit(-1);
|
||||
}
|
||||
/*
|
||||
// Run calibration procedure
|
||||
float txrx_calibrationBandwidth_MHz = 5;
|
||||
opStatus = s->lmsControl.CalibrateTx(txrx_calibrationBandwidth_MHz);
|
||||
if (opStatus != LIBLMS7_SUCCESS){
|
||||
printf("TX Calibration failed\n");
|
||||
exit(-1);
|
||||
}
|
||||
opStatus = s->lmsControl.CalibrateRx(txrx_calibrationBandwidth_MHz);
|
||||
if (opStatus != LIBLMS7_SUCCESS){
|
||||
printf("RX Calibration failed\n");
|
||||
exit(-1);
|
||||
}
|
||||
*/
|
||||
|
||||
s->lmsStream = new LMS_StreamBoard(&s->Port);
|
||||
LMS_StreamBoard::Status opStreamStatus;
|
||||
// this will configure that sampling rate at output of FPGA
|
||||
opStreamStatus = s->lmsStream->ConfigurePLL(&s->Port,openair0_cfg[0].sample_rate,openair0_cfg[0].sample_rate,90);
|
||||
if (opStatus != LIBLMS7_SUCCESS){
|
||||
printf("Sample rate programming failed\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/*
|
||||
::uhd::gain_range_t gain_range = s->usrp->get_rx_gain_range(i);
|
||||
// limit to maximum gain
|
||||
if (openair0_cfg[0].rx_gain[i]-openair0_cfg[0].rx_gain_offset[i] > gain_range.stop()) {
|
||||
|
||||
printf("RX Gain %lu too high, lower by %f dB\n",i,openair0_cfg[0].rx_gain[i]-openair0_cfg[0].rx_gain_offset[i] - gain_range.stop());
|
||||
exit(-1);
|
||||
}
|
||||
s->usrp->set_rx_gain(openair0_cfg[0].rx_gain[i]-openair0_cfg[0].rx_gain_offset[i],i);
|
||||
printf("RX Gain %lu %f (%f) => %f (max %f)\n",i,
|
||||
openair0_cfg[0].rx_gain[i],openair0_cfg[0].rx_gain_offset[i],
|
||||
openair0_cfg[0].rx_gain[i]-openair0_cfg[0].rx_gain_offset[i],gain_range.stop());
|
||||
}
|
||||
}
|
||||
for(i=0;i<s->usrp->get_tx_num_channels();i++) {
|
||||
if (i<openair0_cfg[0].tx_num_channels) {
|
||||
s->usrp->set_tx_rate(openair0_cfg[0].sample_rate,i);
|
||||
s->usrp->set_tx_bandwidth(openair0_cfg[0].tx_bw,i);
|
||||
printf("Setting tx freq/gain on channel %lu/%lu: BW %f (readback %f)\n",i,s->usrp->get_tx_num_channels(),openair0_cfg[0].tx_bw/1e6,s->usrp->get_tx_bandwidth(i)/1e6);
|
||||
s->usrp->set_tx_freq(openair0_cfg[0].tx_freq[i],i);
|
||||
s->usrp->set_tx_gain(openair0_cfg[0].tx_gain[i],i);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// create tx & rx streamer
|
||||
|
||||
//stream_args_rx.args["spp"] = str(boost::format("%d") % 2048);//(openair0_cfg[0].rx_num_channels*openair0_cfg[0].samples_per_packet));
|
||||
|
||||
/*
|
||||
for (i=0;i<openair0_cfg[0].rx_num_channels;i++) {
|
||||
if (i<openair0_cfg[0].rx_num_channels) {
|
||||
printf("RX Channel %lu\n",i);
|
||||
std::cout << boost::format("Actual RX sample rate: %fMSps...") % (s->usrp->get_rx_rate(i)/1e6) << std::endl;
|
||||
std::cout << boost::format("Actual RX frequency: %fGHz...") % (s->usrp->get_rx_freq(i)/1e9) << std::endl;
|
||||
std::cout << boost::format("Actual RX gain: %f...") % (s->usrp->get_rx_gain(i)) << std::endl;
|
||||
std::cout << boost::format("Actual RX bandwidth: %fM...") % (s->usrp->get_rx_bandwidth(i)/1e6) << std::endl;
|
||||
std::cout << boost::format("Actual RX antenna: %s...") % (s->usrp->get_rx_antenna(i)) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0;i<openair0_cfg[0].tx_num_channels;i++) {
|
||||
|
||||
if (i<openair0_cfg[0].tx_num_channels) {
|
||||
printf("TX Channel %lu\n",i);
|
||||
std::cout << std::endl<<boost::format("Actual TX sample rate: %fMSps...") % (s->usrp->get_tx_rate(i)/1e6) << std::endl;
|
||||
std::cout << boost::format("Actual TX frequency: %fGHz...") % (s->usrp->get_tx_freq(i)/1e9) << std::endl;
|
||||
std::cout << boost::format("Actual TX gain: %f...") % (s->usrp->get_tx_gain(i)) << std::endl;
|
||||
std::cout << boost::format("Actual TX bandwidth: %fM...") % (s->usrp->get_tx_bandwidth(i)/1e6) << std::endl;
|
||||
std::cout << boost::format("Actual TX antenna: %s...") % (s->usrp->get_tx_antenna(i)) << std::endl;
|
||||
}
|
||||
*/
|
||||
}
|
||||
else {
|
||||
printf("Please connect SoDeRa\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
device->priv = s;
|
||||
device->trx_start_func = trx_sodera_start;
|
||||
device->trx_write_func = trx_sodera_write;
|
||||
device->trx_read_func = trx_sodera_read;
|
||||
device->trx_get_stats_func = trx_sodera_get_stats;
|
||||
device->trx_reset_stats_func = trx_sodera_reset_stats;
|
||||
device->trx_end_func = trx_sodera_end;
|
||||
device->trx_stop_func = trx_sodera_stop;
|
||||
device->trx_set_freq_func = trx_sodera_set_freq;
|
||||
device->trx_set_gains_func = trx_sodera_set_gains;
|
||||
|
||||
s->sample_rate = openair0_cfg[0].sample_rate;
|
||||
s->channelscount = openair0_cfg[0].rx_num_channels;
|
||||
|
||||
// TODO:
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user