/**************************************************************************** * Data Source 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:............ source.c * * DATE CREATED:.... 08 SEP 07 * * DATE MODIFIED:... 08 SEP 07 * **************************************************************************** * * REVISION HISTORY * **************************************************************************** * * DESCRIPTION * * This module supports the data source for both the TX and the RX. * */ //------------------------------------------------------------------------ // REQUIRED INCLUDES //------------------------------------------------------------------------ #include // memmove() #include // malloc(), free() #include "bbcftp.h" #include "source.h" #include "dirtyd.h" //------------------------------------------------------------------------ // 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. //------------------------------------------------------------------------ // PUBLIC FUNCTION DEFINITIONS //------------------------------------------------------------------------ SOURCE *SOURCE_Del(SOURCE *p) { if (p) { if (p->v) { free(p->v); p->v = NULL; } free(p); p = NULL; } return p; } /* * Eventually the source and sink will be Gnu Radio and therefore very * little effort has been made to make this temporary source flexible * or sophisticated. The SOURCE_New() function opens the source file, * allocated memory for the entire contents, loads the entire contents * into memory, and then closes the source file. * * TX: If configured as a transmitter, the data file is assumed to be a * binary file that is to be transmitted across a BBC link. The file * is brought up into memory as a series of messages using the following * format: * * [Checksum] [SeqNum] [DataBits] [Data] * * The sequence number is a 16-bit number starting at 0 and incrementing * by one for each packet. The length field is also a 16-bit number that * contains the number of bits of actual data follows. The data field * contains a string of bits read directly from the file being transmitted. * It is a fixed width field and is zero padded if necessary. The checksum * field is the last 32-bits of the message and contains a CRC checksum for * message up to, but not including, the checksum field. At the present time, * the checksum field is set to all zeros. * */ DWORD SOURCE_NewTX(SOURCE *p, CONFIG *c) { DWORD err; FILE *fp; BYTE *base; DWORD bytes_read; WORD seqnum, loadbits, id, length; BYTE *buffer; err = 0; // Initialize state information p->streaming = TRUE; p->sample = 0; p->samples = 0; // Data Source fp = NULL; if (c->source_name) { fp = fopen(c->source_name, "rb"); if (!fp) err |= 1 << 7; } // Create Data Read Buffer if (fp) { // Determine the size of the file fseek(fp, 0, SEEK_END); p->file_bytes = ftell(fp); fseek(fp, 0, SEEK_SET); // How much memory each message needs in the Source Buffer p->sample_size_bytes = c->bytes_per_message; // Determine if each message can carry at least one file byte. if ( !((c->codec_message_bits/8) > BBC_FTP_HEADER_BYTES) ) err |= 1 << 4; } if (!err) { // Calculate how many bytes of the file each message can hold. p->chunk_size = (c->codec_message_bits/8) - BBC_FTP_HEADER_BYTES; // File bytes per message p->sample_limit = p->file_bytes / p->chunk_size; // Messages needed for whole chunks if ( p->file_bytes % p->chunk_size ) // Plus one for any partial chunk p->sample_limit++; p->sample_limit+=2; // Plus one each for header/trailer p->buffer_size = p->sample_limit * p->sample_size_bytes; if (p->buffer_size) p->v = malloc(p->buffer_size); else err |= 1 << 2; if (!p->v) err |= 1 << 3; buffer = malloc(p->chunk_size); if (!buffer) err |= 1 << 5; } // Fill Data Buffer if (!err) { p->samples = 0; id = c->source_id; seqnum = 0; bytes_read = 0; do { base = p->v + p->samples * p->sample_size_bytes; length = p->chunk_size; if ((p->file_bytes - bytes_read) <= length) length = p->file_bytes - bytes_read; if (seqnum) { if (length) length = fread(buffer, 1, length, fp); SetMessagePayload(base, buffer, length, 0); bytes_read += length; } else { length = strlen(c->source_name); if (length > p->chunk_size) length = p->chunk_size; SetMessagePayload(base, c->source_name, length, 0); } loadbits = 8 * length; SetMessageChecksum(base, 0); // Force checksum to zero (temporary convenience) SetMessageSeq(base, seqnum); SetMessageLoadBits(base, loadbits); SetMessageID(base, c->source_id); seqnum++; if (c->diagnostics) PrintMessage(base); p->samples++; } while (length); fclose(fp); fp = NULL; } return err; } DWORD SOURCE_NewRX(SOURCE *p, CONFIG *c) { DWORD err; FILE *fp; err = 0; // Initialize state information p->streaming = TRUE; p->samples = 0; // Data Source fp = NULL; if (c->source_name) { fp = fopen(c->source_name, "rb"); if (!fp) err |= 1 << 7; } // Create Data Read Buffer if (fp) { // Determine the size of the file fseek(fp, 0, SEEK_END); p->file_bytes = ftell(fp); fseek(fp, 0, SEEK_SET); p->sample_size_bytes = c->source_sample_size_bytes; // Determine number of complete samples in data file p->sample_limit = p->file_bytes / p->sample_size_bytes; // Adjust sample limit if initialization file sets a lower limit if ((c->source_sample_limit)&&(p->sample_limit > c->source_sample_limit)) p->sample_limit = c->source_sample_limit; p->buffer_size = p->sample_limit * p->sample_size_bytes; if (p->buffer_size) p->v = malloc(p->buffer_size); else err |= 1 << 2; if (!p->v) err |= 1 << 3; } // Fill Data Buffer if (!err) { p->sample_limit = fread(p->v, p->sample_size_bytes, p->sample_limit, fp); fclose(fp); fp = NULL; } return err; } SOURCE *SOURCE_New(CONFIG *c, DWORD *errcode) { DWORD err; SOURCE *p; p = NULL; err = 0; p = (SOURCE *) malloc(sizeof(SOURCE)); if (!p) err |= 1 << 0; if (!err) if (c->scheduler_TX_notRX) err = SOURCE_NewTX(p, c); else err = SOURCE_NewRX(p, c); if (c->diagnostics) { // Diagnostic Report printf("------------------------------------------\n"); if (c->scheduler_TX_notRX) printf("MESSAGE SOURCE\n"); else printf("USRP SOURCE\n"); printf(" File name:.............. %s\n", c->source_name); printf(" Creation:............... %s\n", ((err)? "FAILED":"SUCCEEDED")); printf(" Location:............... %p\n", (void *) p); printf(" File size:.............. %lu bytes\n", (unsigned long) p->file_bytes); printf(" Chunk size:............. %lu bytes\n", (unsigned long) p->chunk_size); printf(" Messages needed:........ %lu\n", (unsigned long) p->sample_limit); printf(" Message requirements:... %lu bytes\n", (unsigned long) p->sample_size_bytes); printf(" Buffer size:............ %lu bytes\n", (unsigned long) p->buffer_size); printf(" Buffer location:........ %p\n", (void *) p->v); printf("------------------------------------------\n"); } if (err) SOURCE_Del(p); *errcode = err; return p; } /* DWORD SOURCE_Run(BBCFTP *sys) { // Load another block of data from the file if possible. while ( (sys->source->fp) && (sys->source->input_fifo_bytes <= sys->config->file_block_size) ) { bytes_read = fread(sys->source->input_fifo + sys->source->fifo_write, 1, sys->config->file_block_size, sys->source->fp); sys->source->input_fifo_bytes += bytes_read; sys->source->input_fifo_write = (sys->source->input_fifo_write + bytes_read) & (sys->config->input_fifo_mask); if (bytes_read < sys->config->file_block_size) { fclose(sys->source->fp); sys->source->fp = NULL; } } // Process as much data from input FIFO to output FIFO as possible if( (sys->source->input_fifo_bytes > sys->source->input_chunk_size) && (sys->source->output_fifo_items < sys->source->output_fifo_size) ) { // Process a chunk of data if (sys->config->scheduler_TX_notRX) { // Prepare a message for encoding } else { // Transfer raw USRP data for demodulation } sys->source->input_fifo_bytes -= sys->source->input_chunk_size; sys->source->input_fifo_read = (sys->source->input_fifo_bytes + sys->source->input_chunk_size) & (sys->config->input_fifo_mask); sys->source->output_fifo_items++; sys->source->output_fifo_write = (sys->source->output_fifo_write + sys->source->output_chunk_size) & (sys->config->output_fifo_mask); } // Determine if source can no longer stream data to its successor if (!sys->source->fp) if (sys->source->input_fifo_bytes < sys->source->input_chunk_size) if (0 == sys->source->output_fifo_items) sys->source->streaming = FALSE; return 0; } */ //------------------------------------------------------------------------