⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rrc_send.c

📁 This a framework to test new ideas in transmission technology. Actual development is a LDPC-coder in
💻 C
字号:
/***************************************************************************              rrc.c  -  SRadio module for a root-raised cosine                            -------------------    begin                :  2002    authors              :  Linus Gasser    emails               :  linus.gasser@epfl.ch ***************************************************************************//***************************************************************************                                 Changes                                 ------- date - name - description 02-10-16 - ineiti - begin 04/03/06 - ineiti - adjusted description                                  Take Care                                 ---------  if ever you should have the idea to change this rrc, take care about the fact that the peak of the RRC is in the middle! **************************************************************************//*************************************************************************** *                                                                         * *   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.                                   * *                                                                         * ***************************************************************************//** * short makes the root-raised-cosine with roll-off 0.22 * * Is more or less a copy-paste from the ancient software-radio. * Highly-optimized convolution and upsampling of 4 in one. */#include "spc.h"#include "antenna.h"#define DBG_LVL 0#define TX_FILTER_LENGTH_CHIPS 12short int data_rrc[] = {                         111,  -270,  -168,  -141,                         -396,   312,  -153,   669,                         753,  -141,   882, -1551,                         -1137,  -435, -2286,  2979,                         1473,  1935,  5322, -5937,                         -1710, -7320,-18573, 27894,                         31506,-27894,-18573,  7320,                         -1710,  5937,  5322, -1935,                         1473, -2979, -2286,   435,                         -1137,  1551,   882,   141,                         753,  -669,  -153,  -312,                         -396,   141,  -168,   270                       };typedef struct {}config_t;typedef struct {}stats_t;typedef struct {  mmx_t tx_filter_def[TX_FILTER_LENGTH_CHIPS] __attribute__ ((aligned(8)));  mmx_t *buffer_in;  int size_in;}private_t;/** * The initialisation part that is only called the first time this module * is instantiated. */int send_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 );  for(i=0;i<12;i++) {    private->tx_filter_def[i].w[0] = data_rrc[4*i];    private->tx_filter_def[i].w[1] = data_rrc[4*i+1];    private->tx_filter_def[i].w[2] = data_rrc[4*i+2];    private->tx_filter_def[i].w[3] = data_rrc[4*i+3];  }  private->buffer_in = 0;  private->size_in = 0;  swr_sdb_free_config_struct( context->id, (void**)&config );  swr_sdb_free_stats_struct( context->id, (void**)&stats );  return 0;}/** * To configure the inputs */int send_configure_inputs( swr_sdb_t *context ) {  config_t *config;  swr_sdb_get_config_struct( context->id, (void**)&config );  size_in(0) = size_out(0) / DAQ_SAMPLES_PER_CHIP;  // Allocate some private buffer for the complex2mmx operation  // But only if the size changed  if ( size_in(0) != private->size_in ) {    if ( private->buffer_in ) {      swr_free( private->buffer_in );    }    private->buffer_in = swr_malloc( size_in(0) * sizeof( SYMBOL_MMX ) );    private->size_in = size_in(0);  }  swr_sdb_free_config_struct( context->id, (void**)&config );  return 0;}/** * To configure the outputs */int send_configure_outputs( swr_sdb_t *context ) {  config_t *config;  swr_sdb_get_config_struct( context->id, (void**)&config );  size_out(0) = size_in(0) * DAQ_SAMPLES_PER_CHIP;  // Allocate some private buffer for the complex2mmx operation  // But only if the size changed  if ( size_in(0) != private->size_in ) {    if ( private->buffer_in ) {      swr_free( private->buffer_in );    }    private->buffer_in = swr_malloc( size_in(0) * sizeof( SYMBOL_MMX ) );    private->size_in = size_in(0);  }  swr_sdb_free_config_struct( context->id, (void**)&config );  return 0;}/** * Every time somebody from the outside changes a configuration value, * this function is called just before the working-function */int send_reconfig( swr_sdb_t *context ) {  config_t *config;  int ret = 0;  swr_sdb_get_config_struct( context->id, (void**)&config );  swr_sdb_free_config_struct( context->id, (void**)&config );  return ret;}/** * The actual working function */int send_pdata( swr_sdb_t *context ) {  stats_t *stats;  SYMBOL_COMPLEX *in_cplx;  SYMBOL_MMX *in;  SAMPLE_S12 *out;  mmx_t ZERO_TWO_LSBs = {0xfffcfffcfffcfffcULL},                        SEND = {0x0002000200020002ULL};  int i, j;  mmx_t *filter = private->tx_filter_def;  PR_DBG( 4, "Entered pdata\n" );  // Convert from complex to complex_mmx  in_cplx = port_in(0).data;  in = private->buffer_in;  for ( i=0; i < size_in(0); i++ ) {    in[i].w[0] = in[i].w[2] = in_cplx[i].real;    in[i].w[1] = in[i].w[3] = in_cplx[i].imag;  }  out = buffer_out( 0 );  PR_DBG( 4, "Got buffer: %p / %p\n", in, out );  PR_DBG( 4, "Got config\n" );  // Convolution for the first couple of samples, we admit  // size_in(0) > 24  // Try to switch the sending on a bit earlier...#define BEFORE 50  out -= 4*BEFORE + 24;  for ( i=-BEFORE; i<0; i++ ) {    movq_m2r( SEND, mm0 );    movq_r2m( mm0, *out );    out += 4;  }  for ( i=0; i < 12; i++ ) {    movq_m2r( filter[ 0 ], mm2 );    pxor_r2r( mm0, mm0 );    movq_m2r( in[ i ], mm3 );    for ( j=1; j<=i; j++ ) {      pmulhw_r2r( mm2, mm3 );      movq_m2r( filter[ j ], mm2 );      paddsw_r2r( mm3, mm0 );      movq_m2r( in[ i - j ], mm3 );    }    pmulhw_r2r( mm2, mm3 );    paddsw_r2r( mm3, mm0 );    pand_m2r( ZERO_TWO_LSBs, mm0 );    por_m2r( SEND, mm0 );    movq_r2m( mm0, *out );    out += 4;  }  // The actual convolution is done here  for ( i=12; i<size_in(0); i++ ) {    movq_m2r( filter[ 0 ], mm2 );    pxor_r2r( mm0, mm0 );    movq_m2r( in[ i ], mm3 );    // This will be unrolled anyway by the compiler...    for ( j=1; j < 10; j += 2 ) {      movq_m2r( filter[ j ], mm4 );      pmulhw_r2r( mm2, mm3 );      movq_m2r( in[ i - j ], mm5 );      paddsw_r2r( mm3, mm0 );      movq_m2r( filter[ j + 1 ], mm2 );      pmulhw_r2r( mm4, mm5 );      movq_m2r( in[ i - j - 1 ], mm3 );      paddsw_r2r( mm5, mm0 );    }    movq_m2r( filter[ 11 ], mm4 );    pmulhw_r2r( mm2, mm3 );    movq_m2r( in[ i - 11 ], mm5 );    paddsw_r2r( mm3, mm0 );    pmulhw_r2r( mm4, mm5 );    paddsw_r2r( mm5, mm0 );    pand_m2r( ZERO_TWO_LSBs, mm0 );    por_m2r( SEND, mm0 );    movq_r2m( mm0, *out );    out += 4;  }  // Convolution for the tail  for ( i=size_in(0); i < size_in(0) + 12; i++ ) {    movq_m2r( filter[ i - size_in(0) + 1 ], mm2 );    pxor_r2r( mm0, mm0 );    movq_m2r( in[ size_in(0) - 1 ], mm3 );    for ( j=2; j < size_in(0) + 12 - i; j++ ) {      pmulhw_r2r( mm2, mm3 );      movq_m2r( filter[ i - size_in(0) + j ], mm2 );      paddsw_r2r( mm3, mm0 );      movq_m2r( in[ size_in(0) - j ], mm3 );    }    pmulhw_r2r( mm2, mm3 );    paddsw_r2r( mm3, mm0 );    pand_m2r( ZERO_TWO_LSBs, mm0 );    por_m2r( SEND, mm0 );    movq_r2m( mm0, *out );    out += 4;  }  emms();  PR_DBG( 4, "Did convolution\n" );  // Update the stats  swr_sdb_get_stats_struct( context->id, (void**)&stats );  swr_sdb_free_stats_struct( context->id, (void**)&stats );  PR_DBG( 4, "About to quit\n" );  return 0;}int send_finalize( swr_sdb_t *context ) {  swr_free( private );  MOD_DEC_USE_COUNT;  return 0;}swr_spc_id_t send_id;/** * This function is called upon "insmod" and is used to register the * different parts of the module to the SPM. */int send_module_init(void) {  swr_spc_desc_t *desc;  // Get a description-part from SPM  // Nbr_input_ports, Nbr_output_ports, Nbr_config_values, Nbr_stats_values  desc = swr_spc_get_new_desc( 1, 1, 0, 0 );  if ( !desc ) {    PR_DBG( 0, "Can't initialise the module. This is bad!\n" );    return -1;  }  // Define the different parts of config, stats and io-ports  // Initialise the callback-functions. NULL for not-used functions  desc->fn_init = send_init;  desc->fn_reconfigure = send_reconfig;  desc->fn_process_data = send_pdata;  desc->fn_custom_msg = NULL;  desc->fn_finalize = send_finalize;  desc->fn_configure_inputs = send_configure_inputs;  desc->fn_configure_outputs = send_configure_outputs;  UM_INPUT( SIG_SYMBOL_COMPLEX, 0 );  UM_OUTPUT( SIG_SAMPLE_S12, 0 );  // And register the module in the SPM  send_id = swr_cdb_register_spc( &desc, "rrc" );  if ( send_id == SWR_SPM_INVALID_ID ) {    swr_spc_free_desc( desc );    PR_DBG( 0, "Couldn't register the module!\n" );    return 1;  }  return 0;}void send_module_exit( void ) {  PR_DBG( 2, "RRC is going\n" );  if ( swr_cdb_unregister_spc( send_id ) < 0 ) {    PR_DBG( 0, "Still in use somewhere\n" );  }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -