Commit f9c418f6 authored by Alan Cox's avatar Alan Cox Committed by Linus Torvalds

[PATCH] kill soundmodem

It was dead before 2.4 (replaced by better userspace versions)
parent a994c542
......@@ -185,120 +185,6 @@ config BAYCOM_EPP
say M here and read <file:Documentation/modules.txt>. This is
recommended. The module will be called baycom_par.o.
config SOUNDMODEM
tristate "Soundcard modem driver"
depends on PARPORT && AX25
---help---
This experimental driver allows a standard Sound Blaster or
WindowsSoundSystem compatible sound card to be used as a packet
radio modem (NOT as a telephone modem!), to send digital traffic
over amateur radio.
To configure the driver, use the sethdlc, smdiag and smmixer
utilities available in the standard ax25 utilities package. For
information on how to key the transmitter, see
<http://www.ife.ee.ethz.ch/~sailer/pcf/ptt_circ/ptt.html> and
<file:Documentation/networking/soundmodem.txt>.
If you want to compile this driver as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
say M here and read <file:Documentation/modules.txt>. This is
recommended. The module will be called soundmodem.o.
config SOUNDMODEM_SBC
bool "soundmodem support for Soundblaster and compatible cards"
depends on SOUNDMODEM
help
This option enables the soundmodem driver to use Sound Blaster and
compatible cards. If you have a dual mode card (i.e. a WSS cards
with a Sound Blaster emulation) you should say N here and Y to
"Sound card modem support for WSS and Crystal cards", below, because
this usually results in better performance. This option also
supports SB16/32/64 in full-duplex mode.
config SOUNDMODEM_WSS
bool "soundmodem support for WSS and Crystal cards"
depends on SOUNDMODEM
help
This option enables the soundmodem driver to use WindowsSoundSystem
compatible cards. These cards feature a codec chip from either
Analog Devices (such as AD1848, AD1845, AD1812) or Crystal
Semiconductors (such as CS4248, CS423x). This option also supports
the WSS full-duplex operation which currently works with Crystal
CS423x chips. If you don't need full-duplex operation, do not enable
it to save performance.
config SOUNDMODEM_AFSK1200
bool "soundmodem support for 1200 baud AFSK modulation"
depends on SOUNDMODEM
help
This option enables the soundmodem driver 1200 baud AFSK modem,
compatible to popular modems using TCM3105 or AM7911. The
demodulator requires about 12% of the CPU power of a Pentium 75 CPU
per channel.
config SOUNDMODEM_AFSK2400_7
bool "soundmodem support for 2400 baud AFSK modulation (7.3728MHz crystal)"
depends on SOUNDMODEM
help
This option enables the soundmodem driver 2400 baud AFSK modem,
compatible to TCM3105 modems (over-)clocked with a 7.3728MHz
crystal. Note that the availability of this driver does _not_ imply
that I recommend building such links. It is only here since users
especially in eastern Europe have asked me to do so. In fact this
modulation scheme has many disadvantages, mainly its incompatibility
with many transceiver designs and the fact that the TCM3105 (if
used) is operated widely outside its specifications.
config SOUNDMODEM_AFSK2400_8
bool "soundmodem support for 2400 baud AFSK modulation (8MHz crystal)"
depends on SOUNDMODEM
help
This option enables the soundmodem driver 2400 baud AFSK modem,
compatible to TCM3105 modems (over-)clocked with an 8MHz crystal.
Note that the availability of this driver does _not_ imply that I
recommend building such links. It is only here since users
especially in eastern Europe have asked me to do so. In fact this
modulation scheme has many disadvantages, mainly its incompatibility
with many transceiver designs and the fact that the TCM3105 (if
used) is operated widely outside its specifications.
config SOUNDMODEM_AFSK2666
bool "soundmodem support for 2666 baud AFSK modulation"
depends on SOUNDMODEM
help
This option enables the soundmodem driver 2666 baud AFSK modem.
This modem is experimental, and not compatible to anything
else I know of.
config SOUNDMODEM_HAPN4800
bool "soundmodem support for 4800 baud HAPN-1 modulation"
depends on SOUNDMODEM
help
This option enables the soundmodem driver 4800 baud HAPN-1
compatible modem. This modulation seems to be widely used 'down
under' and in the Netherlands. Here, nobody uses it, so I could not
test if it works. It is compatible to itself, however :-)
config SOUNDMODEM_PSK4800
bool "soundmodem support for 4800 baud PSK modulation"
depends on SOUNDMODEM
help
This option enables the soundmodem driver 4800 baud 8PSK modem.
This modem is experimental, and not compatible to anything
else I know of.
config SOUNDMODEM_FSK9600
bool "soundmodem support for 9600 baud FSK G3RUH modulation"
depends on SOUNDMODEM
help
This option enables the soundmodem driver 9600 baud FSK modem,
compatible to the G3RUH standard. The demodulator requires about 4%
of the CPU power of a Pentium 75 CPU per channel. You can say Y to
both 1200 baud AFSK and 9600 baud FSK if you want (but obviously you
can only use one protocol at a time, depending on what the other end
can understand).
config YAM
tristate "YAM driver for AX.25"
depends on AX25
......
#
# Makefile for the soundmodem device driver.
#
obj-$(CONFIG_SOUNDMODEM) += soundmodem.o
soundmodem-y := sm.o
soundmodem-$(CONFIG_SOUNDMODEM_SBC) += sm_sbc.o
soundmodem-$(CONFIG_SOUNDMODEM_WSS) += sm_wss.o
soundmodem-$(CONFIG_SOUNDMODEM_AFSK1200) += sm_afsk1200.o
soundmodem-$(CONFIG_SOUNDMODEM_AFSK2400_7) += sm_afsk2400_7.o
soundmodem-$(CONFIG_SOUNDMODEM_AFSK2400_8) += sm_afsk2400_8.o
soundmodem-$(CONFIG_SOUNDMODEM_AFSK2666) += sm_afsk2666.o
soundmodem-$(CONFIG_SOUNDMODEM_HAPN4800) += sm_hapn4800.o
soundmodem-$(CONFIG_SOUNDMODEM_PSK4800) += sm_psk4800.o
soundmodem-$(CONFIG_SOUNDMODEM_FSK9600) += sm_fsk9600.o
soundmodem-objs := $(soundmodem-y)
host-progs := gentbl
HOST_LOADLIBES := -lm
# Files generated that shall be removed upon make clean
clean-files := sm_tbl_afsk1200.h sm_tbl_afsk2400_7.h \
sm_tbl_afsk2400_8.h sm_tbl_afsk2666.h \
sm_tbl_psk4800.h sm_tbl_hapn4800.h \
sm_tbl_fsk9600.h
include $(TOPDIR)/Rules.make
# Dependencies on generates files need to be listed explicitly
$(obj)/sm_afsk1200.o: $(obj)/sm_tbl_afsk1200.h
$(obj)/sm_afsk2400_7.o: $(obj)/sm_tbl_afsk2400_7.h
$(obj)/sm_afsk2400_8.o: $(obj)/sm_tbl_afsk2400_8.h
$(obj)/sm_afsk2666.o: $(obj)/sm_tbl_afsk2666.h
$(obj)/sm_psk4800.o: $(obj)/sm_tbl_psk4800.h
$(obj)/sm_hapn4800.o: $(obj)/sm_tbl_hapn4800.h
$(obj)/sm_fsk9600.o: $(obj)/sm_tbl_fsk9600.h
$(obj)/sm_tbl_%: $(obj)/gentbl
cd $(obj) && ./gentbl
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*****************************************************************************/
/*
* sm_afsk1200.c -- soundcard radio modem driver, 1200 baud AFSK modem
*
* Copyright (C) 1996 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_afsk1200.h"
/* --------------------------------------------------------------------- */
struct demod_state_afsk12 {
unsigned int shreg;
unsigned int bit_pll;
unsigned char last_sample;
unsigned int dcd_shreg;
int dcd_sum0, dcd_sum1, dcd_sum2;
unsigned int dcd_time;
unsigned char last_rxbit;
};
struct mod_state_afsk12 {
unsigned int shreg;
unsigned char tx_bit;
unsigned int bit_pll;
unsigned int dds_inc;
unsigned int txphase;
};
/* --------------------------------------------------------------------- */
static const int dds_inc[2] = {
AFSK12_TX_FREQ_LO*0x10000/AFSK12_SAMPLE_RATE,
AFSK12_TX_FREQ_HI*0x10000/AFSK12_SAMPLE_RATE
};
static void modulator_1200_u8(struct sm_state *sm, unsigned char *buf,
unsigned int buflen)
{
struct mod_state_afsk12 *st = (struct mod_state_afsk12 *)(&sm->m);
for (; buflen > 0; buflen--) {
if (!((st->txphase++) & 7)) {
if (st->shreg <= 1)
st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1;
st->shreg >>= 1;
}
st->dds_inc = dds_inc[st->tx_bit & 1];
*buf++ = OFFSCOS(st->bit_pll);
st->bit_pll += st->dds_inc;
}
}
/* --------------------------------------------------------------------- */
static void modulator_1200_s16(struct sm_state *sm, short *buf, unsigned int buflen)
{
struct mod_state_afsk12 *st = (struct mod_state_afsk12 *)(&sm->m);
for (; buflen > 0; buflen--) {
if (!((st->txphase++) & 7)) {
if (st->shreg <= 1)
st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1;
st->shreg >>= 1;
}
st->dds_inc = dds_inc[st->tx_bit & 1];
*buf++ = COS(st->bit_pll);
st->bit_pll += st->dds_inc;
}
}
/* --------------------------------------------------------------------- */
static __inline__ int convolution8_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 >>= 7;
return sum * sum;
}
static __inline__ int convolution8_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 >>= 15;
return sum * sum;
}
static __inline__ int do_filter_1200_u8(const unsigned char *buf)
{
int sum = convolution8_u8(buf, afsk12_tx_lo_i, SUM_AFSK12_TX_LO_I);
sum += convolution8_u8(buf, afsk12_tx_lo_q, SUM_AFSK12_TX_LO_Q);
sum -= convolution8_u8(buf, afsk12_tx_hi_i, SUM_AFSK12_TX_HI_I);
sum -= convolution8_u8(buf, afsk12_tx_hi_q, SUM_AFSK12_TX_HI_Q);
return sum;
}
static __inline__ int do_filter_1200_s16(const short *buf)
{
int sum = convolution8_s16(buf, afsk12_tx_lo_i, SUM_AFSK12_TX_LO_I);
sum += convolution8_s16(buf, afsk12_tx_lo_q, SUM_AFSK12_TX_LO_Q);
sum -= convolution8_s16(buf, afsk12_tx_hi_i, SUM_AFSK12_TX_HI_I);
sum -= convolution8_s16(buf, afsk12_tx_hi_q, SUM_AFSK12_TX_HI_Q);
return sum;
}
/* --------------------------------------------------------------------- */
static const int pll_corr[2] = { -0x1000, 0x1000 };
static void demodulator_1200_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen)
{
struct demod_state_afsk12 *st = (struct demod_state_afsk12 *)(&sm->d);
int j;
int sum;
unsigned char newsample;
for (; buflen > 0; buflen--, buf++) {
sum = do_filter_1200_u8(buf);
st->dcd_shreg <<= 1;
st->bit_pll += 0x2000;
newsample = (sum > 0);
if (st->last_sample ^ newsample) {
st->last_sample = newsample;
st->dcd_shreg |= 1;
st->bit_pll += pll_corr
[st->bit_pll < 0x9000];
j = 4 * hweight8(st->dcd_shreg & 0x38)
- hweight16(st->dcd_shreg & 0x7c0);
st->dcd_sum0 += j;
}
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 = 120;
}
if (st->bit_pll >= 0x10000) {
st->bit_pll &= 0xffff;
st->shreg >>= 1;
st->shreg |= (!(st->last_rxbit ^
st->last_sample)) << 16;
st->last_rxbit = st->last_sample;
diag_trigger(sm);
if (st->shreg & 1) {
hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1);
st->shreg = 0x10000;
}
}
diag_add(sm, (((int)*buf)-0x80) << 8, sum);
}
}
/* --------------------------------------------------------------------- */
static void demodulator_1200_s16(struct sm_state *sm, const short *buf, unsigned int buflen)
{
struct demod_state_afsk12 *st = (struct demod_state_afsk12 *)(&sm->d);
int j;
int sum;
unsigned char newsample;
for (; buflen > 0; buflen--, buf++) {
sum = do_filter_1200_s16(buf);
st->dcd_shreg <<= 1;
st->bit_pll += 0x2000;
newsample = (sum > 0);
if (st->last_sample ^ newsample) {
st->last_sample = newsample;
st->dcd_shreg |= 1;
st->bit_pll += pll_corr
[st->bit_pll < 0x9000];
j = 4 * hweight8(st->dcd_shreg & 0x38)
- hweight16(st->dcd_shreg & 0x7c0);
st->dcd_sum0 += j;
}
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 = 120;
}
if (st->bit_pll >= 0x10000) {
st->bit_pll &= 0xffff;
st->shreg >>= 1;
st->shreg |= (!(st->last_rxbit ^
st->last_sample)) << 16;
st->last_rxbit = st->last_sample;
diag_trigger(sm);
if (st->shreg & 1) {
hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1);
st->shreg = 0x10000;
}
}
diag_add(sm, *buf, sum);
}
}
/* --------------------------------------------------------------------- */
static void demod_init_1200(struct sm_state *sm)
{
struct demod_state_afsk12 *st = (struct demod_state_afsk12 *)(&sm->d);
st->dcd_time = 120;
st->dcd_sum0 = 2;
}
/* --------------------------------------------------------------------- */
const struct modem_tx_info sm_afsk1200_tx = {
"afsk1200", sizeof(struct mod_state_afsk12),
AFSK12_SAMPLE_RATE, 1200, modulator_1200_u8, modulator_1200_s16, NULL
};
const struct modem_rx_info sm_afsk1200_rx = {
"afsk1200", sizeof(struct demod_state_afsk12),
AFSK12_SAMPLE_RATE, 1200, 8, AFSK12_SAMPLE_RATE/1200,
demodulator_1200_u8, demodulator_1200_s16, demod_init_1200
};
/* --------------------------------------------------------------------- */
/*****************************************************************************/
/*
* sm_afsk2400_7.c -- soundcard radio modem driver, 2400 baud AFSK modem
*
* Copyright (C) 1996 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.
*
*/
/*
* This driver is intended to be compatible with TCM3105 modems
* overclocked to 7.3728MHz. The mark and space frequencies therefore
* lie at 3658 and 1996 Hz.
* Note that I do _not_ recommend the building of such links, I provide
* this only for the users who live in the coverage area of such
* a "legacy" link.
*/
#include "sm.h"
#include "sm_tbl_afsk2400_7.h"
/* --------------------------------------------------------------------- */
struct demod_state_afsk24 {
unsigned int shreg;
unsigned int bit_pll;
unsigned char last_sample;
unsigned int dcd_shreg;
int dcd_sum0, dcd_sum1, dcd_sum2;
unsigned int dcd_time;
unsigned char last_rxbit;
};
struct mod_state_afsk24 {
unsigned int shreg;
unsigned char tx_bit;
unsigned int bit_pll;
unsigned int tx_seq;
unsigned int phinc;
};
/* --------------------------------------------------------------------- */
static const int dds_inc[2] = { AFSK24_TX_FREQ_LO*0x10000/AFSK24_SAMPLERATE,
AFSK24_TX_FREQ_HI*0x10000/AFSK24_SAMPLERATE };
static void modulator_2400_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen)
{
struct mod_state_afsk24 *st = (struct mod_state_afsk24 *)(&sm->m);
for (; buflen > 0; buflen--, buf++) {
if (st->tx_seq < 0x5555) {
if (st->shreg <= 1)
st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1;
st->shreg >>= 1;
st->phinc = dds_inc[st->tx_bit & 1];
}
st->tx_seq += 0x5555;
st->tx_seq &= 0xffff;
*buf = OFFSCOS(st->bit_pll);
st->bit_pll += st->phinc;
}
}
/* --------------------------------------------------------------------- */
static void modulator_2400_s16(struct sm_state *sm, short *buf, unsigned int buflen)
{
struct mod_state_afsk24 *st = (struct mod_state_afsk24 *)(&sm->m);
for (; buflen > 0; buflen--, buf++) {
if (st->tx_seq < 0x5555) {
if (st->shreg <= 1)
st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1;
st->shreg >>= 1;
st->phinc = dds_inc[st->tx_bit & 1];
}
st->tx_seq += 0x5555;
st->tx_seq &= 0xffff;
*buf = COS(st->bit_pll);
st->bit_pll += st->phinc;
}
}
/* --------------------------------------------------------------------- */
static __inline__ int convolution14_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]);
sum += (st[-12] * coeff[12]);
sum += (st[-13] * coeff[13]);
sum >>= 7;
return sum * sum;
}
static __inline__ int convolution14_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 += (st[-12] * coeff[12]);
sum += (st[-13] * coeff[13]);
sum >>= 15;
return sum * sum;
}
static __inline__ int do_filter_2400_u8(const unsigned char *buf)
{
int sum = convolution14_u8(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I);
sum += convolution14_u8(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q);
sum -= convolution14_u8(buf, afsk24_tx_hi_i, SUM_AFSK24_TX_HI_I);
sum -= convolution14_u8(buf, afsk24_tx_hi_q, SUM_AFSK24_TX_HI_Q);
return sum;
}
static __inline__ int do_filter_2400_s16(const short *buf)
{
int sum = convolution14_s16(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I);
sum += convolution14_s16(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q);
sum -= convolution14_s16(buf, afsk24_tx_hi_i, SUM_AFSK24_TX_HI_I);
sum -= convolution14_s16(buf, afsk24_tx_hi_q, SUM_AFSK24_TX_HI_Q);
return sum;
}
/* --------------------------------------------------------------------- */
static void demodulator_2400_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen)
{
struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d);
int j;
int sum;
unsigned char newsample;
for (; buflen > 0; buflen--, buf++) {
sum = do_filter_2400_u8(buf);
st->dcd_shreg <<= 1;
st->bit_pll += AFSK24_BITPLL_INC;
newsample = (sum > 0);
if (st->last_sample ^ newsample) {
st->last_sample = newsample;
st->dcd_shreg |= 1;
if (st->bit_pll < (0x8000+AFSK24_BITPLL_INC/2))
st->bit_pll += AFSK24_BITPLL_INC/2;
else
st->bit_pll -= AFSK24_BITPLL_INC/2;
j = /* 2 * */ hweight8(st->dcd_shreg & 0x1c)
- hweight16(st->dcd_shreg & 0x1e0);
st->dcd_sum0 += j;
}
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 = 120;
}
if (st->bit_pll >= 0x10000) {
st->bit_pll &= 0xffff;
st->shreg >>= 1;
st->shreg |= (!(st->last_rxbit ^
st->last_sample)) << 16;
st->last_rxbit = st->last_sample;
diag_trigger(sm);
if (st->shreg & 1) {
hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1);
st->shreg = 0x10000;
}
}
diag_add(sm, (((int)*buf)-0x80) << 8, sum);
}
}
/* --------------------------------------------------------------------- */
static void demodulator_2400_s16(struct sm_state *sm, const short *buf, unsigned int buflen)
{
struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d);
int j;
int sum;
unsigned char newsample;
for (; buflen > 0; buflen--, buf++) {
sum = do_filter_2400_s16(buf);
st->dcd_shreg <<= 1;
st->bit_pll += AFSK24_BITPLL_INC;
newsample = (sum > 0);
if (st->last_sample ^ newsample) {
st->last_sample = newsample;
st->dcd_shreg |= 1;
if (st->bit_pll < (0x8000+AFSK24_BITPLL_INC/2))
st->bit_pll += AFSK24_BITPLL_INC/2;
else
st->bit_pll -= AFSK24_BITPLL_INC/2;
j = /* 2 * */ hweight8(st->dcd_shreg & 0x1c)
- hweight16(st->dcd_shreg & 0x1e0);
st->dcd_sum0 += j;
}
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 = 120;
}
if (st->bit_pll >= 0x10000) {
st->bit_pll &= 0xffff;
st->shreg >>= 1;
st->shreg |= (!(st->last_rxbit ^
st->last_sample)) << 16;
st->last_rxbit = st->last_sample;
diag_trigger(sm);
if (st->shreg & 1) {
hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1);
st->shreg = 0x10000;
}
}
diag_add(sm, *buf, sum);
}
}
/* --------------------------------------------------------------------- */
static void demod_init_2400(struct sm_state *sm)
{
struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d);
st->dcd_time = 120;
st->dcd_sum0 = 2;
}
/* --------------------------------------------------------------------- */
const struct modem_tx_info sm_afsk2400_7_tx = {
"afsk2400_7", sizeof(struct mod_state_afsk24), AFSK24_SAMPLERATE, 2400,
modulator_2400_u8, modulator_2400_s16, NULL
};
const struct modem_rx_info sm_afsk2400_7_rx = {
"afsk2400_7", sizeof(struct demod_state_afsk24),
AFSK24_SAMPLERATE, 2400, 14, AFSK24_SAMPLERATE/2400,
demodulator_2400_u8, demodulator_2400_s16, demod_init_2400
};
/* --------------------------------------------------------------------- */
/*****************************************************************************/
/*
* sm_afsk2400_8.c -- soundcard radio modem driver, 2400 baud AFSK modem
*
* Copyright (C) 1996 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.
*
*/
/*
* This driver is intended to be compatible with TCM3105 modems
* overclocked to 8MHz. The mark and space frequencies therefore
* lie at 3970 and 2165 Hz.
* Note that I do _not_ recommend the building of such links, I provide
* this only for the users who live in the coverage area of such
* a "legacy" link.
*/
#include "sm.h"
#include "sm_tbl_afsk2400_8.h"
/* --------------------------------------------------------------------- */
struct demod_state_afsk24 {
unsigned int shreg;
unsigned int bit_pll;
unsigned char last_sample;
unsigned int dcd_shreg;
int dcd_sum0, dcd_sum1, dcd_sum2;
unsigned int dcd_time;
unsigned char last_rxbit;
};
struct mod_state_afsk24 {
unsigned int shreg;
unsigned char tx_bit;
unsigned int bit_pll;
unsigned int tx_seq;
unsigned int phinc;
};
/* --------------------------------------------------------------------- */
static const int dds_inc[2] = { AFSK24_TX_FREQ_LO*0x10000/AFSK24_SAMPLERATE,
AFSK24_TX_FREQ_HI*0x10000/AFSK24_SAMPLERATE };
static void modulator_2400_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen)
{
struct mod_state_afsk24 *st = (struct mod_state_afsk24 *)(&sm->m);
for (; buflen > 0; buflen--, buf++) {
if (st->tx_seq < 0x5555) {
if (st->shreg <= 1)
st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1;
st->shreg >>= 1;
st->phinc = dds_inc[st->tx_bit & 1];
}
st->tx_seq += 0x5555;
st->tx_seq &= 0xffff;
*buf = OFFSCOS(st->bit_pll);
st->bit_pll += st->phinc;
}
}
/* --------------------------------------------------------------------- */
static void modulator_2400_s16(struct sm_state *sm, short *buf, unsigned int buflen)
{
struct mod_state_afsk24 *st = (struct mod_state_afsk24 *)(&sm->m);
for (; buflen > 0; buflen--, buf++) {
if (st->tx_seq < 0x5555) {
if (st->shreg <= 1)
st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1;
st->shreg >>= 1;
st->phinc = dds_inc[st->tx_bit & 1];
}
st->tx_seq += 0x5555;
st->tx_seq &= 0xffff;
*buf = COS(st->bit_pll);
st->bit_pll += st->phinc;
}
}
/* --------------------------------------------------------------------- */
static __inline__ int convolution14_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]);
sum += (st[-12] * coeff[12]);
sum += (st[-13] * coeff[13]);
sum >>= 7;
return sum * sum;
}
static __inline__ int convolution14_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 += (st[-12] * coeff[12]);
sum += (st[-13] * coeff[13]);
sum >>= 15;
return sum * sum;
}
static __inline__ int do_filter_2400_u8(const unsigned char *buf)
{
int sum = convolution14_u8(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I);
sum += convolution14_u8(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q);
sum -= convolution14_u8(buf, afsk24_tx_hi_i, SUM_AFSK24_TX_HI_I);
sum -= convolution14_u8(buf, afsk24_tx_hi_q, SUM_AFSK24_TX_HI_Q);
return sum;
}
static __inline__ int do_filter_2400_s16(const short *buf)
{
int sum = convolution14_s16(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I);
sum += convolution14_s16(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q);
sum -= convolution14_s16(buf, afsk24_tx_hi_i, SUM_AFSK24_TX_HI_I);
sum -= convolution14_s16(buf, afsk24_tx_hi_q, SUM_AFSK24_TX_HI_Q);
return sum;
}
/* --------------------------------------------------------------------- */
static void demodulator_2400_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen)
{
struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d);
int j;
int sum;
unsigned char newsample;
for (; buflen > 0; buflen--, buf++) {
sum = do_filter_2400_u8(buf);
st->dcd_shreg <<= 1;
st->bit_pll += AFSK24_BITPLL_INC;
newsample = (sum > 0);
if (st->last_sample ^ newsample) {
st->last_sample = newsample;
st->dcd_shreg |= 1;
if (st->bit_pll < (0x8000+AFSK24_BITPLL_INC/2))
st->bit_pll += AFSK24_BITPLL_INC/2;
else
st->bit_pll -= AFSK24_BITPLL_INC/2;
j = /* 2 * */ hweight8(st->dcd_shreg & 0x1c)
- hweight16(st->dcd_shreg & 0x1e0);
st->dcd_sum0 += j;
}
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 = 120;
}
if (st->bit_pll >= 0x10000) {
st->bit_pll &= 0xffff;
st->shreg >>= 1;
st->shreg |= (!(st->last_rxbit ^
st->last_sample)) << 16;
st->last_rxbit = st->last_sample;
diag_trigger(sm);
if (st->shreg & 1) {
hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1);
st->shreg = 0x10000;
}
}
diag_add(sm, (((int)*buf)-0x80) << 8, sum);
}
}
/* --------------------------------------------------------------------- */
static void demodulator_2400_s16(struct sm_state *sm, const short *buf, unsigned int buflen)
{
struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d);
int j;
int sum;
unsigned char newsample;
for (; buflen > 0; buflen--, buf++) {
sum = do_filter_2400_s16(buf);
st->dcd_shreg <<= 1;
st->bit_pll += AFSK24_BITPLL_INC;
newsample = (sum > 0);
if (st->last_sample ^ newsample) {
st->last_sample = newsample;
st->dcd_shreg |= 1;
if (st->bit_pll < (0x8000+AFSK24_BITPLL_INC/2))
st->bit_pll += AFSK24_BITPLL_INC/2;
else
st->bit_pll -= AFSK24_BITPLL_INC/2;
j = /* 2 * */ hweight8(st->dcd_shreg & 0x1c)
- hweight16(st->dcd_shreg & 0x1e0);
st->dcd_sum0 += j;
}
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 = 120;
}
if (st->bit_pll >= 0x10000) {
st->bit_pll &= 0xffff;
st->shreg >>= 1;
st->shreg |= (!(st->last_rxbit ^
st->last_sample)) << 16;
st->last_rxbit = st->last_sample;
diag_trigger(sm);
if (st->shreg & 1) {
hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1);
st->shreg = 0x10000;
}
}
diag_add(sm, *buf, sum);
}
}
/* --------------------------------------------------------------------- */
static void demod_init_2400(struct sm_state *sm)
{
struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d);
st->dcd_time = 120;
st->dcd_sum0 = 2;
}
/* --------------------------------------------------------------------- */
const struct modem_tx_info sm_afsk2400_8_tx = {
"afsk2400_8", sizeof(struct mod_state_afsk24), AFSK24_SAMPLERATE, 2400,
modulator_2400_u8, modulator_2400_s16, NULL
};
const struct modem_rx_info sm_afsk2400_8_rx = {
"afsk2400_8", sizeof(struct demod_state_afsk24),
AFSK24_SAMPLERATE, 2400, 14, AFSK24_SAMPLERATE/2400,
demodulator_2400_u8, demodulator_2400_s16, demod_init_2400
};
/* --------------------------------------------------------------------- */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*****************************************************************************/
/*
* smdma.h -- soundcard radio modem driver dma buffer routines.
*
* Copyright (C) 1996 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.
*
*/
#ifndef _SMDMA_H
#define _SMDMA_H
/* ---------------------------------------------------------------------- */
#include "sm.h"
/* ---------------------------------------------------------------------- */
#define DMA_MODE_AUTOINIT 0x10
#define NUM_FRAGMENTS 4
/*
* NOTE: make sure that hdlcdrv_hdlcbuffer contains enough space
* for the modulator to fill the whole DMA buffer without underrun
* at the highest possible baud rate, otherwise the TX state machine will
* not work correctly. That is (9k6 FSK): HDLCDRV_HDLCBUFFER > 6*NUM_FRAGMENTS
*/
/* --------------------------------------------------------------------- */
/*
* ===================== DMA buffer management ===========================
*/
/*
* returns the number of samples per fragment
*/
static __inline__ unsigned int dma_setup(struct sm_state *sm, int send, unsigned int dmanr)
{
if (send) {
disable_dma(dmanr);
clear_dma_ff(dmanr);
set_dma_mode(dmanr, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);
set_dma_addr(dmanr, virt_to_bus(sm->dma.obuf));
set_dma_count(dmanr, sm->dma.ofragsz * NUM_FRAGMENTS);
enable_dma(dmanr);
if (sm->dma.o16bit)
return sm->dma.ofragsz/2;
return sm->dma.ofragsz;
} else {
disable_dma(dmanr);
clear_dma_ff(dmanr);
set_dma_mode(dmanr, DMA_MODE_READ | DMA_MODE_AUTOINIT);
set_dma_addr(dmanr, virt_to_bus(sm->dma.ibuf));
set_dma_count(dmanr, sm->dma.ifragsz * NUM_FRAGMENTS);
enable_dma(dmanr);
if (sm->dma.i16bit)
return sm->dma.ifragsz/2;
return sm->dma.ifragsz;
}
}
/* --------------------------------------------------------------------- */
static __inline__ unsigned int dma_ptr(struct sm_state *sm, int send, unsigned int dmanr,
unsigned int *curfrag)
{
unsigned int dmaptr, sz, frg, offs;
dmaptr = get_dma_residue(dmanr);
if (send) {
sz = sm->dma.ofragsz * NUM_FRAGMENTS;
if (dmaptr == 0 || dmaptr > sz)
dmaptr = sz;
dmaptr--;
frg = dmaptr / sm->dma.ofragsz;
offs = (dmaptr % sm->dma.ofragsz) + 1;
*curfrag = NUM_FRAGMENTS - 1 - frg;
#ifdef SM_DEBUG
if (!sm->debug_vals.dma_residue || offs < sm->debug_vals.dma_residue)
sm->debug_vals.dma_residue = offs;
#endif /* SM_DEBUG */
if (sm->dma.o16bit)
return offs/2;
return offs;
} else {
sz = sm->dma.ifragsz * NUM_FRAGMENTS;
if (dmaptr == 0 || dmaptr > sz)
dmaptr = sz;
dmaptr--;
frg = dmaptr / sm->dma.ifragsz;
offs = (dmaptr % sm->dma.ifragsz) + 1;
*curfrag = NUM_FRAGMENTS - 1 - frg;
#ifdef SM_DEBUG
if (!sm->debug_vals.dma_residue || offs < sm->debug_vals.dma_residue)
sm->debug_vals.dma_residue = offs;
#endif /* SM_DEBUG */
if (sm->dma.i16bit)
return offs/2;
return offs;
}
}
/* --------------------------------------------------------------------- */
static __inline__ int dma_end_transmit(struct sm_state *sm, unsigned int curfrag)
{
unsigned int diff = (NUM_FRAGMENTS + curfrag - sm->dma.ofragptr) % NUM_FRAGMENTS;
sm->dma.ofragptr = curfrag;
if (sm->dma.ptt_cnt <= 0) {
sm->dma.ptt_cnt = 0;
return 0;
}
sm->dma.ptt_cnt -= diff;
if (sm->dma.ptt_cnt <= 0) {
sm->dma.ptt_cnt = 0;
return -1;
}
return 0;
}
static __inline__ void dma_transmit(struct sm_state *sm)
{
void *p;
while (sm->dma.ptt_cnt < NUM_FRAGMENTS && hdlcdrv_ptt(&sm->hdrv)) {
p = (unsigned char *)sm->dma.obuf + sm->dma.ofragsz *
((sm->dma.ofragptr + sm->dma.ptt_cnt) % NUM_FRAGMENTS);
if (sm->dma.o16bit) {
time_exec(sm->debug_vals.mod_cyc,
sm->mode_tx->modulator_s16(sm, p, sm->dma.ofragsz/2));
} else {
time_exec(sm->debug_vals.mod_cyc,
sm->mode_tx->modulator_u8(sm, p, sm->dma.ofragsz));
}
sm->dma.ptt_cnt++;
}
}
static __inline__ void dma_init_transmit(struct sm_state *sm)
{
sm->dma.ofragptr = 0;
sm->dma.ptt_cnt = 0;
}
static __inline__ void dma_start_transmit(struct sm_state *sm)
{
sm->dma.ofragptr = 0;
if (sm->dma.o16bit) {
time_exec(sm->debug_vals.mod_cyc,
sm->mode_tx->modulator_s16(sm, sm->dma.obuf, sm->dma.ofragsz/2));
} else {
time_exec(sm->debug_vals.mod_cyc,
sm->mode_tx->modulator_u8(sm, sm->dma.obuf, sm->dma.ofragsz));
}
sm->dma.ptt_cnt = 1;
}
static __inline__ void dma_clear_transmit(struct sm_state *sm)
{
sm->dma.ptt_cnt = 0;
memset(sm->dma.obuf, (sm->dma.o16bit) ? 0 : 0x80, sm->dma.ofragsz * NUM_FRAGMENTS);
}
/* --------------------------------------------------------------------- */
static __inline__ void dma_receive(struct sm_state *sm, unsigned int curfrag)
{
void *p;
while (sm->dma.ifragptr != curfrag) {
if (sm->dma.ifragptr)
p = (unsigned char *)sm->dma.ibuf +
sm->dma.ifragsz * sm->dma.ifragptr;
else {
p = (unsigned char *)sm->dma.ibuf + NUM_FRAGMENTS * sm->dma.ifragsz;
memcpy(p, sm->dma.ibuf, sm->dma.ifragsz);
}
if (sm->dma.o16bit) {
time_exec(sm->debug_vals.demod_cyc,
sm->mode_rx->demodulator_s16(sm, p, sm->dma.ifragsz/2));
} else {
time_exec(sm->debug_vals.demod_cyc,
sm->mode_rx->demodulator_u8(sm, p, sm->dma.ifragsz));
}
sm->dma.ifragptr = (sm->dma.ifragptr + 1) % NUM_FRAGMENTS;
}
}
static __inline__ void dma_init_receive(struct sm_state *sm)
{
sm->dma.ifragptr = 0;
}
/* --------------------------------------------------------------------- */
#endif /* _SMDMA_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment