Merge remote-tracking branch 'origin/ru_rau_enhancement_L1_renaming' into develop_integration_2019_w25

This commit is contained in:
Raphael Defosseux
2019-06-18 13:40:42 +02:00
234 changed files with 4738 additions and 592547 deletions
+13
View File
@@ -204,6 +204,8 @@ typedef struct {
double tx_bw;
//! clock source
clock_source_t clock_source;
//! timing_source
clock_source_t time_source;
//! Manual SDR IP address
char *sdr_addrs;
//! Auto calibration flag
@@ -288,6 +290,10 @@ struct openair0_device_t {
/* !brief ETH params set by application */
eth_params_t *eth_params;
/* !brief Indicates if device already initialized */
int is_init;
/*!brief Can be used by driver to hold internal structure*/
void *priv;
@@ -298,6 +304,13 @@ struct openair0_device_t {
*/
int (*trx_start_func)(openair0_device *device);
/*! \brief Called to configure the device
@param device pointer to the device structure specific to the RF hardware target
*/
int (*trx_config_func)(openair0_device* device, openair0_config_t *openair0_cfg);
/*! \brief Called to send a request message between RAU-RRU on control port
@param device pointer to the device structure specific to the RF hardware target
@param msg pointer to the message structure passed between RAU-RRU
@@ -176,7 +176,8 @@ int trx_eth_read_udp_IF4p5(openair0_device *device, openair0_timestamp *timestam
int block_cnt=0;
packet_size = max(UDP_IF4p5_PRACH_SIZE_BYTES, max(UDP_IF4p5_PULFFT_SIZE_BYTES(nblocks), UDP_IF4p5_PDLFFT_SIZE_BYTES(nblocks)));
// *2 because of 2 antennas PUL/DLFFT are controlled by nsamps, PRACH is not
packet_size = max(UDP_IF4p5_PRACH_SIZE_BYTES*2, max(UDP_IF4p5_PULFFT_SIZE_BYTES(nblocks), UDP_IF4p5_PDLFFT_SIZE_BYTES(nblocks)));
while(bytes_received == -1) {
again:
@@ -190,6 +191,7 @@ int trx_eth_read_udp_IF4p5(openair0_device *device, openair0_timestamp *timestam
eth->num_rx_errors++;
if (errno == EAGAIN) {
printf("Lost IF4p5 connection with %s\n", inet_ntoa(eth->dest_addrd.sin_addr));
return -1;
} else if (errno == EWOULDBLOCK) {
block_cnt++;
usleep(10);
@@ -209,7 +211,6 @@ int trx_eth_read_udp_IF4p5(openair0_device *device, openair0_timestamp *timestam
eth->rx_count++;
}
}
//printf("size of third %d subtype %d frame %d subframe %d symbol %d \n", bytes_received, test_header->sub_type, ((test_header->frame_status)>>6)&0xffff, ((test_header->frame_status)>>22)&0x000f, ((test_header->frame_status)>>26)&0x000f) ;
eth->rx_nsamps = nsamps;
return(bytes_received);
@@ -237,7 +238,7 @@ int trx_eth_write_udp_IF4p5(openair0_device *device, openair0_timestamp timestam
packet_size = UDP_IF4p5_PULTICK_SIZE_BYTES;
} else if ((flags >= IF4p5_PRACH)&&
(flags <= (IF4p5_PRACH+4))) {
packet_size = UDP_IF4p5_PRACH_SIZE_BYTES;
packet_size = UDP_HEADER_SIZE_BYTES + IPV4_HEADER_SIZE_BYTES + sizeof_IF4p5_header_t + (nsamps<<1);
} else {
printf("trx_eth_write_udp_IF4p5: unknown flags %d\n",flags);
return(-1);
@@ -116,7 +116,7 @@ int trx_eth_start(openair0_device *device) {
*/
/* adjust MTU wrt number of samples per packet */
if(ethernet_tune (device,MTU_SIZE,UDP_IF4p5_PRACH_SIZE_BYTES)!=0) return -1;
// if(ethernet_tune (device,MTU_SIZE,UDP_IF4p5_PRACH_SIZE_BYTES)!=0) return -1;
@@ -148,6 +148,7 @@ int trx_eth_start(openair0_device *device) {
if(ethernet_tune (device, KERNEL_SND_BUF_MAX_SIZE, 200000000)!=0) return -1;
if(ethernet_tune (device, KERNEL_RCV_BUF_MAX_SIZE, 200000000)!=0) return -1;
return 0;
}
@@ -1,11 +0,0 @@
# PROMGEN: Xilinx Prom Generator O.76xd
# Copyright (c) 1995-2011 Xilinx, Inc. All rights reserved.
SOFTWARE_VERSION O.76xd
DATE 1/ 3/2017 - 11:49
SOURCE /homes/kaltenbe/Devel/openair/openairinterface5g/targets/ARCH/EXMIMO/BITSTREAM/exmimo2_prom.mcs
DEVICE 8192K
DATA_WIDTH 4
FILL_DATA 0xFF
SIGNATURE 0x416AB633
START_ADDRESS 0x00000000 END_ADDRESS 0x00406577 DIRECTION_UP "express-mimo2.bit" 6slx150tfgg900
File diff suppressed because it is too large Load Diff
@@ -1,17 +0,0 @@
PROMGEN: Xilinx Prom Generator O.76xd
Copyright (c) 1995-2011 Xilinx, Inc. All rights reserved.
promgen -w -p mcs -c FF -o /homes/kaltenbe/Devel/openair/openairinterface5g/targets/ARCH/EXMIMO/BITSTREAM//exmimo2_prom -s 8192 -u 0000 express-mimo2.bit -spi
PROM /homes/kaltenbe/Devel/openair/openairinterface5g/targets/ARCH/EXMIMO/BITSTREAM/exmimo2_prom.prm map: Tue Jan 3 11:49:20 2017
Calculating PROM checksum with fill value ff
Format Mcs86 (32-bit)
Size 8192K
PROM start 0000:0000
PROM end 007f:ffff
PROM checksum 416ab633
Addr1 Addr2 Date File(s)
0000:0000 0040:6577 Jan 3 10:48:16 2017 express-mimo2.bit
Binary file not shown.
Binary file not shown.
Binary file not shown.
-7
View File
@@ -1,7 +0,0 @@
setMode -bs
setCable -port auto
Identify
identifyMPM
assignFile -p 1 -file "express-mimo2.bit"
Program -p 1 -defaultVersion 0
quit
@@ -1,4 +0,0 @@
#!/bin/bash
impact -batch prom_generate.cmd
impact -batch prom_load.cmd
@@ -1,34 +0,0 @@
setMode -pff
addConfigDevice -name "exmimo2_prom"
setSubmode -pffspi
setAttribute -configdevice -attr multibootBpiType -value ""
addDesign -version 0 -name "0"
setMode -pff
addDeviceChain -index 0
setMode -pff
addDeviceChain -index 0
setAttribute -configdevice -attr compressed -value "FALSE"
setAttribute -configdevice -attr compressed -value "FALSE"
setAttribute -configdevice -attr autoSize -value "FALSE"
setAttribute -configdevice -attr fileFormat -value "mcs"
setAttribute -configdevice -attr fillValue -value "FF"
setAttribute -configdevice -attr swapBit -value "FALSE"
setAttribute -configdevice -attr dir -value "UP"
setAttribute -configdevice -attr multiboot -value "FALSE"
setAttribute -configdevice -attr multiboot -value "FALSE"
setAttribute -configdevice -attr spiSelected -value "TRUE"
setAttribute -configdevice -attr spiSelected -value "TRUE"
addPromDevice -p 1 -size 8192 -name 8M
setMode -pff
addDeviceChain -index 0
setMode -pff
addDeviceChain -index 0
setSubmode -pffspi
setMode -pff
setAttribute -design -attr name -value "0000"
addDevice -p 1 -file "express-mimo2.bit"
setMode -pff
setSubmode -pffspi
generate
setCurrentDesign -version 0
quit
@@ -1,10 +0,0 @@
setMode -bs
setCable -port auto
Identify -inferir
identifyMPM
assignFile -p 1 -file "express-mimo2.bit"
attachflash -position 1 -spi "W25Q64BV"
assignfiletoattachedflash -position 1 -file "exmimo2_prom.mcs"
attachflash -position 1 -spi "W25Q64BV"
Program -p 1 -dataWidth 4 -spionly -e -v -loadfpga
quit
-126
View File
@@ -1,126 +0,0 @@
/*
* 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
*/
#ifndef OPENAIR_DEVICE_H
#define OPENAIR_DEVICE_H
// Maximum number of concurrently supported cards
#define MAX_CARDS 16
#define INIT_ZEROS {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
/** PCIe subsystem configuration Space
*/
// Vendor and System IDs
//
#define XILINX_VENDOR 0x10ee
#define XILINX_ID 0x0007
//
// PCIe Subsystem Vendor ID
#define EURECOM_VENDOR 0x0001
#define TELECOM_PARISTECH_VENDOR 0x0002
/*
PCIe Subsystem ID = exmimo_id.board_exmimoversion(1,2) (4 bits) | exmimo_id.board_hwrev (4 bits) | exmimo_id.board_swrev (Protocol Revision, 8 bits)
Board IDs (exmimo_id.board_exmimoversion(1,2) (4 bits) + exmimo_id.board_hwrev (4 bits))
0x11 => ExpressMIMO-1, first run/HW revision
0x12 => ExpressMIMO-1, second run
0x21 => ExpressMIMO-2, first run
0x22 => ExpressMIMO-2, second run
SW/Protocol revisions: (exmimo_id.board_swrev (Protocol Revision, 8 bits)
BOARD_SWREV_LEGACY:
- IRQ Leon->PC Bit 7 (AHBPCIE_INTERRUPT_ASSERT_BIT) must be cleared in PC kernel driver
- PC->Leon and Leon->PC commands share a single register CONTROL1
BOARD_SWREV_CMDREGISTERS:
- IRQ Leon->PC Bit 7 (AHBPCIE_INTERRUPT_ASSERT_BIT) is automatically cleared on PCIe read
- PC->Leon and Leon->PC commands have separete command registers CONTROL1 (PC->Leon) and CONTROL2 (Leon->PC)
BOARD_SWREV_CMDFIFOS:
- uses two command FIFOs (for PC->Leon and Leon->PC), by Telecom Paristech
*/
#define BOARD_SWREV_LEGACY 0x07
#define BOARD_SWREV_CMDREGISTERS 0x08
#define BOARD_SWREV_CNTL2 0x0A
#define BOARD_SWREV_CMDFIFOS 0x11
// ExpressMIMO PCIe register offsets to bar0
//
#define PCIE_CONTROL0 0x00
#define PCIE_CONTROL1 0x04
#define PCIE_CONTROL2 0x64
#define PCIE_STATUS 0x08
#define PCIE_PCIBASEL 0x1c
#define PCIE_PCIBASEH 0x20
// Device IO definitions and operations
//
#define openair_MAJOR 127
//#define openair_writel(dev,offset,val) pci_write_config_dword(dev,(int)offset,(unsigned int)val)//{writel((uclong)(val),(ulong)(port)); mb();}
//#define openair_readl(dev,offset,val) pci_read_config_dword(dev,(int)offset,(unsigned int*)val)//{writel((uclong)(val),(ulong)(port)); mb();}
#define openair_IOC_MAGIC 'm'
#define openair_GET_BIGSHMTOPS_KVIRT _IOR(openair_IOC_MAGIC,1,int)
#define openair_GET_PCI_INTERFACE_BOTS_KVIRT _IOR(openair_IOC_MAGIC,2,int)
#define openair_GET_NUM_DETECTED_CARDS _IOR(openair_IOC_MAGIC,3,int)
#define openair_DUMP_CONFIG _IOR(openair_IOC_MAGIC,18,int)
#define openair_GET_FRAME _IOR(openair_IOC_MAGIC,6,int)
#define openair_START_RT_ACQUISITION _IOR(openair_IOC_MAGIC,28,int)
#define openair_STOP _IOR(openair_IOC_MAGIC,5,int)
#define openair_STOP_WITHOUT_RESET _IOR(openair_IOC_MAGIC,9,int)
#define openair_RECONFIGURE _IOR(openair_IOC_MAGIC,10,int)
#define openair_UPDATE_FIRMWARE _IOR(openair_IOC_MAGIC,40,int)
/* Update firmware commands */
#define UPDATE_FIRMWARE_TRANSFER_BLOCK 0x1
#define UPDATE_FIRMWARE_CLEAR_BSS 0x2
#define UPDATE_FIRMWARE_START_EXECUTION 0x3
#define UPDATE_FIRMWARE_FORCE_REBOOT 0x4
#define UPDATE_FIRMWARE_TEST_GOK 0x5
// mmap page offset vg_pgoff is used to pass arguments to kernel
// bit0..3: memory block: BIGSHM:0, RX:1,3,5,7, TX:2,4,6,8
// bit4..7: card_id
#define openair_mmap_BIGSHM 0
#define openair_mmap_RX(ant) (((ant)<<1)+1)
#define openair_mmap_TX(ant) (((ant)<<1)+2)
#define openair_mmap_getMemBlock(o) ((o)&0xF)
#define openair_mmap_getAntRX(o) (((o)-1)>>1)
#define openair_mmap_getAntTX(o) (((o)-2)>>1)
#define openair_mmap_Card(c) ( ((c)&0xF)<<4 )
#define openair_mmap_getCard(o) ( ((o)>>4)&0xF )
#endif /* OPENAIR_DEVICE_H */
-406
View File
@@ -1,406 +0,0 @@
/*
* 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
*/
/** pcie_interface.h
Interface definitions to handle communication between PC (kernel driver & SDR application) and Leon3
- commands from PC->Leon and Leon->PC passed through CONTROL1 register (or new: FIFOs)
- structure for passing initial (shared PC memory) buffer pointers
- #defines for buffer sizes
This is now the CENTRAL header file for all structs and defines that are
requires on both LEON and Kernel and PC Application
Changelog:
01.12.2012: Fix: RXEN and TXEN were swapped
New rf_mode flag: use DMAMODE_RX and DMAMODE_TX to selectively enable DMA transfers (only used on ExpressMIMO2)
use RXOUTSW to close Lime baseband RXout switch between RFFE and ADC
09.01.2013: Renamed exmimo_rf_t.mbox --> .p_mbox to indicate this is a pointer to the mbox and not the mbox itself
15.01.2013: added command (EXMIMO_GET_SYSTEMID) and structure (exmimo_system_id_t)
to get system ID and bitstream and software versions on PC
22.01.2013: Moved structures into pcie/pcie_interface.h to have all these spread-out definitions in a single place
Author: Matthias Ihmig <matthias.ihmig@mytum.de>, 2012
Raymond Knopp <raymond.knopp@eurecom.fr>
Riadh Ghaddab <riadh.ghaddab@eurecom.fr>
*/
#ifndef PCIE_INTERFACE_H
#define PCIE_INTERFACE_H
#ifndef __KERNEL__
#include <stdint.h>
#endif
// ------------------------------
// Buffer sizes
// ------------------------------
#define MAX_ANTENNAS 4
#define MAX_FIRMWARE_BLOCK_SIZE_B 262144
#define MAX_PRINTK_BUFFER_B 1024
// #define FRAME_LENGTH_COMPLEX_SAMPLES 76800
// Buffer size per channel: FRAME_LENGTH_COMPLEX_SAMPLES+2048 smp/frame: LTE frame+tail, *4 (7.68*4 MsmpPS), *4 Bytes/smp
#define ADAC_BUFFERSZ_PERCHAN_B ((76800+2048)*4*4)
#define BIGSHM_SIZE_PAGES ((( MAX_FIRMWARE_BLOCK_SIZE_B + \
MAX_PRINTK_BUFFER_B + \
sizeof(exmimo_pci_interface_bot_t) + \
sizeof(exmimo_config_t) + \
sizeof(exmimo_id_t) + \
2*MAX_ANTENNAS*sizeof(uint32_t)*4 + \
16*256 /* alignment overhead */ ) >> PAGE_SHIFT ) +1 )
/*
* Commands exchanged between PC <--> LEON
*
* Idle/Ready: EXMIMO_NOP
*/
#define EXMIMO_NOP 0x9999
// Commands from PC --> LEON, passed through ahbpcie_control1 register (must be smaller than 0x1000 !
#define EXMIMO_PCIE_INIT 0x0000
#define EXMIMO_FW_INIT 0x0001
#define EXMIMO_FW_CLEAR_BSS 0x0002
#define EXMIMO_FW_START_EXEC 0x0003
#define EXMIMO_REBOOT 0x0004
#define EXMIMO_CONFIG 0x0005
#define EXMIMO_GET_FRAME 0x0006
#define EXMIMO_START_RT_ACQUISITION 0x0007
#define EXMIMO_STOP 0x0008
#define EXMIMO_STOP_WITHOUT_RESET 0x0009
#define IS_EXMIMOCMD_FROM_PC(x) ( (x)<0x1000 ? 1 : 0)
// Commands from LEON --> PC, passed through ahbpcie_control2 register
#define PCI_PRINTK 0x2222
#define GET_FRAME_DONE 0x3333
#define EXMIMO_CONTROL2_COOKIE 0x43545232
// Default MODEM configuration in TV whitespace(400.850MHz), using RX/TX switch
#define TVWS_TDD 0xF7E04002
// 850MHz .. 865MHz
#define DD_FDD 0xFAE40041
#define DD_TDD 0xF7E04000
#define B19G_TDD 0xCBC20084
#define B24G_TDD 0xCBA20084
#define B26G_TDD 0xCB820084
#define B26G_FDD 0xDEE60108
#define B35G_TDD 0xE9F01810
#define B50G_TDD 0xC079A020
// used for DPD and dirty RF validation, TX fed back to RX through attenuators
#define TVWS_TDD_DPD 0xF5E04000
#define DD_TDD_DPD 0xF5E04000
#define B19G_TDD_DPD 0xCDC20080
#define B24G_TDD_DPD 0xCDA20080
#define B26G_TDD_DPD 0xCD820080
#define B35G_TDD_DPD 0xEDF01880
// -----------------------------------------------------------
// structures for communication between ExMIMO and kernel
// -----------------------------------------------------------
/*
* struct exmimo_system_id_t:
* Contains information on the bitstream, filled by Leon,
* based on data stored in an APB block on FPGA (TODO)
*
* struct exmimo_id_t:
* Compound structure, also includes information
* from PCI configuration space (board_)
*/
typedef struct {
uint32_t bitstream_id;
uint32_t bitstream_build_date;
uint32_t software_id;
uint32_t software_build_date;
uint32_t dsp_bitstream_id;
uint32_t dsp_bitstream_build_date;
} exmimo_system_id_t;
typedef struct {
exmimo_system_id_t system_id;
uint32_t board_vendor;
uint32_t board_exmimoversion;
uint32_t board_hwrev;
uint32_t board_swrev;
} exmimo_id_t;
/****************************************************
* Structure and flags for configuring RF and LIME
* (struct exmimo_rf_t)
*/
//
// register values and masks for rf_mode
//
#define RXEN 1
#define TXEN 2
#define TXLPFENMASK 4
#define TXLPFEN 4
#define TXLPFMASK (15<<3)
#define TXLPF14 0
#define TXLPF10 (1<<3)
#define TXLPF7 (2<<3)
#define TXLPF6 (3<<3)
#define TXLPF5 (4<<3)
#define TXLPF4375 (5<<3)
#define TXLPF35 (6<<3)
#define TXLPF3 (7<<3)
#define TXLPF275 (8<<3)
#define TXLPF25 (9<<3)
#define TXLPF192 (10<<3)
#define TXLPF15 (11<<3)
#define TXLPF1375 (12<<3)
#define TXLPF125 (13<<3)
#define TXLPF0875 (14<<3)
#define TXLPF075 (15<<3)
#define RXLPFENMASK (1<<7)
#define RXLPFEN 128
#define RXLPFMASK (15<<8)
#define RXLPF14 0
#define RXLPF10 (1<<8)
#define RXLPF7 (2<<8)
#define RXLPF6 (3<<8)
#define RXLPF5 (4<<8)
#define RXLPF4375 (5<<8)
#define RXLPF35 (6<<8)
#define RXLPF3 (7<<8)
#define RXLPF275 (8<<8)
#define RXLPF25 (9<<8)
#define RXLPF192 (10<<8)
#define RXLPF15 (11<<8)
#define RXLPF1375 (12<<8)
#define RXLPF125 (13<<8)
#define RXLPF0875 (14<<8)
#define RXLPF075 (15<<8)
#define LNAMASK (3<<12)
#define LNADIS 0
#define LNA1ON (1<<12)
#define LNA2ON (2<<12)
#define LNA3ON (3<<12)
#define LNAGAINMASK (3<<14)
#define LNAByp (1<<14)
#define LNAMed (2<<14)
#define LNAMax (3<<14)
// RFBBMASK: enable different loopback modes for calibration and testing. Use RFBBNORM for normal operation
#define RFBBMASK (7<<16)
#define RFBBNORM 0
#define RFBBRXLPF (1<<16)
#define RFBBRXVGA (2<<16)
#define RFBBOUTPUT (3<<16)
#define RFBBLNA1 (4<<16)
#define RFBBLNA2 (5<<16)
#define RFBBLNA3 (6<<16)
#define RXLPFMODEMASK (3<<19)
#define RXLPFNORM 0
#define RXLPFBYP (1<<19)
#define RXLPFBPY2 (3<<19)
#define TXLPFMODEMASK (1<<21)
#define TXLPFNORM 0
#define TXLPFBYP (1<<21)
#define RXOUTSW (1<<22)
#define DMAMODE_TRXMASK (3<<23)
#define DMAMODE_RX (1<<23)
#define DMAMODE_TX (2<<23)
// register values and masks for rf_local
#define TXLOIMASK 63
#define TXLOQMASK (63<<6)
#define RXLOIMASK (63<<12)
#define RXLOQMASK (63<<18)
typedef struct {
uint32_t do_autocal[MAX_ANTENNAS];
uint32_t rf_freq_rx[MAX_ANTENNAS];
uint32_t rf_freq_tx[MAX_ANTENNAS];
// TX Gain [Chain0..3][0=LIME Gain, 1=currently ignored]
uint32_t tx_gain[MAX_ANTENNAS][2];
// RX Gain [Chain0..3][0=LIME Gain, 1=currently ignored]
uint32_t rx_gain[MAX_ANTENNAS][2];
//LIME RF modes
// 21 | 20:19 | 18:16 |15:14 | 13:12|11:8 | 7 |6:3 |2 |1 |0 |
// TXBYP | RXBYP | RF/BB |LNAMode| LNA |RXLPF|RXLPFen|TXLPF|TXLPFen|TXen|RXen|
uint32_t rf_mode[MAX_ANTENNAS];
// LIME LO Calibration Constants
// | RXLOQ | RXLOI | TXLOQ | TXLOI |
// | 23:18 | 17:12 | 11:6 | 5:0 |
uint32_t rf_local[MAX_ANTENNAS];
// LIME RX DC OFFSET
// | RXDCQ | RXDCI |
// | 15:8 | 7:0 |
uint32_t rf_rxdc[MAX_ANTENNAS];
// LIME VCO Calibration Constants
// | RXVCOCAP | TXVCOCAP |
// | 11:6 | 5:0 |
uint32_t rf_vcocal[MAX_ANTENNAS];
// External RF Frontend, as used on ExpressMIMO-2
uint32_t rffe_gain_txlow[MAX_ANTENNAS];
uint32_t rffe_gain_txhigh[MAX_ANTENNAS];
uint32_t rffe_gain_rxfinal[MAX_ANTENNAS];
uint32_t rffe_gain_rxlow[MAX_ANTENNAS];
uint32_t rffe_band_mode[MAX_ANTENNAS];
} exmimo_rf_t;
/*********************************************************
* Structure and flags for configuring Framing and Sync
* (struct exmimo_framing_t)
*/
//
// ** multicard synchronization mode (framing.multicard_syncmode)
//
// slave: take sync_newframe & sync_getframe from IO_SYNC header pin
// master: enable IO_SYNC header OUTPUT (do this only on a single card!) for sync_newframe & sync_getframe
#define SYNCMODE_FREE 0
#define SYNCMODE_MASTER 1
#define SYNCMODE_SLAVE 2
//
// ** register values and masks for tdd_config
//
// In TDD mode, there are two ways to control the RX/TX switch:
// 1. using the LSB from the TX data (TXRXSWITCH_LSB)
// only the LSB from RF chain set in the ACTIVE_RF register controls the switch on all the chains
// 2. using FPGA logic, based on switch_offset[0..3]
// this mode is not tested well and should be used with care
#define DUPLEXMODE_MASK (1<<0)
#define DUPLEXMODE_FDD 0
#define DUPLEXMODE_TDD (1<<0)
#define TXRXSWITCH_MASK (3<<1)
#define TXRXSWITCH_LSB 0
#define TXRXSWITCH_FPGA (1<<1)
#define TXRXSWITCH_TESTRX (2<<1)
#define TXRXSWITCH_TESTTX (3<<1)
#define SWITCHSTATE_MASK (1<<3)
#define SWITCHSTATE_0 0
#define SWITCHSTATE_1 (1<<3)
#define TEST_ADACLOOP_MASK (1<<4)
#define TEST_ADACLOOP_EN (1<<4)
#define RF_ACTIVE_MASK (15<<5)
#define RF_ACTIVE_1 (1<<5)
#define RF_ACTIVE_2 (2<<5)
#define RF_ACTIVE_3 (4<<5)
#define RF_ACTIVE_4 (8<<5)
typedef enum {
BW5,
BW10,
BW20
} exmimo_bw_t;
typedef struct {
uint32_t multicard_syncmode;
uint32_t eNB_flag;
uint32_t tdd_config;
uint32_t frame_length; // e.g. 76800
uint32_t frame_start; // e.g. 18
uint32_t adac_buffer_period; // e.g. 2048
uint32_t adac_intr_period; // e.g. 1024
uint32_t switch_offset[4]; // sample offsets (relative to start of frame) used to control the RX/TX switch in TDD mode
uint32_t resampling_factor[4]; // 0=>1, 1=>2, 2=>4, applied equally to each chain and TX/RX
} exmimo_framing_t;
typedef struct {
exmimo_rf_t rf;
exmimo_framing_t framing;
} exmimo_config_t;
/*****************************************
* Structures to pass pointers
* between Leon, Kernel and Userspace
*/
/*
* struct exmimo_pci_interface_bot_t:
* Main structure to exchange physical(DMA) pointers between kernel and Leon
*/
typedef struct {
uint32_t firmware_block_ptr;
uint32_t printk_buffer_ptr;
uint32_t exmimo_config_ptr;
uint32_t exmimo_id_ptr;
// rxcnt / txcnt: stores the current ring buffer position indicators (formerly mbox)
// - increment by one for every 512 samples (512 DW)
// - currently wraps at 150 (0..149) to cover 1 LTE frame in the buffer
// - in current sdr LEON code: only rxcnt_ptr[0] is used
uint32_t rxcnt_ptr[MAX_ANTENNAS]; // points to uint32_t RX ring buffer position for each antenna
uint32_t txcnt_ptr[MAX_ANTENNAS]; // points to uint32_t TX ring buffer position for each antenna
uint32_t adc_head[MAX_ANTENNAS]; // address of start of ADC (RX) buffer in PC memory
uint32_t dac_head[MAX_ANTENNAS]; // address of start of DAC (TX) buffer in PC memory
#ifdef NOINIT
uint32_t dummy[13]; // used only in simulation for Modelsim memcopy tests
#endif
} exmimo_pci_interface_bot_t;
/*
* Equivalent structure to exmimo_pci_interface_bot, which keeps type-specific virtual pointers
*/
typedef struct {
char *firmware_block_ptr;
char *printk_buffer_ptr;
exmimo_config_t *exmimo_config_ptr;
exmimo_id_t *exmimo_id_ptr;
uint32_t *rxcnt_ptr[MAX_ANTENNAS]; // points to uint32_t RX ring buffer position for each antenna
uint32_t *txcnt_ptr[MAX_ANTENNAS]; // points to uint32_t TX ring buffer position for each antenna
uint32_t *adc_head[MAX_ANTENNAS]; // address of start of ADC (RX) buffer in PC memory
uint32_t *dac_head[MAX_ANTENNAS]; // address of start of DAC (TX) buffer in PC memory
} exmimo_pci_interface_bot_virtual_t;
#endif
@@ -1,23 +0,0 @@
CCC = gcc
include $(OPENAIR_DIR)/common/utils/Makefile.inc
KERNEL_MAIN_TYPE:=$(shell echo `uname -r | cut -d. -f-2 | tr "." "_"`)
export KERNEL_MAIN_TYPE
EXTRA_CFLAGS = -ggdb -D__KERNEL__ -DMODULE -D_LOOSE_KERNEL_NAMES -I$(KERNEL_DIR)/build/include -I$(KERNEL_DIR)/build/include/asm/mach-default -include $(KERNEL_DIR)/build/include/linux/autoconf.h
EXTRA_CFLAGS += -I$(PWD)/../../DEFS
ccflags-y= $(CFLAGS) $(EXTRA_CFLAGS)
CFLAGS=
obj-m += openair_rf.o
openair_rf-objs += module_main.o irq.o fileops.o exmimo_fw.o
all:
make -C $(KERNEL_DIR)/build M=$(PWD) modules
clean:
rm -rf *.o
make -C $(KERNEL_DIR)/build M=$(PWD) clean
@@ -1,4 +0,0 @@
echo "Hint: this may not work if /usr/src/linux is not set to currently booted kernel."
echo "Try 'make' instead."
make -C /usr/src/linux V=1 M=`pwd`
-73
View File
@@ -1,73 +0,0 @@
/*
* 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
*/
#ifndef __DEFS_H__
#define __DEFS_H__
#include <asm/io.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
#include <asm/segment.h>
#include <asm/page.h>
#include <asm/delay.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/slab.h>
//#include <linux/config.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#ifdef KERNEL2_6
#include <linux/slab.h>
#endif
#include "openair_device.h"
#include "linux/moduleparam.h"
/*------------------------------------------------*/
/* Prototypes */
/*------------------------------------------------*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)
long openair_device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
#else
int openair_device_ioctl(struct inode *inode,struct file *filp, unsigned int cmd, unsigned long arg);
#endif
int openair_device_open (struct inode *inode,struct file *filp);
int openair_device_release (struct inode *inode,struct file *filp);
int openair_device_mmap (struct file *filp, struct vm_area_struct *vma);
int exmimo_memory_alloc(int card);
int exmimo_firmware_init(int card);
int exmimo_firmware_cleanup(int card_id);
int exmimo_send_pccmd(int card_id, unsigned int cmd);
#endif
@@ -1,20 +0,0 @@
#!/bin/sh
# Re-Enumerate FPGA card
# After resetting or powering up the card or after reloading the FPGA bitstream,
# run this script to re-enumerate the PCIe device in Linux.
# You may need to change the device path. Check lspci output for this.
# You need to run this as root:
# sudo ./do_reenumerate_expressmimo.sh
# Matthias <ihmig@eurecom.fr>, 2013
rmmod openair_rf
echo 1 > /sys/bus/pci/devices/0000\:01\:00.0/remove
echo 1 > /sys/bus/pci/devices/0000\:05\:00.0/remove
echo 1 > /sys/bus/pci/rescan
insmod openair_rf.ko
@@ -1 +0,0 @@
rmmod openair_rf && sleep 1 ; insmod openair_rf.ko
@@ -1,353 +0,0 @@
/*
* 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
*/
/** exmimo_fw.c
*
* Initialization routines for
* Shared Memory management for ExMIMO and PC(kernel) data exchange
* (memory allocation, pointer management)
*
* There is now one pci_alloc_consistent for each RX and TX buffer
* and one for all structures, including pointers, printk, firmware_dump and config
*
* Authors: Matthias Ihmig <matthias.ihmig@mytum.de>, 2012, 2013
* Riadh Ghaddab <riadh.ghaddab@eurecom.fr>
* Raymond Knopp <raymond.knopp@eurecom.fr>
*
* Changelog:
* 24.01.2013: added memory management functions for bigshm, lots of cleanups
*/
#include <linux/delay.h>
#include "extern.h"
#include "defs.h"
#include "pcie_interface.h"
/*****************************************************
* Private functions within this file
*/
void mem_SetPageReserved(void *kvirt_addr, unsigned int size_pages)
{
size_t temp_size = size_pages << PAGE_SHIFT;
void *adr = kvirt_addr;
while (temp_size > 0) {
SetPageReserved( virt_to_page(adr) );
adr += PAGE_SIZE;
temp_size -= PAGE_SIZE;
}
}
void mem_ClearPageReserved(void *kvirt_addr, unsigned int size_pages)
{
size_t temp_size = size_pages << PAGE_SHIFT;
void *adr = kvirt_addr;
while (temp_size > 0) {
ClearPageReserved( virt_to_page(adr) );
adr += PAGE_SIZE;
temp_size -= PAGE_SIZE;
}
}
// allocates big shared memory, to be used for structures, pointers, etc.
// bigshm allocs a single larger memory block for shared structures and pointers, one per card, except: ADC+DAC buffers!
// returns -1 on error, 0 on success
int bigshm_init(int card)
{
printk("[openair][module] calling pci_alloc_consistent for card %d, bigshm (size: %lu*%lu bytes)...\n", card, BIGSHM_SIZE_PAGES, PAGE_SIZE);
if ( sizeof(dma_addr_t) != 4)
printk("!!! WARNING: sizeof (dma_addr_t) = %lu! Only 32bit mode (= 4) (also: no PAE) is supported at this time!\n", sizeof(dma_addr_t));
if ( bigshm_head[card] == NULL )
bigshm_head[card] = pci_alloc_consistent( pdev[card], BIGSHM_SIZE_PAGES<<PAGE_SHIFT, &bigshm_head_phys[card] );
if (bigshm_head[card] == NULL) {
printk("[openair][MODULE][ERROR] Cannot Allocate Memory (%lu bytes) for shared data (bigshm)\n", BIGSHM_SIZE_PAGES<<PAGE_SHIFT);
return -ENOMEM;
} else {
printk("[openair][MODULE][INFO] Bigshm at %p (phys %x)\n", bigshm_head[card], (unsigned int) bigshm_head_phys[card]);
bigshm_currentptr[card] = bigshm_head[card];
mem_SetPageReserved( bigshm_head[card], BIGSHM_SIZE_PAGES);
memset(bigshm_head[card], 0, BIGSHM_SIZE_PAGES << PAGE_SHIFT);
}
return 0;
}
// use this instead of pci_alloc_consistent to assign memory from the bigshm block
// return kernel virtual pointer and sets physical DMA address in dma_handle
void *bigshm_assign( int card, size_t size_bytes, dma_addr_t *dma_handle_ptr )
{
void *ret;
size_t size = size_bytes;
//size = (size-1) + 4 - ( (size-1) % 4); // round up to keep addresses aligned to DWs
//size = (size-1) + 16 - ( (size-1) % 16); // round up to keep addresses aligned to 4 DWs
// round up to the next 64 DW (workaround for current bug in DMA on ExMIMO2)
size = (size-1) + 256 - ( (size-1) % 256);
if ( (bigshm_currentptr[card] - bigshm_head[card]) > (BIGSHM_SIZE_PAGES<<PAGE_SHIFT) -size ) {
printk("Not enough memory in bigshm! Make BIGSHM_SIZE_PAGES bigger!\n");
return NULL;
}
*dma_handle_ptr = bigshm_head_phys[card] + ( (dma_addr_t)bigshm_currentptr[card] - (dma_addr_t)bigshm_head[card] );
ret = bigshm_currentptr[card];
bigshm_currentptr[card] = (char *)bigshm_currentptr[card] + size;
//printk("bigshm_assign: size %d, virt = %p, dma = %x, bigshm_phys=%x, _current=%p, _head=%p\n",
// size, ret, *dma_handle_ptr, bigshm_head_phys[card], bigshm_currentptr[card], bigshm_head[card]);
return ret;
}
// assign shared memory between card an PC for data exchange: interface structure with pointers,
// firmware- and printk buffers, configuration structure
// returns -1 on error, 0 on success
int exmimo_assign_shm_vars(int card_id)
{
int j;
if (p_exmimo_pci_phys[card_id] == NULL) {
p_exmimo_pci_phys[card_id] = (exmimo_pci_interface_bot_t *) bigshm_assign( card_id,
sizeof(exmimo_pci_interface_bot_t),
&pphys_exmimo_pci_phys[card_id]);
printk("Intializing EXMIMO interface support (exmimo_pci_bot at %p, phys %x, size %lu bytes)\n",p_exmimo_pci_phys[card_id],(unsigned int)pphys_exmimo_pci_phys[card_id],
sizeof(exmimo_pci_interface_bot_t));
exmimo_pci_kvirt[card_id].firmware_block_ptr = (char *) bigshm_assign( card_id,
MAX_FIRMWARE_BLOCK_SIZE_B,
(dma_addr_t*)&(p_exmimo_pci_phys[card_id]->firmware_block_ptr));
printk("firmware_code_block_ptr : %p (phys = %08x)\n", exmimo_pci_kvirt[card_id].firmware_block_ptr, p_exmimo_pci_phys[card_id]->firmware_block_ptr);
exmimo_pci_kvirt[card_id].printk_buffer_ptr = (char *) bigshm_assign( card_id,
MAX_PRINTK_BUFFER_B,
(dma_addr_t*)&(p_exmimo_pci_phys[card_id]->printk_buffer_ptr));
printk("printk_buffer_ptr : %p (phys = %08x)\n", exmimo_pci_kvirt[card_id].printk_buffer_ptr, p_exmimo_pci_phys[card_id]->printk_buffer_ptr);
exmimo_pci_kvirt[card_id].exmimo_config_ptr = (exmimo_config_t *) bigshm_assign( card_id,
sizeof(exmimo_config_t),
(dma_addr_t*)&(p_exmimo_pci_phys[card_id]->exmimo_config_ptr));
printk("exmimo_config_ptr : %p (phys = %08x)\n", exmimo_pci_kvirt[card_id].exmimo_config_ptr, p_exmimo_pci_phys[card_id]->exmimo_config_ptr);
exmimo_pci_kvirt[card_id].exmimo_id_ptr = (exmimo_id_t *) bigshm_assign( card_id,
sizeof(exmimo_id_t),
(dma_addr_t*)&(p_exmimo_pci_phys[card_id]->exmimo_id_ptr));
printk("exmimo_id_ptr : %p (phys = %08x)\n", exmimo_pci_kvirt[card_id].exmimo_id_ptr, p_exmimo_pci_phys[card_id]->exmimo_id_ptr);
if ( p_exmimo_pci_phys[card_id] == NULL || exmimo_pci_kvirt[card_id].firmware_block_ptr == NULL
|| exmimo_pci_kvirt[card_id].printk_buffer_ptr == NULL || exmimo_pci_kvirt[card_id].exmimo_config_ptr == NULL
|| exmimo_pci_kvirt[card_id].exmimo_id_ptr == NULL )
return -1;
for (j=0; j<MAX_ANTENNAS; j++) {
// size 4*1 should be sufficient, but just to make sure we can also use DMA of size 4DW as fallback
exmimo_pci_kvirt[card_id].rxcnt_ptr[j] = (uint32_t *) bigshm_assign( card_id, 4*4,
(dma_addr_t*)&(p_exmimo_pci_phys[card_id]->rxcnt_ptr[j]) );
printk("exmimo_pci_kvirt[%d].rxcnt_ptr[%d] = %p (phys = %08x)\n", card_id, j, exmimo_pci_kvirt[card_id].rxcnt_ptr[j], p_exmimo_pci_phys[card_id]->rxcnt_ptr[j]);
exmimo_pci_kvirt[card_id].txcnt_ptr[j] = (uint32_t *) bigshm_assign( card_id, 4*4,
(dma_addr_t*)&(p_exmimo_pci_phys[card_id]->txcnt_ptr[j]) );
printk("exmimo_pci_kvirt[%d].txcnt_ptr[%d] = %p (phys = %08x)\n", card_id, j, exmimo_pci_kvirt[card_id].txcnt_ptr[j], p_exmimo_pci_phys[card_id]->txcnt_ptr[j]);
if ( exmimo_pci_kvirt[card_id].rxcnt_ptr[j] == NULL || exmimo_pci_kvirt[card_id].txcnt_ptr[j] == NULL)
return -1;
}
}
return 0;
}
// allocate memory for RX and TX chains for all antennas
// returns -1 on error, 0 on success
int exmimo_allocate_rx_tx_buffers(int card_id)
{
size_t size;
int j;
dma_addr_t dma_addr_dummy;
// Round up to the next PAGE_SIZE (typ. 4096 bytes)
size = (ADAC_BUFFERSZ_PERCHAN_B >> PAGE_SHIFT) + 1;
size <<= PAGE_SHIFT;
for (j=0; j<MAX_ANTENNAS; j++) {
exmimo_pci_kvirt[card_id].adc_head[j] = (uint32_t *)pci_alloc_consistent( pdev[card_id], size, &dma_addr_dummy);
p_exmimo_pci_phys[card_id]->adc_head[j]=((uint32_t*)&dma_addr_dummy)[0];
printk("exmimo_pci_kvirt[%d].adc_head[%d] = %p (phys = %08x)\n", card_id, j, exmimo_pci_kvirt[card_id].adc_head[j], p_exmimo_pci_phys[card_id]->adc_head[j]);
if ( exmimo_pci_kvirt[card_id].adc_head[j] == NULL)
return -1;
// printk("[MODULE MAIN0]Phys address TX[0] : (%8lx)\n",p_exmimo_pci_phys[0]->dac_head[ openair_mmap_getAntTX(2) ]);
mem_SetPageReserved( exmimo_pci_kvirt[card_id].adc_head[j], size >> PAGE_SHIFT );
memset( exmimo_pci_kvirt[card_id].adc_head[j], 0x10+j, size);
// printk("[MODULE MAIN1]Phys address TX[0] : (%8lx)\n",p_exmimo_pci_phys[0]->dac_head[ openair_mmap_getAntTX(2) ]);
exmimo_pci_kvirt[card_id].dac_head[j] = (uint32_t *)pci_alloc_consistent( pdev[card_id], size,&dma_addr_dummy);
p_exmimo_pci_phys[card_id]->dac_head[j]=((uint32_t*)&dma_addr_dummy)[0];
// printk("exmimo_pci_kvirt[%d].dac_head[%d] = %p (phys = %08x)\n", card_id, j, exmimo_pci_kvirt[card_id].dac_head[j], p_exmimo_pci_phys[card_id]->dac_head[j]);
if ( exmimo_pci_kvirt[card_id].dac_head[j] == NULL)
return -ENOMEM;
// printk("[MODULE MAIN2]Phys address TX[0] : (%8lx)\n",p_exmimo_pci_phys[0]->dac_head[ openair_mmap_getAntTX(2) ]);
mem_SetPageReserved( exmimo_pci_kvirt[card_id].dac_head[j], size >> PAGE_SHIFT );
memset( exmimo_pci_kvirt[card_id].dac_head[j], 0x20+j, size);
// printk("[MODULE MAIN3]Phys address TX[0] : (%8lx)\n",p_exmimo_pci_phys[0]->dac_head[ openair_mmap_getAntTX(2) ]);
}
return 0;
}
/*********************************************
* Public functions ExpressMIMO Interface
*/
/* Allocates buffer and assigns pointers
*
* return 0 on success
*/
int exmimo_memory_alloc(int card)
{
if ( bigshm_init( card ) ) {
printk("exmimo_memory_alloc(): bigshm_init failed for card %d.\n", card);
return -ENOMEM;
}
if ( exmimo_assign_shm_vars( card ) ) {
printk("exmimo_memory_alloc(): exmimo_assign_shm_vars failed to assign enough shared memory for all variables and structures for card %i!\n", card);
return -ENOMEM;
}
if ( exmimo_allocate_rx_tx_buffers( card ) ) {
printk("exmimo_memory_alloc(): exmimo_allocate_rx_tx_buffers() failed to allocate enough memory for RX and TX buffers for card %i!\n", card);
return -ENOMEM;
}
return 0;
}
/*
* Copies pointer to Leon
*/
int exmimo_firmware_init(int card)
{
/* pci_dma_sync_single_for_device(pdev[card],
pphys_exmimo_pci_phys[card],
sizeof(exmimo_pci_interface_bot_t),
PCI_DMA_TODEVICE); */
// put DMA pointer to exmimo_pci_interface_bot into LEON register
iowrite32( pphys_exmimo_pci_phys[card], (bar[card]+PCIE_PCIBASEL) ); // lower 32bit of address
iowrite32( 0, (bar[card]+PCIE_PCIBASEH) ); // higher 32bit of address
if (exmimo_pci_kvirt[card].exmimo_id_ptr->board_swrev == BOARD_SWREV_CMDREGISTERS)
iowrite32( EXMIMO_CONTROL2_COOKIE, bar[card]+ PCIE_CONTROL2);
//printk("exmimo_firmware_init(): initializing Leon (EXMIMO_PCIE_INIT)...\n");
exmimo_send_pccmd(card, EXMIMO_PCIE_INIT);
return 0;
}
/*
* Free memory on unloading the kernel driver
*/
int exmimo_firmware_cleanup(int card)
{
size_t size;
int j;
// free exmimo_allocate_rx_tx_buffers
size = (ADAC_BUFFERSZ_PERCHAN_B >> PAGE_SHIFT) + 1;
size <<= PAGE_SHIFT;
for (j=0; j<MAX_ANTENNAS; j++) {
if ( exmimo_pci_kvirt[card].adc_head[j] ) {
mem_ClearPageReserved( exmimo_pci_kvirt[card].adc_head[j], size >> PAGE_SHIFT );
pci_free_consistent( pdev[card], size, exmimo_pci_kvirt[card].adc_head[j], p_exmimo_pci_phys[card]->adc_head[j] );
}
if ( exmimo_pci_kvirt[card].dac_head[j] ) {
mem_ClearPageReserved( exmimo_pci_kvirt[card].dac_head[j], size >> PAGE_SHIFT );
pci_free_consistent( pdev[card], size, exmimo_pci_kvirt[card].dac_head[j], p_exmimo_pci_phys[card]->dac_head[j] );
}
}
if ( bigshm_head[card] ) {
printk("free bigshm_head[%d] pdev %p, size %lu, head %p, phys %x\n", card, pdev[card], BIGSHM_SIZE_PAGES<<PAGE_SHIFT, bigshm_head[card], (unsigned int)bigshm_head_phys[card]);
mem_ClearPageReserved( bigshm_head[card], BIGSHM_SIZE_PAGES );
pci_free_consistent( pdev[card], BIGSHM_SIZE_PAGES<<PAGE_SHIFT, bigshm_head[card], bigshm_head_phys[card]);
}
return 0;
}
/*
* Send command to Leon and wait until command is completed
*/
int exmimo_send_pccmd(int card_id, unsigned int cmd)
{
unsigned int val;
unsigned int cnt=0;
//printk("Sending command to ExpressMIMO (card %d) : %x\n",card_id, cmd);
iowrite32(cmd,(bar[card_id]+PCIE_CONTROL1));
// printk("Readback of control1 %x\n",ioread32(bar[0]+PCIE_CONTROL1));
val = ioread32(bar[card_id]+PCIE_CONTROL0); // this is only necessary for ExMIMO1. ExMIMO2 will not overwrite any bits in CONTROL0 whenever bit0 is set.
// set interrupt bit to trigger LEON interrupt
iowrite32(val|0x1,bar[card_id]+PCIE_CONTROL0);
// printk("Readback of control0 %x\n",ioread32(bar[0]+PCIE_CONTROL0));
// workaround for ExMIMO1: no command ack -> sleep
while (cnt<100 && ( ioread32(bar[card_id]+PCIE_CONTROL1) != EXMIMO_NOP )) {
//printk("ctrl0: %08x, ctrl1: %08x, ctrl2: %08x, status: %08x\n", ioread32(bar[card_id]+PCIE_CONTROL0), ioread32(bar[card_id]+PCIE_CONTROL1), ioread32(bar[card_id]+PCIE_CONTROL2), ioread32(bar[card_id]+PCIE_STATUS));
msleep(100);
cnt++;
}
if (cnt==100)
printk("exmimo_send_pccmd error: Timeout: no EXMIMO_NOP received within 10sec for card%d, pccmd=%x\n", card_id, cmd);
//printk("Ctrl0: %08x, ctrl1: %08x, ctrl2: %08x, status: %08x\n", ioread32(bar[card_id]+PCIE_CONTROL0), ioread32(bar[card_id]+PCIE_CONTROL1), ioread32(bar[card_id]+PCIE_CONTROL2), ioread32(bar[card_id]+PCIE_STATUS));
return(0);
}
@@ -1,51 +0,0 @@
/*
* 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
*/
#ifndef __EXTERN_H__
#define __EXTERN_H__
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci.h>
#ifdef KERNEL2_6
#include <linux/slab.h>
#endif
#include "defs.h"
#include "pcie_interface.h"
extern char number_of_cards;
extern int major;
extern struct pci_dev *pdev[MAX_CARDS];
extern void __iomem *bar[MAX_CARDS];
extern void *bigshm_head[MAX_CARDS];
extern void *bigshm_currentptr[MAX_CARDS];
extern dma_addr_t bigshm_head_phys[MAX_CARDS];
extern dma_addr_t pphys_exmimo_pci_phys[MAX_CARDS];
extern exmimo_pci_interface_bot_t *p_exmimo_pci_phys[MAX_CARDS];
extern exmimo_pci_interface_bot_virtual_t exmimo_pci_kvirt[MAX_CARDS];
#endif // __EXTERN_H__
@@ -1,488 +0,0 @@
/*
* 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
*/
/** fileops.c
*
* Device IOCTL File Operations on character device /dev/openair0
*
* Authors: Matthias Ihmig <matthias.ihmig@mytum.de>, 2012, 2013
* Riadh Ghaddab <riadh.ghaddab@eurecom.fr>
* Raymond Knopp <raymond.knopp@eurecom.fr>
*
* Changelog:
* 14.01.2013: removed remaining of BIGPHYS stuff and replaced with pci_alloc_consistent
*/
#include <linux/delay.h>
#include "openair_device.h"
#include "defs.h"
#include "extern.h"
#include "pcie_interface.h"
#define invert4(x) { \
unsigned int ltmp; \
ltmp=x; x=((ltmp & 0xff)<<24) | ((ltmp & 0xff00)<<8) | \
((ltmp & 0xff0000)>>8) | ((ltmp & 0xff000000)>>24); \
}
extern int get_frame_done;
int is_card_num_invalid(int card)
{
if (card<0 || card>=number_of_cards) {
printk("[openair][IOCTL]: ERROR: received invalid card number (%d)!\n", card);
return -1;
} else
return 0;
}
//-----------------------------------------------------------------------------
int openair_device_open (struct inode *inode,struct file *filp)
{
//printk("[openair][MODULE] openair_open()\n");
return 0;
}
//-----------------------------------------------------------------------------
int openair_device_release (struct inode *inode,struct file *filp)
{
// printk("[openair][MODULE] openair_release(), MODE = %d\n",openair_daq_vars.mode);
return 0;
}
//-----------------------------------------------------------------------------
int openair_device_mmap(struct file *filp, struct vm_area_struct *vma)
{
unsigned long phys;
unsigned long start = (unsigned long)vma->vm_start;
unsigned long size = (unsigned long)(vma->vm_end-vma->vm_start);
unsigned long maxsize;
unsigned int memblock_ind;
unsigned int card;
memblock_ind = openair_mmap_getMemBlock( vma->vm_pgoff );
card = openair_mmap_getCard( vma->vm_pgoff );
/*printk("[openair][MMAP] called (start %lx, end %lx, pg_off %lx, size %lx)\n",
vma->vm_start,
vma->vm_end,
vma->vm_pgoff,
size);
*/
vma->vm_pgoff = 0;
// not supported by 64 bit kernels
//vma->vm_flags |= VM_RESERVED;
vma->vm_flags |= VM_IO;
if ( is_card_num_invalid(card) )
return -EINVAL;
if (memblock_ind == openair_mmap_BIGSHM) {
// map a buffer from bigshm
maxsize = BIGSHM_SIZE_PAGES<<PAGE_SHIFT;
if ( size > maxsize) {
printk("[openair][MMAP][ERROR] Trying to map more than %d bytes (req size=%d)\n",
(unsigned int)(BIGSHM_SIZE_PAGES<<PAGE_SHIFT), (unsigned int)size);
return -EINVAL;
}
phys = bigshm_head_phys[card];
} else if ( (memblock_ind & 1) == 1) {
// mmap a RX buffer
maxsize = ADAC_BUFFERSZ_PERCHAN_B;
if ( size > maxsize) {
printk("[openair][MMAP][ERROR] Trying to map more than %d bytes (req size=%d)\n",
(unsigned int)(ADAC_BUFFERSZ_PERCHAN_B), (unsigned int)size);
return -EINVAL;
}
phys = p_exmimo_pci_phys[card]->adc_head[ openair_mmap_getAntRX(memblock_ind) ];
} else {
// mmap a TX buffer
maxsize = ADAC_BUFFERSZ_PERCHAN_B;
if ( size > maxsize) {
printk("[openair][MMAP][ERROR] Trying to map more than %d bytes (%d)\n",
(unsigned int)(ADAC_BUFFERSZ_PERCHAN_B), (unsigned int)size);
return -EINVAL;
}
phys = p_exmimo_pci_phys[card]->dac_head[ openair_mmap_getAntTX(memblock_ind) ];
}
if (0)
printk("[openair][MMAP] card%d: map phys (%08lx) at start %lx, end %lx, pg_off %lx, size %lx\n",
card,
phys,
vma->vm_start,
vma->vm_end,
vma->vm_pgoff,
size);
/* loop through all the physical pages in the buffer */
/* Remember this won't work for vmalloc()d memory ! */
if (remap_pfn_range(vma,
start,
phys>>PAGE_SHIFT,
vma->vm_end-vma->vm_start,
vma->vm_page_prot)) {
printk("[openair][MMAP] ERROR EAGAIN\n");
return -EAGAIN;
}
return 0;
}
//-----------------------------------------------------------------------------
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)
long openair_device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
#else
int openair_device_ioctl(struct inode *inode,struct file *filp, unsigned int cmd, unsigned long arg)
#endif
{
/* arg is not meaningful if no arg is passed in user space */
//-----------------------------------------------------------------------------
int i, c;
int tmp;
unsigned int user_args[4];
static unsigned int update_firmware_command;
static unsigned int update_firmware_address;
static unsigned int update_firmware_length;
static unsigned int* update_firmware_kbuffer;
static unsigned int* __user update_firmware_ubuffer;
static unsigned int update_firmware_start_address;
static unsigned int update_firmware_stack_pointer;
static unsigned int update_firmware_bss_address;
static unsigned int update_firmware_bss_size;
unsigned int *fw_block;
unsigned int sparc_tmp_0;
unsigned int sparc_tmp_1;
static unsigned int lendian_length;
unsigned int get_frame_cnt=0;
switch(cmd) {
case openair_STOP:
printk("[openair][IOCTL] openair_STOP(card%d)\n", (int)arg);
if ( is_card_num_invalid((int)arg) )
return -EINVAL;
exmimo_send_pccmd((int)arg, EXMIMO_STOP);
break;
case openair_STOP_WITHOUT_RESET:
printk("[openair][IOCTL] openair_STOP_WITHOUT_RESET(card%d)\n", (int)arg);
if ( is_card_num_invalid((int)arg) )
return -EINVAL;
exmimo_send_pccmd((int)arg, EXMIMO_STOP_WITHOUT_RESET);
break;
case openair_GET_FRAME:
get_frame_cnt=0;
get_frame_done = 0;
printk("[openair][IOCTL] : openair_GET_FRAME: calling exmimo_send_pccmd(%d, EXMIMO_GET_FRAME)\n", (int)arg);
if ( is_card_num_invalid((int)arg) )
return -EINVAL;
exmimo_send_pccmd((int)arg, EXMIMO_GET_FRAME);
while (get_frame_cnt<10 && !get_frame_done) {
msleep(10);
get_frame_cnt++;
}
if (get_frame_cnt==200)
printk("[openair][IOCTL] : Get frame error: no IRQ received within 2000ms.\n");
get_frame_done = 0;
break;
case openair_GET_BIGSHMTOPS_KVIRT:
//printk("[openair][IOCTL] : openair_GET_BIGSHMTOPS_KVIRT (0x%p)[0] = %p[0] (bigshm_head) for 0..3 (sizeof %d) \n", (void *)arg, bigshm_head[0], sizeof(bigshm_head));
copy_to_user((void *)arg, bigshm_head, sizeof(bigshm_head));
break;
case openair_GET_PCI_INTERFACE_BOTS_KVIRT:
//printk("[openair][IOCTL] : openair_GET_PCI_INTERFACE_BOTS_KVIRT: copying exmimo_pci_kvirt(@%8p) to %lx (sizeof %d)\n", &exmimo_pci_kvirt[0], arg, sizeof(exmimo_pci_kvirt));
copy_to_user((void *)arg, exmimo_pci_kvirt, sizeof(exmimo_pci_kvirt));
break;
case openair_GET_NUM_DETECTED_CARDS:
//printk("[openair][IOCTL] : openair_GET_NUM_DETECTED_CARDS: *(0x%p) = %d\n", (void *)arg, number_of_cards);
copy_to_user((void *)arg, &number_of_cards, sizeof(number_of_cards));
break;
case openair_DUMP_CONFIG:
//printk("[openair][IOCTL] openair_DUMP_CONFIG(%d)\n", (int)arg);
if ( is_card_num_invalid((int)arg) ) {
printk("[openair][IOCTL] openair_DUMP_CONFIG: Invalid card number %d.\n", (int)arg);
return -EINVAL;
}
printk("[openair][IOCTL] : openair_DUMP_CONFIG(%d): exmimo_pci_kvirt[%d].exmimo_config_ptr = %p (phys %08x)\n",
(int)arg, (int)arg, exmimo_pci_kvirt[(int)arg].exmimo_config_ptr, p_exmimo_pci_phys[(int)arg]->exmimo_config_ptr);
printk("[openair][IOCTL]: EXMIMO_CONFIG: freq0 %u Hz, freq1 %u Hz, freqtx0 %u Hz, freqtx1 %u Hz, \nRX gain0 %d dB, RX Gain1 %d dB, autocal (%d,%d,%d,%d)\n",
exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.rf_freq_rx[0],
exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.rf_freq_rx[1],
exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.rf_freq_tx[0],
exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.rf_freq_tx[1],
exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.rx_gain[0][0],
exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.rx_gain[1][0],
exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.do_autocal[0],
exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.do_autocal[1],
exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.do_autocal[2],
exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.do_autocal[3]);
exmimo_send_pccmd((int)arg, EXMIMO_CONFIG);
break;
case openair_START_RT_ACQUISITION:
printk("[openair][IOCTL] openair_START_TX_SIG(%d): send_pccmd(EXMIMO_START_RT_ACQUISITION).\n", (int) arg);
if ( is_card_num_invalid((int)arg) )
return -EINVAL;
exmimo_send_pccmd((int)arg, EXMIMO_START_RT_ACQUISITION);
break;
case openair_UPDATE_FIRMWARE:
printk("[openair][IOCTL] openair_UPDATE_FIRMWARE\n");
/***************************************************
* Updating the firmware of Cardbus-MIMO-1 or ExpressMIMO SoC *
***************************************************/
/* 1st argument of this ioctl indicates the action to perform among these:
- Transfer a block of data at a specified address (given as the 2nd argument)
and for a specified length (given as the 3rd argument, in number of 32-bit words).
The USER-SPACE address where to find the block of data is given as the 4th
argument.
- Ask the Leon processor to clear the .bss section. In this case, the base
address of section .bss is given as the 2nd argument, and its size is
given as the 3rd one.
- Ask the Leon processor to jump at a specified address (given as the 2nd
argument, most oftenly expected to be the top address of Ins, Scratch Pad
Ram), after having set the stack pointer (given as the 3rd argument).
For the openair_UPDATE_FIRMWARE ioctl, we perform a partial infinite loop
while acknowledging the PCI irq from Leon software: the max number of loop
is yielded by preprocessor constant MAX_IOCTL_ACK_CNT. This avoids handing
the kernel with an infinite polling loop. An exception is the case of clearing
the bss: it takes time to Leon3 to perform this operation, so we poll te
acknowledge with no limit */
#define MAX_IOCTL_ACK_CNT 500
/* 'arg' is an unsigned long and is supposed to be big enough
* to hold an address - this hypothesis is okay for i386 and x86_64
* maybe not somewhere else
* this will probably fail with older kernels
* (works with 3.17 on x86_64)
*/
tmp = copy_from_user(&user_args, (void*)arg, 4*sizeof(unsigned int));
if (tmp) {
printk("[openair][IOCTL] UPDATE_FIRMWARE: error copying parameters to kernel-space (%d bytes uncopied).\n", tmp);
return -1;
}
update_firmware_command = user_args[0];
switch (update_firmware_command) {
case UPDATE_FIRMWARE_TRANSFER_BLOCK:
update_firmware_address = user_args[1];
update_firmware_length = user_args[2];
/* This is totally wrong on x86_64: a pointer is 64 bits and
* unsigned int is 32 bits. The userspace program has to ensure
* that its buffer address fits into 32 bits.
* If it proves a too strong requirement, we may change things
* in the future.
* The compiler emits a warning here. Do not remove this warning!
* This is to clearly remember this problem.
* If you require the compilation to work with zero warning,
* consider this one as an exception and find a proper workaround.
*/
update_firmware_ubuffer = user_args[3];
update_firmware_kbuffer = (unsigned int*)kmalloc(update_firmware_length * 4 /* 4 because kmalloc expects bytes */,
GFP_KERNEL);
if (!update_firmware_kbuffer) {
printk("[openair][IOCTL] Could NOT allocate %u bytes from kernel memory (kmalloc failed).\n", lendian_length * 4);
return -1;
break;
}
// update all cards at the same time
for (c=0; c<number_of_cards; c++) {
fw_block = (unsigned int *)exmimo_pci_kvirt[c].firmware_block_ptr;
/* Copy the data block from user space */
fw_block[0] = update_firmware_address;
fw_block[1] = update_firmware_length;
//printk("copy_from_user %p => %p (pci) => fw[0]=fw_addr=%08x (ahb), fw[1]=fw_length=%d DW\n",update_firmware_ubuffer,&fw_block[16],update_firmware_address,update_firmware_length);
tmp = copy_from_user(update_firmware_kbuffer,
update_firmware_ubuffer, /* from */
update_firmware_length * 4 /* in bytes */
);
if (tmp) {
printk("[openair][IOCTL] Could NOT copy all data from user-space to kernel-space (%d bytes remained uncopied).\n", tmp);
return -1;
}
// pci_map_single(pdev[0],(void*)fw_block, update_firmware_length*4,PCI_DMA_BIDIRECTIONAL);
for (i=0; i<update_firmware_length; i++) {
fw_block[32+i] = ((unsigned int *)update_firmware_kbuffer)[i];
// Endian flipping is done in user-space so undo it
invert4(fw_block[32+i]);
}
exmimo_send_pccmd(c, EXMIMO_FW_INIT);
printk("[openair][IOCTL] card%d: ok %u DW copied to address 0x%08x (fw_block_ptr %p)\n",
c, fw_block[1], fw_block[0],fw_block);
}
kfree(update_firmware_kbuffer);
/*
for (i=0; i<update_firmware_length;i++) {
printk("%08x ", fw_block[32+i]);
if ((i % 8) == 7)
printk("\n");
}*/
break;
case UPDATE_FIRMWARE_CLEAR_BSS:
update_firmware_bss_address = user_args[1];
update_firmware_bss_size = user_args[2];
sparc_tmp_0 = update_firmware_bss_address;
sparc_tmp_1 = update_firmware_bss_size;
printk("[openair][IOCTL] ok asked Leon to clear .bss (addr 0x%08x, size %d bytes)\n", sparc_tmp_0, sparc_tmp_1);
// update all cards at the same time
for (c=0; c<number_of_cards; c++) {
fw_block = (unsigned int *)exmimo_pci_kvirt[c].firmware_block_ptr;
fw_block[0] = update_firmware_bss_address;
fw_block[1] = update_firmware_bss_size;
exmimo_send_pccmd(c, EXMIMO_FW_CLEAR_BSS);
}
break;
case UPDATE_FIRMWARE_START_EXECUTION:
update_firmware_start_address = user_args[1];
update_firmware_stack_pointer = user_args[2];
sparc_tmp_0 = update_firmware_start_address;
sparc_tmp_1 = update_firmware_stack_pointer;
printk("[openair][IOCTL] ok asked Leon to set stack and start execution (addr 0x%08x, stackptr %08x)\n", sparc_tmp_0, sparc_tmp_1);
for (c=0; c<number_of_cards; c++) {
fw_block = (unsigned int *)exmimo_pci_kvirt[c].firmware_block_ptr;
fw_block[0] = update_firmware_start_address;
fw_block[1] = update_firmware_stack_pointer;
exmimo_send_pccmd(c, EXMIMO_FW_START_EXEC);
msleep(10);
exmimo_firmware_init(c);
}
break;
case UPDATE_FIRMWARE_FORCE_REBOOT:
printk("[openair][IOCTL] ok asked Leon to reboot.\n");
for (c=0; c<number_of_cards; c++) {
exmimo_send_pccmd(c, EXMIMO_REBOOT);
exmimo_firmware_init(c);
}
break;
case UPDATE_FIRMWARE_TEST_GOK:
printk("[openair][IOCTL] TEST_GOK command doesn't work with ExpressMIMO. Ignored.\n");
break;
default:
return -1;
break;
}
break;
default:
//----------------------
printk("[IOCTL] openair_IOCTL unknown: basecmd = %i (cmd=%X)\n", _IOC_NR(cmd), cmd );
return -EPERM;
break;
}
return 0;
}
-185
View File
@@ -1,185 +0,0 @@
/*
* 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
*/
/** irq.c
- IRQ Handler: IRQ from Leon to PCIe/Kernel: exmimo_irq_handler
- sends received packets to userspace
- send command from PC to Leon and trigger IRQ on Leon using CONTROL1 register
- commands are defined in $OPENAIR0/express-mimo/software/pcie_interface.h
- added: pass card_id as parameter to tasklet and irq handler
Authors:
Raymond Knopp <raymond.knopp@eurecom.fr>
Matthias Ihmig <matthias.ihmig@mytum.de>, 2011, 2013
*/
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/swab.h>
#include "openair_device.h"
#include "extern.h"
unsigned int openair_bh_cnt;
int get_frame_done = 0;
void pcie_printk(int card_id);
void openair_do_tasklet (unsigned long card_id);
DECLARE_TASKLET (openair_tasklet, openair_do_tasklet, 0);
irqreturn_t openair_irq_handler(int irq, void *cookie)
{
unsigned int irqval;
unsigned int irqcmd = EXMIMO_NOP;
unsigned long card_id; // = (unsigned long) cookie;
unsigned int pcie_control = PCIE_CONTROL2;
// check interrupt status register
//pci_read_config_word(pdev[0],6 , &irqval);
// find card_id. cookie is set by request_irq and static, so we will always find it
for (card_id=0; card_id<MAX_CARDS; card_id++)
if ( pdev[card_id] == cookie )
break;
if (exmimo_pci_kvirt[card_id].exmimo_id_ptr->board_swrev == BOARD_SWREV_LEGACY)
pcie_control = PCIE_CONTROL1;
else
pcie_control = PCIE_CONTROL2;
//printk("irq hndl called: card_id=%i, irqval=%i\n", card_id, irqval);
// get AHBPCIE interrupt line (bit 7) to determine if IRQ was for us from ExMIMO card, or from a different device
// reading CONTROL0 will also clear this bit and the LEON-to-PC IRQ line
irqval = ioread32(bar[card_id]+PCIE_CONTROL0);
irqcmd = ioread32(bar[card_id]+pcie_control);
//printk("IRQ handler: ctrl0: %08x, ctrl1: %08x, ctrl2: %08x, status: %08x\n", irqval, ioread32(bar[card_id]+PCIE_CONTROL1), ioread32(bar[card_id]+PCIE_CONTROL2), ioread32(bar[card_id]+PCIE_STATUS));
if ( (irqval & 0x80) == 0 ) { // CTRL0.bit7 is no set -> IRQ is not from ExMIMO i.e. not for us
if (exmimo_pci_kvirt[card_id].exmimo_id_ptr->board_swrev == BOARD_SWREV_CMDREGISTERS) {
if (irqcmd != EXMIMO_NOP && irqcmd != EXMIMO_CONTROL2_COOKIE) {
if (irqcmd == GET_FRAME_DONE) {
get_frame_done = 1;
}
openair_tasklet.data = card_id;
tasklet_schedule(&openair_tasklet);
openair_bh_cnt++;
return IRQ_HANDLED;
} else {
return IRQ_NONE;
}
} else
return IRQ_NONE;
} else {
if (exmimo_pci_kvirt[card_id].exmimo_id_ptr->board_swrev == BOARD_SWREV_LEGACY) {
// clear PCIE interrupt (bit 7 of register 0x0)
iowrite32(irqval&0xffffff7f,bar[card_id]+PCIE_CONTROL0);
}
if (irqcmd == GET_FRAME_DONE) {
get_frame_done = 1;
}
openair_tasklet.data = card_id;
tasklet_schedule(&openair_tasklet);
openair_bh_cnt++;
return IRQ_HANDLED;
}
}
void openair_do_tasklet (unsigned long card_id)
{
int save_irq_cnt = openair_bh_cnt;
unsigned int irqcmd;
unsigned int pcie_control = PCIE_CONTROL2;
openair_bh_cnt = 0;
if (exmimo_pci_kvirt[card_id].exmimo_id_ptr->board_swrev == BOARD_SWREV_LEGACY)
pcie_control = PCIE_CONTROL1;
else
pcie_control = PCIE_CONTROL2;
irqcmd = ioread32(bar[card_id]+pcie_control);
if (save_irq_cnt > 1)
printk("[openair][IRQ tasklet(%ld)]: Warning: received more than 1 PCIE IRQ (openair_bh_cnt=%i), only the last one is acted upon(irqcmd= %i (0x%X)\n", card_id, openair_bh_cnt, irqcmd, irqcmd);
switch( irqcmd ) {
case PCI_PRINTK:
// printk("Got PCIe interrupt for printk ...\n");
pcie_printk((int) card_id);
break;
case GET_FRAME_DONE:
printk("[openair][IRQ tasklet] : Got PCIe interrupt for GET_FRAME_DONE ...\n");
break;
case EXMIMO_NOP:
printk("[openair][IRQ tasklet] : Received IRQ, with CONTROL0.bit7(IRQ Leon2PC) set, but irqcmd = EXMIMO_NOP. This should not happen with bitstreams built after June 3rd 2013.\n");
break;
default:
printk("[openair][IRQ tasklet] : Got unknown PCIe cmd: card_id = %li, irqcmd(CONTROL1) = %i (0x%X)\n", card_id, irqcmd, irqcmd);
}
iowrite32(EXMIMO_NOP, bar[card_id]+pcie_control);
}
void pcie_printk(int card_id)
{
char *buffer = exmimo_pci_kvirt[card_id].printk_buffer_ptr;
unsigned int len = ((unsigned int *)buffer)[0];
unsigned int off=0,i;
unsigned char *dword;
unsigned char tmp;
//printk("In pci_fifo_printk : buffer %p, len %d: \n",buffer,len);
printk("[LEON card%d]: ", card_id);
if (len<1024) {
if ( (len&3) >0 )
off=1;
for (i=0; i<(off+(len>>2)); i++) {
dword = &((unsigned char *)buffer)[(1+i)<<2];
tmp = dword[3];
dword[3] = dword[0];
dword[0] = tmp;
tmp = dword[2];
dword[2] = dword[1];
dword[1] = tmp;
}
for (i=0; i<len; i++)
printk("%c",((char*)&buffer[4])[i]);
}
}
@@ -1,356 +0,0 @@
/*
* 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
*/
/** module_main.c (was: device.c)
*
* Main Kernel module functions for load/init and cleanup of the kernel driver
*
* Supports multiple ExpressMIMO cards
*
* Authors: Matthias Ihmig <matthias.ihmig@mytum.de>, 2012, 2013
* Riadh Ghaddab <riadh.ghaddab@eurecom.fr>
* Raymond Knopp <raymond.knopp@eurecom.fr>
*
* Changelog:
* 14.01.2013: removed remaining of BIGPHYS stuff and replaced with pci_alloc_consistent
* 20.01.2013: added support for multiple cards
* 24.01.2013: restructured interfaces & structures of how physical and virtual pointers are handled
*/
#include "openair_device.h"
#include "defs.h"
#include "vars.h"
#include <linux/moduleparam.h>
#include <linux/interrupt.h>
#include <linux/aer.h>
#include <linux/pci_regs.h>
#include <linux/delay.h>
static void openair_cleanup(void);
extern irqreturn_t openair_irq_handler(int irq, void *cookie);
static int irq = 0;
module_param(irq,int,S_IRUSR|S_IWUSR);
static struct file_operations openair_fops = {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)
unlocked_ioctl:openair_device_ioctl,
#else
ioctl: openair_device_ioctl,
#endif
open: openair_device_open,
release:openair_device_release,
mmap: openair_device_mmap
};
static int __init openair_init_module( void )
{
int res = 0;
unsigned int readback;
unsigned int card, j;
unsigned int vid,did;
unsigned int val;
unsigned short vendor, subid;
exmimo_id_t exmimo_id_tmp[MAX_CARDS];
//------------------------------------------------
// Find and enable ExpressMIMO PCI cards
//------------------------------------------------
//
card = 0;
pdev[card] = pci_get_device(XILINX_VENDOR, XILINX_ID, NULL);
if( pdev[card] ) {
// This print does not work for 64 bit kernels
// printk("[openair][INIT_MODULE][INFO]: openair card (ExpressMIMO) %d found, bus 0x%x, primary 0x%x, secondary 0x%x\n",card,
// pdev[card]->bus->number, pdev[card]->bus->primary,pdev[card]->bus->secondary);
pci_read_config_word(pdev[card], PCI_SUBSYSTEM_ID, &subid);
pci_read_config_word(pdev[card], PCI_SUBSYSTEM_VENDOR_ID, &vendor);
exmimo_id_tmp[card].board_vendor = vendor;
if ( exmimo_id_tmp[card].board_vendor == XILINX_VENDOR )
exmimo_id_tmp[card].board_vendor = EURECOM_VENDOR; // set default to EURECOM
exmimo_id_tmp[card].board_exmimoversion = (subid >> 12) & 0x0F;
if (exmimo_id_tmp[card].board_exmimoversion == 0)
exmimo_id_tmp[card].board_exmimoversion = 1; // default (for old bitstreams) is ExpressMIMO-1
exmimo_id_tmp[card].board_hwrev = (subid >> 8) & 0x0F;
exmimo_id_tmp[card].board_swrev = (subid ) & 0xFF;
printk("[openair][INIT_MODULE][INFO]: card %d: ExpressMIMO-%i (HW Rev %i), Bitstream: %s, SW/Protocol Revision: 0x%02X\n", card,
exmimo_id_tmp[card].board_exmimoversion, exmimo_id_tmp[card].board_hwrev, ( (exmimo_id_tmp[card].board_vendor == EURECOM_VENDOR) ? "Eurecom" : "Telecom Paristech"), exmimo_id_tmp[card].board_swrev );
card++;
vid = XILINX_VENDOR;
did = XILINX_ID;
} else {
printk("[openair][INIT_MODULE][INFO]: no card found, stopping.\n");
return -ENODEV;
}
// Now look for more cards on the same bus
while (card<MAX_CARDS) {
pdev[card] = pci_get_device(vid,did, pdev[card-1]);
if(pdev[card]) {
// This print does not work for 64 bit kernels
// printk("[openair][INIT_MODULE][INFO]: openair card %d found, bus 0x%x, primary 0x%x, secondary 0x%x\n",card,
// pdev[card]->bus->number,pdev[card]->bus->primary,pdev[card]->bus->secondary);
pci_read_config_word(pdev[card], PCI_SUBSYSTEM_ID, &subid);
pci_read_config_word(pdev[card], PCI_SUBSYSTEM_VENDOR_ID, &vendor);
exmimo_id_tmp[card].board_vendor = vendor;
if ( exmimo_id_tmp[card].board_vendor == XILINX_VENDOR )
exmimo_id_tmp[card].board_vendor = EURECOM_VENDOR; // default (for old bitstreams) is EURECOM_VENDOR
exmimo_id_tmp[card].board_exmimoversion = (subid >> 12) & 0x0F;
if (exmimo_id_tmp[card].board_exmimoversion == 0)
exmimo_id_tmp[card].board_exmimoversion = 1; // default (for old bitstreams) is ExpressMIMO-1
exmimo_id_tmp[card].board_hwrev = (subid >> 8) & 0x0F;
exmimo_id_tmp[card].board_swrev = (subid ) & 0xFF;
printk("[openair][INIT_MODULE][INFO]: card %d: ExpressMIMO-%i (HW Rev %i), Bitstream: %s, SW/Protocol Revision: 0x%02X\n", card,
exmimo_id_tmp[card].board_exmimoversion, exmimo_id_tmp[card].board_hwrev, ( (exmimo_id_tmp[card].board_vendor == EURECOM_VENDOR) ? "Eurecom" : "Telecom Paristech"), exmimo_id_tmp[card].board_swrev );
card++;
} else
break;
}
// at least one device found, enable it
number_of_cards = card;
for (card=0; card<number_of_cards; card++) {
if( pci_enable_device(pdev[card]) ) {
printk("[openair][INIT_MODULE][INFO]: Could not enable PCI card device %d\n",card);
openair_cleanup();
return -ENODEV;
} else {
printk("[openair][INIT_MODULE][INFO]: *** CARD DEVICE %d (pdev=%p) ENABLED, irq %d\n",card,pdev[card],irq);
printk("[openair][INIT_MODULE][INFO]: *** CARD DEVICE %d (pdev=%p) ENABLED, irq %d\n",card,pdev[card],pdev[card]->irq);
openair_pci_device_enabled[card] = 1;
}
// Make the FPGA to a PCI master
pci_set_master(pdev[card]);
// set DMA mask
if (!pci_set_dma_mask(pdev[card], DMA_BIT_MASK(32))) {
if (pci_set_consistent_dma_mask(pdev[card], DMA_BIT_MASK(32))) {
printk(KERN_INFO "[openair][INIT_MODULE]: Unable to obtain 32bit DMA for consistent allocations\n");
openair_cleanup();
return -EIO;
}
}
//if (pci_enable_pcie_error_reporting(pdev[card]) > 0)
// printk("[openair][INIT_MODULE][INFO]: Enabled PCIe error reporting\n");
//else
// printk("[openair][INIT_MODULE][INFO]: Failed to enable PCIe error reporting\n");
//pci_cleanup_aer_uncorrect_error_status(pdev[card]);
mmio_start[card] = pci_resource_start(pdev[card], 0); // get start of BAR0
mmio_length[card] = pci_resource_len (pdev[card], 0);
mmio_flags[card] = pci_resource_flags(pdev[card], 0);
if (request_mem_region(mmio_start[card],256,"openair_rf") == NULL) {
printk("[openair][INIT_MODULE][FATAL] : Cannot get memory region 0, aborting\n");
mmio_start[card] = 0;
openair_cleanup();
return -EBUSY;
} else
printk("[openair][INIT_MODULE][INFO] : Reserved memory region 0 : mmio_start = 0x%x\n",(unsigned int)mmio_start[card]);
bar[card] = pci_iomap( pdev[card], 0, mmio_length[card] ); // get virtual kernel address for BAR0
printk("[openair][INIT_MODULE][INFO]: BAR0 card %d = 0x%p\n", card, bar[card]);
printk("[openair][INIT_MODULE][INFO]: Writing 0x%x to BAR0+0x1c (PCIBASEL)\n", 0x12345678);
iowrite32( 0x12345678, (bar[card]+PCIE_PCIBASEL) );
udelay(100);
readback = ioread32( bar[card]+PCIE_PCIBASEL );
if (readback != 0x12345678) {
printk("[openair][INIT_MODULE][INFO]: Readback of FPGA register failed (%x)\n",readback);
openair_cleanup();
return -EIO;
}
iowrite32((1<<8), bar[card] +PCIE_CONTROL0 ); // bit8=AHBPCIE_CTL0_SOFTRESET, but what is bit9 and bit10?
udelay(1000);
readback = ioread32( bar[card] +PCIE_CONTROL0);
printk("CONTROL0 readback %x\n",readback);
// This is for displaying the card number in the leds of the exmimo card
val = ioread32(bar[card]+PCIE_CONTROL0);
iowrite32(val| ((card & 0x1F) << 9),bar[card]+PCIE_CONTROL0);
//val = ioread32(bar[card]+PCIE_CONTROL0);
//printk("[openair][INIT_MODULE][INFO]: writing leds for card %d control0 %x\n",card,val);
// allocating buffers
if ( exmimo_memory_alloc( card ) ) {
printk("[openair][MODULE][ERROR] exmimo_memory_alloc() failed!\n");
openair_cleanup();
return -ENOMEM;
}
exmimo_pci_kvirt[card].exmimo_id_ptr->board_vendor = exmimo_id_tmp[card].board_vendor;
exmimo_pci_kvirt[card].exmimo_id_ptr->board_exmimoversion = exmimo_id_tmp[card].board_exmimoversion;
exmimo_pci_kvirt[card].exmimo_id_ptr->board_hwrev = exmimo_id_tmp[card].board_hwrev;
exmimo_pci_kvirt[card].exmimo_id_ptr->board_swrev = exmimo_id_tmp[card].board_swrev;
if (irq!=0)
printk("[OPENAIR][SCHED][INIT] card %d: Trying to get IRQ %d\n", card,irq);
else
printk("[OPENAIR][SCHED][INIT] card %d: Trying to get IRQ %d\n", card, pdev[card]->irq);
openair_irq_enabled[card] = 0;
// #ifdef CONFIG_PREEMPT_RT doesn't work -> fix misconfigured header files?
#if 1
if (irq!=0) {
if ( (res = request_irq(irq, openair_irq_handler,
IRQF_SHARED , "openair_rf", pdev[card] )) == 0) {
openair_irq_enabled[card] = 1;
} else {
printk("[EXMIMO][SCHED][INIT] Cannot get IRQ %d for HW, error: %d\n", irq, res);
openair_cleanup();
return -EBUSY;
}
} else {
if ( (res = request_irq(pdev[card]->irq, openair_irq_handler,
IRQF_SHARED , "openair_rf", pdev[card] )) == 0) {
openair_irq_enabled[card] = 1;
} else {
printk("[EXMIMO][SCHED][INIT] Cannot get IRQ %d for HW, error: %d\n", pdev[card]->irq, res);
openair_cleanup();
return -EBUSY;
}
}
#else
printk("Warning: didn't request IRQ for PREEMPT_REALTIME\n");
#endif
} // for (i=0; i<number_of_cards; i++)
//------------------------------------------------
// Register the device in /dev
//------------------------------------------------
//
major = openair_MAJOR;
if( (res = register_chrdev(major, "openair", &openair_fops )) < 0) {
printk("[openair][INIT_MODULE][ERROR]: can't register char device driver, major : %d, error: %d\n", major, res);
for (j=0; j<=number_of_cards; j++)
release_mem_region(mmio_start[j],256);
return -EBUSY;
} else {
printk("[openair][INIT_MODULE][INFO]: char device driver registered major : %d\n", major);
openair_chrdev_registered = 1;
}
printk("[openair][MODULE][INFO] Initializing Leon (EXMIMO_PCIE_INIT) on all cards...\n");
for (card=0; card<number_of_cards; card++)
exmimo_firmware_init( card );
printk("[openair][MODULE][INFO] Done module init\n");
return 0;
}
static void __exit openair_cleanup_module(void)
{
//int card;
printk("[openair][CLEANUP MODULE]\n");
// stop any ongoing acquisition
//for (card = 0; card < number_of_cards; card++)
// exmimo_send_pccmd(card, EXMIMO_STOP);
openair_cleanup();
}
static void openair_cleanup(void)
{
int card;
if ( openair_chrdev_registered )
unregister_chrdev(major,"openair");
openair_chrdev_registered = 0;
for (card=0; card<number_of_cards; card++) {
// unregister interrupt
if ( openair_irq_enabled[card] ) {
printk("[openair][CLEANUP] disabling interrupt card %d\n", card);
if (irq!=0)
free_irq(irq, pdev[card] );
else
free_irq( pdev[card]->irq, pdev[card] );
openair_irq_enabled[card] = 0;
}
exmimo_firmware_cleanup( card );
if ( bar[card] ) {
printk("unmap bar[%d] %p\n", card, bar[card]);
iounmap((void *)bar[card]);
}
if ( mmio_start[card] ) {
printk("release mem[%d] %x\n", card, (unsigned int)mmio_start[card]);
release_mem_region(mmio_start[card],256);
}
if ( openair_pci_device_enabled[card] ) {
printk("pci_disable_device %i\n", card);
pci_disable_device( pdev[card] );
}
}
}
MODULE_AUTHOR ("Raymond KNOPP <raymond.knopp@eurecom.fr>, Matthias IHMIG <matthias.ihmig@eurecom.fr>, Florian KALTENBERGER <florian.kaltenberger@eurecom.fr>");
MODULE_DESCRIPTION ("openair ExpressMIMO/ExpressMIMO2 driver");
MODULE_LICENSE ("GPL");
module_init (openair_init_module);
module_exit (openair_cleanup_module);
-62
View File
@@ -1,62 +0,0 @@
/*
* 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
*/
#ifndef __VARS_H__
#define __VARS_H__
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci.h>
#ifdef KERNEL2_6
#include <linux/slab.h>
#endif
#include "defs.h"
#include "pcie_interface.h"
unsigned int openair_irq_enabled[MAX_CARDS] = INIT_ZEROS;
unsigned int openair_chrdev_registered = 0;
unsigned int openair_pci_device_enabled[MAX_CARDS] = INIT_ZEROS;
struct pci_dev *pdev[MAX_CARDS] = INIT_ZEROS;
void __iomem *bar[MAX_CARDS] = INIT_ZEROS;
resource_size_t mmio_start[MAX_CARDS] = INIT_ZEROS;
resource_size_t mmio_length[MAX_CARDS];
unsigned int mmio_flags[MAX_CARDS];
int major;
char number_of_cards;
// bigshm allocs a single larger block, used for shared structures and pointers
dma_addr_t bigshm_head_phys[MAX_CARDS] = INIT_ZEROS;
void *bigshm_head[MAX_CARDS] = INIT_ZEROS;
void *bigshm_currentptr[MAX_CARDS];
dma_addr_t pphys_exmimo_pci_phys[MAX_CARDS]; // phys pointer to pci_bot structure in shared mem
exmimo_pci_interface_bot_t *p_exmimo_pci_phys[MAX_CARDS] = INIT_ZEROS; // inside struct has physical (DMA) pointers to pci_bot memory blocks
exmimo_pci_interface_bot_virtual_t exmimo_pci_kvirt[MAX_CARDS]; // has virtual pointers to pci_bot memory blocks
#endif
@@ -1,20 +0,0 @@
CCC = gcc
include $(OPENAIR_DIR)/common/utils/Makefile.inc
KERNEL_MAIN_TYPE=$(shell echo `uname -r | cut -d. -f-2 | tr "." "_"`)
export KERNEL_MAIN_TYPE
EXTRA_CFLAGS = -ggdb -D__KERNEL__ -DMODULE -D_LOOSE_KERNEL_NAMES -I$(KERNEL_DIR)/build/include -I$(KERNEL_DIR)/build/include/asm/mach-default -include $(KERNEL_DIR)/build/include/linux/autoconf.h
EXTRA_CFLAGS += -I$(PWD)/../../DEFS
obj-m += openair_rf.o
openair_rf-objs += module_main.o irq.o fileops.o exmimo_fw.o
all:
make -C $(KERNEL_DIR)/build M=$(PWD) modules
clean:
rm -rf *.o
make -C $(KERNEL_DIR)/build M=$(PWD) clean
@@ -1,4 +0,0 @@
echo "Hint: this may not work if /usr/src/linux is not set to currently booted kernel."
echo "Try 'make' instead."
make -C /usr/src/linux V=1 M=`pwd`
-73
View File
@@ -1,73 +0,0 @@
/*
* 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
*/
#ifndef __DEFS_H__
#define __DEFS_H__
#include <asm/io.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
#include <asm/segment.h>
#include <asm/page.h>
#include <asm/delay.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/slab.h>
//#include <linux/config.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#ifdef KERNEL2_6
#include <linux/slab.h>
#endif
#include "openair_device.h"
#include "linux/moduleparam.h"
/*------------------------------------------------*/
/* Prototypes */
/*------------------------------------------------*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)
long openair_device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
#else
int openair_device_ioctl(struct inode *inode,struct file *filp, unsigned int cmd, unsigned long arg);
#endif
int openair_device_open (struct inode *inode,struct file *filp);
int openair_device_release (struct inode *inode,struct file *filp);
int openair_device_mmap (struct file *filp, struct vm_area_struct *vma);
int exmimo_memory_alloc(int card);
int exmimo_firmware_init(int card);
int exmimo_firmware_cleanup(int card_id);
int exmimo_send_pccmd(int card_id, unsigned int cmd);
#endif
@@ -1,20 +0,0 @@
#!/bin/sh
# Re-Enumerate FPGA card
# After resetting or powering up the card or after reloading the FPGA bitstream,
# run this script to re-enumerate the PCIe device in Linux.
# You may need to change the device path. Check lspci output for this.
# You need to run this as root:
# sudo ./do_reenumerate_expressmimo.sh
# Matthias <ihmig@eurecom.fr>, 2013
rmmod openair_rf
echo 1 > /sys/bus/pci/devices/0000\:01\:00.0/remove
echo 1 > /sys/bus/pci/devices/0000\:05\:00.0/remove
echo 1 > /sys/bus/pci/rescan
insmod openair_rf.ko
@@ -1 +0,0 @@
rmmod openair_rf && sleep 1 ; insmod openair_rf.ko
@@ -1,360 +0,0 @@
/*
* 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
*/
/** exmimo_fw.c
*
* Initialization routines for
* Shared Memory management for ExMIMO and PC(kernel) data exchange
* (memory allocation, pointer management)
*
* There is now one pci_alloc_consistent for each RX and TX buffer
* and one for all structures, including pointers, printk, firmware_dump and config
*
* Authors: Matthias Ihmig <matthias.ihmig@mytum.de>, 2012, 2013
* Riadh Ghaddab <riadh.ghaddab@eurecom.fr>
* Raymond Knopp <raymond.knopp@eurecom.fr>
*
* Changelog:
* 24.01.2013: added memory management functions for bigshm, lots of cleanups
*/
#include <linux/delay.h>
#include "extern.h"
#include "defs.h"
#include "pcie_interface.h"
/*****************************************************
* Private functions within this file
*/
void mem_SetPageReserved(void *kvirt_addr, unsigned int size_pages)
{
size_t temp_size = size_pages << PAGE_SHIFT;
void *adr = kvirt_addr;
while (temp_size > 0) {
SetPageReserved( virt_to_page(adr) );
adr += PAGE_SIZE;
temp_size -= PAGE_SIZE;
}
}
void mem_ClearPageReserved(void *kvirt_addr, unsigned int size_pages)
{
size_t temp_size = size_pages << PAGE_SHIFT;
void *adr = kvirt_addr;
while (temp_size > 0) {
ClearPageReserved( virt_to_page(adr) );
adr += PAGE_SIZE;
temp_size -= PAGE_SIZE;
}
}
// allocates big shared memory, to be used for structures, pointers, etc.
// bigshm allocs a single larger memory block for shared structures and pointers, one per card, except: ADC+DAC buffers!
// returns -1 on error, 0 on success
int bigshm_init(int card)
{
printk("[openair][module] calling pci_alloc_consistent for card %d, bigshm (size: %lu*%lu bytes)...\n", card, BIGSHM_SIZE_PAGES, PAGE_SIZE);
if ( sizeof(dma_addr_t) != 4)
printk("!!! WARNING: sizeof (dma_addr_t) = %lu! Only 32bit mode (= 4) (also: no PAE) is supported at this time!\n", sizeof(dma_addr_t));
if ( bigshm_head[card] == NULL )
bigshm_head[card] = pci_alloc_consistent( pdev[card], BIGSHM_SIZE_PAGES<<PAGE_SHIFT, &bigshm_head_phys[card] );
if (bigshm_head[card] == NULL) {
printk("[openair][MODULE][ERROR] Cannot Allocate Memory (%lu bytes) for shared data (bigshm)\n", BIGSHM_SIZE_PAGES<<PAGE_SHIFT);
return -ENOMEM;
} else {
printk("[openair][MODULE][INFO] Bigshm at %p (phys %x)\n", bigshm_head[card], (unsigned int) bigshm_head_phys[card]);
bigshm_currentptr[card] = bigshm_head[card];
mem_SetPageReserved( bigshm_head[card], BIGSHM_SIZE_PAGES);
memset(bigshm_head[card], 0, BIGSHM_SIZE_PAGES << PAGE_SHIFT);
}
return 0;
}
// use this instead of pci_alloc_consistent to assign memory from the bigshm block
// return kernel virtual pointer and sets physical DMA address in dma_handle
void *bigshm_assign( int card, size_t size_bytes, dma_addr_t *dma_handle_ptr )
{
void *ret;
size_t size = size_bytes;
//size = (size-1) + 4 - ( (size-1) % 4); // round up to keep addresses aligned to DWs
//size = (size-1) + 16 - ( (size-1) % 16); // round up to keep addresses aligned to 4 DWs
// round up to the next 64 DW (workaround for current bug in DMA on ExMIMO2)
size = (size-1) + 256 - ( (size-1) % 256);
if ( (bigshm_currentptr[card] - bigshm_head[card]) > (BIGSHM_SIZE_PAGES<<PAGE_SHIFT) -size ) {
printk("Not enough memory in bigshm! Make BIGSHM_SIZE_PAGES bigger!\n");
return NULL;
}
*dma_handle_ptr = bigshm_head_phys[card] + ( (dma_addr_t)bigshm_currentptr[card] - (dma_addr_t)bigshm_head[card] );
ret = bigshm_currentptr[card];
bigshm_currentptr[card] = (char *)bigshm_currentptr[card] + size;
//printk("bigshm_assign: size %d, virt = %p, dma = %x, bigshm_phys=%x, _current=%p, _head=%p\n",
// size, ret, *dma_handle_ptr, bigshm_head_phys[card], bigshm_currentptr[card], bigshm_head[card]);
return ret;
}
// assign shared memory between card an PC for data exchange: interface structure with pointers,
// firmware- and printk buffers, configuration structure
// returns -1 on error, 0 on success
int exmimo_assign_shm_vars(int card_id)
{
int j;
if (p_exmimo_pci_phys[card_id] == NULL) {
p_exmimo_pci_phys[card_id] = (exmimo_pci_interface_bot_t *) bigshm_assign( card_id,
sizeof(exmimo_pci_interface_bot_t),
&pphys_exmimo_pci_phys[card_id]);
printk("Intializing EXMIMO interface support (exmimo_pci_bot at %p, phys %x, size %lu bytes)\n",p_exmimo_pci_phys[card_id],(unsigned int)pphys_exmimo_pci_phys[card_id],
sizeof(exmimo_pci_interface_bot_t));
exmimo_pci_kvirt[card_id].firmware_block_ptr = (char *) bigshm_assign( card_id,
MAX_FIRMWARE_BLOCK_SIZE_B,
(dma_addr_t*)&(p_exmimo_pci_phys[card_id]->firmware_block_ptr));
printk("firmware_code_block_ptr : %p (phys = %08x)\n", exmimo_pci_kvirt[card_id].firmware_block_ptr, p_exmimo_pci_phys[card_id]->firmware_block_ptr);
exmimo_pci_kvirt[card_id].printk_buffer_ptr = (char *) bigshm_assign( card_id,
MAX_PRINTK_BUFFER_B,
(dma_addr_t*)&(p_exmimo_pci_phys[card_id]->printk_buffer_ptr));
printk("printk_buffer_ptr : %p (phys = %08x)\n", exmimo_pci_kvirt[card_id].printk_buffer_ptr, p_exmimo_pci_phys[card_id]->printk_buffer_ptr);
exmimo_pci_kvirt[card_id].exmimo_config_ptr = (exmimo_config_t *) bigshm_assign( card_id,
sizeof(exmimo_config_t),
(dma_addr_t*)&(p_exmimo_pci_phys[card_id]->exmimo_config_ptr));
printk("exmimo_config_ptr : %p (phys = %08x)\n", exmimo_pci_kvirt[card_id].exmimo_config_ptr, p_exmimo_pci_phys[card_id]->exmimo_config_ptr);
exmimo_pci_kvirt[card_id].exmimo_id_ptr = (exmimo_id_t *) bigshm_assign( card_id,
sizeof(exmimo_id_t),
(dma_addr_t*)&(p_exmimo_pci_phys[card_id]->exmimo_id_ptr));
printk("exmimo_id_ptr : %p (phys = %08x)\n", exmimo_pci_kvirt[card_id].exmimo_id_ptr, p_exmimo_pci_phys[card_id]->exmimo_id_ptr);
if ( p_exmimo_pci_phys[card_id] == NULL || exmimo_pci_kvirt[card_id].firmware_block_ptr == NULL
|| exmimo_pci_kvirt[card_id].printk_buffer_ptr == NULL || exmimo_pci_kvirt[card_id].exmimo_config_ptr == NULL
|| exmimo_pci_kvirt[card_id].exmimo_id_ptr == NULL )
return -1;
for (j=0; j<MAX_ANTENNAS; j++) {
// size 4*1 should be sufficient, but just to make sure we can also use DMA of size 4DW as fallback
exmimo_pci_kvirt[card_id].rxcnt_ptr[j] = (uint32_t *) bigshm_assign( card_id, 4*4,
(dma_addr_t*)&(p_exmimo_pci_phys[card_id]->rxcnt_ptr[j]) );
printk("exmimo_pci_kvirt[%d].rxcnt_ptr[%d] = %p (phys = %08x)\n", card_id, j, exmimo_pci_kvirt[card_id].rxcnt_ptr[j], p_exmimo_pci_phys[card_id]->rxcnt_ptr[j]);
exmimo_pci_kvirt[card_id].txcnt_ptr[j] = (uint32_t *) bigshm_assign( card_id, 4*4,
(dma_addr_t*)&(p_exmimo_pci_phys[card_id]->txcnt_ptr[j]) );
printk("exmimo_pci_kvirt[%d].txcnt_ptr[%d] = %p (phys = %08x)\n", card_id, j, exmimo_pci_kvirt[card_id].txcnt_ptr[j], p_exmimo_pci_phys[card_id]->txcnt_ptr[j]);
if ( exmimo_pci_kvirt[card_id].rxcnt_ptr[j] == NULL || exmimo_pci_kvirt[card_id].txcnt_ptr[j] == NULL)
return -1;
}
}
return 0;
}
// allocate memory for RX and TX chains for all antennas
// returns -1 on error, 0 on success
int exmimo_allocate_rx_tx_buffers(int card_id)
{
size_t size;
int j,i;
dma_addr_t dma_addr_dummy;
// Round up to the next PAGE_SIZE (typ. 4096 bytes)
size = (ADAC_BUFFERSZ_PERCHAN_B >> PAGE_SHIFT) + 1;
size <<= PAGE_SHIFT;
for (j=0; j<MAX_ANTENNAS; j++) {
exmimo_pci_kvirt[card_id].adc_head[j] = (uint32_t *)pci_alloc_consistent( pdev[card_id], size, &dma_addr_dummy);
p_exmimo_pci_phys[card_id]->adc_head[j]=((uint32_t*)&dma_addr_dummy)[0];
printk("exmimo_pci_kvirt[%d].adc_head[%d] = %p (phys = %08x)\n", card_id, j, exmimo_pci_kvirt[card_id].adc_head[j], p_exmimo_pci_phys[card_id]->adc_head[j]);
if ( exmimo_pci_kvirt[card_id].adc_head[j] == NULL)
return -1;
// printk("[MODULE MAIN0]Phys address TX[0] : (%8lx)\n",p_exmimo_pci_phys[0]->dac_head[ openair_mmap_getAntTX(2) ]);
mem_SetPageReserved( exmimo_pci_kvirt[card_id].adc_head[j], size >> PAGE_SHIFT );
memset( exmimo_pci_kvirt[card_id].adc_head[j], 0x10+j, size);
// printk("[MODULE MAIN1]Phys address TX[0] : (%8lx)\n",p_exmimo_pci_phys[0]->dac_head[ openair_mmap_getAntTX(2) ]);
exmimo_pci_kvirt[card_id].dac_head[j] = (uint32_t *)pci_alloc_consistent( pdev[card_id], size,&dma_addr_dummy);
p_exmimo_pci_phys[card_id]->dac_head[j]=((uint32_t*)&dma_addr_dummy)[0];
// printk("exmimo_pci_kvirt[%d].dac_head[%d] = %p (phys = %08x)\n", card_id, j, exmimo_pci_kvirt[card_id].dac_head[j], p_exmimo_pci_phys[card_id]->dac_head[j]);
if ( exmimo_pci_kvirt[card_id].dac_head[j] == NULL)
return -ENOMEM;
// printk("[MODULE MAIN2]Phys address TX[0] : (%8lx)\n",p_exmimo_pci_phys[0]->dac_head[ openair_mmap_getAntTX(2) ]);
mem_SetPageReserved( exmimo_pci_kvirt[card_id].dac_head[j], size >> PAGE_SHIFT );
memset( exmimo_pci_kvirt[card_id].dac_head[j], 0x20+j, size);
// printk("[MODULE MAIN3]Phys address TX[0] : (%8lx)\n",p_exmimo_pci_phys[0]->dac_head[ openair_mmap_getAntTX(2) ]);
}
return 0;
}
/*********************************************
* Public functions ExpressMIMO Interface
*/
/* Allocates buffer and assigns pointers
*
* return 0 on success
*/
int exmimo_memory_alloc(int card)
{
int i;
if ( bigshm_init( card ) ) {
printk("exmimo_memory_alloc(): bigshm_init failed for card %d.\n", card);
return -ENOMEM;
}
if ( exmimo_assign_shm_vars( card ) ) {
printk("exmimo_memory_alloc(): exmimo_assign_shm_vars failed to assign enough shared memory for all variables and structures for card %i!\n", card);
return -ENOMEM;
}
if ( exmimo_allocate_rx_tx_buffers( card ) ) {
printk("exmimo_memory_alloc(): exmimo_allocate_rx_tx_buffers() failed to allocate enough memory for RX and TX buffers for card %i!\n", card);
return -ENOMEM;
}
return 0;
}
/*
* Copies pointer to Leon
*/
int exmimo_firmware_init(int card)
{
// put DMA pointer to exmimo_pci_interface_bot into LEON register
iowrite32( pphys_exmimo_pci_phys[card], (bar[card]+PCIE_PCIBASEL) ); // lower 32bit of address
iowrite32( 0, (bar[card]+PCIE_PCIBASEH) ); // higher 32bit of address
for (j=0; j<MAX_ANTENNAS; j++) {
iowrite32(p_exmimo_pci_phys[card]->adc_head[j], (bar[card]+));
iowrite32(p_exmimo_pci_phys[card]->dac_head[j], (bar[card]+));
}
exmimo_send_pccmd(card, EXMIMO_PCIE_INIT);
return 0;
}
/*
* Free memory on unloading the kernel driver
*/
int exmimo_firmware_cleanup(int card)
{
size_t size;
int j;
// free exmimo_allocate_rx_tx_buffers
size = (ADAC_BUFFERSZ_PERCHAN_B >> PAGE_SHIFT) + 1;
size <<= PAGE_SHIFT;
for (j=0; j<MAX_ANTENNAS; j++) {
if ( exmimo_pci_kvirt[card].adc_head[j] ) {
mem_ClearPageReserved( exmimo_pci_kvirt[card].adc_head[j], size >> PAGE_SHIFT );
pci_free_consistent( pdev[card], size, exmimo_pci_kvirt[card].adc_head[j], p_exmimo_pci_phys[card]->adc_head[j] );
}
if ( exmimo_pci_kvirt[card].dac_head[j] ) {
mem_ClearPageReserved( exmimo_pci_kvirt[card].dac_head[j], size >> PAGE_SHIFT );
pci_free_consistent( pdev[card], size, exmimo_pci_kvirt[card].dac_head[j], p_exmimo_pci_phys[card]->dac_head[j] );
}
}
if ( bigshm_head[card] ) {
printk("free bigshm_head[%d] pdev %p, size %lu, head %p, phys %x\n", card, pdev[card], BIGSHM_SIZE_PAGES<<PAGE_SHIFT, bigshm_head[card], (unsigned int)bigshm_head_phys[card]);
mem_ClearPageReserved( bigshm_head[card], BIGSHM_SIZE_PAGES );
pci_free_consistent( pdev[card], BIGSHM_SIZE_PAGES<<PAGE_SHIFT, bigshm_head[card], bigshm_head_phys[card]);
}
return 0;
}
/*
* Send command to Leon and wait until command is completed
*/
int exmimo_send_pccmd(int card_id, unsigned int cmd)
{
unsigned int val;
unsigned int cnt=0;
//printk("Sending command to ExpressMIMO (card %d) : %x\n",card_id, cmd);
iowrite32(cmd,(bar[card_id]+PCIE_CONTROL1));
// printk("Readback of control1 %x\n",ioread32(bar[0]+PCIE_CONTROL1));
switch(cmd) {
case EXMIMO_CONFIG :
break;
case EXMIMO_PCIE_INIT :
break;
}
// workaround for ExMIMO1&2: no command ack -> sleep
while (cnt<100 && ( ioread32(bar[card_id]+PCIE_CONTROL1) != EXMIMO_NOP )) {
//printk("ctrl0: %08x, ctrl1: %08x, ctrl2: %08x, status: %08x\n", ioread32(bar[card_id]+PCIE_CONTROL0), ioread32(bar[card_id]+PCIE_CONTROL1), ioread32(bar[card_id]+PCIE_CONTROL2), ioread32(bar[card_id]+PCIE_STATUS));
msleep(100);
cnt++;
}
if (cnt==100)
printk("exmimo_send_pccmd error: Timeout: no EXMIMO_NOP received within 10sec for card%d, pccmd=%x\n", card_id, cmd);
//printk("Ctrl0: %08x, ctrl1: %08x, ctrl2: %08x, status: %08x\n", ioread32(bar[card_id]+PCIE_CONTROL0), ioread32(bar[card_id]+PCIE_CONTROL1), ioread32(bar[card_id]+PCIE_CONTROL2), ioread32(bar[card_id]+PCIE_STATUS));
return(0);
}
@@ -1,51 +0,0 @@
/*
* 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
*/
#ifndef __EXTERN_H__
#define __EXTERN_H__
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci.h>
#ifdef KERNEL2_6
#include <linux/slab.h>
#endif
#include "defs.h"
#include "pcie_interface.h"
extern char number_of_cards;
extern int major;
extern struct pci_dev *pdev[MAX_CARDS];
extern void __iomem *bar[MAX_CARDS];
extern void *bigshm_head[MAX_CARDS];
extern void *bigshm_currentptr[MAX_CARDS];
extern dma_addr_t bigshm_head_phys[MAX_CARDS];
extern dma_addr_t pphys_exmimo_pci_phys[MAX_CARDS];
extern exmimo_pci_interface_bot_t *p_exmimo_pci_phys[MAX_CARDS];
extern exmimo_pci_interface_bot_virtual_t exmimo_pci_kvirt[MAX_CARDS];
#endif // __EXTERN_H__
@@ -1,459 +0,0 @@
/*
* 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
*/
/** fileops.c
*
* Device IOCTL File Operations on character device /dev/openair0
*
* Authors: Matthias Ihmig <matthias.ihmig@mytum.de>, 2012, 2013
* Riadh Ghaddab <riadh.ghaddab@eurecom.fr>
* Raymond Knopp <raymond.knopp@eurecom.fr>
*
* Changelog:
* 14.01.2013: removed remaining of BIGPHYS stuff and replaced with pci_alloc_consistent
*/
#include <linux/delay.h>
#include "openair_device.h"
#include "defs.h"
#include "extern.h"
#include "pcie_interface.h"
#define invert4(x) { \
unsigned int ltmp; \
ltmp=x; x=((ltmp & 0xff)<<24) | ((ltmp & 0xff00)<<8) | \
((ltmp & 0xff0000)>>8) | ((ltmp & 0xff000000)>>24); \
}
extern int get_frame_done;
int is_card_num_invalid(int card)
{
if (card<0 || card>=number_of_cards) {
printk("[openair][IOCTL]: ERROR: received invalid card number (%d)!\n", card);
return -1;
} else
return 0;
}
//-----------------------------------------------------------------------------
int openair_device_open (struct inode *inode,struct file *filp)
{
//printk("[openair][MODULE] openair_open()\n");
return 0;
}
//-----------------------------------------------------------------------------
int openair_device_release (struct inode *inode,struct file *filp)
{
// printk("[openair][MODULE] openair_release(), MODE = %d\n",openair_daq_vars.mode);
return 0;
}
//-----------------------------------------------------------------------------
int openair_device_mmap(struct file *filp, struct vm_area_struct *vma)
{
unsigned long phys;
unsigned long start = (unsigned long)vma->vm_start;
unsigned long size = (unsigned long)(vma->vm_end-vma->vm_start);
unsigned long maxsize;
unsigned int memblock_ind;
unsigned int card;
memblock_ind = openair_mmap_getMemBlock( vma->vm_pgoff );
card = openair_mmap_getCard( vma->vm_pgoff );
/*printk("[openair][MMAP] called (start %lx, end %lx, pg_off %lx, size %lx)\n",
vma->vm_start,
vma->vm_end,
vma->vm_pgoff,
size);
*/
vma->vm_pgoff = 0;
// not supported by 64 bit kernels
//vma->vm_flags |= VM_RESERVED;
vma->vm_flags |= VM_IO;
if ( is_card_num_invalid(card) )
return -EINVAL;
if (memblock_ind == openair_mmap_BIGSHM) {
// map a buffer from bigshm
maxsize = BIGSHM_SIZE_PAGES<<PAGE_SHIFT;
if ( size > maxsize) {
printk("[openair][MMAP][ERROR] Trying to map more than %d bytes (req size=%d)\n",
(unsigned int)(BIGSHM_SIZE_PAGES<<PAGE_SHIFT), (unsigned int)size);
return -EINVAL;
}
phys = bigshm_head_phys[card];
} else if ( (memblock_ind & 1) == 1) {
// mmap a RX buffer
maxsize = ADAC_BUFFERSZ_PERCHAN_B;
if ( size > maxsize) {
printk("[openair][MMAP][ERROR] Trying to map more than %d bytes (req size=%d)\n",
(unsigned int)(ADAC_BUFFERSZ_PERCHAN_B), (unsigned int)size);
return -EINVAL;
}
phys = p_exmimo_pci_phys[card]->adc_head[ openair_mmap_getAntRX(memblock_ind) ];
} else {
// mmap a TX buffer
maxsize = ADAC_BUFFERSZ_PERCHAN_B;
if ( size > maxsize) {
printk("[openair][MMAP][ERROR] Trying to map more than %d bytes (%d)\n",
(unsigned int)(ADAC_BUFFERSZ_PERCHAN_B), (unsigned int)size);
return -EINVAL;
}
phys = p_exmimo_pci_phys[card]->dac_head[ openair_mmap_getAntTX(memblock_ind) ];
}
if (0)
printk("[openair][MMAP] card%d: map phys (%08lx) at start %lx, end %lx, pg_off %lx, size %lx\n",
card,
phys,
vma->vm_start,
vma->vm_end,
vma->vm_pgoff,
size);
/* loop through all the physical pages in the buffer */
/* Remember this won't work for vmalloc()d memory ! */
if (remap_pfn_range(vma,
start,
phys>>PAGE_SHIFT,
vma->vm_end-vma->vm_start,
vma->vm_page_prot)) {
printk("[openair][MMAP] ERROR EAGAIN\n");
return -EAGAIN;
}
return 0;
}
//-----------------------------------------------------------------------------
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)
long openair_device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
#else
int openair_device_ioctl(struct inode *inode,struct file *filp, unsigned int cmd, unsigned long arg)
#endif
{
/* arg is not meaningful if no arg is passed in user space */
//-----------------------------------------------------------------------------
int i, c;
int tmp;
static unsigned int update_firmware_command;
static unsigned int update_firmware_address;
static unsigned int update_firmware_length;
static unsigned int* update_firmware_kbuffer;
static unsigned int* __user update_firmware_ubuffer;
static unsigned int update_firmware_start_address;
static unsigned int update_firmware_stack_pointer;
static unsigned int update_firmware_bss_address;
static unsigned int update_firmware_bss_size;
unsigned int *fw_block;
unsigned int sparc_tmp_0;
unsigned int sparc_tmp_1;
static unsigned int lendian_length;
unsigned int get_frame_cnt=0;
switch(cmd) {
case openair_STOP:
printk("[openair][IOCTL] openair_STOP(card%d)\n", (int)arg);
if ( is_card_num_invalid((int)arg) )
return -EINVAL;
exmimo_send_pccmd((int)arg, EXMIMO_STOP);
break;
case openair_STOP_WITHOUT_RESET:
printk("[openair][IOCTL] openair_STOP_WITHOUT_RESET(card%d)\n", (int)arg);
if ( is_card_num_invalid((int)arg) )
return -EINVAL;
exmimo_send_pccmd((int)arg, EXMIMO_STOP_WITHOUT_RESET);
break;
case openair_GET_FRAME:
get_frame_cnt=0;
get_frame_done = 0;
printk("[openair][IOCTL] : openair_GET_FRAME: calling exmimo_send_pccmd(%d, EXMIMO_GET_FRAME)\n", (int)arg);
if ( is_card_num_invalid((int)arg) )
return -EINVAL;
exmimo_send_pccmd((int)arg, EXMIMO_GET_FRAME);
while (get_frame_cnt<10 && !get_frame_done) {
msleep(10);
get_frame_cnt++;
}
if (get_frame_cnt==200)
printk("[openair][IOCTL] : Get frame error: no IRQ received within 2000ms.\n");
get_frame_done = 0;
break;
case openair_GET_BIGSHMTOPS_KVIRT:
//printk("[openair][IOCTL] : openair_GET_BIGSHMTOPS_KVIRT (0x%p)[0] = %p[0] (bigshm_head) for 0..3 (sizeof %d) \n", (void *)arg, bigshm_head[0], sizeof(bigshm_head));
copy_to_user((void *)arg, bigshm_head, sizeof(bigshm_head));
break;
case openair_GET_PCI_INTERFACE_BOTS_KVIRT:
//printk("[openair][IOCTL] : openair_GET_PCI_INTERFACE_BOTS_KVIRT: copying exmimo_pci_kvirt(@%8p) to %lx (sizeof %d)\n", &exmimo_pci_kvirt[0], arg, sizeof(exmimo_pci_kvirt));
copy_to_user((void *)arg, exmimo_pci_kvirt, sizeof(exmimo_pci_kvirt));
break;
case openair_GET_NUM_DETECTED_CARDS:
//printk("[openair][IOCTL] : openair_GET_NUM_DETECTED_CARDS: *(0x%p) = %d\n", (void *)arg, number_of_cards);
copy_to_user((void *)arg, &number_of_cards, sizeof(number_of_cards));
break;
case openair_DUMP_CONFIG:
//printk("[openair][IOCTL] openair_DUMP_CONFIG(%d)\n", (int)arg);
if ( is_card_num_invalid((int)arg) ) {
printk("[openair][IOCTL] openair_DUMP_CONFIG: Invalid card number %d.\n", (int)arg);
return -EINVAL;
}
printk("[openair][IOCTL] : openair_DUMP_CONFIG(%d): exmimo_pci_kvirt[%d].exmimo_config_ptr = %p (phys %08x)\n",
(int)arg, (int)arg, exmimo_pci_kvirt[(int)arg].exmimo_config_ptr, p_exmimo_pci_phys[(int)arg]->exmimo_config_ptr);
/*printk("EXMIMO_CONFIG: freq0 %d Hz, freq1 %d Hz, freqtx0 %d Hz, freqtx1 %d Hz, \nRX gain0 %d dB, RX Gain1 %d dB\n",
exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.rf_freq_rx[0],
exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.rf_freq_rx[1],
exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.rf_freq_tx[0],
exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.rf_freq_tx[1],
exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.rx_gain[0][0],
exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.rx_gain[1][0]);
*/
exmimo_send_pccmd((int)arg, EXMIMO_CONFIG);
break;
case openair_START_RT_ACQUISITION:
printk("[openair][IOCTL] openair_START_TX_SIG(%d): send_pccmd(EXMIMO_START_RT_ACQUISITION).\n", (int) arg);
if ( is_card_num_invalid((int)arg) )
return -EINVAL;
exmimo_send_pccmd((int)arg, EXMIMO_START_RT_ACQUISITION);
break;
case openair_UPDATE_FIRMWARE:
printk("[openair][IOCTL] openair_UPDATE_FIRMWARE\n");
/***************************************************
* Updating the firmware of Cardbus-MIMO-1 or ExpressMIMO SoC *
***************************************************/
/* 1st argument of this ioctl indicates the action to perform among these:
- Transfer a block of data at a specified address (given as the 2nd argument)
and for a specified length (given as the 3rd argument, in number of 32-bit words).
The USER-SPACE address where to find the block of data is given as the 4th
argument.
- Ask the Leon processor to clear the .bss section. In this case, the base
address of section .bss is given as the 2nd argument, and its size is
given as the 3rd one.
- Ask the Leon processor to jump at a specified address (given as the 2nd
argument, most oftenly expected to be the top address of Ins, Scratch Pad
Ram), after having set the stack pointer (given as the 3rd argument).
For the openair_UPDATE_FIRMWARE ioctl, we perform a partial infinite loop
while acknowledging the PCI irq from Leon software: the max number of loop
is yielded by preprocessor constant MAX_IOCTL_ACK_CNT. This avoids handing
the kernel with an infinite polling loop. An exception is the case of clearing
the bss: it takes time to Leon3 to perform this operation, so we poll te
acknowledge with no limit */
#define MAX_IOCTL_ACK_CNT 500
update_firmware_command = *((unsigned int*)arg);
switch (update_firmware_command) {
case UPDATE_FIRMWARE_TRANSFER_BLOCK:
update_firmware_address = ((unsigned int*)arg)[1];
update_firmware_length = ((unsigned int*)arg)[2];
update_firmware_ubuffer = (unsigned int*)((unsigned int*)arg)[3];
update_firmware_kbuffer = (unsigned int*)kmalloc(update_firmware_length * 4 /* 4 because kmalloc expects bytes */,
GFP_KERNEL);
if (!update_firmware_kbuffer) {
printk("[openair][IOCTL] Could NOT allocate %u bytes from kernel memory (kmalloc failed).\n", lendian_length * 4);
return -1;
break;
}
// update all cards at the same time
for (c=0; c<number_of_cards; c++) {
fw_block = (unsigned int *)exmimo_pci_kvirt[c].firmware_block_ptr;
/* Copy the data block from user space */
fw_block[0] = update_firmware_address;
fw_block[1] = update_firmware_length;
//printk("copy_from_user %p => %p (pci) => fw[0]=fw_addr=%08x (ahb), fw[1]=fw_length=%d DW\n",update_firmware_ubuffer,&fw_block[16],update_firmware_address,update_firmware_length);
tmp = copy_from_user(update_firmware_kbuffer,
update_firmware_ubuffer, /* from */
update_firmware_length * 4 /* in bytes */
);
if (tmp) {
printk("[openair][IOCTL] Could NOT copy all data from user-space to kernel-space (%d bytes remained uncopied).\n", tmp);
return -1;
}
// pci_map_single(pdev[0],(void*)fw_block, update_firmware_length*4,PCI_DMA_BIDIRECTIONAL);
for (i=0; i<update_firmware_length; i++) {
fw_block[32+i] = ((unsigned int *)update_firmware_kbuffer)[i];
// Endian flipping is done in user-space so undo it
invert4(fw_block[32+i]);
}
exmimo_send_pccmd(c, EXMIMO_FW_INIT);
printk("[openair][IOCTL] card%d: ok %u DW copied to address 0x%08x (fw_block_ptr %p)\n",
c, fw_block[1], fw_block[0],fw_block);
}
kfree(update_firmware_kbuffer);
/*
for (i=0; i<update_firmware_length;i++) {
printk("%08x ", fw_block[32+i]);
if ((i % 8) == 7)
printk("\n");
}*/
break;
case UPDATE_FIRMWARE_CLEAR_BSS:
update_firmware_bss_address = ((unsigned int*)arg)[1];
update_firmware_bss_size = ((unsigned int*)arg)[2];
sparc_tmp_0 = update_firmware_bss_address;
sparc_tmp_1 = update_firmware_bss_size;
printk("[openair][IOCTL] ok asked Leon to clear .bss (addr 0x%08x, size %d bytes)\n", sparc_tmp_0, sparc_tmp_1);
// update all cards at the same time
for (c=0; c<number_of_cards; c++) {
fw_block = (unsigned int *)exmimo_pci_kvirt[c].firmware_block_ptr;
fw_block[0] = update_firmware_bss_address;
fw_block[1] = update_firmware_bss_size;
exmimo_send_pccmd(c, EXMIMO_FW_CLEAR_BSS);
}
break;
case UPDATE_FIRMWARE_START_EXECUTION:
update_firmware_start_address = ((unsigned int*)arg)[1];
update_firmware_stack_pointer = ((unsigned int*)arg)[2];
sparc_tmp_0 = update_firmware_start_address;
sparc_tmp_1 = update_firmware_stack_pointer;
printk("[openair][IOCTL] ok asked Leon to set stack and start execution (addr 0x%08x, stackptr %08x)\n", sparc_tmp_0, sparc_tmp_1);
for (c=0; c<number_of_cards; c++) {
fw_block = (unsigned int *)exmimo_pci_kvirt[c].firmware_block_ptr;
fw_block[0] = update_firmware_start_address;
fw_block[1] = update_firmware_stack_pointer;
exmimo_send_pccmd(c, EXMIMO_FW_START_EXEC);
msleep(10);
exmimo_firmware_init(c);
}
break;
case UPDATE_FIRMWARE_FORCE_REBOOT:
printk("[openair][IOCTL] ok asked Leon to reboot.\n");
for (c=0; c<number_of_cards; c++) {
exmimo_send_pccmd(c, EXMIMO_REBOOT);
exmimo_firmware_init(c);
}
break;
case UPDATE_FIRMWARE_TEST_GOK:
printk("[openair][IOCTL] TEST_GOK command doesn't work with ExpressMIMO. Ignored.\n");
break;
default:
return -1;
break;
}
break;
default:
//----------------------
printk("[IOCTL] openair_IOCTL unknown: basecmd = %i (cmd=%X)\n", _IOC_NR(cmd), cmd );
return -EPERM;
break;
}
return 0;
}
-185
View File
@@ -1,185 +0,0 @@
/*
* 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
*/
/** irq.c
- IRQ Handler: IRQ from Leon to PCIe/Kernel: exmimo_irq_handler
- sends received packets to userspace
- send command from PC to Leon and trigger IRQ on Leon using CONTROL1 register
- commands are defined in $OPENAIR0/express-mimo/software/pcie_interface.h
- added: pass card_id as parameter to tasklet and irq handler
Authors:
Raymond Knopp <raymond.knopp@eurecom.fr>
Matthias Ihmig <matthias.ihmig@mytum.de>, 2011, 2013
*/
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/swab.h>
#include "openair_device.h"
#include "extern.h"
unsigned int openair_bh_cnt;
int get_frame_done = 0;
void pcie_printk(int card_id);
void openair_do_tasklet (unsigned long card_id);
DECLARE_TASKLET (openair_tasklet, openair_do_tasklet, 0);
irqreturn_t openair_irq_handler(int irq, void *cookie)
{
unsigned int irqval;
unsigned int irqcmd = EXMIMO_NOP;
unsigned long card_id; // = (unsigned long) cookie;
unsigned int pcie_control = PCIE_CONTROL2;
// check interrupt status register
//pci_read_config_word(pdev[0],6 , &irqval);
// find card_id. cookie is set by request_irq and static, so we will always find it
for (card_id=0; card_id<MAX_CARDS; card_id++)
if ( pdev[card_id] == cookie )
break;
if (exmimo_pci_kvirt[card_id].exmimo_id_ptr->board_swrev == BOARD_SWREV_LEGACY)
pcie_control = PCIE_CONTROL1;
else
pcie_control = PCIE_CONTROL2;
//printk("irq hndl called: card_id=%i, irqval=%i\n", card_id, irqval);
// get AHBPCIE interrupt line (bit 7) to determine if IRQ was for us from ExMIMO card, or from a different device
// reading CONTROL0 will also clear this bit and the LEON-to-PC IRQ line
irqval = ioread32(bar[card_id]+PCIE_CONTROL0);
irqcmd = ioread32(bar[card_id]+pcie_control);
//printk("IRQ handler: ctrl0: %08x, ctrl1: %08x, ctrl2: %08x, status: %08x\n", irqval, ioread32(bar[card_id]+PCIE_CONTROL1), ioread32(bar[card_id]+PCIE_CONTROL2), ioread32(bar[card_id]+PCIE_STATUS));
if ( (irqval & 0x80) == 0 ) { // CTRL0.bit7 is no set -> IRQ is not from ExMIMO i.e. not for us
if (exmimo_pci_kvirt[card_id].exmimo_id_ptr->board_swrev == BOARD_SWREV_CMDREGISTERS) {
if (irqcmd != EXMIMO_NOP && irqcmd != EXMIMO_CONTROL2_COOKIE) {
if (irqcmd == GET_FRAME_DONE) {
get_frame_done = 1;
}
openair_tasklet.data = card_id;
tasklet_schedule(&openair_tasklet);
openair_bh_cnt++;
return IRQ_HANDLED;
} else {
return IRQ_NONE;
}
} else
return IRQ_NONE;
} else {
if (exmimo_pci_kvirt[card_id].exmimo_id_ptr->board_swrev == BOARD_SWREV_LEGACY) {
// clear PCIE interrupt (bit 7 of register 0x0)
iowrite32(irqval&0xffffff7f,bar[card_id]+PCIE_CONTROL0);
}
if (irqcmd == GET_FRAME_DONE) {
get_frame_done = 1;
}
openair_tasklet.data = card_id;
tasklet_schedule(&openair_tasklet);
openair_bh_cnt++;
return IRQ_HANDLED;
}
}
void openair_do_tasklet (unsigned long card_id)
{
int save_irq_cnt = openair_bh_cnt;
unsigned int irqcmd;
unsigned int pcie_control = PCIE_CONTROL2;
openair_bh_cnt = 0;
if (exmimo_pci_kvirt[card_id].exmimo_id_ptr->board_swrev == BOARD_SWREV_LEGACY)
pcie_control = PCIE_CONTROL1;
else
pcie_control = PCIE_CONTROL2;
irqcmd = ioread32(bar[card_id]+pcie_control);
if (save_irq_cnt > 1)
printk("[openair][IRQ tasklet(%ld)]: Warning: received more than 1 PCIE IRQ (openair_bh_cnt=%i), only the last one is acted upon(irqcmd= %i (0x%X)\n", card_id, openair_bh_cnt, irqcmd, irqcmd);
switch( irqcmd ) {
case PCI_PRINTK:
// printk("Got PCIe interrupt for printk ...\n");
pcie_printk((int) card_id);
break;
case GET_FRAME_DONE:
printk("[openair][IRQ tasklet] : Got PCIe interrupt for GET_FRAME_DONE ...\n");
break;
case EXMIMO_NOP:
printk("[openair][IRQ tasklet] : Received IRQ, with CONTROL0.bit7(IRQ Leon2PC) set, but irqcmd = EXMIMO_NOP. This should not happen with bitstreams built after June 3rd 2013.\n");
break;
default:
printk("[openair][IRQ tasklet] : Got unknown PCIe cmd: card_id = %li, irqcmd(CONTROL1) = %i (0x%X)\n", card_id, irqcmd, irqcmd);
}
iowrite32(EXMIMO_NOP, bar[card_id]+pcie_control);
}
void pcie_printk(int card_id)
{
char *buffer = exmimo_pci_kvirt[card_id].printk_buffer_ptr;
unsigned int len = ((unsigned int *)buffer)[0];
unsigned int off=0,i;
unsigned char *dword;
unsigned char tmp;
//printk("In pci_fifo_printk : buffer %p, len %d: \n",buffer,len);
printk("[LEON card%d]: ", card_id);
if (len<1024) {
if ( (len&3) >0 )
off=1;
for (i=0; i<(off+(len>>2)); i++) {
dword = &((unsigned char *)buffer)[(1+i)<<2];
tmp = dword[3];
dword[3] = dword[0];
dword[0] = tmp;
tmp = dword[2];
dword[2] = dword[1];
dword[1] = tmp;
}
for (i=0; i<len; i++)
printk("%c",((char*)&buffer[4])[i]);
}
}
@@ -1,350 +0,0 @@
/*
* 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
*/
/** module_main.c (was: device.c)
*
* Main Kernel module functions for load/init and cleanup of the kernel driver
*
* Supports multiple ExpressMIMO cards
*
* Authors: Matthias Ihmig <matthias.ihmig@mytum.de>, 2012, 2013
* Riadh Ghaddab <riadh.ghaddab@eurecom.fr>
* Raymond Knopp <raymond.knopp@eurecom.fr>
*
* Changelog:
* 14.01.2013: removed remaining of BIGPHYS stuff and replaced with pci_alloc_consistent
* 20.01.2013: added support for multiple cards
* 24.01.2013: restructured interfaces & structures of how physical and virtual pointers are handled
*/
#include "openair_device.h"
#include "defs.h"
#include "vars.h"
#include <linux/moduleparam.h>
#include <linux/interrupt.h>
#include <linux/aer.h>
#include <linux/pci_regs.h>
#include <linux/delay.h>
static void openair_cleanup(void);
extern irqreturn_t openair_irq_handler(int irq, void *cookie);
static int irq = 0;
module_param(irq,int,S_IRUSR|S_IWUSR);
static struct file_operations openair_fops = {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)
unlocked_ioctl:openair_device_ioctl,
#else
ioctl: openair_device_ioctl,
#endif
open: openair_device_open,
release:openair_device_release,
mmap: openair_device_mmap
};
static int __init openair_init_module( void )
{
int res = 0;
unsigned int readback;
unsigned int card, j;
unsigned int vid,did;
unsigned short vendor, subid;
exmimo_id_t exmimo_id_tmp[MAX_CARDS];
//------------------------------------------------
// Find and enable ExpressMIMO PCI cards
//------------------------------------------------
//
card = 0;
pdev[card] = pci_get_device(XILINX_VENDOR, XILINX_ID, NULL);
if( pdev[card] ) {
// This print does not work for 64 bit kernels
// printk("[openair][INIT_MODULE][INFO]: openair card (ExpressMIMO) %d found, bus 0x%x, primary 0x%x, secondary 0x%x\n",card,
// pdev[card]->bus->number, pdev[card]->bus->primary,pdev[card]->bus->secondary);
pci_read_config_word(pdev[card], PCI_SUBSYSTEM_ID, &subid);
pci_read_config_word(pdev[card], PCI_SUBSYSTEM_VENDOR_ID, &vendor);
exmimo_id_tmp[card].board_vendor = vendor;
if ( exmimo_id_tmp[card].board_vendor == XILINX_VENDOR )
exmimo_id_tmp[card].board_vendor = EURECOM_VENDOR; // set default to EURECOM
exmimo_id_tmp[card].board_exmimoversion = (subid >> 12) & 0x0F;
if (exmimo_id_tmp[card].board_exmimoversion == 0)
exmimo_id_tmp[card].board_exmimoversion = 1; // default (for old bitstreams) is ExpressMIMO-1
exmimo_id_tmp[card].board_hwrev = (subid >> 8) & 0x0F;
exmimo_id_tmp[card].board_swrev = (subid ) & 0xFF;
printk("[openair][INIT_MODULE][INFO]: card %d: ExpressMIMO-%i (HW Rev %i), Bitstream: %s, SW/Protocol Revision: 0x%02X\n", card,
exmimo_id_tmp[card].board_exmimoversion, exmimo_id_tmp[card].board_hwrev, ( (exmimo_id_tmp[card].board_vendor == EURECOM_VENDOR) ? "Eurecom" : "Telecom Paristech"), exmimo_id_tmp[card].board_swrev );
card++;
vid = XILINX_VENDOR;
did = XILINX_ID;
} else {
printk("[openair][INIT_MODULE][INFO]: no card found, stopping.\n");
return -ENODEV;
}
// Now look for more cards on the same bus
while (card<MAX_CARDS) {
pdev[card] = pci_get_device(vid,did, pdev[card-1]);
if(pdev[card]) {
// This print does not work for 64 bit kernels
// printk("[openair][INIT_MODULE][INFO]: openair card %d found, bus 0x%x, primary 0x%x, secondary 0x%x\n",card,
// pdev[card]->bus->number,pdev[card]->bus->primary,pdev[card]->bus->secondary);
pci_read_config_word(pdev[card], PCI_SUBSYSTEM_ID, &subid);
pci_read_config_word(pdev[card], PCI_SUBSYSTEM_VENDOR_ID, &vendor);
exmimo_id_tmp[card].board_vendor = vendor;
if ( exmimo_id_tmp[card].board_vendor == XILINX_VENDOR )
exmimo_id_tmp[card].board_vendor = EURECOM_VENDOR; // default (for old bitstreams) is EURECOM_VENDOR
exmimo_id_tmp[card].board_exmimoversion = (subid >> 12) & 0x0F;
if (exmimo_id_tmp[card].board_exmimoversion == 0)
exmimo_id_tmp[card].board_exmimoversion = 1; // default (for old bitstreams) is ExpressMIMO-1
exmimo_id_tmp[card].board_hwrev = (subid >> 8) & 0x0F;
exmimo_id_tmp[card].board_swrev = (subid ) & 0xFF;
printk("[openair][INIT_MODULE][INFO]: card %d: ExpressMIMO-%i (HW Rev %i), Bitstream: %s, SW/Protocol Revision: 0x%02X\n", card,
exmimo_id_tmp[card].board_exmimoversion, exmimo_id_tmp[card].board_hwrev, ( (exmimo_id_tmp[card].board_vendor == EURECOM_VENDOR) ? "Eurecom" : "Telecom Paristech"), exmimo_id_tmp[card].board_swrev );
card++;
} else
break;
}
// at least one device found, enable it
number_of_cards = card;
for (card=0; card<number_of_cards; card++) {
if( pci_enable_device(pdev[card]) ) {
printk("[openair][INIT_MODULE][INFO]: Could not enable PCI card device %d\n",card);
openair_cleanup();
return -ENODEV;
} else {
printk("[openair][INIT_MODULE][INFO]: *** CARD DEVICE %d (pdev=%p) ENABLED, irq %d\n",card,pdev[card],irq);
printk("[openair][INIT_MODULE][INFO]: *** CARD DEVICE %d (pdev=%p) ENABLED, irq %d\n",card,pdev[card],pdev[card]->irq);
openair_pci_device_enabled[card] = 1;
}
// Make the FPGA to a PCI master
pci_set_master(pdev[card]);
// set DMA mask
if (!pci_set_dma_mask(pdev[card], DMA_BIT_MASK(32))) {
if (pci_set_consistent_dma_mask(pdev[card], DMA_BIT_MASK(32))) {
printk(KERN_INFO "[openair][INIT_MODULE]: Unable to obtain 32bit DMA for consistent allocations\n");
openair_cleanup();
return -EIO;
}
}
//if (pci_enable_pcie_error_reporting(pdev[card]) > 0)
// printk("[openair][INIT_MODULE][INFO]: Enabled PCIe error reporting\n");
//else
// printk("[openair][INIT_MODULE][INFO]: Failed to enable PCIe error reporting\n");
//pci_cleanup_aer_uncorrect_error_status(pdev[card]);
mmio_start[card] = pci_resource_start(pdev[card], 0); // get start of BAR0
mmio_length[card] = pci_resource_len (pdev[card], 0);
mmio_flags[card] = pci_resource_flags(pdev[card], 0);
if (check_mem_region(mmio_start[card],256) < 0) {
printk("[openair][INIT_MODULE][FATAL] : Cannot get memory region 0, aborting\n");
mmio_start[card] = 0;
openair_cleanup();
return -EBUSY;
} else
printk("[openair][INIT_MODULE][INFO] : Reserving memory region 0 : mmio_start = 0x%x\n",(unsigned int)mmio_start[card]);
request_mem_region(mmio_start[card], 256, "openair_rf");
bar[card] = pci_iomap( pdev[card], 0, mmio_length[card] ); // get virtual kernel address for BAR0
printk("[openair][INIT_MODULE][INFO]: BAR0 card %d = 0x%p\n", card, bar[card]);
printk("[openair][INIT_MODULE][INFO]: Writing 0x%x to BAR0+0x1c (PCIBASEL)\n", 0x12345678);
iowrite32( 0x12345678, (bar[card]+PCIE_PCIBASEL) );
udelay(100);
readback = ioread32( bar[card]+PCIE_PCIBASEL );
if (readback != 0x12345678) {
printk("[openair][INIT_MODULE][INFO]: Readback of FPGA register failed (%x)\n",readback);
openair_cleanup();
return -EIO;
}
iowrite32((1<<8), bar[card] +PCIE_CONTROL0 ); // bit8=AHBPCIE_CTL0_SOFTRESET, but what is bit9 and bit10?
udelay(1000);
readback = ioread32( bar[card] +PCIE_CONTROL0);
printk("CONTROL0 readback %x\n",readback);
// allocating buffers
if ( exmimo_memory_alloc( card ) ) {
printk("[openair][MODULE][ERROR] exmimo_memory_alloc() failed!\n");
openair_cleanup();
return -ENOMEM;
}
exmimo_pci_kvirt[card].exmimo_id_ptr->board_vendor = exmimo_id_tmp[card].board_vendor;
exmimo_pci_kvirt[card].exmimo_id_ptr->board_exmimoversion = exmimo_id_tmp[card].board_exmimoversion;
exmimo_pci_kvirt[card].exmimo_id_ptr->board_hwrev = exmimo_id_tmp[card].board_hwrev;
exmimo_pci_kvirt[card].exmimo_id_ptr->board_swrev = exmimo_id_tmp[card].board_swrev;
if (irq!=0)
printk("[OPENAIR][SCHED][INIT] card %d: Trying to get IRQ %d\n", card,irq);
else
printk("[OPENAIR][SCHED][INIT] card %d: Trying to get IRQ %d\n", card, pdev[card]->irq);
openair_irq_enabled[card] = 0;
// #ifdef CONFIG_PREEMPT_RT doesn't work -> fix misconfigured header files?
#if 1
if (irq!=0) {
if ( (res = request_irq(irq, openair_irq_handler,
IRQF_SHARED , "openair_rf", pdev[card] )) == 0) {
openair_irq_enabled[card] = 1;
} else {
printk("[EXMIMO][SCHED][INIT] Cannot get IRQ %d for HW, error: %d\n", irq, res);
openair_cleanup();
return -EBUSY;
}
} else {
if ( (res = request_irq(pdev[card]->irq, openair_irq_handler,
IRQF_SHARED , "openair_rf", pdev[card] )) == 0) {
openair_irq_enabled[card] = 1;
} else {
printk("[EXMIMO][SCHED][INIT] Cannot get IRQ %d for HW, error: %d\n", pdev[card]->irq, res);
openair_cleanup();
return -EBUSY;
}
}
#else
printk("Warning: didn't request IRQ for PREEMPT_REALTIME\n");
#endif
} // for (i=0; i<number_of_cards; i++)
//------------------------------------------------
// Register the device in /dev
//------------------------------------------------
//
major = openair_MAJOR;
if( (res = register_chrdev(major, "openair", &openair_fops )) < 0) {
printk("[openair][INIT_MODULE][ERROR]: can't register char device driver, major : %d, error: %d\n", major, res);
for (j=0; j<=number_of_cards; j++)
release_mem_region(mmio_start[j],256);
return -EBUSY;
} else {
printk("[openair][INIT_MODULE][INFO]: char device driver registered major : %d\n", major);
openair_chrdev_registered = 1;
}
printk("[openair][MODULE][INFO] Initializing Leon (EXMIMO_PCIE_INIT) on all cards...\n");
for (card=0; card<number_of_cards; card++)
exmimo_firmware_init( card );
printk("[openair][MODULE][INFO] Done module init\n");
return 0;
}
static void __exit openair_cleanup_module(void)
{
//int card;
printk("[openair][CLEANUP MODULE]\n");
// stop any ongoing acquisition
//for (card = 0; card < number_of_cards; card++)
// exmimo_send_pccmd(card, EXMIMO_STOP);
openair_cleanup();
}
static void openair_cleanup(void)
{
int card;
if ( openair_chrdev_registered )
unregister_chrdev(major,"openair");
openair_chrdev_registered = 0;
for (card=0; card<number_of_cards; card++) {
// unregister interrupt
if ( openair_irq_enabled[card] ) {
printk("[openair][CLEANUP] disabling interrupt card %d\n", card);
if (irq!=0)
free_irq(irq, pdev[card] );
else
free_irq( pdev[card]->irq, pdev[card] );
openair_irq_enabled[card] = 0;
}
exmimo_firmware_cleanup( card );
if ( bar[card] ) {
printk("unmap bar[%d] %p\n", card, bar[card]);
iounmap((void *)bar[card]);
}
if ( mmio_start[card] ) {
printk("release mem[%d] %x\n", card, (unsigned int)mmio_start[card]);
release_mem_region(mmio_start[card],256);
}
if ( openair_pci_device_enabled[card] ) {
printk("pci_disable_device %i\n", card);
pci_disable_device( pdev[card] );
}
}
}
MODULE_AUTHOR ("Raymond KNOPP <raymond.knopp@eurecom.fr>, Matthias IHMIG <matthias.ihmig@eurecom.fr>, Florian KALTENBERGER <florian.kaltenberger@eurecom.fr>, Riadh GHADDAB <riadh.ghaddab@eurecom.fr>");
MODULE_DESCRIPTION ("openair ExpressMIMO/ExpressMIMO3 driver");
MODULE_LICENSE ("GPL");
module_init (openair_init_module);
module_exit (openair_cleanup_module);
@@ -1,12 +0,0 @@
#!/bin/bash
PCI=`lspci -m | grep Xilinx`
if [ -z "$PCI" ]; then
echo "No card found. Stopping!"
return
fi
SLOT_NUMBER=`echo $PCI | awk -F\" '{print $1}'`
setpci -s $SLOT_NUMBER 60.b=10
-62
View File
@@ -1,62 +0,0 @@
/*
* 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
*/
#ifndef __VARS_H__
#define __VARS_H__
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci.h>
#ifdef KERNEL2_6
#include <linux/slab.h>
#endif
#include "defs.h"
#include "pcie_interface.h"
unsigned int openair_irq_enabled[MAX_CARDS] = INIT_ZEROS;
unsigned int openair_chrdev_registered = 0;
unsigned int openair_pci_device_enabled[MAX_CARDS] = INIT_ZEROS;
struct pci_dev *pdev[MAX_CARDS] = INIT_ZEROS;
void __iomem *bar[MAX_CARDS] = INIT_ZEROS;
resource_size_t mmio_start[MAX_CARDS] = INIT_ZEROS;
resource_size_t mmio_length[MAX_CARDS];
unsigned int mmio_flags[MAX_CARDS];
int major;
char number_of_cards;
// bigshm allocs a single larger block, used for shared structures and pointers
dma_addr_t bigshm_head_phys[MAX_CARDS] = INIT_ZEROS;
void *bigshm_head[MAX_CARDS] = INIT_ZEROS;
void *bigshm_currentptr[MAX_CARDS];
dma_addr_t pphys_exmimo_pci_phys[MAX_CARDS]; // phys pointer to pci_bot structure in shared mem
exmimo_pci_interface_bot_t *p_exmimo_pci_phys[MAX_CARDS] = INIT_ZEROS; // inside struct has physical (DMA) pointers to pci_bot memory blocks
exmimo_pci_interface_bot_virtual_t exmimo_pci_kvirt[MAX_CARDS]; // has virtual pointers to pci_bot memory blocks
#endif
-19
View File
@@ -1,19 +0,0 @@
Here are the PC kernel drivers.
Currently, there are two drivers:
telecomparistech/
---
- supports the new ExpressMIMO-1 bitstream by Telecom Paristech
- uses command two command FIFOs to pass commands between Leon<->PC
eurecom/
---
- supports the legacy ExpressMIMO-1 bitstream
- supports ExpressMIMO-2, also multiple cards for sample-synchronous acquisition
- uses CONTROLx registers to pass commands between Leon<->PC
- allocates buffers in kernel space using pci_alloc_consistent
- used by ../USERSPACE/LIB/openair0_lib for simple access through userspace
@@ -1,7 +0,0 @@
obj-m += em1.o
em1-objs = em1_drv.o em1_fifos.o em1_rw.o em1_dev.o em1_ioctl.o em1_mmap.o
default:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
@@ -1,185 +0,0 @@
/*
* 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 "em1_drv.h"
static irqreturn_t irq_handler(int irq, void *dev_id)
{
uint32_t irqval;
irqreturn_t res = IRQ_NONE;
struct em1_private_s *pv = dev_id;
spin_lock(&pv->lock);
irqval = ioread32(pv->base + REG_ISTATUS);
if (irqval & IRQ_MSK) {
// printk(KERN_DEBUG "em1 irqval 0x%x", irqval);
if ((irqval & EM1_NOTFULL_IRQ) && (pv->busy & EM1_BUSY_FIFO_W)) {
wake_up_all(&pv->rq_wait_fifo_w);
res = IRQ_HANDLED;
}
if ((irqval & EM1_NOTEMPTY_IRQ) && (pv->busy & EM1_BUSY_FIFO_R)) {
wake_up_all(&pv->rq_wait_fifo_r);
res = IRQ_HANDLED;
}
if (irqval & EM1_DMA_IRQ) {
pv->dma_done = irqval >> 16;
wake_up_all(&pv->rq_wait_dma);
res = IRQ_HANDLED;
}
}
spin_unlock(&pv->lock);
return res;
}
int __devinit em1_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
int ret, i;
resource_size_t len, start;
struct em1_private_s *pv;
for (i = 0; i < MAX_EM1_DEVICES; i++)
if (em1_devices[i] == NULL)
goto found;
printk("exmimo1 : Too many devices");
return -ENOENT;
found:
pv = kmalloc(sizeof(struct em1_private_s), GFP_KERNEL);
em1_devices[i] = pv;
if (pv == NULL) {
printk(KERN_ERR "exmimo1 : Out of memory\n");
return -ENOMEM;
}
pci_set_drvdata(dev, pv);
ret = pci_enable_device(dev);
if (ret <0) {
printk(KERN_WARNING "exmimo1 : Problem when enabling PCI device\n");
goto err_kfree;
}
/* Set interrupt handler function */
ret = request_irq(dev->irq, &irq_handler, IRQF_SHARED, "exmimo1", pv);
if (ret <0) {
printk(KERN_WARNING "exmimo1 : Problem when requesting interrupt for PCI device\n");
goto err_disable;
}
/* Address of first PCI BAR region */
len = pci_resource_len(dev, 0);
start = pci_resource_start(dev, 0);
printk("exmimo1 : len : %d\n", len);
printk("exmimo1 : start : %x\n", start);
if (check_mem_region(start, len) < 0) {
printk(KERN_ERR "exmimo1 : Cannot check memory region 0, already in use\n");
ret = -ENOMEM;
goto err_req_irq;
}
if (request_mem_region(start, len, "exmimo") == NULL) {
printk(KERN_ERR "exmimo1 : Cannot get memory region 0, already in use\n");
ret = -ENOMEM;
goto err_req_irq;
}
pv->base = pci_iomap(dev, 0, len);
printk(KERN_DEBUG "exmimo1 : base address := 0x%x\n", (unsigned int)pv->base);
pci_set_master(dev);
init_waitqueue_head(&pv->rq_wait_fifo_r);
init_waitqueue_head(&pv->rq_wait_fifo_w);
init_waitqueue_head(&pv->rq_wait_dma);
pv->ie = 0;
pv->busy = 0;
pv->fifo_read_left = 0;
pv->fifo_write_left = 0;
spin_lock_init(&pv->lock);
pv->dev = &dev->dev;
pv->pdev = dev;
/* Get DMA done counter */
pv->dma_started = pv->dma_done = ioread32(pv->base + REG_ISTATUS) >> 16;
/* Disable interrupt */
iowrite32(pv->ie, pv->base + REG_FSTATUS);
return 0;
err_req_irq:
free_irq(dev->irq, pv);
err_disable:
pci_disable_device(dev);
err_kfree:
kfree(pv);
em1_devices[i] = NULL;
return ret;
}
void __devexit em1_remove(struct pci_dev *dev)
{
int i;
struct em1_private_s *pv = pci_get_drvdata(dev);
resource_size_t len, start;
printk(KERN_DEBUG "exmimo1 : remove()\n");
iounmap((void*)pv->base);
/* Address of first PCI BAR region */
len = pci_resource_len(dev, 0);
start = pci_resource_start(dev, 0);
release_mem_region(start, len);
// Unregister interrupt
free_irq(dev->irq, pv);
pci_disable_device(dev);
//Free private data
kfree(pv);
for (i = 0; i < MAX_EM1_DEVICES; i++)
if (em1_devices[i] == pv)
em1_devices[i] = NULL;
}
/*
* Local Variables:
* c-file-style: "linux"
* indent-tabs-mode: t
* tab-width: 8
* End:
*/
@@ -1,181 +0,0 @@
/*
* 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 "em1_drv.h"
MODULE_AUTHOR("Alexandre Becoulet, Cerdan Sebastien");
MODULE_DESCRIPTION("Driver for Express-Mimo 1 board");
MODULE_SUPPORTED_DEVICE("Express-Mimo 1");
MODULE_LICENSE("GPL");
static int major = 256;
struct em1_private_s *em1_devices[MAX_EM1_DEVICES] = {};
int em1_user_op_enter(struct em1_private_s *pv, wait_queue_t *wait,
wait_queue_head_t *wh, int busy_flag, int new_state)
{
add_wait_queue(wh, wait);
spin_lock_irq(&pv->lock);
/* wait for other tasks to leave */
while (pv->busy & busy_flag) {
if (new_state == TASK_INTERRUPTIBLE &&
signal_pending(current))
return 1;
set_current_state(new_state);
spin_unlock_irq(&pv->lock);
schedule();
spin_lock_irq(&pv->lock);
}
pv->busy |= busy_flag;
return 0;
}
void em1_user_op_leave(struct em1_private_s *pv, wait_queue_t *wait,
wait_queue_head_t *wh)
{
set_current_state(TASK_RUNNING);
spin_unlock_irq(&pv->lock);
remove_wait_queue(wh, wait);
// wake other waiting tasks
wake_up_all(wh);
}
static int em1_open(struct inode *inode, struct file *file)
{
int i;
//FIXME Lock list access
for (i = 0; i < MAX_EM1_DEVICES; i++) {
struct em1_private_s *pv = em1_devices[i];
if (pv != NULL && i == iminor(inode)) {
struct em1_file_s *fpv = kmalloc(sizeof(struct em1_file_s), GFP_KERNEL);
if (!fpv)
return -ENOMEM;
printk(KERN_DEBUG "exmimo1 : open()\n");
fpv->pv = pv;
file->private_data = fpv;
fpv->read.addr = 0;
fpv->write.addr = 0;
memset(fpv->mmap_list, 0, sizeof(fpv->mmap_list));
return 0;
}
}
return -ENODEV;
}
static int em1_release(struct inode *inode, struct file *file)
{
int i;
struct em1_file_s *fpv = file->private_data;
em1_unlock_user_page(&fpv->read);
em1_unlock_user_page(&fpv->write);
for (i = 0; i < MAX_EM1_MMAP; i++)
if (fpv->mmap_list[i].virt) {
struct em1_mmap_ctx * mctx = fpv->mmap_list + i;
pci_free_consistent(fpv->pv->pdev, mctx->size, mctx->virt, mctx->phys);
}
kfree(fpv);
printk(KERN_DEBUG "exmimo1 : release()\n");
return 0;
}
static const struct file_operations em1_fops = {
.read = em1_read,
.write = em1_write,
.open = em1_open,
.release = em1_release,
.ioctl = em1_ioctl,
.mmap = em1_mmap,
};
/* Supported devices */
static struct pci_device_id em1_pci_tbl[] = {
{ XILINX_VENDOR, XILINX_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0,}
};
MODULE_DEVICE_TABLE(pci, em1_pci_tbl);
static struct pci_driver em1_driver = {
.name = "exmimo1",
.id_table = em1_pci_tbl,
.probe = em1_probe,
.remove = em1_remove,
};
static int __init em1_init(void)
{
int ret;
printk(KERN_DEBUG "exmimo1 : Hello world!\n");
ret = pci_register_driver(&em1_driver);
if (ret < 0) {
printk(KERN_ERR "exmimo1 : Error when registering PCI driver\n");
goto err;
}
ret = register_chrdev(major, "exmimo1", &em1_fops);
if (ret < 0) {
printk(KERN_ERR "exmimo1 : Error when registering char device\n");
goto err;
}
err:
return ret;
}
static void __exit em1_cleanup(void)
{
printk(KERN_DEBUG "exmimo1 : Goodbye world!\n");
unregister_chrdev(major, "exmimo1");
pci_unregister_driver(&em1_driver);
}
module_init(em1_init);
module_exit(em1_cleanup);
/*
* Local Variables:
* c-file-style: "linux"
* indent-tabs-mode: t
* tab-width: 8
* End:
*/
@@ -1,185 +0,0 @@
/*
* 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
*/
#ifndef USER_APP
#include <linux/uaccess.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/list.h>
#include <linux/pci.h>
#include <linux/blkdev.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/spinlock_types.h>
#include <linux/interrupt.h>
/*
Operations:
- DMA from pc to em1: The Linux driver writes a 4 words command to
the control fifo [0x103 phys_hi phys_lo size] and waits for a DMA
end interrupt from the em1 board.
This operation is requested by the user application using the
write syscall. The buffer provided by the application must not
span across multiple pages.
- DMA from em1 to pc: The Linux driver writes a 4 words command to
the control fifo [0x203 phys_hi phys_lo size] and waits for a DMA
end interrupt from the em1 board.
This operation is requested by the user application using the read
syscall. The buffer provided by the application must not span
across multiple pages.
*/
#define XILINX_VENDOR 0x10ee
#define XILINX_ID 0x0007
#define REG_FCMD 0x0
#define REG_FSTATUS 0x4
#define REG_ISTATUS 0x8
#define REG_STATUS 0x10
#define REG_PCI_BASE_L 0x28
#define REG_PCI_BASE_H 0x2c
#define PUSH_FULL_STATUS_MSK (1 << 3)
#define POP_EMPTY_STATUS_MSK (1 << 2)
#define EM1_NOTFULL_IRQ (1 << 0)
#define EM1_NOTEMPTY_IRQ (1 << 1)
#define EM1_DMA_IRQ (1 << 2)
#define PUSH_NO_FULL_IRQ_MSK (1 << 19)
#define POP_NO_EMPTY_IRQ_MSK (1 << 18)
#define IRQ_MSK 7
#define EM1_CMD_OP_DMA_PC2EM1 0x0100
#define EM1_CMD_OP_DMA_EM12PC 0x0200
#define MAX_EM1_DEVICES 8
#define MAX_EM1_MMAP 4
#define EM1_BUSY_FIFO_R 1
#define EM1_BUSY_FIFO_W 2
#define EM1_BUSY_DMA 4
struct em1_private_s;
struct em1_page_s {
uintptr_t addr;
struct page *page;
};
struct em1_mmap_ctx {
void* virt;
dma_addr_t phys;
size_t size;
};
struct em1_file_s {
struct em1_private_s *pv;
struct em1_page_s read;
struct em1_page_s write;
struct em1_mmap_ctx mmap_list[MAX_EM1_MMAP];
};
struct em1_private_s {
struct pci_dev *pdev;
struct device *dev;
spinlock_t lock;
/* memeory mapped device base address */
void * base;
/* wait queues */
wait_queue_head_t rq_wait_fifo_r;
wait_queue_head_t rq_wait_fifo_w;
wait_queue_head_t rq_wait_dma;
/* Number of fifo words left to read or write */
size_t fifo_read_left;
size_t fifo_write_left;
/* Cached interrupt enabled value */
uint32_t ie;
/* Driver busy operations flags */
int busy;
/* Completed DMA transfer counters */
uint16_t dma_started, dma_done;
};
extern struct em1_private_s *em1_devices[MAX_EM1_DEVICES];
/* em1_drv.c */
int em1_user_op_enter(struct em1_private_s *pv, wait_queue_t *wait,
wait_queue_head_t *wh, int busy_flag, int new_state);
void em1_user_op_leave(struct em1_private_s *pv, wait_queue_t *wait,
wait_queue_head_t *wh);
/* em1_rw.c: read and write syscalls */
int em1_lock_user_page(struct em1_page_s *ep, uintptr_t addr, int direction);
void em1_unlock_user_page(struct em1_page_s *fpv);
ssize_t em1_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos);
ssize_t em1_read(struct file *file, char __user *buf, size_t size, loff_t *ppos);
/* em1_dev.c */
int __devinit em1_probe(struct pci_dev *dev, const struct pci_device_id *id);
void __devexit em1_remove(struct pci_dev *dev);
/* em1_fifos.c */
int em1_fifo_write(struct em1_private_s *pv, const uint32_t *buf, size_t count);
int em1_fifo_read(struct em1_private_s *pv, uint32_t *buf, size_t count);
/* em1_ioctl.c */
int em1_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg);
/* em1_mmap.c */
int em1_mmap(struct file *filp, struct vm_area_struct *vma);
#endif
enum em1_ioctl_cmd {
EM1_IOCTL_FIFO_WRITE,
EM1_IOCTL_FIFO_READ,
};
#define EM1_MAX_FIFO_PAYLOAD 128
struct em1_ioctl_fifo_params {
uint32_t *words;
size_t count;
};
/*
* Local Variables:
* c-file-style: "linux"
* indent-tabs-mode: t
* tab-width: 8
* End:
*/
@@ -1,5 +0,0 @@
#!/bin/sh
sudo insmod em1.ko
sudo mknod /dev/exmimo1 c 256 0
sudo chmod 666 /dev/exmimo1
@@ -1,110 +0,0 @@
/*
* 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 "em1_drv.h"
int em1_fifo_write(struct em1_private_s *pv, const uint32_t *buf, size_t count)
{
int retval = 0;
size_t cnt = count;
while (cnt > 0) {
//read fifo state register
uint32_t data = ioread32(pv->base + REG_FSTATUS);
if (data & PUSH_FULL_STATUS_MSK) {
/* Enable push fifo no full interrupt */
pv->ie |= PUSH_NO_FULL_IRQ_MSK;
iowrite32(pv->ie, pv->base + REG_FSTATUS);
set_current_state(TASK_UNINTERRUPTIBLE);
spin_unlock_irq(&pv->lock);
// printk(KERN_DEBUG "sleep %08x %i", data, current->state);
schedule();
// printk(KERN_DEBUG "wake");
spin_lock_irq(&pv->lock);
continue;
}
data = *buf++;
cnt--;
iowrite32(data, pv->base + REG_FCMD);
if (!pv->fifo_write_left) {
/* Size must be retrieved from POP fifo entry */
pv->fifo_write_left = data & 0xFF;
} else {
pv->fifo_write_left--;
}
if (!pv->fifo_write_left)
break;
}
pv->ie &= ~PUSH_NO_FULL_IRQ_MSK;
iowrite32(pv->ie, pv->base + REG_FSTATUS);
return retval;
}
int em1_fifo_read(struct em1_private_s *pv, uint32_t *buf, size_t count)
{
int retval = 0;
size_t cnt = count;
while (cnt > 0) {
//read fifo state register
uint32_t data = ioread32(pv->base + REG_FSTATUS);
if (data & POP_EMPTY_STATUS_MSK) {
/* Enable pop fifo no empty interrupt */
pv->ie |= POP_NO_EMPTY_IRQ_MSK;
iowrite32(pv->ie, pv->base + REG_FSTATUS);
set_current_state(TASK_UNINTERRUPTIBLE);
spin_unlock_irq(&pv->lock);
schedule();
spin_lock_irq(&pv->lock);
continue;
}
data = ioread32(pv->base + REG_FCMD);
*buf++ = data;
cnt--;
if (!pv->fifo_read_left) {
/* Size must be retrieved from POP fifo entry */
pv->fifo_read_left = data & 0xFF;
} else {
pv->fifo_read_left--;
}
if (!pv->fifo_read_left)
break;
}
pv->ie &= ~POP_NO_EMPTY_IRQ_MSK;
iowrite32(pv->ie, pv->base + REG_FSTATUS);
return retval;
}
@@ -1,111 +0,0 @@
/*
* 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 "em1_drv.h"
static int em1_ioctl_fifo_write(struct em1_private_s *pv, size_t size, uint32_t *words)
{
DECLARE_WAITQUEUE(wait, current);
int res = -ERESTARTSYS;
if (!em1_user_op_enter(pv, &wait, &pv->rq_wait_fifo_w,
EM1_BUSY_FIFO_W, TASK_INTERRUPTIBLE)) {
res = em1_fifo_write(pv, words, size);
res = 0;
pv->busy &= ~EM1_BUSY_FIFO_W;
}
em1_user_op_leave(pv, &wait, &pv->rq_wait_fifo_w);
return res;
}
static int em1_ioctl_fifo_read(struct em1_private_s *pv, size_t size, uint32_t *words)
{
DECLARE_WAITQUEUE(wait, current);
int res = -ERESTARTSYS;
if (!em1_user_op_enter(pv, &wait, &pv->rq_wait_fifo_r,
EM1_BUSY_FIFO_R, TASK_INTERRUPTIBLE)) {
res = em1_fifo_read(pv, words, size);
pv->busy &= ~EM1_BUSY_FIFO_R;
}
em1_user_op_leave(pv, &wait, &pv->rq_wait_fifo_r);
return res;
}
int em1_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct em1_file_s *fpv = file->private_data;
struct em1_private_s *pv = fpv->pv;
switch ((enum em1_ioctl_cmd)cmd) {
case EM1_IOCTL_FIFO_WRITE: {
struct em1_ioctl_fifo_params p;
uint32_t w[EM1_MAX_FIFO_PAYLOAD];
if (copy_from_user(&p, (void*)arg, sizeof(p)))
return -EFAULT;
if (p.count > EM1_MAX_FIFO_PAYLOAD)
return -EINVAL;
if (copy_from_user(w, p.words, p.count * sizeof(uint32_t)))
return -EFAULT;
return em1_ioctl_fifo_write(pv, p.count, w);
}
case EM1_IOCTL_FIFO_READ: {
struct em1_ioctl_fifo_params p;
uint32_t w[EM1_MAX_FIFO_PAYLOAD];
int res;
if (copy_from_user(&p, (void*)arg, sizeof(p)))
return -EFAULT;
if (p.count > EM1_MAX_FIFO_PAYLOAD)
return -EINVAL;
res = em1_ioctl_fifo_read(pv, p.count, w);
if (!res && copy_to_user(p.words, w, p.count * sizeof(uint32_t)))
return -EFAULT;
return res;
}
}
return 0;
}
/*
* Local Variables:
* c-file-style: "linux"
* indent-tabs-mode: t
* tab-width: 8
* End:
*/
@@ -1,73 +0,0 @@
/*
* 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 "em1_drv.h"
int em1_mmap(struct file *filp, struct vm_area_struct *vma)
{
int i;
struct em1_file_s *fpv = filp->private_data;
struct em1_mmap_ctx * mctx;
size_t size = vma->vm_end - vma->vm_start;
void * virt;
dma_addr_t phys;
printk(KERN_DEBUG "exmimo1 : mmap()\n");
if (vma->vm_end <= vma->vm_start)
return -EINVAL;
for (i = 0; i < MAX_EM1_MMAP; i++) {
mctx = fpv->mmap_list + i;
if (mctx->virt == 0)
break;
}
if (i == MAX_EM1_MMAP)
return -ENOMEM;
virt = pci_alloc_consistent(fpv->pv->pdev, size, &phys);
if (virt < 0)
return -EINVAL;
if (remap_pfn_range(vma, vma->vm_start, phys >> PAGE_SHIFT, size, vma->vm_page_prot))
return -EAGAIN;
mctx->virt = virt;
mctx->phys = phys;
mctx->size = size;
return 0;
}
/*
* Local Variables:
* c-file-style: "linux"
* indent-tabs-mode: t
* tab-width: 8
* End:
*/
@@ -1,151 +0,0 @@
/*
* 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 "em1_drv.h"
void em1_unlock_user_page(struct em1_page_s *ep)
{
if (ep->addr != 0) {
// printk(KERN_DEBUG "unlocking user read page");
page_cache_release(ep->page);
ep->addr = 0;
}
}
int em1_lock_user_page(struct em1_page_s *ep, uintptr_t addr, int direction)
{
int res;
if (ep->addr == addr)
return 0;
em1_unlock_user_page(ep);
// printk(KERN_DEBUG "locking user page for addr %p", addr);
down_read(&current->mm->mmap_sem);
res = get_user_pages(current, current->mm, addr & ~(PAGE_SIZE-1),
1, direction == DMA_FROM_DEVICE,
0, /* don't force */ &ep->page, NULL);
up_read(&current->mm->mmap_sem);
if (res != 1) {
printk(KERN_ERR "exmimo1: get_user_pages error");
return -EFAULT;
}
ep->addr = addr;
return 0;
}
static ssize_t em1_dma_access(struct em1_file_s *fpv, char __user *buf,
size_t size, int direction, int opcode)
{
DECLARE_WAITQUEUE(wait, current);
struct em1_private_s *pv = fpv->pv;
uint32_t cmd[4];
uintptr_t addr = (uintptr_t)buf;
uintptr_t end = (uintptr_t)buf + size - 1;
struct em1_page_s *page;
int fres = -ERESTARTSYS;
uint16_t dma_this;
/* check single page span */
if ((addr & ~(PAGE_SIZE-1)) != (end & ~(PAGE_SIZE-1)))
return -EINVAL;
if (!access_ok(direction == DMA_FROM_DEVICE ? VERIFY_WRITE : VERIFY_READ, buf, size))
return -EFAULT;
page = direction == DMA_FROM_DEVICE ? &fpv->read : &fpv->write;
if (em1_lock_user_page(page, addr, direction))
return -EFAULT;
addr = dma_map_page(pv->dev, page->page, 0, PAGE_SIZE, direction);
/* prepare command for em1 */
cmd[0] = opcode | 3;
cmd[1] = sizeof(addr) > 4 ? (uint32_t)(addr >> 32) : 0;
cmd[2] = (uint32_t)addr;
cmd[3] = size;
if (!em1_user_op_enter(pv, &wait, &pv->rq_wait_fifo_w,
EM1_BUSY_FIFO_W, TASK_INTERRUPTIBLE)) {
/* send command */
fres = em1_fifo_write(pv, cmd, 4);
pv->busy &= ~EM1_BUSY_FIFO_W;
dma_this = ++pv->dma_started;
}
em1_user_op_leave(pv, &wait, &pv->rq_wait_fifo_w);
// printk(KERN_DEBUG "exmimo1: dma fifo write %i, addr %x", fres, addr);
if (!fres) {
if (!em1_user_op_enter(pv, &wait, &pv->rq_wait_dma,
EM1_BUSY_DMA, TASK_UNINTERRUPTIBLE)) {
// printk(KERN_DEBUG "wait dma");
/* wait for DMA end irq */
while ((int16_t)(dma_this - pv->dma_done) > 0) {
set_current_state(TASK_UNINTERRUPTIBLE);
spin_unlock_irq(&pv->lock);
schedule();
spin_lock_irq(&pv->lock);
}
pv->busy &= ~EM1_BUSY_DMA;
fres = size;
}
em1_user_op_leave(pv, &wait, &pv->rq_wait_dma);
}
dma_unmap_page(pv->dev, addr, PAGE_SIZE, direction);
if (direction == DMA_FROM_DEVICE)
SetPageDirty(page->page);
return fres;
}
ssize_t em1_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos)
{
return em1_dma_access(file->private_data, (char*)buf, size,
DMA_TO_DEVICE, EM1_CMD_OP_DMA_PC2EM1);
}
ssize_t em1_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
return em1_dma_access(file->private_data, buf, size,
DMA_FROM_DEVICE, EM1_CMD_OP_DMA_EM12PC);
}
/*
* Local Variables:
* c-file-style: "linux"
* indent-tabs-mode: t
* tab-width: 8
* End:
*/
@@ -1,15 +0,0 @@
# compiles the example
OPENAIRTARGETS_DIR ?=../../../..
OPENAIROBJS += $(OPENAIRTARGETS_DIR)/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.o
CFLAGS += -I$(OPENAIRTARGETS_DIR)/ARCH/EXMIMO/USERSPACE/LIB -I$(OPENAIRTARGETS_DIR)/ARCH/EXMIMO/DEFS
example: example.o $(OPENAIROBJS)
gcc -o $@ $(CFLAGS) -lm $(OPENAIROBJS) $<
clean:
rm -f *.o *~
rm -f example
-119
View File
@@ -1,119 +0,0 @@
/*
* 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 <stdio.h>
#include "openair0_lib.h"
exmimo_config_t *p_exmimo_config;
exmimo_id_t *p_exmimo_id;
unsigned int build_rflocal(txi, txq, rxi, rxq)
{
return (txi + txq<<6 + rxi<<12 + rxq<<18);
}
unsigned int build_rfdc(int dcoff_i_rxfe, int dcoff_q_rxfe)
{
return (dcoff_i_rxfe + dcoff_q_rxfe<<8);
}
void test_config(int card, int ant, unsigned int rf_mode)
{
p_exmimo_config->framing.eNB_flag = 0;
p_exmimo_config->framing.tdd_config = 0;
p_exmimo_config->rf.rf_freq_rx[ant] = 1907600000;
p_exmimo_config->rf.rf_freq_tx[ant] = 1907600000;;
p_exmimo_config->rf.rx_gain[ant][0] = 20;
p_exmimo_config->rf.tx_gain[ant][0] = 10;
p_exmimo_config->rf.rf_mode[ant] = rf_mode;
p_exmimo_config->rf.rf_local[ant] = build_rflocal(20,25,26,04);
p_exmimo_config->rf.rf_rxdc[ant] = build_rfdc(128, 128);
p_exmimo_config->rf.rf_vcocal[ant] = 0xE<<6 + 0xE;
openair0_dump_config( card );
}
void read_firmware_buffer(int card)
{
int i;
unsigned int *p= (unsigned int *) (openair0_exmimo_pci[card].firmware_block_ptr);
printf("firmware_buffer: \n");
for (i=0; i<0x30; i++)
printf("u32 fwbuf[%d]: value=%08X\n", i, p[i]);
}
void main(void)
{
int ret, card, ant;
unsigned int my_rf_mode;
unsigned int *p_rx_ant0, *p_tx_ant0;
ret = openair0_open();
if ( ret != 0 ) {
if (ret == -1)
printf("Error opening /dev/openair0");
if (ret == -2)
printf("Error mapping bigshm");
if (ret == -3)
printf("Error mapping RX or TX buffer");
return;
}
my_rf_mode = RXEN + TXEN + TXLPFNORM + TXLPFEN + TXLPF25 + RXLPFNORM + RXLPFEN + RXLPF25 + LNA1ON +LNAMax + RFBBNORM;
my_rf_mode += DMAMODE_RX + DMAMODE_TX;
printf ("Detected %d number of cards.\n", openair0_num_detected_cards);
card =0;
ant =0;
printf ("Will configure card %d, antenna %d\n", card, ant);
p_exmimo_config = openair0_exmimo_pci[card].exmimo_config_ptr;
p_exmimo_id = openair0_exmimo_pci[card].exmimo_id_ptr;
printf("Card %d: ExpressMIMO %d, HW Rev %d, SW Rev 0x%d\n", card, p_exmimo_id->board_exmimoversion, p_exmimo_id->board_hwrev, p_exmimo_id->board_swrev);
//read_firmware_buffer(card);
test_config( card, ant, my_rf_mode);
// pointer to data
p_rx_ant0 = openair0_exmimo_pci[ card ].adc_head[ ant ];
p_tx_ant0 = openair0_exmimo_pci[ card ].dac_head[ ant ];
// do something with the data here
openair0_close();
}
@@ -1,91 +0,0 @@
/*
* 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 "openair0_lib.h"
#include "gain_control.h"
//#define DEBUG_PHY
#ifdef DEBUG_PHY
#include "UTIL/LOG/log_extern.h"
#endif
void gain_control_all (unsigned int rx_power_fil_dB, unsigned int card) {
unsigned int ant;
for (ant=0; ant<4; ant++)
gain_control (rx_power_fil_dB,ant,card);
}
void gain_control (unsigned int rx_power_fil_dB, unsigned int ant, unsigned int card) {
exmimo_config_t *p_exmimo_config = openair0_exmimo_pci[card].exmimo_config_ptr;
unsigned int rf_mode, rx_gain, LNA;
rx_gain = p_exmimo_config->rf.rx_gain[ant][0];
rf_mode = p_exmimo_config->rf.rf_mode[ant];
LNA = rf_mode & LNAGAINMASK;
// Gain control with hysterisis
if (rx_power_fil_dB < TARGET_RX_POWER_MIN) { //increase gain
switch (LNA) {
case LNAByp:
p_exmimo_config->rf.rf_mode[ant] = (rf_mode & (~LNAGAINMASK)) | LNAMed;
break;
case LNAMed:
p_exmimo_config->rf.rf_mode[ant] = (rf_mode & (~LNAGAINMASK)) | LNAMax;
break;
case LNAMax:
p_exmimo_config->rf.rx_gain[ant][0] = min(30,rx_gain+5);
break;
default:
break;
}
} else if (rx_power_fil_dB > TARGET_RX_POWER_MAX) { //decrease gain
if (rx_gain==0) {
switch (LNA) {
case LNAMax:
p_exmimo_config->rf.rf_mode[ant] = (rf_mode & (~LNAGAINMASK)) | LNAMed;
break;
case LNAMed:
p_exmimo_config->rf.rf_mode[ant] = (rf_mode & (~LNAGAINMASK)) | LNAByp;
break;
case LNAByp:
break;
default:
break;
}
} else {
p_exmimo_config->rf.rx_gain[ant][0] = max(0,(int)rx_gain-5);
}
}
#ifdef DEBUG_PHY
LOG_D(PHY,"AGC for chain %d: rx_power_fil_dB=%d, rx_gain=%d, LNA=%d (1=Byp,2=Med,3=Max)\n",ant,rx_power_fil_dB,p_exmimo_config->rf.rx_gain[ant][0],(p_exmimo_config->rf.rf_mode[ant]&LNAGAINMASK)>>14);
#endif //DEBUG_PHY
}
@@ -1,31 +0,0 @@
/*
* 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
*/
#define TARGET_RX_POWER 50 // Target digital power for the AGC
#define TARGET_RX_POWER_MAX 53 // Maximum digital power for AGC
#define TARGET_RX_POWER_MIN 48 // Minimum digital power for AGC
#ifndef min
#define min(a,b) (((a)<(b))?(a):(b))
#define max(a,b) (((a)>(b))?(a):(b))
#endif
void gain_control_all (unsigned int rx_power_fil_dB, unsigned int card);
void gain_control (unsigned int rx_power_fil_dB, unsigned int ant, unsigned int card);
File diff suppressed because it is too large Load Diff
@@ -1,119 +0,0 @@
/*
* 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
*/
/** openair0_lib : API to interface with ExpressMIMO kernel driver
*
* Authors: Matthias Ihmig <matthias.ihmig@mytum.de>, 2013
* Raymond Knopp <raymond.knopp@eurecom.fr>
*
* Changelog:
* 28.01.2013: Initial version
*/
#ifndef __OPENAIR0_LIB_H__
#define __OPENAIR0_LIB_H__
#include "pcie_interface.h"
#include "openair_device.h"
#include "common_lib.h"
#include <pthread.h>
#include <sched.h>
#include <linux/sched.h>
typedef enum {
idle=0,
waiting_for_synch,
running
} exmimo_daq_state_t;
typedef struct {
pthread_t watchdog;
pthread_attr_t watchdog_attr;
struct sched_param watchdog_sched_param;
pthread_mutex_t watchdog_mutex;
int watchdog_exit;
int wait_first_read;
exmimo_daq_state_t daq_state;
openair0_timestamp ts;
openair0_timestamp last_ts_rx;
int samples_per_tick;
int samples_per_frame;
int last_mbox;
} exmimo_state_t;
// Use this to access shared memory (configuration structures, adc/dac data buffers, ...)
// contains userspace pointers
extern exmimo_pci_interface_bot_virtual_t openair0_exmimo_pci[MAX_CARDS];
extern int openair0_fd;
extern int openair0_num_antennas[MAX_CARDS];
extern int openair0_num_detected_cards;
// opens device and mmaps kernel memory and calculates interface and system_id userspace pointers
// return 0 on success
int openair0_open(void);
// close device and unmaps kernel memory
// return 0 on success
int openair0_close(void);
// trigger config update on card
// return 0 on success
int openair0_dump_config(int card);
// wrapper function for openair0_open (defined in common_lib.h)
// int openair0_device_init(openair0_device *device, openair0_config_t *openair0_cfg);
// copies data from openair0_cfg into exmimo_config and calls openair0_dump_config (for all cards)
int openair0_config(openair0_config_t *openair0_cfg, int UE_flag);
// copies data from openair0_cfg into exmimo_config (frequencies and gains only); does not call openair0_dump_configu (no IOCTL)
int openair0_reconfig(openair0_config_t *openair0_cfg);
// triggers recording of exactly 1 frame
// in case of synchronized multiple cards, send this only to the master card
// return 0 on success
int openair0_get_frame(int card);
// starts continuous acquisition/transmission
// in case of synchronized multiple cards, send this only to the master card
// return 0 on success
int openair0_start_rt_acquisition(int card);
// stops continuous acquitision/transmission and reset the RF chips
// return 0 on success
int openair0_stop(int card);
// stops continuous acquitision/transmission without resetting the RF chips
// return 0 on success
int openair0_stop_without_reset(int card);
// return the DAQ block counter
unsigned int *openair0_daq_cnt(void);
// set the TX and RX frequencies (card 0 only for now, to retain USRP compatibility)
int openair0_set_frequencies(openair0_device* device, openair0_config_t *openair0_cfg,int exmimo_dump_config);
int openair0_set_gains(openair0_device* device, openair0_config_t *openair0_cfg);
#endif
@@ -1,6 +0,0 @@
updatefw: updatefw.c
$(CC) updatefw.c -o updatefw -I../../DEFS
clean:
rm -f updatefw
@@ -1,577 +0,0 @@
/*============================================================================
File: elf.h
Include file for ELF file. Defines both 32-/64-bit files.
Copyright Hewlett-Packard Co. 1996. All rights reserved.
============================================================================*/
#ifndef ELF_INCLUDED
#define ELF_INCLUDED
#include "elftypes.h"
#ifdef __cplusplus
extern "C" {
#endif
/*============================================================================
Constant values for the sizes of fundamental types
============================================================================*/
#define ELF64_FSZ_ADDR 8
#define ELF64_FSZ_HALF 2
#define ELF64_FSZ_OFF 8
#define ELF64_FSZ_SWORD 4
#define ELF64_FSZ_WORD 4
#define ELF64_FSZ_SXWORD 8
#define ELF64_FSZ_XWORD 8
#define ELF32_FSZ_ADDR 4
#define ELF32_FSZ_HALF 2
#define ELF32_FSZ_OFF 4
#define ELF32_FSZ_SWORD 4
#define ELF32_FSZ_WORD 4
#define ELF32_FSZ_XWORD 4
/*============================================================================
The EI_* macros define indices into the e_ident[] array of the
ElfXX_Ehdr structure.
============================================================================*/
#define EI_MAG0 0 /* File identification */
#define EI_MAG1 1 /* File identification */
#define EI_MAG2 2 /* File identification */
#define EI_MAG3 3 /* File identification */
#define EI_CLASS 4 /* File class */
#define EI_DATA 5 /* Data encoding */
#define EI_VERSION 6 /* File version */
#define EI_OSABI 7 /* OS/ABI identification */
#define EI_ABIVERSION 8 /* ABI version */
#define EI_PAD 9 /* Start of padding bytes */
#define EI_NIDENT 16 /* Size of e_ident[] */
/*============================================================================
ElfXX_Ehdr - ELF file header structure.
============================================================================*/
typedef struct {
unsigned char e_ident[EI_NIDENT]; /* ELF identification */
Elf64_Half e_type; /* Object file type */
Elf64_Half e_machine; /* Machine type */
Elf64_Word e_version; /* Object file version */
Elf64_Addr e_entry; /* Entry point address */
Elf64_Off e_phoff; /* Program header offset */
Elf64_Off e_shoff; /* Section header offset */
Elf64_Word e_flags; /* Processor-specific flags */
Elf64_Half e_ehsize; /* ELF header size */
Elf64_Half e_phentsize; /* Size of program header entry */
Elf64_Half e_phnum; /* Number of program header entries */
Elf64_Half e_shentsize; /* Size of section header entry */
Elf64_Half e_shnum; /* Number of section header entries */
Elf64_Half e_shstrndx; /* Section name string table index */
} Elf64_Ehdr;
typedef struct {
unsigned char e_ident[EI_NIDENT]; /*16/ ELF "magic number" */
Elf32_Half e_type; /* 2/ Identifies object file type */
Elf32_Half e_machine; /* 2/ Specifies required architecture */
Elf32_Word e_version; /* 4/ Identifies object file version */
Elf32_Addr e_entry; /* 4/ Entry point virtual address */
Elf32_Off e_phoff; /* 4/ Program header table file offset */
Elf32_Off e_shoff; /* 4/ Section header table file offset */
Elf32_Word e_flags; /* 4/ Processor-specific flags */
Elf32_Half e_ehsize; /* 2/ ELF header size in bytes */
Elf32_Half e_phentsize; /* 2/ Program header table entry size */
Elf32_Half e_phnum; /* 2/ Program header table entry count */
Elf32_Half e_shentsize; /* 2/ Section header table entry size */
Elf32_Half e_shnum; /* 2/ Section header table entry count */
Elf32_Half e_shstrndx; /* 2/ Section header string table index */
} Elf32_Ehdr;
/*============================================================================
The ELFCLASS* macros are the defined values of e_ident[EI_CLASS].
============================================================================*/
#define ELFCLASSNONE 0 /* Invalid class */
#define ELFCLASS32 1 /* 32-bit objects */
#define ELFCLASS64 2 /* 64-bit objects */
#define ELFCLASS64_A 200 /* 64-bit objects (interim definition) */
/*============================================================================
The ELFDATA* macros are the allowed values of e_ident[EI_DATA].
============================================================================*/
#define ELFDATANONE 0 /* Invalid data encoding */
#define ELFDATA2LSB 1 /* 2's complement, LSB at lowest byte address */
#define ELFDATA2MSB 2 /* 2's complement, MSB at lowest byte address */
/*============================================================================
The ELFOSIABI* macros are the allowed values of e_ident[EI_OSABI].
============================================================================*/
#define ELFOSABI_SYSV 0 /* System V ABI, third edition, no checking */
#define ELFOSABI_HPUX 1 /* HP-UX operating system */
#define ELFOSABI_STANDALONE 255 /* STANDALONE operating system */
/*============================================================================
The ELFABIVERSION* macros are the allowed values of e_ident[EI_ABIVERSION].
============================================================================*/
#define ELFABI_HPUX_NONE 0 /* None specified */
#define ELFABI_HPUX_REL11 1
/*============================================================================
The ET_* macros define the values of the e_type field of the ElfXX_Ehdr
structure.
============================================================================*/
#define ET_NONE 0 /* No file type */
#define ET_REL 1 /* Relocatable file */
#define ET_EXEC 2 /* Executable file */
#define ET_DYN 3 /* Shared object file */
#define ET_CORE 4 /* Core file */
#define ET_LOOS 0xfe00 /* OS-specific lowest value */
#define ET_HIOS 0xfeff /* OS-specific highest value */
#define ET_LOPROC 0xff00 /* Processor-specific lowest value */
#define ET_HIPROC 0xffff /* Processor-specific highest value */
/*============================================================================
The EV_* macros are the allowed values of the e_version field of
ElfXX_Ehdr;
============================================================================*/
#define EV_NONE 0 /* Invalid version */
#define EV_CURRENT 1 /* Current version */
/*============================================================================
The ELFMAG* macros are the values of e_ident[EI_MAG0-4]
============================================================================*/
#define ELFMAG0 0x7f /* magic number, byte 0 */
#define ELFMAG1 'E' /* magic number, byte 1 */
#define ELFMAG2 'L' /* magic number, byte 2 */
#define ELFMAG3 'F' /* magic number, byte 3 */
#define ELFMAG "\177ELF" /* magic string */
#define SELFMAG 4 /* magic string length */
/*============================================================================
ElfXX_Phdr - program header structure. Element of the array of
program headers.
============================================================================*/
typedef struct {
Elf64_Word p_type; /* Type of segment */
Elf64_Word p_flags; /* Segment attributes */
Elf64_Off p_offset; /* Offset in file */
Elf64_Addr p_vaddr; /* Virtual address in memory */
Elf64_Addr p_paddr; /* Reserved */
Elf64_Xword p_filesz; /* Size of segment in file */
Elf64_Xword p_memsz; /* Size of segment in memory */
Elf64_Xword p_align; /* Alignment of segment */
} Elf64_Phdr;
typedef struct {
Elf32_Word p_type; /* Type of segment */
Elf32_Off p_offset; /* Offset in file */
Elf32_Addr p_vaddr; /* Virtual address in memory */
Elf32_Addr p_paddr; /* Reserved */
Elf32_Xword p_filesz; /* Size of segment in file */
Elf32_Xword p_memsz; /* Size of segment in memory */
Elf32_Word p_flags; /* Segment attributes */
Elf32_Xword p_align; /* Alignment of segment */
} Elf32_Phdr;
/*============================================================================
The PF_* macros are the segment flag bits in p_flags of ElfXX_Phdr.
============================================================================*/
#define PF_X 0x1 /* Execute */
#define PF_W 0x2 /* Write */
#define PF_R 0x4 /* Read */
#define PF_MASKOS 0x0ff00000 /* OS-specific */
#define PF_MASKPROC 0xf0000000 /* Processor-specific */
/*============================================================================
The PT_* macros are the values of p_type in ElfXX_Phdr.
============================================================================*/
#define PT_NULL 0 /* Array element is unused. Ignore. */
#define PT_LOAD 1 /* Loadable segment. */
#define PT_DYNAMIC 2 /* Dynamic Section */
#define PT_INTERP 3 /* Section is a path to an interpreter */
#define PT_NOTE 4 /* Note Section */
#define PT_SHLIB 5 /* Currently unspecified semantics */
#define PT_PHDR 6 /* Program header table. */
#define PT_LOOS 0x60000000 /* Lowest OS-specific type */
#define PT_HIOS 0x6fffffff /* Highest OS-specific type */
#define PT_LOPROC 0x70000000 /* Lowest Processor-specific type */
#define PT_HIPROC 0x7fffffff /* Highest Processor-specific type */
/*============================================================================
ElfXX_Shdr - structure for an ELF section header. Element of the array
of section headers.
============================================================================*/
typedef struct {
Elf64_Word sh_name; /* Section name */
Elf64_Word sh_type; /* Section type */
Elf64_Xword sh_flags; /* Section attributes */
Elf64_Addr sh_addr; /* Virtual address in memory */
Elf64_Off sh_offset; /* Offset in file */
Elf64_Xword sh_size; /* Size of section */
Elf64_Word sh_link; /* Link to other section */
Elf64_Word sh_info; /* Miscellaneous information */
Elf64_Xword sh_addralign; /* Address alignment boundary */
Elf64_Xword sh_entsize; /* Entry size, if section has table */
} Elf64_Shdr;
typedef struct {
Elf32_Word sh_name; /* Section name */
Elf32_Word sh_type; /* Section type */
Elf32_Xword sh_flags; /* Section attributes */
Elf32_Addr sh_addr; /* Virtual address in memory */
Elf32_Off sh_offset; /* Offset in file */
Elf32_Xword sh_size; /* Size of section */
Elf32_Word sh_link; /* Link to other section */
Elf32_Word sh_info; /* Miscellaneous information */
Elf32_Xword sh_addralign; /* Address alignment boundary*/
Elf32_Xword sh_entsize; /* Entry size, if section has table */
} Elf32_Shdr;
/*============================================================================
The ELF_STRING_xxx macros are names of common sections
============================================================================*/
#define ELF_STRING_bss ".bss"
#define ELF_STRING_hbss ".hbss"
#define ELF_STRING_sbss ".sbss"
#define ELF_STRING_tbss ".tbss"
#define ELF_STRING_data ".data"
#define ELF_STRING_hdata ".hdata"
#define ELF_STRING_sdata ".sdata"
#define ELF_STRING_fini ".fini"
#define ELF_STRING_init ".init"
#define ELF_STRING_interp ".interp"
#define ELF_STRING_rodata ".rodata"
#define ELF_STRING_text ".text"
#define ELF_STRING_comment ".comment"
#define ELF_STRING_dynamic ".dynamic"
#define ELF_STRING_dynstr ".dynstr"
#define ELF_STRING_dynsym ".dynsym"
#define ELF_STRING_dlt ".dlt"
#define ELF_STRING_note ".note"
#define ELF_STRING_opd ".opd"
#define ELF_STRING_plt ".plt"
#define ELF_STRING_bss_rela ".rela.bss"
#define ELF_STRING_hbss_rela ".rela.hbss"
#define ELF_STRING_data_rela ".rela.data"
#define ELF_STRING_dlt_rela ".rela.dlt"
#define ELF_STRING_plt_rela ".rela.plt"
#define ELF_STRING_sdata_rela ".rela.sdata"
#define ELF_STRING_strtab ".strtab"
#define ELF_STRING_symtab ".symtab"
#define ELF_STRING_hash ".hash"
#define ELF_STRING_shstrtab ".shstrtab"
#define ELF_STRING_shsymtab ".shsymtab"
#define ELF_STRING_rela ".rela"
#define ELF_STRING_rel ".rel"
/*============================================================================
The SHF_* macros are the allowed values of the sh_flags field of
ElfXX_Shdr. These 1-bit flags define attributes of a section.
============================================================================*/
#define SHF_WRITE 0x1 /* Writable during execution */
#define SHF_ALLOC 0x2 /* Occupies memory during execution */
#define SHF_EXECINSTR 0x4 /* Contains executable instructions */
#define SHF_MASKPROC 0xf0000000 /* mask for processor-specific bits */
/*============================================================================
SHN_* macros are reserved section header indices. An object file will
not have sections for these special indices.
============================================================================*/
#define SHN_UNDEF 0 /* undefined, e.g. undefined symbol */
#define SHN_LORESERVE 0xff00 /* Lower bound of reserved indices */
#define SHN_LOPROC 0xff00 /* Lower bound processor-specific index */
#define SHN_HIPROC 0xff1f/* Upper bound processor-specific index */
#define SHN_LOOS 0xff20 /* Lower bound OS-specific index */
#define SHN_HIOS 0xff3f /* Upper bound OS-specific index */
#define SHN_ABS 0xfff1 /* Absolute value, not relocated */
#define SHN_COMMON 0xfff2/* FORTRAN common or unallocated C */
#define SHN_HIRESERVE 0xffff /* Upper bound of reserved indices */
/*============================================================================
SHT_* macros are the values of sh_type in ElfXX_Shdr
============================================================================*/
#define SHT_NULL 0 /* Inactive section header */
#define SHT_PROGBITS 1 /* Information defined by the program */
#define SHT_SYMTAB 2 /* Symbol table - not DLL */
#define SHT_STRTAB 3 /* String table */
#define SHT_RELA 4 /* Explicit addend relocations, Elf64_Rela */
#define SHT_HASH 5 /* Symbol hash table */
#define SHT_DYNAMIC 6 /* Information for dynamic linking */
#define SHT_NOTE 7 /* A Note section */
#define SHT_NOBITS 8 /* Like SHT_PROGBITS with no data */
#define SHT_REL 9 /* Implicit addend relocations, Elf64_Rel */
#define SHT_SHLIB 10 /* Currently unspecified semantics */
#define SHT_DYNSYM 11 /* Symbol table for a DLL */
#define SHT_LOOS 0x60000000 /* Lowest OS-specific section type */
#define SHT_HIOS 0x6fffffff /* Highest OS-specific section type */
#define SHT_LOPROC 0x70000000 /* Lowest processor-specific section type */
#define SHT_HIPROC 0x7fffffff /* Highest processor-specific section type */
/*============================================================================
ElfXX_Sym - ELF symbol structure.
============================================================================*/
typedef struct {
Elf64_Word st_name; /* Symbol name */
unsigned char st_info; /* Type and Binding attributes */
unsigned char st_other; /* Reserved */
Elf64_Half st_shndx; /* Section table index */
Elf64_Addr st_value; /* Symbol value */
Elf64_Xword st_size; /* Size of object (e.g., common) */
} Elf64_Sym;
typedef struct {
Elf32_Word st_name; /* Symbol name */
Elf32_Addr st_value; /* Symbol value */
Elf32_Xword st_size; /* Size of object (e.g., common) */
unsigned char st_info; /* Type and Binding attributes */
unsigned char st_other; /* Reserved */
Elf32_Half st_shndx; /* Section table index */
} Elf32_Sym;
/*============================================================================
The ELFXX_ST_* macros operate on the st_info field of ElfXX_Sym
to extract binding attributes, type information and how to build
an st_info value from binding and type information.
============================================================================*/
#define ELF64_ST_BIND(val) ((val) >> 4)
#define ELF64_ST_TYPE(val) ((val) & 0xf)
#define ELF64_ST_INFO(bind,type) (((bind) << 4) + ((type) & 0xf))
#define ELF32_ST_BIND(val) ((val) >> 4)
#define ELF32_ST_TYPE(val) ((val) & 0xf)
#define ELF32_ST_INFO(bind,type) (((bind) << 4) + ((type) & 0xf))
/*============================================================================
STN_UNDEF (zero) designeates the first entry in the symbol table and serves
as the undefined symbol index.
============================================================================*/
#define STN_UNDEF 0
/*============================================================================
The STB_* macros are the defined values of the binding information part
of st_info in ElfXX_Sym.
============================================================================*/
#define STB_LOCAL 0 /* Local symbols */
#define STB_GLOBAL 1 /* Globally visible symbols */
#define STB_WEAK 2 /* Global symbols with lower precedence */
#define STB_LOOS 10 /* Lowest OS-specific value */
#define STB_HIOS 12 /* Highest OS-specific value */
#define STB_LOPROC 13 /* Lowest processor-specific value */
#define STB_HIPROC 15 /* Highest processor-specific value */
/*===========================================================================
The STT_* macros are the allowed values of the type information part of
st_info in ElfXX_Sym.
============================================================================*/
#define STT_NOTYPE 0 /* Undefined symbol type */
#define STT_OBJECT 1 /* A data object, variable, array, etc. */
#define STT_FUNC 2 /* A function or other executable code */
#define STT_SECTION 3 /* Symbol associated with a section */
#define STT_FILE 4 /* Typically the name of the source file */
#define STT_LOOS 10 /* Lowest OS-specific symbol type */
#define STT_HIOS 12 /* Highest OS-specific symbol type */
#define STT_LOPROC 13 /* Lowest processor-specific symbol type */
#define STT_HIPROC 15 /* Highest processor-specific symbol type */
/*============================================================================
ElfXX_Rel - ELF relocation without an explicit addend.
============================================================================*/
typedef struct {
Elf64_Addr r_offset; /* Address of reference */
Elf64_Xword r_info; /* Symbol index, relocation type */
} Elf64_Rel;
typedef struct {
Elf32_Addr r_offset; /* Address of reference */
Elf32_Xword r_info; /* Symbol index, reloc. type */
} Elf32_Rel;
/*============================================================================
ElfXX_Rela - ELF relocation with an explicit addend.
============================================================================*/
typedef struct {
Elf64_Addr r_offset; /* Address of reference */
Elf64_Xword r_info; /* Symbol index, relocation type */
Elf64_Sxword r_addend; /* Constant part of expression */
} Elf64_Rela;
typedef struct {
Elf32_Addr r_offset; /* Address of reference */
Elf32_Xword r_info; /* Symbol index, reloc. type */
Elf32_Sword r_addend; /* Constant part of expression */
} Elf32_Rela;
/*============================================================================
The ELFXX_R_* macros show how to extract the type and index parts
of r_info in ElfXX_Rel and ElfXX_Rela and how to build r_info
from a symbol index and type.
============================================================================*/
#define ELF64_R_INFO(sym,type) \
((((Elf64_Addr) (sym)) << 32) + ((Elf64_Addr) (type)))
#define ELF64_R_SYM(info) \
((Elf64_Sword) (((Elf64_Addr) (info)) >> 32))
#define ELF64_R_TYPE(info) \
((Elf64_Word) (((Elf64_Addr) (info)) & 0xffffffffLL))
#define ELF32_R_INFO(sym,type) (((sym) << 8) + ((unsigned char) (type)))
#define ELF32_R_SYM(info) ((info) >> 8)
#define ELF32_R_TYPE(info) ((unsigned char) (info))
/*============================================================================
ElfXX_Dyn - dynamic array entry.
============================================================================*/
typedef struct {
Elf32_Sword d_tag;
union {
Elf32_Word d_val; /* unsigned word */
Elf32_Addr d_ptr; /* address */
} d_un;
} Elf32_Dyn;
extern Elf32_Dyn _DYNAMIC32[];
typedef struct {
Elf64_Sxword d_tag;
union {
Elf64_Xword d_val; /* unsigned word */
Elf64_Addr d_ptr; /* address */
} d_un;
} Elf64_Dyn;
extern Elf64_Dyn _DYNAMIC[];
/*============================================================================
The DT_* defines are the allowed values of d_tag in ElfXX_dyn.
These are the Dynamic Array types.
============================================================================*/
/* (i)gnore (m)andatory (o)ptional */
/* d_un Exec DLL */
/* ---- ---- --- */
#define DT_NULL 0 /* ignored m m */
#define DT_NEEDED 1 /* d_val o o */
#define DT_PLTRELSZ 2 /* d_val o o */
#define DT_PLTGOT 3 /* d_ptr o o */
#define DT_HASH 4 /* d_ptr m m */
#define DT_STRTAB 5 /* d_ptr m m */
#define DT_SYMTAB 6 /* d_ptr m m */
#define DT_RELA 7 /* d_ptr m o */
#define DT_RELASZ 8 /* d_val m o */
#define DT_RELAENT 9 /* d_val m o */
#define DT_STRSZ 10 /* d_val m m */
#define DT_SYMENT 11 /* d_val m m */
#define DT_INIT 12 /* d_ptr o o */
#define DT_FINI 13 /* d_ptr o o */
#define DT_SONAME 14 /* d_val i o */
#define DT_RPATH 15 /* d_val o i */
#define DT_SYMBOLIC 16 /* ignored i o */
#define DT_REL 17 /* d_ptr m o */
#define DT_RELSZ 18 /* d_val m o */
#define DT_RELENT 19 /* d_val m o */
#define DT_PLTREL 20 /* d_val o o */
#define DT_DEBUG 21 /* d_ptr o i */
#define DT_TEXTREL 22 /* ignored o o */
#define DT_JMPREL 23 /* d_ptr o o */
#define DT_BIND_NOW 24 /* ignored */
#define DT_INIT_ARRAY 25 /* d_ptr o o */
#define DT_FINI_ARRAY 26 /* d_ptr o o */
#define DT_INIT_ARRAYSZ 27 /* d_val o o */
#define DT_FINI_ARRAYSZ 28 /* d_val o o */
#define DT_LOOS 0x60000000 /* unspecified - OS specific */
#define DT_HIOS 0x6fffffff /* unspecified - OS specific */
#define DT_LOPROC 0x70000000 /* unspecified - processor specific */
#define DT_HIPROC 0x7fffffff /* unspecified - processor specific */
#ifndef _HP_NO_ELF_DEPRICATED
/* These defines have been depricated and will be removed in a future release.*/
#define ELFOSABI_NONE 0 /* None specified */
#define ELFOSABI_NT 2 /* NT operating system */
#define ELFOSABI_SCOUNIX 3 /* SCO UNIX operating system */
#define SHF_COMDAT 0x8 /* Is a member of a COMDAT group */
#define SHT_COMDAT 12 /* COMDAT group directory -> SHT_HP_COMDAT */
#endif /* ifndef _HP_NO_ELF_DEPRICATED */
#ifdef __cplusplus
}
#endif /* ifndef _HP_NO_ELF_DEPRICATED */
#if defined(ELF_TARGET_ALL) || defined(ELF_TARGET_PARISC)
#include <elf_parisc.h>
#endif
#endif /* ELF_INCLUDED */
@@ -1,52 +0,0 @@
/*============================================================================
File: elftypes.h
Include file for Elf types. Define elf types for Elf structures.
Copyright Hewlett-Packard Co. 1995. All rights reserved.
============================================================================*/
#ifndef ELFTYPES_INCLUDED
#define ELFTYPES_INCLUDED
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __LP64__
typedef unsigned int Elf32_Addr; /* Unsigned program address */
typedef unsigned int Elf32_Off; /* Unsigned file offset */
typedef int Elf32_Sword; /* Signed large integer */
typedef unsigned int Elf32_Xword; /* Unsigned large integer */
#else
typedef unsigned long Elf32_Addr; /* Unsigned program address */
typedef unsigned long Elf32_Off; /* Unsigned file offset */
typedef long Elf32_Sword; /* Signed large integer */
typedef unsigned long Elf32_Xword; /* Unsigned large integer */
#endif
typedef unsigned int Elf32_Word; /* Unsigned large integer */
typedef unsigned short Elf32_Half; /* Unsigned medium integer */
typedef unsigned char Elf32_Char; /* Unsigned tiny integer */
typedef unsigned char Elf32_Byte; /* Unsigned tiny integer */
#ifdef __LP64__
typedef unsigned long Elf64_Addr;
typedef unsigned long Elf64_Off;
typedef unsigned long Elf64_Xword;
typedef long Elf64_Sxword;
#else
typedef unsigned long long Elf64_Addr;
typedef unsigned long long Elf64_Off;
typedef unsigned long long Elf64_Xword;
typedef long long Elf64_Sxword;
#endif
typedef unsigned short Elf64_Half;
typedef int Elf64_Sword;
typedef unsigned int Elf64_Word;
typedef unsigned char Elf64_Byte; /* Unsigned tiny integer */
#ifdef __cplusplus
}
#endif
#endif /* ELFTYPES_INCLUDED */
@@ -1,687 +0,0 @@
/*
* 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
*/
/*
C Header file <updatefw.h> for updatefw tool.
K. Khalfallah, Aug, 2007
kkhalfallah@free.fr
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/ioctl.h>
#include "openair_device.h"
#include "elf.h"
#include "elftypes.h"
#define EM_SPARC 2
#define MAX_SIZE_STRING_TABLE 1024
#define MAX_SIZE_SECTION_NAME 32
#include "updatefw.h"
/* Interface with OpenAirInterface driver */
#define DEVICE_NAME "/dev/openair0"
#define ACCESS_MODE O_RDONLY
#define SWITCH_IS_OFF 0
#define SWITCH_IS_ON 1
static unsigned int helpflag = SWITCH_IS_OFF;
static unsigned int pflag = SWITCH_IS_OFF;
static unsigned int noexecflag = SWITCH_IS_OFF;
static unsigned int fflag = SWITCH_IS_OFF;
static unsigned int sflag = SWITCH_IS_OFF;
static unsigned int rebootflag = SWITCH_IS_OFF;
static FILE* p_elfimage;
static Elf32_Ehdr elf_Ehdr;
static Elf32_Shdr elf_Shdr;
long Shdr_pos, StringSec_pos, StringSec_size;
//char section_name[MAX_SIZE_SECTION_NAME];
char SecNameStnTable[MAX_SIZE_STRING_TABLE];
unsigned int ioctl_params[4];
#define LONGOPTIONS_NB 6
struct option updatefw_longopts[LONGOPTIONS_NB+1] = {
{ .name = "help", .has_arg = no_argument, .flag = &helpflag, .val = SWITCH_IS_ON },
{ .name = "firmware", .has_arg = required_argument, .flag = NULL, .val = 'f' },
{ .name = "pretend", .has_arg = no_argument, .flag = &pflag, .val = SWITCH_IS_ON },
{ .name = "noexec", .has_arg = no_argument, .flag = &noexecflag, .val = SWITCH_IS_ON },
{ .name = "stackptr", .has_arg = required_argument, .flag = NULL, .val = 's' },
{ .name = "forcereboot", .has_arg = no_argument, .flag = &rebootflag, .val = SWITCH_IS_ON },
{0, 0, 0, 0}
};
#define TRUE 1
#define FALSE 0
void show_usage(char* pgname) {
unsigned int i;
fprintf(stderr, " %s : Tool to update firmware of Cardbus-MIMO-1/Leon3 card through the PCI interface,\n", pgname);
fprintf(stderr, " ");
for (i=0; i<strlen(pgname); i++) fprintf(stderr, " ");
fprintf(stderr, " that is, even without using the Xilinx parallel cable. The tool performs sequentially\n");
fprintf(stderr, " ");
for (i=0; i<strlen(pgname); i++) fprintf(stderr, " ");
fprintf(stderr, " the 5 following operations:\n");
fprintf(stderr, " ");
for (i=0; i<strlen(pgname); i++) fprintf(stderr, " ");
fprintf(stderr, " 1) Ask card driver to reboot (optionally)\n");
fprintf(stderr, " ");
for (i=0; i<strlen(pgname); i++) fprintf(stderr, " ");
fprintf(stderr, " 2) Ask card driver to transfer .text section\n");
fprintf(stderr, " ");
for (i=0; i<strlen(pgname); i++) fprintf(stderr, " ");
fprintf(stderr, " 3) Ask card driver to transfer .data section\n");
fprintf(stderr, " ");
for (i=0; i<strlen(pgname); i++) fprintf(stderr, " ");
fprintf(stderr, " 4) Ask card driver to clear .bss section\n");
fprintf(stderr, " ");
for (i=0; i<strlen(pgname); i++) fprintf(stderr, " ");
fprintf(stderr, " 5) Ask card driver to have Leon processor set stack-pointer\n");
fprintf(stderr, " ");
for (i=0; i<strlen(pgname); i++) fprintf(stderr, " ");
fprintf(stderr, " and jump to firmware entry.\n");
fprintf(stderr, "Usage:\n");
fprintf(stderr, " %s [-f|--firmware 'filename'] [-s|--stackptr value] [-b|--forcereboot]\n",pgname);
fprintf(stderr, " ");
for (i=0; i<strlen(pgname); i++) fprintf(stderr, " ");
fprintf(stderr, "[-v|-vv|-vvv|-vvvv] [-h|--help] [-p|--pretend]\n\n");
fprintf(stderr, " [-f|--firmware ] Mandatory option, to set the name of the executable file\n");
fprintf(stderr, " of the firmware to update the remote card with.\n");
fprintf(stderr, " The file should be an executable file in the Sparc32 ELF binary\n");
fprintf(stderr, " format, containing at least the 3 mandatory sections .text, .data & .bss\n");
fprintf(stderr, " [-s|--stackptr] Mandatory option, to set the value of the stack pointer before\n");
fprintf(stderr, " giving hand to the firmware. The specified value must be an integer\n");
fprintf(stderr, " number of 8 hexadecimal digits preceded by token '0x'.\n");
fprintf(stderr, " [-b|--forcereboot] Force reboot of Leon processor before updating the firmware.\n");
fprintf(stderr, " [-p|--pretend] Just pretend to transfer commands (ioctls) to driver, don't do it\n");
fprintf(stderr, " actually. Useful together with verbose -vv switch.\n");
fprintf(stderr, " [-n|--noexec] Transfer all data and text segments, but don't do actually start the code on Leon (no START_EXEC).\n");
fprintf(stderr, " [-v|-vv|-vvv|-vvvv] Verbose modes.\n");
fprintf(stderr, " [-h|--help] Displays this help.\n");
}
int get_elf_header(Elf32_Ehdr* p_Elf32_hdr, FILE* p_file) {
int nbread;
nbread = fread(p_Elf32_hdr, sizeof(elf_Ehdr), 1, p_file);
if (nbread != 1) {
fprintf(stderr, "Error : while reading ELF header (fread() returned %d)\n", nbread);
exit(-1);
}
invert2(p_Elf32_hdr->e_type); /* $$$$KMK: bad code !!! Endianess dependant ! */
invert2(p_Elf32_hdr->e_machine);
invert4(p_Elf32_hdr->e_version);
invert4(p_Elf32_hdr->e_entry);
invert4(p_Elf32_hdr->e_phoff);
invert4(p_Elf32_hdr->e_shoff);
invert4(p_Elf32_hdr->e_flags);
invert2(p_Elf32_hdr->e_ehsize);
invert2(p_Elf32_hdr->e_phentsize);
invert2(p_Elf32_hdr->e_phnum);
invert2(p_Elf32_hdr->e_shentsize);
invert2(p_Elf32_hdr->e_shnum);
invert2(p_Elf32_hdr->e_shstrndx);
return (p_Elf32_hdr->e_type == ET_EXEC)
&& (p_Elf32_hdr->e_machine == EM_SPARC)
&& (p_Elf32_hdr->e_version == EV_CURRENT)
&& (p_Elf32_hdr->e_ident[EI_CLASS] == ELFCLASS32)
&& (p_Elf32_hdr->e_ident[EI_DATA] == ELFDATA2MSB)
&& (p_Elf32_hdr->e_ident[EI_VERSION] == EV_CURRENT);
}
int get_elf_section_header(Elf32_Shdr* p_Elf32_Shdr, FILE* p_file, unsigned int section_ndx) {
int nbread;
/* retrieve the position of the section header table */
fseek(p_file, Shdr_pos + (section_ndx * elf_Ehdr.e_shentsize), 0);
/* set file pointer to the position of the section header section_ndx */
// seekrst = fseek(p_file, (long), 0);
nbread = fread(p_Elf32_Shdr, sizeof(elf_Shdr), 1, p_file);
if (nbread != 1) {
fprintf(stderr, "Error : while reading elf section header (fread() returned %d)\n", nbread);
exit(-1);
}
invert4(p_Elf32_Shdr->sh_name); /* $$$$KMK: bad code !!! Endianess dependant ! */
invert4(p_Elf32_Shdr->sh_type);
invert4(p_Elf32_Shdr->sh_flags);
invert4(p_Elf32_Shdr->sh_addr);
invert4(p_Elf32_Shdr->sh_offset);
invert4(p_Elf32_Shdr->sh_size);
invert4(p_Elf32_Shdr->sh_link);
invert4(p_Elf32_Shdr->sh_info);
invert4(p_Elf32_Shdr->sh_addralign);
invert4(p_Elf32_Shdr->sh_entsize);
//fseek(p_file, StringSec_pos + p_Elf32_Shdr->sh_name, 0);
//fread();
//strcpy(sname, );
return nbread;
}
void find_and_transfer_section(char* section_name, unsigned int verboselevel) {
/* Interface with driver */
int ioctlretval;
int ifile;
char* section_content;
int nbread;
unsigned int secnb = 0;
if(p_elfimage == NULL) {
fprintf(stderr, "%s %d:Error, firmware file not opened\n",__FILE__,__LINE__);
}
for (secnb = 0 ; secnb < elf_Ehdr.e_shnum; secnb++) {
get_elf_section_header(&elf_Shdr, p_elfimage, secnb);
if (!strcmp(SecNameStnTable + elf_Shdr.sh_name, section_name)) {
if (verboselevel >= VERBOSE_LEVEL_SECTION_DETAILS)
printf("Info: ok, found section %s (as section nb. %u)\n", SecNameStnTable + elf_Shdr.sh_name, secnb);
/* Check that section size is a multiple of 4 bytes. */
if (elf_Shdr.sh_size % 4) {
fprintf(stderr, "Error: section %s has a non-multiple-of-4-bytes size (%lu).\n",
SecNameStnTable + elf_Shdr.sh_name, (unsigned long)elf_Shdr.sh_size);
fclose(p_elfimage);
exit(-1);
} else if (verboselevel >= VERBOSE_LEVEL_SECTION_DETAILS) {
printf("Info: ok, section %s has size %lu bytes (multiple of 4 bytes).\n",
SecNameStnTable + elf_Shdr.sh_name, (unsigned long)elf_Shdr.sh_size);
}
/* Dynamically allocate a chunk of memory to store the section into. */
section_content = (char*)malloc(elf_Shdr.sh_size);
/* Fail if the address returned by malloc does not fit in 32 bits.
* The kernel driver gets this address as 32 bits and uses it to copy
* from userspace. If the address does not fit into 32 bits the kernel
* will copy garbage or fail to copy completely.
* To be reworked if things do not work on some setups.
*/
if (sizeof(char*) > 4 && (((uintptr_t)section_content)>>32)) {
fprintf(stderr, "FATAL ERROR: an internal serious problem has been encountered.\n");
fprintf(stderr, "Contact the authors so as to solve this issue.\n");
exit(-1);
}
if (!section_content) {
fprintf(stderr, "Error: could not dynamically allocate %lu bytes for section %s.\n",
(unsigned long)elf_Shdr.sh_size, (SecNameStnTable + elf_Shdr.sh_name));
fclose(p_elfimage);
exit(-1);
} else if (verboselevel >= VERBOSE_LEVEL_IOCTL) {
printf("Info: ok, dynamically allocated a %lu bytes buffer for section %s.\n",
(unsigned long)elf_Shdr.sh_size, SecNameStnTable + elf_Shdr.sh_name);
}
/* Position the file cursor at the begining of proper section. */
fseek(p_elfimage, (long)(elf_Shdr.sh_offset), 0);
/* Copy the section's content into this temporary buffer. */
nbread = fread(section_content, elf_Shdr.sh_size, 1, p_elfimage);
if (nbread != 1) {
fprintf(stderr, "Error: could not read %lu bytes from ELF file into dynamic buffer.\n", (unsigned long)elf_Shdr.sh_size);
free(section_content);
fclose(p_elfimage);
exit(-1);
} else if (verboselevel >= VERBOSE_LEVEL_IOCTL) {
printf("Info: ok, copied content of section %s into dynamic buffer (%lu bytes copied).\n",
SecNameStnTable + elf_Shdr.sh_name, (unsigned long)elf_Shdr.sh_size);
}
/* Open the special device file. */
if (!pflag) {
ifile = open(DEVICE_NAME, ACCESS_MODE, 0);
if (ifile<0) {
fprintf(stderr, "Error: could not open %s (open() returned %d, errno=%u)\n", DEVICE_NAME, ifile, errno);
free(section_content);
fclose(p_elfimage);
exit(-1);
} else if (verboselevel >= VERBOSE_LEVEL_IOCTL) {
printf("Info: ok, successfully opened %s.\n", DEVICE_NAME);
}
/* Collect control data for ioctl. */
ioctl_params[0] = UPDATE_FIRMWARE_TRANSFER_BLOCK;
ioctl_params[1] = elf_Shdr.sh_addr;
ioctl_params[2] = elf_Shdr.sh_size / 4;
/* This is wrong on x86_64 because a pointer is 64 bits and
* an unsigned int is only 32 bits.
* The compiler emits a warning, but the test
* above on the value of section_content makes it work
* (hopefully).
* To be changed if things do not work.
*/
ioctl_params[3] = (unsigned int)((unsigned int*)section_content);
//invert4(ioctl_params[1]);
//invert4(ioctl_params[2]);
/* Call ioctl driver */
ioctlretval = ioctl(ifile, openair_UPDATE_FIRMWARE, ioctl_params);
if (ioctlretval) {
fprintf(stderr, "Error: ioctl on %s failed.\n", DEVICE_NAME);
close(ifile);
free(section_content);
fclose(p_elfimage);
exit(-1);
} else if (verboselevel >= VERBOSE_LEVEL_IOCTL) {
printf("Info: ok, successful ioctl on %s for section %s.\n",
DEVICE_NAME, SecNameStnTable + elf_Shdr.sh_name);
}
close(ifile);
} /* pflag */
free(section_content);
} /* section_name */
} /* for secnb */
}
void find_and_clear_section_bss(unsigned int verboselevel) {
/* Interface with driver */
int ioctlretval;
int ifile;
unsigned int secnb = 0;
if(p_elfimage == NULL) {
fprintf(stderr, "%s %d:Error, firmware file not opened\n",__FILE__,__LINE__);
}
for (secnb = 0 ; secnb < elf_Ehdr.e_shnum; secnb++) {
get_elf_section_header(&elf_Shdr, p_elfimage, secnb);
if (!strcmp(SecNameStnTable + elf_Shdr.sh_name, ".bss")) {
if (verboselevel >= VERBOSE_LEVEL_SECTION_DETAILS)
printf("Info: ok, found section %s (as section nb. %u)\n", SecNameStnTable + elf_Shdr.sh_name, secnb);
/* Open the special device file. */
if (!pflag) {
ifile = open(DEVICE_NAME, ACCESS_MODE, 0);
if (ifile<0) {
fprintf(stderr, "Error: could not open %s (open() returned %d, errno=%u)\n", DEVICE_NAME, ifile, errno);
fclose(p_elfimage);
exit(-1);
} else if (verboselevel >= VERBOSE_LEVEL_IOCTL) {
printf("Info: ok, successfully opened %s.\n", DEVICE_NAME);
}
/* Collect control data for ioctl. */
ioctl_params[0] = UPDATE_FIRMWARE_CLEAR_BSS;
ioctl_params[1] = elf_Shdr.sh_addr;
ioctl_params[2] = elf_Shdr.sh_size;
//invert4(ioctl_params[1]);
//invert4(ioctl_params[2]);
/* Call ioctl driver */
ioctlretval = ioctl(ifile, openair_UPDATE_FIRMWARE, ioctl_params);
if (ioctlretval) {
fprintf(stderr, "Error: ioctl on %s failed.\n", DEVICE_NAME);
close(ifile);
fclose(p_elfimage);
exit(-1);
} else if (verboselevel >= VERBOSE_LEVEL_IOCTL) {
printf("Info: ok, successful ioctl on %s for section %s.\n",
DEVICE_NAME, SecNameStnTable + elf_Shdr.sh_name);
}
close(ifile);
} /* pflag */
} /* section_name */
} /* for secnb */
}
int main(int argc, char** argv) {
/* Interface with driver */
int ioctlretval;
int ifile;
/* Interface with getopt_long() libC function */
int getoptret;
int indexptr;
int erroroption = FALSE;
char* p_str_fwn = NULL;
char* p_str_stkptr = NULL;
char* filename;
unsigned int verboselevel = 0;
unsigned int i;
char* c;
unsigned int stackpointer = 0;
unsigned int ioctl_test_gok = 0;
unsigned int do_UPDATE_FIRMWARE_START_EXECUTION = 1;
/*****************
* Parse options *
*****************/
while ((getoptret = getopt_long_only (argc, argv, "f:vhpns:b", updatefw_longopts, &indexptr)) != -1)
switch (getoptret) {
/* Without-argument options */
case 0: /* means that the option just sets a flag. Nothing has to be done,
since getopt_long already sets the flag. */
break;
/* With-argument options & equivalent short options */
case 'v':
verboselevel++;
break;
case 'h': /* short switch -h was used */
helpflag = SWITCH_IS_ON;
break;
case 'p': /* short switch -p was used */
pflag = SWITCH_IS_ON;
break;
case 'n': /* short switch -n was used */
noexecflag = SWITCH_IS_ON;
break;
case 'f': /* short switch -f was used */
fflag = SWITCH_IS_ON;
p_str_fwn = optarg;
break;
case 's': /* short switch -s was used */
sflag = SWITCH_IS_ON;
p_str_stkptr = optarg;
break;
case 'b': /* short switch -b was used */
rebootflag = SWITCH_IS_ON;
break;
default:
erroroption = TRUE;
break;
};
/* End of while */
/********************************
* Check consistency of options *
********************************/
/* First, any irregularity in the use of the options ? Leave. */
if (erroroption == TRUE) {
fprintf(stderr, "%s: Misuse (--help to show usage)\n", argv[0]);
exit(-1);
}
/* Let print the help if it has been explicitly asked for */
if (helpflag == SWITCH_IS_ON) {
show_usage(argv[0]);
exit(0);
}
/* Check that mandatory firmware option was specified */
if (fflag != SWITCH_IS_ON) {
fprintf(stderr, "%s: missing mandatory [-f|--firmware] option (--help to show usage).\n", argv[0]);
exit(-1);
}
/* Check that mandatory stack pointer option was specified */
if (sflag != SWITCH_IS_ON) {
fprintf(stderr, "%s: missing mandatory [-s|--stackptr] option (--help to show usage).\n", argv[0]);
exit(-1);
}
/* Check consistency of stack pointer value. */
/* 1/2 - The address must start with the 2 characters '0x' and be exactly 10 characters long. */
if ((strncmp(p_str_stkptr, "0x", 2)) || (strlen(p_str_stkptr) != 10)) { /* 10 is for 0x + 8 hex digits. */
fprintf(stderr, "%s: Invalid value to [s|--stackptr] option (--help to show usage).\n", argv[0]);
exit(-1);
}
/* 2/2 - The address must only be made of hexadecimal digits. */
for (i=0,c=p_str_stkptr+2; i < 8 ; i++,c++) {
if (!
( ((*c >= '0') && (*c <= '9'))
|| ((*c >= 'a') && (*c <= 'f'))
|| ((*c >= 'A') && (*c <= 'F'))
)
) {
fprintf(stderr, "%s: Invalid value to [s|--stackptr] option (--help to show usage).\n", argv[0]);
exit(-1);
}
/* Transcode string hexadecinmal value into binary value */
if ((*c <= '9') && (*c >= '0'))
stackpointer |= (*c - '0') << 28-(i*4);
else if ((*c <= 'F') && (*c >= 'A'))
stackpointer |= ((*c - 'A') + 10) << 28-(i*4);
else if ((*c <= 'f') && (*c >= 'a'))
stackpointer |= ((*c - 'a') + 10) << 28-(i*4);
}
/* Open firmware file in READ_ONLY mode. */
filename = p_str_fwn;
if (filename == NULL) {
fprintf(stderr, "%s %d: No filename specified\n", __FILE__, __LINE__);
exit(-1);
}
p_elfimage = fopen(filename, READ_FILE_MODE);
if (p_elfimage == NULL) {
fprintf(stderr, "Error : could not open file <%s> in %s mode.\n", filename, READ_FILE_MODE);
exit(-1);
}
if (verboselevel >= VERBOSE_LEVEL_ACCESS_FILES)
printf("Info: using file <%s> (successfully opened in %s mode).\n", filename, READ_FILE_MODE);
/* Read elf binary image file */
/* Get informations from header file */
if (!(get_elf_header(&elf_Ehdr, p_elfimage))) {
fprintf(stderr, "Error : file doesn't match expected format.\n");
fclose(p_elfimage);
exit(-1);
}
if (verboselevel >= VERBOSE_LEVEL_ACCESS_FILES)
printf("Info: ok, file matches expected format.\n");
/* record the position of the section header table in the file */
fseek(p_elfimage, (long)(elf_Ehdr.e_shoff), 0);
Shdr_pos = ftell(p_elfimage);
/* record the position of the section name string table */
get_elf_section_header(&elf_Shdr, p_elfimage, elf_Ehdr.e_shstrndx);
fseek(p_elfimage, (long)(elf_Shdr.sh_offset), 0);
StringSec_pos = ftell(p_elfimage);
StringSec_size = elf_Shdr.sh_size;
/* copy the string table into global variable */
if (StringSec_size > MAX_SIZE_STRING_TABLE) {
fprintf(stderr, "Error: section name string table too big (%ld > %d);"
" increase max. allowed value in source code and recompile\n",
StringSec_size, MAX_SIZE_STRING_TABLE);
fclose(p_elfimage);
exit(-1);
}
fread(SecNameStnTable, 1, StringSec_size, p_elfimage);
/* Action 1: force reboot (if option was specified) */
if (verboselevel >= VERBOSE_LEVEL_MAIN_STEPS) {
if (rebootflag == SWITCH_IS_ON)
printf("Info: entering action #1 (forcing reboot of Leon).\n");
else
printf("Info: squeezed action #1 (forcing reboot of Leon).\n");
}
if ((rebootflag == SWITCH_IS_ON) && (!pflag)) {
ifile = open(DEVICE_NAME, ACCESS_MODE, 0);
if (ifile<0) {
fprintf(stderr, "Error: could not open %s (open() returned %d, errno=%u).\n", DEVICE_NAME, ifile, errno);
fclose(p_elfimage);
exit(-1);
} else if (verboselevel >= VERBOSE_LEVEL_IOCTL) {
printf("Info: ok, successfully opened %s.\n", DEVICE_NAME);
}
ioctl_params[0] = UPDATE_FIRMWARE_FORCE_REBOOT;
/* Call ioctl driver */
ioctlretval = ioctl(ifile, openair_UPDATE_FIRMWARE, ioctl_params);
if (ioctlretval) {
fprintf(stderr, "Error: ioctl on %s failed.\n", DEVICE_NAME);
close(ifile);
fclose(p_elfimage);
exit(-1);
} else if (verboselevel >= VERBOSE_LEVEL_IOCTL) {
printf("Info: ok, successful ioctl on %s to force reboot.\n", DEVICE_NAME);
}
/* If the card received the boot order, then
1) The firmware who handled the order must have cleared the BOOT_GOK bit
before rebooting ;
2) Boot-strap should once again set it back upon its init operations.
So we wait for this bit to be set again before issuing the rest of the
update-firmware operations (transfer loadable sections and so on...).
Note: putting the polling loop here is better than to have it in the
openair driver, because it avoids hanging the kernel if the card was
ever not to reboot cleanly. If the loop was to not end, user can simply
gives up the update-firmware operation by issuing a Ctrl-C. */
ioctl_params[0] = UPDATE_FIRMWARE_TEST_GOK;
/* Call ioctl driver */
if (verboselevel >= VERBOSE_LEVEL_MAIN_STEPS)
printf("Info: waiting for GOK bit (as acknowledge of reboot command) - May take a few seconds...\n");
ioctl_test_gok = 0;
do {
ioctlretval = ioctl(ifile, openair_UPDATE_FIRMWARE, ioctl_params);
ioctl_test_gok++;
sleep(1); /* sleep 1 second */
if (!(ioctl_test_gok % 10))
printf("Warning: card does not seem to have rebooted cleanly (no GOK bit). Still trying ([Ctrl-C] to abort).\n");
} while (ioctlretval);
if (verboselevel >= VERBOSE_LEVEL_IOCTL)
printf("Info: ok, card set again GOK bit (after %u seconds).\n", ioctl_test_gok);
close(ifile);
} /* rebootflag && pflag */
if ((verboselevel >= VERBOSE_LEVEL_MAIN_STEPS) && (rebootflag == SWITCH_IS_ON))
printf("Info: action #1 done.\n");
/* Action 2: Find the .text section */
if (verboselevel >= VERBOSE_LEVEL_MAIN_STEPS) printf("Info: entering action #2 (Transfer .text section).\n");
find_and_transfer_section(".text", verboselevel);
sleep(1);
if (verboselevel >= VERBOSE_LEVEL_MAIN_STEPS) printf("Info: action #2 done.\n");
/* Action 3 : Find the .data section */
if (verboselevel >= VERBOSE_LEVEL_MAIN_STEPS) printf("Info: entering action #3 (Transfer .data section).\n");
find_and_transfer_section(".data", verboselevel);
sleep(1);
if (verboselevel >= VERBOSE_LEVEL_MAIN_STEPS) printf("Info: action #3 done.\n");
/* Action 4 : Find the .bss section */
if (verboselevel >= VERBOSE_LEVEL_MAIN_STEPS) printf("Info: entering action #4 (Clear .bss section).\n");
find_and_clear_section_bss(verboselevel);
sleep(1);
if (verboselevel >= VERBOSE_LEVEL_MAIN_STEPS) printf("Info: action #4 done.\n");
/* Action 5 : Find the entry address */
if (verboselevel >= VERBOSE_LEVEL_MAIN_STEPS) printf("Info: entering action #5 (Jump to firmware/set stack-pointer).\n");
if (verboselevel >= VERBOSE_LEVEL_SECTION_DETAILS)
printf("Info: Firmware entry point = 0x%08x, setting stack pointer = 0x%08x.\n", (unsigned int)elf_Ehdr.e_entry, stackpointer);
/* Open the special device file. */
if (!pflag) {
ifile = open(DEVICE_NAME, ACCESS_MODE, 0);
if (ifile<0) {
fprintf(stderr, "Error: could not open %s (open() returned %d, errno=%u).\n", DEVICE_NAME, ifile, errno);
fclose(p_elfimage);
exit(-1);
} else if (verboselevel >= VERBOSE_LEVEL_IOCTL) {
printf("Info: ok, successfully opened %s.\n", DEVICE_NAME);
}
/* Collect control data for ioctl. */
ioctl_params[0] = UPDATE_FIRMWARE_START_EXECUTION;
ioctl_params[1] = elf_Ehdr.e_entry;
ioctl_params[2] = stackpointer;
//invert4(ioctl_params[1]);
//invert4(ioctl_params[2]);
/* Call ioctl driver */
if ( noexecflag == SWITCH_IS_OFF ) {
ioctlretval = ioctl(ifile, openair_UPDATE_FIRMWARE, ioctl_params);
if (ioctlretval) {
fprintf(stderr, "Error: ioctl on %s failed.\n", DEVICE_NAME);
close(ifile);
fclose(p_elfimage);
exit(-1);
} else if (verboselevel >= VERBOSE_LEVEL_IOCTL) {
printf("Info: ok, successful ioctl on %s for stack-pointer setting/firmware-execution.\n", DEVICE_NAME);
}
}
close(ifile);
} /* pflag */
if (verboselevel >= VERBOSE_LEVEL_MAIN_STEPS) printf("Info: action #5 done.\n");
fclose(p_elfimage);
/* Did we pretend ? */
if (pflag) printf("Nothing done.\n");
exit(0);
}
@@ -1,65 +0,0 @@
/*
* 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
*/
/*
C Header file <updatefw.h> for updatefw tool.
K. Khalfallah, Aug, 2007
kkhalfallah@free.fr
*/
#ifndef UPDATEFW_H
#define UPDATEFW_H
#include <stdio.h>
#include <errno.h>
#define _testsyscall(x, y, z) {if (x==-1) { \
fprintf(stderr, "Error : %s() returned "z" (errno=%d)\n", y, x, errno); \
fprintf(stderr, "Warning : not leaving normally. Remove ipc ressources by hand !"); \
fprintf(stderr, " (use shell commands ipcs & ipcrm)\n"); \
exit(-1); \
}}
// else { \
// printf("Info : successfully called %s, returned "z"\n", y, x);}}
/* Intel is little-endian, sparc is big */
unsigned long ltmp;
#define invert4(x) {ltmp=x; x=((ltmp & 0xff)<<24) | ((ltmp & 0xff00)<<8) | \
((ltmp & 0xff0000)>>8) | ((ltmp & 0xff000000)>>24); }
unsigned short stmp;
#define invert2(x) {stmp=x; x=((stmp & 0xff)<< 8) | ((stmp & 0xff00)>>8);}
/* static variables, global */
char* virt_addr;
unsigned int packet_ndx = 0;
#define FSEEK_ORIGIN 0
#define FSEEK_CURRENT 1
#define READ_FILE_MODE "r"
/* Verbose levels */
#define VERBOSE_LEVEL_MAIN_STEPS 1
#define VERBOSE_LEVEL_ACCESS_FILES 2
#define VERBOSE_LEVEL_SECTION_DETAILS 3
#define VERBOSE_LEVEL_IOCTL 4
#endif /* UPDATEFW_H */
@@ -1,50 +0,0 @@
CC = gcc
CFLAGS = -DEXMIMO -g
XTRA_CFLAGS = -msse -msse2 -mssse3 -fPIC
#ifndef OPENAIR0_DIR
# $(error Environment variable OPENAIR0_DIR must be set!)
#else
# CFLAGS += -I$(OPENAIR0_DIR)/express-mimo/software/pcie
#endif
GCCVERSION = $(shell gcc --version | grep ^gcc | sed 's/^.* //g')
ifeq "$(GCCVERSION)" "4.4.3"
CFLAGS += -Wno-packed-bitfield-compat
endif
ifeq "$(GCCVERSION)" "4.5.2"
CFLAGS += -Wno-packed-bitfield-compat
endif
ifeq "$(GCCVERSION)" "4.6.1"
CFLAGS += -Wno-packed-bitfield-compat
endif
OPENAIRTARGETS_DIR ?=../../../..
OPENAIROBJS += $(OPENAIRTARGETS_DIR)/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.o
CFLAGS += -I$(OPENAIRTARGETS_DIR)/ARCH/EXMIMO/USERSPACE/LIB -I$(OPENAIRTARGETS_DIR)/ARCH/EXMIMO/DEFS -I$(OPENAIRTARGETS_DIR)/ARCH/COMMON
#OPENAIROBJS = $(OPENAIR1_DIR)/PHY/CONFIG/openair_readconfigfile.o $(OPENAIR1_DIR)/PHY/CONFIG/openair_configure.o
OCTAVEOBJS = oarf_config_exmimo.oct oarf_get_frame.oct oarf_stop.oct oarf_send_frame.oct oarf_get_num_detected_cards.oct oarf_stop_without_reset.oct
all: $(OCTAVEOBJS) gpib_send.oct
oarf: $(OCTAVEOBJS)
$(OPENAIROBJS) : %.o : %.c
gcc -c $(CFLAGS) $(XTRA_CFLAGS) -o $@ $<
test:
echo $(OPENAIROBJS)
$(OCTAVEOBJS) : %.oct : %.cc $(OPENAIROBJS)
mkoctfile -o $@ $(CFLAGS) -lm $(OPENAIROBJS) $<
gpib_send.oct: gpib_send.cc
mkoctfile -I/usr/include/gpib -I/usr/local/include/gpib -lgpib gpib_send.cc
clean:
rm -f gpib_send.oct $(OCTAVEOBJS) $(OPENAIROBJS) *.o octave-core
@@ -1,19 +0,0 @@
function [sig,sig_length] = OFDM_TX(num_carriers,num_zeros,prefix_length,input)
% OFDM Transmitter - DC removed
% sig is the output signal
% length is the length of the output signal
% num_carriers - number of sub-carriers (power of 2)
% num_zeros - number of zeros minus 1 (DC) in output spectrum (odd)
% prefix_length - length of cyclic prefix
% input - input dimensions (length = number_carriers - num_zeros - 1)
if (length(input) + num_zeros + 1 ~= num_carriers)
fprintf('error in lengths\n');
return;
end
ext_input = [0 input(1:length(input)/2) zeros(1,num_zeros) input((1+length(input)/2) : length(input))];
output_1 = ifft(ext_input);
sig = [output_1((num_carriers - prefix_length + 1) : num_carriers) output_1];
sig_length = length(sig);
@@ -1,25 +0,0 @@
function [sig, sig_f] = OFDM_TX_FRAME(num_carriers,num_zeros,prefix_length,num_symbols_frame,preamble_length)
% sig - output signal
% sig_length - output signal length
% num_carriers - number of sub-carriers
% num_zeros - number of zero carriers minus 1 (DC)
% prefix_length - length of cyclic prefix
% num_symbols_frame - number of symbols per OFDM frame
% preamble_length - length of 4-QAM preamble
num_useful_carriers = num_carriers - num_zeros -1;
sig = zeros(1,(num_carriers+prefix_length)*num_symbols_frame);
sig_f = zeros(num_symbols_frame,num_useful_carriers);
for k=1:preamble_length
QAM4_preamble = QAM_MOD(4,floor(4*abs(rand(1,num_useful_carriers/4))));
sig((k-1)*(num_carriers+prefix_length)+1:k*(num_carriers+prefix_length)) = OFDM_TX(num_carriers,num_zeros,prefix_length,QAM4_preamble);
sig_f(k,:) = QAM4_preamble;
end
for k=preamble_length+1:num_symbols_frame
QAM_data = QAM_MOD(256,floor(256*abs(rand(1,num_useful_carriers/256))));
sig((k-1)*(num_carriers+prefix_length)+1:k*(num_carriers+prefix_length)) = OFDM_TX(num_carriers,num_zeros,prefix_length,QAM_data);
sig_f(k,:) = QAM_data;
end
@@ -1,29 +0,0 @@
function [sig,sig_length] = QAM_MOD(size,input)
% sig - output symbols
% size - modulation size (4,16,256)
% input - vector of bytes to be modulated
AM2 = [-1 1];
AM4 = [-3 -1 1 3]; AM4 = 2*AM4/sqrt(AM4*AM4');
AM16 = [-15 -13 -11 -9 -7 -5 -3 -1 1 3 5 7 9 11 13 15]; AM16 = 4*AM16/sqrt(AM16*AM16');
sig = zeros(1,length(input)*8/log2(size));
sig_length = length(input)*8/log2(size);
for l=1:length(input)
if (size == 256)
sig(l) = (AM16(1+ floor((input(l)/16))) +sqrt(-1)*AM16(1+rem(input(l),16)))/sqrt(2);
elseif (size == 16)
sig(1 + 2*(l-1)) = (AM4(1+floor((input(l)/64))) + sqrt(-1)*AM4(1+rem(floor(input(l)/16) , 4)))/sqrt(2);
sig(2 + 2*(l-1)) = (AM4(1+rem(floor(input(l)/4) , 4)) + sqrt(-1)*AM4(1+rem(input(l) , 4)))/sqrt(2);
elseif (size == 4)
sig(1+ 4*(l-1)) = (AM2(1+(floor(input(l)/128))) + sqrt(-1)*AM2(1+rem(floor(input(l)/64) , 2)))/sqrt(2);
sig(2+ 4*(l-1)) = (AM2(1+rem(floor(input(l)/32) ,2)) + sqrt(-1)*AM2(1+rem(floor(input(l)/16) , 2)))/sqrt(2);
sig(3+ 4*(l-1)) = (AM2(1+rem(floor(input(l)/8) , 2)) + sqrt(-1)*AM2(1+rem(floor(input(l)/4) , 2)))/sqrt(2);
sig(4+ 4*(l-1)) = (AM2(1+rem(floor(input(l)/2) , 2)) + sqrt(-1)*AM2(1+rem(input(l) , 2)))/sqrt(2);
end
end
@@ -1,19 +0,0 @@
chan=1;
hold off ;
card=0;
s=oarf_get_frame(card);
s2=zeros(76800*2,1);
s2(1:2:end) = s(:,chan);
s2(2:2:end) = s(:,chan);
plot(real(s2),'b',"markersize",1);
hold on; plot(imag(s2),'r',"markersize",1);
bit11_I = rem(floor(real(2048+s(:,chan))/2048),2);
bit11_Q = rem(floor(imag((2048*j)+s(:,chan))/2048),2);
bit11_IQ = zeros(1,2*length(bit11_I));
bit11_IQ(1:2:end) = bit11_I;
bit11_IQ(2:2:end) = bit11_Q;
plot(500*bit11_IQ,'k')
axis([0 76800 -1000 1000])
@@ -1,17 +0,0 @@
vlen=76800
chan=2
gainimb_rx = -0.0020; phaseimb_rx = -2.38; % ExMIMO1 / lime1, VGAgain2 = 0, 1.9 GHz
gainimb_rx = 0.55; phaseimb_rx = 24.3; % ExMIMO1 / lime1, VGAgain2 = 0, 1.9 GHz
phaseimb_rx = phaseimb_rx/180*pi; % phaser imb in radians
beta_rx = (1/2)*(1 + (1+ gainimb_rx) * exp(1i*phaseimb_rx));
alpha_rx = (1/2)*(1 - (1+ gainimb_rx) * exp(-1i*phaseimb_rx));
den=abs(beta_rx)^2-abs(alpha_rx)^2;
beta_rx=beta_rx/den;
alpha_rx=alpha_rx/den;
s2 = beta_rx.*s + alpha_rx.*conj(s);
hold off ; plot(20*log10(abs(fftshift(fft(s2(:,chan)))))); grid on;
@@ -1,47 +0,0 @@
dual_tx=0;
eNBflag = 0;
card=0;
limeparms;
%% acquisition
%rf_mode = ( RXEN + TXLPFNORM + TXLPFEN + TXLPF25 + RXLPFNORM + RXLPFEN + RXLPF25 + LNA1ON +LNAMax + RFBBNORM + RXOUTSW )*[1 1 0 0];
rf_mode = ( RXEN + TXEN + TXLPFNORM + TXLPFEN + TXLPF25 + RXLPFNORM + RXLPFEN + RXLPF25 + LNA1ON +LNAMax + RFBBNORM )*[1 1 1 1];
% internal loopback test
%rf_mode = (RXEN+TXEN+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNAByp+RFBBLNA1)*[1 1 0 0];
%rf_mode = (RXEN+ TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNAByp+RFBBLNA1)*[1 1 1 1];
%rf_mode = [0 0 0 0];
%% Select DMA directions
rf_mode = rf_mode + (DMAMODE_RX + DMAMODE_TX)*[1 0 0 0];
freq_rx = (1907600000 - 0*9000)*[1 1 1 1];
%rf_local= [rfl(56,56,31,31) rfl(16,12,31,31) rfl(36,48,31,31) rfl(32,20,31,31)]; % 1.9 GHz, Exmimo2-No1, lime_cal_exmimo
%rf_local= [rfl(34,40,31,31) rfl(20,25,38,21) rfl(12,38,21,14) rfl(31,19,36, 6)]; % 1.9 GHz, Exmimo2-No1, LIME GUI
rf_local= [rfl(32,36,26,25) rfl(20,25,37,21) rfl(12,38,21,14) rfl(31,19,36, 6)];
rf_vcocal=(( 0xE)*(2^6)) + ( 0xE)*[1 1 1 1]; % 1.907 GHz, (OLD)
freq_tx = freq_rx + 000000; % 1kHz offset: @30 MSPS: 2.5 sines, @15 MSPS: 5 sines, @7 MSPS: 10 sines
rf_rxdc = rf_rxdc*[1 1 1 1];
tx_gain = 13*[1 1 1 1]; rx_gain = 25*[1 1 1 1]; amp=32000;
%tx_gain = 25*[1 1 1 1]; rx_gain = 0*[1 1 1 1]; amp=32000;
oarf_config_exmimo(card,freq_rx,freq_tx,0,dual_tx,rx_gain,tx_gain,eNBflag,rf_mode,rf_rxdc,rf_local,rf_vcocal);
sleep(1);
% create_testvector
vlen=76800
chan=1
v=0000*exp(-i*(3*[0:vlen-1]/vlen)*2*pi); v=[v;v]'; oarf_send_frame(card,v,16); sleep(0.2);
s = oarf_get_frame(card); figure ; plot(real(s(:,chan)),'b-.',"markersize",2) ; hold on ; plot(imag(s(:,chan)),'r-.',"markersize",2);
s = s(:,chan) - mean(s(:,chan)); % remove DC
e_s0 = sum( s' * s )
v=amp*exp(-i*(10000*[0:vlen-1]/vlen)*2*pi); e_v=sum(v*v'); v=[v;v]'; oarf_send_frame(card,v,16); sleep(0.2);
s = oarf_get_frame(card); figure ; plot(real(s(:,chan)),'b-.',"markersize",2) ; hold on ; plot(imag(s(:,chan)),'r-.',"markersize",2);
s = s(:,chan) - mean(s(:,chan)); % remove DC
figure; plot(20*log10(fftshift(abs(fft(s))))); grid on;
e_v
e_s = sum( s' * s )
s_over_s0_db = 10*log10( e_s / e_s0 )
@@ -1,68 +0,0 @@
dual_tx=0;
eNBflag = 0;
card=0;
limeparms;
%% acquisition
%rf_mode = ( RXEN + TXLPFNORM + TXLPFEN + TXLPF25 + RXLPFNORM + RXLPFEN + RXLPF25 + LNA1ON +LNAMax + RFBBNORM + RXOUTSW )*[1 1 0 0];
rf_mode = ( TXEN + TXLPFNORM + TXLPFEN + TXLPF25 + RXLPFNORM + RXLPFEN + RXLPF25 + LNA1ON +LNAMax + RFBBNORM )*[1 1 0 0];
% internal loopback test
%rf_mode = (RXEN+TXEN+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNAByp+RFBBLNA1)*[1 1 0 0];
%rf_mode = (RXEN+ TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNAByp+RFBBLNA1)*[1 1 1 1];
%rf_mode = [0 0 0 0];
%% Select DMA directions
rf_mode = rf_mode + (DMAMODE_TX)*[0 1 0 0];
freq_rx = (1907600000 - 0*9000)*[1 1 1 1];
%rf_local= [rfl(56,56,31,31) rfl(16,12,31,31) rfl(36,48,31,31) rfl(32,20,31,31)]; % 1.9 GHz, Exmimo2-No1, lime_cal_exmimo
%rf_local= [rfl(34,40,31,31) rfl(20,25,38,21) rfl(12,38,21,14) rfl(31,19,36, 6)]; % 1.9 GHz, Exmimo2-No1, LIME GUI
%rf_local= [rfl(32,36,26,25) rfl(20,25,37,21) rfl(12,38,21,14) rfl(31,19,36, 6)];
rf_local= [rfl(33,36,26,25) rfl(20,24,37,21) rfl(12,38,21,14) rfl(31,19,36, 6)];
rf_vcocal=(( 0xE)*(2^6)) + ( 0xE)*[1 1 1 1]; % 1.907 GHz, (OLD)
freq_tx = freq_rx + 000000; % 1kHz offset: @30 MSPS: 2.5 sines, @15 MSPS: 5 sines, @7 MSPS: 10 sines
rf_rxdc = rf_rxdc*[1 1 1 1];
tx_gain = 20*[1 1 1 1]; rx_gain = 25*[1 1 1 1]; amp=10000;
%tx_gain = 25*[1 1 1 1]; rx_gain = 0*[1 1 1 1]; amp=32000;
oarf_config_exmimo(card, freq_rx,freq_tx,0,dual_tx,rx_gain,tx_gain,eNBflag,rf_mode,rf_rxdc,rf_local,rf_vcocal);
sleep(1);
% create_testvector
vlen=76800
chan=1
%v=0000*exp(-i*(3*[0:vlen-1]/vlen)*2*pi); v=[v;v]'; oarf_send_frame(card,v,16); sleep(0.2);
%s = oarf_get_frame(card); figure ; plot(real(s(:,chan)),'b-.',"markersize",2) ; hold on ; plot(imag(s(:,chan)),'r-.',"markersize",2);
% create_testvector
vlen=76800
chan=1
amp=10000
%v=0000*exp(-i*(3*[0:vlen-1]/vlen)*2*pi); v=[v;v]'; oarf_send_frame(card,v,16); sleep(0.2);
%s = oarf_get_frame(card); figure ; plot(real(s(:,chan)),'b-.',"markersize",2) ; hold on ; plot(imag(s(:,chan)),'r-.',"markersize",2);
v=amp*exp(-i*(10000*[0:vlen-1]/vlen)*2*pi); v=[v;v]';
%for gainimb_tx = -0.05:0.01:0.05
%for phaseimb_tx= -5:1:5
gainimb_tx = -0.028; % gain imabalance of modulator in linear scale
phaseimb_tx = 3.0; % phase imbalance of modulator in degrees
gainimb_tx = -0.028; phaseimb_tx = 3.0; % for exmimo2-1 lime1
phaseimb_tx = phaseimb_tx/180*pi; % phaser imb in radians
beta_tx = (1/2)*(1 + (1+ gainimb_tx) * exp(1i*phaseimb_tx));
alpha_tx = (1/2)*(1 - (1+ gainimb_tx) * exp(-1i*phaseimb_tx));
den=abs(beta_tx)^2-abs(alpha_tx)^2;
beta_tx=beta_tx/den;
alpha_tx=alpha_tx/den;
v = beta_tx.*v + alpha_tx.*conj(v);
sleep(0.5); oarf_send_frame(card,v,16);
@@ -1,99 +0,0 @@
% Basic configuration script for ExpressMIMO-1 and ExpressMIMO-2
% Some functions are only available on ExpressMIMO-2!
limeparms;
eNBflag = 0;
card=0;
tdd_config = TXRXSWITCH_LSB;
%tdd_config = TXRXSWITCH_TESTTX;
syncmode = SYNCMODE_FREE;
%% acquisition
%rf_mode = ( RXEN + TXLPFNORM + TXLPFEN + TXLPF25 + RXLPFNORM + RXLPFEN + RXLPF25 + LNA1ON +LNAMax + RFBBNORM + RXOUTSW )*[1 1 0 0];
rf_mode = ( RXEN + TXEN + TXLPFNORM + TXLPFEN + TXLPF25 + RXLPFNORM + RXLPFEN + RXLPF25 + LNA1ON +LNAMax + RFBBNORM )*[ 1 0 0 0 ];
%rf_mode = rf_mode + (RXEN+TXLPFNORM + TXLPFEN + TXLPF25 + RXLPFNORM + RXLPFEN + RXLPF25 + LNA1ON +LNAMax + RFBBNORM )*[ 0 1 0 0 ];
% internal loopback test
%rf_mode = (RXEN+TXEN+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNAByp+RFBBLNA1)*[1 1 0 0];
%rf_mode = (RXEN+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA.1ON+LNAByp+RFBBLNA1)*[1 1 1 1];
%rf_mode = [0 0 0 0];
%% Select DMA directions
%rf_mode = rf_mode + (DMAMODE_RX)*[0 1 0 0];
%rf_mode = rf_mode + (DMAMODE_RX)*[0 0 1 1];
%rf_mode = rf_mode + (DMAMODE_TX)*[1 1 0 0];
rf_mode = rf_mode + (DMAMODE_RX + DMAMODE_TX)*[ 1 0 0 0 ];
%rf_mode = rf_mode + (DMAMODE_RX )*[0 1 0 0];
%rf_mode = rf_mode + (DMAMODE_TX)*[1 0 0 0]; rf_mode = rf_mode + (DMAMODE_RX)*[0 1 0 0];
%freq_rx = 749600000*[1 1 1 1];
%rf_local= [8255004 8253440 8257340 8257340]; % 700 MHz
%rf_vcocal=((0x24)*(2^6)) + (0x24)*[1 1 1 1]; % 700 MHz
freq_rx = (1907600000 - 0*9000)*[1 1 1 1];
%rf_local= [rfl( 0, 0,31,31) rfl(28,44,31,31) rfl(60,60,31,31) rfl(60,60,31,31)]; % 1.9 GHz, OLD
%rf_local= [rfl(56,56,31,31) rfl(16,12,31,31) rfl(36,48,31,31) rfl(32,20,31,31)]; % 1.9 GHz, Exmimo2-No1, lime_cal_exmimo
%rf_local= [rfl(34,40,31,31) rfl(20,25,38,21) rfl(12,38,21,14) rfl(31,19,36, 6)]; % 1.9 GHz, Exmimo2-No1, LIME GUI
rf_local= [rfl(20,25,26,04) rfl(20,25,26,04) 0 0]; % 1.9 GHz & 860 MHz, VGA2Gain=0
%rf_local= [0 rfl(20,25,38,21) 0 0 ]; % 1.9 GHz, VGA2Gain=30
rf_vcocal=(( 0xE)*(2^6)) + ( 0xE)*[1 1 1 1]; % 1.907 GHz, (OLD)
%rf_vcocal=((0x14)*(2^6)) + (0x13)*[1 1 1 1]; % 1.907 GHz, RX(msbs)+ TX(lsbs), RX:0xC..0x14, TX:0xB..0x13 (ExMIMO2-No1)
%rf_vcocal=((0x12)*(2^6)) + (0x10)*[1 1 1 1]; % 1.917 GHz, RX(msbs)+ TX(lsbs), RX:0xD..0x16, TX:0xC..0x14 (ExMIMO2-No1)
%freq_rx = ( 860000000 - 0*9000)*[1 1 1 1];
%rf_vcocal=((0x1d)*(2^6)) + (0x1d)*[1 1 1 1]; % 860 MHz
freq_tx = freq_rx + 0000000; % 1kHz offset: @30 MSPS: 2.5 sines, @15 MSPS: 5 sines, @7 MSPS: 10 sines
tx_gain = 13*[1 1 1 1];
rx_gain = 20*[1 1 1 1];
rf_rxdc = rf_rxdc*[1 1 1 1];
rffe_rxg_low = 63*[1 1 1 1];
rffe_rxg_final = 63*[1 1 1 1];
rffe_band = TVWS_TDD*[1 1 1 1];
autocal = [1 1 1 1];
oarf_config_exmimo(card,freq_rx,freq_tx,tdd_config,syncmode,rx_gain,tx_gain,eNBflag,rf_mode,rf_rxdc,rf_local,rf_vcocal,rffe_rxg_low,rffe_rxg_final,rffe_band,autocal)
%sleep(0.2)
% stuff for I/Q imbalance correction on RX
%gainimb_rx = -0.0020; phaseimb_rx = -2.38; % RX IQ imbal. ExMIMO1 / lime1, VGAgain2 = 0, 1.9 GHz
gainimb_rx = -0.0030; phaseimb_rx = -2.38; % RX IQ imbal. ExMIMO1 / lime1, VGAgain2 = 30, 1.9 GHz
phaseimb_rx = phaseimb_rx/180*pi; % phaser imb in radians
beta_rx = (1/2)*(1 + (1+ gainimb_rx) * exp(1i*phaseimb_rx));
alpha_rx = (1/2)*(1 - (1+ gainimb_rx) * exp(-1i*phaseimb_rx));
den=abs(beta_rx)^2-abs(alpha_rx)^2;
beta_rx=beta_rx/den;
alpha_rx=alpha_rx/den;
% create_testvector
vlen=76800
%v=10000*exp(-i*2*pi*1/7.68*[0:vlen-1]); v=[v;v]'; oarf_send_frame(card,v,16);
%v=([2:1+vlen; 10002:10001+vlen] - i*[3:2+vlen; 10003:10002+vlen])';
%v=32767*(1+i)*ones(vlen,2); oarf_send_frame(card,v,16);
%v = floor(( [640:639+vlen ; 640:639+vlen] / 5 ))'; oarf_send_frame(card,v,16);
%v = floor(( [75000:-1:75001-vlen ; 75000:-1:75001-vlen] / 5 ))'; oarf_send_frame(card,v,16);
%v=i*2^11*ones(vlen,2)+2^11*ones(vlen,2); oarf_send_frame(card,v,16);
%v=15000*exp(-i*2*pi*1/7.68*[0:vlen-1]); v=[v;v]'; oarf_send_frame(card,v,16);
%v=10000*exp(-i*(3000*[0:vlen-1]/vlen)*2*pi); v=[v;v]'; oarf_send_frame(card,v,16);
%v=20000*exp(-i*pi*(0:vlen-1)/2); v=[v;v]'; oarf_send_frame(card,v,16);
% Set LSB to RX (,1) or to TX(,0)
%v=10000*m'.*exp(-i*(50*[0:vlen-1]/vlen)*2*pi); v=bitset(real(v),1,0) + i*bitset(imag(v),1,0); v=[v;v]'; oarf_send_frame(card,v,16);
v2=15000*sin((1:vlen)/vlen*2*pi); v2=[v2;v2]';
v=15000*exp(i*2*pi*1/7.68*[1:vlen]); v=[v;v]';
%oarf_send_frame(card,v,16);
%len=1000;off=0; chan=2; s=oarf_get_frame(card); hold off ; plot(real(s(off+1:off+len,chan)),'-o',"markersize",2) ; hold on ; plot(imag(s(off+1:off+len,chan)),'r-o',"markersize",2)
%chan=1; s = oarf_get_frame(card); hold off ; plot(real(s(:,chan)),'b-o',"markersize",2) ; hold on ; plot(imag(s(:,chan)),'r-o',"markersize",2)
%while 1;len=5000;off=0; chan=1; s = oarf_get_frame(card); hold off ; plot(real(s(off+1:off+len,chan)),'-o',"markersize",2) ; hold on ; plot(imag(s(off+1:off+len,chan)),'r-o',"markersize",3); sleep(0.3);endwhile
%chan=2; s=oarf_get_frame(card); s=s-0.99999*mean(s(:,chan)); s = beta_rx.*s + alpha_rx.*conj(s); hold off ; plot(20*log10(abs(fftshift(fft(s(:,chan)))))); grid on; min_r=min(real(s(:,chan))); min_i=min(imag(s(:,chan))); max_r=max(real(s(:,chan))); max_i=max(imag(s(:,chan))); disp("Min-I/Q Max-I/Q"); disp([min_r min_i max_r max_i]);
%chan=2; s=oarf_get_frame(card); s=s-0.99999*mean(s(:,chan)); s = beta_rx.*s + alpha_rx.*conj(s); hold off ; plot(20*log10(abs(fftshift(fft(hamming(vlen).*s(:,chan)))))); grid on; min_r=min(real(s(:,chan))); min_i=min(imag(s(:,chan))); max_r=max(real(s(:,chan))); max_i=max(imag(s(:,chan))); disp("Min-I/Q Max-I/Q"); disp([min_r min_i max_r max_i]);
@@ -1,33 +0,0 @@
% Switch off limes
limeparms;
eNBflag = 0;
card=-1;
tdd_config = TXRXSWITCH_LSB;
%tdd_config = TXRXSWITCH_TESTTX;
syncmode = SYNCMODE_FREE;
rf_mode = [0 0 0 0];
%% Select DMA directions
rf_mode = rf_mode + (DMAMODE_RX + DMAMODE_TX)*[ 1 0 0 0 ];
rf_mode = rf_mode + (DMAMODE_RX )*[0 1 0 0];
freq_rx = (1907593260)*[1 1 1 1];
rf_local= [0 0 0 0 ];
rf_vcocal=(( 0xE)*(2^6)) + ( 0xE)*[1 1 1 1]; % 1.907 GHz, (OLD)
freq_tx = freq_rx + 0000000; % 1kHz offset: @30 MSPS: 2.5 sines, @15 MSPS: 5 sines, @7 MSPS: 10 sines
tx_gain = 13*[1 1 1 1];
rx_gain = 10*[1 1 1 1];
rf_rxdc = (1 + 1*(2^8))*[1 1 1 1]; % I:LSB, Q:MSB
oarf_config_exmimo(card,freq_rx,freq_tx,tdd_config,syncmode,rx_gain,tx_gain,eNBflag,rf_mode,rf_rxdc,rf_local,rf_vcocal)
oarf_stop(-1);
%sleep(0.2)
@@ -1,51 +0,0 @@
% Basic configuration script for ExpressMIMO-1 and ExpressMIMO-2
% Some functions are only available on ExpressMIMO-2!
limeparms;
eNBflag = 0;
card=0;
tdd_config = TXRXSWITCH_LSB;
%tdd_config = TXRXSWITCH_TESTTX;
tdd_config += TEST_ADACLOOP_EN;
syncmode = SYNCMODE_FREE;
%% acquisition
%rf_mode = ( RXEN + TXLPFNORM + TXLPFEN + TXLPF25 + RXLPFNORM + RXLPFEN + RXLPF25 + LNA1ON +LNAMax + RFBBNORM + RXOUTSW )*[1 1 0 0];
rf_mode = ( RXEN + TXEN + TXLPFNORM + TXLPFEN + TXLPF25 + RXLPFNORM + RXLPFEN + RXLPF25 + LNA1ON +LNAMax + RFBBNORM )*[ 1 1 0 0 ];
%% Select DMA directions
rf_mode = rf_mode + (DMAMODE_RX + DMAMODE_TX)*[ 1 0 0 0 ];
rf_mode = rf_mode + (DMAMODE_TX )*[0 1 0 0];
freq_rx = (1907600000)*[1 1 1 1];
rf_local= [rfl(20,25,26,04) rfl(20,25,26,04) 0 0]; % 1.9 GHz & 860 MHz, VGA2Gain=0
rf_vcocal=(( 0xE)*(2^6)) + ( 0xE)*[1 1 1 1]; % 1.907 GHz, (OLD)
freq_tx = freq_rx + 0000000; % 1kHz offset: @30 MSPS: 2.5 sines, @15 MSPS: 5 sines, @7 MSPS: 10 sines
tx_gain = 13*[1 1 1 1];
rx_gain = 20*[1 1 1 1];
rf_rxdc = (1 + 1*(2^8))*[1 1 1 1]; % I:LSB, Q:MSB
rffe_rxg_low = 61*[1 1 1 1];
rffe_rxg_final = 61*[1 1 1 1];
rffe_band = B19G_TDD*[1 1 1 1];
oarf_config_exmimo(card,freq_rx,freq_tx,tdd_config,syncmode,rx_gain,tx_gain,eNBflag,rf_mode,rf_rxdc,rf_local,rf_vcocal,rffe_rxg_low,rffe_rxg_final,rffe_band)
% create_testvector
vlen=76800
v = floor(( [ (201:200+60000) - i*(101:100+60000) ] ))' - (30000+i*30000);
v = [v; floor(( [ (201:200+vlen-60000) - i*(101:100+vlen-60000) ] ))' - (30000+i*30000) ];
%v=([11:10+vlen] - i*[101:100+vlen])'; % attention, doesn't wrap!
%v=15000*exp(-i*2*pi*1/7.68*[0:vlen-1])';
v2=30000*(1+i)*ones(vlen,2);
oarf_send_frame(card,[v v2],16);
sleep(2); % need this, otherwise, get_frame will return garbage sometimes
%len=1000;off=0; chan=2; hold off ; plot(real(s(off+1:off+len,chan)),'-o',"markersize",2) ; hold on ; plot(imag(s(off+1:off+len,chan)),'r-o',"markersize",2)
chan=1; s = oarf_get_frame(card); hold off ; grid on; plot(real(s(:,chan)),'b-o',"markersize",2) ; hold on ; plot(imag(s(:,chan)),'r-o',"markersize",2)
@@ -1,44 +0,0 @@
% Try out multicard setup
limeparms;
eNBflag = 0;
tdd_config = DUPLEXMODE_FDD + TXRXSWITCH_LSB;
rf_mode = ( RXEN + TXEN + TXLPFNORM + TXLPFEN + TXLPF25 + RXLPFNORM + RXLPFEN + RXLPF25 + LNA1ON +LNAMax + RFBBNORM )*[1 0 0 0];
rf_mode = rf_mode + (DMAMODE_RX + DMAMODE_TX)*[1 0 0 0];
freq_rx = (1908600000 - 0*9000)*[1 1 1 1];
freq_tx = freq_rx + 0000000; % 1kHz offset: @30 MSPS: 2.5 sines, @15 MSPS: 5 sines, @7 MSPS: 10 sines
rf_local= [ rfl(20,25,26,04) 0 0 0 ]; % 1.9 GHz & 860 MHz, VGA2Gain=0
rf_vcocal=(( 0xE)*(2^6)) + ( 0xE)*[1 1 1 1]; % 1.907 GHz, (OLD)
tx_gain = 13*[1 1 1 1];
rx_gain = 20*[1 1 1 1];
rf_rxdc = rf_rxdc*[1 1 1 1];
% set first card to slave mode
card=1; % -1 for all cards
syncmode = SYNCMODE_SLAVE;
oarf_config_exmimo(card,freq_rx,freq_tx,tdd_config,syncmode,rx_gain,tx_gain,eNBflag,rf_mode,rf_rxdc,rf_local,rf_vcocal)
sleep(1)
% set second card to master mode
card=0; % -1 for all cards
syncmode = SYNCMODE_MASTER;
oarf_config_exmimo(card,freq_rx,freq_tx,tdd_config,syncmode,rx_gain,tx_gain,eNBflag,rf_mode,rf_rxdc,rf_local,rf_vcocal)
sleep(1)
% create_testvector
vlen=76800
%v=5000*exp(-i*(300*[0:vlen-1]/vlen)*2*pi); v=[v;v;v;v]'; oarf_send_frame(0,v,16);
%v=5000*exp(-i*( 30*[0:vlen-1]/vlen)*2*pi); v=[v;v;v;v]'; oarf_send_frame(1,v,16);
%len=1000;off=0; chan=2; s=oarf_get_frame(card); hold off ; plot(real(s(off+1:off+len,chan)),'-o',"markersize",2) ; hold on ; plot(imag(s(off+1:off+len,chan)),'r-o',"markersize",2)
%while 1;len=5000;off=0; chan=1; s = oarf_get_frame(card); hold off ; plot(real(s(off+1:off+len,chan)),'-o',"markersize",2) ; hold on ; plot(imag(s(off+1:off+len,chan)),'r-o',"markersize",3); sleep(0.3);endwhile
%while 1;len=vlen;off=0; chan=[1 5]; s = oarf_get_frame(-1); hold off ; plot(real(s(off+1:off+len,chan)),'-o',"markersize",2) ; hold on ; plot(imag(s(off+1:off+len,chan)),'r-o',"markersize",3); sleep(0.5);endwhile
v = 5000* [ zeros(1,1000) ones(1,500) zeros(1,500) ones(1,1) zeros(1,vlen-1000-1000-1)]; v=[v;v;v;v]'; oarf_send_frame(1,v,16);
sleep(1)
len=2500;off=0; chan=[1 5]; s = oarf_get_frame(-1); hold off ; plot(real(s(off+1:off+len,chan)),'-o',"markersize",2) ; hold on ; plot(imag(s(off+1:off+len,chan)),'r-o',"markersize",2);
@@ -1,44 +0,0 @@
dual_tx=0;
eNBflag = 0;
card=0;
limeparms;
% internal loopback test
rf_mode = (RXEN+TXEN+TXLPFNORM+TXLPFEN+TXLPF5+RXLPFNORM+RXLPFEN+RXLPF5+LNA1ON+LNAByp+RFBBLNA1)*[1 1 0 0];
%rf_mode = [0 0 0 0];
%% Select DMA directions
%rf_mode = rf_mode + (DMAMODE_RX)*[1 0 0 0 ];
%rf_mode = rf_mode + (DMAMODE_RX)*[1 1 0 0];
%rf_mode = rf_mode + (DMAMODE_TX)*[1 1 0 0];
%rf_mode = rf_mode + (DMAMODE_RX + DMAMODE_TX)*[1 0 0 0];
rf_mode = rf_mode + (DMAMODE_RX + DMAMODE_TX)*[1 0 0 0];
freq_rx = 1907600000*[1 1 1 1];
rf_local= [8254744 8255063 8257340 8257340]; % 1.9 GHz
rf_vcocal=((0xE)*(2^6)) + (0xE)*[1 1 1 1]; % 1.9 GHz
freq_tx = freq_rx + 1;
tx_gain = 25*[1 1 1 1];
rx_gain = 20*[1 1 1 1];
rf_rxdc = rf_rxdc*[1 1 1 1];
oarf_config_exmimo(card, freq_rx,freq_tx,0,dual_tx,rx_gain,tx_gain,eNBflag,rf_mode,rf_rxdc,rf_local,rf_vcocal)
% create_testvector
vlen=76800
%v=([2:1+vlen; 10002:10001+vlen] - i*[3:2+vlen; 10003:10002+vlen])'; % achtung, wrapped nicht!
v = floor(( [640:639+vlen ; 640:639+vlen] / 5 ))';
break
sleep(5)
oarf_send_frame(card,v,16);
%len=1000;off=0; chan=2; hold off ; plot(real(s(off+1:off+len,chan)),'-o',"markersize",2) ; hold on ; plot(imag(s(off+1:off+len,chan)),'r-o',"markersize",2)
chan=1; s = oarf_get_frame(card); hold off ; plot(real(s(:,chan)),'b',"markersize",1) ; % hold on ; plot(imag(s(:,chan)),'r',"markersize",1)
@@ -1,105 +0,0 @@
close all
clear all
hold off
card = 0;
% Maxime Guillaud - created Wed May 10 18:08:04 CEST 2006
gpib_card=0; % first GPIB PCI card in the computer
gpib_device=28; % this is configured in the signal generator Utilities->System->GPIB->Address menu
cables_loss_dB = 6; % we need to account for the power loss between the signal generator and the card input (splitter, cables)
dual_tx = 0;
tdd = 1;
fc = 1907600e3;
%fc = 2.68e9;
fs = 7680e3;
%fs = 6500e3;
fref = fc+fs/4;
power_dBm=-70;
f_off_min = 1e6;
limeparms;
%rf_mode = (RXEN+TXEN+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNAMax+RFBBNORM)*[1 1 1 1];
rf_mode = (RXEN+0+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNAMax+RFBBNORM+DMAMODE_RX+0)*[1 0 0 0];
freq_rx = fc*[1 0 0 0];
freq_tx = freq_rx+1920000;
rx_gain = 30*[1 1 1 1];
tx_gain = 25*[1 1 1 1];
%rf_local=rf_local*[1 1 1 1];
rf_local = [8254813 8255016 8254813 8254813]; %exmimo2_2
%rf_rxdc =rf_rxdc*[1 1 1 1];
rf_rxdc = [37059 35459 36300 36999]; %exmimo2_2
rf_vcocal=rf_vcocal_19G*[1 1 1 1];
tdd_config = DUPLEXMODE_FDD + TXRXSWITCH_LSB;
syncmode = SYNCMODE_FREE;
rffe_rxg_low = 63*[1 1 1 1];
rffe_rxg_final = 31*[1 1 1 1];
rffe_band = B19G_TDD*[1 1 1 1];
autocal = [1 1 1 1];
resampling = [2 2 2 2];
%gpib_send(gpib_card,gpib_device,'*RST;*CLS'); % reset and configure the signal generator
%gpib_send(gpib_card,gpib_device,['POW ' int2str(power_dBm+cables_loss_dB) 'dBm']);
%gpib_send(gpib_card,gpib_device,['FREQ 1.91860 Ghz']); % set the frequency
%gpib_send(gpib_card,gpib_device,['FREQ ' int2str(fref/1e3) 'khz']); % set the frequency
%gpib_send(gpib_card,gpib_device,'OUTP:STAT ON'); % activate output
%keyboard;
sleep(2)
step = 4096;
i=0;
do
format long
fc
freq_rx = fc*[1 0 0 0];
freq_tx = freq_rx+1920000;
oarf_config_exmimo(card, freq_rx,freq_tx,tdd_config,syncmode,rx_gain,tx_gain,0,rf_mode,rf_rxdc,rf_local,rf_vcocal,rffe_rxg_low,rffe_rxg_final,rffe_band,autocal,resampling);
i=i+1;
sleep(1);
s=oarf_get_frame(card); %oarf_get_frame
s(76801:end,:)=[];
nb_rx = 1; %size(s,2);
% find the DC component
m = mean(s);
s_phase = unwrap(angle(s(10000:4:length(s),1).'));
s_phase = s_phase - s_phase(1,1);
f_off = mean(s_phase(2:length(s_phase))*fs/4./(1:(length(s_phase)-1))/2/pi)
plot(1:length(s_phase),s_phase,'r');
if (nb_rx>1)
s_phase2 = unwrap(angle(s(10000:4:length(s),2).'));
s_phase2 = s_phase2 - s_phase2(1,1);
f_off2 = mean(s_phase2(2:length(s_phase2))*fs/4./(1:(length(s_phase2)-1))/2/pi)
hold on
plot(1:length(s_phase2),s_phase2,'g');
drawnow;
hold off
end
if (abs(f_off) < f_off_min)
f_off_min = abs((f_off));
end
if ((f_off) > 0)
fc = fc + step;
else
fc = fc - step;
endif
step = step/2;
until (step < 50)
%gpib_send(gpib_card,gpib_device,'OUTP:STAT OFF'); % deactivate output
@@ -1,121 +0,0 @@
/*
* 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
*/
// Maxime Guillaud - created Wed May 10 19:23:30 CEST 2006
// see http://www.gnu.org/software/octave/doc/interpreter/Dynamically-Linked-Functions.html#Dynamically-Linked-Functions
// and http://octave.sourceforge.net/coda/c58.html
// compile with: mkoctfile -I/usr/local/include/gpib -lgpib gpib_send.cc
#include <octave/oct.h>
#include <gpib/ib.h>
static bool any_bad_argument(const octave_value_list &args)
{
if (args.length()!=3)
{
error("gpib_send: syntax: gpib_send(gpib_board,gpib_device,gpib_str).");
return true;
}
if (!args(0).is_real_scalar())
{
error("gpib_send: GPIB board number must be a positive integer.");
return true;
}
if (args(0).scalar_value() < 0.0)
{
error("gpib_send: GPIB board number must be a positive integer.");
return true;
}
if (floor(args(0).scalar_value()) != args(0).scalar_value())
{
error("gpib_send: GPIB board number must be a positive integer.");
return true;
}
if (!args(1).is_real_scalar())
{
error("gpib_send: GPIB device number must be a positive integer.");
return true;
}
if (args(1).scalar_value() < 0.0)
{
error("gpib_send: GPIB device number must be a positive integer.");
return true;
}
if (floor(args(1).scalar_value()) != args(1).scalar_value())
{
error("gpib_send: GPIB device number must be a positive integer.");
return true;
}
if (!args(2).is_string())
{
error("gpib_send: third parameter must be a char string.");
return true;
}
return false;
}
DEFUN_DLD (gpib_send, args, nargout,"sends commands to the GPIB bus")
{
if (any_bad_argument(args))
return octave_value_list();
const int gpib_board = args(0).int_value();
const int gpib_device = args(1).int_value();
const std::string gpib_string = args(2).string_value();
unsigned short addlist[2] = {gpib_device, NOADDR};
SendIFC(gpib_board);
// ENABLE all on GPIB bus
EnableRemote(gpib_board, addlist);
// If error, Bye!
if (ibsta & ERR)
{
error("gpib_send: Instrument enable failed!");
return octave_value_list();
}
Send(gpib_board, gpib_device, gpib_string.c_str(), strlen(gpib_string.c_str()), NLend);
if (ibsta & ERR)
{
error("gpib_send: Send failed!");
return octave_value_list();
}
return octave_value_list();
}
@@ -1,78 +0,0 @@
clear all
close all
addpath([getenv('OPENAIR1_DIR') '/PHY/LTE_REFSIG/']);
addpath([getenv('OPENAIR1_DIR') '/PHY/LTE_TRANSPORT/']);
primary_synch; %loads the primary sync signal
sss_gen; %loads the secondary sync signal
% grab a frame
ch=1;
rx_spec;
% load frame
%addpath([getenv('OPENAIR_TARGETS') '/SIMU/USER/']);
%eNBtxsig1
%s = txs1;
figure(1)
plot(real(s))
pss_t = upsample(primary_synch0_time,4);
[corr,lag] = xcorr(s(:,ch).',pss_t);
figure(2);
plot(lag,abs(corr));
[pss_amp, pss_pos0] = max(abs(corr));
pss_pos = lag(pss_pos0);
%pss_pos = 8817;
%sss_pos = pss_pos - 548; %FDD normal CP
%sss_pos = pss_pos - 640; %FDD extended CP
sss_pos = pss_pos - 1648; %TDD normal CP
%sss_pos = pss_pos - 1920; %TDD extended CP
psst = s([pss_pos:(pss_pos+511)],ch);
pssf = fft(psst);
ssst = s([sss_pos:(sss_pos+511)],ch);
sssf = fft(ssst);
pssf_ext = pssf([(512-30):512 2:32]); % extract innter 62 subcarriers
sssf_ext = sssf([(512-30):512 2:32]); % extract innter 62 subcarriers
%estimate channel from pss
pss_ch = pssf_ext.*(primary_synch0(6:67)');
pss_ch = pss_ch./mean(abs(pss_ch));
%compensate sssf_ext with channel
sssf_comp = sssf_ext.*conj(pss_ch);
% frequency domain correlation (dot-wise product) of sssf_comp and d0 and d5
% account for phase offset
Nid2=0;
for Nid1=0:167
for phase=0; %-4:4
corr0(Nid1+1,phase+1) = d0(Nid2+Nid1*3+1,:)*conj(sssf_comp*exp(1j*pi*phase/8));
corr5(Nid1+1,phase+1) = d5(Nid2+Nid1*3+1,:)*conj(sssf_comp*exp(1j*pi*phase/8));
end
end
figure(3)
plot(abs(corr0))
figure(4)
plot(abs(corr5))
[m0,i0] = max(abs(corr0(:)));
[m5,i5] = max(abs(corr5(:)));
if (m0>m5)
frame_start = pss_pos - 8816
phase = floor((i0-1)/168) %phase
Nid1 = mod(i0-1,168) %Nid
else
frame_start = pss_pos - 47216
phase = floor((i5-1)/168) %phase
Nid1 = mod(i5-1,168) %Nid
end
@@ -1,218 +0,0 @@
clear;
card=0;
limeparms;
TX_LO_LEAKAGE_MIN0 = 99999;
TX_LO_LEAKAGE_MIN1 = 99999;
freq_rx = 1907600000*[1 1 1 1];
%freq_rx = 859500000*[1 1 1 1];
freq_tx = freq_rx+1920000;
rf_vcocal = rf_vcocal_19G*[1 1 1 1];
rf_rxdc = rf_rxdc*[1 1 1 1];
rxgain = 30*[1 1 1 1];
txgain = 25*[1 1 1 1];
tdd_config = DUPLEXMODE_FDD + TXRXSWITCH_LSB;
syncmode = SYNCMODE_FREE;
rffe_rxg_low = 31*[1 1 1 1];
rffe_rxg_final = 31*[1 1 1 1];
rffe_band = TVWS_TDD*[1 1 1 1];
sleepafterconfig=0.2
% coarse calibration loop for both rx chains
for txdc_I=0:4:63
for txdc_Q=0:4:63
rf_mode = (RXEN+TXEN+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNAByp+RFBBLNA1)*[1 1 0 0];
rf_mode = rf_mode + (DMAMODE_RX+DMAMODE_TX)*[1 1 0 0];
rf_local = (txdc_I + (txdc_Q)*(2^6) + 31*(2^12) + 31*(2^18))*[1 1 1 1];
oarf_config_exmimo(card, freq_rx,freq_tx,tdd_config,syncmode,rxgain,txgain,0,rf_mode,rf_rxdc,rf_local,rf_vcocal,rffe_rxg_low,rffe_rxg_final,rffe_band);
sleep(sleepafterconfig)
s=oarf_get_frame(card);
sF0 = 20*log10(abs(fftshift(fft(s(:,1)))));
sF1 = 20*log10(abs(fftshift(fft(s(:,2)))));
f = (7.68*(0:length(s(:,1))-1)/(length(s(:,1))))-3.84;
spec0 = sF0;
spec1 = sF1;
RX_LO_LEAKAGE0 = sF0(1+(length(sF0)/2));
TX_LO_LEAKAGE0 = sF0(1+(.75*length(sF0)));
TX_SIG0 = sF0(1+((11/16)*length(sF0)));
TX_IQ0 = sF0(1+((13/16)*length(sF0))) - TX_SIG0;
RX_IQ0 = sF0(1+((5/16)*length(sF0))) - TX_SIG0;
RX_LO_LEAKAGE1 = sF1(1+(length(sF0)/2));
TX_LO_LEAKAGE1 = sF1(1+(.75*length(sF0)));
TX_SIG1 = sF1(1+((11/16)*length(sF0)));
TX_IQ1 = sF1(1+((13/16)*length(sF0))) - TX_SIG1;
RX_IQ1 = sF1(1+((5/16)*length(sF0))) - TX_SIG1;
% subplot(211)
% plot(f',spec0,'r')
% axis([-3.84,3.84,40,160])
% subplot(212)
% plot(f',spec1,'b')
% axis([-3.84,3.84,40,160])
% grid
% drawnow
if (TX_LO_LEAKAGE0 < TX_LO_LEAKAGE_MIN0)
TX_LO_LEAKAGE_MIN0=TX_LO_LEAKAGE0;
txdc_I_min0 = txdc_I;
txdc_Q_min0 = txdc_Q;
TX_LO_LEAKAGE0
txdc_I_min0
txdc_Q_min0
fflush(stdout);
end
if (TX_LO_LEAKAGE1 < TX_LO_LEAKAGE_MIN1)
TX_LO_LEAKAGE_MIN1=TX_LO_LEAKAGE1;
txdc_I_min1 = txdc_I;
txdc_Q_min1 = txdc_Q;
TX_LO_LEAKAGE1
txdc_I_min1
txdc_Q_min1
fflush(stdout);
end
end
end
% fine calibration loop for RX1 (RX2 stays constant)
txdc_I_min02 = txdc_I_min0;
txdc_Q_min02 = txdc_Q_min0;
for deltaI = -3:3,
for deltaQ = -3:3,
txdc_I = txdc_I_min0 + deltaI;
txdc_Q = txdc_Q_min0 + deltaQ;
if (txdc_I>=0) && (txdc_Q>=0) && (txdc_I < 64) && (txdc_Q < 64)
% printf("txdc_IQ => (%d,%d)\n",txdc_I,txdc_Q);
% fflush(stdout);
rf_local(1) = txdc_I + (txdc_Q)*(2^6) + 31*(2^12) + 31*(2^18);
rf_local(2) = txdc_I_min1 + (txdc_Q_min1)*(2^6) + 31*(2^12) + 31*(2^18);
oarf_config_exmimo(card, freq_rx,freq_tx,tdd_config,syncmode,rxgain,txgain,0,rf_mode,rf_rxdc,rf_local,rf_vcocal,rffe_rxg_low,rffe_rxg_final,rffe_band);
sleep(sleepafterconfig)
s=oarf_get_frame(card);
sF0 = 20*log10(abs(fftshift(fft(s(:,1)))));
spec0 = sF0;
spec1 = sF1;
RX_LO_LEAKAGE = sF0(1+(length(sF0)/2));
TX_LO_LEAKAGE = sF0(1+(.75*length(sF0)));
TX_SIG = sF0(1+((11/16)*length(sF0)));
TX_IQ = sF0(1+((13/16)*length(sF0))) - TX_SIG;
RX_IQ = sF0(1+((5/16)*length(sF0))) - TX_SIG;
% subplot(211)
% plot(f',spec0,'r')
% axis([-3.84,3.84,40,160])
% grid
% drawnow
if (TX_LO_LEAKAGE < TX_LO_LEAKAGE_MIN0)
TX_LO_LEAKAGE_MIN0=TX_LO_LEAKAGE;
txdc_I_min02 = txdc_I;
txdc_Q_min02 = txdc_Q;
TX_LO_LEAKAGE
txdc_I_min02
txdc_Q_min02
fflush(stdout);
end
end
end
end
% fine calibration loop for RX2 (RX1 stays constant)
txdc_I_min12 = txdc_I_min1;
txdc_Q_min12 = txdc_Q_min1;
for deltaI = -3:3,
for deltaQ = -3:3,
txdc_I = txdc_I_min1 + deltaI;
txdc_Q = txdc_Q_min1 + deltaQ;
if (txdc_I>=0) && (txdc_Q>=0) && (txdc_I < 64) && (txdc_Q < 64)
% printf("txdc_IQ => (%d,%d)\n",txdc_I,txdc_Q);
% fflush(stdout);
% rf_local = txdc_I_min02 + (txdc_Q_min02)*(2^6) + (txdc_I)*(2^12) + (txdc_Q)*(2^18);
rf_local(1) = txdc_I_min02 + (txdc_Q_min02)*(2^6) + 31*(2^12) + 31*(2^18);
rf_local(2) = txdc_I + (txdc_Q)*(2^6) + 31*(2^12) + 31*(2^18);
oarf_config_exmimo(card, freq_rx,freq_tx,tdd_config,syncmode,rxgain,txgain,0,rf_mode,rf_rxdc,rf_local,rf_vcocal,rffe_rxg_low,rffe_rxg_final,rffe_band);
sleep(sleepafterconfig)
s=oarf_get_frame(card);
sF1 = 20*log10(abs(fftshift(fft(s(:,2)))));
spec1 = sF1;
RX_LO_LEAKAGE = sF1(1+(length(sF0)/2));
TX_LO_LEAKAGE = sF1(1+(.75*length(sF0)));
TX_SIG = sF1(1+((11/16)*length(sF0)));
TX_IQ = sF1(1+((13/16)*length(sF0))) - TX_SIG;
RX_IQ = sF1(1+((5/16)*length(sF0))) - TX_SIG;
% subplot(212)
% plot(f',spec1,'b')
% axis([-3.84,3.84,40,160])
% grid
% drawnow
if (TX_LO_LEAKAGE < TX_LO_LEAKAGE_MIN1)
TX_LO_LEAKAGE_MIN1=TX_LO_LEAKAGE;
txdc_I_min12 = txdc_I;
txdc_Q_min12 = txdc_Q;
TX_LO_LEAKAGE
txdc_I_min12
txdc_Q_min12
fflush(stdout);
end
end
end
end
TX_LO_LEAKAGE_MIN0
txdc_I_min02
txdc_Q_min02
TX_LO_LEAKAGE_MIN1
txdc_I_min12
txdc_Q_min12
rf_local(1) = txdc_I_min02 + (txdc_Q_min02)*(2^6) + 31*(2^12) + 31*(2^18);
rf_local(2) = txdc_I_min12 + (txdc_Q_min12)*(2^6) + 31*(2^12) + 31*(2^18);
oarf_config_exmimo(card, freq_rx,freq_tx,tdd_config,syncmode,rxgain,txgain,0,rf_mode,rf_rxdc,rf_local,rf_vcocal,rffe_rxg_low,rffe_rxg_final,rffe_band);
sleep(sleepafterconfig)
s=oarf_get_frame(card);
sF0 = 20*log10(abs(fftshift(fft(s(:,1)))));
sF1 = 20*log10(abs(fftshift(fft(s(:,2)))));
spec0 = sF0;
spec1 = sF1;
RX_LO_LEAKAGE = sF0(1+(length(sF0)/2))
TX_LO_LEAKAGE = sF0(1+(.75*length(sF0)))
TX_SIG = sF0(1+((11/16)*length(sF0)))
TX_IQ = sF0(1+((13/16)*length(sF0))) - TX_SIG
RX_IQ = sF0(1+((5/16)*length(sF0))) - TX_SIG
RX_LO_LEAKAGE = sF1(1+(length(sF0)/2))
TX_LO_LEAKAGE = sF1(1+(.75*length(sF0)))
TX_SIG = sF1(1+((11/16)*length(sF0)))
TX_IQ = sF1(1+((13/16)*length(sF0))) - TX_SIG
RX_IQ = sF1(1+((5/16)*length(sF0))) - TX_SIG
subplot(211)
plot(f',spec0,'r')
subplot(212)
plot(f',spec1,'b')
axis([-3.84,3.84,40,160])
grid
drawnow
%gpib_send(gpib_card,gpib_device,'OUTP:STAT OFF'); % activate output
%legend('Antenna Port 0','Antenna Port 1');
grid
rf_local
@@ -1,131 +0,0 @@
clear all
close all
card=0;
limeparms;
freq_rx = 1907600000*[1 1 1 1];
%freq_rx = 700600000*[1 1 1 1];
%freq_rx = 748000000*[1 1 1 1];
freq_tx = freq_rx+1920000;
rxgain = 30*[1 1 1 1];
txgain = 0*[1 1 1 1];
tdd_config = DUPLEXMODE_FDD + TXRXSWITCH_TESTRX;
syncmode = SYNCMODE_FREE;
autocal = [1 1 1 1];
resampling = [2 2 2 2];
rf_mode = (RXEN+0+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNAMax+RFBBNORM+DMAMODE_RX+0) * [1 1 1 1];
rf_local = [8254813 8255016 8254813 8254813]; % from the tx calibration
%rf_local = [8255842 8255064 8257340 8257340]; % 700MHz
%rf_local = [8256776 8255788 8257340 8257340]; % 850MHz
rf_rxdc = rf_rxdc*[1 1 1 1]; % initial value
rf_vcocal= rf_vcocal_19G*[1 1 1 1];
rffe_rxg_low = 31*[1 1 1 1];
rffe_rxg_final = 31*[1 1 1 1];
rffe_band = B19G_TDD*[1 1 1 1];
oarf_config_exmimo(card, freq_rx,freq_tx,tdd_config,syncmode,rxgain,txgain,0,rf_mode,rf_rxdc,rf_local,rf_vcocal,rffe_rxg_low,rffe_rxg_final,rffe_band,autocal,resampling);
autocal = [2 2 2 2];
sleepafterconfig=0.2
% coarse calibration loop for both rx chains
for ant=1:4
%rf_mode = zeros(1,4);
%rf_mode(ant) = (RXEN+0+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNAMax+RFBBNORM+DMAMODE_RX+0);
dc_off_re_min = 99999;
dc_off_im_min = 99999;
stepsize = 64;
rxdc_Q_s = 0;
rxdc_I = 0;
while (stepsize>=1)
stepsize = stepsize/2;
if (rxdc_I<0)
rxdc_I_s = 64+abs(rxdc_I);
else
rxdc_I_s = rxdc_I;
end
rf_rxdc(ant) = ((128+rxdc_I_s) + (128+rxdc_Q_s)*(2^8));
oarf_config_exmimo(card, freq_rx,freq_tx,tdd_config,syncmode,rxgain,txgain,0,rf_mode,rf_rxdc,rf_local,rf_vcocal,rffe_rxg_low,rffe_rxg_final,rffe_band,autocal,resampling);
sleep(sleepafterconfig)
s=oarf_get_frame(card);
figure(1)
plot(real(s));
ylim([-2048 2048]);
drawnow;
%sF0 = 20*log10(abs(fftshift(fft(s(:,1)))));
%sF1 = 20*log10(abs(fftshift(fft(s(:,2)))));
%f = (7.68*(0:length(s(:,1))-1)/(length(s(:,1))))-3.84;
%spec0 = sF0;
%spec1 = sF1;
rxdc_I
rxdc_I_s
dc_offset = mean(s(:,ant));
fflush(stdout);
if (abs(real(dc_offset))<dc_off_re_min)
dc_off_re_min = abs(real(dc_offset));
rxdc_I_min(ant) = rxdc_I_s;
end
if (real(dc_offset)>0)
rxdc_I = rxdc_I+stepsize;
else
rxdc_I = rxdc_I-stepsize;
end
end
stepsize = 64;
rxdc_Q = 0;
while (stepsize>=1)
stepsize = stepsize/2;
if (rxdc_Q<0)
rxdc_Q_s = 64+abs(rxdc_Q);
else
rxdc_Q_s = rxdc_Q;
end
rf_rxdc(ant) = ((128+rxdc_I_s) + (128+rxdc_Q_s)*(2^8));
oarf_config_exmimo(card, freq_rx,freq_tx,tdd_config,syncmode,rxgain,txgain,0,rf_mode,rf_rxdc,rf_local,rf_vcocal,rffe_rxg_low,rffe_rxg_final,rffe_band,autocal,resampling);
sleep(sleepafterconfig)
s=oarf_get_frame(card);
figure(2)
plot(imag(s));
ylim([-2048 2048]);
drawnow;
%sF0 = 20*log10(abs(fftshift(fft(s(:,1)))));
%sF1 = 20*log10(abs(fftshift(fft(s(:,2)))));
%f = (7.68*(0:length(s(:,1))-1)/(length(s(:,1))))-3.84;
%spec0 = sF0;
%spec1 = sF1;
rxdc_Q
rxdc_Q_s
dc_offset = mean(s(:,ant));
fflush(stdout);
if (abs(imag(dc_offset))<dc_off_im_min)
dc_off_im_min = abs(imag(dc_offset));
rxdc_Q_min(ant) = rxdc_Q_s;
end
if (imag(dc_offset)>0)
rxdc_Q = rxdc_Q+stepsize;
else
rxdc_Q = rxdc_Q-stepsize;
end
end
end
rxdc_I_min
rxdc_Q_min
rf_rxdc_min = ((128+rxdc_I_min) + (128+rxdc_Q_min)*(2^8))
@@ -1,122 +0,0 @@
% Octave defines, according to pcie_interface.h
% Parameters for rf_mode in structure exmimo_rf_t
RXEN=1;
TXEN=2;
TXLPFENMASK=4;
TXLPFEN=4;
TXLPFMASK =15*(2^3);
TXLPF14 =0;
TXLPF10 =1*(2^3);
TXLPF7 =2*(2^3);
TXLPF6 =3*(2^3);
TXLPF5 =4*(2^3);
TXLPF4375 =5*(2^3);
TXLPF35 =6*(2^3);
TXLPF3 =7*(2^3);
TXLPF275 =8*(2^3);
TXLPF25 =9*(2^3);
TXLPF192 =10*(2^3);
TXLPF15 =11*(2^3);
TXLPF1375 =12*(2^3);
TXLPF125 =13*(2^3);
TXLPF0875 =14*(2^3);
TXLPF075 =15*(2^3);
RXLPFENMASK=1*(2^7);
RXLPFEN =128;
RXLPFMASK =15*(2^8);
RXLPF14 =0;
RXLPF10 =1*(2^8);
RXLPF7 =2*(2^8);
RXLPF6 =3*(2^8);
RXLPF5 =4*(2^8);
RXLPF4375 =5*(2^8);
RXLPF35 =6*(2^8);
RXLPF3 =7*(2^8);
RXLPF275 =8*(2^8);
RXLPF25 =9*(2^8);
RXLPF192 =10*(2^8);
RXLPF15 =11*(2^8);
RXLPF1375 =12*(2^8);
RXLPF125 =13*(2^8);
RXLPF0875 =14*(2^8);
RXLPF075 =15*(2^8);
LNAMASK=3*(2^12);
LNADIS =0;
LNA1ON =1*(2^12);
LNA2ON =2*(2^12) ;
LNA3ON =3*(2^12);
LNAGAINMASK=3*(2^14);
LNAByp =1*(2^14);
LNAMed =2*(2^14);
LNAMax =3*(2^14);
RFBBMASK =7*(2^16);
RFBBNORM =0;
RFBBRXLPF =1*(2^16);
RFBBRXVGA =2*(2^16);
RFBBOUTPUT=3*(2^16);
RFBBLNA1 =4*(2^16);
RFBBLNA2 =5*(2^16);
RFBBLNA3 =6*(2^16);
RXLPFMODEMASK=3*(2^19);
RXLPFNORM =0;
RXLPFBYP =1*(2^19);
RXLPFBPY2 =3*(2^19);
TXLPFMODEMASK=1*(2^21);
TXLPFNORM =0;
TXLPFBYP =1*(2^21);
RXOUTSW =1*(2^22);
DMAMODE_TRXMASK =3*(2^23);
DMAMODE_RX =1*(2^23);
DMAMODE_TX =2*(2^23);
rf_local = 31 + 31*(2^6) + 31*(2^12) + 31*(2^18);
rf_rxdc = 0 + 0*(2^8); % DC offset ( DCOFF_I_RXFE [6:0], DCOFF_Q_RXFE[14:8] )
rf_vcocal_19G = ((0xE)*(2^6)) + (0xE); % VCO calibration values for 1.9 GHz
rf_vcocal_700 = ((0x24)*(2^6)) + (0x24); % 700 MHz
rf_vcocal_850 = ((0x1d)*(2^6)) + (0x1d); %850 MHz
rf_vcocal_859 = ((31)*(2^6)) + (31); %859.5 MHz
%rf_vcocal_26G_eNB = ((0x1f)*(2^6)) + (0x13);
%rf_vcocal_26G_UE = ((0x13)*(2^6)) + (0x1f);
rf_vcocal_26G_UE = ((0x3)*(2^6)) + (0x26);
rf_vcocal_26G_eNB = ((0x26)*(2^6)) + (0x0);
% register values and masks for tdd_config
DUPLEXMODE_MASK = 1*(2^0);
DUPLEXMODE_FDD = 0;
DUPLEXMODE_TDD = 2*(2^0);
TXRXSWITCH_MASK = 3*(2^1);
TXRXSWITCH_LSB = 0;
TXRXSWITCH_FPGA = 1*(2^1);
TXRXSWITCH_TESTRX = 2*(2^1);
TXRXSWITCH_TESTTX = 3*(2^1);
SWITCHSTATE_MASK = 1*(2^3);
SWITCHSTATE_0 = 0;
SWITCHSTATE_1 = 1*(2^3);
TEST_ADACLOOP_MASK= 1*(2^4);
TEST_ADACLOOP_EN = 1*(2^4);
% multicard synchronization mode (multicard_syncmode)
SYNCMODE_FREE = 0;
SYNCMODE_MASTER = 1;
SYNCMODE_SLAVE = 2;
% external RF frontend
TVWS_TDD = 0;
DD_FDD = 1;
DD_TDD = 2;
B19G_TDD = 3;
B24G_TDD = 4;
B26G_TDD = 5;
B26G_FDD = 6;
B35G_TDD = 7;
B50G_TDD = 8;
@@ -1,22 +0,0 @@
/*
* 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
*/
volatile int oai_exit=0;
@@ -1,446 +0,0 @@
/*
* 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
*/
// Matthias Ihmig, based on code from Maxime Guillaud - created 28.01.2013
// see http://www.gnu.org/software/octave/doc/interpreter/Dynamically-Linked-Functions.html#Dynamically-Linked-Functions
// and http://wiki.octave.org/wiki.pl?CodaTutorial
// and http://octave.sourceforge.net/coda/c58.html
// compilation: see Makefile
#include <octave/oct.h>
#include "pcie_interface.h"
#include "oarf.h"
extern "C" {
#include "openair0_lib.h"
}
#define FCNNAME "oarf_config_exmimo"
#define TRACE 1
static bool any_bad_argument(const octave_value_list &args)
{
octave_value v,w;
int i;
if (args.length()!=17)
{
error(FCNNAME);
error("Wrong number of parameters! Did you add the card number as first parameter?");
error("syntax: oarf_config_exmimo(card,freqrx,freq_tx,tdd_config,syncmode,rxgain,txgain,eNB_flag,rf_mode,rx_dc,rf_local,rf_vcolocal,rffe_rxg_low,rffe_rxg_final,autocal,resampling_factor)");
return true;
}
v=args(1);
for (i=0;i<v.columns();i++) {
if ((real(v.row_vector_value()(i)) < 0.0) ||
(floor(real(v.row_vector_value()(i))) != real(v.row_vector_value()(i))) ||
(real(v.row_vector_value()(i)) > 3.9e9))
{
error(FCNNAME);
error("rx freqband %d must be 0-3.9e9",i);
return true;
}
}
v=args(2);
for (i=0;i<v.columns();i++) {
if ((real(v.row_vector_value()(i)) < 0.0) ||
(floor(real(v.row_vector_value()(i))) != real(v.row_vector_value()(i))) ||
(real(v.row_vector_value()(i)) > 3.9e9))
{
error(FCNNAME);
error("tx freqband %d must be 0-3.9e9",i);
return true;
}
}
if ((!args(3).is_real_scalar()))
{
error(FCNNAME);
error("tdd_config must be an integer.");
return true;
}
if ((!args(4).is_real_scalar()))
{
error(FCNNAME);
error("multicard_syncmode must be an integer.");
return true;
}
v=args(5);
if (v.columns() == 4)
{
for (i=0;i<v.columns();i++)
{
if ((real(args(5).row_vector_value()(i))<0.0) || (real(args(5).row_vector_value()(i))>63.0))
{
error(FCNNAME);
error("rx gain must be between 0 and 63. (got %f).",args(5).row_vector_value()(i));
return true;
}
}
}
else {
error(FCNNAME);
error("number of columns for rxgain must be 4 (got %d)\n",v.columns());
}
v=args(6);
if (v.columns() == 4)
{
for (i=0;i<v.columns();i++)
{
if ((real(args(6).row_vector_value()(i))<0.0) || (real(args(6).row_vector_value()(i))>63.0))
{
error(FCNNAME);
error("tx gain must be between 0 and 63. (got %f).",args(6).row_vector_value()(i));
return true;
}
}
}
else {
error(FCNNAME);
error("number of columns for txgain must be 4 (got %d)\n",v.columns());
}
if ((!args(7).is_real_scalar()) || (args(7).scalar_value()<0.0) || (args(7).scalar_value()>1)) {
error(FCNNAME);
error("eNB_flag must be between 0 and 1 (got %f).",args(7).scalar_value());
return true;
}
v = args(8);
if (v.columns() == 4)
{
for (i=0;i<v.columns();i++)
{
if ((v.row_vector_value()(i)<0.0) || (v.row_vector_value()(i)>(double)((uint32_t)(1<<31)))) {
error(FCNNAME);
error("rf_mode %d must be between 0 and 2^31 (got %f).",i,v.row_vector_value()(i));
return true;
}
}
}
else {
error(FCNNAME);
error("number of columns for rf_mode must be 4\n");
}
v = args(9);
if (v.columns() == 4)
{
for (i=0;i<v.columns();i++)
{
if ((v.row_vector_value()(i)<0.0) || (v.row_vector_value()(i)>(double)((uint32_t)(1<<16)))) {
error(FCNNAME);
error("rx_dc %d must be between 0 and 2^16 (got %f).",i,v.row_vector_value()(i));
return true;
}
}
}
else {
error(FCNNAME);
error("number of columns for rf_mode must be 4\n");
}
v = args(10);
if (v.columns() == 4)
{
for (i=0;i<v.columns();i++)
{
if ((v.row_vector_value()(i)<0.0) || (v.row_vector_value()(i)>(double)((uint32_t)(1<<24)))) {
error(FCNNAME);
error("rf_local %d must be between 0 and 2^24 (got %f).",i,v.row_vector_value()(i));
return true;
}
}
}
else {
error(FCNNAME);
error("number of columns for rf_local must be 4\n");
}
v = args(11);
if (v.columns() == 4)
{
for (i=0;i<v.columns();i++)
{
if ((v.row_vector_value()(i)<0.0) || (v.row_vector_value()(i)>(double)((uint32_t)(1<<12)))) {
error(FCNNAME);
error("rf_vcocal %d must be between 0 and 2^12 (got %f).",i,v.row_vector_value()(i));
return true;
}
}
}
else {
error(FCNNAME);
error("number of columns for rf_vcocal must be 4\n");
}
v = args(12);
if (v.columns() == 4)
{
for (i=0;i<v.columns();i++)
{
if ((v.row_vector_value()(i)<0.0) || (v.row_vector_value()(i)>63.0)) {
error(FCNNAME);
error("rffe_rxg_low %d must be between 0 and 63 (got %f).",i,v.row_vector_value()(i));
return true;
}
}
}
else {
error(FCNNAME);
error("number of columns for rffe_rxg_low must be 4\n");
}
v = args(13);
if (v.columns() == 4)
{
for (i=0;i<v.columns();i++)
{
if ((v.row_vector_value()(i)<0.0) || (v.row_vector_value()(i)>63.0)) {
error(FCNNAME);
error("rffe_rxg_final %d must be between 0 and 63 (got %f).",i,v.row_vector_value()(i));
return true;
}
}
}
else {
error(FCNNAME);
error("number of columns for rffe_rxg_final must be 4\n");
}
v = args(14);
if (v.columns() == 4)
{
for (i=0;i<v.columns();i++)
{
if ((v.row_vector_value()(i)<0.0) || (v.row_vector_value()(i)>8.0)) {
error(FCNNAME);
error("rffe_band %d must be between 0 and 8 (got %f).",i,v.row_vector_value()(i));
return true;
}
}
}
else {
error(FCNNAME);
error("number of columns for rffe_band must be 4\n");
}
v = args(15);
if (v.columns() == 4)
{
for (i=0;i<v.columns();i++)
{
if ((v.row_vector_value()(i)<0.0) || (v.row_vector_value()(i)>2.0)) {
error(FCNNAME);
error("autocal %d must be 0 or 2 (got %f).",i,v.row_vector_value()(i));
return true;
}
}
}
else {
error(FCNNAME);
error("number of columns for autocal must be 4\n");
}
v = args(16);
if (v.columns() == 4)
{
for (i=0;i<v.columns();i++)
{
if ((v.row_vector_value()(i)<0.0) || (v.row_vector_value()(i)>2.0)) {
error(FCNNAME);
error("resampling_factor %d must be 0, 1 or 2 (got %f).",i,v.row_vector_value()(i));
return true;
}
}
}
else {
error(FCNNAME);
error("number of columns for resampling_factor must be 4\n");
}
if ( !args(0).is_real_scalar() )
{
error(FCNNAME);
error("card_id must be scalar (count starting from 0).\nUse card_id = -1 to send command to all cards.\nUse card_id = -2 to update config in memory, but do not send DUMP_CONFIG ioctl.");
return true;
}
return false;
}
DEFUN_DLD (oarf_config_exmimo, args, nargout,"configure the openair interface - returns 0 if successful")
{
int ret;
int ant;
int a,b;
int no_dump_config = 0;
if (any_bad_argument(args))
return octave_value_list();
int card = args(0).int_value();
RowVector freqrx = args(1).row_vector_value();
RowVector freqtx = args(2).row_vector_value();
const int tdd_config = args(3).int_value();
const int multicard_syncmode = args(4).int_value();
RowVector rxgain = args(5).row_vector_value();
RowVector txgain = args(6).row_vector_value();
const int eNB_flag = args(7).int_value();
RowVector rf_mode = args(8).row_vector_value();
RowVector rf_dc = args(9).row_vector_value();
RowVector rf_local = args(10).row_vector_value();
RowVector rf_vcocal = args(11).row_vector_value();
RowVector rffe_rxg_low = args(12).row_vector_value();
RowVector rffe_rxg_final = args(13).row_vector_value();
RowVector rffe_band = args(14).row_vector_value();
RowVector autocal = args(15).row_vector_value();
RowVector resampling_factor = args(16).row_vector_value();
int rffe_band_int;
exmimo_config_t *p_exmimo_config;
exmimo_id_t *p_exmimo_id;
octave_value returnvalue;
ret = openair0_open();
if ( ret != 0 )
{
error(FCNNAME);
if (ret == -1)
error("Error opening /dev/openair0");
if (ret == -2)
error("Error mapping bigshm");
if (ret == -3)
error("Error mapping RX or TX buffer");
if (ret == -5)
error("Error Firmware/Software do not match");
return octave_value(ret);
}
if (card == -2) {
no_dump_config = 1;
card = -1;
}
if (card <-1 || card >= openair0_num_detected_cards) {
warning("Invalid card number %d! Must be between 0 and %d. Or -1 for all card. Will assume -1.", openair0_num_detected_cards-1);
card = -1;
}
if (card == -1) {
a = 0;
b = openair0_num_detected_cards;
} else {
a = card;
b = card+1;
}
//printf("Number of cards: %d\n", openair0_num_detected_cards);
for (card = a; card < b; card++)
{
p_exmimo_config = openair0_exmimo_pci[card].exmimo_config_ptr;
p_exmimo_id = openair0_exmimo_pci[card].exmimo_id_ptr;
p_exmimo_config->framing.eNB_flag = eNB_flag;
p_exmimo_config->framing.tdd_config = tdd_config;
p_exmimo_config->framing.multicard_syncmode = multicard_syncmode;
// p_exmimo_config->framing.resampling_factor = 2;
for (ant=0; ant<4; ant++)
{
p_exmimo_config->rf.do_autocal[ant] = autocal(ant);
p_exmimo_config->rf.rf_freq_rx[ant] = freqrx(ant);
p_exmimo_config->rf.rf_freq_tx[ant] = freqtx(ant);
p_exmimo_config->rf.rx_gain[ant][0] = (uint32_t) rxgain(ant);
p_exmimo_config->rf.tx_gain[ant][0] = (uint32_t) txgain(ant);
p_exmimo_config->rf.rf_mode[ant] = rf_mode(ant);
p_exmimo_config->rf.rf_local[ant] = rf_local(ant);
p_exmimo_config->rf.rf_rxdc[ant] = rf_dc(ant);
p_exmimo_config->rf.rf_vcocal[ant] = rf_vcocal(ant);
p_exmimo_config->rf.rffe_gain_txlow[ant] = 31;
p_exmimo_config->rf.rffe_gain_txhigh[ant] = 31;
p_exmimo_config->rf.rffe_gain_rxfinal[ant] = rffe_rxg_final(ant);
p_exmimo_config->rf.rffe_gain_rxlow[ant] = rffe_rxg_low(ant);
p_exmimo_config->framing.resampling_factor[ant] = resampling_factor(ant);
rffe_band_int = (int) rffe_band(ant);
switch (rffe_band_int) {
case 0:
p_exmimo_config->rf.rffe_band_mode[ant] = TVWS_TDD;
break;
case 1:
p_exmimo_config->rf.rffe_band_mode[ant] = DD_FDD;
break;
case 2:
p_exmimo_config->rf.rffe_band_mode[ant] = DD_TDD;
break;
case 3:
p_exmimo_config->rf.rffe_band_mode[ant] = B19G_TDD;
break;
case 4:
p_exmimo_config->rf.rffe_band_mode[ant] = B24G_TDD;
break;
case 5:
p_exmimo_config->rf.rffe_band_mode[ant] = B26G_TDD;
break;
case 6:
p_exmimo_config->rf.rffe_band_mode[ant] = B26G_FDD;
break;
case 7:
p_exmimo_config->rf.rffe_band_mode[ant] = B35G_TDD;
break;
case 8:
p_exmimo_config->rf.rffe_band_mode[ant] = B50G_TDD;
break;
default:
p_exmimo_config->rf.rffe_band_mode[ant] = TVWS_TDD;
break;
}
}
if (no_dump_config == 0)
returnvalue = openair0_dump_config( card );
if (0)
printf("Card %d: ExpressMIMO %d, HW Rev. 0x%d, SW Rev 0x%d, SVN Rev %d, Builddate %d, %d antennas\n", card, p_exmimo_id->board_exmimoversion,
p_exmimo_id->board_hwrev, p_exmimo_id->board_swrev,
p_exmimo_id->system_id.bitstream_id, p_exmimo_id->system_id.bitstream_build_date,
openair0_num_antennas[card]);
}
openair0_close();
return octave_value(returnvalue);
}
@@ -1,213 +0,0 @@
/*
* 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
*/
// Maxime Guillaud - created Fri May 12 16:20:04 CEST 2006
// Matthias Ihmig, 2013
// see http://www.gnu.org/software/octave/doc/interpreter/Dynamically-Linked-Functions.html#Dynamically-Linked-Functions
// and http://wiki.octave.org/wiki.pl?CodaTutorial
// and http://octave.sourceforge.net/coda/c58.html
// compilation: see Makefile
// Update: Wed May 23 17:25:39 CEST 2007, fifo acquisition of signal buffer (RK)
// 29.01.2013: adopted to new kernel driver
#include <octave/oct.h>
extern "C" {
#include "openair0_lib.h"
}
#include "oarf.h"
#define FCNNAME "oarf_get_frame"
#define TRACE 1
#define FRAME_LENGTH_COMPLEX_SAMPLES 76800
static bool any_bad_argument(const octave_value_list &args)
{
octave_value v;
if (args.length()!=1)
{
error(FCNNAME);
error("syntax: oarf_get_frame(card)");
return true;
}
v=args(0);
if ((!v.is_real_scalar()) || (v.scalar_value() < -2) || (floor(v.scalar_value()) != v.scalar_value()) || (v.scalar_value() >= MAX_CARDS))
{
error(FCNNAME);
error("card must be 0-19 for a specific card, or -1 to get frame from all cards.\nSet framing.sync_mode =SYNCMODE_MASTER for one card and =SYNCMODE_SLAVE to obtain synchronized frames.\n");
return true;
}
return false;
}
int find_mastercard()
{
int card=0, found_master=0, i;
const char *str[] = { "FREE", "MASTER", "SLAVE" };
printf("Card configuration: card");
for (i=0; i<openair0_num_detected_cards; i++)
printf(" [%i]=%s,", i, str[ openair0_exmimo_pci[i].exmimo_config_ptr->framing.multicard_syncmode ]);
printf("\n");
for (i=0; i<openair0_num_detected_cards; i++)
{
if ( openair0_exmimo_pci[i].exmimo_config_ptr->framing.multicard_syncmode == SYNCMODE_MASTER )
{
if (found_master >= 1)
{
printf("Warning: There is more than one master active! Will put card[%i] back into SYNCMODE_FREE!\n", i);
openair0_exmimo_pci[i].exmimo_config_ptr->framing.multicard_syncmode == SYNCMODE_FREE;
}
else
{
card = i;
found_master++;
}
}
}
if (found_master == 0)
printf("Warning: No master activated! Will trigger getframe on card 0\n");
return card;
}
DEFUN_DLD (oarf_get_frame, args, nargout,"Get frame")
{
int numant, no_getframe_ioctl=0;
if (any_bad_argument(args))
return octave_value_list();
int card = args(0).int_value();
octave_value returnvalue;
int i,aa,j;
short *rx_sig[MAX_CARDS * MAX_ANTENNAS];
int ret;
int frame_length_samples[MAX_CARDS];
ret = openair0_open();
if ( ret != 0 )
{
error(FCNNAME);
if (ret == -1)
error("Error opening /dev/openair0");
if (ret == -2)
error("Error mapping bigshm");
if (ret == -3)
error("Error mapping RX or TX buffer");
return octave_value(ret);
}
if (card == -2)
{
no_getframe_ioctl = 1;
card = -1;
}
if (card <-1 || card >= openair0_num_detected_cards) {
error("card number must be between 0 and %d. Or -1 for all cards.", openair0_num_detected_cards-1);
return octave_value(-4);
}
if (card == -1) {
numant = openair0_num_detected_cards * openair0_num_antennas[0];
card = find_mastercard();
}
else
numant = openair0_num_antennas[card];
if ( no_getframe_ioctl )
{
// print mbox counters
for (i=0; i<numant; i++)
{
if ( numant == openair0_num_antennas[card] )
printf("rx_cnt[%d] = %d, tx_cnt[%d] = %d, ", i, *openair0_exmimo_pci[card].rxcnt_ptr[i],
i, *openair0_exmimo_pci[card].txcnt_ptr[i]);
else
printf("rx_cnt[%d] = %d, tx_cnt[%d] = %d, ", i, *openair0_exmimo_pci[i / (int)openair0_num_antennas[0]].rxcnt_ptr[i % openair0_num_antennas[0]],
i, *openair0_exmimo_pci[i / (int)openair0_num_antennas[0]].txcnt_ptr[i % openair0_num_antennas[0]]);
}
printf("\n");
}
for (i=0; i<openair0_num_detected_cards; i++)
{
if (openair0_exmimo_pci[i].exmimo_config_ptr->framing.resampling_factor[0] == 2)
frame_length_samples[i] = FRAME_LENGTH_COMPLEX_SAMPLES;
else if (openair0_exmimo_pci[i].exmimo_config_ptr->framing.resampling_factor[0] == 1)
frame_length_samples[i] = FRAME_LENGTH_COMPLEX_SAMPLES*2;
else if (openair0_exmimo_pci[i].exmimo_config_ptr->framing.resampling_factor[0] == 0)
frame_length_samples[i] = FRAME_LENGTH_COMPLEX_SAMPLES*4;
else
frame_length_samples[i] = FRAME_LENGTH_COMPLEX_SAMPLES;
}
printf("Info : Only resampling_factor of channel 0 is taken into account for copying received frame for all the other chains\n");
ComplexMatrix dx (FRAME_LENGTH_COMPLEX_SAMPLES*4, MAX_ANTENNAS*openair0_num_detected_cards);
/*
// set the tx buffer to 0x00010001 to put switch in rx mode
for (aa=0; aa<numant; aa++)
for (i=0; i<FRAME_LENGTH_COMPLEX_SAMPLES; i++)
((int*)(openair0_exmimo_pci[card].dac_head[aa]))[i] = 0x00010001;
*/
if ((openair0_exmimo_pci[card].exmimo_config_ptr->framing.tdd_config & TXRXSWITCH_MASK) != TXRXSWITCH_TESTRX)
printf("Warning: tdd_config is not set to TXRXSWITCH_TESTRX! You better know what you are doing! :)\n");
// assign userspace pointers
for (j=0; j<openair0_num_detected_cards;j++)
{
for (i=0; i<MAX_ANTENNAS; i++)
{
//if ( numant == openair0_num_antennas[j] )
rx_sig[i+(j*MAX_ANTENNAS)] = (short*) openair0_exmimo_pci[ j ].adc_head[ i ];
//else
// rx_sig[i+(j*MAX_ANTENNAS)] = (short*) openair0_exmimo_pci[ i / (int)openair0_num_antennas[0] ].adc_head[i % openair0_num_antennas[0]];
// printf("Card %i adc_head[%i] = %p \n",j, i, rx_sig[i+(j*MAX_ANTENNAS)]);
}
}
// msg("Getting buffer...\n");
if ( no_getframe_ioctl == 0)
openair0_get_frame(card);
for (j=0; j<openair0_num_detected_cards;j++)
for (i=0; i<frame_length_samples[j]; i++)
for (aa=0; aa<MAX_ANTENNAS; aa++)
dx(i, aa+j*MAX_ANTENNAS) = Complex( rx_sig[aa+j*MAX_ANTENNAS][i*2], rx_sig[aa+j*MAX_ANTENNAS][i*2+1] );
openair0_close();
return octave_value (dx);
}
@@ -1,87 +0,0 @@
/*
* 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
*/
// Matthias Ihmig, 2013
// see http://www.gnu.org/software/octave/doc/interpreter/Dynamically-Linked-Functions.html#Dynamically-Linked-Functions
// and http://wiki.octave.org/wiki.pl?CodaTutorial
// and http://octave.sourceforge.net/coda/c58.html
// compilation: see Makefile
#include <octave/oct.h>
extern "C" {
#include "openair0_lib.h"
}
#include "oarf.h"
#define FCNNAME "oarf_get_num_detected_cards"
#define TRACE 1
static bool any_bad_argument(const octave_value_list &args)
{
octave_value v;
if (args.length()!=0)
{
error(FCNNAME);
error("syntax: oarf_get_num_detected_cards");
return true;
}
return false;
}
DEFUN_DLD (oarf_get_num_detected_cards, args, nargout,"Returns number of detected cards.")
{
if (any_bad_argument(args))
return octave_value_list();
int ret;
octave_value returnvalue;
ret = openair0_open();
if ( ret != 0 )
{
error(FCNNAME);
if (ret == -1)
error("Error opening /dev/openair0");
if (ret == -2)
error("Error mapping bigshm");
if (ret == -3)
error("Error mapping RX or TX buffer");
return octave_value(ret);
}
returnvalue = openair0_num_detected_cards;
openair0_close( );
return octave_value(returnvalue);
}
@@ -1,169 +0,0 @@
/*
* 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
*/
// Matthias Ihmig, 2013
// Maxime Guillaud - created Fri May 12 16:20:04 CEST 2006
// see http://www.gnu.org/software/octave/doc/interpreter/Dynamically-Linked-Functions.html#Dynamically-Linked-Functions
// and http://wiki.octave.org/wiki.pl?CodaTutorial
// and http://octave.sourceforge.net/coda/c58.html
// compilation: see Makefile
// Update: Wed May 23 17:25:39 CEST 2007, fifo acquisition of signal buffer (RK)
#include <octave/oct.h>
extern "C" {
#include "openair0_lib.h"
}
#include "oarf.h"
#define FCNNAME "oarf_send_frame"
#define TRACE 1
static bool any_bad_argument(const octave_value_list &args)
{
octave_value v;
if (args.length()!=3)
{
error(FCNNAME);
error("syntax: oarf_send_frame(card,sig,nbits)\n card (starting from 0), sig is a 2D array (size depends on no. of antennas and resampling factor), nbits is number of bits to quantize the signal to.");
return true;
}
v=args(0);
if ((!v.is_real_scalar()) || (v.scalar_value() < 0.0) || (floor(v.scalar_value()) != v.scalar_value()) || (v.scalar_value() >= MAX_CARDS))
{
error(FCNNAME);
error("card must be between 0 and MAX_CARDS.");
return true;
}
v=args(1);
printf("signal: R %d, C %d\n",v.rows(),v.columns());
v=args(2);
if ((!v.is_real_scalar()) && (v.scalar_value()!=8) && (v.scalar_value()!=16))
{
error(FCNNAME);
error("nbits must be either 8 (CBMIMO) or 16 (ExpressMIMO)bits.");
return true;
}
return false;
}
DEFUN_DLD (oarf_send_frame, args, nargout,"Send frame")
{
if (any_bad_argument(args))
return octave_value_list();
const int card = args(0).int_value();
ComplexMatrix dx = args(1).complex_matrix_value();
octave_value returnvalue;
int i, ret;
unsigned int length,aa,nbits,numcols;
unsigned int resampling_factor[4];
ret = openair0_open();
if ( ret != 0 )
{
error(FCNNAME);
if (ret == -1)
error("Error opening /dev/openair0");
if (ret == -2)
error("Error mapping bigshm");
if (ret == -3)
error("Error mapping RX or TX buffer");
return octave_value(ret);
}
if (card <0 || card >= openair0_num_detected_cards) {
error("Invalid card number!");
return octave_value(-4);
}
numcols = args(1).columns();
//printf("colums = %d, rows = %d\n\n\n", numcols, args(1).rows());
if ( numcols<1 || (numcols > openair0_num_antennas[card]))
{
error(FCNNAME);
error("input array must be of column size %d.", openair0_num_antennas[card]);
return octave_value_list();
}
for (i=0;i<4;i++) {
resampling_factor[i] = (openair0_exmimo_pci[card].exmimo_config_ptr)->framing.resampling_factor[i];
printf("card %d, ant %d, resampling %u\n",card,i,resampling_factor[i]);
}
for (i=0;i<numcols;i++){
if (args(1).rows()<(76800*(1 << (2-resampling_factor[i]))))
{
error(FCNNAME);
error("input array column number %d must be of size %d.",i,(76800*(1 << (2-resampling_factor[i]))));
return octave_value_list();
}
}
if ((openair0_exmimo_pci[card].exmimo_config_ptr->framing.tdd_config & TXRXSWITCH_MASK) != TXRXSWITCH_TESTTX)
printf("Warning: tdd_config is not set to TXRXSWITCH_TESTTX! You better know what you are doing! :)\n");
nbits = args(2).scalar_value();
for (aa=0;aa<numcols;aa++)
{
if (nbits==16)
{
for (i=0;i<(76800*(1 << (2-resampling_factor[aa])));i++)
{
//if (i<64) printf("%d: %d,%d\n",i,(short)real(dx(i,aa)),(short)imag(dx(i,aa)));
((short*) openair0_exmimo_pci[card].dac_head[aa])[2*i] = (short)(real(dx(i,aa)));
((short*) openair0_exmimo_pci[card].dac_head[aa])[1+(2*i)] = (short)(imag(dx(i,aa)));
}
}
else if (nbits==8)
{
for (i=0;i<(76800*(1 << (2-resampling_factor[aa])));i++)
{
//if (i<64) printf("%d: %d,%d\n",i,char(real(dx(i,aa))),char(imag(dx(i,aa))));
((char*) openair0_exmimo_pci[card].dac_head[aa])[2*i] = char(real(dx(i,aa)));
((char*) openair0_exmimo_pci[card].dac_head[aa])[1+(2*i)] = char(imag(dx(i,aa)));
}
}
else {
error(FCNNAME);
error("nbits has to be 8 or 16!");
}
}
openair0_start_rt_acquisition( card );
openair0_close();
return octave_value (dx);
}
@@ -1,104 +0,0 @@
/*
* 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
*/
// Matthias Ihmig, 2013
// Florian Kaltenberger - created 2010-01-22
// see http://www.gnu.org/software/octave/doc/interpreter/Dynamically-Linked-Functions.html#Dynamically-Linked-Functions
// and http://wiki.octave.org/wiki.pl?CodaTutorial
// and http://octave.sourceforge.net/coda/c58.html
// compilation: see Makefile
#include <octave/oct.h>
extern "C" {
#include "openair0_lib.h"
}
#include "oarf.h"
#define FCNNAME "oarf_stop"
#define TRACE 1
static bool any_bad_argument(const octave_value_list &args)
{
octave_value v;
if (args.length()!=1)
{
error(FCNNAME);
error("syntax: oarf_stop(card)");
return true;
}
v=args(0);
if ((!v.is_real_scalar()) || (v.scalar_value() < -1) || (floor(v.scalar_value()) != v.scalar_value()) || (v.scalar_value() >= MAX_CARDS))
{
error(FCNNAME);
error("card must be 0..number of cards-1.\nUse card = -1 to stop all cards.\n");
return true;
}
return false;
}
DEFUN_DLD (oarf_stop, args, nargout,"Stop RT acquisition and write registers.")
{
int a,b;
if (any_bad_argument(args))
return octave_value_list();
int card = args(0).int_value();
int ret;
octave_value returnvalue;
ret = openair0_open();
if ( ret != 0 )
{
error(FCNNAME);
if (ret == -1)
error("Error opening /dev/openair0");
if (ret == -2)
error("Error mapping bigshm");
if (ret == -3)
error("Error mapping RX or TX buffer");
return octave_value(ret);
}
if (card <-1 || card >= openair0_num_detected_cards)
error("Invalid card number (num detected cards: %d, card: %d)!", openair0_num_detected_cards, card);
if (card == -1) {
for (card = 0; card < openair0_num_detected_cards; card++)
returnvalue = openair0_stop( card );
} else
returnvalue = openair0_stop( card );
openair0_close( );
return octave_value(returnvalue);
}
@@ -1,99 +0,0 @@
/*
* 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
*/
// Riadh Ghaddab - created 2013-10-24
// see http://www.gnu.org/software/octave/doc/interpreter/Dynamically-Linked-Functions.html#Dynamically-Linked-Functions
// and http://wiki.octave.org/wiki.pl?CodaTutorial
// and http://octave.sourceforge.net/coda/c58.html
// compilation: see Makefile
#include <octave/oct.h>
extern "C" {
#include "openair0_lib.h"
}
#include "oarf.h"
#define FCNNAME "oarf_stop_without_reset"
#define TRACE 1
static bool any_bad_argument(const octave_value_list &args)
{
octave_value v;
if (args.length()!=1)
{
error(FCNNAME);
error("syntax: oarf_stop(card)");
return true;
}
v=args(0);
if ((!v.is_real_scalar()) || (v.scalar_value() < -1) || (floor(v.scalar_value()) != v.scalar_value()) || (v.scalar_value() >= MAX_CARDS))
{
error(FCNNAME);
error("card must be 0..number of cards-1.\nUse card = -1 to stop all cards.\n");
return true;
}
return false;
}
DEFUN_DLD (oarf_stop_without_reset, args, nargout,"Stop RT acquisition and write registers.")
{
int a,b;
if (any_bad_argument(args))
return octave_value_list();
int card = args(0).int_value();
int ret;
octave_value returnvalue;
ret = openair0_open();
if ( ret != 0 )
{
error(FCNNAME);
if (ret == -1)
error("Error opening /dev/openair0");
if (ret == -2)
error("Error mapping bigshm");
if (ret == -3)
error("Error mapping RX or TX buffer");
return octave_value(ret);
}
if (card <-1 || card >= openair0_num_detected_cards)
error("Invalid card number (num detected cards: %d, card: %d)!", openair0_num_detected_cards, card);
if (card == -1) {
for (card = 0; card < openair0_num_detected_cards; card++)
returnvalue = openair0_stop( card );
} else
returnvalue = openair0_stop_without_reset( card );
openair0_close( );
return octave_value(returnvalue);
}
@@ -1,49 +0,0 @@
card=0;
s = oarf_get_frame(card);
%s=s-0.99999*mean(s(:,2));
sig0 = s(:,1);
sig1 = s(:,2);
#sig0 = s(5000:end,1); % first channel
#sig1 = s(5000:end,2); % 2nd channel
bw=7.68e6;
spec = abs(fft(sig1)).^2;
%[a,b] = max(spec(2:end)); b=b+1;
[a,b] = max(spec);
freq = (b-1)*bw/length(sig0);
L= 1000;
W = 1;
offset_vec = (0:L-1)*((2*W)+1);
W2 = 1+(2*W);
window_vec = (-W : W);
pn = zeros(1,(2*L) - 1);
for i = 1:L,
pn(i+L-1) = sum(spec(offset_vec(i) + b + window_vec));
end
for i = 2:L,
pn(L-i+1) = sum(spec(-offset_vec(i) + b + window_vec));
end
pn_2 = 10*log10(pn / pn(L)) - 10*log10(W2*bw/length(sig0));
f = ((-L+1):(L-1))*W2*bw/length(sig0);
ylabel('dBc/Hz')
xlabel("f_offset (Hz)")
title("Phase Noise @ IQ output for Fc = 1912.6 + Fs/4 MHz CW input at antenna")
semilogx(f(L:(2*L - 1)),pn_2(L:(2*L -1)))
grid on
axis([1e2 100e3 -90 -30]);
sum(pn*(f(2)-f(1)))
signal_amp = 10*log10(pn(L))
@@ -1,8 +0,0 @@
## Composes rf_local values: rfl(txi, txq, rxi, rxq)
## Author: Matthias Ihmig <ihmig@solstice>
## Created: 2012-12-05
function [ ret ] = rfl(txi, txq, rxi, rxq)
ret = txi + txq*2^6 + rxi*2^12 + rxq*2^18;
endfunction
@@ -1,11 +0,0 @@
## Decodes rf_local values: [ txi, txq, rxi, rxq ] = rfldec(rflocal)
## Author: Matthias Ihmig <ihmig@solstice>
## Created: 2012-12-05
function [ txi, txq, rxi, rxq ] = rfldec(rflocal)
txi = mod(floor( rflocal /1 ), 64)
txq = mod(floor( rflocal /64), 64)
rxi = mod(floor( rflocal /4096), 64)
rxq = mod(floor( rflocal /262144), 64)
endfunction
@@ -1,194 +0,0 @@
close all
clear all
hold off
%gpib_card=0; % first GPIB PCI card in the computer
%gpib_device=28; % this is configured in the signal generator Utilities->System->GPIB->Address menu
smbv_ip_addr = "192.168.12.201";
command = [getenv("OPENAIR_TARGETS") "/TEST/ROHDE_SCHWARZ/EthernetRawCommand.out"];
%fc = 1907600e3;
fc = 2.6e9;
%fc=800e6;
fs = 7680e3;
fref = fc+fs/4;
power_dBm = [-70 -80 -90]+20;
cables_loss_dB = 12; % we need to account for the power loss between the signal generator and the card input (splitter, cables)
dual_tx = 0;
tdd = 1;
card = 0;
limeparms;
%rf_mode = (RXEN+TXEN+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNAMax+RFBBNORM+DMAMODE_RX+DMAMODE_TX)*[1 1 1 1];
rf_mode = (RXEN+0+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNAMax+RFBBNORM+DMAMODE_RX+0)*[1 1 1 1];
freq_rx = fc*[1 1 1 1];
freq_tx = freq_rx;
tx_gain = 25*[1 1 1 1];
rx_gain = 15*[1 1 1 1];
%rf_local= [8254744 8255063 8257340 8257340]; %rf_local*[1 1 1 1];
rf_local = [8254813 8255016 8254813 8254813]; %exmimo2_2
%rf_rxdc = rf_rxdc*[1 1 1 1];
%rf_rxdc = ((128+rxdc_I) + (128+rxdc_Q)*(2^8))*[1 1 1 1];
rf_rxdc = [37059 35459 36300 36999]; %exmimo2_2
rf_vcocal=rf_vcocal_19G*[1 1 1 1];
eNBflag = 0;
tdd_config = DUPLEXMODE_FDD + TXRXSWITCH_TESTRX;
%syncmode = SYNCMODE_FREE;
syncmode = [SYNCMODE_MASTER SYNCMODE_SLAVE];
rffe_rxg_low = 63*[1 1 1 1];
rffe_rxg_final = 63*[1 1 1 1];
rffe_band = B19G_TDD*[1 1 1 1];
autocal = [1 1 1 1];
resampling_factor = [2 2 2 2];
system(sprintf('%s %s ''*RST;*CLS''',command, smbv_ip_addr)); % reset and configure the signal generator
%gpib_send(gpib_card,gpib_device,sprintf("POW %ddBm",power_dBm+cables_loss_dB));
%gpib_send(gpib_card,gpib_device,'POW -14dBm');
%gpib_send(gpib_card,gpib_device,'FREQ 1.91860GHz');
%gpib_send(gpib_card,gpib_device,'FREQ 1.919225GHz');
%gpib_send(gpib_card,gpib_device,'FREQ 1.909225GHz');
system(sprintf('%s %s ''FREQ %ldHz''',command,smbv_ip_addr,fref));
for card=1:oarf_get_num_detected_cards
oarf_config_exmimo(card-1,freq_rx,freq_tx,tdd_config,syncmode(card),rx_gain,tx_gain,eNBflag,rf_mode,rf_rxdc,rf_local,rf_vcocal,rffe_rxg_low,rffe_rxg_final,rffe_band,autocal,resampling_factor);
end
autocal = [0 0 0 0];
ALL_rxrfmode = [LNAByp LNAMed LNAMax];
ALL_gain = 0:5:30;
num_chains = 4*oarf_get_num_detected_cards;
SpN0 = zeros(length(ALL_rxrfmode),length(ALL_gain),num_chains);
%SpN1 = zeros(length(ALL_rxrfmode),length(ALL_gain));
N0 = zeros(length(ALL_rxrfmode),length(ALL_gain),num_chains);
%N1 = zeros(length(ALL_rxrfmode),length(ALL_gain));
S0 = zeros(length(ALL_rxrfmode),length(ALL_gain),num_chains);
S0_lin = zeros(length(ALL_rxrfmode),length(ALL_gain),num_chains);
%S1 = zeros(length(ALL_rxrfmode),length(ALL_gain),num_chains);
G0 = zeros(length(ALL_rxrfmode),length(ALL_gain),num_chains);
%G1 = zeros(length(ALL_rxrfmode),length(ALL_gain));
NF0 = zeros(length(ALL_rxrfmode),length(ALL_gain),num_chains);
%NF1 = zeros(length(ALL_rxrfmode),length(ALL_gain));
SNR0 = zeros(length(ALL_rxrfmode),length(ALL_gain),num_chains);
%SNR1 = zeros(length(ALL_rxrfmode),length(ALL_gain));
%keyboard
idx_power = 1;
for mode_idx = 1:3
LNA=ALL_rxrfmode(mode_idx);
system(sprintf('%s %s ''POW %d dBm''',command,smbv_ip_addr,power_dBm(mode_idx)+cables_loss_dB));
idx_gain = 1;
for rx_gain=ALL_gain
rf_mode = (RXEN+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNA+RFBBNORM+DMAMODE_RX)*[1 1 1 1];
rx_gain = rx_gain * [1 1 1 1];
for card=1:oarf_get_num_detected_cards
oarf_config_exmimo(card-1,freq_rx,freq_tx,tdd_config,syncmode(card),rx_gain,tx_gain,eNBflag,rf_mode,rf_rxdc,rf_local,rf_vcocal,rffe_rxg_low,rffe_rxg_final,rffe_band,autocal,resampling_factor);
end
sleep(1);
% signal measurement
system(sprintf('%s %s ''OUTP:STAT ON''',command,smbv_ip_addr)); % activate output
sleep(.5);
s=oarf_get_frame(0);
sleep(.5);
SpN0(idx_power,idx_gain,:) = mean(abs(s).^2,1) - abs(mean(s,1)).^2;
%SpN1(idx_power,idx_gain) = mean(abs(s(:,2)).^2) - abs(mean(s(:,2))).^2;
figure(1);
hold off
plot(20*log10(abs(fft(s(:,end)))),'r'); %,20*log10(abs(fft(s(:,2)))),'b')
title("Signal");
ylim([0 200]);
% noise measurement
system(sprintf('%s %s ''OUTP:STAT OFF''',command,smbv_ip_addr)); % deactivate output
sleep(.5);
s=oarf_get_frame(0); %oarf_get_frame
sleep(.5);
N0(idx_power,idx_gain,:) = mean(abs(s).^2,1) - abs(mean(s,1)).^2;
%N1(idx_power,idx_gain) = mean(abs(s(:,2)).^2) - abs(mean(s(:,2))).^2;
figure(2);
hold off
plot(20*log10(abs(fft(s(:,end)))),'r'); %,20*log10(abs(fft(s(:,2)))),'b')
title("Noise");
ylim([0 200]);
% do some plausibility checks
% if ((N0(idx_power,idx_gain) > SpN0(idx_power,idx_gain)) ||
% (N1(idx_power,idx_gain) > SpN1(idx_power,idx_gain)))
% error("something is wrong");
% end
S0_lin(idx_power,idx_gain,:) = SpN0(idx_power,idx_gain,:)-N0(idx_power,idx_gain,:);
S0_lin(idx_power,idx_gain,S0_lin(idx_power,idx_gain,:)<0) = 0;
S0(idx_power,idx_gain,:) = 10*log10(S0_lin(idx_power,idx_gain,:));
%S1(idx_power,idx_gain) = 10*log10(SpN1(idx_power,idx_gain)-N1(idx_power,idx_gain));
G0(idx_power,idx_gain,:) = S0(idx_power,idx_gain,:) - power_dBm(mode_idx);
%G1(idx_power,idx_gain) = S1(idx_power,idx_gain) - power_dBm;
NF0(idx_power,idx_gain,:) = 10*log10(N0(idx_power,idx_gain,:)) - G0(idx_power,idx_gain,:) + 105; % 108 is the thermal noise
%NF1(idx_power,idx_gain) = 10*log10(N1(idx_power,idx_gain)) - G1(idx_power,idx_gain) + 105;
SNR0(idx_power,idx_gain,:) = S0(idx_power,idx_gain,:)-10*log10(N0(idx_power,idx_gain,:));
%SNR1(idx_power,idx_gain) = S1(idx_power,idx_gain)-10*log10(N1(idx_power,idx_gain));
%printf(' %d: Signal strength (%f,%f), Gain (%f %f), N (%f %f) SNR (%f %f) NF (%f %f)\n',
% rx_gain(1), S0(idx_power,idx_gain),S1(idx_power,idx_gain),
% G0(idx_power,idx_gain),G1(idx_power,idx_gain),
% 10*log10(N0(idx_power,idx_gain)),10*log10(N1(idx_power,idx_gain)),
% SNR0(idx_power,idx_gain),SNR1(idx_power,idx_gain),
% NF0(idx_power,idx_gain),NF1(idx_power,idx_gain));
%fflush(stdout);
%fprintf(fid,'%d, %d, %d, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f\n',
%power_dBm,gain2391,gain9862, S0,S1,G0,G1,10*log10(N0),10*log10(N1),SNR0,SNR1,NF0,NF1);
figure(3)
hold off
plot(ALL_gain,G0(:,:,1),'o-','markersize',10)
hold on
plot(ALL_gain,G0(:,:,2),'x-','markersize',10)
plot(ALL_gain,G0(:,:,3),'s-','markersize',10)
plot(ALL_gain,G0(:,:,4),'d-','markersize',10)
legend('Byp RX0','Med RX0','Max RX0','Byp RX1','Med RX1','Max RX1','Byp RX2','Med RX2','Max RX2','Byp RX3','Med RX3','Max RX3');
title('Gains')
figure(4)
hold off
plot(ALL_gain,NF0(:,:,1),'o-','markersize',10)
hold on
plot(ALL_gain,NF0(:,:,2),'x-','markersize',10)
plot(ALL_gain,NF0(:,:,3),'s-','markersize',10)
plot(ALL_gain,NF0(:,:,4),'d-','markersize',10)
legend('Byp RX0','Med RX0','Max RX0','Byp RX1','Med RX1','Max RX1','Byp RX2','Med RX2','Max RX2','Byp RX3','Med RX3','Max RX3');
title('Noise Figure')
idx_gain = idx_gain + 1;
end
idx_power = idx_power + 1;
end
%gpib_send(gpib_card,gpib_device,'OUTP:STAT OFF'); % deactivate output
%l0 = [ALL_gain2391; ones(size(ALL_gain2391))].'\G0;
%l1 = [ALL_gain2391; ones(size(ALL_gain2391))].'\G1;
@@ -1,276 +0,0 @@
close all
clear all
hold off
%gpib_card=0; % first GPIB PCI card in the computer
%gpib_device=28; % this is configured in the signal generator Utilities->System->GPIB->Address menu
smbv_ip_addr = "192.168.12.201";
command = [getenv("OPENAIR_TARGETS") "/TEST/ROHDE_SCHWARZ/EthernetRawCommand.out"];
fc = 1907600e3;
%fc = 2.6e9;
%fc=700e6;
fs = 7680e3;
fref = fc+fs/4;
power_dBm = [-70 -80 -90]; %needs to be adjusted based on carrier freq
cables_loss_dB = 11; % we need to account for the power loss between the signal generator and the card input (splitter, cables)
nb_meas = 10;
dual_tx = 0;
tdd = 1;
card = 0;
limeparms;
%rf_mode = (RXEN+TXEN+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNAMax+RFBBNORM+DMAMODE_RX+DMAMODE_TX)*[1 1 1 1];
rf_mode = (RXEN+0+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNAMax+RFBBNORM+DMAMODE_RX+0)*[1 1 1 1];
freq_rx = fc*[1 1 1 1];
freq_tx = freq_rx;
tx_gain = 25*[1 1 1 1];
rx_gain = 15*[1 1 1 1];
%rf_local= [8254744 8255063 8257340 8257340]; %rf_local*[1 1 1 1];
rf_local = [8254813 8255016 8254813 8254813]; %exmimo2_2
%rf_rxdc = rf_rxdc*[1 1 1 1];
%rf_rxdc = ((128+rxdc_I) + (128+rxdc_Q)*(2^8))*[1 1 1 1];
rf_rxdc = [37059 35459 36300 36999]; %exmimo2_2
rf_vcocal=rf_vcocal_19G*[1 1 1 1];
eNBflag = 0;
tdd_config = DUPLEXMODE_FDD + TXRXSWITCH_TESTRX;
syncmode = SYNCMODE_FREE;
%syncmode = [SYNCMODE_MASTER SYNCMODE_SLAVE];
rffe_rxg_low = 63*[1 1 1 1];
rffe_rxg_final = 63*[1 1 1 1];
rffe_band = B19G_TDD*[1 1 1 1];
autocal = [1 1 1 1];
resampling_factor = [2 2 2 2];
system(sprintf('%s %s ''*RST;*CLS''',command, smbv_ip_addr)); % reset and configure the signal generator
%gpib_send(gpib_card,gpib_device,sprintf("POW %ddBm",power_dBm+cables_loss_dB));
%gpib_send(gpib_card,gpib_device,'POW -14dBm');
%gpib_send(gpib_card,gpib_device,'FREQ 1.91860GHz');
%gpib_send(gpib_card,gpib_device,'FREQ 1.919225GHz');
%gpib_send(gpib_card,gpib_device,'FREQ 1.909225GHz');
system(sprintf('%s %s ''FREQ %ldHz''',command,smbv_ip_addr,fref));
%for card=1:oarf_get_num_detected_cards
%oarf_config_exmimo(card-1,freq_rx,freq_tx,tdd_config,syncmode(card),rx_gain,tx_gain,eNBflag,rf_mode,rf_rxdc,rf_local,rf_vcocal,rffe_rxg_low,rffe_rxg_final,rffe_band,autocal,resampling_factor);
%end
autocal = [0 0 0 0];
ALL_rxrfmode = [LNAByp LNAMed LNAMax];
%ALL_rxrfmode = [LNAMax];
ALL_gain = 0:10:30;
num_chains = 4*oarf_get_num_detected_cards;
SpN0 = zeros(length(ALL_rxrfmode),length(ALL_gain),num_chains);
%SpN1 = zeros(length(ALL_rxrfmode),length(ALL_gain));
N0 = zeros(length(ALL_rxrfmode),length(ALL_gain),num_chains);
%N1 = zeros(length(ALL_rxrfmode),length(ALL_gain));
S0 = zeros(length(ALL_rxrfmode),length(ALL_gain),num_chains);
S0_lin = zeros(length(ALL_rxrfmode),length(ALL_gain),num_chains);
%S1 = zeros(length(ALL_rxrfmode),length(ALL_gain),num_chains);
G0 = zeros(length(ALL_rxrfmode),length(ALL_gain),num_chains);
G1 = zeros(length(ALL_rxrfmode),length(ALL_gain),num_chains);
NF0 = zeros(length(ALL_rxrfmode),length(ALL_gain),num_chains);
NF1 = zeros(length(ALL_rxrfmode),length(ALL_gain),num_chains);
NF2 = zeros(length(ALL_rxrfmode),length(ALL_gain),num_chains);
SNR0 = zeros(length(ALL_rxrfmode),length(ALL_gain),num_chains);
%SNR1 = zeros(length(ALL_rxrfmode),length(ALL_gain));
%keyboard
for mode_idx = 3
LNA=ALL_rxrfmode(mode_idx);
system(sprintf('%s %s ''POW %d dBm''',command,smbv_ip_addr,power_dBm(mode_idx)+cables_loss_dB));
idx_gain = 1;
for rx_gain=ALL_gain
rf_mode = (RXEN+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNA+RFBBNORM+DMAMODE_RX)*[1 1 1 1];
rx_gain = rx_gain * [1 1 1 1];
for card=1:oarf_get_num_detected_cards
oarf_config_exmimo(card-1,freq_rx,freq_tx,tdd_config,syncmode(card),rx_gain,tx_gain,eNBflag,rf_mode,rf_rxdc,rf_local,rf_vcocal,rffe_rxg_low,rffe_rxg_final,rffe_band,autocal,resampling_factor);
end
sleep(1);
% signal measurement
system(sprintf('%s %s ''OUTP:STAT ON''',command,smbv_ip_addr)); % activate output
sleep(.5);
%f1 = (7.68*(0:length(s(:,2))-1)/(length(s(:,2))))-3.84;
f1 = (7.68*(0:307200-1)/307200)-3.84;
%nidx = find(f1>=0.5 & f1<=1.5); %1MHz
nidx = find(f1>=1.5 & f1<=2.5); %1MHz
sidx = find(f1>=1.87 & f1<=1.97); %100kHz
SpN0_temp = 0;
spn0_temp = 0;
for k=1:nb_meas
s=oarf_get_frame(0);
sleep(.5);
s = s - repmat(mean(s,1),size(s,1),1);
SpN0_temp = SpN0_temp + mean(abs(s).^2,1) - abs(mean(s,1)).^2;
sf = fftshift(fft(s),1)/sqrt(length(s));
%np = 10*log10(sum(abs(sf(nidx,:)).^2));
%sp_temp = sp_temp + 10*log10(sum(abs(sf(sidx,:)).^2));
spn0_temp = spn0_temp + sum(abs(sf).^2);
end
%SpN0(mode_idx,idx_gain,:) = mean(abs(s).^2,1) - abs(mean(s,1)).^2;
%SpN1(mode_idx,idx_gain) = mean(abs(s(:,2)).^2) - abs(mean(s(:,2))).^2;
SpN0(mode_idx,idx_gain,:) = SpN0_temp/nb_meas;
spn0 = spn0_temp/nb_meas;
%keyboard;
sf = fftshift(fft(s),1)/sqrt(length(s));
figure(1);
hold off
plot(f1,20*log10(abs((sf(:,3)))),'r');
hold on
plot(f1(nidx),20*log10(abs(sf(nidx,3))),'b');
plot(f1(sidx),20*log10(abs(sf(sidx,3))),'g');
title("Signal");
ylim([0 200]);
% noise measurement
system(sprintf('%s %s ''OUTP:STAT OFF''',command,smbv_ip_addr)); % deactivate output
sleep(.5);
N0_temp = 0;
np_temp = 0;
np_temp_unit = 0;
for k=1:nb_meas
s=oarf_get_frame(0); %oarf_get_frame
sleep(.5);
s = s - repmat(mean(s,1),size(s,1),1);
N0_temp = N0_temp + mean(abs(s).^2,1) - abs(mean(s,1)).^2;
%N1(idx_power,idx_gain) = mean(abs(s(:,2)).^2) - abs(mean(s(:,2))).^2;
sf = fftshift(fft(s),1)/sqrt(length(s));
np_temp = np_temp + sum(abs(sf).^2);
np_temp_unit = np_temp_unit + sum(abs(sf(nidx,:)).^2);
end
N0(mode_idx,idx_gain,:) = N0_temp/nb_meas;
%N0(mode_idx,idx_gain,:) = mean(abs(s).^2,1) - abs(mean(s,1)).^2;
%N1(mode_idx,idx_gain) = mean(abs(s(:,2)).^2) - abs(mean(s(:,2))).^2;
%G1(mode_idx,idx_gain,:) = sp - power_dBm(mode_idx);
np = np_temp/nb_meas;
snr = 10*log10((spn0-np)./np); %measured snr
snr_real = power_dBm(mode_idx) - (-174 + 10*log10(7.68e6)); %signal over thermal noise
np_unit = np_temp_unit/nb_meas;
snr_output_unit = 10*log10((spn0-np_unit)./np_unit); %measured snr
snr_input_unit = power_dBm(mode_idx) - (-174 + 10*log10(1e6)); %signal over thermal noise
NF1(mode_idx,idx_gain,:) = snr_real - snr;
NF2(mode_idx,idx_gain,:) = snr_input_unit - snr_output_unit;
sf = fftshift(fft(s),1)/sqrt(length(s));
figure(2);
hold off
plot(f1,20*log10(abs((sf(:,3)))),'r');
title("Noise");
ylim([0 200]);
% do some plausibility checks
% if ((N0(mode_idx,idx_gain) > SpN0(mode_idx,idx_gain)) ||
% (N1(mode_idx,idx_gain) > SpN1(mode_idx,idx_gain)))
% error("something is wrong");
% end
S0_lin(mode_idx,idx_gain,:) = SpN0(mode_idx,idx_gain,:)-N0(mode_idx,idx_gain,:);
S0_lin(mode_idx,idx_gain,S0_lin(mode_idx,idx_gain,:)<0) = 0;
S0(mode_idx,idx_gain,:) = 10*log10(S0_lin(mode_idx,idx_gain,:));
%S1(mode_idx,idx_gain) = 10*log10(SpN1(mode_idx,idx_gain)-N1(mode_idx,idx_gain));
G0(mode_idx,idx_gain,:) = S0(mode_idx,idx_gain,:) - power_dBm(mode_idx);
%G1(mode_idx,idx_gain) = S1(mode_idx,idx_gain) - power_dBm;
NF0(mode_idx,idx_gain,:) = 10*log10(N0(mode_idx,idx_gain,:)) - G0(mode_idx,idx_gain,:) + 105; % 108 is the thermal noise
%NF1(mode_idx,idx_gain) = 10*log10(N1(mode_idx,idx_gain)) - G1(mode_idx,idx_gain) + 105;
SNR0(mode_idx,idx_gain,:) = S0(mode_idx,idx_gain,:)-10*log10(N0(mode_idx,idx_gain,:));
%SNR1(mode_idx,idx_gain) = S1(mode_idx,idx_gain)-10*log10(N1(mode_idx,idx_gain));
%printf(' %d: Signal strength (%f,%f), Gain (%f %f), N (%f %f) SNR (%f %f) NF (%f %f)\n',
% rx_gain(1), S0(mode_idx,idx_gain),S1(mode_idx,idx_gain),
% G0(mode_idx,idx_gain),G1(mode_idx,idx_gain),
% 10*log10(N0(mode_idx,idx_gain)),10*log10(N1(mode_idx,idx_gain)),
% SNR0(mode_idx,idx_gain),SNR1(mode_idx,idx_gain),
% NF0(mode_idx,idx_gain),NF1(mode_idx,idx_gain));
%fflush(stdout);
%fprintf(fid,'%d, %d, %d, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f\n',
%power_dBm,gain2391,gain9862, S0,S1,G0,G1,10*log10(N0),10*log10(N1),SNR0,SNR1,NF0,NF1);
%keyboard
figure(3)
hold off
plot(ALL_gain,G0(:,:,1),'o-','markersize',10)
hold on
plot(ALL_gain,G0(:,:,2),'x-','markersize',10)
plot(ALL_gain,G0(:,:,3),'s-','markersize',10)
plot(ALL_gain,G0(:,:,4),'d-','markersize',10)
%legend('Byp RX0','Med RX0','Max RX0','Byp RX1','Med RX1','Max RX1');
legend('Byp RX0','Med RX0','Max RX0','Byp RX1','Med RX1','Max RX1','Byp RX2','Med RX2','Max RX2','Byp RX3','Med RX3','Max RX3');
title('Gains')
xlabel('rx gains (dB)')
ylabel('NF (dB)')
figure(4)
hold off
plot(ALL_gain,NF0(:,:,1),'o-','markersize',10)
hold on
plot(ALL_gain,NF0(:,:,2),'x-','markersize',10)
plot(ALL_gain,NF0(:,:,3),'s-','markersize',10)
plot(ALL_gain,NF0(:,:,4),'d-','markersize',10)
%legend('Byp RX0','Med RX0','Max RX0','Byp RX1','Med RX1','Max RX1');
legend('Byp RX0','Med RX0','Max RX0','Byp RX1','Med RX1','Max RX1','Byp RX2','Med RX2','Max RX2','Byp RX3','Med RX3','Max RX3');
title('Averaged Noise Figure measured in time domain')
xlabel('rx gains (dB)')
ylabel('NF (dB)')
figure(5)
hold off
plot(ALL_gain,NF1(:,:,1),'o-','markersize',10)
hold on
plot(ALL_gain,NF1(:,:,2),'x-','markersize',10)
plot(ALL_gain,NF1(:,:,3),'s-','markersize',10)
plot(ALL_gain,NF1(:,:,4),'d-','markersize',10)
%legend('Byp RX0','Med RX0','Max RX0','Byp RX1','Med RX1','Max RX1');
legend('Byp RX0','Med RX0','Max RX0','Byp RX1','Med RX1','Max RX1','Byp RX2','Med RX2','Max RX2','Byp RX3','Med RX3','Max RX3');
title('Averaged Noise Figure measured in frequency domain')
xlabel('rx gains (dB)')
ylabel('NF (dB)')
figure(6)
hold off
plot(ALL_gain,NF2(:,:,1),'o-','markersize',10)
hold on
plot(ALL_gain,NF2(:,:,2),'x-','markersize',10)
plot(ALL_gain,NF2(:,:,3),'s-','markersize',10)
plot(ALL_gain,NF2(:,:,4),'d-','markersize',10)
%legend('Byp RX0','Med RX0','Max RX0','Byp RX1','Med RX1','Max RX1');
legend('Byp RX0','Med RX0','Max RX0','Byp RX1','Med RX1','Max RX1','Byp RX2','Med RX2','Max RX2','Byp RX3','Med RX3','Max RX3');
title('Unit Bandwidth Noise Figure measured in frequency domain')
xlabel('rx gains (dB)')
ylabel('NF (dB)')
idx_gain = idx_gain + 1;
end
end
%gpib_send(gpib_card,gpib_device,'OUTP:STAT OFF'); % deactivate output
%l0 = [ALL_gain2391; ones(size(ALL_gain2391))].'\G0;
%l1 = [ALL_gain2391; ones(size(ALL_gain2391))].'\G1;
@@ -1,183 +0,0 @@
close all
clear all
hold off
gpib_card=0; % first GPIB PCI card in the computer
gpib_device=28; % this is configured in the signal generator Utilities->System->GPIB->Address menu
fc = 1907600e3;
fs = 7680e3;
fref = fc+fs/4;
power_dBm = -70;
cables_loss_dB = 6; % we need to account for the power loss between the signal generator and the card input (splitter, cables)
dual_tx = 0;
tdd = 1;
card = 0;
limeparms;
%rf_mode = (RXEN+TXEN+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNAMax+RFBBNORM+DMAMODE_RX+DMAMODE_TX)*[1 1 1 1];
rf_mode1 = (RXEN+0+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNAMax+RFBBNORM+DMAMODE_RX+0);
rf_mode2 = (RXEN+0+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA2ON+LNAMax+RFBBNORM+DMAMODE_RX+0);
rf_mode = [rf_mode1 rf_mode2 0 0];
freq_rx = 1907600000*[1 1 1 1];
freq_tx = freq_rx;
tx_gain = 25*[1 1 1 1];
rx_gain = 15*[1 1 1 1];
%rf_local= [8254744 8255063 8257340 8257340]; %rf_local*[1 1 1 1];
rf_local = [8254813 8255016 8254813 8254813]; %exmimo2_2
%rf_rxdc = rf_rxdc*[1 1 1 1];
%rf_rxdc = ((128+rxdc_I) + (128+rxdc_Q)*(2^8))*[1 1 1 1];
rf_rxdc = [37059 35459 36300 36999]; %exmimo2_2
rf_rxdc = [34689 34756 36300 36999]; %exmimo2_2 with external RF
rf_vcocal=rf_vcocal_19G*[1 1 1 1];
eNBflag = 0;
tdd_config = DUPLEXMODE_FDD + TXRXSWITCH_TESTRX;
syncmode = SYNCMODE_FREE;
rffe_rxg_low = 31*[1 1 1 1];
rffe_rxg_final = 31*[1 1 1 1];
rffe_band = B19G_TDD*[1 1 1 1];
autocal = [1 1 1 1];
gpib_send(gpib_card,gpib_device,'*RST;*CLS'); % reset and configure the signal generator
%gpib_send(gpib_card,gpib_device,sprintf("POW %ddBm",power_dBm+cables_loss_dB));
gpib_send(gpib_card,gpib_device,sprintf("POW %ddBm",0));
%gpib_send(gpib_card,gpib_device,'FREQ 1.91860GHz');
%gpib_send(gpib_card,gpib_device,'FREQ 1.919225GHz');
%gpib_send(gpib_card,gpib_device,'FREQ 1.909225GHz');
gpib_send(gpib_card,gpib_device,sprintf("FREQ %dHz",fref));
oarf_config_exmimo(card,freq_rx,freq_tx,tdd_config,syncmode,rx_gain,tx_gain,eNBflag,rf_mode,rf_rxdc,rf_local,rf_vcocal,rffe_rxg_low,rffe_rxg_final,rffe_band,autocal);
autocal = [0 0 0 0];
%ALL_rxrfmode = [LNAByp LNAMed LNAMax];
%ALL_gain = 0:10:30;
ALL_rxrfmode = LNAMax;
ALL_gain = 30;
ALL_rffe_rxg_low = [0 7:8:64];
ALL_rffe_rxg_final = [0 7:8:64];
SpN0 = zeros(length(ALL_rffe_rxg_low),length(ALL_rffe_rxg_final));
SpN1 = zeros(length(ALL_rffe_rxg_low),length(ALL_rffe_rxg_final));
N0 = zeros(length(ALL_rffe_rxg_low),length(ALL_rffe_rxg_final));
N1 = zeros(length(ALL_rffe_rxg_low),length(ALL_rffe_rxg_final));
S0 = zeros(length(ALL_rffe_rxg_low),length(ALL_rffe_rxg_final));
S1 = zeros(length(ALL_rffe_rxg_low),length(ALL_rffe_rxg_final));
G0 = zeros(length(ALL_rffe_rxg_low),length(ALL_rffe_rxg_final));
G1 = zeros(length(ALL_rffe_rxg_low),length(ALL_rffe_rxg_final));
NF0 = zeros(length(ALL_rffe_rxg_low),length(ALL_rffe_rxg_final));
NF1 = zeros(length(ALL_rffe_rxg_low),length(ALL_rffe_rxg_final));
SNR0 = zeros(length(ALL_rffe_rxg_low),length(ALL_rffe_rxg_final));
SNR1 = zeros(length(ALL_rffe_rxg_low),length(ALL_rffe_rxg_final));
%keyboard
idx_power = 1;
for LNA=ALL_rxrfmode
rf_mode = (RXEN+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNA+RFBBNORM+DMAMODE_RX)*[1 1 0 0];
for rffe_rxg_low=ALL_rffe_rxg_low
rffe_rxg_low = rffe_rxg_low*[1 1 1 1];
idx_gain = 1;
for rx_gain=ALL_gain
rx_gain = rx_gain * [1 1 1 1];
for rffe_rxg_final=ALL_rffe_rxg_final
rffe_rxg_final = rffe_rxg_final*[1 1 1 1];
oarf_config_exmimo(card,freq_rx,freq_tx,tdd_config,syncmode,rx_gain,tx_gain,eNBflag,rf_mode,rf_rxdc,rf_local,rf_vcocal,rffe_rxg_low,rffe_rxg_final,rffe_band,autocal);
sleep(1);
% signal measurement
gpib_send(gpib_card,gpib_device,'OUTP:STAT ON'); % activate output
sleep(.5);
s=oarf_get_frame(card);
sleep(.5);
SpN0(idx_power,idx_gain) = mean(abs(s(:,1)).^2) - abs(mean(s(:,1))).^2;
SpN1(idx_power,idx_gain) = mean(abs(s(:,2)).^2) - abs(mean(s(:,2))).^2;
figure(1);
hold off
plot(20*log10(abs(fft(s(:,1)))),'r',20*log10(abs(fft(s(:,2)))),'b')
title("Signal");
ylim([0 200]);
% noise measurement
gpib_send(gpib_card,gpib_device,'OUTP:STAT OFF'); % deactivate output
sleep(.5);
s=oarf_get_frame(card); %oarf_get_frame
sleep(.5);
N0(idx_power,idx_gain) = mean(abs(s(:,1)).^2) - abs(mean(s(:,1))).^2;
N1(idx_power,idx_gain) = mean(abs(s(:,2)).^2) - abs(mean(s(:,2))).^2;
figure(2);
hold off
plot(20*log10(abs(fft(s(:,1)))),'r',20*log10(abs(fft(s(:,2)))),'b')
title("Noise");
ylim([0 200]);
% do some plausibility checks
% if ((N0(idx_power,idx_gain) > SpN0(idx_power,idx_gain)) ||
% (N1(idx_power,idx_gain) > SpN1(idx_power,idx_gain)))
% error("something is wrong");
% end
S0(idx_power,idx_gain) = 10*log10(SpN0(idx_power,idx_gain)-N0(idx_power,idx_gain));
S1(idx_power,idx_gain) = 10*log10(SpN1(idx_power,idx_gain)-N1(idx_power,idx_gain));
G0(idx_power,idx_gain) = S0(idx_power,idx_gain) - power_dBm;
G1(idx_power,idx_gain) = S1(idx_power,idx_gain) - power_dBm;
NF0(idx_power,idx_gain) = 10*log10(N0(idx_power,idx_gain)) - G0(idx_power,idx_gain) + 105; % 108 is the thermal noise
NF1(idx_power,idx_gain) = 10*log10(N1(idx_power,idx_gain)) - G1(idx_power,idx_gain) + 105;
SNR0(idx_power,idx_gain) = S0(idx_power,idx_gain)-10*log10(N0(idx_power,idx_gain));
SNR1(idx_power,idx_gain) = S1(idx_power,idx_gain)-10*log10(N1(idx_power,idx_gain));
printf(' %d: Signal strength (%f,%f), Gain (%f %f), N (%f %f) SNR (%f %f) NF (%f %f)\n',
rx_gain(1), S0(idx_power,idx_gain),S1(idx_power,idx_gain),
G0(idx_power,idx_gain),G1(idx_power,idx_gain),
10*log10(N0(idx_power,idx_gain)),10*log10(N1(idx_power,idx_gain)),
SNR0(idx_power,idx_gain),SNR1(idx_power,idx_gain),
NF0(idx_power,idx_gain),NF1(idx_power,idx_gain));
fflush(stdout);
%fprintf(fid,'%d, %d, %d, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f\n',
%power_dBm,gain2391,gain9862, S0,S1,G0,G1,10*log10(N0),10*log10(N1),SNR0,SNR1,NF0,NF1);
idx_gain = idx_gain + 1;
figure(3)
hold off
plot(ALL_rffe_rxg_final,G0,'o-','markersize',10)
hold on
plot(ALL_rffe_rxg_final,G1,'x-','markersize',10)
legend('Byp RX0','Med RX0','Max RX0','Byp RX1','Med RX1','Max RX1');
title('Gains')
figure(4)
hold off
plot(ALL_rffe_rxg_final,NF0,'o-','markersize',10)
hold on
plot(ALL_rffe_rxg_final,NF1,'x-','markersize',10)
legend('Byp RX0','Med RX0','Max RX0','Byp RX1','Med RX1','Max RX1');
title('Noise Figure')
end
end
idx_power = idx_power + 1;
end
end
%gpib_send(gpib_card,gpib_device,'OUTP:STAT OFF'); % deactivate output
%l0 = [ALL_gain2391; ones(size(ALL_gain2391))].'\G0;
%l1 = [ALL_gain2391; ones(size(ALL_gain2391))].'\G1;
@@ -1,124 +0,0 @@
dual_tx=0;
card=0;
limeparms;
active_rf = zeros(1,4);
active_rf = [1 1 1 1];
autocal = [1 1 1 1];
resampling_factor = [2 2 2 2];
%rf_mode = (RXEN+TXEN+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNAMax+RFBBNORM)*[1 1 1 1];
rf_mode = (RXEN+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNAMax+RFBBNORM)*active_rf;
rf_mode = rf_mode+((DMAMODE_RX+DMAMODE_TX)*active_rf);
%freq_rx = 2540000000*[1 1 1 1];
freq_rx = 747000000*active_rf;
%freq_rx = 2680000000*active_rf; %+ 2540000000*[0 1 0 0]; % + 859500000*[0 0 1 0];
%freq_rx = 1912600000*[1 1 1 1];
%freq_rx = 859500000*[1 1 1 1];
freq_tx = freq_rx-120000000*active_rf;
tx_gain = 0*active_rf; %[1 1 1 1];
rx_gain = 0*active_rf; %1 1 1 1];
rf_local= rf_local*active_rf; %[1 1 1 1];
rf_rxdc = rf_rxdc*active_rf; %[1 1 1 1];
%rf_vcocal=rf_vcocal_859*[1 1 1 1];
rf_vcocal=rf_vcocal_19G*active_rf; %1 1 1 1];
eNBflag = 0;
tdd_config = DUPLEXMODE_FDD + TXRXSWITCH_TESTRX;
%tdd_config = DUPLEXMODE_FDD + TXRXSWITCH_LSB;
syncmode = SYNCMODE_FREE;
rffe_rxg_low = 31*active_rf; %[1 1 1 1];
rffe_rxg_final = 63*active_rf; %[1 1 1 1];
rffe_band = B19G_TDD*active_rf; %[1 1 1 1];
oarf_config_exmimo(card,freq_rx,freq_tx,tdd_config,syncmode,rx_gain,tx_gain,eNBflag,rf_mode,rf_rxdc,rf_local,rf_vcocal,rffe_rxg_low,rffe_rxg_final,rffe_band,autocal,resampling_factor)
gpib_card=0; % first GPIB PCI card in the computer
gpib_device=28; % this is configured in the signal generator Utilities->System
cables_loss_dB = 6; % we need to account for the power loss between the signa
power_dBm = -95;
%gpib_send(gpib_card,gpib_device,['POW ' int2str(power_dBm+cables_loss_dB) 'dBm']);
%gpib_send(gpib_card,gpib_device,'OUTP:STAT ON'); % activate output
s=oarf_get_frame(card);
if (resampling_factor(1)== 2)
f0 = (7.68*(0:length(s(:,1))-1)/(length(s(:,1))))-3.84;
axis([-3.84,3.84,40,200]);
elseif (resampling_factor(1) == 1)
f0 = (15.36*(0:length(s(:,1))-1)/(length(s(:,1))))-7.68;
axis([-7.68,7.68,40,200]);
else
f0 = (30.72*(0:length(s(:,1))-1)/(length(s(:,1))))-15.36;
axis([-15.36,15.36,40,200]);
endif
if (resampling_factor(2)== 2)
f1 = (7.68*(0:length(s(:,2))-1)/(length(s(:,2))))-3.84;
axis([-3.84,3.84,40,200]);
elseif (resampling_factor(2) == 1)
f1 = (15.36*(0:length(s(:,2))-1)/(length(s(:,2))))-7.68;
axis([-7.68,7.68,40,200]);
else
f1 = (30.72*(0:length(s(:,2))-1)/(length(s(:,2))))-15.36;
axis([-15.36,15.36,40,200]);
endif
if (resampling_factor(3)== 2)
f2 = (7.68*(0:length(s(:,3))-1)/(length(s(:,3))))-3.84;
axis([-3.84,3.84,40,200]);
elseif (resampling_factor(3) == 1)
f2 = (15.36*(0:length(s(:,3))-1)/(length(s(:,3))))-7.68;
axis([-7.68,7.68,40,200]);
else
f2 = (30.72*(0:length(s(:,3))-1)/(length(s(:,3))))-15.36;
axis([-15.36,15.36,40,200]);
endif
if (resampling_factor(4)== 2)
f3 = (7.68*(0:length(s(:,4))-1)/(length(s(:,4))))-3.84;
axis([-3.84,3.84,40,200]);
elseif (resampling_factor(4) == 1)
f3 = (15.36*(0:length(s(:,4))-1)/(length(s(:,4))))-7.68;
axis([-7.68,7.68,40,200]);
else
f3 = (30.72*(0:length(s(:,4))-1)/(length(s(:,4))))-15.36;
axis([-15.36,15.36,40,200]);
endif
spec0 = 20*log10(abs(fftshift(fft(s(:,1)))));
spec1 = 20*log10(abs(fftshift(fft(s(:,2)))));
spec2 = 20*log10(abs(fftshift(fft(s(:,3)))));
spec3 = 20*log10(abs(fftshift(fft(s(:,4)))));
clf
if (active_rf(1) == 1)
hold off;
plot(f0',spec0,'r');
endif
%hold on
if (active_rf(2) == 1)
hold off;
figure;
plot(f1',spec1,'b');
endif
%hold on
if (active_rf(3) == 1)
hold off;
figure;
plot(f2',spec2,'g');
endif
%hold on
if (active_rf(4) == 1)
hold off;
figure;
plot(f3',spec3,'m');
endif
%hold on
%hold off
%axis([-3.84,3.84,40,160]);
%gpib_send(gpib_card,gpib_device,'OUTP:STAT OFF'); % activate output
%legend('Antenna Port 0','Antenna Port 1','Antenna Port 2','Antenna Port 3');
grid
@@ -1,170 +0,0 @@
dual_tx=0;
card0=0;
card1=1;
limeparms;
active_rf = zeros(1,4);
active_rf = [1 1 1 1];
autocal = [1 1 1 1];
resampling_factor = [2 2 2 2];
%rf_mode = (RXEN+TXEN+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNAMax+RFBBNORM)*[1 1 1 1];
rf_mode = (RXEN+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNAMax+RFBBNORM)*active_rf;
rf_mode = rf_mode+((DMAMODE_RX)*active_rf);
%freq_rx = 2540000000*[1 1 1 1];
freq_rx = 2600000000*active_rf;
%freq_rx = 2680000000*active_rf; %+ 2540000000*[0 1 0 0]; % + 859500000*[0 0 1 0];
%freq_rx = 1912600000*[1 1 1 1];
%freq_rx = 859500000*[1 1 1 1];
freq_tx = freq_rx;
tx_gain = 0*active_rf; %[1 1 1 1];
rx_gain = 0*active_rf; %1 1 1 1];
rf_local= rf_local*active_rf; %[1 1 1 1];
rf_rxdc = rf_rxdc*active_rf; %[1 1 1 1];
%rf_vcocal=rf_vcocal_859*[1 1 1 1];
rf_vcocal=rf_vcocal_19G*active_rf; %1 1 1 1];
eNBflag = 0;
tdd_config = DUPLEXMODE_FDD + TXRXSWITCH_TESTRX;
%tdd_config = DUPLEXMODE_FDD + TXRXSWITCH_LSB;
syncmode0 = SYNCMODE_MASTER;
syncmode1 = SYNCMODE_SLAVE;
rffe_rxg_low = 31*active_rf; %[1 1 1 1];
rffe_rxg_final = 63*active_rf; %[1 1 1 1];
rffe_band = B19G_TDD*active_rf; %[1 1 1 1];
printf('Configuring Card 0\n');
oarf_config_exmimo(card0,freq_rx,freq_tx,tdd_config,syncmode0,rx_gain,tx_gain,eNBflag,rf_mode,rf_rxdc,rf_local,rf_vcocal,rffe_rxg_low,rffe_rxg_final,rffe_band,autocal,resampling_factor)
sleep(1);
printf('Configuring Card 1\n');
oarf_config_exmimo(card1,freq_rx,freq_tx,tdd_config,syncmode1,rx_gain,tx_gain,eNBflag,rf_mode,rf_rxdc,rf_local,rf_vcocal,rffe_rxg_low,rffe_rxg_final,rffe_band,autocal,resampling_factor)
gpib_card=0; % first GPIB PCI card in the computer
gpib_device=28; % this is configured in the signal generator Utilities->System
cables_loss_dB = 6; % we need to account for the power loss between the signa
power_dBm = -95;
%gpib_send(gpib_card,gpib_device,['POW ' int2str(power_dBm+cables_loss_dB) 'dBm']);
%gpib_send(gpib_card,gpib_device,'OUTP:STAT ON'); % activate output
%vlen=76800;
%v = 5000* [ zeros(1,1000) ones(1,500) zeros(1,500) ones(1,1) zeros(1,vlen-1000-1000-1)]; v=[v;v;v;v]'; oarf_send_frame(1,v,16);
%sleep(1)
s=oarf_get_frame(0);
%s1=oarf_get_frame(1);
%s = [s s1];
if (resampling_factor(1)== 2)
length1 = 76800;
f0 = (7.68*(0:length(s(:,1))/4-1)/(length(s(:,1))/4))-3.84;
axis([-3.84,3.84,40,200]);
elseif (resampling_factor(1) == 1)
length1 = 153600;
f0 = (15.36*(0:length(s(:,1))/2-1)/(length(s(:,1))/2))-7.68;
axis([-7.68,7.68,40,200]);
else
length1 = 307200;
f0 = (30.72*(0:length(s(:,1))-1)/(length(s(:,1))))-15.36;
axis([-15.36,15.36,40,200]);
endif
if (resampling_factor(2)== 2)
length2 = 76800;
f1 = (7.68*(0:length(s(:,2))/4-1)/(length(s(:,2))/4))-3.84;
axis([-3.84,3.84,40,200]);
elseif (resampling_factor(2) == 1)
length2 = 153600;
f1 = (15.36*(0:length(s(:,2))/2-1)/(length(s(:,2))/2))-7.68;
axis([-7.68,7.68,40,200]);
else
length2 = 307200;
f1 = (30.72*(0:length(s(:,2))-1)/(length(s(:,2))))-15.36;
axis([-15.36,15.36,40,200]);
endif
if (resampling_factor(3)== 2)
length3 = 76800;
f2 = (7.68*(0:length(s(:,3))/4-1)/(length(s(:,3))/4))-3.84;
axis([-3.84,3.84,40,200]);
elseif (resampling_factor(3) == 1)
length3 = 153600;
f2 = (15.36*(0:length(s(:,3))/2-1)/(length(s(:,3))/2))-7.68;
axis([-7.68,7.68,40,200]);
else
length3 = 307200;
f2 = (30.72*(0:length(s(:,3))-1)/(length(s(:,3))))-15.36;
axis([-15.36,15.36,40,200]);
endif
if (resampling_factor(4)== 2)
length4 = 76800;
f3 = (7.68*(0:length(s(:,4))/4-1)/(length(s(:,4))/4))-3.84;
axis([-3.84,3.84,40,200]);
elseif (resampling_factor(4) == 1)
length4 = 153600;
f3 = (15.36*(0:length(s(:,4))/2-1)/(length(s(:,4))/2))-7.68;
axis([-7.68,7.68,40,200]);
else
length4 = 307200;
f3 = (30.72*(0:length(s(:,4))-1)/(length(s(:,4))))-15.36;
axis([-15.36,15.36,40,200]);
endif
length_slave = 76800;
spec0 = 20*log10(abs(fftshift(fft(s(1:length1,1)))));
spec1 = 20*log10(abs(fftshift(fft(s(1:length2,2)))));
spec2 = 20*log10(abs(fftshift(fft(s(1:length3,3)))));
spec3 = 20*log10(abs(fftshift(fft(s(1:length4,4)))));
spec4 = 20*log10(abs(fftshift(fft(s(1:length_slave,5)))));
spec5 = 20*log10(abs(fftshift(fft(s(1:length_slave,6)))));
spec6 = 20*log10(abs(fftshift(fft(s(1:length_slave,7)))));
spec7 = 20*log10(abs(fftshift(fft(s(1:length_slave,8)))));
axis_time = [1:76800*4];
clf
if (active_rf(1) == 1)
hold off;
plot(f0',spec0,'r');
figure
plot(f0',spec4,'b');
endif
%hold on
if (active_rf(2) == 1)
hold off;
figure;
plot(f1',spec1,'b');
endif
%hold on
if (active_rf(3) == 1)
hold off;
figure;
plot(f2',spec2,'g');
endif
%hold on
if (active_rf(4) == 1)
hold off;
figure;
plot(f3',spec3,'m');
endif
%hold on
hold off;
figure;
plot(real(s(1:length1,1)),'r');
hold on
plot(real(s(1:length_slave,5)),'b');
hold off;
figure;
plot(imag(s(1:length1,1)),'r');
hold on
plot(imag(s(1:length_slave,5)),'b');
%len=2500;off=0; chan=[1 5]; hold off ; figure; plot(real(s(off+1:off+len,chan)),'-o',"markersize",2) ; hold off ; figure; plot(imag(s(off+1:off+len,chan)),'r-o',"markersize",2);
%hold off
%axis([-3.84,3.84,40,160]);
%gpib_send(gpib_card,gpib_device,'OUTP:STAT OFF'); % activate output
%legend('Antenna Port 0','Antenna Port 1','Antenna Port 2','Antenna Port 3');
grid
@@ -1,137 +0,0 @@
fc = 2560000000
%fc = 1907600000;
%fc = 859.5e6;
rxgain=0;
txgain=0;
eNB_flag = 0;
card = 0;
active_rf = [1 0 0 0];
autocal = [1 1 1 1];
resampling_factor = [2 2 2 2];
limeparms;
rf_mode = (RXEN+TXEN+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNAMax+RFBBNORM) * active_rf;
rf_mode = rf_mode + (DMAMODE_RX + DMAMODE_TX)*active_rf;
%rf_mode = rf_mode + (DMAMODE_TX)*active_rf + DMAMODE_RX*active_rf;
%rf_mode = RXEN+TXEN+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNAByp+RFBBLNA1;
%rf_local= [8253704 8253704 8257340 8257340]; %eNB2tx %850MHz
%rf_local= [8255004 8253440 8257340 8257340]; % ex2 700 MHz
rf_local = [8254744 8255063 8257340 8257340]; %eNB2tx 1.9GHz
%rf_local = [8257292 8257300 8257340 8257340]; %ex2 850 MHz
%rf_local = rf_local * chan_sel;
rf_rxdc = rf_rxdc * active_rf;
%rf_vcocal = rf_vcocal_859 * chan_sel;
rf_vcocal = rf_vcocal_19G * active_rf;
%rf_vcocal = rf_vcocal_26G_eNB * chan_sel;
rxgain = rxgain*active_rf;
txgain = txgain*active_rf;
freq_tx = fc.*active_rf;
freq_rx = freq_tx;
%freq_rx = freq_tx-120000000*chan_sel;
%freq_tx = freq_rx+1920000;
%tdd_config = DUPLEXMODE_FDD + TXRXSWITCH_LSB;
tdd_config = DUPLEXMODE_FDD + TXRXSWITCH_TESTTX;
syncmode = SYNCMODE_FREE;
rffe_rxg_low = 61*[1 1 1 1];
rffe_rxg_final = 61*[1 1 1 1];
rffe_band = B19G_TDD*[1 1 1 1];
oarf_config_exmimo(card, freq_rx,freq_tx,tdd_config,syncmode,rxgain,txgain,eNB_flag,rf_mode,rf_rxdc,rf_local,rf_vcocal,rffe_rxg_low,rffe_rxg_final,rffe_band,autocal,resampling_factor);
%oarf_config_exmimo(1, freq_rx,freq_tx,tdd_config,syncmode,rxgain,txgain,eNB_flag,rf_mode,rf_rxdc,rf_local,rf_vcocal,rffe_rxg_low,rffe_rxg_final,rffe_band,autocal,resampling_factor);
amp = pow2(10)-1;
n_bit = 16;
length = 307200/pow2(resampling_factor(1));
s = zeros(length,4);
select = 7;
switch(select)
case 0
s(:,1) = amp * ones(1,length);
s(:,2) = amp * ones(1,length);
s(:,3) = amp * ones(1,length);
s(:,4) = amp * ones(1,length);
case 1
s(:,1) = floor(amp * (exp(1i*2*pi*(0:((length)-1))/4)));
s(:,2) = floor(amp * (exp(1i*2*pi*(0:((length)-1))/4)));
s(:,3) = floor(amp * (exp(1i*2*pi*(0:((length)-1))/4)));
s(:,4) = floor(amp * (exp(1i*2*pi*(0:((length)-1))/4)));
case 2
s(38400+128,1)= 80-1j*40;
s(38400+138,1)= -80+1j*40;
case 3
for i=0:(12*5-1)
s((38401+640*i):(38400+640*(i+1)),1)=floor(linspace(-127,128,640)); %+1j*floor(linspace(128,-127,640));
end
case 4
pss0_f0=[0,0,0,0,0,0,0,0,0,0,32767,0,-26120,-19785,11971,-30502,-24020,-22288,32117,6492,31311,9658,-16384,-28378,25100,-21063,-7292,-31946,20429,25618,14948,29158,11971,-30502,31311,9658,25100,-21063,-16384,28377,-24020,22287,32117,6492,-7292,31945,20429,25618,-26120,-19785,-16384,-28378,-16384,28377,-26120,-19785,-32402,4883,31311,-9659,32117,6492,-7292,-31946,32767,-1,25100,-21063,-24020,22287,-32402,4883,-32402,4883,-24020,22287,25100,-21063,32767,-1,-7292,-31946,32117,6492,31311,-9659,-32402,4883,-26120,-19785,-16384,28377,-16384,-28378,-26120,-19785,20429,25618,-7292,31945,32117,6492,-24020,22287,-16384,28377,25100,-21063,31311,9658,11971,-30502,14948,29158,20429,25618,-7292,-31946,25100,-21063,-16384,-28378,31311,9658,32117,6492,-24020,-22288,11971,-30502,-26120,-19785,32767,0,0,0,0,0,0,0,0,0,0,0];
%pss0_f = pss0_f0(1:2:length(pss0_f0)) + sqrt(-1)*pss0_f0(2:2:length(pss0_f0));
pss0_f = pss0_f0(1:2:size(pss0_f0,2)) + sqrt(-1)*pss0_f0(2:2:size(pss0_f0,2));
pss0_f = [0 pss0_f(37:72) zeros(1,512-73) pss0_f(1:36)];
pss0_t = ifft(pss0_f);
pss0_t = [pss0_t((512-127):512) pss0_t];
pss0_t = [pss0_t zeros(1,512+36) pss0_t];
pss0_max = max(max(abs(real(pss0_t))),max(abs(imag(pss0_t))));
pss0_t_fp_re = floor(real(8192*pss0_t/pss0_max));
pss0_t_fp_im = floor(imag(8192*pss0_t/pss0_max));
%keyboard;
s(38400+(1:length(pss0_t_fp_re)),1) = 2*floor(pss0_t_fp_re) + 2*sqrt(-1)*floor(pss0_t_fp_im);
s(38400+(1:length(pss0_t_fp_re)),2) = 2*floor(pss0_t_fp_re) + 2*sqrt(-1)*floor(pss0_t_fp_im);
s(38400+(1:length(pss0_t_fp_re)),3) = 2*floor(pss0_t_fp_re) + 2*sqrt(-1)*floor(pss0_t_fp_im);
s(38400+(1:length(pss0_t_fp_re)),4) = 2*floor(pss0_t_fp_re) + 2*sqrt(-1)*floor(pss0_t_fp_im);
%s(38400+(1:size(pss0_t_fp_re,2)),1) = 2*floor(pss0_t_fp_re) + 2*sqrt(-1)*floor(pss0_t_fp_im);
%s(38400+(1:size(pss0_t_fp_re,2)),2) = 2*floor(pss0_t_fp_re) + 2*sqrt(-1)*floor(pss0_t_fp_im);
%s(38400+(1:size(pss0_t_fp_re,2)),3) = 2*floor(pss0_t_fp_re) + 2*sqrt(-1)*floor(pss0_t_fp_im);
%s(38400+(1:size(pss0_t_fp_re,2)),4) = 2*floor(pss0_t_fp_re) + 2*sqrt(-1)*floor(pss0_t_fp_im);
case 5
x=1:length;
s(:,1) = 1i*8*(mod(x-1,4096)); % + 1i*(8*(mod(x-1,4096)));
s(:,2) = 8*(mod(x-1,4096)) + 1i*(8*(mod(x-1,4096)));
s(:,3) = 8*(mod(x-1,4096)) + 1i*(8*(mod(x-1,4096)));
s(:,4) = 8*(mod(x-1,4096)) + 1i*(8*(mod(x-1,4096)));
case 6
nb_rb = 100; %this can be 25, 50, or 100
num_carriers = 2048/100*nb_rb;
num_zeros = num_carriers-(12*nb_rb+1);
prefix_length = num_carriers/4; %this is extended CP
num_symbols_frame = 120;
preamble_length = 120;
s(:,1) = OFDM_TX_FRAME(num_carriers,num_zeros,prefix_length,num_symbols_frame,preamble_length);
s(:,1) = floor(amp*(s(:,1)./max([real(s(:,1)); imag(s(:,1))])));
case 7
s(:,1) = floor(txs0);
otherwise
error('unknown case')
end %switch
s = s*2;
oarf_send_frame(card,s,n_bit);
%oarf_send_frame(1,s,n_bit);
%sleep (1)
%r = oarf_get_frame(card);
figure(1)
hold off
plot(real(s(:,1)),'r')
%hold on
%plot(imag(s(:,2)),'b')
@@ -1,121 +0,0 @@
%fc = 2660000000;
fc = 1907600000;
%fc = 859.5e6;
rxgain=0;
txgain=25;
eNB_flag = 0;
card = 0;
active_rf = [1 1 0 0];
autocal = [1 1 1 1];
resampling_factor = [2 2 2 2];
limeparms;
rf_mode = (RXEN+TXEN+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNAMax+RFBBNORM) * active_rf;
rf_mode = rf_mode + (DMAMODE_RX + DMAMODE_TX)*active_rf;
%rf_mode = RXEN+TXEN+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNAByp+RFBBLNA1;
%rf_local= [8253704 8253704 8257340 8257340]; %eNB2tx %850MHz
%rf_local= [8255004 8253440 8257340 8257340]; % ex2 700 MHz
rf_local = [8254744 8255063 8257340 8257340]; %eNB2tx 1.9GHz
%rf_local = [8257292 8257300 8257340 8257340]; %ex2 850 MHz
%rf_local = rf_local * chan_sel;
rf_rxdc = rf_rxdc * active_rf;
%rf_vcocal = rf_vcocal_859 * chan_sel;
rf_vcocal = rf_vcocal_19G * active_rf;
%rf_vcocal = rf_vcocal_26G_eNB * chan_sel;
rxgain = rxgain*active_rf;
txgain = txgain*active_rf;
freq_tx = fc*active_rf;
freq_rx = freq_tx;
%freq_rx = freq_tx-120000000*chan_sel;
%freq_tx = freq_rx+1920000;
tdd_config = DUPLEXMODE_FDD + TXRXSWITCH_TESTTX;
syncmode0 = SYNCMODE_MASTER;
syncmode1 = SYNCMODE_SLAVE;
rffe_rxg_low = 61*[1 1 1 1];
rffe_rxg_final = 61*[1 1 1 1];
rffe_band = B19G_TDD*[1 1 1 1];
oarf_config_exmimo(0, freq_rx,freq_tx,tdd_config,syncmode0,rxgain,txgain,eNB_flag,rf_mode,rf_rxdc,rf_local,rf_vcocal,rffe_rxg_low,rffe_rxg_final,rffe_band,autocal,resampling_factor);
sleep(1);
oarf_config_exmimo(1, freq_rx,freq_tx,tdd_config,syncmode1,rxgain,txgain,eNB_flag,rf_mode,rf_rxdc,rf_local,rf_vcocal,rffe_rxg_low,rffe_rxg_final,rffe_band,autocal,resampling_factor);
amp = pow2(14)-1;
n_bit = 16;
s = zeros(76800*4,4);
select = 1;
switch(select)
case 1
s(:,1) = floor(amp * (exp(1i*2*pi*(0:((76800*4)-1))/7680)));
s(:,2) = floor(amp * (exp(1i*2*pi*(0:((76800*4)-1))/7680)));
s(:,3) = floor(amp * (exp(1i*2*pi*(0:((76800*4)-1))/7680)));
s(:,4) = floor(amp * (exp(1i*2*pi*(0:((76800*4)-1))/7680)));
case 2
s(38400+128,1)= 80-1j*40;
s(38400+138,1)= -80+1j*40;
case 3
for i=0:(12*5-1)
s((38401+640*i):(38400+640*(i+1)),1)=floor(linspace(-127,128,640)); %+1j*floor(linspace(128,-127,640));
end
case 4
pss0_f0=[0,0,0,0,0,0,0,0,0,0,32767,0,-26120,-19785,11971,-30502,-24020,-22288,32117,6492,31311,9658,-16384,-28378,25100,-21063,-7292,-31946,20429,25618,14948,29158,11971,-30502,31311,9658,25100,-21063,-16384,28377,-24020,22287,32117,6492,-7292,31945,20429,25618,-26120,-19785,-16384,-28378,-16384,28377,-26120,-19785,-32402,4883,31311,-9659,32117,6492,-7292,-31946,32767,-1,25100,-21063,-24020,22287,-32402,4883,-32402,4883,-24020,22287,25100,-21063,32767,-1,-7292,-31946,32117,6492,31311,-9659,-32402,4883,-26120,-19785,-16384,28377,-16384,-28378,-26120,-19785,20429,25618,-7292,31945,32117,6492,-24020,22287,-16384,28377,25100,-21063,31311,9658,11971,-30502,14948,29158,20429,25618,-7292,-31946,25100,-21063,-16384,-28378,31311,9658,32117,6492,-24020,-22288,11971,-30502,-26120,-19785,32767,0,0,0,0,0,0,0,0,0,0,0];
pss0_f = pss0_f0(1:2:length(pss0_f0)) + sqrt(-1)*pss0_f0(2:2:length(pss0_f0));
pss0_f = [0 pss0_f(37:72) zeros(1,512-73) pss0_f(1:36)];
pss0_t = ifft(pss0_f);
pss0_t = [pss0_t((512-127):512) pss0_t];
pss0_t = [pss0_t zeros(1,512+36) pss0_t];
pss0_max = max(max(abs(real(pss0_t))),max(abs(imag(pss0_t))));
pss0_t_fp_re = floor(real(8192*pss0_t/pss0_max));
pss0_t_fp_im = floor(imag(8192*pss0_t/pss0_max));
s(38400+(1:length(pss0_t_fp_re)),1) = 2*floor(pss0_t_fp_re) + 2*sqrt(-1)*floor(pss0_t_fp_im);
s(38400+(1:length(pss0_t_fp_re)),2) = 2*floor(pss0_t_fp_re) + 2*sqrt(-1)*floor(pss0_t_fp_im);
s(38400+(1:length(pss0_t_fp_re)),3) = 2*floor(pss0_t_fp_re) + 2*sqrt(-1)*floor(pss0_t_fp_im);
s(38400+(1:length(pss0_t_fp_re)),4) = 2*floor(pss0_t_fp_re) + 2*sqrt(-1)*floor(pss0_t_fp_im);
case 5
x=1:76800;
s(:,1) = 1i*8*(mod(x-1,4096)); % + 1i*(8*(mod(x-1,4096)));
s(:,2) = 8*(mod(x-1,4096)) + 1i*(8*(mod(x-1,4096)));
s(:,3) = 8*(mod(x-1,4096)) + 1i*(8*(mod(x-1,4096)));
s(:,4) = 8*(mod(x-1,4096)) + 1i*(8*(mod(x-1,4096)));
% s(:,4) = 8*(rem(x-1,2048))-2**15 + 1i*(8*(rem(x-1,2048))-2**15);
% s(:,4) = 8*(mod(x-1,4096)) + 1i*8*(mod(x-1,4096));
%s(:,1) = 8*floor(mod(x-1,76800)/75) + 1i*8*floor(mod(x-1,76800)/75);
%s(:,2) = 8*floor(mod(x-1,76800)/75) + 1i*8*floor(mod(x-1,76800)/75);
%s(:,3) = 8*floor(mod(x-1,76800)/75) + 1i*8*floor(mod(x-1,76800)/75);
%s(:,4) = 8*floor(mod(x-1,76800)/75) + 1i*8*floor(mod(x-1,76800)/75);
otherwise
error('unknown case')
endswitch
%s = s*2 - 2**15 -1i*(2**15);
s = s*2;
%s(38400:end,1) = (1+1j);
%s(38400:end,2) = (1+1j);
sleep (1)
%keyboard
oarf_send_frame(0,s,n_bit);
sleep(1);
oarf_send_frame(1,s,n_bit);
%r = oarf_get_frame(card);
figure(1)
hold off
plot(real(s(:,1)),'r')
%hold on
%plot(imag(s(:,2)),'b')
@@ -1,27 +0,0 @@
dual_tx=1;
cbmimo1=0;
if (cbmimo1)
oarf_config(0,1,dual_tx,255);
amp = pow2(7)-1;
n_bit = 8;
else
oarf_config_exmimo(1902600000,1,dual_tx,30);
amp = pow2(15)-1;
n_bit = 16;
end
s = zeros(76800,2);
s(:,1) = 8*floor(amp*OFDM_TX_FRAME(512,211,128,120,8));
s(:,2) = 8*floor(amp*OFDM_TX_FRAME(512,211,128,120,8));
%s(:,1) = amp * (exp(sqrt(-1)*.5*pi*(0:((76800)-1))));
%s(:,2) = amp * (exp(sqrt(-1)*.5*pi*(0:((76800)-1))));
if (cbmimo1)
oarf_set_tx_gain(110,110,110,110);
end
oarf_send_frame(0,s,n_bit);
plot(20*log10(abs(fft(s(:,1)))))

Some files were not shown because too many files have changed in this diff Show More