diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-08-25 09:12:35 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-08-25 09:12:35 +0000 |
commit | c7fc24dc4420057f103afe8fc64524ebc25c5d37 (patch) | |
tree | 3682407a599b8f9f03fc096298134cafba1c9b2f /drivers/net/hamradio/soundmodem | |
parent | 1d793fade8b063fde3cf275bf1a5c2d381292cd9 (diff) |
o Merge with Linux 2.1.116.
o New Newport console code.
o New G364 console code.
Diffstat (limited to 'drivers/net/hamradio/soundmodem')
-rw-r--r-- | drivers/net/hamradio/soundmodem/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/hamradio/soundmodem/gentbl.c | 2 | ||||
-rw-r--r-- | drivers/net/hamradio/soundmodem/sm.c | 107 | ||||
-rw-r--r-- | drivers/net/hamradio/soundmodem/sm.h | 17 | ||||
-rw-r--r-- | drivers/net/hamradio/soundmodem/sm_afsk2666.c | 356 | ||||
-rw-r--r-- | drivers/net/hamradio/soundmodem/sm_psk4800.c | 418 |
6 files changed, 793 insertions, 109 deletions
diff --git a/drivers/net/hamradio/soundmodem/Makefile b/drivers/net/hamradio/soundmodem/Makefile index 1aabdd9e8..a5adf62d0 100644 --- a/drivers/net/hamradio/soundmodem/Makefile +++ b/drivers/net/hamradio/soundmodem/Makefile @@ -46,7 +46,7 @@ all: all_targets .PHONY: all gentbl: gentbl.c - $(HOSTCC) -Wall $< -o $@ -lm + $(HOSTCC) $(HOSTCFLAGS) $< -o $@ -lm TBLHDR := sm_tbl_afsk1200.h sm_tbl_afsk2400_8.h TBLHDR += sm_tbl_afsk2666.h sm_tbl_psk4800.h diff --git a/drivers/net/hamradio/soundmodem/gentbl.c b/drivers/net/hamradio/soundmodem/gentbl.c index e67733831..a481a56f9 100644 --- a/drivers/net/hamradio/soundmodem/gentbl.c +++ b/drivers/net/hamradio/soundmodem/gentbl.c @@ -438,7 +438,7 @@ static void gentbl_hapn4800(FILE *f) { int i, j, k, l; float s; - float c[40]; + float c[44]; float min, max; fprintf(f, "\n/*\n * hapn4800 specific tables\n */\n\n"); diff --git a/drivers/net/hamradio/soundmodem/sm.c b/drivers/net/hamradio/soundmodem/sm.c index 3423807ac..fbfbb7e36 100644 --- a/drivers/net/hamradio/soundmodem/sm.c +++ b/drivers/net/hamradio/soundmodem/sm.c @@ -3,7 +3,7 @@ /* * sm.c -- soundcard radio modem driver. * - * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) + * Copyright (C) 1996-1998 Thomas Sailer (sailer@ife.ee.ethz.ch) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -40,6 +40,7 @@ * 0.5 03.03.97 fixed LPT probing (check_lpt result was interpreted the wrong way round) * 0.6 16.04.97 init code/data tagged * 0.7 30.07.97 fixed halfduplex interrupt handlers/hotfix for CS423X + * 0.8 14.04.98 cleanups */ /*****************************************************************************/ @@ -53,6 +54,8 @@ #include <linux/net.h> #include <linux/in.h> #include <linux/string.h> +#include <linux/init.h> +#include <asm/uaccess.h> #include <asm/system.h> #include <asm/io.h> #include <asm/bitops.h> @@ -62,59 +65,9 @@ /* --------------------------------------------------------------------- */ -/* - * currently this module is supposed to support both module styles, i.e. - * the old one present up to about 2.1.9, and the new one functioning - * starting with 2.1.21. The reason is I have a kit allowing to compile - * this module also under 2.0.x which was requested by several people. - * This will go in 2.2 - */ -#include <linux/version.h> - -#if LINUX_VERSION_CODE >= 0x20100 -#include <asm/uaccess.h> -#else -#include <asm/segment.h> -#include <linux/mm.h> - -#undef put_user -#undef get_user - -#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; }) -#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; }) - -extern inline int copy_from_user(void *to, const void *from, unsigned long n) -{ - int i = verify_area(VERIFY_READ, from, n); - if (i) - return i; - memcpy_fromfs(to, from, n); - return 0; -} - -extern inline int copy_to_user(void *to, const void *from, unsigned long n) -{ - int i = verify_area(VERIFY_WRITE, to, n); - if (i) - return i; - memcpy_tofs(to, from, n); - return 0; -} -#endif - -#if LINUX_VERSION_CODE >= 0x20123 -#include <linux/init.h> -#else -#define __init -#define __initdata -#define __initfunc(x) x -#endif - -/* --------------------------------------------------------------------- */ - /*static*/ const char sm_drvname[] = "soundmodem"; -static const char sm_drvinfo[] = KERN_INFO "soundmodem: (C) 1996-1997 Thomas Sailer, HB9JNX/AE4WA\n" -KERN_INFO "soundmodem: version 0.7 compiled " __TIME__ " " __DATE__ "\n"; +static const char sm_drvinfo[] = KERN_INFO "soundmodem: (C) 1996-1998 Thomas Sailer, HB9JNX/AE4WA\n" +KERN_INFO "soundmodem: version 0.8 compiled " __TIME__ " " __DATE__ "\n"; /* --------------------------------------------------------------------- */ @@ -685,51 +638,6 @@ static int sm_ioctl(struct device *dev, struct ifreq *ifr, /* --------------------------------------------------------------------- */ -#ifdef __i386__ - -int sm_x86_capability = 0; - -__initfunc(static void i386_capability(void)) -{ - unsigned long flags; - unsigned long fl1; - union { - struct { - unsigned int ebx, edx, ecx; - } r; - unsigned char s[13]; - } id; - unsigned int eax; - - save_flags(flags); - flags |= 0x200000; - restore_flags(flags); - save_flags(flags); - fl1 = flags; - flags &= ~0x200000; - restore_flags(flags); - save_flags(flags); - if (!(fl1 & 0x200000) || (flags & 0x200000)) { - printk(KERN_WARNING "%s: cpu does not support CPUID\n", sm_drvname); - return; - } - __asm__ ("cpuid" : "=a" (eax), "=b" (id.r.ebx), "=c" (id.r.ecx), "=d" (id.r.edx) : - "0" (0)); - id.s[12] = 0; - if (eax < 1) { - printk(KERN_WARNING "%s: cpu (vendor string %s) does not support capability " - "list\n", sm_drvname, id.s); - return; - } - printk(KERN_INFO "%s: cpu: vendor string %s ", sm_drvname, id.s); - __asm__ ("cpuid" : "=a" (eax), "=d" (sm_x86_capability) : "0" (1) : "ebx", "ecx"); - printk("fam %d mdl %d step %d cap 0x%x\n", (eax >> 8) & 15, (eax >> 4) & 15, - eax & 15, sm_x86_capability); -} -#endif /* __i386__ */ - -/* --------------------------------------------------------------------- */ - #ifdef MODULE __initfunc(static int sm_init(void)) #else /* MODULE */ @@ -742,9 +650,6 @@ __initfunc(int sm_init(void)) char ifname[HDLCDRV_IFNAMELEN]; printk(sm_drvinfo); -#ifdef __i386__ - i386_capability(); -#endif /* __i386__ */ /* * register net devices */ diff --git a/drivers/net/hamradio/soundmodem/sm.h b/drivers/net/hamradio/soundmodem/sm.h index 25bbc8ba9..66e8f936c 100644 --- a/drivers/net/hamradio/soundmodem/sm.h +++ b/drivers/net/hamradio/soundmodem/sm.h @@ -3,7 +3,7 @@ /* * sm.h -- soundcard radio modem driver internal header. * - * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) + * Copyright (C) 1996-1998 Thomas Sailer (sailer@ife.ee.ethz.ch) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,6 +32,8 @@ #include <linux/hdlcdrv.h> #include <linux/soundmodem.h> +#include <asm/processor.h> +#include <linux/bitops.h> #define SM_DEBUG @@ -71,7 +73,7 @@ struct sm_state { * state of the modem code */ union { - long m[32/sizeof(long)]; + long m[48/sizeof(long)]; } m; union { long d[256/sizeof(long)]; @@ -228,6 +230,7 @@ static inline void diag_add_constellation(struct sm_state *sm, int vali, int val * ===================== utility functions =============================== */ +#if 0 extern inline unsigned int hweight32(unsigned int w) __attribute__ ((unused)); extern inline unsigned int hweight16(unsigned short w) @@ -259,6 +262,8 @@ extern inline unsigned int hweight8(unsigned char w) return (res & 0x0F) + ((res >> 4) & 0x0F); } +#endif + extern inline unsigned int gcd(unsigned int x, unsigned int y) __attribute__ ((unused)); extern inline unsigned int lcm(unsigned int x, unsigned int y) @@ -291,13 +296,13 @@ extern inline unsigned int lcm(unsigned int x, unsigned int y) #ifdef __i386__ -extern int sm_x86_capability; +#include <asm/processor.h> -#define HAS_RDTSC (sm_x86_capability & 0x10) +#define HAS_RDTSC (current_cpu_data.x86_capability & X86_FEATURE_TSC) /* - * only do 32bit cycle counter arithmetic; we hope we won't overflow :-) - * in fact, overflowing modems would require over 2THz clock speeds :-) + * only do 32bit cycle counter arithmetic; we hope we won't overflow. + * in fact, overflowing modems would require over 2THz CPU clock speeds :-) */ #define time_exec(var,cmd) \ diff --git a/drivers/net/hamradio/soundmodem/sm_afsk2666.c b/drivers/net/hamradio/soundmodem/sm_afsk2666.c new file mode 100644 index 000000000..2aa2972e4 --- /dev/null +++ b/drivers/net/hamradio/soundmodem/sm_afsk2666.c @@ -0,0 +1,356 @@ +/*****************************************************************************/ + +/* + * sm_afsk2666.c -- soundcard radio modem driver, 2666 baud AFSK modem + * + * Copyright (C) 1997 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please note that the GPL allows you to use the driver, NOT the radio. + * In order to use the radio, you need a license from the communications + * authority of your country. + * + */ + +#include "sm.h" +#include "sm_tbl_afsk2666.h" + +/* --------------------------------------------------------------------- */ + +struct demod_state_afsk26 { + unsigned int shreg; + unsigned long descram; + int dem_sum[8]; + int dem_sum_mean; + int dem_cnt; + unsigned int bit_pll; + unsigned char last_sample; + unsigned int dcd_shreg; + int dcd_sum0, dcd_sum1, dcd_sum2; + unsigned int dcd_time; +}; + +struct mod_state_afsk26 { + unsigned int shreg; + unsigned long scram; + unsigned int bit_pll; + unsigned int phinc; + unsigned int tx_seq; +}; + +/* --------------------------------------------------------------------- */ + +#define DESCRAM_TAP1 0x20000 +#define DESCRAM_TAP2 0x01000 +#define DESCRAM_TAP3 0x00001 + +#define DESCRAM_TAPSH1 17 +#define DESCRAM_TAPSH2 12 +#define DESCRAM_TAPSH3 0 + +#define SCRAM_TAP1 0x20000 /* X^17 */ +#define SCRAM_TAPN 0x00021 /* X^0+X^5 */ + +/* --------------------------------------------------------------------- */ + +static void modulator_2666_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen) +{ + struct mod_state_afsk26 *st = (struct mod_state_afsk26 *)(&sm->m); + + for (; buflen > 0; buflen--, buf++) { + if (!st->tx_seq++) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->scram = ((st->scram << 1) | (st->scram & 1)); + st->scram ^= (!(st->shreg & 1)); + st->shreg >>= 1; + if (st->scram & (SCRAM_TAP1 << 1)) + st->scram ^= SCRAM_TAPN << 1; + st->phinc = afsk26_carfreq[!(st->scram & (SCRAM_TAP1 << 2))]; + } + if (st->tx_seq >= 6) + st->tx_seq = 0; + *buf = OFFSCOS(st->bit_pll); + st->bit_pll += st->phinc; + } +} + +/* --------------------------------------------------------------------- */ + +static void modulator_2666_s16(struct sm_state *sm, short *buf, unsigned int buflen) +{ + struct mod_state_afsk26 *st = (struct mod_state_afsk26 *)(&sm->m); + + for (; buflen > 0; buflen--, buf++) { + if (!st->tx_seq++) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->scram = ((st->scram << 1) | (st->scram & 1)); + st->scram ^= (!(st->shreg & 1)); + st->shreg >>= 1; + if (st->scram & (SCRAM_TAP1 << 1)) + st->scram ^= SCRAM_TAPN << 1; + st->phinc = afsk26_carfreq[!(st->scram & (SCRAM_TAP1 << 2))]; + } + if (st->tx_seq >= 6) + st->tx_seq = 0; + *buf = COS(st->bit_pll); + st->bit_pll += st->phinc; + } +} + +/* --------------------------------------------------------------------- */ + +extern __inline__ int convolution12_u8(const unsigned char *st, const int *coeff, int csum) +{ + int sum = -0x80 * csum; + + sum += (st[0] * coeff[0]); + sum += (st[-1] * coeff[1]); + sum += (st[-2] * coeff[2]); + sum += (st[-3] * coeff[3]); + sum += (st[-4] * coeff[4]); + sum += (st[-5] * coeff[5]); + sum += (st[-6] * coeff[6]); + sum += (st[-7] * coeff[7]); + sum += (st[-8] * coeff[8]); + sum += (st[-9] * coeff[9]); + sum += (st[-10] * coeff[10]); + sum += (st[-11] * coeff[11]); + + return sum; +} + +extern __inline__ int convolution12_s16(const short *st, const int *coeff, int csum) +{ + int sum = 0; + + sum += (st[0] * coeff[0]); + sum += (st[-1] * coeff[1]); + sum += (st[-2] * coeff[2]); + sum += (st[-3] * coeff[3]); + sum += (st[-4] * coeff[4]); + sum += (st[-5] * coeff[5]); + sum += (st[-6] * coeff[6]); + sum += (st[-7] * coeff[7]); + sum += (st[-8] * coeff[8]); + sum += (st[-9] * coeff[9]); + sum += (st[-10] * coeff[10]); + sum += (st[-11] * coeff[11]); + + sum >>= 8; + return sum; +} + +/* ---------------------------------------------------------------------- */ + +#if 0 +static int binexp(unsigned int i) +{ + int ret = 31; + + if (!i) + return 0; + if (i < 0x10000LU) { + i <<= 16; + ret -= 16; + } + if (i < 0x1000000LU) { + i <<= 8; + ret -= 8; + } + if (i < 0x10000000LU) { + i <<= 4; + ret -= 4; + } + if (i < 0x40000000LU) { + i <<= 2; + ret -= 2; + } + if (i < 0x80000000LU) + ret -= 1; + return ret; +} + +static const sqrt_tab[16] = { + 00000, 16384, 23170, 28378, 32768, 36636, 40132, 43348, + 46341, 49152, 51811, 54340, 56756, 59073, 61303, 63455 +}; + + +static unsigned int int_sqrt_approx(unsigned int i) +{ + unsigned int j; + + if (i < 16) + return sqrt_tab[i] >> 14; + j = binexp(i) >> 1; + i >>= (j * 2 - 2); + return (sqrt_tab[i & 0xf] << j) >> 15; +} +#endif + +/* --------------------------------------------------------------------- */ + +extern unsigned int est_pwr(int i, int q) +{ + unsigned int ui = abs(i); + unsigned int uq = abs(q); + + if (uq > ui) { + unsigned int tmp; + tmp = ui; + ui = uq; + uq = tmp; + } + if (uq > (ui >> 1)) + return 7*(ui>>3) + 9*(uq>>4); + else + return ui + (uq>>2); +} + +/* --------------------------------------------------------------------- */ + +static void demod_one_sample(struct sm_state *sm, struct demod_state_afsk26 *st, int curval, + int loi, int loq, int hii, int hiq) +{ + static const int pll_corr[2] = { -0xa00, 0xa00 }; + unsigned char curbit; + unsigned int descx; + int val; + + /* + * estimate power + */ + val = est_pwr(hii, hiq) - est_pwr(loi, loq); + /* + * estimate center value + */ + st->dem_sum[0] += val >> 8; + if ((++st->dem_cnt) >= 256) { + st->dem_cnt = 0; + st->dem_sum_mean = (st->dem_sum[0]+st->dem_sum[1]+ + st->dem_sum[2]+st->dem_sum[3]+ + st->dem_sum[4]+st->dem_sum[5]+ + st->dem_sum[6]+st->dem_sum[7]) >> 3; + memmove(st->dem_sum+1, st->dem_sum, + sizeof(st->dem_sum)-sizeof(st->dem_sum[0])); + st->dem_sum[0] = 0; + } + /* + * decision and bit clock regen + */ + val -= st->dem_sum_mean; + diag_add(sm, curval, val); + + st->dcd_shreg <<= 1; + st->bit_pll += 0x1555; + curbit = (val > 0); + if (st->last_sample ^ curbit) { + st->dcd_shreg |= 1; + st->bit_pll += pll_corr[st->bit_pll < (0x8000+0x1555)]; + st->dcd_sum0 += 4*hweight8(st->dcd_shreg & 0x1e) - + hweight16(st->dcd_shreg & 0xfe00); + } + st->last_sample = curbit; + hdlcdrv_channelbit(&sm->hdrv, curbit); + if ((--st->dcd_time) <= 0) { + hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + st->dcd_sum1 + + st->dcd_sum2) < 0); + st->dcd_sum2 = st->dcd_sum1; + st->dcd_sum1 = st->dcd_sum0; + st->dcd_sum0 = 2; /* slight bias */ + st->dcd_time = 400; + } + if (st->bit_pll >= 0x10000) { + st->bit_pll &= 0xffffu; + st->descram = (st->descram << 1) | curbit; + descx = st->descram ^ (st->descram >> 1); + descx ^= ((descx >> DESCRAM_TAPSH1) ^ + (descx >> DESCRAM_TAPSH2)); + st->shreg >>= 1; + st->shreg |= (!(descx & 1)) << 16; + if (st->shreg & 1) { + hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); + st->shreg = 0x10000; + } + diag_trigger(sm); + } +} + +/* --------------------------------------------------------------------- */ + +static void demodulator_2666_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen) +{ + struct demod_state_afsk26 *st = (struct demod_state_afsk26 *)(&sm->d); + + for (; buflen > 0; buflen--, buf++) { + demod_one_sample(sm, st, (*buf-0x80)<<8, + convolution12_u8(buf, afsk26_dem_tables[0][0].i, AFSK26_DEM_SUM_I_0_0), + convolution12_u8(buf, afsk26_dem_tables[0][0].q, AFSK26_DEM_SUM_Q_0_0), + convolution12_u8(buf, afsk26_dem_tables[0][1].i, AFSK26_DEM_SUM_I_0_1), + convolution12_u8(buf, afsk26_dem_tables[0][1].q, AFSK26_DEM_SUM_Q_0_1)); + demod_one_sample(sm, st, (*buf-0x80)<<8, + convolution12_u8(buf, afsk26_dem_tables[1][0].i, AFSK26_DEM_SUM_I_1_0), + convolution12_u8(buf, afsk26_dem_tables[1][0].q, AFSK26_DEM_SUM_Q_1_0), + convolution12_u8(buf, afsk26_dem_tables[1][1].i, AFSK26_DEM_SUM_I_1_1), + convolution12_u8(buf, afsk26_dem_tables[1][1].q, AFSK26_DEM_SUM_Q_1_1)); + } +} + +/* --------------------------------------------------------------------- */ + +static void demodulator_2666_s16(struct sm_state *sm, const short *buf, unsigned int buflen) +{ + struct demod_state_afsk26 *st = (struct demod_state_afsk26 *)(&sm->d); + + for (; buflen > 0; buflen--, buf++) { + demod_one_sample(sm, st, *buf, + convolution12_s16(buf, afsk26_dem_tables[0][0].i, AFSK26_DEM_SUM_I_0_0), + convolution12_s16(buf, afsk26_dem_tables[0][0].q, AFSK26_DEM_SUM_Q_0_0), + convolution12_s16(buf, afsk26_dem_tables[0][1].i, AFSK26_DEM_SUM_I_0_1), + convolution12_s16(buf, afsk26_dem_tables[0][1].q, AFSK26_DEM_SUM_Q_0_1)); + demod_one_sample(sm, st, *buf, + convolution12_s16(buf, afsk26_dem_tables[1][0].i, AFSK26_DEM_SUM_I_1_0), + convolution12_s16(buf, afsk26_dem_tables[1][0].q, AFSK26_DEM_SUM_Q_1_0), + convolution12_s16(buf, afsk26_dem_tables[1][1].i, AFSK26_DEM_SUM_I_1_1), + convolution12_s16(buf, afsk26_dem_tables[1][1].q, AFSK26_DEM_SUM_Q_1_1)); + } +} + +/* --------------------------------------------------------------------- */ + +static void demod_init_2666(struct sm_state *sm) +{ + struct demod_state_afsk26 *st = (struct demod_state_afsk26 *)(&sm->d); + + st->dcd_time = 400; + st->dcd_sum0 = 2; +} + +/* --------------------------------------------------------------------- */ + +const struct modem_tx_info sm_afsk2666_tx = { + "afsk2666", sizeof(struct mod_state_afsk26), AFSK26_SAMPLERATE, 2666, + modulator_2666_u8, modulator_2666_s16, NULL +}; + +const struct modem_rx_info sm_afsk2666_rx = { + "afsk2666", sizeof(struct demod_state_afsk26), AFSK26_SAMPLERATE, 2666, 12, 6, + demodulator_2666_u8, demodulator_2666_s16, demod_init_2666 +}; + +/* --------------------------------------------------------------------- */ diff --git a/drivers/net/hamradio/soundmodem/sm_psk4800.c b/drivers/net/hamradio/soundmodem/sm_psk4800.c new file mode 100644 index 000000000..cbb49042b --- /dev/null +++ b/drivers/net/hamradio/soundmodem/sm_psk4800.c @@ -0,0 +1,418 @@ +/*****************************************************************************/ + +/* + * sm_psk4800.c -- soundcard radio modem driver, 4800 baud 8PSK modem + * + * Copyright (C) 1997 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please note that the GPL allows you to use the driver, NOT the radio. + * In order to use the radio, you need a license from the communications + * authority of your country. + * + */ + +#include "sm.h" +#include "sm_tbl_psk4800.h" + +/* --------------------------------------------------------------------- */ + +#define DESCRAM_TAP1 0x20000 +#define DESCRAM_TAP2 0x01000 +#define DESCRAM_TAP3 0x00001 + +#define DESCRAM_TAPSH1 17 +#define DESCRAM_TAPSH2 12 +#define DESCRAM_TAPSH3 0 + +#define SCRAM_TAP1 0x20000 /* X^17 */ +#define SCRAM_TAPN 0x00021 /* X^0+X^5 */ + +#define SCRAM_SHIFT 17 + +/* --------------------------------------------------------------------- */ + +struct demod_state_psk48 { + /* + * input mixer and lowpass + */ + short infi[PSK48_RXF_LEN/2], infq[PSK48_RXF_LEN/2]; + unsigned int downmixer; + int ovrphase; + short magi, magq; + /* + * sampling instant recovery + */ + int pwrhist[5]; + unsigned int s_phase; + int cur_sync; + /* + * phase recovery + */ + short cur_phase_dev; + short last_ph_err; + unsigned short pskph; + unsigned int phase; + unsigned short last_pskph; + unsigned char cur_raw, last_raw, rawbits; + /* + * decoding + */ + unsigned int shreg; + unsigned long descram; + unsigned int bit_pll; + unsigned char last_sample; + unsigned int dcd_shreg; + int dcd_sum0, dcd_sum1, dcd_sum2; + unsigned int dcd_time; +}; + +struct mod_state_psk48 { + unsigned char txbits[PSK48_TXF_NUMSAMPLES]; + unsigned short txphase; + unsigned int shreg; + unsigned long scram; + const short *tbl; + unsigned int txseq; +}; + +/* --------------------------------------------------------------------- */ + +static void modulator_4800_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen) +{ + struct mod_state_psk48 *st = (struct mod_state_psk48 *)(&sm->m); + int i, j; + int si, sq; + + for (; buflen > 0; buflen--, buf++) { + if (!st->txseq++) { + memmove(st->txbits+1, st->txbits, + sizeof(st->txbits)-sizeof(st->txbits[0])); + for (i = 0; i < 3; i++) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->scram = (st->scram << 1) | + (st->shreg & 1); + st->shreg >>= 1; + if (st->scram & SCRAM_TAP1) + st->scram ^= SCRAM_TAPN; + } + j = (st->scram >> (SCRAM_SHIFT+3)) & 7; + st->txbits[0] -= (j ^ (j >> 1)); + st->txbits[0] &= 7; + st->tbl = psk48_tx_table; + } + if (st->txseq >= PSK48_TXF_OVERSAMPLING) + st->txseq = 0; + for (j = si = sq = 0; j < PSK48_TXF_NUMSAMPLES; j++, st->tbl += 16) { + si += st->tbl[st->txbits[j]]; + sq += st->tbl[st->txbits[j]+8]; + } + *buf = ((si*COS(st->txphase)+ sq*SIN(st->txphase)) >> 23) + 0x80; + st->txphase = (st->txphase + PSK48_PHASEINC) & 0xffffu; + } +} + +/* --------------------------------------------------------------------- */ + +static void modulator_4800_s16(struct sm_state *sm, short *buf, unsigned int buflen) +{ + struct mod_state_psk48 *st = (struct mod_state_psk48 *)(&sm->m); + int i, j; + int si, sq; + + for (; buflen > 0; buflen--, buf++) { + if (!st->txseq++) { + memmove(st->txbits+1, st->txbits, + sizeof(st->txbits)-sizeof(st->txbits[0])); + for (i = 0; i < 3; i++) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->scram = (st->scram << 1) | + (st->shreg & 1); + st->shreg >>= 1; + if (st->scram & SCRAM_TAP1) + st->scram ^= SCRAM_TAPN; + } + j = (st->scram >> (SCRAM_SHIFT+3)) & 7; + st->txbits[0] -= (j ^ (j >> 1)); + st->txbits[0] &= 7; + st->tbl = psk48_tx_table; + } + if (st->txseq >= PSK48_TXF_OVERSAMPLING) + st->txseq = 0; + for (j = si = sq = 0; j < PSK48_TXF_NUMSAMPLES; j++, st->tbl += 16) { + si += st->tbl[st->txbits[j]]; + sq += st->tbl[st->txbits[j]+8]; + } + *buf = (si*COS(st->txphase)+ sq*SIN(st->txphase)) >> 15; + st->txphase = (st->txphase + PSK48_PHASEINC) & 0xffffu; + } +} + +/* --------------------------------------------------------------------- */ + +static __inline__ unsigned short tbl_atan(short q, short i) +{ + short tmp; + unsigned short argoffs = 0; + + if (i == 0 && q == 0) + return 0; + switch (((q < 0) << 1) | (i < 0)) { + case 0: + break; + case 1: + tmp = q; + q = -i; + i = tmp; + argoffs = 0x4000; + break; + case 3: + q = -q; + i = -i; + argoffs = 0x8000; + break; + case 2: + tmp = -q; + q = i; + i = tmp; + argoffs = 0xc000; + break; + } + if (q > i) { + tmp = i / q * ATAN_TABLEN; + return (argoffs+0x4000-atan_tab[((i<<15)/q*ATAN_TABLEN>>15)]) + &0xffffu; + } + return (argoffs+atan_tab[((q<<15)/i*ATAN_TABLEN)>>15])&0xffffu; +} + +#define ATAN(q,i) tbl_atan(q, i) + +/* --------------------------------------------------------------------- */ + +static void demod_psk48_baseband(struct sm_state *sm, struct demod_state_psk48 *st, + short vali, short valq) +{ + int i, j; + + st->magi = vali; + st->magq = valq; + memmove(st->pwrhist+1, st->pwrhist, + sizeof(st->pwrhist)-sizeof(st->pwrhist[0])); + st->pwrhist[0] = st->magi * st->magi + + st->magq * st->magq; + st->cur_sync = ((st->pwrhist[4] >> 2) > st->pwrhist[2] && + (st->pwrhist[0] >> 2) > st->pwrhist[2] && + st-> pwrhist[3] > st->pwrhist[2] && + st->pwrhist[1] > st->pwrhist[2]); + st->s_phase &= 0xffff; + st->s_phase += PSK48_SPHASEINC; + st->dcd_shreg <<= 1; + if (st->cur_sync) { + if (st->s_phase >= (0x8000 + 5*PSK48_SPHASEINC/2)) + st->s_phase -= PSK48_SPHASEINC/6; + else + st->s_phase += PSK48_SPHASEINC/6; + st->dcd_sum0 = 4*hweight8(st->dcd_shreg & 0xf8)- + hweight16(st->dcd_shreg & 0x1f00); + } + if ((--st->dcd_time) <= 0) { + hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + st->dcd_sum1 + + st->dcd_sum2) < 0); + st->dcd_sum2 = st->dcd_sum1; + st->dcd_sum1 = st->dcd_sum0; + st->dcd_sum0 = 2; /* slight bias */ + st->dcd_time = 240; + } + if (st->s_phase < 0x10000) + return; + /* + * sample one constellation + */ + st->last_pskph = st->pskph; + st->pskph = (ATAN(st->magq, st->magi)- + st->phase) & 0xffffu; + st->last_ph_err = (st->pskph & 0x1fffu) - 0x1000; + st->phase += st->last_ph_err/16; + st->last_raw = st->cur_raw; + st->cur_raw = ((st->pskph >> 13) & 7); + i = (st->cur_raw - st->last_raw) & 7; + st->rawbits = i ^ (i >> 1) ^ (i >> 2); + st->descram = (st->descram << 3) | (st->rawbits); + hdlcdrv_channelbit(&sm->hdrv, st->descram & 4); + hdlcdrv_channelbit(&sm->hdrv, st->descram & 2); + hdlcdrv_channelbit(&sm->hdrv, st->descram & 1); + i = (((st->descram >> DESCRAM_TAPSH1) & 7) ^ + ((st->descram >> DESCRAM_TAPSH2) & 7) ^ + ((st->descram >> DESCRAM_TAPSH3) & 7)); + for (j = 4; j; j >>= 1) { + st->shreg >>= 1; + st->shreg |= (!!(i & j)) << 16; + if (st->shreg & 1) { + hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); + st->shreg = 0x10000; + } + } + +#if 0 + st->dcd_shreg <<= 1; + st->bit_pll += 0x4000; + curbit = (*buf >= 0x80); + if (st->last_sample ^ curbit) { + st->dcd_shreg |= 1; + st->bit_pll += pll_corr + [st->bit_pll < 0xa000]; + st->dcd_sum0 += 8 * + hweight8(st->dcd_shreg & 0x0c) - + !!(st->dcd_shreg & 0x10); + } + st->last_sample = curbit; + hdlcdrv_channelbit(&sm->hdrv, st->last_sample); + if ((--st->dcd_time) <= 0) { + hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + + st->dcd_sum1 + + st->dcd_sum2) < 0); + st->dcd_sum2 = st->dcd_sum1; + st->dcd_sum1 = st->dcd_sum0; + st->dcd_sum0 = 2; /* slight bias */ + st->dcd_time = 240; + } + if (st->bit_pll >= 0x10000) { + st->bit_pll &= 0xffffu; + st->descram = (st->descram << 1) | curbit; + descx = st->descram ^ (st->descram >> 1); + descx ^= ((descx >> DESCRAM_TAPSH1) ^ + (descx >> DESCRAM_TAPSH2)); + st->shreg >>= 1; + st->shreg |= (!(descx & 1)) << 16; + if (st->shreg & 1) { + hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); + st->shreg = 0x10000; + } + diag_trigger(sm); + } + diag_add_one(sm, ((short)(*buf - 0x80)) << 8); +#endif + + diag_trigger(sm); + diag_add_constellation(sm, (vali*COS(st->phase)+ valq*SIN(st->phase)) >> 13, + (valq*COS(st->phase) - vali*SIN(st->phase)) >> 13); +} + +/* --------------------------------------------------------------------- */ + +static void demodulator_4800_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen) +{ + struct demod_state_psk48 *st = (struct demod_state_psk48 *)(&sm->d); + int i, si, sq; + const short *coeff; + + for (; buflen > 0; buflen--, buf++) { + memmove(st->infi+1, st->infi, + sizeof(st->infi)-sizeof(st->infi[0])); + memmove(st->infq+1, st->infq, + sizeof(st->infq)-sizeof(st->infq[0])); + si = *buf; + si &= 0xff; + si -= 128; + diag_add_one(sm, si << 8); + st->infi[0] = (si * COS(st->downmixer))>>7; + st->infq[0] = (si * SIN(st->downmixer))>>7; + st->downmixer = (st->downmixer-PSK48_PHASEINC)&0xffffu; + for (i = si = sq = 0, coeff = psk48_rx_coeff; i < (PSK48_RXF_LEN/2); + i++, coeff += 2) { + si += st->infi[i] * (*coeff); + sq += st->infq[i] * (*coeff); + } + demod_psk48_baseband(sm, st, si >> 15, sq >> 15); + for (i = si = sq = 0, coeff = psk48_rx_coeff + 1; i < (PSK48_RXF_LEN/2); + i++, coeff += 2) { + si += st->infi[i] * (*coeff); + sq += st->infq[i] * (*coeff); + } + demod_psk48_baseband(sm, st, si >> 15, sq >> 15); + } +} + +/* --------------------------------------------------------------------- */ + +static void demodulator_4800_s16(struct sm_state *sm, const short *buf, unsigned int buflen) +{ + struct demod_state_psk48 *st = (struct demod_state_psk48 *)(&sm->d); + int i, si, sq; + const short *coeff; + + for (; buflen > 0; buflen--, buf++) { + memmove(st->infi+1, st->infi, + sizeof(st->infi)-sizeof(st->infi[0])); + memmove(st->infq+1, st->infq, + sizeof(st->infq)-sizeof(st->infq[0])); + si = *buf; + diag_add_one(sm, si); + st->infi[0] = (si * COS(st->downmixer))>>15; + st->infq[0] = (si * SIN(st->downmixer))>>15; + st->downmixer = (st->downmixer-PSK48_PHASEINC)&0xffffu; + for (i = si = sq = 0, coeff = psk48_rx_coeff; i < (PSK48_RXF_LEN/2); + i++, coeff += 2) { + si += st->infi[i] * (*coeff); + sq += st->infq[i] * (*coeff); + } + demod_psk48_baseband(sm, st, si >> 15, sq >> 15); + for (i = si = sq = 0, coeff = psk48_rx_coeff + 1; i < (PSK48_RXF_LEN/2); + i++, coeff += 2) { + si += st->infi[i] * (*coeff); + sq += st->infq[i] * (*coeff); + } + demod_psk48_baseband(sm, st, si >> 15, sq >> 15); + } +} + +/* --------------------------------------------------------------------- */ + +static void mod_init_4800(struct sm_state *sm) +{ + struct mod_state_psk48 *st = (struct mod_state_psk48 *)(&sm->m); + + st->scram = 1; +} + +/* --------------------------------------------------------------------- */ + +static void demod_init_4800(struct sm_state *sm) +{ + struct demod_state_psk48 *st = (struct demod_state_psk48 *)(&sm->d); + + st->dcd_time = 120; + st->dcd_sum0 = 2; +} + +/* --------------------------------------------------------------------- */ + +const struct modem_tx_info sm_psk4800_tx = { + "psk4800", sizeof(struct mod_state_psk48), + PSK48_SAMPLERATE, 4800, + modulator_4800_u8, modulator_4800_s16, mod_init_4800 +}; + +const struct modem_rx_info sm_psk4800_rx = { + "psk4800", sizeof(struct demod_state_psk48), + PSK48_SAMPLERATE, 4800, 1, PSK48_TXF_OVERSAMPLING, + demodulator_4800_u8, demodulator_4800_s16, demod_init_4800 +}; + +/* --------------------------------------------------------------------- */ |