/**************************************************************************** * Configuration Module for the Real-time BBC Codec/Modem * **************************************************************************** * William L. Bahn * * Academy Center for Information Security * * Department of Computer Science * * United States Air Force Academy * * USAFA, CO 80840 * **************************************************************************** * FILE:............ config.c * * DATE CREATED:.... 03 SEP 07 * * DATE MODIFIED:... 03 SEP 07 * **************************************************************************** * * REVISION HISTORY * **************************************************************************** * * DESCRIPTION * * This module imports and manages the configuration information for the * modem and the codec. * */ //------------------------------------------------------------------------ // REQUIRED INCLUDES //------------------------------------------------------------------------ #include // malloc(), free() #include #include #include #include "config.h" #include "dirtyd.h" #define USRP_SAMPLE_SIZE (2*sizeof(float)) //------------------------------------------------------------------------ // STRUCTURE DEFINITIONS //------------------------------------------------------------------------ // NOTE: Normally the structure definition would be in the *.c file to make // the structure members inaccessible to outside functions except through // public function calls. But for the real-time code it has been decided // to make the structure members directly visible to the functions that // manipulate them. //------------------------------------------------------------------------ // PRIVATE FUNCTION DEFINITIONS //------------------------------------------------------------------------ // Nominal String: xxx"filename"xxxx // If both double quotes are not found, a NULL pointer is returned. char *ExtractName(char *s) { char *filename; char *t; int len; filename = NULL; // Advance s to first double quote or end of string while ((*s)&&('\"' != *s)) s++; // If double quote found, advance to next character if (*s) s++; // Advance t to next double quote or end of string for (t = s; (*t)&&('\"' != *t); t++) EMPTYLOOP; // Calculate length of string between first pair of double quotes len = t - s; t = filename = malloc(len + 1); if (filename) { while (len--) *t++ = *s++; *t = '\0'; } return filename; } // NOTE: The character string may me changed by this function. void UpdateConfig(CONFIG *c, char *string) { char *s, *v; DWORD vi; double vf; if ((!c)||(!string)) return; // Advance into string to first non-whitespace character for (s = string; isspace(*s); s++) EMPTYLOOP; // Ignore blank or comment lines if ((NUL == *s)||('#' == *s)) return; // Identify parameter keyword and convert to uppercase for (v = s; (*v) && (!((isspace(*v)) || (':' == *v) || ('=' == *v))); v++) *v = toupper(*v); // Terminate keyword and start value immediately after (if anything there) if (*v) *v++ = NUL; // Skip over whitespace, colons, and equal signs. while ( (isspace(*v)) || (':' == *v) || ('=' == *v) ) v++; // Process those parameters that use string values if (!strcmp(s, "SOURCE_NAME")) c->source_name = ExtractName(v); if (!strcmp(s, "SINK_NAME")) c->sink_name = ExtractName(v); // Process remaining parameters // Extract value from string vi = atoi(v); vf = atof(v); // SCHEDULER Configuration if (!strcmp(s, "DIAGNOSTICS")) c->diagnostics = TRUE; if (!strcmp(s, "SCHEDULER_TX_NOTRX")) c->scheduler_TX_notRX = vi; if (!strcmp(s, "SCHEDULER_REALTIME")) c->scheduler_realtime = vi; // SOURCE Configuration if (!strcmp(s, "SOURCE_ID")) c->source_id = vi; // SOURCE_NAME processed above due to string value // CODEC Configuration if (!strcmp(s, "CODEC_MESSAGE_BITS")) c->codec_message_bits = vi; if (!strcmp(s, "CODEC_RANDOM_BITS")) c->codec_random_bits = vi; if (!strcmp(s, "CODEC_CLAMP_BITS")) c->codec_clamp_bits = vi; if (!strcmp(s, "CODEC_FRAGMENT_BITS")) c->codec_fragment_bits = vi; if (!strcmp(s, "CODEC_STOP_BITS")) c->codec_stop_bits = vi; if (!strcmp(s, "CODEC_EXPANSION")) c->codec_expansion = vi; if (!strcmp(s, "CODEC_PACKET_LOAD")) c->codec_packet_load = vi; if (!strcmp(s, "CODEC_DECODE_LIMIT")) c->codec_decode_limit = vi; // BUFFER Configuration if (!strcmp(s, "BUFFER_PACKETS")) c->buffer_packets = vi; if (!strcmp(s, "BUFFER_LAMBDA")) c->buffer_lambda = vf; // MODEM Configuration if (!strcmp(s, "MODEM_PACKET_RATE_BPS")) c->modem_packet_rate_bps = vi; if (!strcmp(s, "MODEM_SAMPLES_PER_BIT")) c->modem_samples_per_bit = vi; if (!strcmp(s, "MODEM_GAIN_DB")) c->modem_gain_dB = vf; if (!strcmp(s, "MODEM_CHANNEL_LOSS_DB")) c->modem_channel_loss_dB = vf; if (!strcmp(s, "MODEM_THRESHOLD_PCT")) c->modem_threshold_pct = vf; if (!strcmp(s, "MODEM_HYSTERESIS_PCT")) c->modem_hysteresis_pct = vf; if (!strcmp(s, "MODEM_JITTER_BITS")) c->modem_jitter_bits = vf; if (!strcmp(s, "MODEM_CUSHION_PCT")) c->modem_cushion_pct = vf; // SINK Configuration // SOURCE_FILE_NAME processed above due to string value if (!strcmp(s, "SINK_SAMPLE_LIMIT")) c->sink_sample_limit = vi; } //------------------------------------------------------------------------ // PUBLIC FUNCTION DEFINITIONS //------------------------------------------------------------------------ CONFIG *CONFIG_Del(CONFIG *p) { if (p) { if (p->source_name) { free(p->source_name); p->source_name = NULL; } if (p->sink_name) { free(p->sink_name); p->sink_name = NULL; } free(p); p = NULL; } return p; } CONFIG *CONFIG_New(char *filename, DWORD *errcode) { CONFIG *p; FILE *fp; DWORD err; int i; char *s; p = NULL; err = 0; s = NULL; p = (CONFIG *) malloc(sizeof(CONFIG)); if (!p) err |= 1 << 0; if (!err) { //-------------------------------------------------------------------- // NOTE: Establish default values and then overwrite with file data //-------------------------------------------------------------------- p->diagnostics = FALSE; // Direction p->scheduler_TX_notRX = TRUE; p->scheduler_realtime = FALSE; // Source Parameters p->source_name = NULL; p->source_id = 0; // Codec Parameters p->codec_message_bits = 512; p->codec_random_bits = 0; p->codec_clamp_bits = 1; p->codec_fragment_bits = 1; p->codec_stop_bits = 100; p->codec_expansion = 100; p->codec_packet_load = 5; p->codec_decode_limit = 100; // Buffer Parameters p->buffer_packets = 2.0; p->buffer_lambda = 1.0; // Modem Parameters p->modem_packet_rate_bps = 500000; p->modem_cushion_pct = 10.0; p->modem_samples_per_bit = 4; p->modem_threshold_pct = 46.3744; p->modem_hysteresis_pct = 5.0; p->modem_gain_dB = 80.0; p->modem_channel_loss_dB = 3.0; p->modem_jitter_bits = 3.0; // Sink Parameters p->sink_name = NULL; p->sink_sample_limit = 0; p->sink_sample_size_bytes = 0; //-------------------------------------------------------------------- // Update values from configuration file //-------------------------------------------------------------------- if (filename) { fp = fopen(filename, "rt"); if (fp) { while (!feof(fp)) { s = fdgets(fp); UpdateConfig(p, s); if (s) free(s); s = NULL; } fclose(fp); } else err |= 1 << 1; } //-------------------------------------------------------------------- // Calculate derived parameters //-------------------------------------------------------------------- // bitmasks to mask bits within a byte. for (i = 0; i < 8; i++) p->bitmask[i] = ((BYTE) 1) << i; // Set USRP sample size to two floats (complex IQ) if (p->scheduler_TX_notRX) p->sink_sample_size_bytes = USRP_SAMPLE_SIZE; else p->source_sample_size_bytes = USRP_SAMPLE_SIZE; // Set sink sample limit if (!p->sink_sample_limit) { if (p->scheduler_TX_notRX) p->sink_sample_limit = 2000000; else p->sink_sample_limit = 1000; } // Set source filename to default if not set by config file if (!p->source_name) { if (p->scheduler_TX_notRX) { p->source_name = malloc(strlen("usrp.txd")+1); if (p->source_name) strcpy(p->source_name, "usrp.txd"); } else { p->source_name = malloc(strlen("usrp.srp")+1); if (p->source_name) strcpy(p->source_name, "usrp.srp"); } } // Set sink filename to default if not set by config file if (!p->sink_name) { if (p->scheduler_TX_notRX) { // Sink Parameters p->sink_name = malloc(strlen("usrp.srp")+1); if (p->sink_name) strcpy(p->sink_name, "usrp.srp"); } else { // Sink Parameters p->sink_name = malloc(strlen("usrp.rxd")+1); if (p->sink_name) strcpy(p->sink_name, "usrp.rxd"); } } // Calculate and store derived quantities p->bytes_per_message = p->codec_message_bits/8; if (p->bytes_per_message % 8) p->bytes_per_message++; p->packet_bits = (p->codec_message_bits * p->codec_expansion); p->last_packet_bit = p->packet_bits - 1; p->bytes_per_packet = p->packet_bits/8; if (p->bytes_per_packet % 8) p->bytes_per_packet++; p->bufferbytes_per_packet = p->bytes_per_packet + 1; p->buffer_advance = (DWORD) (p->bytes_per_packet * p->buffer_lambda); p->cushion_bits = (DWORD) (p->packet_bits * p->modem_cushion_pct / 100.0); p->nominal_tx_signal = pow(10.0, (p->modem_gain_dB)/20.0); p->nominal_rx_signal = pow(10.0, (p->modem_gain_dB - p->modem_channel_loss_dB)/20.0); // Compute storage requirments for BBC decode tree if ((0 == p->codec_clamp_bits)||(0 == p->codec_fragment_bits)) { p->codec_clamp_bits = 0; p->codec_fragment_bits = p->codec_random_bits + p->codec_message_bits; } p->fragments = (p->codec_random_bits + p->codec_message_bits)/p->codec_fragment_bits; p->padded_message_bits = p->fragments * (p->codec_clamp_bits + p->codec_fragment_bits); if ((p->codec_random_bits + p->codec_message_bits) % p->codec_fragment_bits) { p->padded_message_bits += p->codec_clamp_bits; p->padded_message_bits += (p->codec_random_bits + p->codec_message_bits)%p->codec_fragment_bits; } p->padded_message_bits += p->codec_stop_bits; //Lookup tables // 0 and 1 represented as BYTEs that can be passed by reference p->bitptr[0] = 0; p->bitptr[1] = 1; // Tally counters; p->message_count = 0; // State information p->marks = 0; // Tally Counters p->actual_trx_bytes = 0; p->nominal_trx_bytes = 0; p->dem_ticks = 0; p->dec_ticks = 0; p->ticks = 0; p->tot_ticks = 0; p->trx_bytes_per_packet_byte = 8 * p->modem_samples_per_bit * USRP_SAMPLE_SIZE; p->bytespertick = ( p->modem_packet_rate_bps * p->modem_samples_per_bit * USRP_SAMPLE_SIZE ) / ((double)CLOCKS_PER_SEC); } if (err) p = CONFIG_Del(p); *errcode = err; return p; } //------------------------------------------------------------------------