📄 sch_send.c
字号:
/**************************************************************************** sch_send.c - Send the System CHannel* -------------------* begin : 2003-03-19* authors : ineiti* emails : linus.gasser@epfl.ch***************************************************************************//**************************************************************************** Changes* -------* date - name - description* 03/04/25 - ineiti - changed target_peak to target_snr* 04/03/02 - ineiti - adjusted gain_adj to reflect the difference of the* target and the actual gain* 04/03/05 - ineiti - adjusted description***************************************************************************//**************************************************************************** ** 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. ** ****************************************************************************//** * In general, it builds a big structure that is sent over the first slot * in a frame. It is also used to tell the clients about the strength of the * signal to be sent. * If there is not enough to send the whole data_usr block through the * slot, it will be truncated and a message will appear in the logs. */#include "spc.h"#include "sch.h"#include "std.h"#include <math.h>#define DBG_LVL 0#define MAX_MID_AMP 10240typedef struct { // the client's id int id[ MAX_CLIENTS ]; // -1 // a bit-field of the uplinks for the clients int uplinks[ MAX_CLIENTS ]; // 0 // a bit-field of the downlinks for the clients int downlinks[ MAX_CLIENTS ]; // 0 // one matched-filter from an uplink that will be used for // gain-control int mafi[ MAX_CLIENTS ]; // -1 // the target snr that the BS tries to achieve by telling // the MS to increase it's sending gain double target_snr[ MAX_CLIENTS ]; // 10 // below this peak-level the client is considered to // be missing int minimum_peak[ MAX_CLIENTS ]; // 150 // is a pointer to a block of data that will be sent along void *data_usr; // NULL // is the length in bytes of the data_usr block int len_usr; // 0}config_t;typedef struct {}stats_t;typedef struct { struct sch_data_t data; void *data_usr; int len_usr;}private_t;/* * The initialisation function, or constructor, * is called the first time this module is instantiated. */int send_init( swr_sdb_t *context ) { // Begin system-definitions { config_t *config; stats_t *stats; int i; 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 ); // } End of system-definitions for ( i=0; i<MAX_CLIENTS; i++ ) { config->id[i] = -1; config->uplinks[i] = 0; config->downlinks[i] = 0; config->mafi[i] = -1; config->target_snr[i] = 10; config->minimum_peak[i] = 150;#ifdef USER_SPACE private->data.client[i].gain = 0.;#else private->data.client[i].gain = -60.;#endif } config->data_usr = NULL; config->len_usr = 0; // Begin system-definitions swr_sdb_free_stats_struct( context->id, (void**)&stats ); swr_sdb_free_config_struct( context->id, (void**)&config ); return 0; // End system-definitions}/* * Every time modules from the outside change the value of a configuration parameter, * this function is called. */int send_reconfig( swr_sdb_t *context ) { // Definition of variables - don't touch config_t *config; int i; swr_sdb_get_config_struct( context->id, (void**)&config ); for ( i=0; i<MAX_CLIENTS; i++ ) { private->data.client[i].id = config->id[i]; private->data.client[i].uplinks = config->uplinks[i]; private->data.client[i].downlinks = config->downlinks[i]; } private->data_usr = config->data_usr; private->data.len_usr = config->len_usr; // Definition - don't touch swr_sdb_free_config_struct( context->id, (void**)&config ); return 0;}/* * This is the function that implements the `main method' of the class * Every class has got just ONE method/working-mode. */int send_pdata( swr_sdb_t *context ) { // Definition of variables - don't touch stats_t *stats; config_t *config; U8 *out; double gain_adj, snr; int i, mid_amp, peak_amp, size_data = sizeof( struct sch_data_t ); // Check for the output-size if ( size_out(0) < size_data ) { PR_DBG( 0, "Output-size is not sufficient to hold the data!\n" ); return -1; } if ( size_out(0) < size_data + private->data.len_usr ) { private->data.len_usr = size_out(0) - size_data; PR_DBG( 0, "Correcting len_usr to %i\n", private->data.len_usr ); } // Look whether we have to do some power-control swr_sdb_get_config_struct( context->id, (void**)&config ); for ( i=0; i<MAX_CLIENTS; i++ ) { if ( config->mafi[i] >= 0 ) { // OK, we have a matched-filter responsible for this mobile... mid_amp = swr_sdb_get_stats_int( config->mafi[i], "mid_amp" ); peak_amp = swr_sdb_get_stats_int( config->mafi[i], "peak_amp" ); snr = swr_sdb_get_stats_double( config->mafi[i], "snr" ); PR_DBG( 4, "peak_amp: %i, snr: %g, target: %g\n", peak_amp, snr, config->target_snr[i] ); if ( peak_amp > config->minimum_peak[i] ) { gain_adj = abs( snr - config->target_snr[i] ) / 10; gain_adj = max( gain_adj, .1 ); // Only do gain-control from a certain point if ( ( snr < config->target_snr[i] ) && ( mid_amp < MAX_MID_AMP ) ) { private->data.client[i].gain = private->data.client[i].gain + gain_adj; // If it's bigger than 100, we suppose nobody's there, and we start at // the bottom, again if ( private->data.client[i].gain > 200 ){ private->data.client[i].gain = -200; } PR_DBG( 4, "Increased gain to %s%i.%i\n", swr_ftosii( private->data.client[i].gain ) ); } else { private->data.client[i].gain = max( private->data.client[i].gain - gain_adj, (double)-300 ); PR_DBG( 4, "Decreased gain to %s%i.%i\n", swr_ftosii( private->data.client[i].gain ) ); } } } } swr_sdb_free_config_struct( context->id, (void**)&config ); out = buffer_out( 0 ); // Add the system-data *((U32*)out) = swr_crc32( &private->data, size_data ); out += sizeof( U32 ); memcpy( out, &private->data, size_data ); out += size_data; *((U32*)out) = swr_crc32( private->data_usr, private->data.len_usr ); out += sizeof( U32 ); memcpy( out, private->data_usr, private->data.len_usr ); swr_sdb_get_stats_struct( context->id, (void**)&stats ); // Put your code here // ADD HERE swr_sdb_free_stats_struct( context->id, (void**)&stats ); return(0);}/** * User messages */int send_custom_msg( swr_sdb_t *context, swr_usr_msg_t *data, swr_msgq ret ) { send_pdata( context ); return 0;}/* * This is the `destructor'. */int send_finalize( swr_sdb_t *context ) { if ( sizeof( private_t ) > 0 ) 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 send_id;int send_module_init(void) { swr_spc_desc_t *desc; int i; char str[16]; /** * Get a description-part from SPM * Give the following parameters: * Input-ports, output-ports, config-params, stat-params */ desc = swr_spc_get_new_desc( 0, 1, MAX_CLIENTS * 6 + 2, 0 ); if ( !desc ) { PR_DBG( 0, "Can't initialise the module. This is BAD!\n" ); return -1; } /** * Define the different parts of config and stats. You have to define * them in the same order as they appear in the structures. The names * can be freely chosen. * * UM_CONFIG_{INT,DOUBLE,STRING128,POINTER}( "name" ); * UM_STATS_{INT,DOUBLE,STRING128,POINTER,BLOCK}( "name" ); */ for ( i=0; i<MAX_CLIENTS; i++ ) { sprintf( str, "id%i", i ); UM_CONFIG_INT( str, PARAMETER_DEBUG ); } for ( i=0; i<MAX_CLIENTS; i++ ) { sprintf( str, "uplinks%i", i ); UM_CONFIG_INT( str, PARAMETER_DEBUG ); } for ( i=0; i<MAX_CLIENTS; i++ ) { sprintf( str, "downlinks%i", i ); UM_CONFIG_INT( str, PARAMETER_DEBUG ); } for ( i=0; i<MAX_CLIENTS; i++ ) { sprintf( str, "mafi%i", i ); UM_CONFIG_INT( str, PARAMETER_DEBUG ); } for ( i=0; i<MAX_CLIENTS; i++ ) { sprintf( str, "target_snr%i", i ); UM_CONFIG_DOUBLE( str ); } for ( i=0; i<MAX_CLIENTS; i++ ) { sprintf( str, "minimum_peak%i", i ); UM_CONFIG_INT( str, PARAMETER_DEBUG ); } UM_CONFIG_POINTER( "data_usr", PARAMETER_DEBUG ); UM_CONFIG_INT( "len_usr", PARAMETER_DEBUG ); /** * The in- and outputs have also to be defined in the right order. First * port first. The additional flag is not used yet, but it will... * * UM_INPUT( SIG_{U8,SYMBOL_{S16,COMPLEX,MMX},SAMPLE_S12,S32}, 0 ); * UM_OUTPUT( SIG_{U8,SYMBOL_{S16,COMPLEX,MMX},SAMPLE_S12,S32}, 0 ); */ UM_OUTPUT( SIG_U8, 0 ); // Initialise the callback-functions. Delete the ones you don't use desc->fn_init = send_init; desc->fn_reconfigure = send_reconfig; desc->fn_process_data = send_pdata; desc->fn_custom_msg = send_custom_msg; desc->fn_finalize = send_finalize; // And register the module in the SPM. Change the name! send_id = swr_cdb_register_spc( &desc, "sch_send" ); if ( send_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\n" ); return 0;}/* * This is called upon rmmod */void send_module_exit( void ) { PR_DBG( 4, "Freeing id: %i\n", send_id ); 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 + -