/**************************************************************************** * MODEM 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:............ modem.c * * DATE CREATED:.... 06 SEP 07 * * DATE MODIFIED:... 06 SEP 07 * **************************************************************************** * * REVISION HISTORY * **************************************************************************** * * DESCRIPTION * * The modem and its public interface is described in modem.h. * **************************************************************************** */ //------------------------------------------------------------------------ // REQUIRED INCLUDES //------------------------------------------------------------------------ #include // malloc() #include // exp() #include "modem.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 //------------------------------------------------------------------------ MODEM *MODEM_Del(MODEM *p) { if (p) { free(p); } return NULL; } MODEM *MODEM_New(CONFIG *c, DWORD *errcode) { MODEM *p; DWORD err; double nominal_steady_state_peak; p = NULL; err = 0; p = (MODEM *) malloc(sizeof(MODEM)); if (!p) err |= 1 << 0; if (!err) { // Derived quantities p->jitter_samples = (int)(c->modem_samples_per_bit * c->modem_jitter_bits); // Integrator parameter p->alpha = exp((2.0/c->modem_samples_per_bit) - 1.0); // Threshold parameters nominal_steady_state_peak = (c->nominal_rx_signal*c->nominal_rx_signal) * (1.0/(1.0-p->alpha)); p->t_hi = nominal_steady_state_peak * ((c->modem_threshold_pct + c->modem_hysteresis_pct/2.0)/100.0); p->t_lo = nominal_steady_state_peak * ((c->modem_threshold_pct - c->modem_hysteresis_pct/2.0)/100.0); // State information p->state = 0; p->integrator = 0.0; p->stamp = 0; } if (err) p = MODEM_Del(p); if (c->diagnostics) { // Diagnostic Report printf("------------------------------------------\n"); printf("MODEM\n"); printf(" Creation:.................. %s\n", ((err)? "FAILED":"SUCCEEDED")); printf(" Location:.................. %p\n", (void *) p); printf(" Integrator alpha:.......... %f\n", p->alpha); printf(" Jitter tolerance:.......... %f\n", p->jitter_samples); printf(" Modem gain:................ %f (%f dB)\n", c->nominal_tx_signal, c->modem_gain_dB); printf(" Nominal channel loss:...... %f dB\n", c->modem_channel_loss_dB); printf(" Nominal rx signal peak:.... %f (%f dB)\n", c->nominal_rx_signal, (c->modem_gain_dB-c->modem_channel_loss_dB)); printf(" Nominal integrator peak:... %f\n", nominal_steady_state_peak); printf(" LO -> HI threshold:........ %f\n", p->t_hi); printf(" HI -> LO threshold:........ %f\n", p->t_lo); printf("------------------------------------------\n"); } *errcode = err; return p; } //------------------------------------------------------------------------ /* MODEM * * The MODEM reads/writes USRP in bursts of samples corresponding to * 8 packet bits. The calling function is responsible for ensuring that * valid data and/or sufficient room for new data exists in the buffer. * */ /* MODULATOR * * The modulator reads one byte of packet data from the buffer and generates * USRP data for the entire set of 8 packet bits. * */ void Modulate(CONFIG *c, BUFFER *buffer, MODEM *modem, SINK *sink) { DWORD originbit, sample; float signal; clock_t ticks; float *v; ticks = clock(); // Push write pointer if packet byte is not available if (!buffer->ready) { buffer->write = (buffer->write + 1) & buffer->buffermask; buffer->ready++; buffer->margin--; } // For each bit in the packet byte at the buffer's read pointer for (originbit = 0; originbit < 8; originbit++) { // Determine if the bit is a mark or a space if (buffer->buffer[buffer->read] & c->bitmask[originbit]) { c->marks++; signal = (float) c->nominal_tx_signal; } else signal = 0.0; // Determine if the sink can take all the samples for the present bit if (sink->samples + c->modem_samples_per_bit < sink->sample_limit) { // Establish the base location within the sink's buffer v = ((float *) sink->v) + (2 * sink->samples); // Generate and write the baseband samples to the sink for (sample = 0; sample < c->modem_samples_per_bit; sample++) { v[2*sample] = signal; // I(t) (actual data) v[2*sample + 1] = 0.0; // Q(t) (forced to zero) } sink->samples += c->modem_samples_per_bit; } else sink->streaming = FALSE; } buffer->buffer[buffer->read] = 0; buffer->read = (buffer->read + 1) & buffer->buffermask; buffer->ready--; buffer->margin++; c->actual_trx_bytes += c->trx_bytes_per_packet_byte; c->dem_ticks += clock() - ticks; } void Demodulate(CONFIG *c, SOURCE *source, MODEM *modem, BUFFER *buf) { DWORD sample; DWORD originbit; clock_t ticks; float *v; double v2; ticks = clock(); for (originbit = 0; originbit < 8; originbit++) { v = ((float *) source->v) + (2 * source->samples); for (sample = 0; sample < c->modem_samples_per_bit; sample++) { if (source->samples < source->sample_limit) { v2 = v[2*sample] * v[2*sample] + v[2*sample+1] * v[2*sample+1]; source->samples++; } else { v2 = 0; source->streaming = FALSE; } modem->integrator = v2 + modem->alpha*(modem->integrator - v2); switch (modem->state) { case 0: if (modem->integrator > modem->t_hi) { modem->state = 1; } break; case 1: if (modem->integrator < modem->t_lo) { modem->state = 2; modem->stamp = (SDWORD) (sample + modem->jitter_samples); } break; case 2: if (modem->integrator > modem->t_hi) modem->state = 1; else if (((SDWORD) sample > modem->stamp)&&(modem->integrator < modem->t_lo)) { modem->state = 0; } break; } } modem->stamp -= c->modem_samples_per_bit; if (0 == buf->empty) { buf->read = (buf->read + 1) & buf->buffermask; buf->empty++; buf->margin--; buf->overflows++; } // Step packet forward and mark next location if (modem->state > 0) { c->marks++; buf->buffer[buf->write] |= c->bitmask[originbit]; } else buf->buffer[buf->write] &= ~c->bitmask[originbit]; } buf->write = (buf->write + 1) & buf->buffermask; buf->margin++; buf->empty--; c->actual_trx_bytes += c->trx_bytes_per_packet_byte; c->dem_ticks += clock() - ticks; } //------------------------------------------------------------------------