📄 convolution_send.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 + -