From 783b56d54788f177881d68ae2ec7a7cb4bb38ac4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 18 Apr 2004 01:35:53 +0000 Subject: Initial commit git-svn-id: file:///home/lennart/svn/public/vfax/trunk@3 541b366f-4dd8-0310-ae39-b2612fd50714 --- Makefile | 15 +++++ bitsplit.c | 104 +++++++++++++++++++++++++++++++ bitsplit.h | 21 +++++++ interpol.c | 139 +++++++++++++++++++++++++++++++++++++++++ interpol.h | 17 +++++ main.c | 87 ++++++++++++++++++++++++++ resample.c | 147 +++++++++++++++++++++++++++++++++++++++++++ resample.h | 12 ++++ util.c | 21 +++++++ util.h | 8 +++ v17dem.c | 102 ++++++++++++++++++++++++++++++ v17mod.c | 206 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ v17mod.h | 22 +++++++ v17tcm.c | 109 ++++++++++++++++++++++++++++++++ v17tcm.h | 15 +++++ 15 files changed, 1025 insertions(+) create mode 100644 Makefile create mode 100644 bitsplit.c create mode 100644 bitsplit.h create mode 100644 interpol.c create mode 100644 interpol.h create mode 100644 main.c create mode 100644 resample.c create mode 100644 resample.h create mode 100644 util.c create mode 100644 util.h create mode 100644 v17dem.c create mode 100644 v17mod.c create mode 100644 v17mod.h create mode 100644 v17tcm.c create mode 100644 v17tcm.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..45cc029 --- /dev/null +++ b/Makefile @@ -0,0 +1,15 @@ +CFLAGS=-pipe -O0 -W -Wall -g -DTEST=7 -D_GNU_SOURCE +CC=gcc +LIBS=-lm + +all: main + +*.o: Makefile + +main: main.o v17tcm.o v17mod.o bitsplit.o util.o interpol.o resample.o + $(CC) -o $@ $^ $(LIBS) + +clean: + rm -f main *.o + +.PHONY: clean diff --git a/bitsplit.c b/bitsplit.c new file mode 100644 index 0000000..ee2074b --- /dev/null +++ b/bitsplit.c @@ -0,0 +1,104 @@ +#include +#include +#include +#include +#include + +#include "bitsplit.h" +#include "util.h" + +void bitsplit_init(struct bitsplit_state *s, int maxbits_in, int maxbits_out) { + assert(s && maxbits_in && maxbits_out); + assert(maxbits_in <= 8 && maxbits_out <= 8); + + memset(s, 0, sizeof(struct bitsplit_state)); + s->maxbits_in = maxbits_in; + s->maxbits_out = maxbits_out; +} + +inline static int read_next_bit(struct bitsplit_state *s, uint8_t **src) { + assert(s); + + if (!s->n_in) { + s->in = **src; + (*src)++; + s->n_in = s->maxbits_in; + } + + return (s->in >> (-- (s->n_in))) & 1; +} + +inline static void write_next_bit(struct bitsplit_state *s, uint8_t **dst, int bit) { + assert(s); + + s->out = (s->out << 1) | (bit & 1); + s->n_out++; + + if (s->n_out >= s->maxbits_out) { + **dst = s->out; + s->out = 0; + (*dst)++; + s->n_out = 0; + } +} + +void bitsplit(struct bitsplit_state *s, uint8_t *src, size_t *src_l, uint8_t *dst, size_t *dst_l) { + uint8_t *save_dst = dst, *save_src = src; + + assert(s && src && dst && src_l && dst_l); + + while ((src < save_src+*src_l /*|| s->n_in*/) && (dst < save_dst+*dst_l /*|| s->n_out < s->maxbits_out*/)) { + int bit; + + bit = read_next_bit(s, &src); + write_next_bit(s, &dst, bit); + } + + *src_l = src - save_src; + *dst_l = dst - save_dst; +} + +#if (TEST == 4) + +int main(int argc, char *argv[]) { + struct bitsplit_state s; + + assert(argc >= 3); + + bitsplit_init(&s, atoi(argv[1]), atoi(argv[2])); + + for (;;) { + uint8_t in[1024]; + uint8_t *i; + + ssize_t r; + + r = read(0, in, sizeof(in)); + assert(r >= 0); + + if (r == 0) + break; + + i = in; + + while (r) { + uint8_t out[1024]; + size_t outl = sizeof(out); + size_t il = r; + ssize_t r2; + + bitsplit(&s, i, &il, out, &outl); + i += il; + r -= il; + + if (outl) { + r2 = loop_write(1, out, outl); + assert(r2 > 0); + } + } + } + + return 0; +} + +#endif diff --git a/bitsplit.h b/bitsplit.h new file mode 100644 index 0000000..8a53f3e --- /dev/null +++ b/bitsplit.h @@ -0,0 +1,21 @@ +#ifndef foobitsplithfoo +#define foobitsplithfoo + +#include +#include + +struct bitsplit_state { + uint8_t in; + int n_in; + int maxbits_in; + + uint8_t out; + int n_out; + int maxbits_out; +}; + + +void bitsplit_init(struct bitsplit_state *s, int maxbits_in, int maxbits_out); +void bitsplit(struct bitsplit_state *s, uint8_t *src, size_t *src_l, uint8_t *dst, size_t *dst_l); + +#endif diff --git a/interpol.c b/interpol.c new file mode 100644 index 0000000..fb710c4 --- /dev/null +++ b/interpol.c @@ -0,0 +1,139 @@ +#include +#include +#include +#include +#include + +#include "interpol.h" +#include "util.h" + +void interpol_init(struct interpol_state *s, int frac, int radius) { + int l; + assert(s && frac); + + memset(s, 0, sizeof(struct interpol_state)); + + s->frac = frac; + + s->radius = radius; + s->coeff = malloc((l = s->radius*frac)*sizeof(float)); + s->coeff_valid = malloc(l*sizeof(int)); + + assert(s->coeff_valid && s->coeff); + + memset(s->coeff_valid, 0, l*sizeof(int)); +} + +void interpol_done(struct interpol_state *s) { + assert(s); + free(s->coeff); + free(s->coeff_valid); +} + +static float sinc(struct interpol_state *s, int x) { + assert(s); + + if (x == 0) + return 1; + + if (x < 0) + x = -x; + + if (x >= s->frac * s->radius) + return 0; + + if (!s->coeff_valid[x]) { + float fx = ((float) x)/s->frac; + float hanning = .5*(1+cos(M_PI * fx / s->radius)); + float _sinc = sin(M_PI * fx) / M_PI / fx; + + /*fprintf(stderr, "%2.10f %2.10f %2.10f\n", fx, hanning, _sinc);*/ + + assert(_sinc <= 1); + assert(_sinc >= -1); + assert(hanning >= 0); + assert(hanning <= 1); + + + s->coeff[x] = hanning * _sinc; + s->coeff_valid[x] = 1; + } + + return s->coeff[x]; +} + +float interpol_get(struct interpol_state *s, float *p, int l, float x) { + int i, j, z, d, n; + float sum; + + assert(s && p && l); + + i = (int) roundf(x*s->frac); /* x in units of 1/fracs */ + z = i/s->frac; /* index of sample left of x */ + j = z*s->frac; /* index of sample left of x in units of 1/fracs */ + d = i-j; + + sum = 0; + + for (n = -s->radius; n <= s->radius; n++) { + int k = z + n; /* sample of current sinc pulse */ + + if (k < 0 || k >= l) + fprintf(stderr, "interpol.c: index out of bound: %i not in 0...%i\n", k, l); + else { +/* + char txt[2]; + snprintf(txt, sizeof(txt), "%f", p[k]); + fprintf(stderr, "%i %i\r", k, l); +*/ + sum += p[k] * sinc(s, -n*s->frac + d); + } + } + + return sum; +} + +#if (TEST == 5) + +int main() { + struct interpol_state s; + int x; + int frac = 9; + + interpol_init(&s, frac); + + for (x = -10*frac; x <= 10*frac; x ++) { + fprintf(stderr, "%2.5f -> %2.5f\n", (float)x/frac, sinc(&s, x)); + } + + interpol_done(&s); + + return 0; +} + +#endif + +#if (TEST == 6) + +int main() { + struct interpol_state s; + float buf[1024], x; + int i, frac = 37; + + interpol_init(&s, frac); + + for (i = 0; i < 1024; i++) + buf[i] = 1; + + for (x = 0; x < 1024; x += 0.1) { + float y = interpol_get(&s, buf, 1024, x); + //loop_write(1, &y, sizeof(float)); + fprintf(stderr, "%2.10f => %2.10f\n", x, y); + } + + interpol_done(&s); + + return 0; +} + +#endif diff --git a/interpol.h b/interpol.h new file mode 100644 index 0000000..e4ba740 --- /dev/null +++ b/interpol.h @@ -0,0 +1,17 @@ +#ifndef foointerpolhfoo +#define foointerpolhfoo + +struct interpol_state { + int frac; + float *coeff; + int *coeff_valid; + int radius; +}; + + +void interpol_init(struct interpol_state *s, int frac, int radius); +void interpol_done(struct interpol_state *s); + +float interpol_get(struct interpol_state *s, float *p, int l, float x); + +#endif diff --git a/main.c b/main.c new file mode 100644 index 0000000..5356f47 --- /dev/null +++ b/main.c @@ -0,0 +1,87 @@ +#include +#include +#include +#include + +#include "v17mod.h" +#include "v17tcm.h" +#include "util.h" + +int16_t *conv_float_16sle(float *p, int l) { + int i; + int16_t *r = (int16_t*) p, *target = (int16_t*) p; + + assert(2*sizeof(int16_t) == sizeof(float)); + + for (i = 0; i < l; i++) { + int v = (int) (0x3FFF * *p); + + if (v < -0x8000) { + v = -0x8000; + fprintf(stderr, "UNDERFLOW: %f\n", *p); + } + + if (v > 0x7fff) { + v = 0x7fff; + fprintf(stderr, "OVERFLOW\n"); + } + + + *(target++) = (int16_t) v; + *(target++) = (int16_t) v; + + p++; + } + + return r; +} + +#ifndef TEST + +int main() { + struct v17mod_state mod; + struct v17tcm_state tcm; + + v17mod_init(&mod); + v17tcm_init(&tcm); + + for (;;) { + ssize_t l; + uint8_t buf[64]; + int i, n; + float f[1024]; + + //fprintf(stderr, "ITERATE\n"); + + if ((l = read(0, buf, sizeof(buf))) <= 0) { + //if (l < 0) + fprintf(stderr, "read failure\n"); + + + goto finish; + } + + for (i = 0; i < l; i++) + buf[i] = v17tcm_encode(&tcm, buf[i] & 7); + + v17mod_push(&mod, buf, l); + + n = v17mod_pull(&mod, f, sizeof(f)/sizeof(float)); + + + + if (loop_write(1, conv_float_16sle(f, n), n*sizeof(int16_t)*2) < 0) { + fprintf(stderr, "write failure\n"); + goto finish; + } + } + + +finish: + + v17mod_done(&mod); + + return 0; +} + +#endif diff --git a/resample.c b/resample.c new file mode 100644 index 0000000..ee9e540 --- /dev/null +++ b/resample.c @@ -0,0 +1,147 @@ +#include +#include +#include +#include +#include + +#include "resample.h" +#include "interpol.h" + +#define SINC_RADIUS 10 + +struct resample_state { + float delta; + + int sfreq, dfreq; + struct interpol_state interpol; +}; + + +static int lcd(int a, int b) { + assert(a >= 1 && b >= 1); + + while (a != b) { + while (a > b) { + a = a-b; + } + + while (b > a) { + b = b-a; + } + } + + return a; +} + +void resample_init(struct resample_state *s) { + assert(s); + memset(s, 0, sizeof(struct resample_state)); + s->sfreq = s->dfreq = -1; +} + +void resample_done(struct resample_state *s) { + assert(s); + interpol_done(&s->interpol); +} + +void resample_get(struct resample_state *s, float* sp, int *sl, float *dp, int *dl, int sfreq, int dfreq) { + int di; + float x = 0; + + assert(s && sp && dp && sfreq > 0 && dfreq > 0); + assert(*sl > 0); + assert(*dl > 0); + + if (sfreq != s->sfreq || dfreq != s->dfreq) { + interpol_done(&s->interpol); + interpol_init(&s->interpol, dfreq/lcd(sfreq,dfreq), SINC_RADIUS); + s->sfreq = sfreq; + s->dfreq = dfreq; + } + + di = 0; + while (di < *dl) { + x = (float) di*sfreq/dfreq + s->delta; + + if (x + SINC_RADIUS + 1 > *sl) + break; + + *(dp++) = interpol_get(&s->interpol, sp, *sl, x); + di++; + } + + *dl = di; + + if (x >= SINC_RADIUS) { + *sl = (int) (x - SINC_RADIUS); + s->delta = x - *sl; + } else + *sl = 0; +} + +#if (TEST == 7) + +#define BUFSIZE (10*1024) + +void sinbuf(float *buf, int l) { + static int i = 0; + + for (; l > 0; l--, i = (i+1 == 100) ? 0 : i+1) + *(buf++) = sin(i*2*M_PI/100); +} + +void convbuf(float *buf, int l) { + int16_t *p = (int16_t*) buf; + for (; l > 0; l--, p+=2) { + float v = ((float) *p + (float) *(p+1))/0x7FFF; + *(buf++) = (v < -1) ? -1 : ((v > 1) ? 1 : v); + } + +} + + +int main(int argc, char *argv[]) { + struct resample_state resample; + float inbuf[BUFSIZE]; + int total_n_inbuf = 0; + + if (argc > 1) { + stdin = fopen(argv[1], "r"); + assert(stdin); + } + + resample_init(&resample); + + while (!feof(stdin)) { + float outbuf[BUFSIZE]; + int n_outbuf = sizeof(outbuf) / sizeof(float); + int n_inbuf, c; + + fprintf(stderr, "LOOP!\n"); + + c = fread(inbuf + total_n_inbuf, sizeof(float), sizeof(inbuf)/sizeof(float) - total_n_inbuf, stdin); + convbuf(inbuf + total_n_inbuf, c); + n_inbuf = (total_n_inbuf += c); + + + +/* sinbuf(inbuf + total_n_inbuf, sizeof(inbuf)/sizeof(float) - total_n_inbuf); */ +/* n_inbuf = total_n_inbuf = sizeof(inbuf)/sizeof(float); *\/ */ + + + resample_get(&resample, inbuf, &n_inbuf, outbuf, &n_outbuf, 44100, 8000); + + fwrite(outbuf, sizeof(float), n_outbuf, stdout); + + if (n_inbuf) { + total_n_inbuf -= n_inbuf; + memmove(inbuf, inbuf + n_inbuf, total_n_inbuf*sizeof(float)); + } + } + + resample_done(&resample); + + return 0; +} + +#endif diff --git a/resample.h b/resample.h new file mode 100644 index 0000000..a2905b3 --- /dev/null +++ b/resample.h @@ -0,0 +1,12 @@ +#ifndef fooresamplehfoo +#define fooresamplehfoo + +struct resample_state; + +void resample_init(struct resample_state *s); +void resample_done(struct resample_state *s); +void resample_get(struct resample_state *s, float* sp, int *sl, float *dp, int *dl, int sfreq, int dfreq); + +#endif + + diff --git a/util.c b/util.c new file mode 100644 index 0000000..3907dad --- /dev/null +++ b/util.c @@ -0,0 +1,21 @@ +#include + +#include "util.h" + +ssize_t loop_write(int fd, const void *b, size_t l) { + ssize_t t = 0; + while (l) { + ssize_t r; + + if ((r = write(fd, b, l)) < 0) + return t == 0 ? r : t; + else if (r == 0) + return t; + + b += r; + l -= r; + t += r; + } + + return t; +} diff --git a/util.h b/util.h new file mode 100644 index 0000000..96dd779 --- /dev/null +++ b/util.h @@ -0,0 +1,8 @@ +#ifndef fooutilhfoo +#define fooutilhfoo + +#include + +ssize_t loop_write(int fd, const void *b, size_t l); + +#endif diff --git a/v17dem.c b/v17dem.c new file mode 100644 index 0000000..4fad8f3 --- /dev/null +++ b/v17dem.c @@ -0,0 +1,102 @@ +#include "v17dem.h" + +#define INITIAL_BAUD_RATE 2400 +#define INITIAL_CARRIER_FREQ 1800 +#define SAMPLE_RATE 8000 +#define SAMPLES_MAX (SAMPLES_RATE*5) /* -> 5s buffer */ + +#define SINC_RADIUS 10 + +struct v17dem_state { + float *samples; + int i_samples, n_samples; + + int sample_index; + + int baud_rate; + int carrier_freq; + + struct interpol_state qam_interpol; + struct interpol_state am_interpol; + + enum { COSINUS, SINUS } current; + float *xam, *yam; + int am_index; +}; + + +void v17dem_init(struct v17dem_state *s) { + assert(s); + + memset(s, 0, sizeof(struct v17dem_state)); + s->baud_rate = INITIAL_BAUD_RATE; + s->carrier_freq = INITIAL_CARRIER_FREQ; + s->samples = malloc(sizeof(float) * SAMPLES_MAX * 2); + + interpol_init(&s->qam_interpol, 9, SINC_RADIUS); +} + +void v17dem_done(struct v17dem_state *s) { + assert(s); + + free(s->samples); + inertpol_done(&s->qam_interpol); +} + +static void move_to_front(struct v17dem_state *s) { + assert(s); + + if (s->i_samples < SAMPLES_MAX) + return; + + memmove(s->samples, s->samples + s->i_samples, s->n_samples*sizeof(float)); + s->i_samples = 0; +} + +void v17dem_push(struct v17dem_state *s, const float *p, int l){ + assert(s && p && l); + + assert(l <= SAMPLES_MAX-s->n_samples); + + move_to_front(s); + + memcpy(s->samples + s->i_samples + s->n_samples, p, l*sizeof(float)); + s->n_samples += l; +} + +int v17dem_pull(struct v17dem_state *s, uint8_t *p, int l){ + int alt = 0; + + assert(s && p && l); + + for (;;) { + int n; + + /* Position für AM-Abtastung im Sample-Puffer berechnen -- alle 90° */ + float x = (SAMPLE_RATE/(4.0*s->carrier_freq) * s->am_index) - s->sample_index; + assert(x >= 0); + + /* AM-Abtatsung druchführen */ + if (s->current = COSINUS) + am = s->xam; + else + am = s->yam; + + am[s->am_index] = interpol_get(s->qam_interpol, s->samples + s->i_samples, s->n_samples, x); + + if (s->current == SINUS) + s->am_index++; + + s->current = !s->current; + + /* Überflüssige Sampledaten killen */ + + n = (int) (x - (float) SINC_RADIUS*SAMPLE_RATE/s->carrier_freq/4); + + if (n > 0) { + s->n_samples -= n; + s->i_samples += n; + s->sample_index += n; + } + } +} diff --git a/v17mod.c b/v17mod.c new file mode 100644 index 0000000..3c604ef --- /dev/null +++ b/v17mod.c @@ -0,0 +1,206 @@ +#include +#include +#include +#include +#include + +#include "v17mod.h" + +#define SAMPLE_RATE 8000 +#define CARRIER_FREQ 1800 +#define BAUD_RATE 2400 +#define SYMBOL_INTERVAL ((float) SAMPLE_RATE/BAUD_RATE) +#define SINC_RADIUS 5 +#define SYMBOLS_MAX 1024 + +static const float v17_7k2_x[] = { + 0.6, -0.2, 0.6, -0.6, + -0.6, 0.2, -0.6, 0.6, + -0.2, 0.6, -0.2, 0.2, + 0.2, -0.6, 0.2, -0.2 +}; + +static const float v17_7k2_y[] = { + -0.6, 0.6, 0.2, -0.6, + 0.6, -0.6, -0.2, 0.6, + 0.2, -0.2, -0.6, 0.2, + -0.2, 0.2, 0.6, -0.2 +}; + +void v17mod_init(struct v17mod_state *s) { + size_t l; + int i; + + assert(s); + memset(s, 0, sizeof(*s)); + + s->xsymbols = malloc(l = (sizeof(float)*SYMBOLS_MAX)); + s->ysymbols = malloc(l); + + s->n_symbols = SINC_RADIUS*2; + + for (i = 0; i < s->n_symbols; i++) + s->xsymbols[i] = s->ysymbols[i] = 0.0; +} + +void v17mod_done(struct v17mod_state *s) { + assert(s); + free(s->xsymbols); + free(s->ysymbols); +} + +static const float sinc_table[] = { + 0.0000, -0.0000, -0.0002, -0.0005, -0.0009, + -0.0014, -0.0018, -0.0020, -0.0019, -0.0013, + 0.0000, 0.0019, 0.0042, 0.0068, 0.0093, + 0.0113, 0.0124, 0.0120, 0.0098, 0.0058, + -0.0000, -0.0073, -0.0153, -0.0234, -0.0303, + -0.0350, -0.0365, -0.0340, -0.0270, -0.0155, + 0.0000, 0.0183, 0.0377, 0.0562, 0.0716, + 0.0815, 0.0838, 0.0771, 0.0605, 0.0344, + -0.0000, -0.0403, -0.0832, -0.1243, -0.1589, + -0.1821, -0.1893, -0.1767, -0.1415, -0.0824, + 0.0000, 0.1035, 0.2241, 0.3561, 0.4926, + 0.6261, 0.7488, 0.8533, 0.9330, 0.9830, + 1.0000, 0.9830, 0.9330, 0.8533, 0.7488, + 0.6261, 0.4926, 0.3561, 0.2241, 0.1035, + 0.0000, -0.0824, -0.1415, -0.1767, -0.1893, + -0.1821, -0.1589, -0.1243, -0.0832, -0.0403, + -0.0000, 0.0344, 0.0605, 0.0771, 0.0838, + 0.0815, 0.0716, 0.0562, 0.0377, 0.0183, + 0.0000, -0.0155, -0.0270, -0.0340, -0.0365, + -0.0350, -0.0303, -0.0234, -0.0153, -0.0073, + -0.0000, 0.0058, 0.0098, 0.0120, 0.0124, + 0.0113, 0.0093, 0.0068, 0.0042, 0.0019, + 0.0000, -0.0013, -0.0019, -0.0020, -0.0018, + -0.0014, -0.0009, -0.0005, -0.0002, -0.0000, + -0.0000 +}; + +static float sinc(float x) { + int i; + assert(sizeof(sinc_table)/sizeof(float) == 121); + + i = (int) (60+x*10+.5); + + if (i < 0) + return 0; + if (i > 120) + return 0; + + return sinc_table[i]; +} + + +void v17mod_push(struct v17mod_state *s, const uint8_t *p, int l) { + int i, j; + + assert(s && p && l); + assert(s->n_symbols+l <= SYMBOLS_MAX); + + for (i = 0, j = (s->i_symbols+s->n_symbols) % SYMBOLS_MAX; i < l; i++, j = (j+1) % SYMBOLS_MAX) { + assert(p[i] < 16); + s->xsymbols[j] = v17_7k2_x[p[i]]; + s->ysymbols[j] = v17_7k2_y[p[i]]; + } + + s->n_symbols += l; +} + +inline static float symbol_at(struct v17mod_state *s, float *a, int i) { + int j = s->i_symbols+i; + + assert(i >= 0); + assert(i < s->n_symbols); + + while(j >= SYMBOLS_MAX) + j -= SYMBOLS_MAX; + + assert(j>=0); + assert(j= 0 && i <= 1); + + symbols = (i == 0) ? s->xsymbols : s->ysymbols; + sum = 0; + d = s->sample - s->symbol_index*SAMPLE_RATE/BAUD_RATE; + + for (n = -SINC_RADIUS; n < SINC_RADIUS; n++) { + float a,b; + a = symbol_at(s, symbols, n+SINC_RADIUS); + b = sinc(-n + d*BAUD_RATE/SAMPLE_RATE); + sum += a*b; + } + assert(sum<=10); + assert(sum >=-10); + + return sum; +} + +int v17mod_pull(struct v17mod_state *s, float *p, int l) { + assert(s && p && l && p && l); + + int n_samples = 0; + + for (;;) { + float x; + int nsi; + + if (s->sample % 800 == 0) + fprintf(stderr, "seconds: %i; samples: %i; symbols: %i \r", s->seconds, s->sample, s->symbol_index); + + if (!l) { + fprintf(stderr, "v17_mod(): destination buffer too short\n"); + return -1; + } + + nsi = (int) ((float) s->sample*BAUD_RATE/SAMPLE_RATE); + if (nsi != s->symbol_index) { + s->i_symbols++; + s->n_symbols--; + + while (s->i_symbols >= SYMBOLS_MAX) + s->i_symbols -= SYMBOLS_MAX; + + s->symbol_index = nsi; + } + + if (s->n_symbols < SINC_RADIUS*2) + return n_samples; + + if (s->sample == SAMPLE_RATE) { + assert(s->symbol_index == BAUD_RATE); + + s->symbol_index = s->sample = 0; + s->seconds++; + } + + + x = (s->sample % SAMPLE_RATE) * M_PI*2 * CARRIER_FREQ / SAMPLE_RATE; + + *(p++) = fsignal(s, 0)*sin(x) + fsignal(s, 1)*cos(x); + l--; + + s->sample++; + n_samples++; + } +} + + +#if (TEST == 3) + +int main() { + fprintf(stderr, "%f\n", sinc(1.0/3)); + + return 0; +} + +#endif diff --git a/v17mod.h b/v17mod.h new file mode 100644 index 0000000..6417ca4 --- /dev/null +++ b/v17mod.h @@ -0,0 +1,22 @@ +#ifndef foov17modhfoo +#define foov17modhfoo + +#include + +struct v17mod_state { + int sample; + int symbol_index; + + int seconds; + + float *xsymbols, *ysymbols; + int i_symbols, n_symbols; +}; + +void v17mod_init(struct v17mod_state *s); +void v17mod_done(struct v17mod_state *s); + +void v17mod_push(struct v17mod_state *s, const uint8_t *p, int l); +int v17mod_pull(struct v17mod_state *s, float *p, int l); + +#endif diff --git a/v17tcm.c b/v17tcm.c new file mode 100644 index 0000000..0edaefe --- /dev/null +++ b/v17tcm.c @@ -0,0 +1,109 @@ +#include +#include +#include +#include + +#include "v17tcm.h" + +static const uint8_t v17tcm_table[] = { + 0, 1, 2, 3, + 1, 2, 3, 0, + 2, 3, 0, 1, + 3, 0, 1, 2 +}; + +static const uint8_t v17tcm_table_reverse[] = { + 0, 1, 2, 3, + 3, 0, 1, 2, + 2, 3, 0, 1, + 1, 2, 3, 0 +}; + +void v17tcm_init(struct v17tcm_state *s) { + assert(s); + memset(s, 0, sizeof(*s)); +} + +static uint8_t conv_encode(struct v17tcm_state* s, uint8_t y) { + uint8_t x, a, b, c, d, e; + + /* + fprintf(stderr, "conv_encode(..., %u)\n", y); + */ + a = (y&1) ^ (y>>1); + b = (a ^ s->c1); + d = s->c2 ^ (s->c2 ^ (y>>1)); + c = b ^ (s->c3 & d); + e = d ^ ((y&1) & s->c3); + + x = s->c3; + + s->c1 = s->c3; + s->c2 = c; + s->c3 = e; + + return x; +} + +uint8_t v17tcm_encode(struct v17tcm_state* s, uint8_t input) { + uint8_t y, c; + + y = s->y = v17tcm_table[((input & 3) << 2) | (s->y & 3)]; + + /*fprintf(stderr, "tcm = %u\n", y);*/ + + c = conv_encode(s, y); + + /*fprintf(stderr, "c:%u von %u\n", c, y);*/ + + return c | ((y | (input & ~3)) << 1); +} + +uint8_t v17tcm_decode(struct v17tcm_state *s, uint8_t input) { + uint8_t y, py; + + if (conv_encode(s, (input >> 1) & 3) != (input & 1)) + fprintf(stderr, "Invalid TCM code, ignoring\n"); + + y = v17tcm_table_reverse[((s->y&3) << 2) | (py = ((input >> 1) & 3))]; + + s->y = py; + + return (input >> 3 << 2) | y; +} + +#ifdef TEST1 +int main() { + uint8_t c; + + for (c = 0; c <= 0xF; c++) { + if (v17tcm_table_reverse[v17tcm_table[c] | ((c&3) << 2)] != (c >> 2)) + fprintf(stderr, "%u: FEHLER\n", c); + else + fprintf(stderr, "%u: OK\n", c); + } + return 0; +} +#endif + +#ifdef TEST2 +int main() { + struct v17tcm_state s1, s2; + int c, n; + + v17tcm_init(&s1); + v17tcm_init(&s2); + + n = 0; + while ((c = getchar()) >= 0) { + uint8_t b = ((uint8_t) c) & 63; + uint8_t u = v17tcm_encode(&s1, b); + uint8_t e = v17tcm_decode(&s2, u); + + fprintf(stderr, "%i) %u %s %u (encoded: %u)\n", n++, b, b == e ? "==" : "!=", e, u); + } + + return 0; +} + +#endif diff --git a/v17tcm.h b/v17tcm.h new file mode 100644 index 0000000..f126714 --- /dev/null +++ b/v17tcm.h @@ -0,0 +1,15 @@ +#ifndef foov17tcmhfoo +#define foov17tcmhfoo + +#include + +struct v17tcm_state { + uint8_t y, c1, c2, c3; +}; + +void v17tcm_init(struct v17tcm_state *s); + +uint8_t v17tcm_encode(struct v17tcm_state* s, uint8_t input); +uint8_t v17tcm_decode(struct v17tcm_state *s, uint8_t input); + +#endif -- cgit