Commit b4e48d88 authored by Raymond Knopp's avatar Raymond Knopp Committed by Robert Schmidt

Squashed commit of the following:

commit 4bbcf7cf
Merge: 6433c1f7 1fb76157
Author: Raymond Knopp <raymond.knopp@eurecom.fr>
Date:   Sat Sep 2 10:38:30 2017 +0200

    Merge branch 'develop' into develop-sidekiq

commit 6433c1f7
Author: Raymond Knopp <raymond.knopp@eurecom.fr>
Date:   Fri Sep 1 19:47:42 2017 +0200

    updates for CMakeLists.txt (for Sidekiq) and tracing in skiq_lib.c

commit f395cb54
Merge: c0725ddc 17b9a9e9
Author: Raymond Knopp <raymond.knopp@eurecom.fr>
Date:   Sun Aug 20 09:08:52 2017 +0200

    Merge branch 'develop' into develop-sidekiq

commit c0725ddc
Author: Raymond Knopp <raymond.knopp@eurecom.fr>
Date:   Sun Aug 20 08:55:24 2017 +0200

    some changes for sidekiq

commit cae97783
Merge: 2253c554 d0e2938b c124e32a
Author: Raymond Knopp <raymond.knopp@eurecom.fr>
Date:   Wed May 3 18:00:07 2017 +0200

    Merge branch 'develop', remote-tracking branch 'origin' into develop-sidekiq

commit 2253c554
Author: Raymond Knopp <raymond.knopp@eurecom.fr>
Date:   Tue Mar 21 19:04:29 2017 +0100

    fixes after merge with develop
    Y

commit 7c1bbb57
Merge: fbaf8a62 bd173433
Author: Raymond Knopp <raymond.knopp@eurecom.fr>
Date:   Tue Mar 21 18:52:03 2017 +0100

    Merge branch 'develop' of https://gitlab.eurecom.fr/oai/openairinterface5g into develop-sidekiq

commit fbaf8a62
Author: Raymond Knopp <raymond.knopp@eurecom.fr>
Date:   Tue Mar 21 18:37:02 2017 +0100

    updates for Sidekiq

commit da500691
Author: Raymond Knopp <raymond.knopp@eurecom.fr>
Date:   Sun Mar 12 10:31:57 2017 +0100

    conflict resolution after merge with develop

commit 63e7c171
Merge: f8ee74de 5c375d3a
Author: Raymond Knopp <raymond.knopp@eurecom.fr>
Date:   Sun Mar 12 10:22:53 2017 +0100

    Merge remote-tracking branch 'origin/develop' into develop-sidekiq

commit f8ee74de
Author: Raymond Knopp <raymond.knopp@eurecom.fr>
Date:   Wed Jan 4 13:23:14 2017 -0500

    remove unused file

commit 2e310b8c
Author: Raymond Knopp <raymond.knopp@eurecom.fr>
Date:   Wed Jan 4 13:22:23 2017 -0500

    SKIQ library

commit 83f00909
Author: Raymond Knopp <raymond.knopp@eurecom.fr>
Date:   Wed Jan 4 13:21:30 2017 -0500

    modifications for sidekiq

commit 18d05df0
Merge: 09831815 3bf8768d
Author: Raymond Knopp <raymond.knopp@eurecom.fr>
Date:   Fri Dec 23 11:18:15 2016 -0500

    Merge remote-tracking branch 'origin/develop' into develop-sidekiq

commit 09831815
Author: Raymond Knopp <raymond.knopp@eurecom.fr>
Date:   Fri Dec 23 11:08:42 2016 -0500

    changes for sidekiq

commit 467384bc
Merge: 933e874c 9927838e
Author: Raymond Knopp <raymond.knopp@eurecom.fr>
Date:   Wed Oct 26 17:07:11 2016 -0400

    Merge branch 'develop' into develop-sidekiq

commit 933e874c
Author: Raymond Knopp <raymond.knopp@eurecom.fr>
Date:   Wed Oct 26 17:05:39 2016 -0400

    added skeleton for Sidekiq

commit 3185d596
Merge: e86ec117 82e54108
Author: Raymond Knopp <raymond.knopp@eurecom.fr>
Date:   Wed Oct 26 17:04:14 2016 -0400

    Merge remote-tracking branch 'origin' into develop-sidekiq
parent 6d030ea2
......@@ -743,6 +743,15 @@ set(HWLIB_BLADERF_SOURCE
add_library(oai_bladerfdevif MODULE ${HWLIB_BLADERF_SOURCE} )
target_link_libraries(oai_bladerfdevif bladeRF)
set (SKIQ_SDK $ENV{SKIQ_SDK})
set (option_HWSKIQLIB_lib "-L ${SKIQ_SDK}/lib/support/x86_64.gcc/usr/lib/epiq ${SKIQ_SDK}/lib/libsidekiq__x86_64.gcc.a ${SKIQ_SDK}/arg_parser/lib/arg_parser__x86_64.gcc.a -lglib-2.0 -Wl,--enable-new-dtags -Wl,-rpath,/usr/lib/epiq ")
add_library(oai_skiqdevif MODULE ${OPENAIR_TARGETS}/ARCH/SKIQ/USERSPACE/LIB/skiq_lib.c)
FIND_LIBRARY(LIBSIDEKIQ NAMES "libsidekiq__x86_64.gcc.a" "arg_parser__x86_64.gcc.a" PATHS ${SKIQ_SDK}/lib NO_DEFAULT_PATH)
target_link_libraries(oai_skiqdevif ${LIBSIDEKIQ})
target_include_directories(oai_skiqdevif PRIVATE "${SKIQ_SDK}/sidekiq_core/inc")
target_include_directories(oai_skiqdevif PRIVATE "${OPENAIR_TARGETS}/ARCH/SKIQ/USERSPACE/LIB/")
set (CMAKE_SHARED_LINKER_FLAGS "-lglib-2.0 -Wl,--enable-new-dtags -Wl,-rpath,/usr/lib/epiq")
include_directories("${OPENAIR_TARGETS}/ARCH/LMSSDR/USERSPACE/LIB/")
set(HWLIB_LMSSDR_SOURCE
......
......@@ -110,7 +110,7 @@ Options:
--UE-gen-nvram [output path]
Specify gen_nvram_path (default \"$gen_nvram_path\")
-w | --hardware
EXMIMO, USRP, BLADERF, LMSSDR, IRIS, ADRV9371_ZC706, SIMU, AW2SORI, None (Default)
EXMIMO, USRP, SKIQ, BLADERF, LMSSDR, IRIS, ADRV9371_ZC706, SIMU, AW2SORI, None (Default)
Adds this RF board support (in external packages installation and in compilation)
-t | --transport
Selects the transport protocol type, options: None, Ethernet, benetel4g, benetel5g
......@@ -300,7 +300,7 @@ function main() {
"EXMIMO")
HW="EXMIMO"
;;
"USRP" | "BLADERF" | "LMSSDR" | "IRIS" | "ADRV9371_ZC706" | "SIMU" | "AW2SORI")
"USRP" | "SKIQ" | "BLADERF" | "LMSSDR" | "IRIS" | "ADRV9371_ZC706" | "SIMU" | "AW2SORI")
HW="OAI_"$2
;;
"None")
......@@ -584,6 +584,10 @@ function main() {
# flash_firmware_iris
#fi
fi
if [ "$HW" == "OAI_SKIQ" ] ; then
echo_info "installing packages for SKIQ support"
check_install_skiq_driver
fi
echo_info "Installing protobuf/protobuf-c for flexran agent support"
install_protobuf_c
echo_success "protobuf/protobuf-c installation successful"
......@@ -859,6 +863,15 @@ function main() {
ln -sf liboai_usrpdevif.so liboai_device.so
ln -sf $dbin/liboai_usrpdevif.so.$REL $dbin/liboai_device.so
echo_info "liboai_device.so is linked to USRP device library"
elif [ "$HW" == "OAI_SKIQ" ] ; then
if [ -f $SKIQ_SDK/sidekiq_core/inc ] ; then
compilations \
$build_dir oai_skiqdevif \
liboai_skiqdevif.so $dbin/liboai_skiqdevif.so.$REL
fi
ln -s liboai_skiqdevif.so liboai_device.so
ln -s $dbin/liboai_skiqdevif.so.$REL $dbin/liboai_device.so
echo_info "liboai_device.so is linked to SIDEKIQ device library"
elif [ "$HW" == "OAI_BLADERF" ] ; then
if [ -f "/usr/include/libbladeRF.h" ] ; then
compilations \
......
......@@ -53,6 +53,7 @@ const char* devtype_names[MAX_RF_DEV_TYPE] = {
"BLADERF",
"LMSSDR",
"IRIS",
"SKIQ",
"No HW",
"ADRV9371_ZC706",
"UEDv2",
......
......@@ -98,6 +98,8 @@ typedef enum {
LMSSDR_DEV,
/*!\brief device is Iris */
IRIS_DEV,
/*!\brief device is SKIQ*/
SKIQ_DEV,
/*!\brief device is NONE*/
NONE_DEV,
/*!\brief device is ADRV9371_ZC706 */
......
/*
* 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.0 (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
*/
/** skiq_lib.cpp
*
* \author: Raymond Knopp : raymond.knopp@eurecom.fr
*/
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include "math.h"
#include "common_lib.h"
#include "sidekiq_api.h"
#include <string.h>
#include <pthread.h>
#include <sys/mman.h>
#include <unistd.h>
#include "PHY/TOOLS/time_meas.h"
/** @addtogroup _SIDEKIQ_PHY_RF_INTERFACE_
* @{
*/
#ifdef __SSE4_1__
# include <smmintrin.h>
#endif
#ifdef __AVX2__
# include <immintrin.h>
#endif
//#define DEBUG_SKIQ_TX 1
//#define DEBUG_SKIQ_RX 1
#define SKIQ_MAX_TX_ELM 10
#define SKIQ_MAX_NUM_TX_PACKETS (30720/1020)
#define SKIQ_BLOCK_SIZE_IN_WORDS (1024-4) /* OAI choice for block size */
#define ANSI_COLOR_RED "\x1b[31m"
#define ANSI_COLOR_GREEN "\x1b[32m"
#define ANSI_COLOR_YELLOW "\x1b[33m"
#define ANSI_COLOR_BLUE "\x1b[34m"
#define ANSI_COLOR_MAGENTA "\x1b[35m"
#define ANSI_COLOR_CYAN "\x1b[36m"
#define ANSI_COLOR_RESET "\x1b[0m"
//#define SKIQ_ASYNCH 1
/* helper MACROs (pulled from Linux kernel) */
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, _type, member) ({ \
const typeof(((_type *)0)->member)*__mptr = (ptr); \
(_type *)((char *)__mptr - offsetof(_type, member)); })
typedef struct {
uint32_t *dataptr;
uint32_t length;
uint64_t timestamp;
uint32_t active;
} TX_input_packet_q_elm_t;
typedef struct {
int head;
int tail;
TX_input_packet_q_elm_t elm[SKIQ_MAX_TX_ELM-1];
} TX_input_packet_q_t;
typedef struct {
uint64_t meta, ts;
int32_t iq[SKIQ_BLOCK_SIZE_IN_WORDS];
} skiq_tx_packet_t;
typedef struct {
void *priv;
int32_t idx;
skiq_tx_packet_t skiq_pkt;
} tx_packet_t;
/*! \brief Sidekiq specific data structure */
typedef struct {
//! Number of cards
uint8_t number_of_cards;
//! List of card ids
uint8_t card_list[SKIQ_MAX_NUM_CARDS];
//! Number of buffers
unsigned int num_buffers;
//! Buffer size
unsigned int buffer_size;
//! Number of transfers
unsigned int num_transfers;
//! RX timeout
unsigned int rx_timeout_ms;
//! TX timeout
unsigned int tx_timeout_ms;
//! Sample rate
unsigned int sample_rate;
//! time offset between transmiter timestamp and receiver timestamp;
double tdiff;
//! TX number of forward samples use brf_time_offset to get this value
int tx_sample_offset; //166 for 20Mhz
//! RX residual samples from last read (flushed upon next read)
uint32_t residual_read_buffer[SKIQ_MAX_NUM_CARDS][1018];
//! RX residual timestamp from last read (used upon next read)
uint64_t residual_ts[SKIQ_MAX_NUM_CARDS];
//! RX residual samples counter
uint32_t residual_read_size[SKIQ_MAX_NUM_CARDS];
// --------------------------------
// Debug and output control
// --------------------------------
//! Number of underflows
int num_underflows;
//! Number of overflows
int num_overflows;
//! number of sequential errors
int num_seq_errors;
//! number of RX errors
int num_rx_errors;
//! Number of TX errors
int num_tx_errors;
//! timestamp of current TX
uint64_t tx_current_ts;
//! timestamp of current RX
uint64_t rx_current_ts;
//! number of actual samples transmitted
uint64_t tx_actual_nsamps;
//! number of actual samples received
uint64_t rx_actual_nsamps;
//! number of TX samples
uint64_t tx_nsamps;
//! number of RX samples
uint64_t rx_nsamps;
//! number of TX count
uint64_t tx_count;
//! number of RX count
uint64_t rx_count;
//! timestamp of RX packet
openair0_timestamp rx_timestamp;
//! size of TX packet blocks;
uint32_t block_size_in_words;
//! closest integer number of blocks
uint32_t num_blocks_per_subframe;
//! Queue for TX requests
TX_input_packet_q_t txq;
//! mutex to protect txq modifications
pthread_mutex_t tx_buffer_mutex;
//! mutex for callback function
pthread_mutex_t space_avail_mutex;
//! condition variable for callback function
pthread_cond_t space_avail_cond;
//! pointers to Sidekiq TX packets
tx_packet_t *tx_packet[SKIQ_MAX_NUM_TX_PACKETS];
//! active status of SKIQ TX packet
int txp_active[SKIQ_MAX_NUM_TX_PACKETS];
//! TX activity indicator
int tx_active;
//! mutex for TX
pthread_mutex_t tx_mutex;
//! pthread structure for TX
pthread_t tx_thread;
} skiq_state_t;
//! Number of Sidekiq devices
int num_devices=0;
/*These items configure the underlying asynch stream used by the the sync interface.
*/
/*! \brief Sidekiq Init function (not used at the moment)
* \param device RF frontend parameters set by application
* \returns 0 on success
*/
int trx_skiq_init(openair0_device *device) {
return 0;
}
/*! \brief get current timestamp
*\param device the hardware to use
*\returns timestamp of Sidekiq
*/
openair0_timestamp trx_get_timestamp(openair0_device *device) {
return 0;
}
void skiq_dump_txpacket(void *txp,int len,FILE *fp) {
printf("txp.idx %d\n",((tx_packet_t*)txp)->idx);
printf("txp.skiq_pkt.meta 0x%" PRIx64 "\n",((tx_packet_t*)txp)->skiq_pkt.meta);
printf("txp.skiq_pkt.ts %llu\n",((tx_packet_t*)txp)->skiq_pkt.ts);
if (fp!=NULL) fwrite(txp,sizeof(skiq_tx_packet_t),1,fp);
/*
for (int i=0;i<len;i++) {
if (i%10 == 0) printf("\n%d :",i);
printf("%x.",((tx_packet_t*)txp)->skiq_pkt.iq[i]);
}
printf("\n");*/
}
#define DUMP_TX_FILE 1
void *skiq_tx_thread(void *arg) {
skiq_state_t *skiq = (skiq_state_t *)arg;
TX_input_packet_q_t *txq = &skiq->txq;
tx_packet_t *txp_i;
int i=0,j;
int next;
int len;
int32_t res;
struct sched_param sparam;
int s;
long long in,out;
int tx_drop_cnt=0;
int tx_cnt=0;
uint32_t late;
#ifdef DUMP_TX_FILE
int dump_cnt=0;
FILE *fp=fopen("/tmp/skiq_txdebug.dat","w");
#endif
memset(&sparam, 0, sizeof(sparam));
sparam.sched_priority = sched_get_priority_max(SCHED_FIFO);
printf("skiq_tx_thread: starting tx_thread (tx_active %d)\n",skiq->tx_active);
s = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sparam);
if (s !=0) {
printf("skiq_tx_thraed: cannot set thread priority\n");
skiq->tx_active=0;
return((void*)NULL);
}
mlockall(MCL_CURRENT | MCL_FUTURE);
// enable the Tx streaming
if( skiq_start_tx_streaming(skiq->card_list[0], skiq_tx_hdl_A1) != 0 ){
printf("Error: unable to start tx streaming\r\n");
return((void*)NULL);
}
else skiq->tx_active=1;
while (skiq->tx_active == 1) {
if (tx_cnt > 1000) {
tx_cnt = 0;
skiq_read_tx_num_late_timestamps(skiq->card_list[0],skiq_tx_hdl_A1,
&late);
printf("skiq: num_late_timestamps %u\n",late);
}
#ifdef DEBUG_SKIQ_TX
printf(ANSI_COLOR_RED "skiq_tx_thread: locking mutex (time %llu) txq->elm[%d].active %d (len %d),skiq->txp_active[%d] %d,txq->elm[txq->head].timestamp %llun" ANSI_COLOR_RESET,rdtsc_oai(),
txq->head,
txq->elm[txq->head].active,
txq->elm[txq->head].length,
i,
skiq->txp_active[i],
txq->elm[txq->head].timestamp
);
#endif
pthread_mutex_lock(&skiq->tx_mutex);
uint64_t txts;
skiq_read_curr_tx_timestamp(skiq->card_list[0],skiq_tx_hdl_A1,
&txts);
in = rdtsc_oai();
#ifdef DEBUG_SKIQ_TX
printf(ANSI_COLOR_RED "skiq_tx_thread: got mutex (time %llu) txq->elm[%d].active %d (len %d),skiq->txp_active[%d] %d,txq->elm[txq->head].timestamp %llu txts %llu\n" ANSI_COLOR_RESET,rdtsc_oai(),
txq->head,
txq->elm[txq->head].active,
txq->elm[txq->head].length,
i,
skiq->txp_active[i],
txq->elm[txq->head].timestamp,
txts);
#endif
if ((txq->elm[txq->head].active==1)&&
(skiq->txp_active[i]==0)) {
//&& ((txq->elm[txq->head].timestamp-txts)<4*(skiq->block_size_in_words))) { // queue is not empty
#ifdef DEBUG_SKIQ_TX
printf(ANSI_COLOR_RED "skiq_tx_thread: inner condition\n" ANSI_COLOR_RESET);
#endif
txp_i = skiq->tx_packet[i];
if (txq->elm[txq->head].length >= skiq->block_size_in_words) {
// there are enough samples in the head of the queue to fill the buffer and we're not too far in advance either
#ifdef DEBUG_SKIQ_TX
printf(ANSI_COLOR_RED "skiq_tx_thread: (head_length >= %d): Putting elm %d (tail %d) to TX packet %d/%d (length %d, TS %llu)\n" ANSI_COLOR_RESET,
skiq->block_size_in_words,
txq->head,txq->tail,
i,
skiq->num_blocks_per_subframe,
txq->elm[txq->head].length,
txq->elm[txq->head].timestamp);
#endif
skiq->txp_active[i]=1;
//timestamp
txp_i->skiq_pkt.meta = 0;
txp_i->skiq_pkt.ts = txq->elm[txq->head].timestamp;
//IQ data
#ifdef DEBUG_SKIQ_TX
printf(ANSI_COLOR_RED "skiq_tx_thread: txp_i %p => dataptr %p\n" ANSI_COLOR_RESET,
txp_i,txq->elm[txq->head].dataptr);
#endif
memcpy(txp_i->skiq_pkt.iq,
(void *)txq->elm[txq->head].dataptr,
skiq->block_size_in_words<<2);
// update tx queue
txq->elm[txq->head].dataptr += skiq->block_size_in_words;
txq->elm[txq->head].timestamp += skiq->block_size_in_words;
txq->elm[txq->head].length -= skiq->block_size_in_words;
#ifdef DEBUG_SKIQ_TX
printf("elm %d: writing %d words/ left %d to tx @%llu -> %p\n",txq->head,skiq->block_size_in_words,txq->elm[txq->head].length,txq->elm[txq->head].timestamp-skiq->block_size_in_words,
txq->elm[txq->head].dataptr-skiq->block_size_in_words);
#endif
// copy skiq pointer in front of TX packet buffer
txp_i->priv = (void *)skiq;
// copy tx_packet index in front of TX packet buffer
txp_i->idx = i;
if (txq->elm[txq->head].length==0) {
// disactivate head element
txq->elm[txq->head].active=0;
// point head to next element in the queue
txq->head=(txq->head+1)%SKIQ_MAX_TX_ELM;
}
#ifdef DEBUG_SKIQ_TX
printf(ANSI_COLOR_RED "skiq_tx_thread: unlocking mutex, time %llu\n" ANSI_COLOR_RESET,rdtsc_oai());
#endif
pthread_mutex_unlock(&skiq->tx_mutex);
#ifdef SKIQ_ASYNCH
if ((res=skiq_transmit(skiq->card_list[0], skiq_tx_hdl_A1,(int32_t*)&(txp_i->skiq_pkt))) == SKIQ_TX_ASYNC_SEND_QUEUE_FULL ) {
#ifdef DEBUG_SKIQ_TX
printf("skiq_tx_thread: send queue full, sleeping\n");
#endif
pthread_mutex_lock( &skiq->space_avail_mutex );
pthread_cond_wait( &skiq->space_avail_cond, &skiq->space_avail_mutex );
pthread_mutex_unlock( &skiq->space_avail_mutex );
// send packet again now that there is room
if ((res=skiq_transmit(skiq->card_list[0], skiq_tx_hdl_A1,(int32_t*)&(txp_i->skiq_pkt))) == SKIQ_TX_ASYNC_SEND_QUEUE_FULL )
printf("skiq_tx_thread: error, send queue still full after cond_signal, packet will be dropped\n");
}
#else
if ((res=skiq_transmit(skiq->card_list[0], skiq_tx_hdl_A1,(int32_t*)&(txp_i->skiq_pkt))) < 0 ) {
printf("skiq_tx_thread: skiq_transmit error, exiting\n");
skiq->tx_active=0;
}
#ifdef DUMP_TX_FILE
if (dump_cnt<1+(153600/skiq->block_size_in_words)) {
printf("skiq_tx_thread: Dumping packet %d/%d\n",dump_cnt,153600/skiq->block_size_in_words);
skiq_dump_txpacket((void*)txp_i,skiq->block_size_in_words,fp);
dump_cnt++;
}
#endif
skiq->txp_active[i]=0;
#endif
tx_cnt++;
i=(i+1)%skiq->num_blocks_per_subframe;
out = rdtsc_oai();
#ifdef DEBUG_SKIQ_TX
printf(ANSI_COLOR_RED "skiq_tx_thread: received res %d from skiq_transmit(), time %d (in %llu)\n" ANSI_COLOR_RESET,
res,(int) (out-in),in);
#endif
}
else {
// empty head and continue with next element if its there
// index of next element in the queue
next =(txq->head+1)%SKIQ_MAX_TX_ELM;
if (txq->elm[next].active>0) {
#ifdef DEBUG_SKIQ_TX
printf(ANSI_COLOR_RED "skiq_tx_thread: (head_length < %d): Putting elm %d (tail %d) to TX packet %d/%d (length %d, TS %llu)\n" ANSI_COLOR_RESET,
skiq->block_size_in_words,
txq->head,
txq->tail,
i,
skiq->num_blocks_per_subframe,
txq->elm[txq->head].length,
txq->elm[txq->head].timestamp);
#endif
// more than one active element in the queue
// length of residual amount in head of queue
len = txq->elm[txq->head].length;
skiq->txp_active[i]=1;
// timestamp of head elemen in queue
txp_i->skiq_pkt.meta = 0;
txp_i->skiq_pkt.ts = txq->elm[txq->head].timestamp;
// IQ data date of head element
memcpy(txp_i->skiq_pkt.iq,
(void *)txq->elm[txq->head].dataptr,
len<<2);
#ifdef DEBUG_SKIQ_TX
printf("elm %d: writing %d words/ left %d to tx @%llu -> %p\n",txq->head,len,len-txq->elm[txq->head].length,
txq->elm[txq->head].timestamp,
txq->elm[txq->head].dataptr);
#endif
// disactivate head element
txq->elm[txq->head].active=0;
// point head to next element in the queue
txq->head=next;
#ifdef DEBUG_SKIQ_TX
printf(ANSI_COLOR_RED "skiq_tx_thread: (head_length < %d): Putting elm %d (tail %d) to TX packet %d/%d (length %d, TS %llu)\n" ANSI_COLOR_RESET,
skiq->block_size_in_words,
txq->head,txq->tail,
i,
skiq->num_blocks_per_subframe,
skiq->block_size_in_words-len,
txq->elm[txq->head].timestamp);
#endif
// copy IQ data from new element
memcpy(&(txp_i->skiq_pkt.iq[len]),
(void*)txq->elm[txq->head].dataptr,
(skiq->block_size_in_words-len)<<2);
// update queue
txq->elm[txq->head].dataptr += (skiq->block_size_in_words-len);
txq->elm[txq->head].timestamp += (skiq->block_size_in_words-len);
txq->elm[txq->head].length -= (skiq->block_size_in_words-len);
#ifdef DEBUG_SKIQ_TX
printf("elm %d : writing %d words/ left %d to tx @%llu -> %p\n",txq->head,skiq->block_size_in_words-len,txq->elm[txq->head].length,
txq->elm[txq->head].timestamp-(skiq->block_size_in_words-len),
txq->elm[txq->head].dataptr-(skiq->block_size_in_words-len));
#endif
// copy skiq pointer in front of TX packet buffer
txp_i->priv = (void *)skiq;
// copy tx_packet index in front of TX packet buffer
txp_i->idx = i;
#ifdef DEBUG_SKIQ_TX
printf(ANSI_COLOR_RED "skiq_tx_thread: Unlocking tx_mutex\n" ANSI_COLOR_RESET);
#endif
pthread_mutex_unlock(&skiq->tx_mutex);
#ifdef SKIQ_ASYNCH
if ((res=skiq_transmit(skiq->card_list[0], skiq_tx_hdl_A1,(int32_t*)&(txp_i->skiq_pkt))) == SKIQ_TX_ASYNC_SEND_QUEUE_FULL ) {
#ifdef DEBUG_SKIQ_TX
printf("skiq_tx_thread: send queue full, sleeping\n");
#endif
pthread_mutex_lock( &skiq->space_avail_mutex );
pthread_cond_wait( &skiq->space_avail_cond, &skiq->space_avail_mutex );
pthread_mutex_unlock( &skiq->space_avail_mutex );
}
#else
if ((res=skiq_transmit(skiq->card_list[0], skiq_tx_hdl_A1,(int32_t*)&(txp_i->skiq_pkt))) < 0 ) {
printf("skiq_tx_thread: skiq_transmit error, exiting\n");
skiq->tx_active=0;
}
skiq->txp_active[i]=0;
#endif
i=(i+1)%skiq->num_blocks_per_subframe;
#ifdef DEBUG_SKIQ_TX
printf(ANSI_COLOR_RED "skiq_tx_thread: received res %d from skiq_transmit(), time now %llu\n" ANSI_COLOR_RESET,
res,rdtsc_oai());
#endif
}
#ifdef DEBUG_SKIQ_TX
// printf(ANSI_COLOR_RED "Unlocking tx_mutex + sleeping, time %llu\n" ANSI_COLOR_RESET,rdtsc_oai());
#endif
pthread_mutex_unlock(&skiq->tx_mutex);
usleep(100);
#ifdef DEBUG_SKIQ_TX
// printf(ANSI_COLOR_RED "skiq_tx_thread: waking up, time %llu\n" ANSI_COLOR_RESET,rdtsc_oai());
#endif
}
} // txp_active[i]=0
else {
#ifdef DEBUG_SKIQ_TX
// printf(ANSI_COLOR_RED "skiq_tx_thread: Unlocking tx_mutex + sleeping, time %llu\n" ANSI_COLOR_RESET,rdtsc_oai());
#endif
pthread_mutex_unlock(&skiq->tx_mutex);
usleep(100);
#ifdef DEBUG_SKIQ_TX
// printf(ANSI_COLOR_RED "skiq_tx_thread: waking up, time %llu\n" ANSI_COLOR_RESET,rdtsc_oai());
#endif
}
}
printf(ANSI_COLOR_RED "skiq_tx_thread: returning\n" ANSI_COLOR_RESET);
#ifdef DUMP_TX_FILE
fclose(fp);
#endif
return((void*)NULL);
}
/*! \brief Start Sidekiq
* \param device the hardware to use
* \returns 0 on success
*/
int trx_skiq_start(openair0_device *device) {
skiq_state_t *skiq = (skiq_state_t*)device->priv;
skiq_write_chan_mode(skiq->card_list[0], skiq_chan_mode_single);
// set 5ms timeout on read
// skiq_set_rx_transfer_timeout(skiq->card_list[0], 5000);
skiq->rx_current_ts=0;
skiq->rx_actual_nsamps=0;
skiq->rx_nsamps=0;
skiq->rx_count=0;
skiq->residual_read_size[skiq->card_list[0]] = 0;
if(skiq_reset_timestamps(skiq->card_list[0]) != 0 ) {
printf("Error: unable to reset the timestamps\r\n");
return (-1);
}
// create the tx thread
pthread_create(&skiq->tx_thread,NULL,skiq_tx_thread,(void*)skiq);
if ( skiq_start_rx_streaming(skiq->card_list[0],skiq_rx_hdl_A1) != 0 ){
printf("Error: unable to start rx streaming\r\n");
return (-1);
}
return 0;
}
int skiq_add_tx_el(skiq_state_t *skiq, openair0_timestamp ptimestamp,void **buff,int nsamps) {
TX_input_packet_q_t *txq = &skiq->txq;
int res=0;
#ifdef DEBUG_SKIQ_TX
printf(ANSI_COLOR_BLUE "skiq_add_tx_el: Locking TX mutex, time %llu\n" ANSI_COLOR_RESET,rdtsc_oai());
#endif
pthread_mutex_lock(&skiq->tx_mutex);
#ifdef DEBUG_SKIQ_TX
printf(ANSI_COLOR_BLUE "skiq_add_tx_el: Unlocked TX mutex, time %llu\n" ANSI_COLOR_RESET,rdtsc_oai());
#endif
if (((txq->tail+1) % SKIQ_MAX_TX_ELM) != txq->head) { // queue is not full
#ifdef DEBUG_SKIQ_TX
printf(ANSI_COLOR_BLUE "skiq_add_tx_el: Adding element at time %lu and size %d to txq (head %d, tail %d, SKIQ_MAX_TX_ELM %d), buff %p\n" ANSI_COLOR_RESET,
(uint64_t)ptimestamp,nsamps,txq->head,txq->tail,SKIQ_MAX_TX_ELM,buff[0]);
#endif
txq->elm[txq->tail].dataptr = buff[0];
txq->elm[txq->tail].timestamp = ptimestamp;
txq->elm[txq->tail].length = nsamps;
txq->elm[txq->tail].active = 1;
txq->tail = (txq->tail+1) % SKIQ_MAX_TX_ELM;
}
else {
printf("TX queue is full, dropping element\n");
res=-1;
}
/*
int diff = (SKIQ_MAX_TX_ELM + txq->tail - txq->head)%SKIQ_MAX_TX_ELM;
if (diff > 2) {
txq->head = (txq->head+1)%SKIQ_MAX_TX_ELM;
printf("dropping TX queue head\n");
}*/
pthread_mutex_unlock(&skiq->tx_mutex);
#ifdef DEBUG_SKIQ_TX
printf(ANSI_COLOR_BLUE "skiq_add_tx_el: unlocked TX mutex, time %llu\n" ANSI_COLOR_RESET,rdtsc_oai());
#endif
return(res);
}
/*! \brief Called to send samples to the Sidekiq 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 cc index of the component carrier
\param flags Ignored for the moment
\returns 0 on success
*/
static int trx_skiq_write(openair0_device *device,openair0_timestamp ptimestamp, void **buff, int nsamps, int cc, int flags) {
skiq_state_t *skiq = (skiq_state_t*)device->priv;
/* SKIQ has only 1 rx/tx chaine : is it correct? */
#ifdef DEBUG_SKIQ_TX
uint32_t late;
uint64_t txts;
/*
skiq_read_tx_num_late_timestamps(skiq->card_list[0],skiq_tx_hdl_A1,
&late);
skiq_read_curr_tx_timestamp(skiq->card_list[0],skiq_tx_hdl_A1,
&txts);
*/
printf(ANSI_COLOR_BLUE "trx_skiq_write: Writing buff %p (%p) @ %llu (time now %llu, SKIQ TS %llu, tx_active %d), late %d\n" ANSI_COLOR_RESET,
buff,buff[0],ptimestamp,rdtsc_oai(),
txts,
late,
skiq->tx_active);
#endif
if (skiq->tx_active == 0) {
printf("TX not active yet, dropping TX packet\n");
return(nsamps);
}
// add write to queue
if (skiq_add_tx_el(skiq,ptimestamp,buff,nsamps) < 0) {
printf("TX buffer full, exiting\n");
skiq->tx_active=0;
sleep(5);
return(0);
}
// skiq_send_tx(skiq);
skiq->tx_current_ts=0;
skiq->tx_actual_nsamps+=0;
skiq->tx_nsamps+=nsamps;
skiq->tx_count++;
return(nsamps);
}
typedef struct {
uint64_t rf_timestamp;
uint64_t sys_timestamp;
uint32_t sys_word;
uint32_t user_word;
} skiq_read_header_t;
/*! \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 cc Index of component carrier
* \returns number of samples read
*/
static int trx_skiq_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int cc) {
skiq_rx_status_t status;
skiq_state_t *skiq = (skiq_state_t*)device->priv;
uint8_t *buf;
uint64_t curr_ts;
skiq_rx_hdl_t hdl = skiq_rx_hdl_A1;
uint32_t total_len = 0;
uint32_t len;
uint32_t nsamps_block=0,nsamps_used=0;
int res;
int gap;
while (total_len < nsamps) {
res = skiq->residual_read_size[skiq->card_list[0]];
// handle residual samples stored from last read
if (res > 0) {
if (res <= nsamps)
total_len = res;
else
total_len = nsamps;
memcpy(buff[0],
(void*)skiq->residual_read_buffer[skiq->card_list[0]],
total_len<<2);
*ptimestamp = skiq->residual_ts[skiq->card_list[0]];
skiq->rx_current_ts = skiq->residual_ts[skiq->card_list[0]] + total_len;
#ifdef DEBUG_SKIQ_RX
printf(ANSI_COLOR_BLUE "trx_skiq_read: requested (residual) %d samps, res %d (total so far %d), ts %lu, next_ts %lu\n" ANSI_COLOR_RESET ,nsamps,res,total_len,
*ptimestamp,skiq->rx_current_ts);
#endif
if (res >= nsamps) { // the read was less than what was left so update residual buffer and return
skiq->residual_read_size[skiq->card_list[0]]-=nsamps;
memmove((void*)skiq->residual_read_buffer[skiq->card_list[0]],
(void*)skiq->residual_read_buffer[skiq->card_list[0]]+(total_len<<2),
skiq->residual_read_size[skiq->card_list[0]]<<2);
return(nsamps);
}
else {
skiq->residual_read_size[skiq->card_list[0]]=0;
}
}
gap = 0;
status = skiq_receive(skiq->card_list[0], &hdl, &buf, &len);
nsamps_block = (len-sizeof(skiq_read_header_t))>>2;
if( status == skiq_rx_status_success ) {
if( buf != NULL ) {
curr_ts = *((uint64_t*)(buf));
#ifdef DEBUG_SKIQ_RX
printf("trx_skiq_read: requested %d samps, got %d (total so far %d), curr_ts %llu, expected %llu\n",nsamps,nsamps_block,total_len,
curr_ts,skiq->rx_current_ts);
#endif
if ((skiq->rx_count > 0) &&
(curr_ts != skiq->rx_current_ts)) { // handel gap in received timestamp
printf("SKIQ Error: timestamp error expected 0x%016lx but got 0x%016lx.\r\n",
skiq->rx_current_ts, curr_ts);
gap = (int)(curr_ts-skiq->rx_current_ts);
printf("SKIQ: gap of %d samples in timestamp, adjusting\n",gap);
printf("SKIQ: total samples received %lu\n", skiq->rx_nsamps);
printf("SKIQ: system word %x\n", ((skiq_read_header_t*)buf)->sys_word);
// return (-1);
}
}
else {
printf("Error: skiq_received returned NULL pointer\r\n");
return (-1);
}
gap=0;
// copy buffer
if (total_len + nsamps_block + gap <= nsamps)
nsamps_used = nsamps_block;
else
nsamps_used = nsamps - total_len;
uint32_t tmp,i;
uint32_t *in = (uint32_t*)(((void*)buf)+sizeof(skiq_read_header_t));
uint32_t *out = (uint32_t*)(((void*)buff[0])+(total_len<<2));
//flip I/Q positions
for (i=0;i<nsamps_used;i++) {
tmp = in[i];
out[i] = (tmp<<16)|(tmp>>16);
}
/*
memcpy(buff[0]+((gap+total_len)<<2),
((void*)buf)+sizeof(skiq_read_header_t),
nsamps_used<<2);*/
if (gap>0)
memset(buff[0]+(total_len<<2),0,gap<<2);
if (total_len == 0) { // this is the first read so copy timestamp
*ptimestamp = (openair0_timestamp)curr_ts;
}
total_len += nsamps_used+gap;
skiq->rx_current_ts = curr_ts+nsamps_used+gap;
skiq->rx_count++;
skiq->rx_actual_nsamps+=(nsamps_used+gap);
if (status == skiq_rx_status_error_overrun)
printf("status : overrun, exiting ...\n");
else if (status == skiq_rx_status_error_generic)
printf("status : generic error, exiting ...\n");
} // skiq_rx_status_success
} // total_len < nsamps
#ifdef DEBUG_SKIQ_RX
printf("trx_skiq_read: (residual update): nsamps_used %d, nsamps_block %d\n",nsamps_used,nsamps_block);
#endif
if ((nsamps_used+gap) < nsamps_block) { //update residual counters
skiq->residual_read_size[skiq->card_list[0]] = nsamps_block-nsamps_used-gap;
skiq->residual_ts[skiq->card_list[0]] = skiq->rx_current_ts;
memcpy((void*)skiq->residual_read_buffer[skiq->card_list[0]],
((void*)buf)+sizeof(skiq_read_header_t),
(nsamps_block-nsamps_used)<<2);
}
skiq->rx_nsamps+=nsamps;
#ifdef DEBUG_SKIQ_TX
printf(ANSI_COLOR_BLUE "trx_skiq_read: returning %d samples @ %llu\n" ANSI_COLOR_RESET,nsamps,*ptimestamp);
#endif
return nsamps;
}
/*! \brief print the Sidekiq statistics
* \param device the hardware to use
* \returns 0 on success
*/
int trx_skiq_get_stats(openair0_device* device) {
return(0);
}
/*! \brief Reset the Sidekiq statistics
* \param device the hardware to use
* \returns 0 on success
*/
int trx_skiq_reset_stats(openair0_device* device) {
return(0);
}
/*! \brief Stop Sidekiq
* \param card the hardware to use
* \returns 0 in success
*/
int trx_skiq_stop(openair0_device *device) {
skiq_state_t *skiq = (skiq_state_t*)device->priv;
printf("SKIQ: Stopping RX streaming now\n");
skiq_stop_rx_streaming(skiq->card_list[0],skiq_rx_hdl_A1);
printf("SKIQ: Stopping TX streaming now\n");
skiq->tx_active=0;
skiq_stop_tx_streaming(skiq->card_list[0],skiq_tx_hdl_A1);
return(0);
}
/*! \brief Terminate operation of the Sidekiq transceiver -- free all associated resources
* \param device the hardware to use
*/
void trx_skiq_end(openair0_device *device) {
skiq_state_t *skiq = (skiq_state_t*)device->priv;
// Disable RX module, shutting down our underlying RX stream
int i;
if (skiq->tx_active==1) {
printf("SKIQ: skiq_end, stopping device\n");
trx_skiq_stop(device);
sleep(1);
}
for (i=0;i<skiq->num_blocks_per_subframe;i++) {
free(skiq->tx_packet[i]);
}
pthread_mutex_destroy(&skiq->tx_mutex);
pthread_mutex_destroy(&skiq->space_avail_mutex);
pthread_cond_destroy(&skiq->space_avail_cond);
skiq_exit();
sleep(1);
free((void*)device->priv);
}
/*! \brief Set frequencies (TX/RX)
* \param device the hardware to use
* \param openair0_cfg1 openair0 Config structure (ignored. It is there to comply with RF common API)
* \param exmimo_dump_config (ignored)
* \returns 0 in success
*/
int trx_skiq_set_freq(openair0_device* device, openair0_config_t *openair0_cfg1,int exmimo_dump_config) {
skiq_state_t *skiq = (skiq_state_t *)device->priv;
openair0_config_t *openair0_cfg = (openair0_config_t *)device->openair0_cfg;
int result;
int cardid=0;
if ((result=skiq_write_rx_LO_freq(skiq->card_list[cardid],
skiq_rx_hdl_A1,
(uint64_t)openair0_cfg->rx_freq[0]) < 0))
{
printf("Error: failed to set Rx LO freq to %llu Hz\n",(unsigned long long)openair0_cfg->rx_freq[0]);
return(-1);
}
return(0);
}
/*! \brief Set Gains (TX/RX)
* \param device the hardware to use
* \param openair0_cfg openair0 Config structure
* \returns 0 in success
*/
int trx_skiq_set_gains(openair0_device* device, openair0_config_t *openair0_cfg) {
return(0);
}
void skiq_tx_complete(int32_t status,uint32_t *p_data) {
tx_packet_t *txp_i;
skiq_tx_packet_t *stp = (skiq_tx_packet_t *)p_data;
skiq_state_t *skiq;
if (p_data) {
txp_i = (tx_packet_t*) container_of(stp,tx_packet_t,skiq_pkt);
skiq = (skiq_state_t *)(txp_i->priv);
if (skiq) {
#ifdef DEBUG_SKIQ_TX
printf("skiq_tx_complete: packet %d (%p) received with status %x, clearing active flag (%d => 0)\n",
txp_i->idx,p_data,status,skiq->txp_active[txp_i->idx]);
#endif
skiq->txp_active[txp_i->idx]=0;
pthread_cond_signal(&skiq->space_avail_cond);
}
}
else {
printf("skiq_tx_complete: received NULL p_data (%p)\n",p_data);
}
}
/*! \brief calibration table for Sidekiq */
rx_gain_calib_table_t calib_table_skiq[] = {
{2300000000.0,49.5},
{1880000000.0,47.5},
{816000000.0,57.5},
{-1,0}};
/*! \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 Initialize Openair Sidekiq target. It returns 0 if OK
* \param device the hardware to use
* \param openair0_cfg RF frontend parameters set by application
* \returns 0 on success
*/
int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
skiq_state_t *skiq = (skiq_state_t*)malloc(sizeof(skiq_state_t));
memset(skiq, 0, sizeof(skiq_state_t));
pthread_mutex_init(&skiq->tx_mutex,NULL);
pthread_mutex_init(&skiq->space_avail_mutex,NULL);
pthread_cond_init(&skiq->space_avail_cond,NULL);
/* device specific */
//openair0_cfg->txlaunch_wait = 1;//manage when TX processing is triggered
//openair0_cfg->txlaunch_wait_slotcount = 1; //manage when TX processing is triggered
openair0_cfg->iq_txshift = 0;// shift
openair0_cfg->iq_rxrescale = 15;//rescale iqs
// init required params
switch ((int)openair0_cfg->sample_rate) {
case 30720000:
openair0_cfg->tx_sample_advance = 0;
skiq->block_size_in_words = SKIQ_BLOCK_SIZE_IN_WORDS;
skiq->num_blocks_per_subframe = 30720/(skiq->block_size_in_words);
break;
case 23040000:
openair0_cfg->tx_sample_advance = 0;
skiq->block_size_in_words = SKIQ_BLOCK_SIZE_IN_WORDS;
skiq->num_blocks_per_subframe = 23040/(skiq->block_size_in_words);
break;
case 15360000:
openair0_cfg->tx_sample_advance = 0;
skiq->block_size_in_words = SKIQ_BLOCK_SIZE_IN_WORDS;
skiq->num_blocks_per_subframe = 15360/(skiq->block_size_in_words);
break;
case 7680000:
openair0_cfg->tx_sample_advance = 0;
skiq->block_size_in_words = SKIQ_BLOCK_SIZE_IN_WORDS;
skiq->num_blocks_per_subframe = 7680/(skiq->block_size_in_words);
break;
case 1920000:
openair0_cfg->tx_sample_advance = 0;
skiq->block_size_in_words = 256-4;
skiq->num_blocks_per_subframe = 1920/(skiq->block_size_in_words);
break;
default:
printf("Error: unsupported sampling rate %f\n",openair0_cfg->sample_rate);
exit(-1);
break;
}
openair0_cfg->iq_txshift= 0;
openair0_cfg->iq_rxrescale = 15; /*not sure*/
openair0_cfg->rx_gain_calib_table = calib_table_skiq;
// open device
printf("[SKIQ] init dev \n");
/* probe the host system for installed Sidekiq cards */
skiq_probe(true, false);
/* query the list of all Sidekiq cards */
skiq_get_avail_cards( &skiq->number_of_cards, skiq->card_list );
if (skiq->number_of_cards>0)
printf("Initializing %d Sidekiq cards\n",skiq->number_of_cards);
else {
printf("Found no Sidekiq cards, exiting\n");
return(-1);
}
skiq_init(skiq_pcie_init_level_2, skiq_usb_init_level_0,skiq->card_list,skiq->number_of_cards);
int32_t result;
uint32_t p_git_hash,p_build_date;
uint8_t p_major,p_minor,p_patch;
skiq_fpga_tx_fifo_size_t p_tx_fifo_size;
for (int cardid=0;cardid<skiq->number_of_cards;cardid++) {
if ((result=skiq_read_fpga_version(skiq->card_list[cardid],
&p_git_hash,
&p_build_date,
&p_major,
&p_minor,
&p_tx_fifo_size))<0)
{
printf("SKIQ Error: failed to get FPGA version information\n");
return(-1);
}
else {
printf("Sidekiq FPGA (git hash %x, build data %d, major %d, minor %d, fifo size %d kwords\n",
p_git_hash,p_build_date,p_major,p_minor,p_tx_fifo_size == 0 ? -1 : 2<<p_tx_fifo_size);
}
if ((result=skiq_read_libsidekiq_version(&p_major,
&p_minor,
&p_patch))<0)
{
printf("SKIQ Error: failed to get libsidekiq version information\n");
return(-1);
}
else {
printf("lisidekiq info (major %d, minor %d, patch %d\n",
p_major,p_minor,p_patch);
}
if((result=skiq_write_rx_sample_rate_and_bandwidth(skiq->card_list[cardid],
skiq_rx_hdl_A1,
(uint32_t)openair0_cfg->sample_rate,
(uint32_t)openair0_cfg->rx_bw) < 0))
{
printf("SKIQ Error: failed to set rx sample rate to %d Hz\n",(uint32_t)openair0_cfg->sample_rate);
return(-1);
}
else {
printf("SKIQ set rx sample rate to %d Hz\n",(uint32_t)openair0_cfg->sample_rate);
}
if((result=skiq_write_tx_sample_rate_and_bandwidth(skiq->card_list[cardid],
skiq_tx_hdl_A1,
(uint32_t)openair0_cfg->sample_rate,
(uint32_t)openair0_cfg->tx_bw) < 0))
{
printf("SKIQ Error: failed to set tx sample rate to %d Hz\n",(uint32_t)openair0_cfg->sample_rate);
return(-1);
}
else {
printf("SKIQ set tx sample rate to %d Hz\n",(uint32_t)openair0_cfg->sample_rate);
}
if ((result=skiq_write_rx_LO_freq(skiq->card_list[cardid],
skiq_rx_hdl_A1,
(uint64_t)openair0_cfg->rx_freq[0]) < 0))
{
printf("SKIQ Error: failed to set Rx LO freq to %llu Hz\n",(unsigned long long)openair0_cfg->rx_freq[0]);
return(-1);
}
else {
printf("SKIQ: set Rx LO freq to %llu Hz\n",(unsigned long long)openair0_cfg->rx_freq[0]);
}
if ((result=skiq_write_tx_LO_freq(skiq->card_list[cardid],
skiq_tx_hdl_A1,
(uint64_t)openair0_cfg->tx_freq[0]) < 0))
{
printf("SKIQ Error: failed to set tx LO freq to %llu Hz\n",(unsigned long long)openair0_cfg->tx_freq[0]);
return(-1);
}
else {
printf("SKIQ: set tx LO freq to %llu Hz\n",(unsigned long long)openair0_cfg->tx_freq[0]);
}
if( (result=skiq_write_tx_data_flow_mode(skiq->card_list[cardid], skiq_tx_hdl_A1,
skiq_tx_with_timestamps_data_flow_mode)) != 0 )
{
printf("Error: unable to configure Tx data flow mode to with_timestatmps\r\n");
return (-1);
}
if( (result=skiq_write_tx_block_size(skiq->card_list[cardid], skiq_tx_hdl_A1,
skiq->block_size_in_words)) != 0 )
{
printf("Error: unable to configure Tx block size\r\n");
return (-1);
}
if( (result=skiq_disable_tx_tone(skiq->card_list[cardid], skiq_tx_hdl_A1)) != 0)
{
printf("Error: unable to disable tx_tone\r\n");
return (-1);
}
#ifdef SKIQ_ASYNCH
// set the transfer mode to async
if( skiq_write_tx_transfer_mode(skiq->card_list[cardid], skiq_tx_hdl_A1, skiq_tx_transfer_mode_async) != 0 )
{
printf("Error: unable to set transfer mode to async\r\n");
return (-1);
}
// register the callback
if( skiq_register_tx_complete_callback(skiq->card_list[cardid], &skiq_tx_complete ) != 0 )
{
printf("Error: unable to register callback\r\n");
return (-1);
}
if( skiq_write_num_tx_threads( skiq->card_list[cardid],
2) != 0)
{
printf("Error: unable to set number of TX threads to 2\r\n");
return (-1);
}
#else
// set the transfer mode to sync
if( skiq_write_tx_transfer_mode(skiq->card_list[cardid], skiq_tx_hdl_A1, skiq_tx_transfer_mode_sync) != 0 )
{
printf("Error: unable to set transfer mode to sync\r\n");
return (-1);
}
#endif
if ((result=skiq_write_rx_gain_mode(skiq->card_list[cardid],
skiq_rx_hdl_A1,
skiq_rx_gain_manual) < 0))
{
printf("SKIQ Error: failed to set Rx gain mode to manual\n");
return(-1);
}
else {
printf("SKIQ: Set RX gain mode to manual\n");
}
set_rx_gain_offset(&openair0_cfg[0],0);
if ((result=skiq_write_rx_gain(skiq->card_list[cardid],
skiq_rx_hdl_A1,
(uint32_t)openair0_cfg->rx_gain[0]-(int32_t)openair0_cfg[0].rx_gain_offset[0]) < 0))
{
printf("SKIQ Error: failed to set Rx gain to %u (offset %d)\n",(uint32_t)openair0_cfg->rx_gain[0],(int32_t)openair0_cfg[0].rx_gain_offset[0]);
return(-1);
}
else {
printf("SKIQ Set rx gain to %u dB (offset %d)\n",(uint32_t)openair0_cfg->rx_gain[0]-(int32_t)openair0_cfg[0].rx_gain_offset[0],(int32_t)openair0_cfg[0].rx_gain_offset[0]);
}
if ((result=skiq_write_tx_attenuation(skiq->card_list[cardid],
skiq_rx_hdl_A1,
0)))
{
printf("SKIQ Error: failed to set tx attenuation to %u\n",0);
return(-1);
}
else {
printf("SKIQ Set tx attenuation %u dB\n",0);
}
}
printf("SKIQ: Initializing openair0_device\n");
device->Mod_id = num_devices++;
device->type = SKIQ_DEV;
device->trx_start_func = trx_skiq_start;
device->trx_end_func = trx_skiq_end;
device->trx_read_func = trx_skiq_read;
device->trx_write_func = trx_skiq_write;
device->trx_get_stats_func = trx_skiq_get_stats;
device->trx_reset_stats_func = trx_skiq_reset_stats;
device->trx_stop_func = trx_skiq_stop;
device->trx_set_freq_func = trx_skiq_set_freq;
device->trx_set_gains_func = trx_skiq_set_gains;
device->openair0_cfg = openair0_cfg;
device->priv = (void *)skiq;
// initializing tx buffers
for (int i=0;i<skiq->num_blocks_per_subframe;i++) {
// allocate buffer for TX packets, 4 = header in 32-bit words, pointer and index at end
skiq->tx_packet[i] = (tx_packet_t *)malloc(sizeof(tx_packet_t));
}
// memcpy((void*)&device->openair0_cfg,(void*)&openair0_cfg[0],sizeof(openair0_config_t));
return 0;
}
/*! \brief skiq error report
* \param status
* \returns 0 on success
*/
int skiq_error(int status) {
//exit(-1);
return status; // or status error code
}
/*@}*/
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment