/**************************************************************************** * Main TX/RX 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:............ usrp.c * * DATE CREATED:.... 03 SEP 07 * * DATE MODIFIED:... 08 SEP 07 * **************************************************************************** * * REVISION HISTORY * **************************************************************************** * * DESCRIPTION * * This program implements a simple file transfer protocol using a BBC-encoded * data channel. Since the purpose of this code is to implement only specific * real-time components, and not all of them, the data source and sinks are * kept very simple. In particular, the transmitter reads the entire file into * memory, formatted as a series of BBC messages, before transmission begins * and, similarly, the receiver stores all of the received messages into memory * before dumping them to disk all at once. This is opposed to the streaming * source and sink modules that will be typical of the complete real-time * implementation. * * The basic, high-level, flow is as follows: * * TX: The Transmitter * * The transmitter uses the following signal flow: * * SOURCE -> ENCODER -> BUFFER -> MODULATOR -> SINK * * * T * RX: The Receiver * * The receiver used the following signal flow * * SOURCE -> MODEM -> BUFFER -> CODEC -> SINK * * //-------------------------------------------------------------------- * the module supports both the transmitter and recevier functions. * * */ /* Real-time BBC CODEC * * This program is designed to process the raw USRP output data and decode * the resulting packets in real-time in a streaming fashion. Since it is * a real-time application, structural overhead has been minimized and * global variables have been used extensively. * * THE DATA BUFFER * * The data is stored in a circular buffer with the following variables: * buffer: Pointer to the block of memory where the buffer starts. * read: Index of the first byte of the present packet. * write: Index of the next unused buffer location. * fill: How many bytes are in buffer beyond the scope of the CODEC. * unused: How many unused bytes are available in the buffer. * * The buffer is seen by two functions, the one that is demodulating the * data packet and the one that is decoding the resulting data. The * demodulating function writes to the buffer at a nominally constant * rate dictated by the communications link. In this application, this is * simulated by reading the stored waveform data from a file and querying * the clock to determine how many bytes to add to the buffer each time * the function is called. The decoding function, on the other hand, always * to decodes eight packets each time it is called provided sufficient data * is available. Specifically, it decodes the eight packets that start with * the bits in the byte stored at the "read" pointer. Since it can't decode * packets that are not completely contained in the buffer, the decoding * function first checks to see if "fill" is non-negative. If it isn't, then * it returns immediately. At the other end of the spectrum, the MODEM * may run out of unused memory to write to. If this happens, data is going * to be lost. It is cleaner to throw away old data instead of introducing * a gap in present data, therefore the MODEM will push the "read" * pointer forward as it overwrites the beginning of the existing packet * data. * */ //------------------------------------------------------------------------ // FILE INCLUSIONS //------------------------------------------------------------------------ #include // printf() #include // exit(), EXIT_SUCCESS, EXIT_FAILURE #include // clock(), CLOCKS_PER_SEC #include "bbcftp.h" #include "config.h" #include "source.h" #include "codec.h" #include "buffer.h" #include "modem.h" #include "sink.h" //------------------------------------------------------------------------ // TRANSMITTER //------------------------------------------------------------------------ int tx(BBCFTP *sys) { int state; //-------------------------------------------------------------------- // Runtime scheduler //-------------------------------------------------------------------- state = 0; sys->config->tot_ticks = clock(); while ( (sys->sink->streaming) && ( sys->source->streaming || sys->buffer->ready ) ) { switch (state) { case 0: // Scheduler if ( (sys->sink->streaming) && (sys->config->actual_trx_bytes < sys->config->nominal_trx_bytes) ) { state = 1; // Run MODEM until sampling is caught up } else if ((sys->source->streaming) &&(0 <= sys->buffer->margin)) { state = 2; // Encode packets subject to maximum amount of time. } else { if (sys->config->scheduler_realtime) sys->config->nominal_trx_bytes = (DWORD) ((clock() - sys->config->tot_ticks) * sys->config->bytespertick); else sys->config->nominal_trx_bytes += 1;//(DWORD) (config->bytespertick); } break; case 1: // Modulator if (sys->buffer->ready == 1000) state = 100; if (sys->buffer->ready == 100) state = 10; if (sys->buffer->ready == 10) state = 1; if (sys->buffer->ready == 1) state = 1; if (sys->buffer->ready == 0) state = 0; Modulate(sys->config, sys->buffer, sys->modem, sys->sink); state = 0; break; case 2: // Encoder Encode(sys->config, sys->source, sys->codec, sys->buffer); if (!sys->source->streaming) state = 100; state = 0; break; } } sys->config->tot_ticks = clock() - sys->config->tot_ticks; //-------------------------------------------------------------------- // POST RUN CODE //-------------------------------------------------------------------- printf("\n"); printf("Marks: %li\n", sys->config->marks); printf("Total time:........... %0.3f sec.\n", ( (double)sys->config->tot_ticks / (double)CLOCKS_PER_SEC )); printf("MODEM time:........... %0.3f sec.\n", ( (double)sys->config->dem_ticks / (double)CLOCKS_PER_SEC )); printf("CODEC time:........... %0.3f sec.\n", ( (double)sys->config->dec_ticks / (double)CLOCKS_PER_SEC )); SINK_Purge(sys->config, sys->sink); return EXIT_SUCCESS; } //------------------------------------------------------------------------ // RECEVIER //------------------------------------------------------------------------ int rx(BBCFTP *sys) { int state; double vmax; //-------------------------------------------------------------------- // Runtime scheduler //-------------------------------------------------------------------- vmax = 0; state = 0; sys->config->tot_ticks = clock(); while ( (sys->source->streaming) || (0 <= sys->buffer->margin) ) { switch (state) { case 0: // Scheduler if ( (sys->source->streaming) && (sys->config->actual_trx_bytes < sys->config->nominal_trx_bytes) ) { state = 1; // Run MODEM until sampling is caught up } else if (0 <= sys->buffer->margin) { state = 2; // Decode packets subject to maximum amount of time. } else { if (sys->config->scheduler_realtime) sys->config->nominal_trx_bytes = (DWORD) ((clock() - sys->config->tot_ticks) * sys->config->bytespertick); else sys->config->nominal_trx_bytes += (DWORD) (sys->config->bytespertick); } break; case 1: // MODEM Demodulate(sys->config, sys->source, sys->modem, sys->buffer); state = 0; break; case 2: // CODEC Decode(sys->config, sys->buffer, sys->codec, sys->sink); state = 0; break; } } sys->config->tot_ticks = clock() - sys->config->tot_ticks; //-------------------------------------------------------------------- // POST RUN CODE //-------------------------------------------------------------------- printf("\n"); printf("Marks: %li\n", sys->config->marks); printf("Messages found: %lu\n", sys->config->message_count); printf("Packets lost: %lu\n", (DWORD) (sys->buffer->overflows * 8)); printf("Total time:........... %0.3f sec.\n", ( (double)sys->config->tot_ticks / (double)CLOCKS_PER_SEC )); printf("MODEM time:........... %0.3f sec.\n", ( (double)sys->config->dem_ticks / (double)CLOCKS_PER_SEC )); printf("CODEC time:........... %0.3f sec.\n", ( (double)sys->config->dec_ticks / (double)CLOCKS_PER_SEC )); SINK_Purge(sys->config, sys->sink); return EXIT_SUCCESS; } //------------------------------------------------------------------------ // MAIN PROGRAM //------------------------------------------------------------------------ int main(int argc, char *argv[]) { BBCFTP *sys; char *config_file_name; DWORD errcode; int res; //-------------------------------------------------------------------- // Read configuration information //-------------------------------------------------------------------- config_file_name = NULL; if (argc < 2) { printf("Mode (T or R): "); res = getc(stdin); switch (res) { case 'T': case 't': config_file_name = "tx.ini"; break; case 'R': case 'r': default : config_file_name = "rx.ini"; } while ('\n' != res) res = getc(stdin); } else config_file_name = argv[1]; sys = BBCFTP_New(config_file_name, &errcode); if (errcode) { printf("BBC FTP System Constructor exited with error code: %lu\n", errcode); exit(EXIT_FAILURE); } //-------------------------------------------------------------------- // Launch transmitter or recever as appropriate //-------------------------------------------------------------------- if (sys->config->scheduler_TX_notRX) tx(sys); else rx(sys); //-------------------------------------------------------------------- // Runtime Scheduler //-------------------------------------------------------------------- // The components of the new scheduler are not yet complete. // while (sys->sink->streaming) // { // SOURCE_Run(sys); // CODEC_Run(sys); // MODEM_Run(sys); // SINK_Run(sys); // } //-------------------------------------------------------------------- // Final Housekeeping //-------------------------------------------------------------------- BBCFTP_Del(sys); printf("\n - Hit ENTER to exit."); getc(stdin); return EXIT_SUCCESS; }