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

📄 convolution_send.c

📁 This a framework to test new ideas in transmission technology. Actual development is a LDPC-coder in
💻 C
字号:
/*************************************************************************** *    _send.c  -  Software Radio convolutional encoder module ***************************************************************************//*************************************************************************** *                                                                         * *   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.                                   * *                                                                         * ***************************************************************************//** * For description also refer to convolution.c * * This module is the sender part (encoder) of the convolution code. * Data blocks are coded independently, i.e. the registers are flushed after each block. * * Besides the configuration parameters described in convolution.c, the * following decoder specific parameters must be set: * NO SPECIFIC CONFIG */#include "math.h"#include "spc.h"#include "library.h"#define DBG_LVL 0typedef struct {  // The number of output bits (output bits per input bit)  int n; // 2  // The number of input bits (number of input bits to generate n output bits)  int k; // 1  // Number of memory registers used  // (limited to 32 because of use of unsigned int to define a state)  int m; // 8  /**  * array of polynome-definitions.   * The array has length n, and holds one REG_STATUS value for each polynome.   * The bits of a value define if this term should be added to the result or not.   * Of each value, only the m LSB are relevant. All others should be set to 0.   * Be aware that the LSB (bit 0) represents the term d^m,   * while the bit m represent the term d^0.   * E.g. A polynome which calculates the result as the latest, 4th latest and  * the 5th latest bits  * p=1+d^3+d^4 has value=0b00000000 00000000 00000000 00011001 = 0x000000019  */  REG_STATUS *polys; // 0x37, 0x73}config_t;typedef struct {}stats_t;typedef struct {  //copy of config->n  int n;  //copy of config->k  int k;  //copy of config->m  int m;  //copy of config->polys. Not only the pointer but the full array is copied  REG_STATUS *polys;  //will contain 1's in its m LSB, 0's otherwise  REG_STATUS regstatMask;  //contains the current register status  REG_STATUS regstat;  //index to currently processed byte  int inByteCounter;  //currently processed byte (only unconsumedBits are valid)  //This byte is copied from in buffer because it will be modified during processing  U8 inByte;  //Number of unprocessed bits in inByte (Bit0 is processed first)  int unconsumedBits;  //refers to the byte in out which is currently written  int outByteCounter;  //number of bits left in currently written out-byte  int outBitsLeft;}private_t;REG_STATUS default_polys_send[]={0x37,0x73};/* * 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;  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  //Init to null for memory management  private->polys=NULL;  //init default values  config->n=2;  config->k=1;  config->m=8;  config->polys=default_polys_send;  // 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}/* * To configure the inputs * this is called when the output-sizes change. */int send_configure_inputs( swr_sdb_t *context ) {  // Definition of variables - don't touch  config_t *config;  double in=size_out( 0 )*8;  swr_sdb_get_config_struct( context->id, (void**)&config );  //In-length in bits Li = ((Lo/n) - m) * k  //Where Lo is output-length in bits.  in/=config->n;  in-=config->m;  in*=config->k;  //convert to bytes. Trunc down because with given output size fewer input bits can be processed  in/=8;  size_in( 0 ) = floor(in);  // Definition - don't touch  swr_sdb_free_config_struct( context->id, (void**)&config );  return 0;}/* * To configure the outputs * this is called when the input-sizes change */int send_configure_outputs( swr_sdb_t *context ) {  // Definition of variables - don't touch  config_t *config;  double out=size_in(0)*8;  swr_sdb_get_config_struct( context->id, (void**)&config );  //Out-length in bits Lo = ((Li/k) + m)*n  //Where Li is input-length in bits.  out/=config->k;  out+=config->m;  out*=config->n;  //convert to bytes. Need a little more output if byte is not enough  out/=8;  size_out(0) = ceil(out);  // Definition - don't touch  swr_sdb_free_config_struct( context->id, (void**)&config );  return 0;}/* * 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 );  //copy configs to private  private->n=config->n;  private->k=config->k;  private->m=config->m;  //copy the polynomes  if (private->polys) {    swr_free(private->polys);  }  private->polys=swr_malloc(private->n*sizeof(REG_STATUS));  memcpy(private->polys,config->polys,private->n*sizeof(REG_STATUS));  //init regstatmask  private->regstatMask=0x00;  for (i=0;i<private->m;i++)    private->regstatMask=(private->regstatMask << 1) | 0x01;  // Definition - don't touch  swr_sdb_free_config_struct( context->id, (void**)&config );  return 0;}/*** Read k bits into the private->regstat, shifting current content to the right* If in is fully read, use an empty flush-byte instead* @param in The data byte array to read from*/void send_readBits(swr_sdb_t *context,U8* in) {  int bitsToRead=private->k;  int consumeNow;  REG_STATUS newData;  while (bitsToRead>0) {    //if all bits were consumed in inByte, read another one    if (private->unconsumedBits == 0) {      if (private->inByteCounter < size_in(0)) {        //There is still some data available. read it        private->inByte = in[private->inByteCounter++];      } else {        //Data is fully processed. Use 0's for flushing        private->inByte=0;      }      PR_DBG(1,"Encoding byte %x\n",private->inByte);      private->unconsumedBits=8;    }    //Calculate number of bits to read in this iteration    //=min(bitsToNextOut,unConsumedBits) because    consumeNow = (bitsToRead<=private->unconsumedBits) ? bitsToRead : private->unconsumedBits;    //Shift register to right (make space for new bits)    private->regstat >>= consumeNow;    newData=private->inByte;    //Shift new byte to top    newData<<=private->m-consumeNow;    //Mask those bits which are not relevant (only let m bits survive)    newData&=private->regstatMask;    //and put to regstat (into newly created space)    private->regstat|=newData;    //remove now processed bits from inByte    private->inByte>>=consumeNow;    //and decrease counters    private->unconsumedBits-=consumeNow;    bitsToRead-=consumeNow;  }}/*** write n bits to out, applying n polynomes onto the register.* @param out The data buffer to which to write the encoded data*/void send_writeBits(swr_sdb_t *context,U8* out) {  //actually write n output bits  int i;  int ctr;  REG_STATUS adder;  for (i=0 ; i < private->n ; i++) {    //(check outByteCounter if out-buffer is too small    //(shouldnt happen, is always required size or a little bigger)    if (private->outByteCounter>= size_out(0)) {      PR_DBG( 1, "ERROR: cant send because outputbuffer too small. "              "Truncating, invalid data.\n");      return;    }    adder = private->polys[i] & private->regstat;    PR_DBG( 4, "writing regstat %x out with polynome %x (anding results in %x)\n",            private->regstat,            private->polys[i],            adder);    //if adder contains odd number of 1's, output a 1, otherwise output a 0 (==modulo2 adder)    //counts the 1's    ctr = countOnes(adder,private->m);    //make space for one bit in outByte    out[private->outByteCounter]>>=1;    if (ctr%2==1) {      //an odd number of 1's was found ==> put a 1 to output      out[private->outByteCounter]|=0x80;    }    //a bit was used in the outByte    private->outBitsLeft--;    if (private->outBitsLeft==0) {      //all bits in outByte used. Try next one      PR_DBG( 4, "Writ outb: %x\n",out[private->outByteCounter]);      private->outByteCounter++;      private->outBitsLeft=8;    }  }}/* * 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;  U8 *in;  int i;  PR_DBG( 4, "start send_pdata\n");  in = buffer_in(0);	//Buffer of U8  out = buffer_out(0);	//Buffer of U8  //init the out-array to 0 to be sure  for (i=0;i<size_out(0);i++) {    out[i]=0x00;  }  //Init the registers to all-zero (slot-start)  private->regstat=0x00;  swr_sdb_get_config_struct( context->id, (void**)&config );  swr_sdb_free_config_struct( context->id, (void**)&config );  PR_DBG( 3, "executing convolution on %d input-U8's\n",size_in(0));  PR_DBG( 3, "having %d output-U8's\n",size_out(0));  //Now iterate all the inputs, k-bit-wise  //every k bits, extract n bits to the output  private->inByteCounter=0;  private->unconsumedBits=0;  //bits in out-value which are still empty  private->outBitsLeft=8;  //counter for written out-values  private->outByteCounter=0;  PR_DBG( 4, "outByteCounter is %d, size_out(0) is %d\n",private->outByteCounter,size_out(0));  //write until the out array is full  //(using empty flush bytes if in-buffer does not provide enough data)  //If out-slot provides more space than needed, it will be filled with flushed bytes.  //If out-slot provides less space than needed, data will be truncated  while(private->outByteCounter<size_out(0)) {    PR_DBG( 4, "outByteCounter is %d\n",private->outByteCounter);    send_readBits(context,in);    //write n output bits    send_writeBits(context,out);  }  swr_sdb_get_stats_struct( context->id, (void**)&stats );  swr_sdb_free_stats_struct( context->id, (void**)&stats );  PR_DBG( 4, "end send_pdata\n");  return(0);}/** * User messages */int send_custom_msg( swr_sdb_t *context, swr_usr_msg_t *data, swr_msgq ret ) {  return 0;}/* * This is the `destructor'. */int send_finalize( swr_sdb_t *context ) {  if (private->polys) {    swr_free(private->polys);  }  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;  /**   * Get a description-part from SPM   * Give the following parameters:   * Input-ports, output-ports, config-params, stat-params   */  desc = swr_spc_get_new_desc( 1, 1, 4, 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,DOUBLE_COMPLEX,STRING128,POINTER}( "name" );   * UM_STATS_{INT,DOUBLE,DOUBLE_COMPLEX,STRING128,POINTER,BLOCK,IMAGE}( "name" );   */  UM_CONFIG_INT( "cfg_n" );  UM_CONFIG_INT( "cfg_k" );  UM_CONFIG_INT( "cfg_m" );  UM_CONFIG_POINTER( "cfg_polys" );  /**   * 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,DOUBLE_{,COMPLEX}}, 0 );   * UM_OUTPUT( SIG_{U8,SYMBOL_{S16,COMPLEX,MMX},SAMPLE_S12,S32,DOUBLE_{,COMPLEX}}, 0 );   */  //SIG_U8 is what sources, e.g. random generate  UM_INPUT( SIG_U8, 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_configure_inputs  = send_configure_inputs;  desc->fn_configure_outputs = send_configure_outputs;  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, "convolution_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 + -