📄 stfa_complex.c
字号:
/*************************************************************************** stfa_complex.c - RTLinux kernel module for a complex STFA ------------------- begin : 2002 authors : Linus Gasser emails : linus.gasser@epfl.ch ***************************************************************************//*************************************************************************** Changes ------- date - name - description 02/09/26 - ineiti - begin 02/11/04 - ineiti - extended for notice_sdb and notice_functions 03/01/06 - ineiti - fix the offset to allow for chip-resolution 03/01/13 - ineiti - added a supplementary offset for the sending part 03/02/25 - ineiti - cleaning up the different offsets 03/03/03 - ineiti - adding sltots_per_frame and slot_size to config 03/03/13 - ineiti - finished with implementation of guard-interval 03/05/12 - ineiti - deleted the amp_* from both config and stats 03/11/13 - ineiti - added SUBS_MSG_UPDATE to make sure the chains are OK 03/11/24 - ineiti - made a complex STFA 03/12/15 - ineiti - chained the STFAs instead of array in first STFA 03/12/?? - ineiti - made it complex 04/03/08 - ineiti - adjusted description 04/03/22 - ineiti - renamed MSG_UPDATE to MSG_PREPARE 04/03/31 - ineiti - made sure that calling chain is not already active 04/04/06 - ineiti - added PREPARE_SWALLOW TODO ---- * Implement a real MAX_SLOTS and NUM_SLOTS... **************************************************************************//*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************//** * The STFA_complex implements a framed TDD-transmission. It is THE module * in the software-radio. It is responsible for the interaction with the * hardware or the simulator, and allows to define the scheduling of the * different slots. * This module has x inputs and x outputs which are tied to one antenna. * It differs from STFA in that it has complex in- and outputs * * User messages: * - "ANT": the antenna received/sent a slot * - "Go": start the STFA * - "Stop": stop the STFA * - "Notice_func": add a notice-function * - "Notice_sdb": add a notice-sdb * * The user-messages can be called using functions which are defined in stfa.h: * - add a notice-function to a slot * void swr_stfa_notice_func( swr_sdb_id stfa, int slot, func *f ) * - add a sdb to a slot * void swr_stfa_notice_sdb( swr_sdb_id stfa, int slot, swr_sdb_id sdb_id ); * - Start the stfa, this also starts the DMA-transfer. * void swr_stfa_go( swr_sdb_id stfa ); * - Stop the stfa. This also stops the DMA-transfer. * void swr_stfa_stop( swr_sdb_id stfa ); */#include "spc.h"#include "antenna.h"#include "stfa.h"#include "rf.h"#define DBG_LVL 0#define MAX_DMA_SIZE ( MAX_SLOT_BYTES * MAX_SLOTS )#define MAX_BUFFER_SIZE ( MAX_SLOT_BYTES + MAX_DMA_SIZE + MAX_SLOT_BYTES )// This is the logical pointer from the start of the DMA-region on where// to find the start of the slot#define OFFSET_RX(slot) \ ( ( ( ( (slot) * private->blocks_per_slot + private->offset_rcv_blocks + \ private->rx_tx_delay_blocks ) % \ private->len_frame_blocks ) * DAQ_DMA_BLOCK_SIZE_BYTES + \ private->rx_tx_delay_bytes + private->offset_rcv_bytes + \ private->dma_bytes ) % private->dma_bytes )// The corrected position, where the last half slot is wrapped IN FRONT// of the DMA region (memcpy has to take place)#define DMA_OFFSET_RX(slot) \ ( ( OFFSET_RX( slot ) > ( private->dma_bytes - private->slot_bytes / 2 ) ) ? \ ( OFFSET_RX( slot ) - private->dma_bytes ) : OFFSET_RX( slot ) )// The memory-buffer is one slot in front of the dma-buffer#define BUFFER_OFFSET_RX(slot) \ ( DMA_OFFSET_RX(slot) + private->slot_bytes )// *_TX is the same as *_RX#define OFFSET_TX(slot) \ ( ( ( ( (slot) * private->blocks_per_slot + private->offset_rcv_blocks ) % \ private->len_frame_blocks ) * DAQ_DMA_BLOCK_SIZE_BYTES + \ private->offset_rcv_bytes - private->offset_send_bytes + \ private->dma_bytes ) % private->dma_bytes )#define DMA_OFFSET_TX(slot) \ ( ( OFFSET_TX( slot ) > ( private->dma_bytes - private->slot_bytes / 2 ) ) ? \ ( OFFSET_TX( slot ) - private->dma_bytes ) : OFFSET_TX( slot ) )#define BUFFER_OFFSET_TX(slot) \ ( DMA_OFFSET_TX(slot) + private->slot_bytes )// some handy definitions#define DMA_BEGIN_RX ( private->buffer_rx + private->slot_bytes )#define DMA_BEGIN_TX ( private->buffer_tx + private->slot_bytes )#define DMA_END_RX ( private->buffer_rx + private->dma_bytes + private->slot_bytes )#define DMA_END_TX ( private->buffer_tx + private->dma_bytes + private->slot_bytes )int nbr_stfa;typedef struct { // How many slots in advance a TX-chain is called int slot_send_offset; // 2 // The general delay between the master and this radio int offset_chips_rcv; // 0 // The more fine delay between the master and this radio int offset_samples_rcv; // 0 // Kind of the distance between the master and this radio, as // the samples will be sent this much earlier, in order to arrive // in synch at the master int offset_samples_send; // 0 // Set the size of the transmission-slots int blocks_per_slot; // 20 // Set the number of slots per frame int slots_per_frame; // 15 // The guard-period, which is put in before and after the slot, in chips int guard_period_chips; // 90 // The gains for direct changes int gain_tx_0, gain_tx_1, gain_tx_2; int gain_rx_0; // The more general gains (the above should disappear sometimes) int gain_tx; // 0 int gain_rx; // 0 // Master-Slave Stfa's in MIMO // Each STFA has the id of the next STFA or -1 to finish the chain int stfa_id; // -1}config_t;typedef struct { // How many frames have been done int frame_count; // This many blocks per slot int blocks_per_slot; // This many slots per frame int slots_per_frame; // The whole reception-dma-area, including buffer-zones block_t rx; // The whole transmission-dma-area, including buffer-zones block_t tx; // How many chips from the beginning of the buffer slot0 is // placed int offset_chips; // How many samples from the beginning of the buffer slot0 is // placed int offset_samples;}stats_t;typedef struct { char *buffer_rx; char *buffer_tx; int nbr_stfa; int ant_index; int sso; // config->offset_chips_rcv * DAQ_QI_SAMPLES_PER_CHIP + // config->offset_samples_rcv = // ( private->offset_rcv_blocks * DAQ_DMA_BLOCK_SIZE_QI_SAMPLES + // private->offset_rcv_bytes / 2 ) // This is done because the hardware works in 'blocks', so we can tell the // hardware to wake us up a bit later/earlier and the calculate the rest. int offset_rcv_blocks; // This is relative to offset_rcv_blocks int offset_rcv_bytes; // This equals config->offset_samples_send, and should only // be used on the MS-end. In bytes int offset_send_bytes; // The delay introduced by the hardware, in blocks and bytes int rx_tx_delay_blocks; int rx_tx_delay_bytes; // The actual slots per frame int slots_per_frame; // The actual size of the transmission-slots, in dma-blocks int blocks_per_slot; // The sdb's to notice at a given rcv-slot swr_sdb_id notice_sdb[ MAX_SLOTS ]; // A function to notice at a given rcv-slot. See stfa.h for a // definition of func func *notice_f[ MAX_SLOTS ]; // To indicate whether the antenna is running right now int running; // Number of bytes in a slot int slot_bytes; // The length of a frame in blocks int len_frame_blocks; // The length of the DMA-part int dma_bytes; // The guard period, in bytes int guard_period_bytes; // The gains for direct changes int gain_tx_0, gain_tx_1, gain_tx_2; int gain_rx_0; // The more general gains int gain_tx; int gain_rx; int stfa_id;}private_t;/** * The initialisation part that is only called the first time this module * is instantiated. */int spc_init( swr_sdb_t *context ) { config_t *config; stats_t *stats; int i; MOD_INC_USE_COUNT; context->private_data = swr_malloc( sizeof( private_t ) ); swr_sdb_get_config_struct( context->id, (void**)&config ); swr_sdb_get_stats_struct( context->id, (void**)&stats ); // Tell the subsystem we don't accept resizes, but only emit them // Furthermore, don't propagate prepare-msgs SET_STATUS( RESIZE_NONE ); SET_STATUS( PREPARE_SWALLOW ); // First of all, initialise the static and private stuff private->nbr_stfa = nbr_stfa++; private->offset_rcv_blocks = 0; private->offset_rcv_bytes = 0; private->offset_send_bytes = 0; private->sso = 2; private->slots_per_frame = 0; private->blocks_per_slot = 0; private->running = 0; private->stfa_id = -1; config->stfa_id = -1; config->slot_send_offset = 2; config->offset_chips_rcv = 0; config->offset_samples_rcv = 0; config->offset_samples_send = 0; // This is pseudo-UMTS standard config->blocks_per_slot = 20; config->slots_per_frame = 15; config->guard_period_chips = 90; // Initialise the antenna-dispatcher. if ( ( private->ant_index = swr_ant_init( context->id ) ) < 0 ) { PR_DBG( 0, "Can't initialise dispatcher\n" ); return -1; } PR_DBG( 1, "Initialised ant-dispatcher %i\n", private->ant_index ); // And put the receive and transmit-buffers in place private->buffer_rx = swr_malloc( MAX_BUFFER_SIZE ); private->buffer_tx = swr_malloc( MAX_BUFFER_SIZE ); if ( !private->buffer_rx || !private->buffer_tx ) { PR_DBG( 0, "Couldn't allocate all necessary memory for the DMA!\n" "Aborting! This is SERIOUS\n" ); return -1; } // Setting up the antenna-parameters i = swr_ant_get_rx_tx_delay( private->nbr_stfa ); private->rx_tx_delay_blocks = i / DAQ_DMA_BLOCK_SIZE_BYTES; private->rx_tx_delay_bytes = i % DAQ_DMA_BLOCK_SIZE_BYTES; //Tell the antenna that we transmitt complex data// swr_ant_set_is_complex( private->ant_index, 1 );// PR_DBG( 4, "antenna %i is told to transmitt complex data \n",// private->ant_index ); // Now we can begin initialising things depending on private-> stats->blocks_per_slot = 0; stats->slots_per_frame = 0; stats->frame_count = 0; stats->rx.data = private->buffer_rx; stats->rx.type = SIG_SYMBOL_COMPLEX; stats->tx.data = private->buffer_tx; stats->tx.type = SIG_SYMBOL_COMPLEX; // Initialise the slots for ( i=0; i < MAX_SLOTS; i++ ) { port_in(i).data = 0; port_in(i).size = 0; port_in(i).flags = SWR_PORT_OWN_MALLOC; port_out(i).data = 0; port_out(i).size = 0; port_out(i).flags = SWR_PORT_OWN_MALLOC; // And initialise the notice-queues private->notice_sdb[i] = -1; private->notice_f[i] = NULL; } // This is only valid with the old RF-cards! swr_ant_rf_get_gains( private->nbr_stfa, &config->gain_tx_0, &config->gain_tx_1, &config->gain_tx_2, &config->gain_rx_0 ); private->gain_tx_0 = config->gain_tx_0; private->gain_tx_1 = config->gain_tx_1; private->gain_tx_2 = config->gain_tx_2; private->gain_rx_0 = config->gain_rx_0; private->gain_tx = private->gain_rx = config->gain_tx = config->gain_rx = 0; swr_sdb_free_stats_struct( context->id, (void**)&stats ); swr_sdb_free_config_struct( context->id, (void**)&config ); return 0;}/** * The initialisation with regard to the slots and frame is quite complex, * so it's outsourced... */int init_slots_frame( swr_sdb_t *context, config_t *config, stats_t *stats ) { if ( private->running ) { PR_DBG( 0, "Can't change slot/frame parameters while running!\n" ); return -1; } if ( config->slots_per_frame <= config->slot_send_offset ) { PR_DBG( 0, "Can't ask to build a slot more than 1 frame in advance.\n" "Offending assertion: slots_per_frame(%i) <= slot_send_offset(%i)\n", config->slots_per_frame, config->slot_send_offset ); return -1; } if ( config->slots_per_frame * config->blocks_per_slot <= private->rx_tx_delay_blocks ) { PR_DBG( 0, "There are less blocks in the frame (%i) than the delay between\n" "the reception and transmission (%i). Aborting\n", config->slots_per_frame * config->blocks_per_slot, private->rx_tx_delay_blocks ); return -1; } // Update the stats (for others) and private (for us) parameters private->slots_per_frame = stats->slots_per_frame = config->slots_per_frame; private->blocks_per_slot = stats->blocks_per_slot = config->blocks_per_slot; private->slot_bytes = private->blocks_per_slot * DAQ_DMA_BLOCK_SIZE_BYTES; private->len_frame_blocks = private->blocks_per_slot * private->slots_per_frame; private->dma_bytes = private->slot_bytes * private->slots_per_frame; // And tell the antenna what we're doing swr_ant_set_slot_len( private->nbr_stfa, private->blocks_per_slot ); swr_ant_set_frame_params( private->nbr_stfa, private->buffer_rx + private->slot_bytes, private->buffer_tx + private->slot_bytes ); // Put the right length for outside viewers. We want to show the whole // frame including the two buffer-spaces, this is the reason for the // + 2 * private->blocks_per_slot stats->rx.size = stats->tx.size = ( private->dma_bytes + 2 * private->slot_bytes ) / DAQ_BYTES_PER_QI_SAMPLE; // Some debugging info (more to come ;-) PR_DBG( 2, "Buffer size:%i*%i*block_size=%i tx@%p-%p and rx@%p-%p\n", private->slots_per_frame, private->blocks_per_slot, private->len_frame_blocks * private->slot_bytes, private->buffer_tx, private->buffer_tx + private->slot_bytes, private->buffer_rx, private->buffer_rx + private->slot_bytes ); return 0;}/** * Every time somebody from the outside changes a configuration value, * this function is called just before the working-function */int spc_reconfig( swr_sdb_t *context ) { config_t *config; int ret = 0, slot, offset_samples; stats_t *stats; swr_sdb_get_config_struct( context->id, (void**)&config ); swr_sdb_get_stats_struct( context->id, (void**)&stats ); // If there is another STFA in the chain, contact it private->stfa_id = config->stfa_id; if( private->stfa_id >= 0 ){ PR_DBG( 4, "Putting values to %i\n", config->stfa_id ); swr_sdb_set_config_int( config->stfa_id, "slot_send_offset", config->slot_send_offset ); swr_sdb_set_config_int( config->stfa_id, "offset_chips_rcv", config->offset_chips_rcv ); swr_sdb_set_config_int( config->stfa_id, "offset_samples_rcv",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -