// samples should be u-law encoded void modem_decode(buffer_t *input, buffer_t *output) { static int phase = -1; int max_idx; size_t i; int16_t max_mag; int16_t samples[SAMPLES_PER_ITER]; for (i = 0; i < SAMPLES_PER_ITER; i++) { uint8_t byte; buffer_read_bytes(input, &byte, 1); samples[i] = comp_decode(byte) * 4; } // apply band-pass filter to remove noise bandpass_filter(samples); // apply convolution with delay line convolution(samples); // apply low-pass filter to remove high-frequency artifacts lowpass_filter(samples); // try and find the middle of the phase if (phase == -1) { max_mag = 0; max_idx = 0; for (i = 0; i < SAMPLES_PER_ITER; i++) { if (samples[i] > max_mag) { max_mag = samples[i]; max_idx = i; } else if (-samples[i] > max_mag) { max_mag = -samples[i]; max_idx = i; } } phase = (max_idx) % (SAMPLES_PER_BIT / 2); } // sample at baudrate to get output for (i = phase; i < SAMPLES_PER_ITER; i += SAMPLES_PER_BIT) { int avg = 0; int j; for (j = 0; j < SAMPLES_PER_BIT / 4; j++) avg += samples[i + j]; //< 0 ? -1 : 1; avg /= SAMPLES_PER_BIT / 4; int bit = avg < 0 ? 1 : 0; buffer_write_bit(output, bit); } }
void modem_encode_frame(buffer_t *output) { size_t i; uint8_t data[FRAME_SIZE / 8 + 1]; buffer_t buf; if (buffer_read_remaining(&g_frames) < FRAME_SIZE) return; buffer_init(&buf, data, sizeof(data)); buffer_write_bits(&buf, 0x13, 5); for (i = 0; i < FRAME_SIZE / 8; i++) { uint8_t byte; buffer_read_bytes(&g_frames, &byte, 1); buffer_write_bytes(&buf, &byte, 1); } modem_encode(&buf, output); }
void modem_loop(modem_rx_cb_t cb) { #define BIT_1 0 #define BIT_2 1 #define BIT_3 2 #define BIT_4 3 #define BIT_5 4 #define WAIT_FOR_DATA 5 int state = 0, recvd = 0; uint64_t mark; static uint8_t indata[1024], decdata[512], pktdata[1024], outdata[32768]; buffer_t inbuf, decbuf, pktbuf, outbuf; buffer_init(&inbuf, indata, sizeof(indata)); buffer_init(&decbuf, decdata, sizeof(decdata)); buffer_init(&pktbuf, pktdata, sizeof(pktdata)); buffer_init(&outbuf, outdata, sizeof(outdata)); while (1) { uint8_t u_sample; size_t bytes = 1; if (ready_to_read() == 0) { // transmit(STDERR, "flush!\n", 7, NULL); flush_output(); } if (get_byte(&u_sample) != 0) break; // if (receive(STDIN, &u_sample, 1, &bytes) != 0 || bytes != 1) // break; recvd++; buffer_write_bytes(&inbuf, &u_sample, 1); // process samples every 0.01 ms if (buffer_read_remaining(&inbuf) / 8 >= SAMPLES_PER_ITER) { modem_decode(&inbuf, &decbuf); while (state != WAIT_FOR_DATA && buffer_read_remaining(&decbuf) >= 8) { uint8_t bit; bit = buffer_read_bit(&decbuf); switch (state) { case BIT_1: state = BIT_2; mark = buffer_read_tell(&decbuf); if (bit != 1) goto reset; break; case BIT_2: state = BIT_3; if (bit != 0) goto reset; break; case BIT_3: state = BIT_4; if (bit != 0) goto reset; break; case BIT_4: state = BIT_5; if (bit != 1) goto reset; break; case BIT_5: state = WAIT_FOR_DATA; if (bit != 1) goto reset; break; } continue; reset: state = BIT_1; buffer_read_seek(&decbuf, mark); } if (state == WAIT_FOR_DATA && buffer_read_remaining(&decbuf) > FRAME_SIZE) { int result = frame_decode(&decbuf, &pktbuf); if (result == FRAME_FAIL) { goto reset; } else if (result == FRAME_END) { // XXX send packet to callback cb(pktdata, buffer_read_remaining(&pktbuf) / 8); buffer_init(&pktbuf, pktdata, sizeof(pktdata)); } state = BIT_1; } } if (buffer_read_remaining(&outbuf) == 0) modem_encode_frame(&outbuf); if (buffer_read_remaining(&outbuf) > 0) buffer_read_bytes(&outbuf, &u_sample, 1); else u_sample = _modem_encode(1); write_byte(u_sample); // transmit(STDOUT, &u_sample, 1, &bytes); } }
/* * you should care about the trailing-null by yourself */ void buffer_read_string(buffer_t *b, char *str, size_t len) { buffer_read_bytes(b, str, len); }