📄 synch_rcv.c
字号:
/*************************************************************************** * rcv.c - Software Radio to detect primary synch * ------------------- * begin : 02/10/22 * authors : Linus Gasser * emails : Linus.Gasser@epfl.ch ***************************************************************************//*************************************************************************** * Changes * ------- * date - name - description * 02/10/22 - ineiti - init * 04/01/07 - ineiti - added a search for other peaks and signal them by * lowering synch_amp and putting synch_pos to -10 * 04/03/01 - ineiti - fixed for ICS-cards (stupid data-format) * 04/03/08 - ineiti - adjusted description * 04/03/08 - ineiti - deleted synch_move, as it's not used anymore * 04/03/29 - ineiti - adjusted synch-movement if there is no synch * **************************************************************************//*************************************************************************** * * * 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 desynchronisation uses a convolution to find the most probable * synchronistaion-signal. Due to the special format of the synch-signal, * it is possible to implement this as two convolutions, which reduces a * lot the computational complexity of the task. */#include "spc.h"#include "mmx.h"#include "antenna.h"#include "synch.h"#define DBG_LVL 0#define PRE_POST_LENGTH 32typedef struct { // If this is set to a valid id, it will set the offset for the stfa int stfa_id; // -1 // If this is 1, the sycnh_rcv also sets the offset_samples_rcv of the stfa int fine_adj; // 0}config_t;typedef struct { // The position of the strongest synchronisation signal int synch_pos; // The amplitude of the strongest signal int synch_amp; // The fine position, 0-3 int fine_pos; // The fine amplitude int fine_amp; // The internal buffer - not really interesting block_t buffer; // The synchronisation signal - OK to look at it block_t synch;}stats_t;typedef struct { mmx_t *buffer; int *synch; int slot_length_chips; int stfa_id; int offset; int fine_pos; int fine_adj; SAMPLE_S12 *output;}private_t;/* * The initialisation function, or constructor, * is called the first time this module is instantiated. */int rcv_init( swr_sdb_t *context ) { // Definition of variables - don't touch if you're not an expert config_t *config; stats_t *stats; MOD_INC_USE_COUNT; if ( sizeof( private_t ) > 0 ) { 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 ); private->slot_length_chips = 0; private->buffer = NULL; private->synch = NULL; private->output = NULL; private->fine_pos = 0; private->stfa_id = config->stfa_id = -1; stats->buffer.data = 0; stats->buffer.size = 0; stats->buffer.type = SIG_SYMBOL_MMX; stats->synch.data = 0; stats->synch.size = 0; stats->synch.type = SIG_S32; stats->synch_pos = 0; stats->synch_amp = 0; stats->fine_pos = 0; stats->fine_amp = 0; config->fine_adj = 0; port_out(0).flags |= SWR_PORT_OWN_MALLOC; // Definition - don't touch swr_sdb_free_config_struct( context->id, (void**)&config ); swr_sdb_free_stats_struct( context->id, (void**)&stats ); return 0;}/* * Every time modules from the outside change the value of a configuration parameter, * this function is called. */int rcv_reconfig( swr_sdb_t *context ) { // Definition of variables - don't touch config_t *config; swr_sdb_get_config_struct( context->id, (void**)&config ); if ( config->stfa_id != private->stfa_id ) { private->stfa_id = config->stfa_id; if ( private->stfa_id >= 0 ) { private->offset = swr_sdb_get_config_int( private->stfa_id, "offset_chips_rcv" ); } } private->fine_adj = config->fine_adj; PR_DBG( 4, "(%i) reconfig: %p\n", context->id, port_in(0).data ); // Definition - don't touch swr_sdb_free_config_struct( context->id, (void**)&config ); return(0);}/* * Reconfigure outputs, abused to set up internal structures */int rcv_configure_outputs( swr_sdb_t *context ) { stats_t *stats; config_t *config; int len; swr_sdb_get_stats_struct( context->id, (void**)&stats ); swr_sdb_get_config_struct( context->id, (void**)&config ); if ( private->slot_length_chips != size_in(0) / DAQ_SAMPLES_PER_CHIP ) { if ( private->slot_length_chips ) { swr_free( private->buffer ); swr_free( private->synch ); swr_free( private->output ); } private->slot_length_chips = port_in(0).size / DAQ_SAMPLES_PER_CHIP; len = ( private->slot_length_chips + 240 ) * sizeof( SYMBOL_MMX ); private->buffer = swr_malloc( len ); memset( private->buffer, 0, len ); stats->buffer.data = private->buffer; stats->buffer.size = len / sizeof( SYMBOL_MMX ); len = private->slot_length_chips * sizeof( S32 ); private->synch = swr_malloc( len ); memset( private->synch, 0, len ); stats->synch.data = private->synch; stats->synch.size = len / sizeof( S32 ); // This is in order to offer some 'buffer-room' to the matched filter // before and after the actual slot, so as to simplify the filtering. len = 4 * ( private->slot_length_chips - SYNCH_PRIM_LENGTH_SYMBOLS ) + 2 * PRE_POST_LENGTH; private->output = swr_malloc( len * sizeof( SAMPLE_S12 ) ); port_out(0).data = private->output + PRE_POST_LENGTH; } // Output 0 size_out(0) = size_in(0) - SYNCH_PRIM_LENGTH_SAMPLES; PR_DBG( 4, "(%i) config-out: %p\n", context->id, port_in(0).data ); swr_sdb_free_config_struct( context->id, (void**)&config ); swr_sdb_free_stats_struct( context->id, (void**)&stats ); return 0;}/* * This is function that impements the `main method' of the class * Every calss has got just ONE method/working-mode. */int rcv_pdata( swr_sdb_t *context ) { // Definition of variables - don't touch stats_t *stats; config_t *config; int i, temp, slot_length, synch_pos, fine_pos = -1, fine_amp = 0, j, synch_amp, total_energy, other_peaks; S32 *synch; SYMBOL_MMX *in, *buffer, fine_mmx; SAMPLE_S12 *out, *in_s12; swr_sdb_get_config_struct( context->id, (void**)&config ); swr_sdb_free_config_struct( context->id, (void**)&config ); slot_length = private->slot_length_chips; buffer = &private->buffer[ 240 ]; synch = private->synch; in = buffer_in(0); // As total_energy is divided by SLOT_LENGTH_CHIPS and then used // as a divisor itself, it has to be at least 1!!! total_energy = slot_length; synch_amp = 0; synch_pos = -1; memcpy( private->buffer, &buffer[ slot_length - 240 ], 240 * sizeof( mmx_t ) ); for ( i=0; i<slot_length; i++ ) { movq_m2r(in[i],mm1); pxor_r2r(mm0,mm0); movq_m2r(in[i-1],mm2); psraw_i2r(8,mm1); psraw_i2r(8,mm2); paddsw_r2r(mm1,mm0); /* +1 */ movq_m2r(in[i-2],mm1); psubsw_r2r(mm2,mm0); /* -1 */ movq_m2r(in[i-3],mm2); psraw_i2r(8,mm1); psraw_i2r(8,mm2); psubsw_r2r(mm1,mm0); /* -1 */ movq_m2r(in[i-4],mm1); paddsw_r2r(mm2,mm0); /* +1 */ movq_m2r(in[i-5],mm2); psraw_i2r(8,mm1); psraw_i2r(8,mm2); psubsw_r2r(mm1,mm0); /* -1 */ movq_m2r(in[i-6],mm1); paddsw_r2r(mm2,mm0); /* +1 */ movq_m2r(in[i-7],mm2); psraw_i2r(8,mm1); psraw_i2r(8,mm2); psubsw_r2r(mm1,mm0); /* -1 */ movq_m2r(in[i-8],mm1); paddsw_r2r(mm2,mm0); /* +1 */ movq_m2r(in[i-9],mm2); psraw_i2r(8,mm1); psraw_i2r(8,mm2); psubsw_r2r(mm1,mm0); /* -1 */ movq_m2r(in[i-10],mm1); psubsw_r2r(mm2,mm0); /* -1 */ movq_m2r(in[i-11],mm2); psraw_i2r(8,mm1); psraw_i2r(8,mm2); paddsw_r2r(mm1,mm0); /* +1 */ movq_m2r(in[i-12],mm1); paddsw_r2r(mm2,mm0); /* +1 */ movq_m2r(in[i-13],mm2); psraw_i2r(8,mm1); psraw_i2r(8,mm2); paddsw_r2r(mm1,mm0); /* +1 */ movq_m2r(in[i-14],mm1); paddsw_r2r(mm2,mm0); /* +1 */ movq_m2r(in[i-15],mm2); psraw_i2r(8,mm1); psraw_i2r(8,mm2); paddsw_r2r(mm1,mm0); /* +1 */ paddsw_r2r(mm2,mm0); /* +1 */ movq_r2m(mm0,buffer[i]); pxor_r2r(mm3,mm3); movq_m2r(buffer[i-16],mm1); paddsw_r2r(mm0,mm3); /* +1 */ movq_m2r(buffer[i-32],mm2); paddsw_r2r(mm1,mm3); /* +1 */ movq_m2r(buffer[i-48],mm1); psubsw_r2r(mm2,mm3); /* -1 */ movq_m2r(buffer[i-64],mm2); paddsw_r2r(mm1,mm3); /* +1 */ movq_m2r(buffer[i-80],mm1); psubsw_r2r(mm2,mm3); /* -1 */ movq_m2r(buffer[i-96],mm2); paddsw_r2r(mm1,mm3); /* +1 */ movq_m2r(buffer[i-112],mm1); paddsw_r2r(mm2,mm3); /* +1 */ movq_m2r(buffer[i-128],mm2); paddsw_r2r(mm1,mm3); /* +1 */ movq_m2r(buffer[i-144],mm1); psubsw_r2r(mm2,mm3); /* -1 */ movq_m2r(buffer[i-160],mm2); psubsw_r2r(mm1,mm3); /* -1 */ movq_m2r(buffer[i-176],mm1); paddsw_r2r(mm2,mm3); /* +1 */ movq_m2r(buffer[i-192],mm2); psubsw_r2r(mm1,mm3); /* -1 */ movq_m2r(buffer[i-208],mm1); psubsw_r2r(mm2,mm3); /* -1 */ movq_m2r(buffer[i-224],mm2); paddsw_r2r(mm1,mm3); /* +1 */ movq_m2r(buffer[i-240],mm1); paddsw_r2r(mm2,mm3); /* +1 */ paddsw_r2r(mm1,mm3); /* +1 */ movq_r2m( mm3, fine_mmx ); pmaddwd_r2r(mm3,mm3); movq_r2r(mm3,mm1); psrlq_i2r(32,mm3); paddd_r2r(mm1,mm3); movd_r2m(mm3,temp); // synch[i] = (synch[i]*2 + temp)/3; synch[i] = temp; total_energy += temp; if (synch[i] > synch_amp) { synch_pos = i % slot_length; synch_amp = synch[i]; fine_amp = abs( fine_mmx.w[0] ); fine_pos = 0; for ( j=1; j<4; j++ ) { if ( abs( fine_mmx.w[j] ) > fine_amp ) { fine_amp = abs( fine_mmx.w[j] ); fine_pos = j; } } } } // Search for other, erroneous peaks for ( other_peaks = 0, i=0; i<slot_length; i++ ) { if ( synch[i] > synch_amp / 2 && synch_pos != i ){ // There is another peak with at least half the amplitude, // let's search further other_peaks++; } } total_energy /= slot_length; // One of these magic numbers... synch_pos -= SYNCH_PRIM_LENGTH_SYMBOLS - 1; if ( other_peaks > 10 ){ PR_DBG( 2, "Other_peaks: %i\n", other_peaks ); synch_pos = -slot_length / 2; synch_amp /= other_peaks * other_peaks; } emms(); // Perhaps we have to synchronise? if ( private->stfa_id >= 0 ) { if ( private->fine_adj ) { private->fine_pos += fine_pos; if ( private->fine_pos >= 4 ) { private->offset++; private->fine_pos -= 4; } swr_sdb_set_config_int( private->stfa_id, "offset_samples_rcv", private->fine_pos ); } private->offset += synch_pos; swr_sdb_set_config_int( private->stfa_id, "offset_chips_rcv", private->offset ); } // Copy the input-buffer to the output-buffer with omitting the middle out = buffer_out(0); if ( out ) { in_s12 = (SAMPLE_S12*)in; memcpy( private->output, in_s12 - PRE_POST_LENGTH + SYNCH_PRIM_LENGTH_SAMPLES, ( size_out(0) + 2 * PRE_POST_LENGTH ) * sizeof( SAMPLE_S12 ) ); } swr_sdb_get_stats_struct( context->id, (void**)&stats ); if ( synch_amp > ( 1 << 24 ) ) { PR_DBG( 3, "Synch amp is REALLY big: %i\n", synch_amp ); } stats->synch_amp = synch_amp; // To have synch_pos in chips stats->synch_pos = synch_pos; stats->fine_pos = fine_pos; stats->fine_amp = fine_amp; swr_sdb_free_stats_struct( context->id, (void**)&stats ); PR_DBG( 4, "Tot_energy: %i, synch_amp: %i, pos: %i, offset: %i\n", total_energy, synch_amp, synch_pos, private->offset ); return(0);}/* * This is the `destructor'. */int rcv_finalize( swr_sdb_t *context ) { swr_free( private->buffer ); swr_free( private->synch ); swr_free( private ); MOD_DEC_USE_COUNT; return(0);}/* * This function is called upon "insmod" and is used to register the * different parts of the module to the SPM. */swr_spc_id_t rcv_id;int rcv_module_init(void) { swr_spc_desc_t *desc; // Get a description-part from SPM // Give the following parameters: // In-ports, output-ports, config-params, stat-params desc = swr_spc_get_new_desc( 1, 1, 2, 6 ); if ( !desc ) { PR_DBG( 0, "Can't initialise the module. This is BAD!\n" ); return -1; } // Define the different parts of config and stats UM_CONFIG_INT( "stfa_id", PARAMETER_DEBUG ); UM_CONFIG_INT( "fine_adj", PARAMETER_DEBUG ); UM_STATS_INT( "synch_pos" ); UM_STATS_INT( "synch_amp" ); UM_STATS_INT( "fine_pos", PARAMETER_DEBUG ); UM_STATS_INT( "fine_amp", PARAMETER_DEBUG ); UM_STATS_BLOCK( "buffer", PARAMETER_DEBUG ); UM_STATS_BLOCK( "synch" ); UM_INPUT( SIG_SAMPLE_S12, 0 ); UM_OUTPUT( SIG_SAMPLE_S12, 0 ); // Initialise the callback-functions. NULL for not-used functions desc->fn_init = rcv_init; desc->fn_reconfigure = rcv_reconfig; desc->fn_process_data = rcv_pdata; desc->fn_finalize = rcv_finalize; desc->fn_configure_outputs = rcv_configure_outputs; // And register the module in the SPM rcv_id = swr_cdb_register_spc( &desc, "synch_rcv" ); if ( rcv_id == SWR_SPM_INVALID_ID ) { swr_spc_free_desc( desc ); PR_DBG( 0, "Couldn't register the module!\n" ); return 1; } PR_DBG( 4, "Ready to synch\n" ); return 0;}/* * This is called upon rmmod */void rcv_module_exit( void ) { PR_DBG( 4, "Freeing id: %i\n", rcv_id ); if ( swr_cdb_unregister_spc( rcv_id ) < 0 ) { PR_DBG( 0, "Still in use somewhere\n" ); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -