diff options
author | russell <russell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2007-09-14 15:42:42 +0000 |
---|---|---|
committer | russell <russell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2007-09-14 15:42:42 +0000 |
commit | 4b7add369a1a77105a5f2738eb4e8c68be8b7c46 (patch) | |
tree | adad85f05da59260b14f303c965bb79c12176d8b | |
parent | eb84605afa03401d6cd92501b72e9b1112fd3247 (diff) |
Remove chan_usbradio from the main 1.4 branch. It can't live here because we
have a strict policy to not include new features in release branches. However,
I'm going to merge it into trunk, and I also have a special 1.4 based branch that
includes this module.
svn co http://svn.digium.com/svn/asterisk/team/jdixon/chan_usbradio-1.4
git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.4@82382 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r-- | channels/Makefile | 6 | ||||
-rw-r--r-- | channels/chan_usbradio.c | 2812 | ||||
-rwxr-xr-x | channels/xpmr/LICENSE | 341 | ||||
-rwxr-xr-x | channels/xpmr/sinetabx.h | 300 | ||||
-rwxr-xr-x | channels/xpmr/xpmr.c | 2266 | ||||
-rwxr-xr-x | channels/xpmr/xpmr.h | 553 | ||||
-rwxr-xr-x | channels/xpmr/xpmr_coef.h | 963 |
7 files changed, 0 insertions, 7241 deletions
diff --git a/channels/Makefile b/channels/Makefile index 7aea7d857..beba0d1ff 100644 --- a/channels/Makefile +++ b/channels/Makefile @@ -116,9 +116,3 @@ misdn/isdn_lib.o: ASTCFLAGS+=-Wno-strict-aliasing $(if $(filter chan_misdn,$(EMBEDDED_MODS)),modules.link,chan_misdn.so): chan_misdn.o misdn_config.o misdn/isdn_lib.o misdn/isdn_msg_parser.o chan_vpb.oo: ASTCFLAGS:=$(filter-out -Wdeclaration-after-statement,$(ASTCFLAGS)) - -chan_usbradio.o: chan_usbradio.c xpmr/xpmr.c xpmr/xpmr.h xpmr/xpmr_coef.h xpmr/sinetabx.h busy.h ringtone.h - -chan_usbradio.so: LIBS+=-lusb -lasound - - diff --git a/channels/chan_usbradio.c b/channels/chan_usbradio.c deleted file mode 100644 index 570f5b569..000000000 --- a/channels/chan_usbradio.c +++ /dev/null @@ -1,2812 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2005, Digium, Inc. - * Copyright (C) 2007, Jim Dixon - * - * Jim Dixon, WB6NIL <jim@lambdatel.com> - * Steve Henke, W9SH <w9sh@arrl.net> - * Based upon work by Mark Spencer <markster@digium.com> and Luigi Rizzo - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*! \file - * - * \brief Channel driver for CM108 USB Cards with Radio Interface - * - * \author Jim Dixon <jim@lambdatel.com> - * \author Steve Henke <w9sh@arrl.net> - * - * \par See also - * \arg \ref Config_usbradio - * - * \ingroup channel_drivers - */ - -/*** MODULEINFO - <depend>ossaudio</depend> - <defaultenabled>no</defaultenabled> - ***/ - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include <stdio.h> -#include <ctype.h> -#include <math.h> -#include <string.h> -#include <unistd.h> -#include <sys/ioctl.h> -#include <fcntl.h> -#include <sys/time.h> -#include <stdlib.h> -#include <errno.h> -#include <usb.h> -#include <alsa/asoundlib.h> - -#define CHAN_USBRADIO 1 - -#define DEBUG_USBRADIO 0 -#define DEBUG_CAPTURES 1 - -#define DEBUG_CAP_RX_OUT 0 -#define DEBUG_CAP_TX_OUT 0 - -#define DEBUG_FILETEST 0 - -#define RX_CAP_RAW_FILE "/tmp/rx_cap_in.pcm" -#define RX_CAP_TRACE_FILE "/tmp/rx_trace.pcm" -#define RX_CAP_OUT_FILE "/tmp/rx_cap_out.pcm" - -#define TX_CAP_RAW_FILE "/tmp/tx_cap_in.pcm" -#define TX_CAP_TRACE_FILE "/tmp/tx_trace.pcm" -#define TX_CAP_OUT_FILE "/tmp/tx_cap_out.pcm" - -#define MIXER_PARAM_MIC_PLAYBACK_SW "Mic Playback Switch" -#define MIXER_PARAM_MIC_PLAYBACK_VOL "Mic Playback Volume" -#define MIXER_PARAM_MIC_CAPTURE_SW "Mic Capture Switch" -#define MIXER_PARAM_MIC_CAPTURE_VOL "Mic Capture Volume" -#define MIXER_PARAM_MIC_BOOST "Auto Gain Control" -#define MIXER_PARAM_SPKR_PLAYBACK_SW "Speaker Playback Switch" -#define MIXER_PARAM_SPKR_PLAYBACK_VOL "Speaker Playback Volume" - -#include "./xpmr/xpmr.h" - -#if 0 -#define traceusb1(a) {printf a;} -#else -#define traceusb1(a) -#endif - -#if 0 -#define traceusb2(a) {printf a;} -#else -#define traceusb2(a) -#endif - -#ifdef __linux -#include <linux/soundcard.h> -#elif defined(__FreeBSD__) -#include <sys/soundcard.h> -#else -#include <soundcard.h> -#endif - -#include "asterisk/lock.h" -#include "asterisk/frame.h" -#include "asterisk/logger.h" -#include "asterisk/callerid.h" -#include "asterisk/channel.h" -#include "asterisk/module.h" -#include "asterisk/options.h" -#include "asterisk/pbx.h" -#include "asterisk/config.h" -#include "asterisk/cli.h" -#include "asterisk/utils.h" -#include "asterisk/causes.h" -#include "asterisk/endian.h" -#include "asterisk/stringfields.h" -#include "asterisk/abstract_jb.h" -#include "asterisk/musiconhold.h" -#include "asterisk/dsp.h" - -/* ringtones we use */ -#include "busy.h" -#include "ringtone.h" -#include "ring10.h" -#include "answer.h" - -#define C108_VENDOR_ID 0x0d8c -#define C108_PRODUCT_ID 0x000c -#define C108_HID_INTERFACE 3 - -#define HID_REPORT_GET 0x01 -#define HID_REPORT_SET 0x09 - -#define HID_RT_INPUT 0x01 -#define HID_RT_OUTPUT 0x02 - -/*! Global jitterbuffer configuration - by default, jb is disabled */ -static struct ast_jb_conf default_jbconf = -{ - .flags = 0, - .max_size = -1, - .resync_threshold = -1, - .impl = "", -}; -static struct ast_jb_conf global_jbconf; - -/* - * usbradio.conf parameters are -START_CONFIG - -[general] - ; General config options, with default values shown. - ; You should use one section per device, with [general] being used - ; for the device. - ; - ; - ; debug = 0x0 ; misc debug flags, default is 0 - - ; Set the device to use for I/O - ; devicenum = 0 - ; Set hardware type here - ; hdwtype=0 ; 0=limey, 1=sph - - ; rxboostset=0 ; no rx gain boost - ; rxctcssrelax=1 ; reduce talkoff from radios w/o CTCSS Tx HPF - ; rxctcssfreq=100.0 ; rx ctcss freq in floating point. must be in table - ; txctcssfreq=100.0 ; tx ctcss freq, any frequency permitted - - ; carrierfrom=dsp ;no,usb,usbinvert,dsp,vox - ; ctcssfrom=dsp ;no,usb,dsp - - ; rxdemod=flat ; input type from radio: no,speaker,flat - ; txprelim=yes ; output is pre-emphasised and limited - ; txtoctype=no ; no,phase,notone - - ; txmixa=composite ;no,voice,tone,composite,auxvoice - ; txmixb=no ;no,voice,tone,composite,auxvoice - - ; invertptt=0 - - ;------------------------------ JITTER BUFFER CONFIGURATION -------------------------- - ; jbenable = yes ; Enables the use of a jitterbuffer on the receiving side of an - ; USBRADIO channel. Defaults to "no". An enabled jitterbuffer will - ; be used only if the sending side can create and the receiving - ; side can not accept jitter. The USBRADIO channel can't accept jitter, - ; thus an enabled jitterbuffer on the receive USBRADIO side will always - ; be used if the sending side can create jitter. - - ; jbmaxsize = 200 ; Max length of the jitterbuffer in milliseconds. - - ; jbresyncthreshold = 1000 ; Jump in the frame timestamps over which the jitterbuffer is - ; resynchronized. Useful to improve the quality of the voice, with - ; big jumps in/broken timestamps, usualy sent from exotic devices - ; and programs. Defaults to 1000. - - ; jbimpl = fixed ; Jitterbuffer implementation, used on the receiving side of an USBRADIO - ; channel. Two implementations are currenlty available - "fixed" - ; (with size always equals to jbmax-size) and "adaptive" (with - ; variable size, actually the new jb of IAX2). Defaults to fixed. - - ; jblog = no ; Enables jitterbuffer frame logging. Defaults to "no". - ;----------------------------------------------------------------------------------- - - -END_CONFIG - - */ - -/* - * Helper macros to parse config arguments. They will go in a common - * header file if their usage is globally accepted. In the meantime, - * we define them here. Typical usage is as below. - * Remember to open a block right before M_START (as it declares - * some variables) and use the M_* macros WITHOUT A SEMICOLON: - * - * { - * M_START(v->name, v->value) - * - * M_BOOL("dothis", x->flag1) - * M_STR("name", x->somestring) - * M_F("bar", some_c_code) - * M_END(some_final_statement) - * ... other code in the block - * } - * - * XXX NOTE these macros should NOT be replicated in other parts of asterisk. - * Likely we will come up with a better way of doing config file parsing. - */ -#define M_START(var, val) \ - char *__s = var; char *__val = val; -#define M_END(x) x; -#define M_F(tag, f) if (!strcasecmp((__s), tag)) { f; } else -#define M_BOOL(tag, dst) M_F(tag, (dst) = ast_true(__val) ) -#define M_UINT(tag, dst) M_F(tag, (dst) = strtoul(__val, NULL, 0) ) -#define M_STR(tag, dst) M_F(tag, ast_copy_string(dst, __val, sizeof(dst))) - -/* - * The following parameters are used in the driver: - * - * FRAME_SIZE the size of an audio frame, in samples. - * 160 is used almost universally, so you should not change it. - * - * FRAGS the argument for the SETFRAGMENT ioctl. - * Overridden by the 'frags' parameter in usbradio.conf - * - * Bits 0-7 are the base-2 log of the device's block size, - * bits 16-31 are the number of blocks in the driver's queue. - * There are a lot of differences in the way this parameter - * is supported by different drivers, so you may need to - * experiment a bit with the value. - * A good default for linux is 30 blocks of 64 bytes, which - * results in 6 frames of 320 bytes (160 samples). - * FreeBSD works decently with blocks of 256 or 512 bytes, - * leaving the number unspecified. - * Note that this only refers to the device buffer size, - * this module will then try to keep the lenght of audio - * buffered within small constraints. - * - * QUEUE_SIZE The max number of blocks actually allowed in the device - * driver's buffer, irrespective of the available number. - * Overridden by the 'queuesize' parameter in usbradio.conf - * - * Should be >=2, and at most as large as the hw queue above - * (otherwise it will never be full). - */ - -#define FRAME_SIZE 160 -#define QUEUE_SIZE 20 - -#if defined(__FreeBSD__) -#define FRAGS 0x8 -#else -#define FRAGS ( ( (6 * 5) << 16 ) | 0xc ) -#endif - -/* - * XXX text message sizes are probably 256 chars, but i am - * not sure if there is a suitable definition anywhere. - */ -#define TEXT_SIZE 256 - -#if 0 -#define TRYOPEN 1 /* try to open on startup */ -#endif -#define O_CLOSE 0x444 /* special 'close' mode for device */ -/* Which device to use */ -#if defined( __OpenBSD__ ) || defined( __NetBSD__ ) -#define DEV_DSP "/dev/audio" -#else -#define DEV_DSP "/dev/dsp" -#endif - -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif -#ifndef MAX -#define MAX(a,b) ((a) > (b) ? (a) : (b)) -#endif - -static char *config = "usbradio.conf"; /* default config file */ -static char *config1 = "usbradio_tune.conf"; /* tune config file */ - -static FILE *frxcapraw = NULL, *frxcaptrace = NULL, *frxoutraw = NULL; -static FILE *ftxcapraw = NULL, *ftxcaptrace = NULL, *ftxoutraw = NULL; - -static int usbradio_debug; -#if 0 //maw asdf sph -static int usbradio_debug_level = 0; -#endif - -enum {RX_AUDIO_NONE,RX_AUDIO_SPEAKER,RX_AUDIO_FLAT}; -enum {CD_IGNORE,CD_XPMR_NOISE,CD_XPMR_VOX,CD_HID,CD_HID_INVERT}; -enum {SD_IGNORE,SD_HID,SD_HID_INVERT,SD_XPMR}; // no,external,externalinvert,software -enum {RX_KEY_CARRIER,RX_KEY_CARRIER_CODE}; -enum {TX_OUT_OFF,TX_OUT_VOICE,TX_OUT_LSD,TX_OUT_COMPOSITE,TX_OUT_AUX}; -enum {TOC_NONE,TOC_PHASE,TOC_NOTONE}; - -/* DECLARE STRUCTURES */ - -/* - * Each sound is made of 'datalen' samples of sound, repeated as needed to - * generate 'samplen' samples of data, then followed by 'silencelen' samples - * of silence. The loop is repeated if 'repeat' is set. - */ -struct sound { - int ind; - char *desc; - short *data; - int datalen; - int samplen; - int silencelen; - int repeat; -}; - -static struct sound sounds[] = { - { AST_CONTROL_RINGING, "RINGING", ringtone, sizeof(ringtone)/2, 16000, 32000, 1 }, - { AST_CONTROL_BUSY, "BUSY", busy, sizeof(busy)/2, 4000, 4000, 1 }, - { AST_CONTROL_CONGESTION, "CONGESTION", busy, sizeof(busy)/2, 2000, 2000, 1 }, - { AST_CONTROL_RING, "RING10", ring10, sizeof(ring10)/2, 16000, 32000, 1 }, - { AST_CONTROL_ANSWER, "ANSWER", answer, sizeof(answer)/2, 2200, 0, 0 }, - { -1, NULL, 0, 0, 0, 0 }, /* end marker */ -}; - - -/* - * descriptor for one of our channels. - * There is one used for 'default' values (from the [general] entry in - * the configuration file), and then one instance for each device - * (the default is cloned from [general], others are only created - * if the relevant section exists). - */ -struct chan_usbradio_pvt { - struct chan_usbradio_pvt *next; - - char *name; - /* - * cursound indicates which in struct sound we play. -1 means nothing, - * any other value is a valid sound, in which case sampsent indicates - * the next sample to send in [0..samplen + silencelen] - * nosound is set to disable the audio data from the channel - * (so we can play the tones etc.). - */ - int sndcmd[2]; /* Sound command pipe */ - int cursound; /* index of sound to send */ - int sampsent; /* # of sound samples sent */ - int nosound; /* set to block audio from the PBX */ - - int total_blocks; /* total blocks in the output device */ - int sounddev; - enum { M_UNSET, M_FULL, M_READ, M_WRITE } duplex; - i16 cdMethod; - int autoanswer; - int autohangup; - int hookstate; - unsigned int queuesize; /* max fragments in queue */ - unsigned int frags; /* parameter for SETFRAGMENT */ - - int warned; /* various flags used for warnings */ -#define WARN_used_blocks 1 -#define WARN_speed 2 -#define WARN_frag 4 - int w_errors; /* overfull in the write path */ - struct timeval lastopen; - - int overridecontext; - int mute; - - /* boost support. BOOST_SCALE * 10 ^(BOOST_MAX/20) must - * be representable in 16 bits to avoid overflows. - */ -#define BOOST_SCALE (1<<9) -#define BOOST_MAX 40 /* slightly less than 7 bits */ - int boost; /* input boost, scaled by BOOST_SCALE */ - char devicenum; - int spkrmax; - int micmax; - - pthread_t sthread; - pthread_t hidthread; - - int stophid; - struct ast_channel *owner; - char ext[AST_MAX_EXTENSION]; - char ctx[AST_MAX_CONTEXT]; - char language[MAX_LANGUAGE]; - char cid_name[256]; /*XXX */ - char cid_num[256]; /*XXX */ - char mohinterpret[MAX_MUSICCLASS]; - - /* buffers used in usbradio_write, 2 per int by 2 channels by 6 times oversampling (48KS/s) */ - char usbradio_write_buf[FRAME_SIZE * 2 * 2 * 6]; - char usbradio_write_buf_1[FRAME_SIZE * 2 * 2* 6]; - - int usbradio_write_dst; - /* buffers used in usbradio_read - AST_FRIENDLY_OFFSET space for headers - * plus enough room for a full frame - */ - char usbradio_read_buf[FRAME_SIZE * (2 * 12) + AST_FRIENDLY_OFFSET]; - char usbradio_read_buf_8k[FRAME_SIZE * 2 + AST_FRIENDLY_OFFSET]; - int readpos; /* read position above */ - struct ast_frame read_f; /* returned by usbradio_read */ - - - char debuglevel; - char radioduplex; // - - char lastrx; - char rxhidsq; - char rxcarrierdetect; // status from pmr channel - char rxctcssdecode; // status from pmr channel - - char rxkeytype; - char rxkeyed; // indicates rx signal present - - char lasttx; - char txkeyed; // tx key request from upper layers - char txchankey; - char txtestkey; - - time_t lasthidtime; - struct ast_dsp *dsp; - - t_pmr_chan *pmrChan; - - char rxcpusaver; - char txcpusaver; - - char rxdemod; - float rxgain; - char rxcdtype; - char rxsdtype; - int rxsquelchadj; /* this copy needs to be here for initialization */ - char txtoctype; - - char txprelim; - float txctcssgain; - char txmixa; - char txmixb; - - char invertptt; - - char rxctcssrelax; - float rxctcssgain; - float rxctcssfreq; - float txctcssfreq; - - int rxmixerset; - int rxboostset; - float rxvoiceadj; - float rxctcssadj; - int txmixaset; - int txmixbset; - int txctcssadj; - - int hdwtype; - int hid_gpio_ctl; - int hid_gpio_ctl_loc; - int hid_io_cor; - int hid_io_cor_loc; - int hid_io_ctcss; - int hid_io_ctcss_loc; - int hid_io_ptt; - int hid_gpio_loc; - - struct { - unsigned rxcapraw:1; - unsigned txcapraw:1; - unsigned txcap2:1; - unsigned rxcap2:1; - }b; -}; - -// maw add additional defaults !!! -static struct chan_usbradio_pvt usbradio_default = { - .cursound = -1, - .sounddev = -1, - .duplex = M_UNSET, /* XXX check this */ - .autoanswer = 1, - .autohangup = 1, - .queuesize = QUEUE_SIZE, - .frags = FRAGS, - .ext = "s", - .ctx = "default", - .readpos = AST_FRIENDLY_OFFSET, /* start here on reads */ - .lastopen = { 0, 0 }, - .boost = BOOST_SCALE, -}; - -/* DECLARE FUNCTION PROTOTYPES */ - -static void store_txtoctype(struct chan_usbradio_pvt *o, char *s); -static int hidhdwconfig(struct chan_usbradio_pvt *o); -static int set_txctcss_level(struct chan_usbradio_pvt *o); -static void pmrdump(struct chan_usbradio_pvt *o); -static void mult_set(struct chan_usbradio_pvt *o); -static int mult_calc(int value); -static void mixer_write(struct chan_usbradio_pvt *o); -static void tune_rxinput(struct chan_usbradio_pvt *o); -static void tune_rxvoice(struct chan_usbradio_pvt *o); -static void tune_rxctcss(struct chan_usbradio_pvt *o); -static void tune_txoutput(struct chan_usbradio_pvt *o, int value); -static void tune_write(struct chan_usbradio_pvt *o); - -static char *usbradio_active; /* the active device */ - -static int setformat(struct chan_usbradio_pvt *o, int mode); - -static struct ast_channel *usbradio_request(const char *type, int format, void *data -, int *cause); -static int usbradio_digit_begin(struct ast_channel *c, char digit); -static int usbradio_digit_end(struct ast_channel *c, char digit, unsigned int duration); -static int usbradio_text(struct ast_channel *c, const char *text); -static int usbradio_hangup(struct ast_channel *c); -static int usbradio_answer(struct ast_channel *c); -static struct ast_frame *usbradio_read(struct ast_channel *chan); -static int usbradio_call(struct ast_channel *c, char *dest, int timeout); -static int usbradio_write(struct ast_channel *chan, struct ast_frame *f); -static int usbradio_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen); -static int usbradio_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); - -#if DEBUG_FILETEST == 1 -static int RxTestIt(struct chan_usbradio_pvt *o); -#endif - -static char tdesc[] = "USB (CM108) Radio Channel Driver"; - -static const struct ast_channel_tech usbradio_tech = { - .type = "Radio", - .description = tdesc, - .capabilities = AST_FORMAT_SLINEAR, - .requester = usbradio_request, - .send_digit_begin = usbradio_digit_begin, - .send_digit_end = usbradio_digit_end, - .send_text = usbradio_text, - .hangup = usbradio_hangup, - .answer = usbradio_answer, - .read = usbradio_read, - .call = usbradio_call, - .write = usbradio_write, - .indicate = usbradio_indicate, - .fixup = usbradio_fixup, -}; - -/* Call with: devnum: alsa major device number, param: ascii Formal -Parameter Name, val1, first or only value, val2 second value, or 0 -if only 1 value. Values: 0-99 (percent) or 0-1 for baboon. - -Note: must add -lasound to end of linkage */ - -static int amixer_max(int devnum,char *param) -{ -int rv,type; -char str[100]; -snd_hctl_t *hctl; -snd_ctl_elem_id_t *id; -snd_hctl_elem_t *elem; -snd_ctl_elem_info_t *info; - - sprintf(str,"hw:%d",devnum); - if (snd_hctl_open(&hctl, str, 0)) return(-1); - snd_hctl_load(hctl); - snd_ctl_elem_id_alloca(&id); - snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER); - snd_ctl_elem_id_set_name(id, param); - elem = snd_hctl_find_elem(hctl, id); - if (!elem) - { - snd_hctl_close(hctl); - return(-1); - } - snd_ctl_elem_info_alloca(&info); - snd_hctl_elem_info(elem,info); - type = snd_ctl_elem_info_get_type(info); - rv = 0; - switch(type) - { - case SND_CTL_ELEM_TYPE_INTEGER: - rv = snd_ctl_elem_info_get_max(info); - break; - case SND_CTL_ELEM_TYPE_BOOLEAN: - rv = 1; - break; - } - snd_hctl_close(hctl); - return(rv); -} - -/* Call with: devnum: alsa major device number, param: ascii Formal -Parameter Name, val1, first or only value, val2 second value, or 0 -if only 1 value. Values: 0-99 (percent) or 0-1 for baboon. - -Note: must add -lasound to end of linkage */ - -static int setamixer(int devnum,char *param, int v1, int v2) -{ -int type; -char str[100]; -snd_hctl_t *hctl; -snd_ctl_elem_id_t *id; -snd_ctl_elem_value_t *control; -snd_hctl_elem_t *elem; -snd_ctl_elem_info_t *info; - - sprintf(str,"hw:%d",devnum); - if (snd_hctl_open(&hctl, str, 0)) return(-1); - snd_hctl_load(hctl); - snd_ctl_elem_id_alloca(&id); - snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER); - snd_ctl_elem_id_set_name(id, param); - elem = snd_hctl_find_elem(hctl, id); - if (!elem) - { - snd_hctl_close(hctl); - return(-1); - } - snd_ctl_elem_info_alloca(&info); - snd_hctl_elem_info(elem,info); - type = snd_ctl_elem_info_get_type(info); - snd_ctl_elem_value_alloca(&control); - snd_ctl_elem_value_set_id(control, id); - switch(type) - { - case SND_CTL_ELEM_TYPE_INTEGER: - snd_ctl_elem_value_set_integer(control, 0, v1); - if (v2 > 0) snd_ctl_elem_value_set_integer(control, 1, v2); - break; - case SND_CTL_ELEM_TYPE_BOOLEAN: - snd_ctl_elem_value_set_integer(control, 0, (v1 != 0)); - break; - } - if (snd_hctl_elem_write(elem, control)) - { - snd_hctl_close(hctl); - return(-1); - } - snd_hctl_close(hctl); - return(0); -} - -static void hid_set_outputs(struct usb_dev_handle *handle, - unsigned char *outputs) -{ - usb_control_msg(handle, - USB_ENDPOINT_OUT + USB_TYPE_CLASS + USB_RECIP_INTERFACE, - HID_REPORT_SET, - 0 + (HID_RT_OUTPUT << 8), - C108_HID_INTERFACE, - (char*)outputs, 4, 5000); -} - -static void hid_get_inputs(struct usb_dev_handle *handle, - unsigned char *inputs) -{ - usb_control_msg(handle, - USB_ENDPOINT_IN + USB_TYPE_CLASS + USB_RECIP_INTERFACE, - HID_REPORT_GET, - 0 + (HID_RT_INPUT << 8), - C108_HID_INTERFACE, - (char*)inputs, 4, 5000); -} - -static struct usb_device *hid_device_init(void) -{ - struct usb_bus *usb_bus; - struct usb_device *dev; - usb_init(); - usb_find_busses(); - usb_find_devices(); - for (usb_bus = usb_busses; - usb_bus; - usb_bus = usb_bus->next) { - for (dev = usb_bus->devices; - dev; - dev = dev->next) { - if ((dev->descriptor.idVendor - == C108_VENDOR_ID) && - (dev->descriptor.idProduct - == C108_PRODUCT_ID)) - return dev; - } - } - return NULL; -} - -static int hidhdwconfig(struct chan_usbradio_pvt *o) -{ - if(o->hdwtype==1) //sphusb - { - o->hid_gpio_ctl = 0x08; /* set GPIO4 to output mode */ - o->hid_gpio_ctl_loc = 2; /* For CTL of GPIO */ - o->hid_io_cor = 4; /* GPIO3 is COR */ - o->hid_io_cor_loc = 1; /* GPIO3 is COR */ - o->hid_io_ctcss = 2; /* GPIO 2 is External CTCSS */ - o->hid_io_ctcss_loc = 1; /* is GPIO 2 */ - o->hid_io_ptt = 8; /* GPIO 4 is PTT */ - o->hid_gpio_loc = 1; /* For ALL GPIO */ - } - else if(o->hdwtype==0) //dudeusb - { - o->hid_gpio_ctl = 0x0c; /* set GPIO 3 & 4 to output mode */ - o->hid_gpio_ctl_loc = 2; /* For CTL of GPIO */ - o->hid_io_cor = 2; /* VOLD DN is COR */ - o->hid_io_cor_loc = 0; /* VOL DN COR */ - o->hid_io_ctcss = 2; /* GPIO 2 is External CTCSS */ - o->hid_io_ctcss_loc = 1; /* is GPIO 2 */ - o->hid_io_ptt = 4; /* GPIO 3 is PTT */ - o->hid_gpio_loc = 1; /* For ALL GPIO */ - } - else if(o->hdwtype==3) // custom version - { - o->hid_gpio_ctl = 0x0c; /* set GPIO 3 & 4 to output mode */ - o->hid_gpio_ctl_loc = 2; /* For CTL of GPIO */ - o->hid_io_cor = 2; /* VOLD DN is COR */ - o->hid_io_cor_loc = 0; /* VOL DN COR */ - o->hid_io_ctcss = 2; /* GPIO 2 is External CTCSS */ - o->hid_io_ctcss_loc = 1; /* is GPIO 2 */ - o->hid_io_ptt = 4; /* GPIO 3 is PTT */ - o->hid_gpio_loc = 1; /* For ALL GPIO */ - } - - return 0; -} - - -static void *hidthread(void *arg) -{ - unsigned char buf[4],keyed; - char lastrx, txtmp; - struct usb_device *usb_dev; - struct usb_dev_handle *usb_handle; - struct chan_usbradio_pvt *o = (struct chan_usbradio_pvt *) arg; - - usb_dev = hid_device_init(); - if (usb_dev == NULL) { - ast_log(LOG_ERROR,"USB HID device not found\n"); - pthread_exit(NULL); - } - usb_handle = usb_open(usb_dev); - if (usb_handle == NULL) { - ast_log(LOG_ERROR,"Not able to open USB device\n"); - pthread_exit(NULL); - } - if (usb_claim_interface(usb_handle,C108_HID_INTERFACE) < 0) - { - if (usb_detach_kernel_driver_np(usb_handle,C108_HID_INTERFACE) < 0) { - ast_log(LOG_ERROR,"Not able to detach the USB device\n"); - pthread_exit(NULL); - } - if (usb_claim_interface(usb_handle,C108_HID_INTERFACE) < 0) { - ast_log(LOG_ERROR,"Not able to claim the USB device\n"); - pthread_exit(NULL); - } - } - memset(buf,0,sizeof(buf)); - buf[2] = o->hid_gpio_ctl; - buf[1] = 0; - hid_set_outputs(usb_handle,buf); - traceusb1(("hidthread: Starting normally!!\n")); - lastrx = 0; - while(!o->stophid) - { - buf[o->hid_gpio_ctl_loc] = o->hid_gpio_ctl; - hid_get_inputs(usb_handle,buf); - keyed = !(buf[o->hid_io_cor_loc] & o->hid_io_cor); - if (keyed != o->rxhidsq) - { - if(o->debuglevel)printf("chan_usbradio() hidthread: update rxhidsq = %d\n",keyed); - o->rxhidsq=keyed; - } - - /* if change in tx stuff */ - txtmp=0; - if(o->txkeyed || o->txchankey || o->txtestkey || o->pmrChan->txPttOut) txtmp=1; - - if (o->lasttx != txtmp) - { - o->lasttx = txtmp; - if(o->debuglevel)printf("hidthread: tx set to %d\n",txtmp); - buf[o->hid_gpio_loc] = 0; - if (txtmp) buf[o->hid_gpio_loc] = o->hid_io_ptt; - buf[o->hid_gpio_ctl_loc] = o->hid_gpio_ctl; - hid_set_outputs(usb_handle,buf); - } - - time(&o->lasthidtime); - usleep(50000); - } - buf[o->hid_gpio_loc] = 0; - if (o->invertptt) buf[o->hid_gpio_loc] = o->hid_io_ptt; - buf[o->hid_gpio_ctl_loc] = o->hid_gpio_ctl; - hid_set_outputs(usb_handle,buf); - pthread_exit(0); -} - -/* - * returns a pointer to the descriptor with the given name - */ -static struct chan_usbradio_pvt *find_desc(char *dev) -{ - struct chan_usbradio_pvt *o = NULL; - - if (!dev) - ast_log(LOG_WARNING, "null dev\n"); - - for (o = usbradio_default.next; o && o->name && dev && strcmp(o->name, dev) != 0; o = o->next); - - if (!o) - ast_log(LOG_WARNING, "could not find <%s>\n", dev ? dev : "--no-device--"); - - return o; -} - -/* - * split a string in extension-context, returns pointers to malloc'ed - * strings. - * If we do not have 'overridecontext' then the last @ is considered as - * a context separator, and the context is overridden. - * This is usually not very necessary as you can play with the dialplan, - * and it is nice not to need it because you have '@' in SIP addresses. - * Return value is the buffer address. - */ -#if 0 -static char *ast_ext_ctx(const char *src, char **ext, char **ctx) -{ - struct chan_usbradio_pvt *o = find_desc(usbradio_active); - - if (ext == NULL || ctx == NULL) - return NULL; /* error */ - - *ext = *ctx = NULL; - - if (src && *src != '\0') - *ext = ast_strdup(src); - - if (*ext == NULL) - return NULL; - - if (!o->overridecontext) { - /* parse from the right */ - *ctx = strrchr(*ext, '@'); - if (*ctx) - *(*ctx)++ = '\0'; - } - - return *ext; -} -#endif - -/* - * Returns the number of blocks used in the audio output channel - */ -static int used_blocks(struct chan_usbradio_pvt *o) -{ - struct audio_buf_info info; - - if (ioctl(o->sounddev, SNDCTL_DSP_GETOSPACE, &info)) { - if (!(o->warned & WARN_used_blocks)) { - ast_log(LOG_WARNING, "Error reading output space\n"); - o->warned |= WARN_used_blocks; - } - return 1; - } - - if (o->total_blocks == 0) { - if (0) /* debugging */ - ast_log(LOG_WARNING, "fragtotal %d size %d avail %d\n", info.fragstotal, info.fragsize, info.fragments); - o->total_blocks = info.fragments; - } - - return o->total_blocks - info.fragments; -} - -/* Write an exactly FRAME_SIZE sized frame */ -static int soundcard_writeframe(struct chan_usbradio_pvt *o, short *data) -{ - int res; - - if (o->sounddev < 0) - setformat(o, O_RDWR); - if (o->sounddev < 0) - return 0; /* not fatal */ - /* - * Nothing complex to manage the audio device queue. - * If the buffer is full just drop the extra, otherwise write. - * XXX in some cases it might be useful to write anyways after - * a number of failures, to restart the output chain. - */ - res = used_blocks(o); - if (res > o->queuesize) { /* no room to write a block */ - if (o->w_errors++ == 0 && (usbradio_debug & 0x4)) - ast_log(LOG_WARNING, "write: used %d blocks (%d)\n", res, o->w_errors); - return 0; - } - o->w_errors = 0; - - return write(o->sounddev, ((void *) data), FRAME_SIZE * 2 * 12); -} - -/* - * Handler for 'sound writable' events from the sound thread. - * Builds a frame from the high level description of the sounds, - * and passes it to the audio device. - * The actual sound is made of 1 or more sequences of sound samples - * (s->datalen, repeated to make s->samplen samples) followed by - * s->silencelen samples of silence. The position in the sequence is stored - * in o->sampsent, which goes between 0 .. s->samplen+s->silencelen. - * In case we fail to write a frame, don't update o->sampsent. - */ -static void send_sound(struct chan_usbradio_pvt *o) -{ - short myframe[FRAME_SIZE]; - int ofs, l, start; - int l_sampsent = o->sampsent; - struct sound *s; - - if (o->cursound < 0) /* no sound to send */ - return; - - s = &sounds[o->cursound]; - - for (ofs = 0; ofs < FRAME_SIZE; ofs += l) { - l = s->samplen - l_sampsent; /* # of available samples */ - if (l > 0) { - start = l_sampsent % s->datalen; /* source offset */ - if (l > FRAME_SIZE - ofs) /* don't overflow the frame */ - l = FRAME_SIZE - ofs; - if (l > s->datalen - start) /* don't overflow the source */ - l = s->datalen - start; - bcopy(s->data + start, myframe + ofs, l * 2); - if (0) - ast_log(LOG_WARNING, "send_sound sound %d/%d of %d into %d\n", l_sampsent, l, s->samplen, ofs); - l_sampsent += l; - } else { /* end of samples, maybe some silence */ - static const short silence[FRAME_SIZE] = { 0, }; - - l += s->silencelen; - if (l > 0) { - if (l > FRAME_SIZE - ofs) - l = FRAME_SIZE - ofs; - bcopy(silence, myframe + ofs, l * 2); - l_sampsent += l; - } else { /* silence is over, restart sound if loop */ - if (s->repeat == 0) { /* last block */ - o->cursound = -1; - o->nosound = 0; /* allow audio data */ - if (ofs < FRAME_SIZE) /* pad with silence */ - bcopy(silence, myframe + ofs, (FRAME_SIZE - ofs) * 2); - } - l_sampsent = 0; - } - } - } - l = soundcard_writeframe(o, myframe); - if (l > 0) - o->sampsent = l_sampsent; /* update status */ -} - -static void *sound_thread(void *arg) -{ - char ign[4096]; - struct chan_usbradio_pvt *o = (struct chan_usbradio_pvt *) arg; - - /* - * Just in case, kick the driver by trying to read from it. - * Ignore errors - this read is almost guaranteed to fail. - */ - read(o->sounddev, ign, sizeof(ign)); - for (;;) { - fd_set rfds, wfds; - int maxfd, res; - - FD_ZERO(&rfds); - FD_ZERO(&wfds); - FD_SET(o->sndcmd[0], &rfds); - maxfd = o->sndcmd[0]; /* pipe from the main process */ - if (o->cursound > -1 && o->sounddev < 0) - setformat(o, O_RDWR); /* need the channel, try to reopen */ - else if (o->cursound == -1 && o->owner == NULL) - { - setformat(o, O_CLOSE); /* can close */ - } - if (o->sounddev > -1) { - if (!o->owner) { /* no one owns the audio, so we must drain it */ - FD_SET(o->sounddev, &rfds); - maxfd = MAX(o->sounddev, maxfd); - } - if (o->cursound > -1) { - FD_SET(o->sounddev, &wfds); - maxfd = MAX(o->sounddev, maxfd); - } - } - /* ast_select emulates linux behaviour in terms of timeout handling */ - res = ast_select(maxfd + 1, &rfds, &wfds, NULL, NULL); - if (res < 1) { - ast_log(LOG_WARNING, "select failed: %s\n", strerror(errno)); - sleep(1); - continue; - } - if (FD_ISSET(o->sndcmd[0], &rfds)) { - /* read which sound to play from the pipe */ - int i, what = -1; - - read(o->sndcmd[0], &what, sizeof(what)); - for (i = 0; sounds[i].ind != -1; i++) { - if (sounds[i].ind == what) { - o->cursound = i; - o->sampsent = 0; - o->nosound = 1; /* block audio from pbx */ - break; - } - } - if (sounds[i].ind == -1) - ast_log(LOG_WARNING, "invalid sound index: %d\n", what); - } - if (o->sounddev > -1) { - if (FD_ISSET(o->sounddev, &rfds)) /* read and ignore errors */ - read(o->sounddev, ign, sizeof(ign)); - if (FD_ISSET(o->sounddev, &wfds)) - send_sound(o); - } - } - return NULL; /* Never reached */ -} - -/* - * reset and close the device if opened, - * then open and initialize it in the desired mode, - * trigger reads and writes so we can start using it. - */ -static int setformat(struct chan_usbradio_pvt *o, int mode) -{ - int fmt, desired, res, fd; - char device[100]; - - if (o->sounddev >= 0) { - ioctl(o->sounddev, SNDCTL_DSP_RESET, 0); - close(o->sounddev); - o->duplex = M_UNSET; - o->sounddev = -1; - } - if (mode == O_CLOSE) /* we are done */ - return 0; - if (ast_tvdiff_ms(ast_tvnow(), o->lastopen) < 1000) - return -1; /* don't open too often */ - o->lastopen = ast_tvnow(); - strcpy(device,"/dev/dsp"); - if (o->devicenum) - sprintf(device,"/dev/dsp%d",o->devicenum); - fd = o->sounddev = open(device, mode | O_NONBLOCK); - if (fd < 0) { - ast_log(LOG_WARNING, "Unable to re-open DSP device %d: %s\n", o->devicenum, strerror(errno)); - return -1; - } - if (o->owner) - o->owner->fds[0] = fd; - -#if __BYTE_ORDER == __LITTLE_ENDIAN - fmt = AFMT_S16_LE; -#else - fmt = AFMT_S16_BE; -#endif - res = ioctl(fd, SNDCTL_DSP_SETFMT, &fmt); - if (res < 0) { - ast_log(LOG_WARNING, "Unable to set format to 16-bit signed\n"); - return -1; - } - switch (mode) { - case O_RDWR: - res = ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0); - /* Check to see if duplex set (FreeBSD Bug) */ - res = ioctl(fd, SNDCTL_DSP_GETCAPS, &fmt); - if (res == 0 && (fmt & DSP_CAP_DUPLEX)) { - if (option_verbose > 1) - ast_verbose(VERBOSE_PREFIX_2 "Console is full duplex\n"); - o->duplex = M_FULL; - }; - break; - case O_WRONLY: - o->duplex = M_WRITE; - break; - case O_RDONLY: - o->duplex = M_READ; - break; - } - - fmt = 1; - res = ioctl(fd, SNDCTL_DSP_STEREO, &fmt); - if (res < 0) { - ast_log(LOG_WARNING, "Failed to set audio device to mono\n"); - return -1; - } - fmt = desired = 48000; /* 8000 Hz desired */ - res = ioctl(fd, SNDCTL_DSP_SPEED, &fmt); - - if (res < 0) { - ast_log(LOG_WARNING, "Failed to set audio device to mono\n"); - return -1; - } - if (fmt != desired) { - if (!(o->warned & WARN_speed)) { - ast_log(LOG_WARNING, - "Requested %d Hz, got %d Hz -- sound may be choppy\n", - desired, fmt); - o->warned |= WARN_speed; - } - } - /* - * on Freebsd, SETFRAGMENT does not work very well on some cards. - * Default to use 256 bytes, let the user override - */ - if (o->frags) { - fmt = o->frags; - res = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fmt); - if (res < 0) { - if (!(o->warned & WARN_frag)) { - ast_log(LOG_WARNING, - "Unable to set fragment size -- sound may be choppy\n"); - o->warned |= WARN_frag; - } - } - } - /* on some cards, we need SNDCTL_DSP_SETTRIGGER to start outputting */ - res = PCM_ENABLE_INPUT | PCM_ENABLE_OUTPUT; - res = ioctl(fd, SNDCTL_DSP_SETTRIGGER, &res); - /* it may fail if we are in half duplex, never mind */ - return 0; -} - -/* - * some of the standard methods supported by channels. - */ -static int usbradio_digit_begin(struct ast_channel *c, char digit) -{ - return 0; -} - -static int usbradio_digit_end(struct ast_channel *c, char digit, unsigned int duration) -{ - /* no better use for received digits than print them */ - ast_verbose(" << Console Received digit %c of duration %u ms >> \n", - digit, duration); - return 0; -} - -static int usbradio_text(struct ast_channel *c, const char *text) -{ - /* print received messages */ - ast_verbose(" << Console Received text %s >> \n", text); - return 0; -} - -/* Play ringtone 'x' on device 'o' */ -static void ring(struct chan_usbradio_pvt *o, int x) -{ - write(o->sndcmd[1], &x, sizeof(x)); -} - -/* - * handler for incoming calls. Either autoanswer, or start ringing - */ -static int usbradio_call(struct ast_channel *c, char *dest, int timeout) -{ - struct chan_usbradio_pvt *o = c->tech_pvt; - - time(&o->lasthidtime); - ast_pthread_create_background(&o->hidthread, NULL, hidthread, o); - ast_setstate(c, AST_STATE_UP); - return 0; -} - -/* - * remote side answered the phone - */ -static int usbradio_answer(struct ast_channel *c) -{ - struct chan_usbradio_pvt *o = c->tech_pvt; - - ast_setstate(c, AST_STATE_UP); - o->cursound = -1; - o->nosound = 0; - return 0; -} - -static int usbradio_hangup(struct ast_channel *c) -{ - struct chan_usbradio_pvt *o = c->tech_pvt; - - o->cursound = -1; - o->nosound = 0; - c->tech_pvt = NULL; - o->owner = NULL; - ast_module_unref(ast_module_info->self); - if (o->hookstate) { - if (o->autoanswer || o->autohangup) { - /* Assume auto-hangup too */ - o->hookstate = 0; - setformat(o, O_CLOSE); - } else { - /* Make congestion noise */ - ring(o, AST_CONTROL_CONGESTION); - } - } - o->stophid = 1; - pthread_join(o->hidthread,NULL); - return 0; -} - - -/* used for data coming from the network */ -static int usbradio_write(struct ast_channel *c, struct ast_frame *f) -{ - int src,datalen; - struct chan_usbradio_pvt *o = c->tech_pvt; - - traceusb2(("usbradio_write() o->nosound= %i\n",o->nosound)); //sph maw asdf - - /* Immediately return if no sound is enabled */ - if (o->nosound) - return 0; - /* Stop any currently playing sound */ - o->cursound = -1; - /* - * we could receive a block which is not a multiple of our - * FRAME_SIZE, so buffer it locally and write to the device - * in FRAME_SIZE chunks. - * Keep the residue stored for future use. - */ - - if(o->txkeyed||o->txtestkey)o->pmrChan->txPttIn=1; - else o->pmrChan->txPttIn=0; - - #if DEBUG_CAPTURES == 1 // to write input data to a file datalen=320 - if (ftxcapraw && o->b.txcapraw) - { - i16 i, tbuff[f->datalen]; - for(i=0;i<f->datalen;i+=2) - { - tbuff[i]= ((i16*)(f->data))[i/2]; - tbuff[i+1]= o->txkeyed*M_Q13; - } - fwrite(tbuff,2,f->datalen,ftxcapraw); - //fwrite(f->data,1,f->datalen,ftxcapraw); - } - #endif - - PmrTx(o->pmrChan,(i16*)f->data,(i16*)o->usbradio_write_buf_1); - - #if 0 // to write 48KS/s stereo data to a file - if (!ftxoutraw) ftxoutraw = fopen(TX_CAP_OUT_FILE,"w"); - if (ftxoutraw) fwrite(o->usbradio_write_buf_1,1,f->datalen * 2 * 6,ftxoutraw); - #endif - - #if DEBUG_CAPTURES == 1 - if (o->b.txcap2 && ftxcaptrace) fwrite((o->pmrChan->ptxDebug),1,FRAME_SIZE * 2 * 16,ftxcaptrace); - #endif - - src = 0; /* read position into f->data */ - datalen = f->datalen * 12; - while (src < datalen) { - /* Compute spare room in the buffer */ - int l = sizeof(o->usbradio_write_buf) - o->usbradio_write_dst; - - if (datalen - src >= l) { /* enough to fill a frame */ - memcpy(o->usbradio_write_buf + o->usbradio_write_dst, o->usbradio_write_buf_1 + src, l); - soundcard_writeframe(o, (short *) o->usbradio_write_buf); - src += l; - o->usbradio_write_dst = 0; - } else { /* copy residue */ - l = datalen - src; - memcpy(o->usbradio_write_buf + o->usbradio_write_dst, o->usbradio_write_buf_1 + src, l); - src += l; /* but really, we are done */ - o->usbradio_write_dst += l; - } - } - return 0; -} - -static struct ast_frame *usbradio_read(struct ast_channel *c) -{ - int res; - struct chan_usbradio_pvt *o = c->tech_pvt; - struct ast_frame *f = &o->read_f,*f1; - struct ast_frame wf = { AST_FRAME_CONTROL }; - time_t now; - - traceusb2(("usbradio_read()\n")); //sph maw asdf - - if (o->lasthidtime) - { - time(&now); - if ((now - o->lasthidtime) > 3) - { - ast_log(LOG_ERROR,"HID process has died or something!!\n"); - return NULL; - } - } - if (o->lastrx && (!o->rxkeyed)) - { - o->lastrx = 0; - wf.subclass = AST_CONTROL_RADIO_UNKEY; - ast_queue_frame(o->owner, &wf); - } else if ((!o->lastrx) && (o->rxkeyed)) - { - o->lastrx = 1; - wf.subclass = AST_CONTROL_RADIO_KEY; - ast_queue_frame(o->owner, &wf); - } - /* XXX can be simplified returning &ast_null_frame */ - /* prepare a NULL frame in case we don't have enough data to return */ - bzero(f, sizeof(struct ast_frame)); - f->frametype = AST_FRAME_NULL; - f->src = usbradio_tech.type; - - res = read(o->sounddev, o->usbradio_read_buf + o->readpos, - sizeof(o->usbradio_read_buf) - o->readpos); - if (res < 0) /* audio data not ready, return a NULL frame */ - return f; - - o->readpos += res; - if (o->readpos < sizeof(o->usbradio_read_buf)) /* not enough samples */ - return f; - - if (o->mute) - return f; - - #if DEBUG_CAPTURES == 1 - if (o->b.rxcapraw && frxcapraw) fwrite((o->usbradio_read_buf + AST_FRIENDLY_OFFSET),1,FRAME_SIZE * 2 * 2 * 6,frxcapraw); - #endif - - #if 1 - PmrRx( o->pmrChan, - (i16 *)(o->usbradio_read_buf + AST_FRIENDLY_OFFSET), - (i16 *)(o->usbradio_read_buf_8k + AST_FRIENDLY_OFFSET)); - - #else - static FILE *hInput; - i16 iBuff[FRAME_SIZE*2*6]; - - o->pmrChan->b.rxCapture=1; - - if(!hInput) - { - hInput = fopen("/usr/src/xpmr/testdata/rx_in.pcm","r"); - if(!hInput) - { - printf(" Input Data File Not Found.\n"); - return 0; - } - } - - if(0==fread((void *)iBuff,2,FRAME_SIZE*2*6,hInput))exit; - - PmrRx( o->pmrChan, - (i16 *)iBuff, - (i16 *)(o->usbradio_read_buf_8k + AST_FRIENDLY_OFFSET)); - - #endif - - #if 0 - if (!frxoutraw) frxoutraw = fopen(RX_CAP_OUT_FILE,"w"); - if (frxoutraw) fwrite((o->usbradio_read_buf_8k + AST_FRIENDLY_OFFSET),1,FRAME_SIZE * 2,frxoutraw); - #endif - - #if DEBUG_CAPTURES == 1 - if (frxcaptrace && o->b.rxcap2) fwrite((o->pmrChan->prxDebug),1,FRAME_SIZE * 2 * 16,frxcaptrace); - #endif - - if(o->rxcdtype==CD_HID && (o->pmrChan->rxExtCarrierDetect!=o->rxhidsq)) - o->pmrChan->rxExtCarrierDetect=o->rxhidsq; - if(o->rxcdtype==CD_HID_INVERT && (o->pmrChan->rxExtCarrierDetect==o->rxhidsq)) - o->pmrChan->rxExtCarrierDetect=!o->rxhidsq; - - if( (o->rxcdtype==CD_HID && o->rxhidsq) || - (o->rxcdtype==CD_HID_INVERT && !o->rxhidsq) || - (o->rxcdtype==CD_XPMR_NOISE && o->pmrChan->rxCarrierDetect) || - (o->rxcdtype==CD_XPMR_VOX && o->pmrChan->rxCarrierDetect) - ) - { - res=1; - } - else res=0; - - if(res!=o->rxcarrierdetect) - { - o->rxcarrierdetect=res; - if(o->debuglevel)printf("rxcarrierdetect = %i\n",res); - } - - if(o->pmrChan->rxCtcss->decode!=o->rxctcssdecode) - { - if(o->debuglevel)printf("rxctcssdecode = %i\n",o->pmrChan->rxCtcss->decode); - o->rxctcssdecode=o->pmrChan->rxCtcss->decode; - } - - if ( - ( o->rxctcssfreq && (o->rxctcssdecode == o->pmrChan->rxCtcssIndex)) || - ( !o->rxctcssfreq && o->rxcarrierdetect) - ) - { - o->rxkeyed = 1; - } - else o->rxkeyed = 0; - - - o->readpos = AST_FRIENDLY_OFFSET; /* reset read pointer for next frame */ - if (c->_state != AST_STATE_UP) /* drop data if frame is not up */ - return f; - /* ok we can build and deliver the frame to the caller */ - f->frametype = AST_FRAME_VOICE; - f->subclass = AST_FORMAT_SLINEAR; - f->samples = FRAME_SIZE; - f->datalen = FRAME_SIZE * 2; - f->data = o->usbradio_read_buf_8k + AST_FRIENDLY_OFFSET; - if (o->boost != BOOST_SCALE) { /* scale and clip values */ - int i, x; - int16_t *p = (int16_t *) f->data; - for (i = 0; i < f->samples; i++) { - x = (p[i] * o->boost) / BOOST_SCALE; - if (x > 32767) - x = 32767; - else if (x < -32768) - x = -32768; - p[i] = x; - } - } - - f->offset = AST_FRIENDLY_OFFSET; - if (o->dsp) - { - f1 = ast_dsp_process(c,o->dsp,f); - if ((f1->frametype == AST_FRAME_DTMF_END) || - (f1->frametype == AST_FRAME_DTMF_BEGIN)) - { - if ((f1->subclass == 'm') || (f1->subclass == 'u')) - f1->frametype = AST_FRAME_DTMF_BEGIN; - if (f1->frametype == AST_FRAME_DTMF_END) - ast_log(LOG_NOTICE,"Got DTMF char %c\n",f1->subclass); - return(f1); - } - } - return f; -} - -static int usbradio_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) -{ - struct chan_usbradio_pvt *o = newchan->tech_pvt; - ast_log(LOG_WARNING,"usbradio_fixup()\n"); - o->owner = newchan; - return 0; -} - -static int usbradio_indicate(struct ast_channel *c, int cond, const void *data, size_t datalen) -{ - struct chan_usbradio_pvt *o = c->tech_pvt; - int res = -1; - - switch (cond) { - case AST_CONTROL_BUSY: - case AST_CONTROL_CONGESTION: - case AST_CONTROL_RINGING: - res = cond; - break; - - case -1: - o->cursound = -1; - o->nosound = 0; /* when cursound is -1 nosound must be 0 */ - return 0; - - case AST_CONTROL_VIDUPDATE: - res = -1; - break; - case AST_CONTROL_HOLD: - ast_verbose(" << Console Has Been Placed on Hold >> \n"); - ast_moh_start(c, data, o->mohinterpret); - break; - case AST_CONTROL_UNHOLD: - ast_verbose(" << Console Has Been Retrieved from Hold >> \n"); - ast_moh_stop(c); - break; - case AST_CONTROL_PROCEEDING: - ast_verbose(" << Call Proceeding... >> \n"); - ast_moh_stop(c); - break; - case AST_CONTROL_PROGRESS: - ast_verbose(" << Call Progress... >> \n"); - ast_moh_stop(c); - break; - case AST_CONTROL_RADIO_KEY: - o->txkeyed = 1; - if(o->debuglevel)ast_verbose(" << Radio Transmit On. >> \n"); - break; - case AST_CONTROL_RADIO_UNKEY: - o->txkeyed = 0; - if(o->debuglevel)ast_verbose(" << Radio Transmit Off. >> \n"); - break; - default: - ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", cond, c->name); - return -1; - } - - if (res > -1) - ring(o, res); - - return 0; -} - -/* - * allocate a new channel. - */ -static struct ast_channel *usbradio_new(struct chan_usbradio_pvt *o, char *ext, char *ctx, int state) -{ - struct ast_channel *c; - char device[100]; - - strcpy(device,"dsp"); - if (o->devicenum) sprintf(device,"dsp%d",o->devicenum); - c = ast_channel_alloc(1, state, o->cid_num, o->cid_name, "", ext, ctx, 0, "usbRadio/%s", device); - if (c == NULL) - return NULL; - c->tech = &usbradio_tech; - if (o->sounddev < 0) - setformat(o, O_RDWR); - c->fds[0] = o->sounddev; /* -1 if device closed, override later */ - c->nativeformats = AST_FORMAT_SLINEAR; - c->readformat = AST_FORMAT_SLINEAR; - c->writeformat = AST_FORMAT_SLINEAR; - c->tech_pvt = o; - - if (!ast_strlen_zero(o->language)) - ast_string_field_set(c, language, o->language); - /* Don't use ast_set_callerid() here because it will - * generate a needless NewCallerID event */ - c->cid.cid_num = ast_strdup(o->cid_num); - c->cid.cid_ani = ast_strdup(o->cid_num); - c->cid.cid_name = ast_strdup(o->cid_name); - if (!ast_strlen_zero(ext)) - c->cid.cid_dnid = ast_strdup(ext); - - o->owner = c; - ast_module_ref(ast_module_info->self); - ast_jb_configure(c, &global_jbconf); - if (state != AST_STATE_DOWN) { - if (ast_pbx_start(c)) { - ast_log(LOG_WARNING, "Unable to start PBX on %s\n", c->name); - ast_hangup(c); - o->owner = c = NULL; - /* XXX what about the channel itself ? */ - /* XXX what about usecnt ? */ - } - } - - return c; -} - -static struct ast_channel *usbradio_request(const char *type, int format, void *data, int *cause) -{ - struct ast_channel *c; - struct chan_usbradio_pvt *o = find_desc(data); - - if (0) - { - ast_log(LOG_WARNING, "usbradio_request ty <%s> data 0x%p <%s>\n", type, data, (char *) data); - } - if (o == NULL) { - ast_log(LOG_NOTICE, "Device %s not found\n", (char *) data); - /* XXX we could default to 'dsp' perhaps ? */ - return NULL; - } - if ((format & AST_FORMAT_SLINEAR) == 0) { - ast_log(LOG_NOTICE, "Format 0x%x unsupported\n", format); - return NULL; - } - if (o->owner) { - ast_log(LOG_NOTICE, "Already have a call (chan %p) on the usb channel\n", o->owner); - *cause = AST_CAUSE_BUSY; - return NULL; - } - c = usbradio_new(o, NULL, NULL, AST_STATE_DOWN); - if (c == NULL) { - ast_log(LOG_WARNING, "Unable to create new usb channel\n"); - return NULL; - } - return c; -} - -static int console_key(int fd, int argc, char *argv[]) -{ - struct chan_usbradio_pvt *o = find_desc(usbradio_active); - - if (argc != 2) - return RESULT_SHOWUSAGE; - o->txtestkey = 1; - return RESULT_SUCCESS; -} - -static int console_unkey(int fd, int argc, char *argv[]) -{ - struct chan_usbradio_pvt *o = find_desc(usbradio_active); - - if (argc != 2) - return RESULT_SHOWUSAGE; - o->txtestkey = 0; - - return RESULT_SUCCESS; -} - -static int radio_tune(int fd, int argc, char *argv[]) -{ - struct chan_usbradio_pvt *o = find_desc(usbradio_active); - int i=0; - - if ((argc < 2) || (argc > 4)) - return RESULT_SHOWUSAGE; - - if (argc == 2) /* just show stuff */ - { - ast_cli(fd,"Output A is currently set to "); - if(o->txmixa==TX_OUT_COMPOSITE)ast_cli(fd,"composite.\n"); - else if (o->txmixa==TX_OUT_VOICE)ast_cli(fd,"voice.\n"); - else if (o->txmixa==TX_OUT_LSD)ast_cli(fd,"tone.\n"); - else if (o->txmixa==TX_OUT_AUX)ast_cli(fd,"auxvoice.\n"); - else ast_cli(fd,"off.\n"); - - ast_cli(fd,"Output B is currently set to "); - if(o->txmixb==TX_OUT_COMPOSITE)ast_cli(fd,"composite.\n"); - else if (o->txmixb==TX_OUT_VOICE)ast_cli(fd,"voice.\n"); - else if (o->txmixb==TX_OUT_LSD)ast_cli(fd,"tone.\n"); - else if (o->txmixb==TX_OUT_AUX)ast_cli(fd,"auxvoice.\n"); - else ast_cli(fd,"off.\n"); - - ast_cli(fd,"Tx Voice Level currently set to %d\n",o->txmixaset); - ast_cli(fd,"Tx Tone Level currently set to %d\n",o->txctcssadj); - ast_cli(fd,"Rx Squelch currently set to %d\n",o->rxsquelchadj); - return RESULT_SHOWUSAGE; - } - - if (!strcasecmp(argv[2],"rxnoise")) tune_rxinput(o); - else if (!strcasecmp(argv[2],"rxvoice")) tune_rxvoice(o); - else if (!strcasecmp(argv[2],"rxtone")) tune_rxctcss(o); - else if (!strcasecmp(argv[2],"rxsquelch")) - { - if (argc == 3) - { - ast_cli(fd,"Current Signal Strength is %d\n",((32767-o->pmrChan->rxRssi)*1000/32767)); - ast_cli(fd,"Current Squelch setting is %d\n",o->rxsquelchadj); - //ast_cli(fd,"Current Raw RSSI is %d\n",o->pmrChan->rxRssi); - //ast_cli(fd,"Current (real) Squelch setting is %d\n",*(o->pmrChan->prxSquelchAdjust)); - } else { - i = atoi(argv[3]); - if ((i < 0) || (i > 999)) return RESULT_SHOWUSAGE; - ast_cli(fd,"Changed Squelch setting to %d\n",i); - o->rxsquelchadj = i; - *(o->pmrChan->prxSquelchAdjust)= ((999 - i) * 32767) / 1000; - } - } - else if (!strcasecmp(argv[2],"txvoice")) { - i = 0; - - if( (o->txmixa!=TX_OUT_VOICE) && (o->txmixb!=TX_OUT_VOICE) && - (o->txmixa!=TX_OUT_COMPOSITE) && (o->txmixb!=TX_OUT_COMPOSITE) - ) - { - ast_log(LOG_ERROR,"No txvoice output configured.\n"); - } - else if (argc == 3) - { - if((o->txmixa==TX_OUT_VOICE)||(o->txmixa==TX_OUT_COMPOSITE)) - ast_cli(fd,"Current txvoice setting on Channel A is %d\n",o->txmixaset); - else - ast_cli(fd,"Current txvoice setting on Channel B is %d\n",o->txmixbset); - } - else - { - i = atoi(argv[3]); - if ((i < 0) || (i > 999)) return RESULT_SHOWUSAGE; - - if((o->txmixa==TX_OUT_VOICE)||(o->txmixa==TX_OUT_COMPOSITE)) - { - o->txmixaset=i; - ast_cli(fd,"Changed txvoice setting on Channel A to %d\n",o->txmixaset); - } - else - { - o->txmixbset=i; - ast_cli(fd,"Changed txvoice setting on Channel B to %d\n",o->txmixbset); - } - mixer_write(o); - mult_set(o); - ast_cli(fd,"Changed Tx Voice Output setting to %d\n",i); - } - tune_txoutput(o,i); - } - else if (!strcasecmp(argv[2],"auxvoice")) { - i = 0; - if( (o->txmixa!=TX_OUT_AUX) && (o->txmixb!=TX_OUT_AUX)) - { - ast_log(LOG_WARNING,"No auxvoice output configured.\n"); - } - else if (argc == 3) - { - if(o->txmixa==TX_OUT_AUX) - ast_cli(fd,"Current auxvoice setting on Channel A is %d\n",o->txmixaset); - else - ast_cli(fd,"Current auxvoice setting on Channel B is %d\n",o->txmixbset); - } - else - { - i = atoi(argv[3]); - if ((i < 0) || (i > 999)) return RESULT_SHOWUSAGE; - if(o->txmixa==TX_OUT_AUX) - { - o->txmixbset=i; - ast_cli(fd,"Changed auxvoice setting on Channel A to %d\n",o->txmixaset); - } - else - { - o->txmixbset=i; - ast_cli(fd,"Changed auxvoice setting on Channel B to %d\n",o->txmixbset); - } - mixer_write(o); - mult_set(o); - } - //tune_auxoutput(o,i); - } - else if (!strcasecmp(argv[2],"txtone")) - { - if (argc == 3) - ast_cli(fd,"Current Tx CTCSS modulation setting = %d\n",o->txctcssadj); - else - { - i = atoi(argv[3]); - if ((i < 0) || (i > 999)) return RESULT_SHOWUSAGE; - o->txctcssadj = i; - set_txctcss_level(o); - ast_cli(fd,"Changed Tx CTCSS modulation setting to %i\n",i); - } - o->txtestkey=1; - usleep(5000000); - o->txtestkey=0; - } - else if (!strcasecmp(argv[2],"dump")) pmrdump(o); - else if (!strcasecmp(argv[2],"nocap")) - { - ast_cli(fd,"File capture (trace) was rx=%d tx=%d and now off.\n",o->b.rxcap2,o->b.txcap2); - ast_cli(fd,"File capture (raw) was rx=%d tx=%d and now off.\n",o->b.rxcapraw,o->b.txcapraw); - o->b.rxcapraw=o->b.txcapraw=o->b.rxcap2=o->b.txcap2=o->pmrChan->b.rxCapture=o->pmrChan->b.txCapture=0; - if (frxcapraw) { fclose(frxcapraw); frxcapraw = NULL; } - if (frxcaptrace) { fclose(frxcaptrace); frxcaptrace = NULL; } - if (frxoutraw) { fclose(frxoutraw); frxoutraw = NULL; } - if (ftxcapraw) { fclose(ftxcapraw); ftxcapraw = NULL; } - if (ftxcaptrace) { fclose(ftxcaptrace); ftxcaptrace = NULL; } - if (ftxoutraw) { fclose(ftxoutraw); ftxoutraw = NULL; } - } - else if (!strcasecmp(argv[2],"rxtracecap")) - { - if (!frxcaptrace) frxcaptrace= fopen(RX_CAP_TRACE_FILE,"w"); - ast_cli(fd,"Trace rx on.\n"); - o->b.rxcap2=o->pmrChan->b.rxCapture=1; - } - else if (!strcasecmp(argv[2],"txtracecap")) - { - if (!ftxcaptrace) ftxcaptrace= fopen(TX_CAP_TRACE_FILE,"w"); - ast_cli(fd,"Trace tx on.\n"); - o->b.txcap2=o->pmrChan->b.txCapture=1; - } - else if (!strcasecmp(argv[2],"rxcap")) - { - if (!frxcapraw) frxcapraw = fopen(RX_CAP_RAW_FILE,"w"); - ast_cli(fd,"cap rx raw on.\n"); - o->b.rxcapraw=1; - } - else if (!strcasecmp(argv[2],"txcap")) - { - if (!ftxcapraw) ftxcapraw = fopen(TX_CAP_RAW_FILE,"w"); - ast_cli(fd,"cap tx raw on.\n"); - o->b.txcapraw=1; - } - else if (!strcasecmp(argv[2],"save")) - { - tune_write(o); - ast_cli(fd,"Saved radio tuning settings to usbradio_tune.conf\n"); - } - else return RESULT_SHOWUSAGE; - return RESULT_SUCCESS; -} - -/* - set transmit ctcss modulation level - adjust mixer output or internal gain depending on output type - setting range is 0.0 to 0.9 -*/ -static int set_txctcss_level(struct chan_usbradio_pvt *o) -{ - if (o->txmixa == TX_OUT_LSD) - { - o->txmixaset=(151*o->txctcssadj) / 1000; - mixer_write(o); - mult_set(o); - } - else if (o->txmixb == TX_OUT_LSD) - { - o->txmixbset=(151*o->txctcssadj) / 1000; - mixer_write(o); - mult_set(o); - } - else - { - *o->pmrChan->ptxCtcssAdjust=(o->txctcssadj * M_Q8) / 1000; - } - return 0; -} -/* - CLI debugging on and off -*/ -static int radio_set_debug(int fd, int argc, char *argv[]) -{ - struct chan_usbradio_pvt *o = find_desc(usbradio_active); - - o->debuglevel=1; - ast_cli(fd,"usbradio debug on.\n"); - - return RESULT_SUCCESS; -} - -static int radio_set_debug_off(int fd, int argc, char *argv[]) -{ - struct chan_usbradio_pvt *o = find_desc(usbradio_active); - - o->debuglevel=0; - ast_cli(fd,"usbradio debug off.\n"); - return RESULT_SUCCESS; -} - -static char key_usage[] = - "Usage: radio key\n" - " Simulates COR active.\n"; - -static char unkey_usage[] = - "Usage: radio unkey\n" - " Simulates COR un-active.\n"; - -/* -radio tune 6 3000 measured tx value -*/ -static char radio_tune_usage[] = - "Usage: radio tune <function>\n" - " rxnoise\n" - " rxvoice\n" - " rxtone\n" - " rxsquelch [newsetting]\n" - " txvoice [newsetting]\n" - " txtone [newsetting]\n" - " auxvoice [newsetting]\n" - " save (settings to tuning file)\n" - "\n All [newsetting]'s are values 0-999\n\n"; - -static struct ast_cli_entry cli_usbradio[] = { - { { "radio", "key", NULL }, - console_key, "Simulate Rx Signal Present", - key_usage, NULL, NULL}, - - { { "radio", "unkey", NULL }, - console_unkey, "Simulate Rx Signal Lusb", - unkey_usage, NULL, NULL }, - - { { "radio", "tune", NULL }, - radio_tune, "Radio Tune", - radio_tune_usage, NULL, NULL }, - - { { "radio", "set", "debug", NULL }, - radio_set_debug, "Radio Debug", - radio_tune_usage, NULL, NULL }, - - { { "radio", "set", "debug", "off", NULL }, - radio_set_debug_off, "Radio Debug", - radio_tune_usage, NULL, NULL }, -}; - -/* - * store the callerid components - */ -#if 0 -static void store_callerid(struct chan_usbradio_pvt *o, char *s) -{ - ast_callerid_split(s, o->cid_name, sizeof(o->cid_name), o->cid_num, sizeof(o->cid_num)); -} -#endif - -static void store_rxdemod(struct chan_usbradio_pvt *o, char *s) -{ - if (!strcasecmp(s,"no")){ - o->rxdemod = RX_AUDIO_NONE; - } - else if (!strcasecmp(s,"speaker")){ - o->rxdemod = RX_AUDIO_SPEAKER; - } - else if (!strcasecmp(s,"flat")){ - o->rxdemod = RX_AUDIO_FLAT; - } - else { - ast_log(LOG_WARNING,"Unrecognized rxdemod parameter: %s\n",s); - } - - //ast_log(LOG_WARNING, "set rxdemod = %s\n", s); -} - - -static void store_txmixa(struct chan_usbradio_pvt *o, char *s) -{ - if (!strcasecmp(s,"no")){ - o->txmixa = TX_OUT_OFF; - } - else if (!strcasecmp(s,"voice")){ - o->txmixa = TX_OUT_VOICE; - } - else if (!strcasecmp(s,"tone")){ - o->txmixa = TX_OUT_LSD; - } - else if (!strcasecmp(s,"composite")){ - o->txmixa = TX_OUT_COMPOSITE; - } - else if (!strcasecmp(s,"auxvoice")){ - o->txmixb = TX_OUT_AUX; - } - else { - ast_log(LOG_WARNING,"Unrecognized txmixa parameter: %s\n",s); - } - - //ast_log(LOG_WARNING, "set txmixa = %s\n", s); -} - -static void store_txmixb(struct chan_usbradio_pvt *o, char *s) -{ - if (!strcasecmp(s,"no")){ - o->txmixb = TX_OUT_OFF; - } - else if (!strcasecmp(s,"voice")){ - o->txmixb = TX_OUT_VOICE; - } - else if (!strcasecmp(s,"tone")){ - o->txmixb = TX_OUT_LSD; - } - else if (!strcasecmp(s,"composite")){ - o->txmixb = TX_OUT_COMPOSITE; - } - else if (!strcasecmp(s,"auxvoice")){ - o->txmixb = TX_OUT_AUX; - } - else { - ast_log(LOG_WARNING,"Unrecognized txmixb parameter: %s\n",s); - } - - //ast_log(LOG_WARNING, "set txmixb = %s\n", s); -} -/* -*/ -static void store_rxcdtype(struct chan_usbradio_pvt *o, char *s) -{ - if (!strcasecmp(s,"no")){ - o->rxcdtype = CD_IGNORE; - } - else if (!strcasecmp(s,"usb")){ - o->rxcdtype = CD_HID; - } - else if (!strcasecmp(s,"dsp")){ - o->rxcdtype = CD_XPMR_NOISE; - } - else if (!strcasecmp(s,"vox")){ - o->rxcdtype = CD_XPMR_VOX; - } - else if (!strcasecmp(s,"usbinvert")){ - o->rxcdtype = CD_HID_INVERT; - } - else { - ast_log(LOG_WARNING,"Unrecognized rxcdtype parameter: %s\n",s); - } - - //ast_log(LOG_WARNING, "set rxcdtype = %s\n", s); -} -/* -*/ -static void store_rxsdtype(struct chan_usbradio_pvt *o, char *s) -{ - if (!strcasecmp(s,"no") || !strcasecmp(s,"SD_IGNORE")){ - o->rxsdtype = SD_IGNORE; - } - else if (!strcasecmp(s,"usb") || !strcasecmp(s,"SD_HID")){ - o->rxsdtype = SD_HID; - } - else if (!strcasecmp(s,"usbinvert") || !strcasecmp(s,"SD_HID_INVERT")){ - o->rxsdtype = SD_HID_INVERT; - } - else if (!strcasecmp(s,"software") || !strcasecmp(s,"SD_XPMR")){ - o->rxsdtype = SD_XPMR; - } - else { - ast_log(LOG_WARNING,"Unrecognized rxsdtype parameter: %s\n",s); - } - - //ast_log(LOG_WARNING, "set rxsdtype = %s\n", s); -} -/* -*/ -static void store_rxgain(struct chan_usbradio_pvt *o, char *s) -{ - float f; - sscanf(s,"%f",&f); - o->rxgain = f; - //ast_log(LOG_WARNING, "set rxgain = %f\n", f); -} -/* -*/ -static void store_rxvoiceadj(struct chan_usbradio_pvt *o, char *s) -{ - float f; - sscanf(s,"%f",&f); - o->rxvoiceadj = f; - //ast_log(LOG_WARNING, "set rxvoiceadj = %f\n", f); -} -/* -*/ -static void store_rxctcssadj(struct chan_usbradio_pvt *o, char *s) -{ - float f; - sscanf(s,"%f",&f); - o->rxctcssadj = f; - //ast_log(LOG_WARNING, "set rxctcssadj = %f\n", f); -} -/* -*/ -static void store_txtoctype(struct chan_usbradio_pvt *o, char *s) -{ - if (!strcasecmp(s,"no") || !strcasecmp(s,"TOC_NONE")){ - o->txtoctype = TOC_NONE; - } - else if (!strcasecmp(s,"phase") || !strcasecmp(s,"TOC_PHASE")){ - o->txtoctype = TOC_PHASE; - } - else if (!strcasecmp(s,"notone") || !strcasecmp(s,"TOC_NOTONE")){ - o->txtoctype = TOC_NOTONE; - } - else { - ast_log(LOG_WARNING,"Unrecognized txtoctype parameter: %s\n",s); - } - - //ast_log(LOG_WARNING, "set txtoctype = %s\n", s); -} -/* -*/ -static void store_rxctcssfreq(struct chan_usbradio_pvt *o, char *s) -{ - float f; - sscanf(s,"%f",&f); - o->rxctcssfreq = f; - //ast_log(LOG_WARNING, "set rxctcss = %f\n", f); -} -/* -*/ -static void store_txctcssfreq(struct chan_usbradio_pvt *o, char *s) -{ - float f; - sscanf(s,"%f",&f); - o->txctcssfreq = f; - //ast_log(LOG_WARNING, "set txctcss = %f\n", f); -} -/* -*/ -static void tune_txoutput(struct chan_usbradio_pvt *o, int value) -{ - o->txtestkey=1; - o->pmrChan->txPttIn=1; - - // generate 1KHz tone at 7200 peak - //o->pmrChan->spsSigGen1->freq=10000; - //o->pmrChan->spsSigGen1->outputGain=(float)(0.22*M_Q8); - //o->pmrChan->b.startSpecialTone=1; - - TxTestTone(o->pmrChan, 1); - - usleep(5000000); - //o->pmrChan->b.stopSpecialTone=1; - usleep(100000); - - TxTestTone(o->pmrChan, 0); - - o->pmrChan->txPttIn=0; - o->txtestkey=0; -} -/* -*/ -static void tune_rxinput(struct chan_usbradio_pvt *o) -{ - const int target=23000; - const int tolerance=2000; - const int settingmin=1; - const int settingstart=2; - const int maxtries=12; - - float settingmax; - - int setting=0, tries=0, tmpdiscfactor, meas; - int tunetype=0; - - settingmax = o->micmax; - - if(o->pmrChan->rxDemod)tunetype=1; - - setting = settingstart; - - while(tries<maxtries) - { - setamixer(o->devicenum,MIXER_PARAM_MIC_CAPTURE_VOL,setting,0); - setamixer(o->devicenum,MIXER_PARAM_MIC_BOOST,o->rxboostset,0); - usleep(100000); - if(o->rxcdtype==CD_XPMR_VOX || o->rxdemod==RX_AUDIO_SPEAKER) - { - // printf("Measure Direct Input\n"); - o->pmrChan->spsMeasure->source = o->pmrChan->spsRx->source; - o->pmrChan->spsMeasure->discfactor=1000; - o->pmrChan->spsMeasure->enabled=1; - o->pmrChan->spsMeasure->amax = o->pmrChan->spsMeasure->amin = 0; - usleep(400000); - meas=o->pmrChan->spsMeasure->apeak; - o->pmrChan->spsMeasure->enabled=0; - } - else - { - // printf("Measure HF Noise\n"); - tmpdiscfactor=o->pmrChan->spsRx->discfactor; - o->pmrChan->spsRx->discfactor=(i16)1000; - o->pmrChan->spsRx->discounteru=o->pmrChan->spsRx->discounterl=0; - o->pmrChan->spsRx->amax=o->pmrChan->spsRx->amin=0; - usleep(200000); - meas=o->pmrChan->rxRssi; - o->pmrChan->spsRx->discfactor=tmpdiscfactor; - o->pmrChan->spsRx->discounteru=o->pmrChan->spsRx->discounterl=0; - o->pmrChan->spsRx->amax=o->pmrChan->spsRx->amin=0; - } - if(!meas)meas++; - printf("tries=%d, setting=%d, meas=%i\n",tries,setting,meas); - - if( meas<(target-tolerance) || meas>(target+tolerance) || tries<3){ - setting=setting*target/meas; - } - else if(tries>4 && meas>(target-tolerance) && meas<(target+tolerance) ) - { - break; - } - - if(setting<settingmin)setting=settingmin; - else if(setting>settingmax)setting=settingmax; - - tries++; - } - printf("DONE tries=%d, setting=%d, meas=%i\n",tries, - (setting * 1000) / o->micmax,meas); - if( meas<(target-tolerance) || meas>(target+tolerance) ){ - printf("ERROR: RX INPUT ADJUST FAILED.\n"); - }else{ - printf("INFO: RX INPUT ADJUST SUCCESS.\n"); - o->rxmixerset=(setting * 1000) / o->micmax; - } -} -/* -*/ -static void tune_rxvoice(struct chan_usbradio_pvt *o) -{ - const int target=7200; // peak - const int tolerance=360; // peak to peak - const float settingmin=0.1; - const float settingmax=4; - const float settingstart=1; - const int maxtries=12; - - float setting; - - int tries=0, meas; - - printf("INFO: RX VOICE ADJUST START.\n"); - printf("target=%i tolerance=%i \n",target,tolerance); - - if(!o->pmrChan->spsMeasure) - printf("ERROR: NO MEASURE BLOCK.\n"); - - if(!o->pmrChan->spsMeasure->source || !o->pmrChan->prxVoiceAdjust ) - printf("ERROR: NO SOURCE OR MEASURE SETTING.\n"); - - o->pmrChan->spsMeasure->source=o->pmrChan->spsRxOut->sink; - o->pmrChan->spsMeasure->enabled=1; - o->pmrChan->spsMeasure->discfactor=1000; - - setting=settingstart; - - // printf("ERROR: NO MEASURE BLOCK.\n"); - - while(tries<maxtries) - { - *(o->pmrChan->prxVoiceAdjust)=setting*M_Q8; - usleep(10000); - o->pmrChan->spsMeasure->amax = o->pmrChan->spsMeasure->amin = 0; - usleep(1000000); - meas = o->pmrChan->spsMeasure->apeak; - printf("tries=%d, setting=%f, meas=%i\n",tries,setting,meas); - - if( meas<(target-tolerance) || meas>(target+tolerance) || tries<3){ - setting=setting*target/meas; - } - else if(tries>4 && meas>(target-tolerance) && meas<(target+tolerance) ) - { - break; - } - if(setting<settingmin)setting=settingmin; - else if(setting>settingmax)setting=settingmax; - - tries++; - } - - o->pmrChan->spsMeasure->enabled=0; - - printf("DONE tries=%d, setting=%f, meas=%f\n",tries,setting,(float)meas); - if( meas<(target-tolerance) || meas>(target+tolerance) ){ - printf("ERROR: RX VOICE GAIN ADJUST FAILED.\n"); - }else{ - printf("INFO: RX VOICE GAIN ADJUST SUCCESS.\n"); - o->rxvoiceadj=setting; - } -} -/* -*/ -static void tune_rxctcss(struct chan_usbradio_pvt *o) -{ - const int target=4096; - const int tolerance=100; - const float settingmin=0.1; - const float settingmax=4; - const float settingstart=1; - const int maxtries=12; - - float setting; - int tries=0, meas; - - printf("INFO: RX CTCSS ADJUST START.\n"); - printf("target=%i tolerance=%i \n",target,tolerance); - - o->pmrChan->spsMeasure->source=o->pmrChan->prxCtcssMeasure; - o->pmrChan->spsMeasure->discfactor=400; - o->pmrChan->spsMeasure->enabled=1; - - setting=settingstart; - - while(tries<maxtries) - { - *(o->pmrChan->prxCtcssAdjust)=setting*M_Q8; - usleep(10000); - o->pmrChan->spsMeasure->amax = o->pmrChan->spsMeasure->amin = 0; - usleep(500000); - meas = o->pmrChan->spsMeasure->apeak; - printf("tries=%d, setting=%f, meas=%i\n",tries,setting,meas); - - if( meas<(target-tolerance) || meas>(target+tolerance) || tries<3){ - setting=setting*target/meas; - } - else if(tries>4 && meas>(target-tolerance) && meas<(target+tolerance) ) - { - break; - } - if(setting<settingmin)setting=settingmin; - else if(setting>settingmax)setting=settingmax; - - tries++; - } - o->pmrChan->spsMeasure->enabled=0; - printf("DONE tries=%d, setting=%f, meas=%f\n",tries,setting,(float)meas); - if( meas<(target-tolerance) || meas>(target+tolerance) ){ - printf("ERROR: RX CTCSS GAIN ADJUST FAILED.\n"); - }else{ - printf("INFO: RX CTCSS GAIN ADJUST SUCCESS.\n"); - o->rxctcssadj=setting; - } -} -/* - this file then is included in chan_usbradio.conf - #include /etc/asterisk/usbradio_tune.conf -*/ -static void tune_write(struct chan_usbradio_pvt *o) -{ - FILE *fp; - - fp=fopen("/etc/asterisk/usbradio_tune.conf","w"); - - if (!strcmp(o->name,"dsp")) - fprintf(fp,"[general]\n"); - else - fprintf(fp,"[%s]\n",o->name); - - fprintf(fp,"; name=%s\n",o->name); - fprintf(fp,"; devicenum=%i\n",o->devicenum); - - fprintf(fp,"rxmixerset=%i\n",o->rxmixerset); - fprintf(fp,"rxboostset=%i\n",o->rxboostset); - fprintf(fp,"txmixaset=%i\n",o->txmixaset); - fprintf(fp,"txmixbset=%i\n",o->txmixbset); - - fprintf(fp,"rxvoiceadj=%f\n",o->rxvoiceadj); - fprintf(fp,"rxctcssadj=%f\n",o->rxctcssadj); - fprintf(fp,"txctcssadj=%i\n",o->txctcssadj); - - fprintf(fp,"rxsquelchadj=%i\n",o->rxsquelchadj); - fclose(fp); -} -// -static void mixer_write(struct chan_usbradio_pvt *o) -{ - setamixer(o->devicenum,MIXER_PARAM_MIC_PLAYBACK_SW,0,0); - setamixer(o->devicenum,MIXER_PARAM_MIC_PLAYBACK_VOL,0,0); - setamixer(o->devicenum,MIXER_PARAM_SPKR_PLAYBACK_SW,1,0); - setamixer(o->devicenum,MIXER_PARAM_SPKR_PLAYBACK_VOL, - o->txmixaset * o->spkrmax / 1000, - o->txmixbset * o->spkrmax / 1000); - setamixer(o->devicenum,MIXER_PARAM_MIC_CAPTURE_VOL, - o->rxmixerset * o->micmax / 1000,0); - setamixer(o->devicenum,MIXER_PARAM_MIC_BOOST,o->rxboostset,0); - setamixer(o->devicenum,MIXER_PARAM_MIC_CAPTURE_SW,1,0); -} -/* - adjust dsp multiplier to add resolution to tx level adjustment -*/ -static void mult_set(struct chan_usbradio_pvt *o) -{ - - if(o->pmrChan->spsTxOutA) { - o->pmrChan->spsTxOutA->outputGain = - mult_calc((o->txmixaset * 152) / 1000); - } - if(o->pmrChan->spsTxOutB){ - o->pmrChan->spsTxOutB->outputGain = - mult_calc((o->txmixbset * 152) / 1000); - } -} -// -// input 0 - 151 outputs are pot and multiplier -// -static int mult_calc(int value) -{ - const int multx=M_Q8; - int pot,mult; - - pot=((int)(value/4)*4)+2; - mult = multx-( ( multx * (3-(value%4)) ) / (pot+2) ); - return(mult); -} - -#define pd(x) {printf(#x" = %d\n",x);} -#define pp(x) {printf(#x" = %p\n",x);} -#define ps(x) {printf(#x" = %s\n",x);} -#define pf(x) {printf(#x" = %f\n",x);} -/* -*/ -static void pmrdump(struct chan_usbradio_pvt *o) -{ - t_pmr_chan *p; - - p=o->pmrChan; - - printf("\nodump()\n"); - - pd(o->devicenum); - - pd(o->rxdemod); - pd(o->rxcdtype); - pd(o->rxsdtype); - pd(o->txtoctype); - - pd(o->rxmixerset); - pf(o->rxvoiceadj); - pf(o->rxctcssadj); - pd(o->rxsquelchadj); - - pd(o->txprelim); - pd(o->txmixa); - pd(o->txmixb); - - pd(o->txmixaset); - pd(o->txmixbset); - - printf("\npmrdump()\n"); - - printf("prxSquelchAdjust=%i\n",*(o->pmrChan->prxSquelchAdjust)); - - pd(p->rxCarrierPoint); - pd(p->rxCarrierHyst); - - pd(p->rxCtcss->relax); - pf(p->rxCtcssFreq); - pd(p->rxCtcssIndex); - pf(p->txCtcssFreq); - - pd(p->txMixA); - pd(p->txMixB); - - pd(p->rxDeEmpEnable); - pd(p->rxCenterSlicerEnable); - pd(p->rxCtcssDecodeEnable); - pd(p->rxDcsDecodeEnable); - - pd(p->txHpfEnable); - pd(p->txLimiterEnable); - pd(p->txPreEmpEnable); - pd(p->txLpfEnable); - - if(p->spsTxOutA)pd(p->spsTxOutA->outputGain); - if(p->spsTxOutB)pd(p->spsTxOutB->outputGain); - - return; -} - - -/* - * grab fields from the config file, init the descriptor and open the device. - */ -static struct chan_usbradio_pvt *store_config(struct ast_config *cfg, char *ctg) -{ - struct ast_variable *v; - struct chan_usbradio_pvt *o; - struct ast_config *cfg1; - - if (ctg == NULL) { - traceusb1((" store_config() ctg == NULL\n")); - o = &usbradio_default; - ctg = "general"; - } else { - if (!(o = ast_calloc(1, sizeof(*o)))){ - return NULL; - } - *o = usbradio_default; - /* "general" is also the default thing */ - if (strcmp(ctg, "general") == 0) { - o->name = ast_strdup("dsp"); - usbradio_active = o->name; - } - else o->name = ast_strdup(ctg); - } - - strcpy(o->mohinterpret, "default"); - o->micmax = amixer_max(o->devicenum,MIXER_PARAM_MIC_CAPTURE_VOL); - o->spkrmax = amixer_max(o->devicenum,MIXER_PARAM_SPKR_PLAYBACK_VOL); - /* fill other fields from configuration */ - for (v = ast_variable_browse(cfg, ctg); v; v = v->next) { - M_START(v->name, v->value); - - /* handle jb conf */ - if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) - continue; - -#if 0 - M_BOOL("autoanswer", o->autoanswer) - M_BOOL("autohangup", o->autohangup) - M_BOOL("overridecontext", o->overridecontext) - M_STR("context", o->ctx) - M_STR("language", o->language) - M_STR("mohinterpret", o->mohinterpret) - M_STR("extension", o->ext) - M_F("callerid", store_callerid(o, v->value)) -#endif - M_UINT("frags", o->frags) - M_UINT("queuesize", o->queuesize) - M_UINT("devicenum", o->devicenum) - M_UINT("debug", usbradio_debug) - M_BOOL("rxcpusaver",o->rxcpusaver) - M_BOOL("txcpusaver",o->txcpusaver) - M_BOOL("invertptt",o->invertptt) - M_F("rxdemod",store_rxdemod(o,v->value)) - M_BOOL("txprelim",o->txprelim); - M_F("txmixa",store_txmixa(o,v->value)) - M_F("txmixb",store_txmixb(o,v->value)) - M_F("carrierfrom",store_rxcdtype(o,v->value)) - M_F("rxsdtype",store_rxsdtype(o,v->value)) - M_F("rxctcssfreq",store_rxctcssfreq(o,v->value)) - M_F("txctcssfreq",store_txctcssfreq(o,v->value)) - M_F("rxgain",store_rxgain(o,v->value)) - M_BOOL("rxboostset", o->rxboostset) - M_UINT("rxctcssrelax", o->rxctcssrelax) - M_F("txtoctype",store_txtoctype(o,v->value)) - M_UINT("hdwtype", o->hdwtype) - M_UINT("duplex", o->radioduplex) - M_END(; - ); - } - - cfg1 = ast_config_load(config1); - if (!cfg1) - { - o->rxmixerset = 500; - o->txmixaset = 500; - o->txmixbset = 500; - o->rxvoiceadj = 0.5; - o->rxctcssadj = 0.5; - o->txctcssadj = 200; - o->rxsquelchadj = 500; - ast_log(LOG_WARNING,"File %s not found, using default parameters.\n",config1); - } else { - for (v = ast_variable_browse(cfg1, ctg); v; v = v->next) { - - M_START(v->name, v->value); - M_UINT("rxmixerset", o->rxmixerset) - M_UINT("txmixaset", o->txmixaset) - M_UINT("txmixbset", o->txmixbset) - M_F("rxvoiceadj",store_rxvoiceadj(o,v->value)) - M_F("rxctcssadj",store_rxctcssadj(o,v->value)) - M_UINT("txctcssadj",o->txctcssadj); - M_UINT("rxsquelchadj", o->rxsquelchadj) - M_END(; - ); - } - ast_config_destroy(cfg1); - } - - o->debuglevel=0; - - if (o == &usbradio_default) /* we are done with the default */ - return NULL; - - o->lastopen = ast_tvnow(); /* don't leave it 0 or tvdiff may wrap */ - o->dsp = ast_dsp_new(); - if (o->dsp) - { - ast_dsp_set_features(o->dsp,DSP_FEATURE_DTMF_DETECT); - ast_dsp_digitmode(o->dsp,DSP_DIGITMODE_DTMF | DSP_DIGITMODE_MUTECONF | DSP_DIGITMODE_RELAXDTMF); - } - - if(o->rxctcssfreq!=0 && o->rxdemod==RX_AUDIO_SPEAKER) - { - ast_log(LOG_ERROR, "Incompatable Options o->rxctcssfreq=%f and o->rxdemod=speaker\n", o->rxctcssfreq); - } - - if(o->pmrChan==NULL) - { - t_pmr_chan tChan; - - memset(&tChan,0,sizeof(t_pmr_chan)); - - tChan.rxDemod=o->rxdemod; - tChan.rxCdType=o->rxcdtype; - - tChan.txMod=o->txprelim; - - tChan.txMixA = o->txmixa; - tChan.txMixB = o->txmixb; - - tChan.rxCpuSaver=o->rxcpusaver; - tChan.txCpuSaver=o->txcpusaver; - - tChan.rxCtcssFreq=o->rxctcssfreq; - tChan.txCtcssFreq=o->txctcssfreq; - - o->pmrChan=createPmrChannel(&tChan,FRAME_SIZE); - - o->pmrChan->radioDuplex=o->radioduplex; - - o->pmrChan->rxCpuSaver=o->rxcpusaver; - o->pmrChan->txCpuSaver=o->txcpusaver; - - *(o->pmrChan->prxSquelchAdjust) = - ((999 - o->rxsquelchadj) * 32767) / 1000; - - o->pmrChan->spsRx->outputGain = o->rxvoiceadj*M_Q8; - - o->pmrChan->txTocType = o->txtoctype; - - if ((o->txmixa == TX_OUT_LSD) || - (o->txmixa == TX_OUT_COMPOSITE) || - (o->txmixb == TX_OUT_LSD) || - (o->txmixb == TX_OUT_COMPOSITE)) - { - *(o->pmrChan->prxCtcssAdjust)=o->rxctcssadj*M_Q8; - set_txctcss_level(o); - } - - o->pmrChan->rxCtcss->relax=o->rxctcssrelax; - - } - - if( (o->txmixa!=TX_OUT_VOICE) && (o->txmixb!=TX_OUT_VOICE) && - (o->txmixa!=TX_OUT_COMPOSITE) && (o->txmixb!=TX_OUT_COMPOSITE) - ) - { - ast_log(LOG_ERROR,"No txvoice output configured.\n"); - } - - if( o->txctcssfreq && - o->txmixa!=TX_OUT_LSD && o->txmixa!=TX_OUT_COMPOSITE && - o->txmixb!=TX_OUT_LSD && o->txmixb!=TX_OUT_COMPOSITE - ) - { - ast_log(LOG_ERROR,"No txtone output configured.\n"); - } - - if( o->rxctcssfreq && o->pmrChan->rxCtcssIndex<0 ) - { - ast_log(LOG_ERROR,"Invalid CTCSS Frequency.\n"); - } - - // RxTestIt(o); - - mixer_write(o); - mult_set(o); - hidhdwconfig(o); - - // pmrdump(o); - - if (pipe(o->sndcmd) != 0) { - ast_log(LOG_ERROR, "Unable to create pipe\n"); - goto error; - } - - printf("creating sound thread\n"); - ast_pthread_create_background(&o->sthread, NULL, sound_thread, o); - - /* link into list of devices */ - if (o != &usbradio_default) { - o->next = usbradio_default.next; - usbradio_default.next = o; - } - return o; - - error: - if (o != &usbradio_default) - free(o); - return NULL; -} - -#if DEBUG_FILETEST == 1 -/* - Test It on a File -*/ -int RxTestIt(struct chan_usbradio_pvt *o) -{ - const int numSamples = SAMPLES_PER_BLOCK; - const int numChannels = 16; - - i16 sample,i,ii; - - i32 txHangTime; - - i16 txEnable; - - t_pmr_chan tChan; - t_pmr_chan *pChan; - - FILE *hInput=NULL, *hOutput=NULL, *hOutputTx=NULL; - - i16 iBuff[numSamples*2*6], oBuff[numSamples]; - - printf("RxTestIt()\n"); - - pChan=o->pmrChan; - pChan->b.txCapture=1; - pChan->b.rxCapture=1; - - txEnable = 0; - - hInput = fopen("/usr/src/xpmr/testdata/rx_in.pcm","r"); - if(!hInput){ - printf(" RxTestIt() File Not Found.\n"); - return 0; - } - hOutput = fopen("/usr/src/xpmr/testdata/rx_debug.pcm","w"); - - printf(" RxTestIt() Working...\n"); - - while(!feof(hInput)) - { - fread((void *)iBuff,2,numSamples*2*6,hInput); - - if(txHangTime)txHangTime-=numSamples; - if(txHangTime<0)txHangTime=0; - - if(pChan->rxCtcss->decode)txHangTime=(8000/1000*2000); - - if(pChan->rxCtcss->decode && !txEnable) - { - txEnable=1; - //pChan->inputBlanking=(8000/1000*200); - } - else if(!pChan->rxCtcss->decode && txEnable) - { - txEnable=0; - } - - PmrRx(pChan,iBuff,oBuff); - - fwrite((void *)pChan->prxDebug,2,numSamples*numChannels,hOutput); - } - pChan->b.txCapture=0; - pChan->b.rxCapture=0; - - if(hInput)fclose(hInput); - if(hOutput)fclose(hOutput); - - printf(" RxTestIt() Complete.\n"); - - return 0; -} -#endif - -#include "./xpmr/xpmr.c" -/* -*/ -static int load_module(void) -{ - struct ast_config *cfg = NULL; - char *ctg = NULL; - - /* Copy the default jb config over global_jbconf */ - memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf)); - - /* load config file */ - if (!(cfg = ast_config_load(config))) { - ast_log(LOG_NOTICE, "Unable to load config %s\n", config); - return AST_MODULE_LOAD_DECLINE; - } - - do { - store_config(cfg, ctg); - } while ( (ctg = ast_category_browse(cfg, ctg)) != NULL); - - ast_config_destroy(cfg); - - if (find_desc(usbradio_active) == NULL) { - ast_log(LOG_NOTICE, "Device %s not found\n", usbradio_active); - /* XXX we could default to 'dsp' perhaps ? */ - /* XXX should cleanup allocated memory etc. */ - return AST_MODULE_LOAD_FAILURE; - } - - if (ast_channel_register(&usbradio_tech)) { - ast_log(LOG_ERROR, "Unable to register channel type 'usb'\n"); - return AST_MODULE_LOAD_FAILURE; - } - - ast_cli_register_multiple(cli_usbradio, sizeof(cli_usbradio) / sizeof(struct ast_cli_entry)); - - return AST_MODULE_LOAD_SUCCESS; -} -/* -*/ -static int unload_module(void) -{ - struct chan_usbradio_pvt *o; - - ast_log(LOG_WARNING, "unload_module() called\n"); - - ast_channel_unregister(&usbradio_tech); - ast_cli_unregister_multiple(cli_usbradio, sizeof(cli_usbradio) / sizeof(struct ast_cli_entry)); - - for (o = usbradio_default.next; o; o = o->next) { - - ast_log(LOG_WARNING, "destroyPmrChannel() called\n"); - if(o->pmrChan)destroyPmrChannel(o->pmrChan); - - #if DEBUG_CAPTURES == 1 - if (frxcapraw) { fclose(frxcapraw); frxcapraw = NULL; } - if (frxcaptrace) { fclose(frxcaptrace); frxcaptrace = NULL; } - if (frxoutraw) { fclose(frxoutraw); frxoutraw = NULL; } - if (ftxcapraw) { fclose(ftxcapraw); ftxcapraw = NULL; } - if (ftxcaptrace) { fclose(ftxcaptrace); ftxcaptrace = NULL; } - if (ftxoutraw) { fclose(ftxoutraw); ftxoutraw = NULL; } - #endif - - close(o->sounddev); - if (o->sndcmd[0] > 0) { - close(o->sndcmd[0]); - close(o->sndcmd[1]); - } - if (o->dsp) ast_dsp_free(o->dsp); - if (o->owner) - ast_softhangup(o->owner, AST_SOFTHANGUP_APPUNLOAD); - if (o->owner) /* XXX how ??? */ - return -1; - /* XXX what about the thread ? */ - /* XXX what about the memory allocated ? */ - } - return 0; -} - -AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "usb Console Channel Driver"); - -/* end of file */ - - diff --git a/channels/xpmr/LICENSE b/channels/xpmr/LICENSE deleted file mode 100755 index a52b16e40..000000000 --- a/channels/xpmr/LICENSE +++ /dev/null @@ -1,341 +0,0 @@ - - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) 19yy <name of author> - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) 19yy name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - <signature of Ty Coon>, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/channels/xpmr/sinetabx.h b/channels/xpmr/sinetabx.h deleted file mode 100755 index 1ceb659e7..000000000 --- a/channels/xpmr/sinetabx.h +++ /dev/null @@ -1,300 +0,0 @@ -/* - * sinetabx.h - for Xelatec Private Mobile Radio Processes - * - * All Rights Reserved. Copyright (C)2007, Xelatec, LLC - * - * 20070808 1235 Steven Henke, W9SH, sph@xelatec.com - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * This version may be optionally licenced under the GNU LGPL licence. - * - * A license has been granted to Digium (via disclaimer) for the use of - * this code. - * - */ - -/*! \file - * - * \brief Private Land Mobile Radio Channel Voice and Signaling Processor - * - * \author Steven Henke, W9SH <sph@xelatec.com> Xelatec, LLC - */ - -#ifndef XPMR_SINETABX_H -#define XPMR_SINETABX_H 1 - -#define SAMPLES_PER_SINE 256 - -const i16 sinetablex[]={ -0, // 0 -804, // 1 -1608, // 2 -2410, // 3 -3212, // 4 -4011, // 5 -4808, // 6 -5602, // 7 -6393, // 8 -7179, // 9 -7962, // 10 -8739, // 11 -9512, // 12 -10278, // 13 -11039, // 14 -11793, // 15 -12539, // 16 -13279, // 17 -14010, // 18 -14732, // 19 -15446, // 20 -16151, // 21 -16846, // 22 -17530, // 23 -18204, // 24 -18868, // 25 -19519, // 26 -20159, // 27 -20787, // 28 -21403, // 29 -22005, // 30 -22594, // 31 -23170, // 32 -23731, // 33 -24279, // 34 -24811, // 35 -25329, // 36 -25832, // 37 -26319, // 38 -26790, // 39 -27245, // 40 -27683, // 41 -28105, // 42 -28510, // 43 -28898, // 44 -29268, // 45 -29621, // 46 -29956, // 47 -30273, // 48 -30571, // 49 -30852, // 50 -31113, // 51 -31356, // 52 -31580, // 53 -31785, // 54 -31971, // 55 -32137, // 56 -32285, // 57 -32412, // 58 -32521, // 59 -32609, // 60 -32678, // 61 -32728, // 62 -32757, // 63 -32767, // 64 -32757, // 65 -32728, // 66 -32678, // 67 -32609, // 68 -32521, // 69 -32412, // 70 -32285, // 71 -32137, // 72 -31971, // 73 -31785, // 74 -31580, // 75 -31356, // 76 -31113, // 77 -30852, // 78 -30571, // 79 -30273, // 80 -29956, // 81 -29621, // 82 -29268, // 83 -28898, // 84 -28510, // 85 -28105, // 86 -27683, // 87 -27245, // 88 -26790, // 89 -26319, // 90 -25832, // 91 -25329, // 92 -24811, // 93 -24279, // 94 -23731, // 95 -23170, // 96 -22594, // 97 -22005, // 98 -21403, // 99 -20787, // 100 -20159, // 101 -19519, // 102 -18868, // 103 -18204, // 104 -17530, // 105 -16846, // 106 -16151, // 107 -15446, // 108 -14732, // 109 -14010, // 110 -13279, // 111 -12539, // 112 -11793, // 113 -11039, // 114 -10278, // 115 -9512, // 116 -8739, // 117 -7962, // 118 -7179, // 119 -6393, // 120 -5602, // 121 -4808, // 122 -4011, // 123 -3212, // 124 -2410, // 125 -1608, // 126 -804, // 127 -0, // 128 --804, // 129 --1608, // 130 --2410, // 131 --3212, // 132 --4011, // 133 --4808, // 134 --5602, // 135 --6393, // 136 --7179, // 137 --7962, // 138 --8739, // 139 --9512, // 140 --10278, // 141 --11039, // 142 --11793, // 143 --12539, // 144 --13279, // 145 --14010, // 146 --14732, // 147 --15446, // 148 --16151, // 149 --16846, // 150 --17530, // 151 --18204, // 152 --18868, // 153 --19519, // 154 --20159, // 155 --20787, // 156 --21403, // 157 --22005, // 158 --22594, // 159 --23170, // 160 --23731, // 161 --24279, // 162 --24811, // 163 --25329, // 164 --25832, // 165 --26319, // 166 --26790, // 167 --27245, // 168 --27683, // 169 --28105, // 170 --28510, // 171 --28898, // 172 --29268, // 173 --29621, // 174 --29956, // 175 --30273, // 176 --30571, // 177 --30852, // 178 --31113, // 179 --31356, // 180 --31580, // 181 --31785, // 182 --31971, // 183 --32137, // 184 --32285, // 185 --32412, // 186 --32521, // 187 --32609, // 188 --32678, // 189 --32728, // 190 --32757, // 191 --32767, // 192 --32757, // 193 --32728, // 194 --32678, // 195 --32609, // 196 --32521, // 197 --32412, // 198 --32285, // 199 --32137, // 200 --31971, // 201 --31785, // 202 --31580, // 203 --31356, // 204 --31113, // 205 --30852, // 206 --30571, // 207 --30273, // 208 --29956, // 209 --29621, // 210 --29268, // 211 --28898, // 212 --28510, // 213 --28105, // 214 --27683, // 215 --27245, // 216 --26790, // 217 --26319, // 218 --25832, // 219 --25329, // 220 --24811, // 221 --24279, // 222 --23731, // 223 --23170, // 224 --22594, // 225 --22005, // 226 --21403, // 227 --20787, // 228 --20159, // 229 --19519, // 230 --18868, // 231 --18204, // 232 --17530, // 233 --16846, // 234 --16151, // 235 --15446, // 236 --14732, // 237 --14010, // 238 --13279, // 239 --12539, // 240 --11793, // 241 --11039, // 242 --10278, // 243 --9512, // 244 --8739, // 245 --7962, // 246 --7179, // 247 --6393, // 248 --5602, // 249 --4808, // 250 --4011, // 251 --3212, // 252 --2410, // 253 --1608, // 254 --804, // 255 -}; - -#endif /* !XPMR_SINETABX_H */ diff --git a/channels/xpmr/xpmr.c b/channels/xpmr/xpmr.c deleted file mode 100755 index c67e40841..000000000 --- a/channels/xpmr/xpmr.c +++ /dev/null @@ -1,2266 +0,0 @@ -/* - * xpmr.c - Xelatec Private Mobile Radio Processes - * - * All Rights Reserved. Copyright (C)2007, Xelatec, LLC - * - * 20070808 1235 Steven Henke, W9SH, sph@xelatec.com - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * This version may be optionally licenced under the GNU LGPL licence. - * - * A license has been granted to Digium (via disclaimer) for the use of - * this code. - * - */ - -/*! \file - * - * \brief Private Land Mobile Radio Channel Voice and Signaling Processor - * - * \author Steven Henke, W9SH <sph@xelatec.com> Xelatec, LLC - */ -/* - FYI = For Your Information - PMR = Private Mobile Radio - RX = Receive - TX = Transmit - CTCSS = Continuous Tone Coded Squelch System - TONE = Same as above. - LSD = Low Speed Data, subaudible signaling. May be tones or codes. - VOX = Voice Operated Transmit - DSP = Digital Signal Processing - LPF = Low Pass Filter - FIR = Finite Impulse Response (Filter) - IIR = Infinite Impulse Response (Filter) -*/ -#include <stdio.h> -#include <ctype.h> -#include <math.h> -#include <string.h> -#include <unistd.h> -#include <sys/ioctl.h> -#include <fcntl.h> -#include <sys/time.h> -#include <stdlib.h> -#include <errno.h> - -#include "xpmr.h" -#include "xpmr_coef.h" -#include "sinetabx.h" - -static i16 pmrChanIndex=0; // count of created pmr instances - -/* - Convert a Frequency in Hz to a zero based CTCSS Table index -*/ -i16 CtcssFreqIndex(float freq) -{ - i16 i,hit=-1; - - for(i=0;i<CTCSS_NUM_CODES;i++){ - if(freq==freq_ctcss[i])hit=i; - } - return hit; -} -/* - pmr_rx_frontend - Takes a block of data and low pass filters it. - Determines the amplitude of high frequency noise for carrier detect. - Decimates input data to change the rate. -*/ -i16 pmr_rx_frontend(t_pmr_sps *mySps) -{ - #define DCgainBpfNoise 65536 - - i16 samples,iOutput, *input, *output, *noutput; - i16 *x, *coef, *coef2; - i32 i, naccum, outputGain, calcAdjust; - i64 y; - i16 nx, hyst, setpt, compOut; - i16 amax, amin, apeak, discounteru, discounterl, discfactor; - i16 decimator, decimate, doNoise; - - TRACEX(("pmr_rx_frontend()\n")); - - if(!mySps->enabled)return(1); - - decimator = mySps->decimator; - decimate = mySps->decimate; - - input = mySps->source; - output = mySps->sink; - noutput = mySps->parentChan->pRxNoise; - - nx = mySps->nx; - coef = mySps->coef; - coef2 = mySps->coef2; - - calcAdjust = mySps->calcAdjust; - outputGain = mySps->outputGain; - - amax=mySps->amax; - amin=mySps->amin; - apeak=mySps->apeak; - discounteru=mySps->discounteru; - discounterl=mySps->discounterl; - discfactor=mySps->discfactor; - setpt=mySps->setpt; - hyst=mySps->hyst; - compOut=mySps->compOut; - - samples=mySps->nSamples*decimate; - x=mySps->x; - iOutput=0; - - if(mySps->parentChan->rxCdType!=CD_XPMR_VOX)doNoise=1; - else doNoise=0; - - for(i=0;i<samples;i++) - { - i16 n; - - //shift the old samples - for(n=nx-1; n>0; n--) - x[n] = x[n-1]; - - x[0] = input[i*2]; - - --decimator; - - if(decimator<=0) - { - decimator=decimate; - - y=0; - for(n=0; n<nx; n++) - y += coef[n] * x[n]; - - y=((y/calcAdjust)*outputGain)/M_Q8; - - if(y>32767)y=32767; - else if(y<-32767)y=-32767; - - output[iOutput]=y; // Rx Baseband decimated - noutput[iOutput++] = apeak; // Rx Noise - } - - if(doNoise) - { - // calculate noise output - naccum=0; - for(n=0; n<nx; n++) - naccum += coef_fir_bpf_noise_1[n] * x[n]; - - naccum /= DCgainBpfNoise; - - if(naccum>amax) - { - amax=naccum; - discounteru=discfactor; - } - else if(--discounteru<=0) - { - discounteru=discfactor; - amax=(i32)((amax*32700)/32768); - } - - if(naccum<amin) - { - amin=naccum; - discounterl=discfactor; - } - else if(--discounterl<=0) - { - discounterl=discfactor; - amin=(i32)((amin*32700)/32768); - } - - apeak=(amax-amin)/2; - - } // if doNoise - } - - if(doNoise) - { - ((t_pmr_chan *)(mySps->parentChan))->rxRssi=apeak; - - if(apeak>setpt || (compOut&&(apeak>(setpt-hyst)))) compOut=1; - else compOut=0; - mySps->compOut=compOut; - mySps->amax=amax; - mySps->amin=amin; - mySps->apeak=apeak; - mySps->discounteru=discounteru; - mySps->discounterl=discounterl; - } - - return 0; -} -/* - pmr general purpose fir - works on a block of samples -*/ -i16 pmr_gp_fir(t_pmr_sps *mySps) -{ - i32 nsamples,inputGain,outputGain,calcAdjust; - i16 *input, *output; - i16 *x, *coef; - i32 i, ii; - i16 nx, hyst, setpt, compOut; - i16 amax, amin, apeak=0, discounteru=0, discounterl=0, discfactor; - i16 decimator, decimate, interpolate; - i16 numChanOut, selChanOut, mixOut, monoOut; - - TRACEX(("pmr_gp_fir() %i\n",mySps->enabled)); - - if(!mySps->enabled)return(1); - - inputGain = mySps->inputGain; - calcAdjust = mySps->calcAdjust; - outputGain = mySps->outputGain; - - input = mySps->source; - output = mySps->sink; - x = mySps->x; - nx = mySps->nx; - coef = mySps->coef; - - decimator = mySps->decimator; - decimate = mySps->decimate; - interpolate = mySps->interpolate; - - setpt = mySps->setpt; - compOut = mySps->compOut; - - inputGain = mySps->inputGain; - outputGain = mySps->outputGain; - numChanOut = mySps->numChanOut; - selChanOut = mySps->selChanOut; - mixOut = mySps->mixOut; - monoOut = mySps->monoOut; - - amax=mySps->amax; - amin=mySps->amin; - - discfactor=mySps->discfactor; - hyst=mySps->hyst; - setpt=mySps->setpt; - nsamples=mySps->nSamples; - - if(mySps->option==3) - { - mySps->option=0; - mySps->enabled=0; - for(i=0;i<nsamples;i++) - { - if(monoOut) - output[(i*2)]=output[(i*2)+1]=0; - else - output[(i*numChanOut)+selChanOut]=0; - } - return 0; - } - - ii=0; - for(i=0;i<nsamples;i++) - { - int ix; - - int64_t y=0; - - if(decimate<0) - { - decimator=decimate; - } - - for(ix=0;ix<interpolate;ix++) - { - i16 n; - y=0; - - for(n=nx-1; n>0; n--) - x[n] = x[n-1]; - x[0] = (input[i]*inputGain)/M_Q8; - - #if 0 - --decimator; - if(decimator<=0) - { - decimator=decimate; - for(n=0; n<nx; n++) - y += coef[n] * x[n]; - y /= (outputGain*3); - output[ii++]=y; - } - #else - for(n=0; n<nx; n++) - y += coef[n] * x[n]; - - y=((y/calcAdjust)*outputGain)/M_Q8; - - if(mixOut){ - if(monoOut){ - output[(ii*2)]=output[(ii*2)+1]+=y; - } - else{ - output[(ii*numChanOut)+selChanOut]+=y; - } - } - else{ - if(monoOut){ - output[(ii*2)]=output[(ii*2)+1]=y; - } - else{ - output[(ii*numChanOut)+selChanOut]=y; - } - } - ii++; - #endif - } - - // amplitude detector - if(setpt) - { - i16 accum=y; - - if(accum>amax) - { - amax=accum; - discounteru=discfactor; - } - else if(--discounteru<=0) - { - discounteru=discfactor; - amax=(i32)((amax*32700)/32768); - } - - if(accum<amin) - { - amin=accum; - discounterl=discfactor; - } - else if(--discounterl<=0) - { - discounterl=discfactor; - amin=(i32)((amin*32700)/32768); - } - - apeak = (i32)(amax-amin)/2; - - if(apeak>setpt)compOut=1; - else if(compOut&&(apeak<(setpt-hyst)))compOut=0; - } - } - - mySps->decimator = decimator; - - mySps->amax=amax; - mySps->amin=amin; - mySps->apeak=apeak; - mySps->discounteru=discounteru; - mySps->discounterl=discounterl; - - mySps->compOut=compOut; - - return 0; -} -/* - general purpose integrator lpf -*/ -i16 gp_inte_00(t_pmr_sps *mySps) -{ - i16 npoints; - i16 *input, *output; - - i32 inputGain, outputGain,calcAdjust; - i32 i; - i32 accum; - - i32 state00; - i16 coeff00, coeff01; - - TRACEX(("gp_inte_00() %i\n",mySps->enabled)); - if(!mySps->enabled)return(1); - - input = mySps->source; - output = mySps->sink; - - npoints=mySps->nSamples; - - inputGain=mySps->inputGain; - outputGain=mySps->outputGain; - calcAdjust=mySps->calcAdjust; - - coeff00=((i16*)mySps->coef)[0]; - coeff01=((i16*)mySps->coef)[1]; - state00=((i32*)mySps->x)[0]; - - // note fixed gain of 2 to compensate for attenuation - // in passband - - for(i=0;i<npoints;i++) - { - accum=input[i]; - state00 = accum + (state00*coeff01)/M_Q15; - accum = (state00*coeff00)/(M_Q15/4); - output[i]=(accum*outputGain)/M_Q8; - } - - ((i32*)(mySps->x))[0]=state00; - - return 0; -} -/* - general purpose differentiator hpf -*/ -i16 gp_diff(t_pmr_sps *mySps) -{ - i16 *input, *output; - i16 npoints; - i32 inputGain, outputGain, calcAdjust; - i32 i; - i32 temp0,temp1; - i16 x0; - i32 y0; - i16 a0,a1; - i16 b0; - i16 *coef; - i16 *x; - - input = mySps->source; - output = mySps->sink; - - npoints=mySps->nSamples; - - inputGain=mySps->inputGain; - outputGain=mySps->outputGain; - calcAdjust=mySps->calcAdjust; - - coef=(i16*)(mySps->coef); - x=(i16*)(mySps->x); - a0=coef[0]; - a1=coef[1]; - b0=coef[2]; - - x0=x[0]; - - TRACEX(("gp_diff()\n")); - - for (i=0;i<npoints;i++) - { - temp0 = x0 * a1; - x0 = input[i]; - temp1 = input[i] * a0; - y0 = (temp0 + temp1)/calcAdjust; - output[i]=(y0*outputGain)/M_Q8; - } - - x[0]=x0; - - return 0; -} -/* ---------------------------------------------------------------------- - CenterSlicer -*/ -i16 CenterSlicer(t_pmr_sps *mySps) -{ - i16 npoints,lhit,uhit; - i16 *input, *output, *buff; - - i32 inputGain, outputGain, inputGainB; - i32 i; - i32 accum; - - i32 amax; // buffer amplitude maximum - i32 amin; // buffer amplitude minimum - i32 apeak; // buffer amplitude peak - i32 center; - i32 setpt; // amplitude set point for peak tracking - - i32 discounteru; // amplitude detector integrator discharge counter upper - i32 discounterl; // amplitude detector integrator discharge counter lower - i32 discfactor; // amplitude detector integrator discharge factor - - TRACEX(("CenterSlicer() %i\n",mySps->enabled)); - - input = mySps->source; - output = mySps->sink; - buff = mySps->buff; - - npoints=mySps->nSamples; - - inputGain=mySps->inputGain; - outputGain=mySps->outputGain; - inputGainB=mySps->inputGainB; - - amax=mySps->amax; - amin=mySps->amin; - setpt=mySps->setpt; - apeak=mySps->apeak; - discounteru=mySps->discounteru; - discounterl=mySps->discounterl; - - discfactor=mySps->discfactor; - npoints=mySps->nSamples; - - for(i=0;i<npoints;i++) - { - accum=input[i]; - - lhit=uhit=0; - - if(accum>amax) - { - amax=accum; - uhit=1; - if(amin<(amax-setpt)) - { - amin=(amax-setpt); - lhit=1; - } - } - else if(accum<amin) - { - amin=accum; - lhit=1; - if(amax>(amin+setpt)) - { - amax=(amin+setpt); - uhit=1; - } - } - - if(--discounteru<=0 && amax>0) - { - amax--; - uhit=1; - } - - if(--discounterl<=0 && amin<0) - { - amin++; - lhit=1; - } - - if(uhit)discounteru=discfactor; - if(lhit)discounterl=discfactor; - - apeak = (amax-amin)/2; - center = (amax+amin)/2; - accum = accum - center; - output[i]=accum; - - // do limiter function - if(accum>inputGainB)accum=inputGainB; - else if(accum<-inputGainB)accum=-inputGainB; - buff[i]=accum; - - #if XPMR_DEBUG0 == 1 - #if 0 - mySps->debugBuff0[i]=center; - #endif - #if 0 - if(mySps->parentChan->frameCountRx&0x01) mySps->parentChan->prxDebug1[i]=amax; - else mySps->parentChan->prxDebug1[i]=amin; - #endif - #endif - } - - mySps->amax=amax; - mySps->amin=amin; - mySps->apeak=apeak; - mySps->discounteru=discounteru; - mySps->discounterl=discounterl; - - return 0; -} -/* ---------------------------------------------------------------------- - MeasureBlock - determine peak amplitude -*/ -i16 MeasureBlock(t_pmr_sps *mySps) -{ - i16 npoints; - i16 *input, *output; - - i32 inputGain, outputGain; - i32 i; - i32 accum; - - i16 amax; // buffer amplitude maximum - i16 amin; // buffer amplitude minimum - i16 apeak=0; // buffer amplitude peak (peak to peak)/2 - i16 setpt; // amplitude set point for amplitude comparator - - i32 discounteru; // amplitude detector integrator discharge counter upper - i32 discounterl; // amplitude detector integrator discharge counter lower - i32 discfactor; // amplitude detector integrator discharge factor - - TRACEX(("MeasureBlock() %i\n",mySps->enabled)); - - if(!mySps->enabled)return 1; - - if(mySps->option==3) - { - mySps->amax = mySps->amin = mySps->apeak = \ - mySps->discounteru = mySps->discounterl = \ - mySps->enabled = 0; - return 1; - } - - input = mySps->source; - output = mySps->sink; - - npoints=mySps->nSamples; - - inputGain=mySps->inputGain; - outputGain=mySps->outputGain; - - amax=mySps->amax; - amin=mySps->amin; - setpt=mySps->setpt; - discounteru=mySps->discounteru; - discounterl=mySps->discounterl; - - discfactor=mySps->discfactor; - npoints=mySps->nSamples; - - for(i=0;i<npoints;i++) - { - accum=input[i]; - - if(accum>amax) - { - amax=accum; - discounteru=discfactor; - } - else if(--discounteru<=0) - { - discounteru=discfactor; - amax=(i32)((amax*32700)/32768); - } - - if(accum<amin) - { - amin=accum; - discounterl=discfactor; - } - else if(--discounterl<=0) - { - discounterl=discfactor; - amin=(i32)((amin*32700)/32768); - } - - apeak = (i32)(amax-amin)/2; - if(output)output[i]=apeak; - } - - mySps->amax=amax; - mySps->amin=amin; - mySps->apeak=apeak; - mySps->discounteru=discounteru; - mySps->discounterl=discounterl; - if(apeak>=setpt) mySps->compOut=1; - else mySps->compOut=0; - - //TRACEX((" -MeasureBlock()=%i\n",mySps->apeak)); - return 0; -} -/* - SoftLimiter -*/ -i16 SoftLimiter(t_pmr_sps *mySps) -{ - i16 npoints; - //i16 samples, lhit,uhit; - i16 *input, *output; - - i32 inputGain, outputGain; - i32 i; - i32 accum; - i32 tmp; - - i32 amax; // buffer amplitude maximum - i32 amin; // buffer amplitude minimum - //i32 apeak; // buffer amplitude peak - i32 setpt; // amplitude set point for amplitude comparator - i16 compOut; // amplitude comparator output - - input = mySps->source; - output = mySps->sink; - - inputGain=mySps->inputGain; - outputGain=mySps->outputGain; - - npoints=mySps->nSamples; - - setpt=mySps->setpt; - amax=(setpt*124)/128; - amin=-amax; - - TRACEX(("SoftLimiter() %i %i %i) \n",amin, amax,setpt)); - - for(i=0;i<npoints;i++) - { - accum=input[i]; - //accum=input[i]*mySps->inputGain/256; - - if(accum>setpt) - { - tmp=((accum-setpt)*4)/128; - accum=setpt+tmp; - if(accum>amax)accum=amax; - compOut=1; - accum=setpt; - } - else if(accum<-setpt) - { - tmp=((accum+setpt)*4)/128; - accum=(-setpt)-tmp; - if(accum<amin)accum=amin; - compOut=1; - accum=-setpt; - } - - output[i]=(accum*outputGain)/M_Q8; - } - - return 0; -} -/* - SigGen() - sine, square function generator - sps overloaded values - discfactor = phase factor - discfactoru = phase index - if source is not NULL then mix it in! - - sign table and output gain are in Q15 format (32767=.999) -*/ -i16 SigGen(t_pmr_sps *mySps) -{ - #define PH_FRACT_FACT 128 - - i32 ph; - i16 i,outputgain,waveform,numChanOut,selChanOut; - i32 accum; - - TRACEX(("SigGen(%i) \n",mySps->option)); - - if(!mySps->freq ||!mySps->enabled)return 0; - - outputgain=mySps->outputGain; - waveform=0; - numChanOut=mySps->numChanOut; - selChanOut=mySps->selChanOut; - - if(mySps->option==1) - { - mySps->option=0; - mySps->state=1; - mySps->discfactor= - (SAMPLES_PER_SINE*mySps->freq*PH_FRACT_FACT)/mySps->sampleRate/10; - - TRACEX((" SigGen() discfactor = %i\n",mySps->discfactor)); - if(mySps->discounterl)mySps->state=2; - } - else if(mySps->option==2) - { - i16 shiftfactor=CTCSS_TURN_OFF_SHIFT; - // phase shift request - mySps->option=0; - mySps->state=2; - mySps->discounterl=CTCSS_TURN_OFF_TIME-(2*MS_PER_FRAME); // - - mySps->discounteru = \ - (mySps->discounteru + (((SAMPLES_PER_SINE*shiftfactor)/360)*PH_FRACT_FACT)) % (SAMPLES_PER_SINE*PH_FRACT_FACT); - //printf("shiftfactor = %i\n",shiftfactor); - //shiftfactor+=10; - } - else if(mySps->option==3) - { - // stop it and clear the output buffer - mySps->option=0; - mySps->state=0; - mySps->enabled=0; - for(i=0;i<mySps->nSamples;i++) - mySps->sink[(i*numChanOut)+selChanOut]=0; - return(0); - } - else if(mySps->state==2) - { - // doing turn off - mySps->discounterl-=MS_PER_FRAME; - if(mySps->discounterl<=0) - { - mySps->option=3; - mySps->state=2; - } - } - else if(mySps->state==0) - { - return(0); - } - - ph=mySps->discounteru; - - for(i=0;i<mySps->nSamples;i++) - { - if(!waveform) - { - // sine - //tmp=(sinetablex[ph/PH_FRACT_FACT]*amplitude)/M_Q16; - accum=sinetablex[ph/PH_FRACT_FACT]; - accum=(accum*outputgain)/M_Q8; - } - else - { - // square - if(ph>SAMPLES_PER_SINE/2) - accum=outputgain/M_Q8; - else - accum=-outputgain/M_Q8; - } - - if(mySps->source)accum+=mySps->source[i]; - - mySps->sink[(i*numChanOut)+selChanOut]=accum; - - ph=(ph+mySps->discfactor)%(SAMPLES_PER_SINE*PH_FRACT_FACT); - } - - mySps->discounteru=ph; - - return 0; -} -/* - adder/mixer - takes existing buffer and adds source buffer to destination buffer - sink buffer = (sink buffer * gain) + source buffer -*/ -i16 pmrMixer(t_pmr_sps *mySps) -{ - i32 accum; - i16 i, *input, *inputB, *output; - i16 inputGain, inputGainB; // apply to input data in Q7.8 format - i16 outputGain; // apply to output data in Q7.8 format - i16 discounteru,discounterl,amax,amin,setpt,discfactor; - i16 npoints,uhit,lhit,apeak,measPeak; - - TRACEX(("pmrMixer()\n")); - - input = mySps->source; - inputB = mySps->sourceB; - output = mySps->sink; - - inputGain=mySps->inputGain; - inputGainB=mySps->inputGainB; - outputGain=mySps->outputGain; - - amax=mySps->amax; - amin=mySps->amin; - setpt=mySps->setpt; - discounteru=mySps->discounteru; - discounterl=mySps->discounteru; - - discfactor=mySps->discfactor; - npoints=mySps->nSamples; - measPeak=mySps->measPeak; - - for(i=0;i<npoints;i++) - { - accum = ((input[i]*inputGain)/M_Q8) + - ((inputB[i]*inputGainB)/M_Q8); - - accum=(accum*outputGain)/M_Q8; - output[i]=accum; - - if(measPeak){ - lhit=uhit=0; - - if(accum>amax){ - amax=accum; - uhit=1; - if(amin<(amax-setpt)){ - amin=(amax-setpt); - lhit=1; - } - } - else if(accum<amin){ - amin=accum; - lhit=1; - if(amax>(amin+setpt)){ - amax=(amin+setpt); - uhit=1; - } - } - - if(--discounteru<=0 && amax>0){ - amax--; - uhit=1; - } - - if(--discounterl<=0 && amin<0){ - amin++; - lhit=1; - } - - if(uhit)discounteru=discfactor; - if(lhit)discounterl=discfactor; - } - } - - if(measPeak){ - apeak = (amax-amin)/2; - mySps->apeak=apeak; - mySps->amax=amax; - mySps->amin=amin; - mySps->discounteru=discounteru; - mySps->discounterl=discounterl; - } - - return 0; -} -/* - DelayLine -*/ -i16 DelayLine(t_pmr_sps *mySps) -{ - i16 *input, *output, *buff; - i16 i, npoints,buffsize,inindex,outindex; - - TRACEX((" DelayLine() %i\n",mySps->enabled)); - - input = mySps->source; - output = mySps->sink; - buff = (i16*)(mySps->buff); - buffsize = mySps->buffSize; - npoints = mySps->nSamples; - - outindex = mySps->buffOutIndex; - inindex = outindex + mySps->buffLead; - - for(i=0;i<npoints;i++) - { - inindex %= buffsize; - outindex %= buffsize; - - buff[inindex]=input[i]; - output[i]=buff[outindex]; - inindex++; - outindex++; - } - mySps->buffOutIndex=outindex; - - return 0; -} -/* - Continuous Tone Coded Squelch (CTCSS) Detector -*/ -i16 ctcss_detect(t_pmr_chan *pmrChan) -{ - i16 i,points2do, points=0, *pInput, hit, thit,relax; - i16 tnum, tmp, indexWas=0, indexNow, gain, peakwas=0, diffpeak; - i16 difftrig; - i16 lasttv0=0, lasttv1=0, lasttv2=0, tv0, tv1, tv2, indexDebug; - - TRACEX(("ctcss_detect(%p) %i %i %i %i\n",pmrChan, - pmrChan->rxCtcss->enabled, - pmrChan->rxCtcssIndex, - pmrChan->rxCtcss->testIndex, - pmrChan->rxCtcss->decode)); - - if(!pmrChan->rxCtcss->enabled)return(1); - - relax = pmrChan->rxCtcss->relax; - pInput = pmrChan->rxCtcss->input; - gain = pmrChan->rxCtcss->gain; - - if(relax) difftrig=(-0.1*M_Q15); - else difftrig=(-0.05*M_Q15); - - thit=hit=-1; - - //TRACEX((" ctcss_detect() %i %i %i %i\n", CTCSS_NUM_CODES,0,0,0)); - - for(tnum=0;tnum<CTCSS_NUM_CODES;tnum++) - { - i32 accum, peak; - t_tdet *ptdet; - i16 fudgeFactor; - i16 binFactor; - - //TRACEX((" ctcss_detect() tnum=%i %i\n",tnum,pmrChan->rxCtcssMap[tnum])); - - if( (pmrChan->rxCtcssMap[tnum] < 0) || - (pmrChan->rxCtcss->decode>=0 && (tnum!= pmrChan->rxCtcss->decode)) || - (!pmrChan->rxCtcss->multiFreq && (tnum!= pmrChan->rxCtcssIndex)) - ) - continue; - - //TRACEX((" ctcss_detect() tnum=%i\n",tnum)); - - ptdet=&(pmrChan->rxCtcss->tdet[tnum]); - indexDebug=0; - points=points2do=pmrChan->nSamplesRx; - fudgeFactor=ptdet->fudgeFactor; - binFactor=ptdet->binFactor; - - while(ptdet->counter < (points2do*CTCSS_SCOUNT_MUL)) - { - //TRACEX((" ctcss_detect() - inner loop\n")); - tmp=(ptdet->counter/CTCSS_SCOUNT_MUL)+1; - ptdet->counter-=(tmp*CTCSS_SCOUNT_MUL); - points2do-=tmp; - indexNow=points-points2do; - - ptdet->counter += ptdet->counterFactor; - - accum = pInput[indexNow-1]; // dude's major bug fix! - - peakwas=ptdet->peak; - - ptdet->z[ptdet->zIndex]+= - (((accum - ptdet->z[ptdet->zIndex])*binFactor)/M_Q15); - - peak = abs(ptdet->z[0]-ptdet->z[2]) + abs(ptdet->z[1]-ptdet->z[3]); - - if (ptdet->peak < peak) - ptdet->peak += ( ((peak-ptdet->peak)*binFactor)/M_Q15); - else - ptdet->peak=peak; - - { - static const i16 a0=13723; - static const i16 a1=-13723; - i32 temp0,temp1; - i16 x0; - - //differentiate - x0=ptdet->zd; - temp0 = x0 * a1; - ptdet->zd = ptdet->peak; - temp1 = ptdet->peak * a0; - diffpeak = (temp0 + temp1)/1024; - } - - if(diffpeak<(-0.03*M_Q15))ptdet->dvd-=4; - else if(ptdet->dvd<0)ptdet->dvd++; - - if((ptdet->dvd < -12) && diffpeak > (-0.02*M_Q15))ptdet->dvu+=2; - else if(ptdet->dvu)ptdet->dvu--; - - tmp=ptdet->setpt; - if(pmrChan->rxCtcss->decode==tnum) - { - if(relax)tmp=(tmp*55)/100; - else tmp=(tmp*80)/100; - } - - if(ptdet->peak > tmp) - { - if(ptdet->decode<(fudgeFactor*32))ptdet->decode++; - } - else if(pmrChan->rxCtcss->decode==tnum) - { - if(ptdet->peak > ptdet->hyst)ptdet->decode--; - else if(relax) ptdet->decode--; - else ptdet->decode-=4; - } - else - { - ptdet->decode=0; - } - - if((pmrChan->rxCtcss->decode==tnum) && !relax && (ptdet->dvu > (0.00075*M_Q15))) - { - ptdet->decode=0; - ptdet->z[0]=ptdet->z[1]=ptdet->z[2]=ptdet->z[3]=ptdet->dvu=0; - //printf("ctcss_detect() turnoff code!\n"); - } - - if(ptdet->decode<0 || !pmrChan->rxCarrierDetect)ptdet->decode=0; - - if(ptdet->decode>=fudgeFactor)thit=tnum; - - #if XPMR_DEBUG0 == 1 - //if(thit>=0 && thit==tnum) - // printf(" ctcss_detect() %i %i %i %i \n",tnum,ptdet->peak,ptdet->setpt,ptdet->hyst); - - // tv0=accum; - tv0=ptdet->peak; - tv1=diffpeak; - tv2=ptdet->dvu; - - //tv1=ptdet->zi*100; - while(indexDebug<indexNow) - { - if(indexDebug==0)lasttv0=ptdet->pDebug0[points-1]; - if(ptdet->pDebug0)ptdet->pDebug0[indexDebug]=lasttv0; - - if(indexDebug==0)lasttv1=ptdet->pDebug1[points-1]; - if(ptdet->pDebug1)ptdet->pDebug1[indexDebug]=lasttv1; - - if(indexDebug==0)lasttv2=ptdet->pDebug2[points-1]; - if(ptdet->pDebug2)ptdet->pDebug2[indexDebug]=lasttv2; - - indexDebug++; - } - lasttv0=tv0; - lasttv1=tv1; - lasttv2=tv2*100; - #endif - indexWas=indexNow; - ptdet->zIndex=(++ptdet->zIndex)%4; - } - ptdet->counter-=(points2do*CTCSS_SCOUNT_MUL); - - #if XPMR_DEBUG0 == 1 - for(i=indexWas;i<points;i++) - { - if(ptdet->pDebug0)ptdet->pDebug0[i]=lasttv0; - if(ptdet->pDebug1)ptdet->pDebug1[i]=lasttv1; - if(ptdet->pDebug2)ptdet->pDebug2[i]=lasttv2; - } - #endif - } - - //TRACEX((" ctcss_detect() thit %i\n",thit)); - - if(pmrChan->rxCtcss->BlankingTimer>0)pmrChan->rxCtcss->BlankingTimer-=points; - if(pmrChan->rxCtcss->BlankingTimer<0)pmrChan->rxCtcss->BlankingTimer=0; - - if(thit>=0 && pmrChan->rxCtcss->decode<0 && !pmrChan->rxCtcss->BlankingTimer) - { - pmrChan->rxCtcss->decode=thit; - } - else if(thit<0 && pmrChan->rxCtcss->decode>=0) - { - pmrChan->rxCtcss->BlankingTimer=SAMPLE_RATE_NETWORK/5; - pmrChan->rxCtcss->decode=-1; - - for(tnum=0;tnum<CTCSS_NUM_CODES;tnum++) - { - t_tdet *ptdet=NULL; - ptdet=&(pmrChan->rxCtcss->tdet[tnum]); - ptdet->decode=0; - ptdet->z[0]=ptdet->z[1]=ptdet->z[2]=ptdet->z[3]=0; - } - } - //TRACEX((" ctcss_detect() thit %i %i\n",thit,pmrChan->rxCtcss->decode)); - return(0); -} -/* - TxTestTone -*/ -static i16 TxTestTone(t_pmr_chan *pChan, i16 function) -{ - if(function==1) - { - pChan->spsSigGen1->enabled=1; - pChan->spsSigGen1->option=1; - pChan->spsTx->source=pChan->spsSigGen1->sink; - } - else - { - pChan->spsSigGen1->option=3; - } - return 0; -} -/* - assumes: - sampling rate is 48KS/s - samples are all 16 bits - samples are filtered and decimated by 1/6th -*/ -t_pmr_chan *createPmrChannel(t_pmr_chan *tChan, i16 numSamples) -{ - i16 i, *inputTmp; - - t_pmr_chan *pChan; - t_pmr_sps *pSps; - t_dec_ctcss *pDecCtcss; - t_tdet *ptdet; - - TRACEX(("createPmrChannel(%p,%i)\n",tChan,numSamples)); - - pChan = (t_pmr_chan *)calloc(sizeof(t_pmr_chan),1); - - if(pChan==NULL) - { - printf("createPmrChannel() failed\n"); - return(NULL); - } - - pChan->nSamplesRx=numSamples; - pChan->nSamplesTx=numSamples; - - pChan->index=pmrChanIndex++; - - for(i=0;i<CTCSS_NUM_CODES;i++) - { - pChan->rxCtcssMap[i]=-1; - } - - pChan->rxCtcssIndex=-1; - - if(tChan==NULL) - { - pChan->rxNoiseSquelchEnable=0; - pChan->rxHpfEnable=0; - pChan->rxDeEmpEnable=0; - pChan->rxCenterSlicerEnable=0; - pChan->rxCtcssDecodeEnable=0; - pChan->rxDcsDecodeEnable=0; - - pChan->rxCarrierPoint = 17000; - pChan->rxCarrierHyst = 2500; - - pChan->rxCtcssFreq=103.5; - - pChan->txHpfEnable=0; - pChan->txLimiterEnable=0; - pChan->txPreEmpEnable=0; - pChan->txLpfEnable=1; - pChan->txCtcssFreq=103.5; - pChan->txMixA=TX_OUT_VOICE; - pChan->txMixB=TX_OUT_LSD; - } - else - { - pChan->rxDemod=tChan->rxDemod; - pChan->rxCdType=tChan->rxCdType; - pChan->rxSquelchPoint = tChan->rxSquelchPoint; - pChan->rxCarrierHyst = 3000; - pChan->rxCtcssFreq=tChan->rxCtcssFreq; - - for(i=0;i<CTCSS_NUM_CODES;i++) - pChan->rxCtcssMap[i]=tChan->rxCtcssMap[i]; - - pChan->txMod=tChan->txMod; - pChan->txHpfEnable=1; - pChan->txLpfEnable=1; - pChan->txCtcssFreq=tChan->txCtcssFreq; - pChan->txMixA=tChan->txMixA; - pChan->txMixB=tChan->txMixB; - pChan->radioDuplex=tChan->radioDuplex; - } - - TRACEX(("misc settings \n")); - - if(pChan->rxCdType==CD_XPMR_NOISE){ - pChan->rxNoiseSquelchEnable=1; - } - - if(pChan->rxDemod==RX_AUDIO_FLAT){ - pChan->rxHpfEnable=1; - pChan->rxDeEmpEnable=1; - } - - pChan->rxCarrierPoint=(pChan->rxSquelchPoint*32767)/100; - pChan->rxCarrierHyst = 3000; //pChan->rxCarrierPoint/15; - - pChan->rxDcsDecodeEnable=0; - - if(pChan->rxCtcssFreq!=0){ - pChan->rxHpfEnable=1; - pChan->rxCenterSlicerEnable=1; - pChan->rxCtcssDecodeEnable=1; - pChan->rxCtcssIndex=CtcssFreqIndex(pChan->rxCtcssFreq); - } - - if(pChan->txMod){ - pChan->txPreEmpEnable=1; - pChan->txLimiterEnable=1; - } - - TRACEX(("calloc buffers \n")); - - pChan->pRxDemod = calloc(numSamples,2); - pChan->pRxNoise = calloc(numSamples,2); - pChan->pRxBase = calloc(numSamples,2); - pChan->pRxHpf = calloc(numSamples,2); - pChan->pRxLsd = calloc(numSamples,2); - pChan->pRxSpeaker = calloc(numSamples,2); - pChan->pRxCtcss = calloc(numSamples,2); - pChan->pRxDcTrack = calloc(numSamples,2); - pChan->pRxLsdLimit = calloc(numSamples,2); - - - pChan->pTxBase = calloc(numSamples,2); - pChan->pTxHpf = calloc(numSamples,2); - pChan->pTxPreEmp = calloc(numSamples,2); - pChan->pTxLimiter = calloc(numSamples,2); - pChan->pTxLsd = calloc(numSamples,2); - pChan->pTxLsdLpf = calloc(numSamples,2); - pChan->pTxComposite = calloc(numSamples,2); - pChan->pSigGen0 = calloc(numSamples,2); - pChan->pSigGen1 = calloc(numSamples,2); - - pChan->pTxCode = calloc(numSamples,2); - pChan->pTxOut = calloc(numSamples,2*2*6); // output buffer - - #if XPMR_DEBUG0 == 1 - pChan->pTxPttIn = calloc(numSamples,2); - pChan->pTxPttOut = calloc(numSamples,2); - pChan->prxDebug0 = calloc(numSamples,2); - pChan->prxDebug1 = calloc(numSamples,2); - pChan->prxDebug2 = calloc(numSamples,2); - pChan->prxDebug3 = calloc(numSamples,2); - pChan->ptxDebug0 = calloc(numSamples,2); - pChan->ptxDebug1 = calloc(numSamples,2); - pChan->ptxDebug2 = calloc(numSamples,2); - pChan->ptxDebug3 = calloc(numSamples,2); - pChan->pNull = calloc(numSamples,2); - for(i=0;i<numSamples;i++)pChan->pNull[i]=((i%(numSamples/2))*8000)-4000; - #endif - - TRACEX(("create ctcss\n")); - - pDecCtcss = (t_dec_ctcss *)calloc(sizeof(t_dec_ctcss),1); - - pChan->rxCtcss=pDecCtcss; - pDecCtcss->enabled=1; - pDecCtcss->gain=1*M_Q8; - pDecCtcss->limit=8192; - pDecCtcss->input=pChan->pRxLsdLimit; - pDecCtcss->testIndex=pChan->rxCtcssIndex; - if(!pDecCtcss->testIndex)pDecCtcss->testIndex=1; - pChan->rxCtcssMap[pChan->rxCtcssIndex]=pChan->rxCtcssIndex; - pDecCtcss->decode=-1; - - for(i=0;i<CTCSS_NUM_CODES;i++) - { - ptdet=&(pChan->rxCtcss->tdet[i]); - ptdet->state=1; - ptdet->setpt=(M_Q15*0.067); // 0.069 - ptdet->hyst =(M_Q15*0.020); - ptdet->counterFactor=coef_ctcss_div[i]; - ptdet->binFactor=(M_Q15*0.135); // was 0.140 - ptdet->fudgeFactor=8; - } - - // General Purpose Function Generator - pSps=pChan->spsSigGen1=createPmrSps(); - pSps->parentChan=pChan; - pSps->sink=pChan->pSigGen1; - pSps->numChanOut=1; - pSps->selChanOut=0; - pSps->sigProc=SigGen; - pSps->nSamples=pChan->nSamplesTx; - pSps->sampleRate=SAMPLE_RATE_NETWORK; - pSps->freq=10000; // in increments of 0.1 Hz - pSps->outputGain=(.25*M_Q8); - pSps->option=0; - pSps->interpolate=1; - pSps->decimate=1; - pSps->enabled=0; - - - // CTCSS ENCODER - pSps = pChan->spsSigGen0 = createPmrSps(); - pSps->parentChan=pChan; - pSps->sink=pChan->pTxLsd; - pSps->sigProc=SigGen; - pSps->numChanOut=1; - pSps->selChanOut=0; - pSps->nSamples=pChan->nSamplesTx; - pSps->sampleRate=SAMPLE_RATE_NETWORK; - pSps->freq=pChan->txCtcssFreq*10; // in increments of 0.1 Hz - pSps->outputGain=(0.5*M_Q8); - pSps->option=0; - pSps->interpolate=1; - pSps->decimate=1; - pSps->enabled=0; - - - // Tx LSD Low Pass Filter - pSps=pChan->spsTxLsdLpf=pSps->nextSps=createPmrSps(); - pSps->source=pChan->pTxLsd; - pSps->sink=pChan->pTxLsdLpf; - pSps->sigProc=pmr_gp_fir; - pSps->enabled=0; - pSps->numChanOut=1; - pSps->selChanOut=0; - pSps->nSamples=pChan->nSamplesTx; - pSps->decimator=pSps->decimate=1; - pSps->interpolate=1; - pSps->inputGain=(1*M_Q8); - pSps->outputGain=(1*M_Q8); - - if(pChan->txCtcssFreq>203.0) - { - pSps->ncoef=taps_fir_lpf_250_9_66; - pSps->size_coef=2; - pSps->coef=(void*)coef_fir_lpf_250_9_66; - pSps->nx=taps_fir_lpf_250_9_66; - pSps->size_x=2; - pSps->x=(void*)(calloc(pSps->nx,pSps->size_x)); - pSps->calcAdjust=gain_fir_lpf_250_9_66; - } - else - { - pSps->ncoef=taps_fir_lpf_215_9_88; - pSps->size_coef=2; - pSps->coef=(void*)coef_fir_lpf_215_9_88; - pSps->nx=taps_fir_lpf_215_9_88; - pSps->size_x=2; - pSps->x=(void*)(calloc(pSps->nx,pSps->size_x)); - pSps->calcAdjust=gain_fir_lpf_215_9_88; - } - - pSps->inputGain=(1*M_Q8); - pSps->outputGain=(1*M_Q8); - - if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n"); - - - // RX Process - TRACEX(("create rx\n")); - pSps = NULL; - - // allocate space for first sps and set pointers - pSps=pChan->spsRx=createPmrSps(); - pSps->parentChan=pChan; - pSps->source=NULL; //set when called - pSps->sink=pChan->pRxBase; - pSps->sigProc=pmr_rx_frontend; - pSps->enabled=1; - pSps->decimator=pSps->decimate=6; - pSps->interpolate=pSps->interpolate=1; - pSps->nSamples=pChan->nSamplesRx; - pSps->ncoef=taps_fir_bpf_noise_1; - pSps->size_coef=2; - pSps->coef=(void*)coef_fir_lpf_3K_1; - pSps->coef2=(void*)coef_fir_bpf_noise_1; - pSps->nx=taps_fir_bpf_noise_1; - pSps->size_x=2; - pSps->x=(void*)(calloc(pSps->nx,pSps->size_coef)); - pSps->calcAdjust=(gain_fir_lpf_3K_1*256)/0x0100; - pSps->outputGain=(1.0*M_Q8); - pSps->discfactor=2; - pSps->hyst=pChan->rxCarrierHyst; - pSps->setpt=pChan->rxCarrierPoint; - pChan->prxSquelchAdjust=&pSps->setpt; - #if XPMR_DEBUG0 == 1 - pSps->debugBuff0=pChan->pRxDemod; - pSps->debugBuff1=pChan->pRxNoise; - pSps->debugBuff2=pChan->prxDebug0; - #endif - - - // allocate space for next sps and set pointers - // Rx SubAudible Decoder Low Pass Filter - pSps=pSps->nextSps=createPmrSps(); - pSps->parentChan=pChan; - pSps->source=pChan->pRxBase; - pSps->sink=pChan->pRxLsd; - pSps->sigProc=pmr_gp_fir; - pSps->enabled=1; - pSps->numChanOut=1; - pSps->selChanOut=0; - pSps->nSamples=pChan->nSamplesRx; - pSps->decimator=pSps->decimate=1; - pSps->interpolate=1; - - if(pChan->rxCtcssFreq>203.5) - { - pSps->ncoef=taps_fir_lpf_250_9_66; - pSps->size_coef=2; - pSps->coef=(void*)coef_fir_lpf_250_9_66; - pSps->nx=taps_fir_lpf_250_9_66; - pSps->size_x=2; - pSps->x=(void*)(calloc(pSps->nx,pSps->size_x)); - pSps->calcAdjust=gain_fir_lpf_250_9_66; - } - else - { - pSps->ncoef=taps_fir_lpf_215_9_88; - pSps->size_coef=2; - pSps->coef=(void*)coef_fir_lpf_215_9_88; - pSps->nx=taps_fir_lpf_215_9_88; - pSps->size_x=2; - pSps->x=(void*)(calloc(pSps->nx,pSps->size_x)); - pSps->calcAdjust=gain_fir_lpf_215_9_88; - } - - pSps->inputGain=(1*M_Q8); - pSps->outputGain=(1*M_Q8); - pChan->prxCtcssMeasure=pSps->sink; - pChan->prxCtcssAdjust=&(pSps->outputGain); - - - // allocate space for next sps and set pointers - // CenterSlicer - if(pChan->rxCenterSlicerEnable) - { - pSps=pSps->nextSps=createPmrSps(); - pSps->parentChan=pChan; - pSps->source=pChan->pRxLsd; - pSps->sink=pChan->pRxDcTrack; - pSps->buff=pChan->pRxLsdLimit; - pSps->sigProc=CenterSlicer; - pSps->enabled=1; - pSps->nSamples=pChan->nSamplesRx; - pSps->discfactor=800; - pSps->inputGain=(1*M_Q8); - pSps->outputGain=(1*M_Q8); - pSps->setpt=3000; - pSps->inputGainB=1000; // limiter set point - } - - // allocate space for next sps and set pointers - // Rx HPF - pSps=pSps->nextSps=createPmrSps(); - pSps->parentChan=pChan; - pChan->spsRxHpf=pSps; - pSps->source=pChan->pRxBase; - pSps->sink=pChan->pRxHpf; - pSps->sigProc=pmr_gp_fir; - pSps->enabled=1; - pSps->numChanOut=1; - pSps->selChanOut=0; - pSps->nSamples=pChan->nSamplesRx; - pSps->decimator=pSps->decimate=1; - pSps->interpolate=1; - pSps->ncoef=taps_fir_hpf_300_9_66; - pSps->size_coef=2; - pSps->coef=(void*)coef_fir_hpf_300_9_66; - pSps->nx=taps_fir_hpf_300_9_66; - pSps->size_x=2; - pSps->x=(void*)(calloc(pSps->nx,pSps->size_x)); - if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n"); - pSps->calcAdjust=gain_fir_hpf_300_9_66; - pSps->inputGain=(1*M_Q8); - pSps->outputGain=(1*M_Q8); - pChan->spsRxOut=pSps; - - // allocate space for next sps and set pointers - // Rx DeEmp - if(pChan->rxDeEmpEnable){ - pSps=pSps->nextSps=createPmrSps(); - pSps->parentChan=pChan; - pChan->spsRxDeEmp=pSps; - pSps->source=pChan->pRxHpf; - pSps->sink=pChan->pRxSpeaker; - pChan->spsRxOut=pSps; // OUTPUT STRUCTURE! maw - pSps->sigProc=gp_inte_00; - pSps->enabled=1; - pSps->nSamples=pChan->nSamplesRx; - - pSps->ncoef=taps_int_lpf_300_1_2; - pSps->size_coef=2; - pSps->coef=(void*)coef_int_lpf_300_1_2; - - pSps->nx=taps_int_lpf_300_1_2; - pSps->size_x=4; - pSps->x=(void*)(calloc(pSps->nx,pSps->size_x)); - if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n"); - pSps->calcAdjust=gain_int_lpf_300_1_2/2; - pSps->inputGain=(1.0*M_Q8); - pSps->outputGain=(1.0*M_Q8); - pChan->prxVoiceMeasure=pSps->sink; - pChan->prxVoiceAdjust=&(pSps->outputGain); - } - - if(pChan->rxDelayLineEnable) - { - TRACEX(("create delayline\n")); - pSps=pChan->spsDelayLine=pSps->nextSps=createPmrSps(); - pSps->sigProc=DelayLine; - pSps->source=pChan->pRxSpeaker; - pSps->sink=pChan->pRxSpeaker; - pSps->enabled=0; - pSps->inputGain=1*M_Q8; - pSps->outputGain=1*M_Q8; - pSps->nSamples=pChan->nSamplesRx; - pSps->buffSize=4096; - pSps->buff=calloc(4096,2); // one second maximum - pSps->buffLead = (SAMPLE_RATE_NETWORK*0.100); - pSps->buffOutIndex=0; - } - - if(pChan->rxCdType==CD_XPMR_VOX) - { - TRACEX(("create vox measureblock\n")); - pSps=pChan->spsRxVox=pSps->nextSps=createPmrSps(); - pSps->sigProc=MeasureBlock; - pSps->parentChan=pChan; - pSps->source=pChan->pRxBase; - pSps->sink=pChan->prxDebug1; - pSps->inputGain=1*M_Q8; - pSps->outputGain=1*M_Q8; - pSps->nSamples=pChan->nSamplesRx; - pSps->discfactor=3; - pSps->setpt=(0.01*M_Q15); - pSps->hyst=(pSps->setpt/10); - pSps->enabled=1; - } - - // tuning measure block - pSps=pChan->spsMeasure=pSps->nextSps=createPmrSps(); - pSps->parentChan=pChan; - pSps->source=pChan->spsRx->sink; - pSps->sink=pChan->prxDebug2; - pSps->sigProc=MeasureBlock; - pSps->enabled=0; - pSps->nSamples=pChan->nSamplesRx; - pSps->discfactor=10; - - pSps->nextSps=NULL; // last sps in chain RX - - - // CREATE TRANSMIT CHAIN - TRACEX((" create tx\n")); - inputTmp=NULL; - pSps = NULL; - - // allocate space for first sps and set pointers - - // Tx HPF SubAudible - if(pChan->txHpfEnable) - { - pSps=createPmrSps(); - pChan->spsTx=pSps; - pSps->source=pChan->pTxBase; - pSps->sink=pChan->pTxHpf; - pSps->sigProc=pmr_gp_fir; - pSps->enabled=1; - pSps->numChanOut=1; - pSps->selChanOut=0; - pSps->nSamples=pChan->nSamplesTx; - pSps->decimator=pSps->decimate=1; - pSps->interpolate=1; - pSps->ncoef=taps_fir_hpf_300_9_66; - pSps->size_coef=2; - pSps->coef=(void*)coef_fir_hpf_300_9_66; - pSps->nx=taps_fir_hpf_300_9_66; - pSps->size_x=2; - pSps->x=(void*)(calloc(pSps->nx,pSps->size_x)); - if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n"); - pSps->calcAdjust=gain_fir_hpf_300_9_66; - pSps->inputGain=(1*M_Q8); - pSps->outputGain=(1*M_Q8); - inputTmp=pChan->pTxHpf; - } - - // Tx PreEmphasis - if(pChan->txPreEmpEnable) - { - if(pSps==NULL) pSps=pChan->spsTx=createPmrSps(); - else pSps=pSps->nextSps=createPmrSps(); - - pSps->parentChan=pChan; - pSps->source=inputTmp; - pSps->sink=pChan->pTxPreEmp; - - pSps->sigProc=gp_diff; - pSps->enabled=1; - pSps->nSamples=pChan->nSamplesTx; - - pSps->ncoef=taps_int_hpf_4000_1_2; - pSps->size_coef=2; - pSps->coef=(void*)coef_int_hpf_4000_1_2; - - pSps->nx=taps_int_hpf_4000_1_2; - pSps->size_x=2; - pSps->x=(void*)(calloc(pSps->nx,pSps->size_x)); - if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n"); - pSps->outputGain=(1*M_Q8); - pSps->calcAdjust=gain_int_hpf_4000_1_2; - pSps->inputGain=(1*M_Q8); - pSps->outputGain=(1*M_Q8); - inputTmp=pSps->sink; - } - - // Tx Limiter - if(pChan->txLimiterEnable) - { - if(pSps==NULL) pSps=pChan->spsTx=createPmrSps(); - else pSps=pSps->nextSps=createPmrSps(); - pSps->source=inputTmp; - pSps->sink=pChan->pTxLimiter; - pSps->sigProc=SoftLimiter; - pSps->enabled=1; - pSps->nSamples=pChan->nSamplesTx; - pSps->inputGain=(1*M_Q8); - pSps->outputGain=(1*M_Q8); - pSps->setpt=12000; - inputTmp=pSps->sink; - } - - // Composite Mix of Voice and LSD - if((pChan->txMixA==TX_OUT_COMPOSITE)||(pChan->txMixB==TX_OUT_COMPOSITE)) - { - if(pSps==NULL) - pSps=pChan->spsTx=createPmrSps(); - else - pSps=pSps->nextSps=createPmrSps(); - pSps->source=inputTmp; - pSps->sourceB=pChan->pTxLsdLpf; //asdf ??? !!! maw pTxLsdLpf - pSps->sink=pChan->pTxComposite; - pSps->sigProc=pmrMixer; - pSps->enabled=1; - pSps->nSamples=pChan->nSamplesTx; - pSps->inputGain=2*M_Q8; - pSps->inputGainB=1*M_Q8/8; - pSps->outputGain=1*M_Q8; - pSps->setpt=0; - inputTmp=pSps->sink; - pChan->ptxCtcssAdjust=&pSps->inputGainB; - } - - // Chan A Upsampler and Filter - if(pSps==NULL) pSps=pChan->spsTx=createPmrSps(); - else pSps=pSps->nextSps=createPmrSps(); - - pChan->spsTxOutA=pSps; - if(!pChan->spsTx)pChan->spsTx=pSps; - pSps->parentChan=pChan; - - if(pChan->txMixA==TX_OUT_COMPOSITE) - { - pSps->source=pChan->pTxComposite; - } - else if(pChan->txMixA==TX_OUT_LSD) - { - pSps->source=pChan->pTxLsdLpf; - } - else if(pChan->txMixA==TX_OUT_VOICE) - { - pSps->source=pChan->pTxHpf; - } - else if (pChan->txMixA==TX_OUT_AUX) - { - pSps->source=inputTmp; - } - else - { - pSps->source=NULL; - } - - pSps->sink=pChan->pTxOut; - pSps->sigProc=pmr_gp_fir; - pSps->enabled=1; - pSps->numChanOut=2; - pSps->selChanOut=0; - pSps->nSamples=pChan->nSamplesTx; - pSps->interpolate=6; - pSps->ncoef=taps_fir_lpf_3K_1; - pSps->size_coef=2; - pSps->coef=(void*)coef_fir_lpf_3K_1; - pSps->nx=taps_fir_lpf_3K_1; - pSps->size_x=2; - pSps->x=(void*)(calloc(pSps->nx,pSps->size_x)); - if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n"); - pSps->calcAdjust=gain_fir_lpf_3K_1; - pSps->inputGain=(1*M_Q8); - pSps->outputGain=(1*M_Q8); - if(pChan->txMixA==pChan->txMixB)pSps->monoOut=1; - else pSps->monoOut=0; - - - // Chan B Upsampler and Filter - if((pChan->txMixA!=pChan->txMixB)&&(pChan->txMixB!=TX_OUT_OFF)) - { - if(pSps==NULL) pSps=pChan->spsTx=createPmrSps(); - else pSps=pSps->nextSps=createPmrSps(); - - pChan->spsTxOutB=pSps; - pSps->parentChan=pChan; - if(pChan->txMixB==TX_OUT_COMPOSITE) - { - pSps->source=pChan->pTxComposite; - } - else if(pChan->txMixB==TX_OUT_LSD) - { - pSps->source=pChan->pTxLsdLpf; - // pChan->ptxCtcssAdjust=&pSps->inputGain; - } - else if(pChan->txMixB==TX_OUT_VOICE) - { - pSps->source=inputTmp; - } - else if(pChan->txMixB==TX_OUT_AUX) - { - pSps->source=pChan->pTxHpf; - } - else - { - pSps->source=NULL; - } - - pSps->sink=pChan->pTxOut; - pSps->sigProc=pmr_gp_fir; - pSps->enabled=1; - pSps->numChanOut=2; - pSps->selChanOut=1; - pSps->mixOut=0; - pSps->nSamples=pChan->nSamplesTx; - pSps->interpolate=6; - pSps->ncoef=taps_fir_lpf_3K_1; - pSps->size_coef=2; - pSps->coef=(void*)coef_fir_lpf_3K_1; - pSps->nx=taps_fir_lpf_3K_1; - pSps->size_x=2; - pSps->x=(void*)(calloc(pSps->nx,pSps->size_x)); - if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n"); - pSps->calcAdjust=(gain_fir_lpf_3K_1); - pSps->inputGain=(1*M_Q8); - pSps->outputGain=(1*M_Q8); - - } - - pSps->nextSps=NULL; - - #if XPMR_DEBUG0 == 1 - { - TRACEX((" configure tracing\n")); - t_tdet *ptdet; - - pChan->rxCtcss->pDebug0=calloc(numSamples,2); - pChan->rxCtcss->pDebug1=calloc(numSamples,2); - pChan->rxCtcss->pDebug2=calloc(numSamples,2); - - for(i=0;i<CTCSS_NUM_CODES;i++){ - ptdet=&(pChan->rxCtcss->tdet[i]); - ptdet->pDebug0=calloc(numSamples,2); - ptdet->pDebug1=calloc(numSamples,2); - ptdet->pDebug2=calloc(numSamples,2); - } - - // buffer, 2 bytes per sample, and 16 channels - pChan->prxDebug=calloc(numSamples*16,2); - pChan->ptxDebug=calloc(numSamples*16,2); - } - #endif - - TRACEX((" createPmrChannel() end\n")); - - return pChan; -} -/* -*/ -i16 destroyPmrChannel(t_pmr_chan *pChan) -{ - t_pmr_sps *pmr_sps, *tmp_sps; - - TRACEX(("destroyPmrChannel()\n")); - - free(pChan->pRxDemod); - free(pChan->pRxNoise); - free(pChan->pRxBase); - free(pChan->pRxHpf); - free(pChan->pRxLsd); - free(pChan->pRxSpeaker); - free(pChan->pRxDcTrack); - if(pChan->pRxLsdLimit)free(pChan->pRxLsdLimit); - free(pChan->pTxBase); - free(pChan->pTxHpf); - free(pChan->pTxPreEmp); - free(pChan->pTxLimiter); - free(pChan->pTxLsd); - free(pChan->pTxLsdLpf); - if(pChan->pTxComposite)free(pChan->pTxComposite); - free(pChan->pTxCode); - free(pChan->pTxOut); - - if(pChan->pSigGen0)free(pChan->pSigGen0); - if(pChan->pSigGen1)free(pChan->pSigGen1); - - #if XPMR_DEBUG0 == 1 - free(pChan->pTxPttIn); - free(pChan->pTxPttOut); - if(pChan->prxDebug)free(pChan->prxDebug); - if(pChan->ptxDebug)free(pChan->ptxDebug); - free(pChan->rxCtcss->pDebug0); - free(pChan->rxCtcss->pDebug1); - - free(pChan->prxDebug0); - free(pChan->prxDebug1); - free(pChan->prxDebug2); - free(pChan->prxDebug3); - - free(pChan->ptxDebug0); - free(pChan->ptxDebug1); - free(pChan->ptxDebug2); - free(pChan->ptxDebug3); - - i16 i; - for(i=0;i<CTCSS_NUM_CODES;i++) - { - free(pChan->rxCtcss->tdet[i].pDebug0); - free(pChan->rxCtcss->tdet[i].pDebug1); - free(pChan->rxCtcss->tdet[i].pDebug2); - } - #endif - - free(pChan->pRxCtcss); - - pmr_sps=pChan->spsRx; - - while(pmr_sps) - { - tmp_sps = pmr_sps; - pmr_sps = tmp_sps->nextSps; - destroyPmrSps(tmp_sps); - } - - free(pChan); - - return 0; -} -/* -*/ -t_pmr_sps *createPmrSps(void) -{ - t_pmr_sps *pSps; - - TRACEX(("createPmrSps()\n")); - - pSps = (t_pmr_sps *)calloc(sizeof(t_pmr_sps),1); - - if(!pSps)printf("Error: createPmrSps()\n"); - - // pSps->x=calloc(pSps->nx,pSps->size_x); - - return pSps; -} -/* -*/ -i16 destroyPmrSps(t_pmr_sps *pSps) -{ - TRACEX(("destroyPmrSps(%i)\n",pSps->index)); - - if(pSps->x!=NULL)free(pSps->x); - free(pSps); - return 0; -} -/* - PmrRx does the whole buffer -*/ -i16 PmrRx(t_pmr_chan *pChan, i16 *input, i16 *output) -{ - int i,ii; - t_pmr_sps *pmr_sps; - - TRACEX(("PmrRx() %i\n",pChan->frameCountRx)); - - if(pChan==NULL){ - printf("PmrRx() pChan == NULL\n"); - return 1; - } - - pChan->frameCountRx++; - - pmr_sps=pChan->spsRx; // first sps - pmr_sps->source=input; - - if(output!=NULL)pChan->spsRxOut->sink=output; //last sps - - #if 0 - if(pChan->inputBlanking>0) - { - pChan->inputBlanking-=pChan->nSamplesRx; - if(pChan->inputBlanking<0)pChan->inputBlanking=0; - for(i=0;i<pChan->nSamplesRx*6;i++) - input[i]=0; - } - #endif - - // || (pChan->radioDuplex && (pChan->pttIn || pChan->pttOut))) - if(pChan->rxCpuSaver && !pChan->rxCarrierDetect) - { - if(pChan->spsRxHpf)pChan->spsRxHpf->enabled=0; - if(pChan->spsRxDeEmp)pChan->spsRxDeEmp->enabled=0; - } - else - { - if(pChan->spsRxHpf)pChan->spsRxHpf->enabled=1; - if(pChan->spsRxDeEmp)pChan->spsRxDeEmp->enabled=1; - } - - i=0; - while(pmr_sps!=NULL && pmr_sps!=0) - { - TRACEX(("PmrRx() sps %i\n",i++)); - pmr_sps->sigProc(pmr_sps); - pmr_sps = (t_pmr_sps *)(pmr_sps->nextSps); - //pmr_sps=NULL; // sph maw - } - - #define XPMR_VOX_HANGTIME 2000 - - if(pChan->rxCdType==CD_XPMR_VOX) - { - if(pChan->spsRxVox->compOut) - { - pChan->rxVoxTimer=XPMR_VOX_HANGTIME; //VOX HangTime in ms - } - if(pChan->rxVoxTimer>0) - { - pChan->rxVoxTimer-=MS_PER_FRAME; - pChan->rxCarrierDetect=1; - } - else - { - pChan->rxVoxTimer=0; - pChan->rxCarrierDetect=0; - } - } - else - { - pChan->rxCarrierDetect=!pChan->spsRx->compOut; - } - - if( !pChan->rxCpuSaver || pChan->rxCarrierDetect - || pChan->rxCtcss->decode!=-1) ctcss_detect(pChan); - - #if XPMR_DEBUG0 == 1 - // TRACEX(("Write file.\n")); - ii=0; - if(pChan->b.rxCapture) - { - for(i=0;i<pChan->nSamplesRx;i++) - { - pChan->prxDebug[ii++]=input[i*2*6]; // input data - pChan->prxDebug[ii++]=output[i]; // output data - pChan->prxDebug[ii++]=pChan->rxCarrierDetect*M_Q14; // carrier detect - if(pChan->rxCtcss) - pChan->prxDebug[ii++]=pChan->rxCtcss->decode*M_Q15/CTCSS_NUM_CODES; // decoded ctcss - else - pChan->prxDebug[ii++]=0; - - pChan->prxDebug[ii++]=pChan->pRxNoise[i]; // rssi - pChan->prxDebug[ii++]=pChan->pRxBase[i]; // decimated, low pass filtered - pChan->prxDebug[ii++]=pChan->pRxHpf[i]; // output to network - pChan->prxDebug[ii++]=pChan->pRxSpeaker[i]; - - pChan->prxDebug[ii++]=pChan->pRxLsd[i]; // CTCSS Filtered - pChan->prxDebug[ii++]=pChan->pRxDcTrack[i]; // DC Restoration - pChan->prxDebug[ii++]=pChan->pRxLsdLimit[i]; // Amplitude Limited - - //pChan->prxDebug[ii++]=pChan->rxCtcss->tdet[pChan->rxCtcss->testIndex+1].pDebug0[i]; // Upper Adjacent CTCSS Code - pChan->prxDebug[ii++]=pChan->rxCtcss->tdet[pChan->rxCtcss->testIndex].pDebug0[i]; // Primary CTCSS Code - pChan->prxDebug[ii++]=pChan->rxCtcss->tdet[pChan->rxCtcss->testIndex].pDebug1[i]; // dv/dt of decoder output - pChan->prxDebug[ii++]=pChan->rxCtcss->tdet[pChan->rxCtcss->testIndex].pDebug2[i]; - - //pChan->prxDebug[ii++]=pChan->rxCtcss->tdet[pChan->rxCtcss->testIndex-1].pDebug0[i]; // Lower Adjacent CTCSS Code - - pChan->prxDebug[ii++]=pChan->prxDebug1[i]; // Measure Output for VOX - pChan->prxDebug[ii++]=pChan->prxDebug2[i]; // Measure Output for Tuning - } - } - #endif - - return 0; -} -/* - PmrTx does the whole buffer -*/ -i16 PmrTx(t_pmr_chan *pChan, i16 *input, i16 *output) -{ - int i, hit=0; - t_pmr_sps *pmr_sps; - - pChan->frameCountTx++; - - TRACEX(("PmrTx() %i\n",pChan->frameCountTx)); - - if(pChan==NULL){ - printf("PmrTx() pChan == NULL\n"); - return 1; - } - - if(pChan->b.startSpecialTone) - { - pChan->b.startSpecialTone=0; - pChan->spsSigGen1->option=1; - pChan->spsSigGen1->enabled=1; - pChan->b.doingSpecialTone=1; - } else if(pChan->b.stopSpecialTone) - { - pChan->b.stopSpecialTone=0; - pChan->spsSigGen1->option=0; - pChan->b.doingSpecialTone=0; - pChan->spsSigGen1->enabled=0; - } else if(pChan->b.doingSpecialTone) - { - pChan->spsSigGen1->sink=output; - pChan->spsSigGen1->sigProc(pChan->spsSigGen1); - for(i=0;i<(pChan->nSamplesTx*2*6);i+=2)output[i+1]=output[i]; - return 0; - } - - // handle transmitter ptt input - hit=0; - if( pChan->txPttIn && pChan->txState==0) - { - pChan->txState = 2; - pChan->txPttOut=1; - pChan->spsSigGen0->freq=pChan->txCtcssFreq*10; - pChan->spsSigGen0->option=1; - pChan->spsSigGen0->enabled=1; - if(pChan->spsTxOutA)pChan->spsTxOutA->enabled=1; - if(pChan->spsTxOutB)pChan->spsTxOutB->enabled=1; - if(pChan->spsTxLsdLpf)pChan->spsTxLsdLpf->enabled=1; - TRACEX((" TxOn\n")); - } - else if(!pChan->txPttIn && pChan->txState==2) - { - if( pChan->txTocType==TOC_NONE || !pChan->txCtcssFreq ) - { - hit=1; - TRACEX((" Tx Off Immediate.\n")); - } - else if(pChan->txCtcssFreq && pChan->txTocType==TOC_NOTONE) - { - pChan->txState=3; - pChan->txHangTime=TOC_NOTONE_TIME/MS_PER_FRAME; - pChan->spsSigGen0->option=3; - TRACEX((" Tx Turn Off No Tone Start.\n")); - } - else - { - pChan->txState=3; - pChan->txHangTime=0; - pChan->spsSigGen0->option=2; - TRACEX((" Tx Turn Off Phase Shift Start.\n")); - } - } - else if(pChan->txState==3) - { - if(pChan->txHangTime) - { - if(--pChan->txHangTime==0)hit=1; - - } - else if(pChan->txHangTime<=0 && pChan->spsSigGen0->state==0) - { - hit=1; - TRACEX((" Tx Off TOC.\n")); - } - if(pChan->txPttIn) - { - TRACEX((" Tx Key During HangTime\n")); - if((pChan->txTocType==TOC_PHASE)||(pChan->txTocType==TOC_NONE)) - { - pChan->txState = 2; - hit=0; - } - } - } - - if( pChan->txCpuSaver && !hit && !pChan->txPttIn && !pChan->txPttOut && pChan->txState==0 ) return (1); - - if(hit) - { - pChan->txPttOut=0; - pChan->txState=0; - if(pChan->spsTxLsdLpf)pChan->spsTxLsdLpf->option=3; - if(pChan->spsTxOutA)pChan->spsTxOutA->option=3; - if(pChan->spsTxOutB)pChan->spsTxOutB->option=3; - TRACEX((" Tx Off hit.\n")); - } - - if(pChan->spsSigGen0) - { - pChan->spsSigGen0->sigProc(pChan->spsSigGen0); - pmr_sps=pChan->spsSigGen0->nextSps; - i=0; - while(pmr_sps!=NULL && pmr_sps!=0) - { - TRACEX((" PmrTx() subaudible sps %i\n",i++)); - //printf(" CTCSS ENCODE %i %i\n",pChan->spsSigGen0->freq,pChan->spsSigGen0->outputGain); - pmr_sps->sigProc(pmr_sps); - pmr_sps = (t_pmr_sps *)(pmr_sps->nextSps); - } - } - - if(pChan->spsSigGen1 && pChan->spsSigGen1->enabled) - { - pChan->spsSigGen1->sigProc(pChan->spsSigGen1); - } - - // Do Voice - pmr_sps=pChan->spsTx; - if(!pChan->spsSigGen1->enabled)pmr_sps->source=input; - else input=pmr_sps->source; - - if(output!=NULL) - { - if(pChan->spsTxOutA)pChan->spsTxOutA->sink=output; - if(pChan->spsTxOutB)pChan->spsTxOutB->sink=output; - } - - i=0; - while(pmr_sps!=NULL && pmr_sps!=0) - { - TRACEX((" PmrTx() sps %i\n",i++)); - pmr_sps->sigProc(pmr_sps); - pmr_sps = (t_pmr_sps *)(pmr_sps->nextSps); - } - - - if(pChan->txMixA==TX_OUT_OFF || !pChan->txPttOut){ - for(i=0;i<pChan->nSamplesTx*2*6;i+=2)output[i]=0; - } - - if(pChan->txMixB==TX_OUT_OFF || !pChan->txPttOut ){ - for(i=0;i<pChan->nSamplesTx*2*6;i+=2)output[i+1]=0; - } - - #if XPMR_DEBUG0 == 1 - if(pChan->b.txCapture) - { - i16 ii=0; - for(i=0;i<pChan->nSamplesTx;i++) - { - pChan->ptxDebug[ii++]=input[i]; - pChan->ptxDebug[ii++]=output[i*2*6]; - pChan->ptxDebug[ii++]=output[(i*2*6)+1]; - pChan->ptxDebug[ii++]=pChan->txPttIn*8192; - - pChan->ptxDebug[ii++]=pChan->txPttOut*8192; - if(pChan->txHpfEnable)pChan->ptxDebug[ii++]=pChan->pTxHpf[i]; - else pChan->ptxDebug[ii++]=0; - if(pChan->txPreEmpEnable)pChan->ptxDebug[ii++]=pChan->pTxPreEmp[i]; - else pChan->ptxDebug[ii++]=0; - if(pChan->txLimiterEnable)pChan->ptxDebug[ii++]=pChan->pTxLimiter[i]; - else pChan->ptxDebug[ii++]=0; - - pChan->ptxDebug[ii++]=pChan->pTxLsd[i]; - pChan->ptxDebug[ii++]=pChan->pTxLsdLpf[i]; - pChan->ptxDebug[ii++]=pChan->pTxComposite[i]; - pChan->ptxDebug[ii++]=pChan->pSigGen1[i]; - - #if 1 - pChan->ptxDebug[ii++]=pChan->ptxDebug0[i]; - pChan->ptxDebug[ii++]=pChan->ptxDebug1[i]; - pChan->ptxDebug[ii++]=pChan->ptxDebug2[i]; - pChan->ptxDebug[ii++]=pChan->ptxDebug3[i]; - #else - pChan->ptxDebug[ii++]=0; - pChan->ptxDebug[ii++]=0; - pChan->ptxDebug[ii++]=0; - pChan->ptxDebug[ii++]=0; - #endif - } - } - #endif - - return 0; -} -/* end of file */ diff --git a/channels/xpmr/xpmr.h b/channels/xpmr/xpmr.h deleted file mode 100755 index d51aa6dca..000000000 --- a/channels/xpmr/xpmr.h +++ /dev/null @@ -1,553 +0,0 @@ -/* - * xpmr.h - for Xelatec Private Mobile Radio Processes - * - * All Rights Reserved. Copyright (C)2007, Xelatec, LLC - * - * 20070808 1235 Steven Henke, W9SH, sph@xelatec.com - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * This version may be optionally licenced under the GNU LGPL licence. - * - * A license has been granted to Digium (via disclaimer) for the use of - * this code. - * - */ - -/*! \file - * - * \brief Private Land Mobile Radio Channel Voice and Signaling Processor - * - * \author Steven Henke, W9SH <sph@xelatec.com> Xelatec, LLC - */ - -#ifndef XPMR_H -#define XPMR_H 1 - -#ifdef CHAN_USBRADIO -#define XPMR_DEBUG0 1 -#define XPMR_TRACE 0 -#else -#define XPMR_DEBUG0 1 -#define XPMR_TRACE 1 -#endif - -#if(XPMR_TRACE == 1) -#define TRACEX(a) {printf a;} -#define TRACEXL(a) {printf("%s @ %u : ",__FILE__ ,__LINE__); printf a; } -#define TRACEXT(a) { struct timeval hack; gettimeofday(&hack,NULL); printf("%ld.",hack.tv_sec%100000); printf("%i : ",(int)hack.tv_usec); printf a; } -#else -#define TRACEX(a) -#define TRACEXL(a) -#define TRACEXT(a) -#endif - -#define i8 int8_t -#define u8 u_int8_t -#define i16 int16_t -#define u16 u_int16_t -#define i32 int32_t -#define u32 u_int32_t -#define i64 int64_t -#define u64 u_int64_t - -#define M_Q24 0x01000000 // -#define M_Q23 0x00800000 // -#define M_Q22 0x00400000 // -#define M_Q21 0x00200000 // -#define M_Q20 0x00100000 // 1048576 -#define M_Q19 0x00080000 // 524288 -#define M_Q18 0x00040000 // 262144 -#define M_Q17 0x00020000 // 131072 -#define M_Q16 0x00010000 // 65536 -#define M_Q15 0x00008000 // 32768 -#define M_Q14 0x00004000 // 16384 -#define M_Q13 0x00002000 // 8182 -#define M_Q12 0x00001000 // 4096 -#define M_Q11 0x00000800 // 2048 -#define M_Q10 0x00000400 // 1024 -#define M_Q9 0x00000200 // 512 -#define M_Q8 0x00000100 // 256 -#define M_Q7 0x00000080 // 128 -#define M_Q6 0x00000040 // 64 -#define M_Q5 0x00000020 // 32 -#define M_Q4 0x00000010 // 16 -#define M_Q3 0x00000008 // 16 -#define M_Q2 0x00000004 // 16 -#define M_Q1 0x00000002 // 16 -#define M_Q0 0x00000001 // 16 - -#define RADIANS_PER_CYCLE (2*M_PI) - -#define SAMPLE_RATE_INPUT 48000 -#define SAMPLE_RATE_NETWORK 8000 - -#define SAMPLES_PER_BLOCK 160 -#define MS_PER_FRAME 20 - -#define CTCSS_NUM_CODES 38 -#define CTCSS_SCOUNT_MUL 100 -#define CTCSS_INTEGRATE 3932 // 32767*.120 // 120/1000 // 0.120 -#define CTCSS_INPUT_LIMIT 1000 -#define CTCSS_DETECT_POINT 1989 -#define CTCSS_HYSTERSIS 200 - -#define CTCSS_TURN_OFF_TIME 160 // ms -#define CTCSS_TURN_OFF_SHIFT 240 // degrees -#define TOC_NOTONE_TIME 600 // ms - -#ifndef CHAN_USBRADIO -enum {RX_AUDIO_NONE,RX_AUDIO_SPEAKER,RX_AUDIO_FLAT}; -enum {TX_AUDIO_NONE,TX_AUDIO_FLAT,TX_AUDIO_FILTERED,TX_AUDIO_PROC}; -enum {CD_IGNORE,CD_XPMR_NOISE,CD_XPMR_VOX,CD_HID,CD_HID_INVERT}; -enum {SD_IGNORE,SD_HID,SD_HID_INVERT,SD_XPMR}; // no,external,externalinvert,software -enum {RX_KEY_CARRIER,RX_KEY_CARRIER_CODE}; -enum {TX_OUT_OFF,TX_OUT_VOICE,TX_OUT_LSD,TX_OUT_COMPOSITE,TX_OUT_AUX}; -enum {TOC_NONE,TOC_PHASE,TOC_NOTONE}; -#endif - -/* - one structure for each ctcss tone to decode -*/ -typedef struct -{ - i16 counter; // counter to next sample - i16 counterFactor; // full divisor used to increment counter - i16 binFactor; - i16 fudgeFactor; - i16 peak; // peak amplitude now maw sph now - i16 enabled; - i16 state; // dead, running, error - i16 zIndex; // z bucket index - i16 z[4]; // maw sph today - i16 zi; - i16 dvu; - i16 dvd; - i16 zd; - i16 setpt; - i16 hyst; - i16 decode; - i16 diffpeak; - i16 debug; // value held from last pass - i16 *pDebug0; // pointer to debug output - i16 *pDebug1; // pointer to debug output - i16 *pDebug2; // pointer to debug output - -} t_tdet; - -typedef struct -{ - i16 enabled; // if 0 none, 0xFFFF all tones, or single tone - i16 *input; - i16 clamplitude; - i16 center; - i16 decode; // current ctcss decode index - i32 BlankingTimer; - u32 TurnOffTimer; - t_tdet tdet[CTCSS_NUM_CODES]; - i16 gain; - i16 limit; - i16 *pDebug0; - i16 *pDebug1; - i16 *pDebug2; - i16 testIndex; - i16 multiFreq; - i8 relax; - -} t_dec_ctcss; - -typedef struct -{ - i16 enabled; // if 0 none, 0xFFFF all tones, or single tone - i16 clamplitude; - i16 center; - i16 decode; // current ctcss decode value - i32 BlankingTimer; - u32 TurnOffTimer; - i16 gain; - i16 limit; - i16 *pDebug0; - i16 *pDebug1; - i16 rxPolarity; -} t_dec_dcs; - -/* - Low Speed Data decoding both polarities -*/ -typedef struct -{ - i16 counter; // counter to next sample - i16 synced; - u32 syncCorr[2]; - u32 data[2]; - i16 state; // disabled, enabled, - i16 decode; - i16 debug; - - i16 polarity; - u32 frameNum; - - u16 area; - u16 chan; - u16 home; - u16 id; - u16 free; - - u16 crc; - i16 rssi; - -} t_decLsd; - - -/* general purpose pmr signal processing element */ - -struct t_pmr_chan; - -typedef struct t_pmr_sps -{ - i16 index; // unique to each instance - - i16 enabled; // enabled/disabled - - struct t_pmr_chan *parentChan; - - i16 *source; // source buffer - i16 *sourceB; // source buffer B - i16 *sink; // sink buffer - - i16 numChanOut; // allows output direct to interleaved buffer - i16 selChanOut; - - u32 ticks; - - void *buff; // this structure's internal buffer - - i16 *debugBuff0; // debug buffer - i16 *debugBuff1; // debug buffer - i16 *debugBuff2; // debug buffer - i16 *debugBuff3; // debug buffer - - i16 nSamples; // number of samples in the buffer - - u32 buffSize; // buffer maximum index - u32 buffInIndex; // index to current input point - u32 buffOutIndex; // index to current output point - u32 buffLead; // lead of input over output through cb - - i16 decimate; // decimation or interpolation factor (could be put in coef's) - i16 interpolate; - i16 decimator; // like the state this must be saved between calls (could be put in x's) - - u32 sampleRate; // in Hz for elements in this structure - u32 freq; // in 0.1 Hz - - i16 measPeak; // do measure Peak - i16 amax; // buffer amplitude maximum - i16 amin; // buffer amplitude minimum - i16 apeak; // buffer amplitude peak value (peak to peak)/2 - i16 setpt; // amplitude set point for amplitude comparator - i16 hyst; // hysterysis for amplitude comparator - i16 compOut; // amplitude comparator output - - i32 discounteru; // amplitude detector integrator discharge counter upper - i32 discounterl; // amplitude detector integrator discharge counter lower - i32 discfactor; // amplitude detector integrator discharge factor - - i16 err; // error condition - i16 option; // option / request zero - i16 state; // stopped, start, stopped assumes zero'd - - i16 cleared; // output buffer cleared - - i16 delay; - i16 decode; - - i32 inputGain; // apply to input data ? in Q7.8 format - i32 inputGainB; // apply to input data ? in Q7.8 format - i32 outputGain; // apply to output data ? in Q7.8 format - i16 mixOut; - i16 monoOut; - - i16 filterType; // iir, fir, 1, 2, 3, 4 ... - - i16 (*sigProc)(struct t_pmr_sps *sps); // function to call - - i32 calcAdjust; // final adjustment - i16 nx; // number of x history elements - i16 ncoef; // number of coefficients - i16 size_x; // size of each x history element - i16 size_coef; // size of each coefficient - void *x; // history registers - void *x2; // history registers, 2nd bank - void *coef; // coefficients - void *coef2; // coefficients 2 - - void *nextSps; // next Sps function - -} t_pmr_sps; - -/* - pmr channel -*/ -typedef struct t_pmr_chan -{ - i16 index; // which one - i16 enabled; // enabled/disabled - i16 status; // ok, error, busy, idle, initializing - - i16 nSamplesRx; // max frame size - i16 nSamplesTx; - - i32 inputSampleRate; // in S/s 48000 - i32 baseSampleRate; // in S/s 8000 - - i16 inputGain; - i16 inputOffset; - - u32 frameCountRx; // number processed - u32 frameCountTx; - - i32 txHangTime; - i32 txTurnOff; - - i16 rxDC; // average DC value of input - i16 rxSqSet; // carrier squelch threshold - i16 rxSqHyst; // carrier squelch hysterysis - i16 rxRssi; // current Rssi level - i16 rxQuality; // signal quality metric - i16 rxCarrierDetect; // carrier detect - i16 rxCdType; - i16 rxExtCarrierDetect; - i32 inputBlanking; // Tx pulse eliminator - - i16 rxDemod; // see enum - i16 txMod; // - - i16 rxNoiseSquelchEnable; - i16 rxHpfEnable; - i16 rxDeEmpEnable; - i16 rxCenterSlicerEnable; - i16 rxCtcssDecodeEnable; - i16 rxDcsDecodeEnable; - i16 rxDelayLineEnable; - - i16 txHpfEnable; - i16 txLimiterEnable; - i16 txPreEmpEnable; - i16 txLpfEnable; - - char radioDuplex; - - struct { - unsigned pmrNoiseSquelch:1; - unsigned rxHpf:1; - unsigned txHpf:1; - unsigned txLpf:1; - unsigned rxDeEmphasis:1; - unsigned txPreEmphasis:1; - unsigned startSpecialTone:1; - unsigned stopSpecialTone:1; - unsigned doingSpecialTone:1; - unsigned extCarrierDetect:1; - unsigned txCapture:1; - unsigned rxCapture:1; - }b; - - i16 dummy; - - i32 txScramFreq; - i32 rxScramFreq; - - i16 gainVoice; - i16 gainSubAudible; - - i16 txMixA; // Off, Ctcss, Voice, Composite - i16 txMixB; // Off, Ctcss, Voice, Composite - - i16 rxMuting; - - i16 rxCpuSaver; - i16 txCpuSaver; - - i8 rxSqMode; // 0 open, 1 carrier, 2 coded - - i8 cdMethod; - - i16 rxSquelchPoint; - - i16 rxCarrierPoint; - i16 rxCarrierHyst; - - i16 rxCtcssMap[CTCSS_NUM_CODES]; - - i16 txCtcssTocShift; - i16 txCtcssTocTime; - i8 txTocType; - - float txCtcssFreq; - float rxCtcssFreq; - float rxInputGain; - - i16 rxCtcssIndex; - - i16 txPttIn; // from external request - i16 txPttOut; // to radio hardware - - i16 bandwidth; // wide/narrow - i16 txCompand; // type - i16 rxCompand; // - - i16 txEqRight; // muted, flat, pre-emp limited filtered - i16 txEqLeft; - - i16 txPotRight; // - i16 txPotLeft; // - - i16 rxPotRight; // - i16 rxPotLeft; // - - i16 function; - - i16 txState; // off,settling,on,hangtime,turnoff - - t_pmr_sps *spsMeasure; // measurement block - - t_pmr_sps *spsRx; // 1st signal processing struct - t_pmr_sps *spsRxLsd; - t_pmr_sps *spsRxDeEmp; - t_pmr_sps *spsRxHpf; - t_pmr_sps *spsRxVox; - t_pmr_sps *spsDelayLine; // Last signal processing struct - t_pmr_sps *spsRxOut; // Last signal processing struct - - t_pmr_sps *spsTx; // 1st signal processing struct - - t_pmr_sps *spsTxLsdLpf; - t_pmr_sps *spsTxOutA; // Last signal processing struct - - t_pmr_sps *spsTxOutB; // Last signal processing struct - - t_pmr_sps *spsSigGen0; // ctcss - t_pmr_sps *spsSigGen1; // test and other tones - - // tune tweaks - - i32 rxVoxTimer; // Vox Hang Timer - - i16 *prxSquelchAdjust; - - // i16 *prxNoiseMeasure; // for autotune - // i32 *prxNoiseAdjust; - - i16 *prxVoiceMeasure; - i32 *prxVoiceAdjust; - - i16 *prxCtcssMeasure; - i32 *prxCtcssAdjust; - - i16 *ptxVoiceAdjust; // from calling application - i32 *ptxCtcssAdjust; // from calling application - - i32 *ptxLimiterAdjust; // from calling application - - i16 *pRxDemod; // buffers - i16 *pRxBase; // decimated lpf input - i16 *pRxNoise; - i16 *pRxLsd; // subaudible only - i16 *pRxHpf; // subaudible removed - i16 *pRxDeEmp; // EIA Audio - i16 *pRxSpeaker; // EIA Audio - i16 *pRxDcTrack; // DC Restored LSD - i16 *pRxLsdLimit; // LSD Limited - i16 *pRxCtcss; // - i16 *pRxSquelch; - - i16 *pTxBase; // input data - i16 *pTxHpf; - i16 *pTxPreEmp; - i16 *pTxLimiter; - i16 *pTxLsd; - i16 *pTxLsdLpf; - i16 *pTxComposite; - i16 *pTxMod; // upsampled, low pass filtered - - i16 *pTxOut; // - - i16 *pTxPttIn; - i16 *pTxPttOut; - i16 *pTxHang; - i16 *pTxCode; - - i16 *pSigGen0; - i16 *pSigGen1; - - i16 *pAlt0; - i16 *pAlt1; - - i16 *pNull; - - i16 *prxDebug; // consolidated debug buffer - i16 *ptxDebug; // consolidated debug buffer - - i16 *prxDebug0; - i16 *prxDebug1; - i16 *prxDebug2; - i16 *prxDebug3; - - i16 *ptxDebug0; - i16 *ptxDebug1; - i16 *ptxDebug2; - i16 *ptxDebug3; - - t_dec_ctcss *rxCtcss; - - i16 clamplitudeDcs; - i16 centerDcs; - u32 dcsBlankingTimer; - i16 dcsDecode; // current dcs decode value - - i16 clamplitudeLsd; - i16 centerLsd; - t_decLsd decLsd[2]; // for both polarities - -} t_pmr_chan; - -static i16 TxTestTone(t_pmr_chan *pChan, i16 function); - -t_pmr_chan *createPmrChannel(t_pmr_chan *tChan, i16 numSamples); -t_pmr_sps *createPmrSps(void); -i16 destroyPmrChannel(t_pmr_chan *pChan); -i16 destroyPmrSps(t_pmr_sps *pSps); -i16 pmr_rx_frontend(t_pmr_sps *mySps); -i16 pmr_gp_fir(t_pmr_sps *mySps); -i16 pmr_gp_iir(t_pmr_sps *mySps); -i16 gp_inte_00(t_pmr_sps *mySps); -i16 gp_diff(t_pmr_sps *mySps); -i16 CenterSlicer(t_pmr_sps *mySps); -i16 ctcss_detect(t_pmr_chan *pmrChan); -i16 SoftLimiter(t_pmr_sps *mySps); -i16 SigGen(t_pmr_sps *mySps); -i16 pmrMixer(t_pmr_sps *mySps); -i16 DelayLine(t_pmr_sps *mySps); -i16 PmrRx(t_pmr_chan *PmrChan, i16 *input, i16 *output); -i16 PmrTx(t_pmr_chan *PmrChan, i16 *input, i16 *output); -i16 CtcssFreqIndex(float freq); -i16 MeasureBlock(t_pmr_sps *mySps); -#endif /* ! XPMR_H */ - -/* end of file */ - - - diff --git a/channels/xpmr/xpmr_coef.h b/channels/xpmr/xpmr_coef.h deleted file mode 100755 index 4b7274e5a..000000000 --- a/channels/xpmr/xpmr_coef.h +++ /dev/null @@ -1,963 +0,0 @@ -/* - * xpmr_coef.h - for Xelatec Private Mobile Radio Processes - * - * All Rights Reserved. Copyright (C)2007, Xelatec, LLC - * - * 20070808 1235 Steven Henke, W9SH, sph@xelatec.com - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * This version may be optionally licenced under the GNU LGPL licence. - * - * A license has been granted to Digium (via disclaimer) for the use of - * this code. - * - * Some filter coeficients via 'WinFilter' http://www.winfilter.20m.com. - * - */ - -/*! \file - * - * \brief Private Land Mobile Radio Channel Voice and Signaling Processor - * - * \author Steven Henke, W9SH <sph@xelatec.com> Xelatec, LLC - */ - -#ifndef XPMR_COEF_H -#define XMPR_COEF_H 1 - -// frequencies in 0.1 Hz -const u32 dtmf_row[] = -{ - 6970, 7700, 8520, 9410 -}; -const u32 dtmf_col[] = -{ - 12090, 13360, 14770, 16330 -}; - -const i16 coef_dcs_rx = 1488; // dcs rx data divisor for oversampling 8000/134.4 -const i16 coef_dcs_tx = 5952; // dcs tx data divisor - -const i16 coef_lsd_div = 672; // low speed data divisor -const u32 coef_lsd_sync = 0x158; // 000101011000 -const u32 coef_lsd_sync_pattern[] = {0x0000000F, 0x0F0FF000}; - -#define CTCSS_COEF_INT 120 -#define CTCSS_SAMPLE_RATE 8000 -#define TDIV(x) ((CTCSS_SAMPLE_RATE*1000/x)+5)/10 - -i32 coef_ctcss[4][5]= -{ - // freq, divisor, integrator, filter - {770,TDIV(770),CTCSS_COEF_INT,0,0}, - {1000,TDIV(1000),CTCSS_COEF_INT,0,0}, - {1035,TDIV(1035),CTCSS_COEF_INT,0,0}, - {0,0,0,0} -}; - - -i16 coef_ctcss_div[]= -{ -2985, // 00 067.0 -2782, // 01 071.9 -2688, // 02 074.4 -2597, // 03 077.0 -2509, // 04 079.7 -2424, // 05 082.5 -2342, // 06 085.4 -2260, // 07 088.5 -2186, // 08 091.5 -2110, // 09 094.8 -2053, // 10 097.4 -2000, // 11 100.0 -1932, // 12 103.5 -1866, // 13 107.2 -1803, // 14 110.9 -1742, // 15 114.8 -1684, // 16 118.8 -1626, // 17 123.0 -1571, // 18 127.3 -1517, // 19 131.8 -1465, // 20 136.5 -1415, // 21 141.3 -1368, // 22 146.2 -1321, // 23 151.4 -1276, // 24 156.7 -1233, // 25 162.2 -1191, // 26 167.9 -1151, // 27 173.8 -1112, // 28 179.9 -1074, // 29 186.2 -1037, // 30 192.8 -983, // 31 203.5 -949, // 32 210.7 -917, // 33 218.1 -886, // 34 225.7 -856, // 35 233.6 -827, // 36 241.8 -799 // 37 250.3 -}; - -float freq_ctcss[]= -{ -067.0, // 00 -071.9, // 01 -074.4, // 02 -077.0, // 03 -079.7, // 04 -082.5, // 05 -085.4, // 06 -088.5, // 07 -091.5, // 08 -094.8, // 09 -097.4, // 10 -100.0, // 11 -103.5, // 12 -107.2, // 13 -110.9, // 14 -114.8, // 15 -118.8, // 16 -123.0, // 17 -127.3, // 18 -131.8, // 19 -136.5, // 20 -141.3, // 21 -146.2, // 22 -151.4, // 23 -156.7, // 24 -162.2, // 25 -167.9, // 26 -173.8, // 27 -179.9, // 28 -186.2, // 29 -192.8, // 30 -203.5, // 31 -210.7 , // 32 -218.1 , // 33 -225.7 , // 34 -233.6 , // 35 -241.8 , // 36 -250.3 // 37 -}; - -/* - noise squelch carrier detect filter -*/ -static const int16_t taps_fir_bpf_noise_1 = 66; -static const int32_t gain_fir_bpf_noise_1 = 65536; -static const int16_t coef_fir_bpf_noise_1[] = { - 139, - -182, - -269, - -66, - 56, - 59, - 250, - 395, - -80, - -775, - -557, - 437, - 779, - 210, - -17, - 123, - -692, - -1664, - -256, - 2495, - 2237, - -1018, - -2133, - -478, - -1134, - -2711, - 2642, - 10453, - 4010, - -14385, - -16488, - 6954, - 23030, - 6954, - -16488, - -14385, - 4010, - 10453, - 2642, - -2711, - -1134, - -478, - -2133, - -1018, - 2237, - 2495, - -256, - -1664, - -692, - 123, - -17, - 210, - 779, - 437, - -557, - -775, - -80, - 395, - 250, - 59, - 56, - -66, - -269, - -182, - 139, - 257 -}; -/* - tbd -*/ -static const int16_t taps_fir_lpf_3K_1 = 66; -static const int32_t gain_fir_lpf_3K_1 = 131072; -static const int16_t coef_fir_lpf_3K_1[] = { - 259, - 58, - -185, - -437, - -654, - -793, - -815, - -696, - -434, - -48, - 414, - 886, - 1284, - 1523, - 1529, - 1254, - 691, - -117, - -1078, - -2049, - -2854, - -3303, - -3220, - -2472, - -995, - 1187, - 3952, - 7086, - 10300, - 13270, - 15672, - 17236, - 17778, - 17236, - 15672, - 13270, - 10300, - 7086, - 3952, - 1187, - -995, - -2472, - -3220, - -3303, - -2854, - -2049, - -1078, - -117, - 691, - 1254, - 1529, - 1523, - 1284, - 886, - 414, - -48, - -434, - -696, - -815, - -793, - -654, - -437, - -185, - 58, - 259, - 393 -}; - -/************************************************************** -Filter type: Low Pass -Filter model: Butterworth -Filter order: 9 -Sampling Frequency: 8 KHz -Cut Frequency: 0.250000 KHz -Coefficents Quantization: 16-bit -***************************************************************/ -static const int16_t taps_fir_lpf_250_11_64 = 64; -static const int32_t gain_fir_lpf_250_11_64 = 262144; -static const int16_t coef_fir_lpf_250_11_64[] = -{ - 366, - -3, - -418, - -865, - -1328, - -1788, - -2223, - -2609, - -2922, - -3138, - -3232, - -3181, - -2967, - -2573, - -1988, - -1206, - -228, - 937, - 2277, - 3767, - 5379, - 7077, - 8821, - 10564, - 12259, - 13855, - 15305, - 16563, - 17588, - 18346, - 18812, - 18968, - 18812, - 18346, - 17588, - 16563, - 15305, - 13855, - 12259, - 10564, - 8821, - 7077, - 5379, - 3767, - 2277, - 937, - -228, - -1206, - -1988, - -2573, - -2967, - -3181, - -3232, - -3138, - -2922, - -2609, - -2223, - -1788, - -1328, - -865, - -418, - -3, - 366, - 680 -}; - -// de-emphasis integrator 300 Hz with 8KS/s -// a0, b1 -static const int16_t taps_int_lpf_300_1_2 = 2; -static const int32_t gain_int_lpf_300_1_2 = 8182; -static const int16_t coef_int_lpf_300_1_2[]={ -6878, -25889 -}; - -// pre-emphasis differentiator 4000 Hz with 8KS/s -// a0,a1,b0, -static const int16_t taps_int_hpf_4000_1_2 = 2; -static const int32_t gain_int_hpf_4000_1_2 = 16384; -static const int16_t coef_int_hpf_4000_1_2[]={ -17610, --17610, -2454 -}; - - -/* - ltr crc table - from http://www.radioreference.com/forums/showthread.php?t=24126 -*/ - -static const u8 ltr_table[]= -{ -0x38, // 00 Area 0111000 -0x1c, // 01 Channel 4 0011100 -0x0e, // 02 Channel 3 0001110 -0x46, // 03 Channel 2 1000110 -0x23, // 04 Channel 1 0100011 -0x51, // 05 Channel 0 1010001 -0x68, // 06 Home 4 1101000 -0x75, // 07 Home 3 1110101 -0x7a, // 08 Home 2 1111010 -0x3d, // 09 Home 1 0111101 -0x1f, // 10 Home 0 0011111 -0x4f, // 11 Group 7 1001111 -0x26, // 12 Group 6 0100110 -0x52, // 13 Group 5 1010010 -0x29, // 14 Group 4 0101001 -0x15, // 15 Group 3 0010101 -0x0d, // 16 Group 2 0001101 -0x45, // 17 Group 1 1000101 -0x62, // 18 Group 0 1100010 -0x31, // 19 Free 4 0110001 -0x19, // 20 Free 3 0011001 -0x0d, // 21 Free 2 0001101 -0x07, // 22 Free 1 0000111 -0x43 // 23 Free 0 1000011 -}; - -static const i16 bitWeight[]= -{ -0, // 0 -1, // 1 -1, // 2 -2, // 3 -1, // 4 -2, // 5 -2, // 6 -3, // 7 -1, // 8 -2, // 9 -2, // 10 -3, // 11 -2, // 12 -3, // 13 -3, // 14 -4, // 15 -1, // 16 -2, // 17 -2, // 18 -3, // 19 -2, // 20 -3, // 21 -3, // 22 -4, // 23 -2, // 24 -3, // 25 -3, // 26 -4, // 27 -3, // 28 -4, // 29 -4, // 30 -5, // 31 -1, // 32 -2, // 33 -2, // 34 -3, // 35 -2, // 36 -3, // 37 -3, // 38 -4, // 39 -2, // 40 -3, // 41 -3, // 42 -4, // 43 -3, // 44 -4, // 45 -4, // 46 -5, // 47 -2, // 48 -3, // 49 -3, // 50 -4, // 51 -3, // 52 -4, // 53 -4, // 54 -5, // 55 -3, // 56 -4, // 57 -4, // 58 -5, // 59 -4, // 60 -5, // 61 -5, // 62 -6, // 63 -1, // 64 -2, // 65 -2, // 66 -3, // 67 -2, // 68 -3, // 69 -3, // 70 -4, // 71 -2, // 72 -3, // 73 -3, // 74 -4, // 75 -3, // 76 -4, // 77 -4, // 78 -5, // 79 -2, // 80 -3, // 81 -3, // 82 -4, // 83 -3, // 84 -4, // 85 -4, // 86 -5, // 87 -3, // 88 -4, // 89 -4, // 90 -5, // 91 -4, // 92 -5, // 93 -5, // 94 -6, // 95 -2, // 96 -3, // 97 -3, // 98 -4, // 99 -3, // 100 -4, // 101 -4, // 102 -5, // 103 -3, // 104 -4, // 105 -4, // 106 -5, // 107 -4, // 108 -5, // 109 -5, // 110 -6, // 111 -3, // 112 -4, // 113 -4, // 114 -5, // 115 -4, // 116 -5, // 117 -5, // 118 -6, // 119 -4, // 120 -5, // 121 -5, // 122 -6, // 123 -5, // 124 -6, // 125 -6, // 126 -7, // 127 -1, // 128 -2, // 129 -2, // 130 -3, // 131 -2, // 132 -3, // 133 -3, // 134 -4, // 135 -2, // 136 -3, // 137 -3, // 138 -4, // 139 -3, // 140 -4, // 141 -4, // 142 -5, // 143 -2, // 144 -3, // 145 -3, // 146 -4, // 147 -3, // 148 -4, // 149 -4, // 150 -5, // 151 -3, // 152 -4, // 153 -4, // 154 -5, // 155 -4, // 156 -5, // 157 -5, // 158 -6, // 159 -2, // 160 -3, // 161 -3, // 162 -4, // 163 -3, // 164 -4, // 165 -4, // 166 -5, // 167 -3, // 168 -4, // 169 -4, // 170 -5, // 171 -4, // 172 -5, // 173 -5, // 174 -6, // 175 -3, // 176 -4, // 177 -4, // 178 -5, // 179 -4, // 180 -5, // 181 -5, // 182 -6, // 183 -4, // 184 -5, // 185 -5, // 186 -6, // 187 -5, // 188 -6, // 189 -6, // 190 -7, // 191 -2, // 192 -3, // 193 -3, // 194 -4, // 195 -3, // 196 -4, // 197 -4, // 198 -5, // 199 -3, // 200 -4, // 201 -4, // 202 -5, // 203 -4, // 204 -5, // 205 -5, // 206 -6, // 207 -3, // 208 -4, // 209 -4, // 210 -5, // 211 -4, // 212 -5, // 213 -5, // 214 -6, // 215 -4, // 216 -5, // 217 -5, // 218 -6, // 219 -5, // 220 -6, // 221 -6, // 222 -7, // 223 -3, // 224 -4, // 225 -4, // 226 -5, // 227 -4, // 228 -5, // 229 -5, // 230 -6, // 231 -4, // 232 -5, // 233 -5, // 234 -6, // 235 -5, // 236 -6, // 237 -6, // 238 -7, // 239 -4, // 240 -5, // 241 -5, // 242 -6, // 243 -5, // 244 -6, // 245 -6, // 246 -7, // 247 -5, // 248 -6, // 249 -6, // 250 -7, // 251 -6, // 252 -7, // 253 -7, // 254 -8 // 255 -}; - - -/* - ctcss decode filter -*/ -/************************************************************** -Filter type: Low Pass -Filter model: Butterworth -Filter order: 9 -Sampling Frequency: 8 KHz -Cut Frequency: 0.250000 KHz -Coefficents Quantization: 16-bit -***************************************************************/ -static const int16_t taps_fir_lpf_250_9_66 = 66; -static const int32_t gain_fir_lpf_250_9_66 = 262144; -static const int16_t coef_fir_lpf_250_9_66[] = -{ - 676, - 364, - -3, - -415, - -860, --1320, --1777, --2209, --2593, --2904, --3119, --3212, --3162, --2949, --2557, --1975, --1198, - -226, - 932, - 2263, - 3744, - 5346, - 7034, - 8767, -10499, -12184, -13770, -15211, -16462, -17480, -18234, -18696, -18852, -18696, -18234, -17480, -16462, -15211, -13770, -12184, -10499, - 8767, - 7034, - 5346, - 3744, - 2263, - 932, - -226, --1198, --1975, --2557, --2949, --3162, --3212, --3119, --2904, --2593, --2209, --1777, --1320, - -860, - -415, - -3, - 364, - 676, - 927 -}; -/* ************************************************************* -Filter type: Low Pass -Filter model: Butterworth -Filter order: 9 -Sampling Frequency: 8 KHz -Cut Frequency: 0.215 KHz -Coefficents Quantization: 16-bit -***************************************************************/ -static const int16_t taps_fir_lpf_215_9_88 = 88; -static const int32_t gain_fir_lpf_215_9_88 = 524288; -static const int16_t coef_fir_lpf_215_9_88[] = { - 2038, - 2049, - 1991, - 1859, - 1650, - 1363, - 999, - 562, - 58, - -502, --1106, --1739, --2382, --3014, --3612, --4153, --4610, --4959, --5172, --5226, --5098, --4769, --4222, --3444, --2430, --1176, - 310, - 2021, - 3937, - 6035, - 8284, -10648, -13086, -15550, -17993, -20363, -22608, -24677, -26522, -28099, -29369, -30299, -30867, -31058, -30867, -30299, -29369, -28099, -26522, -24677, -22608, -20363, -17993, -15550, -13086, -10648, - 8284, - 6035, - 3937, - 2021, - 310, --1176, --2430, --3444, --4222, --4769, --5098, --5226, --5172, --4959, --4610, --4153, --3612, --3014, --2382, --1739, --1106, - -502, - 58, - 562, - 999, - 1363, - 1650, - 1859, - 1991, - 2049, - 2038, - 1966 -}; -// end coef fir_lpf_215_9_88 -// -/************************************************************** -Filter type: High Pass -Filter model: Butterworth -Filter order: 9 -Sampling Frequency: 8 KHz -Cut Frequency: 0.300000 KHz -Coefficents Quantization: 16-bit -***************************************************************/ -static const int16_t taps_fir_hpf_300_9_66 = 66; -static const int32_t gain_fir_hpf_300_9_66 = 32768; -static const int16_t coef_fir_hpf_300_9_66[] = -{ - -141, - -114, - -77, - -30, - 23, - 83, - 147, - 210, - 271, - 324, - 367, - 396, - 407, - 396, - 362, - 302, - 216, - 102, - -36, - -199, - -383, - -585, - -798, --1017, --1237, --1452, --1653, --1836, --1995, --2124, --2219, --2278, -30463, --2278, --2219, --2124, --1995, --1836, --1653, --1452, --1237, --1017, - -798, - -585, - -383, - -199, - -36, - 102, - 216, - 302, - 362, - 396, - 407, - 396, - 367, - 324, - 271, - 210, - 147, - 83, - 23, - -30, - -77, - -114, - -141, - -158 - }; -#endif /* !XPMR_COEF_H */ -/* end of file */ - - - - |