00001 #define NEW_ASTERISK
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058 #include "asterisk.h"
00059
00060 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 284666 $")
00061
00062 #include <stdio.h>
00063 #include <ctype.h>
00064 #include <math.h>
00065 #include <string.h>
00066 #include <unistd.h>
00067 #ifdef HAVE_SYS_IO_H
00068 #include <sys/io.h>
00069 #endif
00070 #include <sys/ioctl.h>
00071 #include <fcntl.h>
00072 #include <sys/time.h>
00073 #include <stdlib.h>
00074 #include <errno.h>
00075 #include <usb.h>
00076 #include <alsa/asoundlib.h>
00077
00078
00079 #ifdef RADIO_XPMRX
00080 #define HAVE_XPMRX 1
00081 #endif
00082
00083 #define CHAN_USBRADIO 1
00084 #define DEBUG_USBRADIO 0
00085 #define DEBUG_CAPTURES 1
00086 #define DEBUG_CAP_RX_OUT 0
00087 #define DEBUG_CAP_TX_OUT 0
00088 #define DEBUG_FILETEST 0
00089
00090 #define RX_CAP_RAW_FILE "/tmp/rx_cap_in.pcm"
00091 #define RX_CAP_TRACE_FILE "/tmp/rx_trace.pcm"
00092 #define RX_CAP_OUT_FILE "/tmp/rx_cap_out.pcm"
00093
00094 #define TX_CAP_RAW_FILE "/tmp/tx_cap_in.pcm"
00095 #define TX_CAP_TRACE_FILE "/tmp/tx_trace.pcm"
00096 #define TX_CAP_OUT_FILE "/tmp/tx_cap_out.pcm"
00097
00098 #define MIXER_PARAM_MIC_PLAYBACK_SW "Mic Playback Switch"
00099 #define MIXER_PARAM_MIC_PLAYBACK_VOL "Mic Playback Volume"
00100 #define MIXER_PARAM_MIC_CAPTURE_SW "Mic Capture Switch"
00101 #define MIXER_PARAM_MIC_CAPTURE_VOL "Mic Capture Volume"
00102 #define MIXER_PARAM_MIC_BOOST "Auto Gain Control"
00103 #define MIXER_PARAM_SPKR_PLAYBACK_SW "Speaker Playback Switch"
00104 #define MIXER_PARAM_SPKR_PLAYBACK_VOL "Speaker Playback Volume"
00105
00106 #define DELIMCHR ','
00107 #define QUOTECHR 34
00108
00109 #define READERR_THRESHOLD 50
00110
00111 #include "./xpmr/xpmr.h"
00112 #ifdef HAVE_XPMRX
00113 #include "./xpmrx/xpmrx.h"
00114 #include "./xpmrx/bitweight.h"
00115 #endif
00116
00117 #if 0
00118 #define traceusb1(a) {printf a;}
00119 #else
00120 #define traceusb1(a)
00121 #endif
00122
00123 #if 0
00124 #define traceusb2(a) {printf a;}
00125 #else
00126 #define traceusb2(a)
00127 #endif
00128
00129 #ifdef __linux
00130 #include <linux/soundcard.h>
00131 #elif defined(__FreeBSD__)
00132 #include <sys/soundcard.h>
00133 #else
00134 #include <soundcard.h>
00135 #endif
00136
00137 #include "asterisk/lock.h"
00138 #include "asterisk/frame.h"
00139 #include "asterisk/logger.h"
00140 #include "asterisk/callerid.h"
00141 #include "asterisk/channel.h"
00142 #include "asterisk/module.h"
00143 #include "asterisk/options.h"
00144 #include "asterisk/pbx.h"
00145 #include "asterisk/config.h"
00146 #include "asterisk/cli.h"
00147 #include "asterisk/utils.h"
00148 #include "asterisk/causes.h"
00149 #include "asterisk/endian.h"
00150 #include "asterisk/stringfields.h"
00151 #include "asterisk/abstract_jb.h"
00152 #include "asterisk/musiconhold.h"
00153 #include "asterisk/dsp.h"
00154
00155 #ifndef NEW_ASTERISK
00156
00157
00158 #include "busy.h"
00159 #include "ringtone.h"
00160 #include "ring10.h"
00161 #include "answer.h"
00162
00163 #endif
00164
00165 #define C108_VENDOR_ID 0x0d8c
00166 #define C108_PRODUCT_ID 0x000c
00167 #define C108_HID_INTERFACE 3
00168
00169 #define HID_REPORT_GET 0x01
00170 #define HID_REPORT_SET 0x09
00171
00172 #define HID_RT_INPUT 0x01
00173 #define HID_RT_OUTPUT 0x02
00174
00175 #define EEPROM_START_ADDR 6
00176 #define EEPROM_END_ADDR 63
00177 #define EEPROM_PHYSICAL_LEN 64
00178 #define EEPROM_TEST_ADDR EEPROM_END_ADDR
00179 #define EEPROM_MAGIC_ADDR 6
00180 #define EEPROM_MAGIC 34329
00181 #define EEPROM_CS_ADDR 62
00182 #define EEPROM_RXMIXERSET 8
00183 #define EEPROM_TXMIXASET 9
00184 #define EEPROM_TXMIXBSET 10
00185 #define EEPROM_RXVOICEADJ 11
00186 #define EEPROM_RXCTCSSADJ 13
00187 #define EEPROM_TXCTCSSADJ 15
00188 #define EEPROM_RXSQUELCHADJ 16
00189
00190
00191 static struct ast_jb_conf default_jbconf =
00192 {
00193 .flags = 0,
00194 .max_size = -1,
00195 .resync_threshold = -1,
00196 .impl = "",
00197 .target_extra = -1,
00198 };
00199 static struct ast_jb_conf global_jbconf;
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292 #define M_START(var, val) \
00293 char *__s = var; char *__val = val;
00294 #define M_END(x) x;
00295 #define M_F(tag, f) if (!strcasecmp((__s), tag)) { f; } else
00296 #define M_BOOL(tag, dst) M_F(tag, (dst) = ast_true(__val) )
00297 #define M_UINT(tag, dst) M_F(tag, (dst) = strtoul(__val, NULL, 0) )
00298 #define M_STR(tag, dst) M_F(tag, ast_copy_string(dst, __val, sizeof(dst)))
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330 #define FRAME_SIZE 160
00331 #define QUEUE_SIZE 2
00332
00333 #if defined(__FreeBSD__)
00334 #define FRAGS 0x8
00335 #else
00336 #define FRAGS ( ( (6 * 5) << 16 ) | 0xc )
00337 #endif
00338
00339
00340
00341
00342
00343 #define TEXT_SIZE 256
00344
00345 #if 0
00346 #define TRYOPEN 1
00347 #endif
00348 #define O_CLOSE 0x444
00349
00350 #if defined( __OpenBSD__ ) || defined( __NetBSD__ )
00351 #define DEV_DSP "/dev/audio"
00352 #else
00353 #define DEV_DSP "/dev/dsp"
00354 #endif
00355
00356 static const char *config = "usbradio.conf";
00357 #define config1 "usbradio_tune_%s.conf"
00358
00359 static FILE *frxcapraw = NULL, *frxcaptrace = NULL, *frxoutraw = NULL;
00360 static FILE *ftxcapraw = NULL, *ftxcaptrace = NULL, *ftxoutraw = NULL;
00361
00362 static char *usb_device_list = NULL;
00363 static int usb_device_list_size = 0;
00364
00365 static int usbradio_debug;
00366 #if 0 //maw asdf sph
00367 static int usbradio_debug_level = 0;
00368 #endif
00369
00370 enum {RX_AUDIO_NONE,RX_AUDIO_SPEAKER,RX_AUDIO_FLAT};
00371 enum {CD_IGNORE,CD_XPMR_NOISE,CD_XPMR_VOX,CD_HID,CD_HID_INVERT};
00372 enum {SD_IGNORE,SD_HID,SD_HID_INVERT,SD_XPMR};
00373 enum {RX_KEY_CARRIER,RX_KEY_CARRIER_CODE};
00374 enum {TX_OUT_OFF,TX_OUT_VOICE,TX_OUT_LSD,TX_OUT_COMPOSITE,TX_OUT_AUX};
00375 enum {TOC_NONE,TOC_PHASE,TOC_NOTONE};
00376
00377
00378
00379
00380
00381
00382
00383
00384 struct sound {
00385 int ind;
00386 char *desc;
00387 short *data;
00388 int datalen;
00389 int samplen;
00390 int silencelen;
00391 int repeat;
00392 };
00393
00394 #ifndef NEW_ASTERISK
00395
00396 static struct sound sounds[] = {
00397 { AST_CONTROL_RINGING, "RINGING", ringtone, sizeof(ringtone)/2, 16000, 32000, 1 },
00398 { AST_CONTROL_BUSY, "BUSY", busy, sizeof(busy)/2, 4000, 4000, 1 },
00399 { AST_CONTROL_CONGESTION, "CONGESTION", busy, sizeof(busy)/2, 2000, 2000, 1 },
00400 { AST_CONTROL_RING, "RING10", ring10, sizeof(ring10)/2, 16000, 32000, 1 },
00401 { AST_CONTROL_ANSWER, "ANSWER", answer, sizeof(answer)/2, 2200, 0, 0 },
00402 { -1, NULL, 0, 0, 0, 0 },
00403 };
00404
00405 #endif
00406
00407
00408
00409
00410
00411
00412
00413
00414 struct chan_usbradio_pvt {
00415 struct chan_usbradio_pvt *next;
00416
00417 char *name;
00418 #ifndef NEW_ASTERISK
00419
00420
00421
00422
00423
00424
00425
00426 int sndcmd[2];
00427 int cursound;
00428 int sampsent;
00429 int nosound;
00430 #endif
00431
00432 int pttkick[2];
00433 int total_blocks;
00434 int sounddev;
00435 enum { M_UNSET, M_FULL, M_READ, M_WRITE } duplex;
00436 i16 cdMethod;
00437 int autoanswer;
00438 int autohangup;
00439 int hookstate;
00440 unsigned int queuesize;
00441 unsigned int frags;
00442
00443 int warned;
00444 #define WARN_used_blocks 1
00445 #define WARN_speed 2
00446 #define WARN_frag 4
00447 int w_errors;
00448 struct timeval lastopen;
00449
00450 int overridecontext;
00451 int mute;
00452
00453
00454
00455
00456 #define BOOST_SCALE (1<<9)
00457 #define BOOST_MAX 40
00458 int boost;
00459 char devicenum;
00460 char devstr[128];
00461 int spkrmax;
00462 int micmax;
00463
00464 #ifndef NEW_ASTERISK
00465 pthread_t sthread;
00466 #endif
00467 pthread_t hidthread;
00468
00469 int stophid;
00470 FILE *hkickhid;
00471
00472 struct ast_channel *owner;
00473 char ext[AST_MAX_EXTENSION];
00474 char ctx[AST_MAX_CONTEXT];
00475 char language[MAX_LANGUAGE];
00476 char cid_name[256];
00477 char cid_num[256];
00478 char mohinterpret[MAX_MUSICCLASS];
00479
00480
00481 char usbradio_write_buf[FRAME_SIZE * 2 * 2 * 6];
00482 char usbradio_write_buf_1[FRAME_SIZE * 2 * 2* 6];
00483
00484 int usbradio_write_dst;
00485
00486
00487
00488 char usbradio_read_buf[FRAME_SIZE * (2 * 12) + AST_FRIENDLY_OFFSET];
00489 char usbradio_read_buf_8k[FRAME_SIZE * 2 + AST_FRIENDLY_OFFSET];
00490 int readpos;
00491 struct ast_frame read_f;
00492
00493 char debuglevel;
00494 char radioduplex;
00495 char wanteeprom;
00496
00497 int tracetype;
00498 int tracelevel;
00499 char area;
00500 char rptnum;
00501 int idleinterval;
00502 int turnoffs;
00503 int txsettletime;
00504 char ukey[48];
00505
00506 char lastrx;
00507 char rxhidsq;
00508 char rxcarrierdetect;
00509 char rxctcssdecode;
00510
00511 int rxdcsdecode;
00512 int rxlsddecode;
00513
00514 char rxkeytype;
00515 char rxkeyed;
00516
00517 char lasttx;
00518 char txkeyed;
00519 char txchankey;
00520 char txtestkey;
00521
00522 time_t lasthidtime;
00523 struct ast_dsp *dsp;
00524
00525 t_pmr_chan *pmrChan;
00526
00527 char rxcpusaver;
00528 char txcpusaver;
00529
00530 char rxdemod;
00531 float rxgain;
00532 char rxcdtype;
00533 char rxsdtype;
00534 int rxsquelchadj;
00535 int rxsqvoxadj;
00536 char txtoctype;
00537
00538 char txprelim;
00539 float txctcssgain;
00540 char txmixa;
00541 char txmixb;
00542
00543 char invertptt;
00544
00545 char rxctcssrelax;
00546 float rxctcssgain;
00547
00548 char txctcssdefault[16];
00549 char rxctcssfreqs[512];
00550 char txctcssfreqs[512];
00551
00552 char txctcssfreq[32];
00553 char rxctcssfreq[32];
00554
00555 char numrxctcssfreqs;
00556 char numtxctcssfreqs;
00557
00558 char *rxctcss[CTCSS_NUM_CODES];
00559 char *txctcss[CTCSS_NUM_CODES];
00560
00561 int txfreq;
00562 int rxfreq;
00563
00564
00565 char set_txctcssdefault[16];
00566 char set_txctcssfreq[16];
00567 char set_rxctcssfreq[16];
00568
00569 char set_numrxctcssfreqs;
00570 char set_numtxctcssfreqs;
00571
00572 char set_rxctcssfreqs[16];
00573 char set_txctcssfreqs[16];
00574
00575 char *set_rxctcss;
00576 char *set_txctcss;
00577
00578 int set_txfreq;
00579 int set_rxfreq;
00580
00581
00582 int rxmixerset;
00583 int rxboostset;
00584 float rxvoiceadj;
00585 float rxctcssadj;
00586 int txmixaset;
00587 int txmixbset;
00588 int txctcssadj;
00589
00590 int hdwtype;
00591 int hid_gpio_ctl;
00592 int hid_gpio_ctl_loc;
00593 int hid_io_cor;
00594 int hid_io_cor_loc;
00595 int hid_io_ctcss;
00596 int hid_io_ctcss_loc;
00597 int hid_io_ptt;
00598 int hid_gpio_loc;
00599
00600 struct {
00601 unsigned rxcapraw:1;
00602 unsigned txcapraw:1;
00603 unsigned txcap2:1;
00604 unsigned rxcap2:1;
00605 unsigned rxplmon:1;
00606 unsigned remoted:1;
00607 unsigned txpolarity:1;
00608 unsigned rxpolarity:1;
00609 unsigned dcstxpolarity:1;
00610 unsigned dcsrxpolarity:1;
00611 unsigned lsdtxpolarity:1;
00612 unsigned lsdrxpolarity:1;
00613 unsigned loopback:1;
00614 unsigned radioactive:1;
00615 }b;
00616 unsigned short eeprom[EEPROM_PHYSICAL_LEN];
00617 char eepromctl;
00618 ast_mutex_t eepromlock;
00619
00620 struct usb_dev_handle *usb_handle;
00621 int readerrs;
00622 };
00623
00624
00625 static struct chan_usbradio_pvt usbradio_default = {
00626 #ifndef NEW_ASTERISK
00627 .cursound = -1,
00628 #endif
00629 .sounddev = -1,
00630 .duplex = M_UNSET,
00631 .autoanswer = 1,
00632 .autohangup = 1,
00633 .queuesize = QUEUE_SIZE,
00634 .frags = FRAGS,
00635 .ext = "s",
00636 .ctx = "default",
00637 .readpos = AST_FRIENDLY_OFFSET,
00638 .lastopen = { 0, 0 },
00639 .boost = BOOST_SCALE,
00640 .wanteeprom = 1,
00641 .area = 0,
00642 .rptnum = 0,
00643 };
00644
00645
00646
00647 static void store_txtoctype(struct chan_usbradio_pvt *o, const char *s);
00648 static int hidhdwconfig(struct chan_usbradio_pvt *o);
00649 static int set_txctcss_level(struct chan_usbradio_pvt *o);
00650 static void pmrdump(struct chan_usbradio_pvt *o);
00651 static void mult_set(struct chan_usbradio_pvt *o);
00652 static int mult_calc(int value);
00653 static void mixer_write(struct chan_usbradio_pvt *o);
00654 static void tune_rxinput(int fd, struct chan_usbradio_pvt *o);
00655 static void tune_rxvoice(int fd, struct chan_usbradio_pvt *o);
00656 static void tune_rxctcss(int fd, struct chan_usbradio_pvt *o);
00657 static void tune_txoutput(struct chan_usbradio_pvt *o, int value, int fd);
00658 static void tune_write(struct chan_usbradio_pvt *o);
00659
00660 static char *usbradio_active;
00661
00662 static int setformat(struct chan_usbradio_pvt *o, int mode);
00663
00664 static struct ast_channel *usbradio_request(const char *type, format_t format,
00665 const struct ast_channel *requestor,
00666 void *data, int *cause);
00667 static int usbradio_digit_begin(struct ast_channel *c, char digit);
00668 static int usbradio_digit_end(struct ast_channel *c, char digit, unsigned int duration);
00669 static int usbradio_text(struct ast_channel *c, const char *text);
00670 static int usbradio_hangup(struct ast_channel *c);
00671 static int usbradio_answer(struct ast_channel *c);
00672 static struct ast_frame *usbradio_read(struct ast_channel *chan);
00673 static int usbradio_call(struct ast_channel *c, char *dest, int timeout);
00674 static int usbradio_write(struct ast_channel *chan, struct ast_frame *f);
00675 static int usbradio_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen);
00676 static int usbradio_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00677 static int xpmr_config(struct chan_usbradio_pvt *o);
00678
00679 #if DEBUG_FILETEST == 1
00680 static int RxTestIt(struct chan_usbradio_pvt *o);
00681 #endif
00682
00683 static char tdesc[] = "USB (CM108) Radio Channel Driver";
00684
00685 static const struct ast_channel_tech usbradio_tech = {
00686 .type = "Radio",
00687 .description = tdesc,
00688 .capabilities = AST_FORMAT_SLINEAR,
00689 .requester = usbradio_request,
00690 .send_digit_begin = usbradio_digit_begin,
00691 .send_digit_end = usbradio_digit_end,
00692 .send_text = usbradio_text,
00693 .hangup = usbradio_hangup,
00694 .answer = usbradio_answer,
00695 .read = usbradio_read,
00696 .call = usbradio_call,
00697 .write = usbradio_write,
00698 .indicate = usbradio_indicate,
00699 .fixup = usbradio_fixup,
00700 };
00701
00702
00703
00704
00705
00706
00707
00708 static int amixer_max(int devnum,char *param)
00709 {
00710 int rv,type;
00711 char str[100];
00712 snd_hctl_t *hctl;
00713 snd_ctl_elem_id_t *id;
00714 snd_hctl_elem_t *elem;
00715 snd_ctl_elem_info_t *info;
00716
00717 sprintf(str,"hw:%d",devnum);
00718 if (snd_hctl_open(&hctl, str, 0)) return(-1);
00719 snd_hctl_load(hctl);
00720 snd_ctl_elem_id_alloca(&id);
00721 snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
00722 snd_ctl_elem_id_set_name(id, param);
00723 elem = snd_hctl_find_elem(hctl, id);
00724 if (!elem)
00725 {
00726 snd_hctl_close(hctl);
00727 return(-1);
00728 }
00729 snd_ctl_elem_info_alloca(&info);
00730 snd_hctl_elem_info(elem,info);
00731 type = snd_ctl_elem_info_get_type(info);
00732 rv = 0;
00733 switch(type)
00734 {
00735 case SND_CTL_ELEM_TYPE_INTEGER:
00736 rv = snd_ctl_elem_info_get_max(info);
00737 break;
00738 case SND_CTL_ELEM_TYPE_BOOLEAN:
00739 rv = 1;
00740 break;
00741 }
00742 snd_hctl_close(hctl);
00743 return(rv);
00744 }
00745
00746
00747
00748
00749
00750
00751
00752 static int setamixer(int devnum,char *param, int v1, int v2)
00753 {
00754 int type;
00755 char str[100];
00756 snd_hctl_t *hctl;
00757 snd_ctl_elem_id_t *id;
00758 snd_ctl_elem_value_t *control;
00759 snd_hctl_elem_t *elem;
00760 snd_ctl_elem_info_t *info;
00761
00762 sprintf(str,"hw:%d",devnum);
00763 if (snd_hctl_open(&hctl, str, 0)) return(-1);
00764 snd_hctl_load(hctl);
00765 snd_ctl_elem_id_alloca(&id);
00766 snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
00767 snd_ctl_elem_id_set_name(id, param);
00768 elem = snd_hctl_find_elem(hctl, id);
00769 if (!elem)
00770 {
00771 snd_hctl_close(hctl);
00772 return(-1);
00773 }
00774 snd_ctl_elem_info_alloca(&info);
00775 snd_hctl_elem_info(elem,info);
00776 type = snd_ctl_elem_info_get_type(info);
00777 snd_ctl_elem_value_alloca(&control);
00778 snd_ctl_elem_value_set_id(control, id);
00779 switch(type)
00780 {
00781 case SND_CTL_ELEM_TYPE_INTEGER:
00782 snd_ctl_elem_value_set_integer(control, 0, v1);
00783 if (v2 > 0) snd_ctl_elem_value_set_integer(control, 1, v2);
00784 break;
00785 case SND_CTL_ELEM_TYPE_BOOLEAN:
00786 snd_ctl_elem_value_set_integer(control, 0, (v1 != 0));
00787 break;
00788 }
00789 if (snd_hctl_elem_write(elem, control))
00790 {
00791 snd_hctl_close(hctl);
00792 return(-1);
00793 }
00794 snd_hctl_close(hctl);
00795 return(0);
00796 }
00797
00798 static void hid_set_outputs(struct usb_dev_handle *handle,
00799 unsigned char *outputs)
00800 {
00801 usleep(1500);
00802 usb_control_msg(handle,
00803 USB_ENDPOINT_OUT + USB_TYPE_CLASS + USB_RECIP_INTERFACE,
00804 HID_REPORT_SET,
00805 0 + (HID_RT_OUTPUT << 8),
00806 C108_HID_INTERFACE,
00807 (char*)outputs, 4, 5000);
00808 }
00809
00810 static void hid_get_inputs(struct usb_dev_handle *handle,
00811 unsigned char *inputs)
00812 {
00813 usleep(1500);
00814 usb_control_msg(handle,
00815 USB_ENDPOINT_IN + USB_TYPE_CLASS + USB_RECIP_INTERFACE,
00816 HID_REPORT_GET,
00817 0 + (HID_RT_INPUT << 8),
00818 C108_HID_INTERFACE,
00819 (char*)inputs, 4, 5000);
00820 }
00821
00822 static unsigned short read_eeprom(struct usb_dev_handle *handle, int addr)
00823 {
00824 unsigned char buf[4];
00825
00826 buf[0] = 0x80;
00827 buf[1] = 0;
00828 buf[2] = 0;
00829 buf[3] = 0x80 | (addr & 0x3f);
00830 hid_set_outputs(handle,buf);
00831 memset(buf,0,sizeof(buf));
00832 hid_get_inputs(handle,buf);
00833 return(buf[1] + (buf[2] << 8));
00834 }
00835
00836 static void write_eeprom(struct usb_dev_handle *handle, int addr,
00837 unsigned short data)
00838 {
00839
00840 unsigned char buf[4];
00841
00842 buf[0] = 0x80;
00843 buf[1] = data & 0xff;
00844 buf[2] = data >> 8;
00845 buf[3] = 0xc0 | (addr & 0x3f);
00846 hid_set_outputs(handle,buf);
00847 }
00848
00849 static unsigned short get_eeprom(struct usb_dev_handle *handle,
00850 unsigned short *buf)
00851 {
00852 int i;
00853 unsigned short cs;
00854
00855 cs = 0xffff;
00856 for(i = EEPROM_START_ADDR; i < EEPROM_END_ADDR; i++)
00857 {
00858 cs += buf[i] = read_eeprom(handle,i);
00859 }
00860 return(cs);
00861 }
00862
00863 static void put_eeprom(struct usb_dev_handle *handle,unsigned short *buf)
00864 {
00865 int i;
00866 unsigned short cs;
00867
00868 cs = 0xffff;
00869 buf[EEPROM_MAGIC_ADDR] = EEPROM_MAGIC;
00870 for(i = EEPROM_START_ADDR; i < EEPROM_CS_ADDR; i++)
00871 {
00872 write_eeprom(handle,i,buf[i]);
00873 cs += buf[i];
00874 }
00875 buf[EEPROM_CS_ADDR] = (65535 - cs) + 1;
00876 write_eeprom(handle,i,buf[EEPROM_CS_ADDR]);
00877 }
00878
00879 static struct usb_device *hid_device_init(char *desired_device)
00880 {
00881 struct usb_bus *usb_bus;
00882 struct usb_device *dev;
00883 char devstr[200],str[200],desdev[200],*cp;
00884 int i;
00885 FILE *fp;
00886
00887 usb_init();
00888 usb_find_busses();
00889 usb_find_devices();
00890 for (usb_bus = usb_busses;
00891 usb_bus;
00892 usb_bus = usb_bus->next) {
00893 for (dev = usb_bus->devices;
00894 dev;
00895 dev = dev->next) {
00896 if ((dev->descriptor.idVendor
00897 == C108_VENDOR_ID) &&
00898 (dev->descriptor.idProduct
00899 == C108_PRODUCT_ID))
00900 {
00901 sprintf(devstr,"%s/%s", usb_bus->dirname,dev->filename);
00902 for(i = 0; i < 32; i++)
00903 {
00904 sprintf(str,"/proc/asound/card%d/usbbus",i);
00905 fp = fopen(str,"r");
00906 if (!fp) continue;
00907 if ((!fgets(desdev,sizeof(desdev) - 1,fp)) || (!desdev[0]))
00908 {
00909 fclose(fp);
00910 continue;
00911 }
00912 fclose(fp);
00913 if (desdev[strlen(desdev) - 1] == '\n')
00914 desdev[strlen(desdev) -1 ] = 0;
00915 if (strcasecmp(desdev,devstr)) continue;
00916 if (i) sprintf(str,"/sys/class/sound/dsp%d/device",i);
00917 else strcpy(str,"/sys/class/sound/dsp/device");
00918 memset(desdev,0,sizeof(desdev));
00919 if (readlink(str,desdev,sizeof(desdev) - 1) == -1)
00920 {
00921 sprintf(str,"/sys/class/sound/controlC%d/device",i);
00922 memset(desdev,0,sizeof(desdev));
00923 if (readlink(str,desdev,sizeof(desdev) - 1) == -1) continue;
00924 }
00925 cp = strrchr(desdev,'/');
00926 if (cp) *cp = 0; else continue;
00927 cp = strrchr(desdev,'/');
00928 if (!cp) continue;
00929 cp++;
00930 break;
00931 }
00932 if (i >= 32) continue;
00933 if (!strcmp(cp,desired_device)) return dev;
00934 }
00935
00936 }
00937 }
00938 return NULL;
00939 }
00940
00941 static int hid_device_mklist(void)
00942 {
00943 struct usb_bus *usb_bus;
00944 struct usb_device *dev;
00945 char devstr[200],str[200],desdev[200],*cp;
00946 int i;
00947 FILE *fp;
00948
00949 usb_device_list = ast_malloc(2);
00950 if (!usb_device_list) return -1;
00951 memset(usb_device_list,0,2);
00952
00953 usb_init();
00954 usb_find_busses();
00955 usb_find_devices();
00956 for (usb_bus = usb_busses;
00957 usb_bus;
00958 usb_bus = usb_bus->next) {
00959 for (dev = usb_bus->devices;
00960 dev;
00961 dev = dev->next) {
00962 if ((dev->descriptor.idVendor
00963 == C108_VENDOR_ID) &&
00964 (dev->descriptor.idProduct
00965 == C108_PRODUCT_ID))
00966 {
00967 sprintf(devstr,"%s/%s", usb_bus->dirname,dev->filename);
00968 for(i = 0;i < 32; i++)
00969 {
00970 sprintf(str,"/proc/asound/card%d/usbbus",i);
00971 fp = fopen(str,"r");
00972 if (!fp) continue;
00973 if ((!fgets(desdev,sizeof(desdev) - 1,fp)) || (!desdev[0]))
00974 {
00975 fclose(fp);
00976 continue;
00977 }
00978 fclose(fp);
00979 if (desdev[strlen(desdev) - 1] == '\n')
00980 desdev[strlen(desdev) -1 ] = 0;
00981 if (strcasecmp(desdev,devstr)) continue;
00982 if (i) sprintf(str,"/sys/class/sound/dsp%d/device",i);
00983 else strcpy(str,"/sys/class/sound/dsp/device");
00984 memset(desdev,0,sizeof(desdev));
00985 if (readlink(str,desdev,sizeof(desdev) - 1) == -1)
00986 {
00987 sprintf(str,"/sys/class/sound/controlC%d/device",i);
00988 memset(desdev,0,sizeof(desdev));
00989 if (readlink(str,desdev,sizeof(desdev) - 1) == -1) continue;
00990 }
00991 cp = strrchr(desdev,'/');
00992 if (cp) *cp = 0; else continue;
00993 cp = strrchr(desdev,'/');
00994 if (!cp) continue;
00995 cp++;
00996 break;
00997 }
00998 if (i >= 32) return -1;
00999 usb_device_list = ast_realloc(usb_device_list,
01000 usb_device_list_size + 2 +
01001 strlen(cp));
01002 if (!usb_device_list) return -1;
01003 usb_device_list_size += strlen(cp) + 2;
01004 i = 0;
01005 while(usb_device_list[i])
01006 {
01007 i += strlen(usb_device_list + i) + 1;
01008 }
01009 strcat(usb_device_list + i,cp);
01010 usb_device_list[strlen(cp) + i + 1] = 0;
01011 }
01012
01013 }
01014 }
01015 return 0;
01016 }
01017
01018
01019 static int usb_get_usbdev(char *devstr)
01020 {
01021 int i;
01022 char str[200],desdev[200],*cp;
01023
01024 for(i = 0;i < 32; i++)
01025 {
01026 if (i) sprintf(str,"/sys/class/sound/dsp%d/device",i);
01027 else strcpy(str,"/sys/class/sound/dsp/device");
01028 memset(desdev,0,sizeof(desdev));
01029 if (readlink(str,desdev,sizeof(desdev) - 1) == -1)
01030 {
01031 sprintf(str,"/sys/class/sound/controlC%d/device",i);
01032 memset(desdev,0,sizeof(desdev));
01033 if (readlink(str,desdev,sizeof(desdev) - 1) == -1) continue;
01034 }
01035 cp = strrchr(desdev,'/');
01036 if (cp) *cp = 0; else continue;
01037 cp = strrchr(desdev,'/');
01038 if (!cp) continue;
01039 cp++;
01040 if (!strcasecmp(cp,devstr)) break;
01041 }
01042 if (i >= 32) return -1;
01043 return i;
01044
01045 }
01046
01047 static int usb_list_check(char *devstr)
01048 {
01049
01050 char *s = usb_device_list;
01051
01052 if (!s) return(0);
01053 while(*s)
01054 {
01055 if (!strcasecmp(s,devstr)) return(1);
01056 s += strlen(s) + 1;
01057 }
01058 return(0);
01059 }
01060
01061
01062 static int hidhdwconfig(struct chan_usbradio_pvt *o)
01063 {
01064 if(o->hdwtype==1)
01065 {
01066 o->hid_gpio_ctl = 0x08;
01067 o->hid_gpio_ctl_loc = 2;
01068 o->hid_io_cor = 4;
01069 o->hid_io_cor_loc = 1;
01070 o->hid_io_ctcss = 2;
01071 o->hid_io_ctcss_loc = 1;
01072 o->hid_io_ptt = 8;
01073 o->hid_gpio_loc = 1;
01074 }
01075 else if(o->hdwtype==0)
01076 {
01077 o->hid_gpio_ctl = 0x0c;
01078 o->hid_gpio_ctl_loc = 2;
01079 o->hid_io_cor = 2;
01080 o->hid_io_cor_loc = 0;
01081 o->hid_io_ctcss = 2;
01082 o->hid_io_ctcss_loc = 1;
01083 o->hid_io_ptt = 4;
01084 o->hid_gpio_loc = 1;
01085 }
01086 else if(o->hdwtype==3)
01087 {
01088 o->hid_gpio_ctl = 0x0c;
01089 o->hid_gpio_ctl_loc = 2;
01090 o->hid_io_cor = 2;
01091 o->hid_io_cor_loc = 0;
01092 o->hid_io_ctcss = 2;
01093 o->hid_io_ctcss_loc = 1;
01094 o->hid_io_ptt = 4;
01095 o->hid_gpio_loc = 1;
01096 }
01097
01098 return 0;
01099 }
01100
01101
01102 static void kickptt(struct chan_usbradio_pvt *o)
01103 {
01104 char c = 0;
01105
01106 if (!o) return;
01107 if (!o->pttkick) return;
01108 if (write(o->pttkick[1],&c,1) < 0) {
01109 ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
01110 }
01111 }
01112
01113
01114 static void *hidthread(void *arg)
01115 {
01116 unsigned char buf[4],bufsave[4],keyed;
01117 char lastrx, txtmp;
01118 int res;
01119 struct usb_device *usb_dev;
01120 struct usb_dev_handle *usb_handle;
01121 struct chan_usbradio_pvt *o = (struct chan_usbradio_pvt *) arg;
01122 struct pollfd pfd = { .events = POLLIN };
01123
01124 usb_dev = hid_device_init(o->devstr);
01125 if (usb_dev == NULL) {
01126 ast_log(LOG_ERROR,"USB HID device not found\n");
01127 pthread_exit(NULL);
01128 }
01129 usb_handle = usb_open(usb_dev);
01130 if (usb_handle == NULL) {
01131 ast_log(LOG_ERROR,"Not able to open USB device\n");
01132 pthread_exit(NULL);
01133 }
01134 if (usb_claim_interface(usb_handle,C108_HID_INTERFACE) < 0)
01135 {
01136 if (usb_detach_kernel_driver_np(usb_handle,C108_HID_INTERFACE) < 0) {
01137 ast_log(LOG_ERROR,"Not able to detach the USB device\n");
01138 pthread_exit(NULL);
01139 }
01140 if (usb_claim_interface(usb_handle,C108_HID_INTERFACE) < 0) {
01141 ast_log(LOG_ERROR,"Not able to claim the USB device\n");
01142 pthread_exit(NULL);
01143 }
01144 }
01145 memset(buf,0,sizeof(buf));
01146 buf[2] = o->hid_gpio_ctl;
01147 buf[1] = 0;
01148 hid_set_outputs(usb_handle,buf);
01149 memcpy(bufsave,buf,sizeof(buf));
01150 if (pipe(o->pttkick) == -1)
01151 {
01152 ast_log(LOG_ERROR,"Not able to create pipe\n");
01153 pthread_exit(NULL);
01154 }
01155 traceusb1(("hidthread: Starting normally on %s!!\n",o->name));
01156 lastrx = 0;
01157
01158 while (!o->stophid) {
01159 pfd.fd = o->pttkick[0];
01160 pfd.revents = 0;
01161
01162 res = ast_poll(&pfd, 1, 50);
01163 if (res < 0) {
01164 ast_log(LOG_WARNING, "poll() failed: %s\n", strerror(errno));
01165 usleep(10000);
01166 continue;
01167 }
01168 if (pfd.revents & POLLIN) {
01169 char c;
01170
01171 if (read(o->pttkick[0], &c, 1) < 0) {
01172 ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
01173 }
01174 }
01175 if (o->wanteeprom) {
01176 ast_mutex_lock(&o->eepromlock);
01177 if (o->eepromctl == 1) {
01178
01179 if (!get_eeprom(usb_handle, o->eeprom)) {
01180 if (o->eeprom[EEPROM_MAGIC_ADDR] != EEPROM_MAGIC) {
01181 ast_log(LOG_NOTICE, "UNSUCCESSFUL: EEPROM MAGIC NUMBER BAD on channel %s\n", o->name);
01182 } else {
01183 o->rxmixerset = o->eeprom[EEPROM_RXMIXERSET];
01184 o->txmixaset = o->eeprom[EEPROM_TXMIXASET];
01185 o->txmixbset = o->eeprom[EEPROM_TXMIXBSET];
01186 memcpy(&o->rxvoiceadj, &o->eeprom[EEPROM_RXVOICEADJ], sizeof(float));
01187 memcpy(&o->rxctcssadj, &o->eeprom[EEPROM_RXCTCSSADJ], sizeof(float));
01188 o->txctcssadj = o->eeprom[EEPROM_TXCTCSSADJ];
01189 o->rxsquelchadj = o->eeprom[EEPROM_RXSQUELCHADJ];
01190 ast_log(LOG_NOTICE,"EEPROM Loaded on channel %s\n",o->name);
01191 }
01192 } else {
01193 ast_log(LOG_NOTICE, "USB Adapter has no EEPROM installed or Checksum BAD on channel %s\n", o->name);
01194 }
01195 hid_set_outputs(usb_handle,bufsave);
01196 }
01197 if (o->eepromctl == 2) {
01198 put_eeprom(usb_handle,o->eeprom);
01199 hid_set_outputs(usb_handle,bufsave);
01200 ast_log(LOG_NOTICE, "USB Parameters written to EEPROM on %s\n", o->name);
01201 }
01202 o->eepromctl = 0;
01203 ast_mutex_unlock(&o->eepromlock);
01204 }
01205 buf[o->hid_gpio_ctl_loc] = o->hid_gpio_ctl;
01206 hid_get_inputs(usb_handle,buf);
01207 keyed = !(buf[o->hid_io_cor_loc] & o->hid_io_cor);
01208 if (keyed != o->rxhidsq) {
01209 if (o->debuglevel) {
01210 printf("chan_usbradio() hidthread: update rxhidsq = %d\n", keyed);
01211 }
01212 o->rxhidsq=keyed;
01213 }
01214
01215
01216 txtmp = o->pmrChan->txPttOut;
01217
01218 if (o->lasttx != txtmp) {
01219 o->pmrChan->txPttHid = o->lasttx = txtmp;
01220 if (o->debuglevel) {
01221 ast_debug(0, "hidthread: tx set to %d\n", txtmp);
01222 }
01223 buf[o->hid_gpio_loc] = 0;
01224 if (!o->invertptt) {
01225 if (txtmp) {
01226 buf[o->hid_gpio_loc] = o->hid_io_ptt;
01227 }
01228 } else {
01229 if (!txtmp) {
01230 buf[o->hid_gpio_loc] = o->hid_io_ptt;
01231 }
01232 }
01233 buf[o->hid_gpio_ctl_loc] = o->hid_gpio_ctl;
01234 memcpy(bufsave, buf, sizeof(buf));
01235 hid_set_outputs(usb_handle, buf);
01236 }
01237 time(&o->lasthidtime);
01238 }
01239 buf[o->hid_gpio_loc] = 0;
01240 if (o->invertptt) {
01241 buf[o->hid_gpio_loc] = o->hid_io_ptt;
01242 }
01243 buf[o->hid_gpio_ctl_loc] = o->hid_gpio_ctl;
01244 hid_set_outputs(usb_handle, buf);
01245 pthread_exit(0);
01246 }
01247
01248
01249
01250
01251 static struct chan_usbradio_pvt *find_desc(char *dev)
01252 {
01253 struct chan_usbradio_pvt *o = NULL;
01254
01255 if (!dev)
01256 ast_log(LOG_WARNING, "null dev\n");
01257
01258 for (o = usbradio_default.next; o && o->name && dev && strcmp(o->name, dev) != 0; o = o->next);
01259 if (!o)
01260 {
01261 ast_log(LOG_WARNING, "could not find <%s>\n", dev ? dev : "--no-device--");
01262 }
01263
01264 return o;
01265 }
01266
01267 static struct chan_usbradio_pvt *find_desc_usb(char *devstr)
01268 {
01269 struct chan_usbradio_pvt *o = NULL;
01270
01271 if (!devstr)
01272 ast_log(LOG_WARNING, "null dev\n");
01273
01274 for (o = usbradio_default.next; o && devstr && strcmp(o->devstr, devstr) != 0; o = o->next);
01275
01276 return o;
01277 }
01278
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288 #if 0
01289 static char *ast_ext_ctx(const char *src, char **ext, char **ctx)
01290 {
01291 struct chan_usbradio_pvt *o = find_desc(usbradio_active);
01292
01293 if (ext == NULL || ctx == NULL)
01294 return NULL;
01295
01296 *ext = *ctx = NULL;
01297
01298 if (src && *src != '\0')
01299 *ext = ast_strdup(src);
01300
01301 if (*ext == NULL)
01302 return NULL;
01303
01304 if (!o->overridecontext) {
01305
01306 *ctx = strrchr(*ext, '@');
01307 if (*ctx)
01308 *(*ctx)++ = '\0';
01309 }
01310
01311 return *ext;
01312 }
01313 #endif
01314
01315
01316
01317
01318 static int used_blocks(struct chan_usbradio_pvt *o)
01319 {
01320 struct audio_buf_info info;
01321
01322 if (ioctl(o->sounddev, SNDCTL_DSP_GETOSPACE, &info)) {
01323 if (!(o->warned & WARN_used_blocks)) {
01324 ast_log(LOG_WARNING, "Error reading output space\n");
01325 o->warned |= WARN_used_blocks;
01326 }
01327 return 1;
01328 }
01329
01330 if (o->total_blocks == 0) {
01331 if (0)
01332 ast_log(LOG_WARNING, "fragtotal %d size %d avail %d\n", info.fragstotal, info.fragsize, info.fragments);
01333 o->total_blocks = info.fragments;
01334 }
01335
01336 return o->total_blocks - info.fragments;
01337 }
01338
01339
01340 static int soundcard_writeframe(struct chan_usbradio_pvt *o, short *data)
01341 {
01342 int res;
01343
01344 if (o->sounddev < 0)
01345 setformat(o, O_RDWR);
01346 if (o->sounddev < 0)
01347 return 0;
01348
01349
01350
01351 if(!o->pmrChan->txPttIn && !o->pmrChan->txPttOut)
01352 {
01353
01354 }
01355
01356
01357
01358
01359
01360
01361 res = used_blocks(o);
01362 if (res > o->queuesize) {
01363
01364 if (o->w_errors++ == 0 && (usbradio_debug & 0x4))
01365 ast_log(LOG_WARNING, "write: used %d blocks (%d)\n", res, o->w_errors);
01366 return 0;
01367 }
01368 o->w_errors = 0;
01369
01370 return write(o->sounddev, ((void *) data), FRAME_SIZE * 2 * 12);
01371 }
01372
01373 #ifndef NEW_ASTERISK
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385 static void send_sound(struct chan_usbradio_pvt *o)
01386 {
01387 short myframe[FRAME_SIZE];
01388 int ofs, l, start;
01389 int l_sampsent = o->sampsent;
01390 struct sound *s;
01391
01392 if (o->cursound < 0)
01393 return;
01394
01395 s = &sounds[o->cursound];
01396
01397 for (ofs = 0; ofs < FRAME_SIZE; ofs += l) {
01398 l = s->samplen - l_sampsent;
01399 if (l > 0) {
01400 start = l_sampsent % s->datalen;
01401 if (l > FRAME_SIZE - ofs)
01402 l = FRAME_SIZE - ofs;
01403 if (l > s->datalen - start)
01404 l = s->datalen - start;
01405 memmove(myframe + ofs, s->data + start, l * 2);
01406 if (0)
01407 ast_log(LOG_WARNING, "send_sound sound %d/%d of %d into %d\n", l_sampsent, l, s->samplen, ofs);
01408 l_sampsent += l;
01409 } else {
01410 static const short silence[FRAME_SIZE] = { 0, };
01411
01412 l += s->silencelen;
01413 if (l > 0) {
01414 if (l > FRAME_SIZE - ofs)
01415 l = FRAME_SIZE - ofs;
01416 memmove(myframe + ofs, silence, l * 2);
01417 l_sampsent += l;
01418 } else {
01419 if (s->repeat == 0) {
01420 o->cursound = -1;
01421 o->nosound = 0;
01422 if (ofs < FRAME_SIZE)
01423 memmove(myframe + ofs, silence, (FRAME_SIZE - ofs) * 2);
01424 }
01425 l_sampsent = 0;
01426 }
01427 }
01428 }
01429 l = soundcard_writeframe(o, myframe);
01430 if (l > 0)
01431 o->sampsent = l_sampsent;
01432 }
01433
01434 static void *sound_thread(void *arg)
01435 {
01436 char ign[4096];
01437 struct chan_usbradio_pvt *o = (struct chan_usbradio_pvt *) arg;
01438
01439
01440
01441
01442
01443 read(o->sounddev, ign, sizeof(ign));
01444 for (;;) {
01445 struct pollfd pfd[2] = { { .fd = o->sndcmd[0], .events = POLLIN }, { .fd = o->sounddev } };
01446 int res;
01447
01448 if (o->cursound > -1 && o->sounddev < 0) {
01449 setformat(o, O_RDWR);
01450 } else if (o->cursound == -1 && o->owner == NULL) {
01451 setformat(o, O_CLOSE);
01452 }
01453 if (o->sounddev > -1) {
01454 if (!o->owner) {
01455 pfd[1].events = POLLIN;
01456 }
01457 if (o->cursound > -1) {
01458 pfd[1].events |= POLLOUT;
01459 }
01460 }
01461 res = ast_poll(pfd, o->sounddev > -1 ? 2 : 1, -1);
01462 if (res < 1) {
01463 ast_log(LOG_WARNING, "poll failed: %s\n", strerror(errno));
01464 sleep(1);
01465 continue;
01466 }
01467 if (pfd[0].revents & POLLIN) {
01468
01469 int i, what = -1;
01470
01471 read(o->sndcmd[0], &what, sizeof(what));
01472 for (i = 0; sounds[i].ind != -1; i++) {
01473 if (sounds[i].ind == what) {
01474 o->cursound = i;
01475 o->sampsent = 0;
01476 o->nosound = 1;
01477 break;
01478 }
01479 }
01480 if (sounds[i].ind == -1) {
01481 ast_log(LOG_WARNING, "invalid sound index: %d\n", what);
01482 }
01483 }
01484 if (o->sounddev > -1) {
01485 if (pfd[1].revents & POLLIN) {
01486 read(o->sounddev, ign, sizeof(ign));
01487 }
01488 if (pfd[1].revents & POLLOUT) {
01489 send_sound(o);
01490 }
01491 }
01492 }
01493 return NULL;
01494 }
01495
01496 #endif
01497
01498
01499
01500
01501
01502
01503 static int setformat(struct chan_usbradio_pvt *o, int mode)
01504 {
01505 int fmt, desired, res, fd;
01506 char device[100];
01507
01508 if (o->sounddev >= 0) {
01509 ioctl(o->sounddev, SNDCTL_DSP_RESET, 0);
01510 close(o->sounddev);
01511 o->duplex = M_UNSET;
01512 o->sounddev = -1;
01513 }
01514 if (mode == O_CLOSE)
01515 return 0;
01516 o->lastopen = ast_tvnow();
01517 strcpy(device,"/dev/dsp");
01518 if (o->devicenum)
01519 sprintf(device,"/dev/dsp%d",o->devicenum);
01520 fd = o->sounddev = open(device, mode | O_NONBLOCK);
01521 if (fd < 0) {
01522 ast_log(LOG_WARNING, "Unable to re-open DSP device %d: %s\n", o->devicenum, strerror(errno));
01523 return -1;
01524 }
01525 if (o->owner)
01526 o->owner->fds[0] = fd;
01527
01528 #if __BYTE_ORDER == __LITTLE_ENDIAN
01529 fmt = AFMT_S16_LE;
01530 #else
01531 fmt = AFMT_S16_BE;
01532 #endif
01533 res = ioctl(fd, SNDCTL_DSP_SETFMT, &fmt);
01534 if (res < 0) {
01535 ast_log(LOG_WARNING, "Unable to set format to 16-bit signed\n");
01536 return -1;
01537 }
01538 switch (mode) {
01539 case O_RDWR:
01540 res = ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
01541
01542 res = ioctl(fd, SNDCTL_DSP_GETCAPS, &fmt);
01543 if (res == 0 && (fmt & DSP_CAP_DUPLEX)) {
01544 if (option_verbose > 1)
01545 ast_verbose(VERBOSE_PREFIX_2 "Console is full duplex\n");
01546 o->duplex = M_FULL;
01547 };
01548 break;
01549 case O_WRONLY:
01550 o->duplex = M_WRITE;
01551 break;
01552 case O_RDONLY:
01553 o->duplex = M_READ;
01554 break;
01555 }
01556
01557 fmt = 1;
01558 res = ioctl(fd, SNDCTL_DSP_STEREO, &fmt);
01559 if (res < 0) {
01560 ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
01561 return -1;
01562 }
01563 fmt = desired = 48000;
01564 res = ioctl(fd, SNDCTL_DSP_SPEED, &fmt);
01565
01566 if (res < 0) {
01567 ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
01568 return -1;
01569 }
01570 if (fmt != desired) {
01571 if (!(o->warned & WARN_speed)) {
01572 ast_log(LOG_WARNING,
01573 "Requested %d Hz, got %d Hz -- sound may be choppy\n",
01574 desired, fmt);
01575 o->warned |= WARN_speed;
01576 }
01577 }
01578
01579
01580
01581
01582 if (o->frags) {
01583 fmt = o->frags;
01584 res = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fmt);
01585 if (res < 0) {
01586 if (!(o->warned & WARN_frag)) {
01587 ast_log(LOG_WARNING,
01588 "Unable to set fragment size -- sound may be choppy\n");
01589 o->warned |= WARN_frag;
01590 }
01591 }
01592 }
01593
01594 res = PCM_ENABLE_INPUT | PCM_ENABLE_OUTPUT;
01595 res = ioctl(fd, SNDCTL_DSP_SETTRIGGER, &res);
01596
01597 return 0;
01598 }
01599
01600
01601
01602
01603 static int usbradio_digit_begin(struct ast_channel *c, char digit)
01604 {
01605 return 0;
01606 }
01607
01608 static int usbradio_digit_end(struct ast_channel *c, char digit, unsigned int duration)
01609 {
01610
01611 ast_verbose(" << Console Received digit %c of duration %u ms >> \n",
01612 digit, duration);
01613 return 0;
01614 }
01615
01616
01617
01618
01619 static int usbradio_text(struct ast_channel *c, const char *text)
01620 {
01621 struct chan_usbradio_pvt *o = find_desc(usbradio_active);
01622 double tx,rx;
01623 char cnt,rxs[16],txs[16],txpl[16],rxpl[16];
01624 char pwr,*cmd;
01625
01626 cmd = alloca(strlen(text) + 10);
01627
01628
01629 if(o->debuglevel)ast_verbose(" << Console Received usbradio text %s >> \n", text);
01630
01631 cnt = sscanf(text, "%300s %15s %15s %15s %15s %1c", cmd, rxs, txs, rxpl, txpl, &pwr);
01632
01633 if (strcmp(cmd,"SETCHAN")==0)
01634 {
01635 u8 chan;
01636 chan=strtod(rxs,NULL);
01637 ppbinout(chan);
01638 if(o->debuglevel)ast_log(LOG_NOTICE,"parse usbradio SETCHAN cmd: %s chan: %i\n",text,chan);
01639 return 0;
01640 }
01641
01642 if (cnt < 6)
01643 {
01644 ast_log(LOG_ERROR,"Cannot parse usbradio text: %s\n",text);
01645 return 0;
01646 }
01647 else
01648 {
01649 if(o->debuglevel)ast_verbose(" << %s %s %s %s %s %c >> \n", cmd,rxs,txs,rxpl,txpl,pwr);
01650 }
01651
01652 if (strcmp(cmd,"SETFREQ")==0)
01653 {
01654 if(o->debuglevel)ast_log(LOG_NOTICE,"parse usbradio SETFREQ cmd: %s\n",text);
01655 tx=strtod(txs,NULL);
01656 rx=strtod(rxs,NULL);
01657 o->set_txfreq = round(tx * (double)1000000);
01658 o->set_rxfreq = round(rx * (double)1000000);
01659 o->pmrChan->txpower = (pwr == 'H');
01660 strcpy(o->set_rxctcssfreqs,rxpl);
01661 strcpy(o->set_txctcssfreqs,txpl);
01662
01663 o->b.remoted=1;
01664 xpmr_config(o);
01665 return 0;
01666 }
01667 ast_log(LOG_ERROR,"Cannot parse usbradio cmd: %s\n",text);
01668 return 0;
01669 }
01670
01671
01672 static void ring(struct chan_usbradio_pvt *o, int x)
01673 {
01674 #ifndef NEW_ASTERISK
01675 write(o->sndcmd[1], &x, sizeof(x));
01676 #endif
01677 }
01678
01679
01680
01681
01682 static int usbradio_call(struct ast_channel *c, char *dest, int timeout)
01683 {
01684 struct chan_usbradio_pvt *o = c->tech_pvt;
01685
01686 o->stophid = 0;
01687 time(&o->lasthidtime);
01688 ast_pthread_create_background(&o->hidthread, NULL, hidthread, o);
01689 ast_setstate(c, AST_STATE_UP);
01690 return 0;
01691 }
01692
01693
01694
01695
01696 static int usbradio_answer(struct ast_channel *c)
01697 {
01698 #ifndef NEW_ASTERISK
01699 struct chan_usbradio_pvt *o = c->tech_pvt;
01700 #endif
01701
01702 ast_setstate(c, AST_STATE_UP);
01703 #ifndef NEW_ASTERISK
01704 o->cursound = -1;
01705 o->nosound = 0;
01706 #endif
01707 return 0;
01708 }
01709
01710 static int usbradio_hangup(struct ast_channel *c)
01711 {
01712 struct chan_usbradio_pvt *o = c->tech_pvt;
01713
01714
01715 #ifndef NEW_ASTERISK
01716 o->cursound = -1;
01717 o->nosound = 0;
01718 #endif
01719 c->tech_pvt = NULL;
01720 o->owner = NULL;
01721 ast_module_unref(ast_module_info->self);
01722 if (o->hookstate) {
01723 if (o->autoanswer || o->autohangup) {
01724
01725 o->hookstate = 0;
01726 setformat(o, O_CLOSE);
01727 } else {
01728
01729 ring(o, AST_CONTROL_CONGESTION);
01730 }
01731 }
01732 o->stophid = 1;
01733 pthread_join(o->hidthread,NULL);
01734 return 0;
01735 }
01736
01737
01738
01739 static int usbradio_write(struct ast_channel *c, struct ast_frame *f)
01740 {
01741 struct chan_usbradio_pvt *o = c->tech_pvt;
01742
01743 traceusb2(("usbradio_write() o->nosound= %i\n",o->nosound));
01744
01745 #ifndef NEW_ASTERISK
01746
01747 if (o->nosound)
01748 return 0;
01749
01750 o->cursound = -1;
01751 #endif
01752
01753
01754
01755
01756
01757
01758
01759 #if DEBUG_CAPTURES == 1 // to write input data to a file datalen=320
01760 if (ftxcapraw && o->b.txcapraw)
01761 {
01762 i16 i, tbuff[f->datalen];
01763 for(i=0;i<f->datalen;i+=2)
01764 {
01765 tbuff[i]= ((i16*)(f->data.ptr))[i/2];
01766 tbuff[i+1]= o->txkeyed*M_Q13;
01767 }
01768 if (fwrite(tbuff,2,f->datalen,ftxcapraw) != f->datalen) {
01769 ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
01770 }
01771
01772 }
01773 #endif
01774
01775
01776
01777 PmrTx(o->pmrChan,(i16*)f->data.ptr);
01778
01779 return 0;
01780 }
01781
01782 static struct ast_frame *usbradio_read(struct ast_channel *c)
01783 {
01784 int res, src, datalen, oldpttout;
01785 int cd,sd;
01786 struct chan_usbradio_pvt *o = c->tech_pvt;
01787 struct ast_frame *f = &o->read_f,*f1;
01788 struct ast_frame wf = { AST_FRAME_CONTROL };
01789 time_t now;
01790
01791 traceusb2(("usbradio_read()\n"));
01792
01793 if (o->lasthidtime)
01794 {
01795 time(&now);
01796 if ((now - o->lasthidtime) > 3)
01797 {
01798 ast_log(LOG_ERROR,"HID process has died or something!!\n");
01799 return NULL;
01800 }
01801 }
01802
01803
01804 memset(f, '\0', sizeof(struct ast_frame));
01805 f->frametype = AST_FRAME_NULL;
01806 f->src = usbradio_tech.type;
01807
01808 res = read(o->sounddev, o->usbradio_read_buf + o->readpos,
01809 sizeof(o->usbradio_read_buf) - o->readpos);
01810 if (res < 0)
01811 {
01812 if (errno != EAGAIN) return NULL;
01813 if (o->readerrs++ > READERR_THRESHOLD)
01814 {
01815 ast_log(LOG_ERROR,"Stuck USB read channel [%s], un-sticking it!\n",o->name);
01816 o->readerrs = 0;
01817 return NULL;
01818 }
01819 if (o->readerrs == 1)
01820 ast_log(LOG_WARNING,"Possibly stuck USB read channel. [%s]\n",o->name);
01821 return f;
01822 }
01823 if (o->readerrs) ast_log(LOG_WARNING,"Nope, USB read channel [%s] wasn't stuck after all.\n",o->name);
01824 o->readerrs = 0;
01825 o->readpos += res;
01826 if (o->readpos < sizeof(o->usbradio_read_buf))
01827 return f;
01828
01829 if (o->mute)
01830 return f;
01831
01832 #if DEBUG_CAPTURES == 1
01833 if ((o->b.rxcapraw && frxcapraw) && (fwrite((o->usbradio_read_buf + AST_FRIENDLY_OFFSET),1,FRAME_SIZE * 2 * 2 * 6,frxcapraw) != FRAME_SIZE * 2 * 2 * 6)) {
01834 ast_log(LOG_ERROR, "fwrite() failed: %s\n", strerror(errno));
01835 }
01836 #endif
01837
01838 #if 1
01839 if(o->txkeyed||o->txtestkey)
01840 {
01841 if(!o->pmrChan->txPttIn)
01842 {
01843 o->pmrChan->txPttIn=1;
01844 if(o->debuglevel) ast_log(LOG_NOTICE,"txPttIn = %i, chan %s\n",o->pmrChan->txPttIn,o->owner->name);
01845 }
01846 }
01847 else if(o->pmrChan->txPttIn)
01848 {
01849 o->pmrChan->txPttIn=0;
01850 if(o->debuglevel) ast_log(LOG_NOTICE,"txPttIn = %i, chan %s\n",o->pmrChan->txPttIn,o->owner->name);
01851 }
01852 oldpttout = o->pmrChan->txPttOut;
01853
01854 PmrRx( o->pmrChan,
01855 (i16 *)(o->usbradio_read_buf + AST_FRIENDLY_OFFSET),
01856 (i16 *)(o->usbradio_read_buf_8k + AST_FRIENDLY_OFFSET),
01857 (i16 *)(o->usbradio_write_buf_1));
01858
01859 if (oldpttout != o->pmrChan->txPttOut)
01860 {
01861 if(o->debuglevel) ast_log(LOG_NOTICE,"txPttOut = %i, chan %s\n",o->pmrChan->txPttOut,o->owner->name);
01862 kickptt(o);
01863 }
01864
01865 #if 0 // to write 48KS/s stereo tx data to a file
01866 if (!ftxoutraw) ftxoutraw = fopen(TX_CAP_OUT_FILE,"w");
01867 if (ftxoutraw) fwrite(o->usbradio_write_buf_1,1,FRAME_SIZE * 2 * 6,ftxoutraw);
01868 #endif
01869
01870 #if DEBUG_CAPTURES == 1 && XPMR_DEBUG0 == 1
01871 if ((o->b.txcap2 && ftxcaptrace) && (fwrite((o->pmrChan->ptxDebug),1,FRAME_SIZE * 2 * 16,ftxcaptrace) != FRAME_SIZE * 2 * 16)) {
01872 ast_log(LOG_ERROR, "fwrite() failed: %s\n", strerror(errno));
01873 }
01874 #endif
01875
01876
01877 datalen = FRAME_SIZE * 24;
01878 src = 0;
01879 while (src < datalen)
01880 {
01881
01882 int l = sizeof(o->usbradio_write_buf) - o->usbradio_write_dst;
01883
01884 if (datalen - src >= l)
01885 {
01886
01887 memcpy(o->usbradio_write_buf + o->usbradio_write_dst, o->usbradio_write_buf_1 + src, l);
01888 soundcard_writeframe(o, (short *) o->usbradio_write_buf);
01889 src += l;
01890 o->usbradio_write_dst = 0;
01891 }
01892 else
01893 {
01894
01895 l = datalen - src;
01896 memcpy(o->usbradio_write_buf + o->usbradio_write_dst, o->usbradio_write_buf_1 + src, l);
01897 src += l;
01898 o->usbradio_write_dst += l;
01899 }
01900 }
01901 #else
01902 static FILE *hInput;
01903 i16 iBuff[FRAME_SIZE*2*6];
01904
01905 o->pmrChan->b.rxCapture=1;
01906
01907 if(!hInput)
01908 {
01909 hInput = fopen("/usr/src/xpmr/testdata/rx_in.pcm","r");
01910 if(!hInput)
01911 {
01912 printf(" Input Data File Not Found.\n");
01913 return 0;
01914 }
01915 }
01916
01917 if(0==fread((void *)iBuff,2,FRAME_SIZE*2*6,hInput))exit;
01918
01919 PmrRx( o->pmrChan,
01920 (i16 *)iBuff,
01921 (i16 *)(o->usbradio_read_buf_8k + AST_FRIENDLY_OFFSET));
01922
01923 #endif
01924
01925 #if 0
01926 if (!frxoutraw) frxoutraw = fopen(RX_CAP_OUT_FILE,"w");
01927 if (frxoutraw) fwrite((o->usbradio_read_buf_8k + AST_FRIENDLY_OFFSET),1,FRAME_SIZE * 2,frxoutraw);
01928 #endif
01929
01930 #if DEBUG_CAPTURES == 1 && XPMR_DEBUG0 == 1
01931 if ((frxcaptrace && o->b.rxcap2 && o->pmrChan->b.radioactive) && (fwrite((o->pmrChan->prxDebug),1,FRAME_SIZE * 2 * 16,frxcaptrace) != FRAME_SIZE * 2 * 16 )) {
01932 ast_log(LOG_ERROR, "fwrite() failed: %s\n", strerror(errno));
01933 }
01934 #endif
01935
01936 cd = 0;
01937 if(o->rxcdtype==CD_HID && (o->pmrChan->rxExtCarrierDetect!=o->rxhidsq))
01938 o->pmrChan->rxExtCarrierDetect=o->rxhidsq;
01939
01940 if(o->rxcdtype==CD_HID_INVERT && (o->pmrChan->rxExtCarrierDetect==o->rxhidsq))
01941 o->pmrChan->rxExtCarrierDetect=!o->rxhidsq;
01942
01943 if( (o->rxcdtype==CD_HID && o->rxhidsq) ||
01944 (o->rxcdtype==CD_HID_INVERT && !o->rxhidsq) ||
01945 (o->rxcdtype==CD_XPMR_NOISE && o->pmrChan->rxCarrierDetect) ||
01946 (o->rxcdtype==CD_XPMR_VOX && o->pmrChan->rxCarrierDetect)
01947 )
01948 {
01949 if (!o->pmrChan->txPttOut || o->radioduplex)cd=1;
01950 }
01951 else
01952 {
01953 cd=0;
01954 }
01955
01956 if(cd!=o->rxcarrierdetect)
01957 {
01958 o->rxcarrierdetect=cd;
01959 if(o->debuglevel) ast_log(LOG_NOTICE,"rxcarrierdetect = %i, chan %s\n",cd,o->owner->name);
01960
01961 }
01962
01963 if(o->pmrChan->b.ctcssRxEnable && o->pmrChan->rxCtcss->decode!=o->rxctcssdecode)
01964 {
01965 if(o->debuglevel)ast_log(LOG_NOTICE,"rxctcssdecode = %i, chan %s\n",o->pmrChan->rxCtcss->decode,o->owner->name);
01966
01967 o->rxctcssdecode=o->pmrChan->rxCtcss->decode;
01968 strcpy(o->rxctcssfreq, o->pmrChan->rxctcssfreq);
01969 }
01970
01971 #ifndef HAVE_XPMRX
01972 if( !o->pmrChan->b.ctcssRxEnable ||
01973 ( o->pmrChan->b.ctcssRxEnable &&
01974 o->pmrChan->rxCtcss->decode>CTCSS_NULL &&
01975 o->pmrChan->smode==SMODE_CTCSS )
01976 )
01977 {
01978 sd=1;
01979 }
01980 else
01981 {
01982 sd=0;
01983 }
01984 #else
01985 if( (!o->pmrChan->b.ctcssRxEnable && !o->pmrChan->b.dcsRxEnable && !o->pmrChan->b.lmrRxEnable) ||
01986 ( o->pmrChan->b.ctcssRxEnable &&
01987 o->pmrChan->rxCtcss->decode>CTCSS_NULL &&
01988 o->pmrChan->smode==SMODE_CTCSS ) ||
01989 ( o->pmrChan->b.dcsRxEnable &&
01990 o->pmrChan->decDcs->decode > 0 &&
01991 o->pmrChan->smode==SMODE_DCS )
01992 )
01993 {
01994 sd=1;
01995 }
01996 else
01997 {
01998 sd=0;
01999 }
02000
02001 if(o->pmrChan->decDcs->decode!=o->rxdcsdecode)
02002 {
02003 if(o->debuglevel)ast_log(LOG_NOTICE,"rxdcsdecode = %s, chan %s\n",o->pmrChan->rxctcssfreq,o->owner->name);
02004
02005 o->rxdcsdecode=o->pmrChan->decDcs->decode;
02006 strcpy(o->rxctcssfreq, o->pmrChan->rxctcssfreq);
02007 }
02008
02009 if(o->pmrChan->rptnum && (o->pmrChan->pLsdCtl->cs[o->pmrChan->rptnum].b.rxkeyed != o->rxlsddecode))
02010 {
02011 if(o->debuglevel)ast_log(LOG_NOTICE,"rxLSDecode = %s, chan %s\n",o->pmrChan->rxctcssfreq,o->owner->name);
02012 o->rxlsddecode=o->pmrChan->pLsdCtl->cs[o->pmrChan->rptnum].b.rxkeyed;
02013 strcpy(o->rxctcssfreq, o->pmrChan->rxctcssfreq);
02014 }
02015
02016 if( (o->pmrChan->rptnum>0 && o->pmrChan->smode==SMODE_LSD && o->pmrChan->pLsdCtl->cs[o->pmrChan->rptnum].b.rxkeyed)||
02017 (o->pmrChan->smode==SMODE_DCS && o->pmrChan->decDcs->decode>0) )
02018 {
02019 sd=1;
02020 }
02021 #endif
02022
02023 if ( cd && sd )
02024 {
02025
02026 if(!o->rxkeyed && o->debuglevel)ast_log(LOG_NOTICE,"o->rxkeyed = 1, chan %s\n", o->owner->name);
02027 o->rxkeyed = 1;
02028 }
02029 else
02030 {
02031
02032 if(o->rxkeyed && o->debuglevel)ast_log(LOG_NOTICE,"o->rxkeyed = 0, chan %s\n",o->owner->name);
02033 o->rxkeyed = 0;
02034 }
02035
02036
02037 if (o->lastrx && (!o->rxkeyed))
02038 {
02039 o->lastrx = 0;
02040
02041 wf.subclass.integer = AST_CONTROL_RADIO_UNKEY;
02042 ast_queue_frame(o->owner, &wf);
02043 }
02044 else if ((!o->lastrx) && (o->rxkeyed))
02045 {
02046 o->lastrx = 1;
02047
02048 wf.subclass.integer = AST_CONTROL_RADIO_KEY;
02049 if(o->rxctcssdecode)
02050 {
02051 wf.data.ptr = o->rxctcssfreq;
02052 wf.datalen = strlen(o->rxctcssfreq) + 1;
02053 TRACEO(1,("AST_CONTROL_RADIO_KEY text=%s\n",o->rxctcssfreq));
02054 }
02055 ast_queue_frame(o->owner, &wf);
02056 }
02057
02058 o->readpos = AST_FRIENDLY_OFFSET;
02059 if (c->_state != AST_STATE_UP)
02060 return f;
02061
02062 f->frametype = AST_FRAME_VOICE;
02063 f->subclass.codec = AST_FORMAT_SLINEAR;
02064 f->samples = FRAME_SIZE;
02065 f->datalen = FRAME_SIZE * 2;
02066 f->data.ptr = o->usbradio_read_buf_8k + AST_FRIENDLY_OFFSET;
02067 if (o->boost != BOOST_SCALE) {
02068 int i, x;
02069 int16_t *p = (int16_t *) f->data.ptr;
02070 for (i = 0; i < f->samples; i++) {
02071 x = (p[i] * o->boost) / BOOST_SCALE;
02072 if (x > 32767)
02073 x = 32767;
02074 else if (x < -32768)
02075 x = -32768;
02076 p[i] = x;
02077 }
02078 }
02079
02080 f->offset = AST_FRIENDLY_OFFSET;
02081 if (o->dsp)
02082 {
02083 f1 = ast_dsp_process(c,o->dsp,f);
02084 if ((f1->frametype == AST_FRAME_DTMF_END) ||
02085 (f1->frametype == AST_FRAME_DTMF_BEGIN))
02086 {
02087 if ((f1->subclass.integer == 'm') || (f1->subclass.integer == 'u'))
02088 {
02089 f1->frametype = AST_FRAME_NULL;
02090 f1->subclass.integer = 0;
02091 return(f1);
02092 }
02093 if (f1->frametype == AST_FRAME_DTMF_END)
02094 ast_log(LOG_NOTICE, "Got DTMF char %c\n", f1->subclass.integer);
02095 return(f1);
02096 }
02097 }
02098 return f;
02099 }
02100
02101 static int usbradio_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
02102 {
02103 struct chan_usbradio_pvt *o = newchan->tech_pvt;
02104 ast_log(LOG_WARNING,"usbradio_fixup()\n");
02105 o->owner = newchan;
02106 return 0;
02107 }
02108
02109 static int usbradio_indicate(struct ast_channel *c, int cond, const void *data, size_t datalen)
02110 {
02111 struct chan_usbradio_pvt *o = c->tech_pvt;
02112 int res = -1;
02113
02114 switch (cond) {
02115 case AST_CONTROL_BUSY:
02116 case AST_CONTROL_CONGESTION:
02117 case AST_CONTROL_RINGING:
02118 res = cond;
02119 break;
02120
02121 case -1:
02122 #ifndef NEW_ASTERISK
02123 o->cursound = -1;
02124 o->nosound = 0;
02125 #endif
02126 return 0;
02127
02128 case AST_CONTROL_VIDUPDATE:
02129 res = -1;
02130 break;
02131 case AST_CONTROL_HOLD:
02132 ast_verbose(" << Console Has Been Placed on Hold >> \n");
02133 ast_moh_start(c, data, o->mohinterpret);
02134 break;
02135 case AST_CONTROL_UNHOLD:
02136 ast_verbose(" << Console Has Been Retrieved from Hold >> \n");
02137 ast_moh_stop(c);
02138 break;
02139 case AST_CONTROL_PROCEEDING:
02140 ast_verbose(" << Call Proceeding... >> \n");
02141 ast_moh_stop(c);
02142 break;
02143 case AST_CONTROL_PROGRESS:
02144 ast_verbose(" << Call Progress... >> \n");
02145 ast_moh_stop(c);
02146 break;
02147 case AST_CONTROL_RADIO_KEY:
02148 o->txkeyed = 1;
02149 if(o->debuglevel)ast_verbose(" << AST_CONTROL_RADIO_KEY Radio Transmit On. >> \n");
02150 break;
02151 case AST_CONTROL_RADIO_UNKEY:
02152 o->txkeyed = 0;
02153 if(o->debuglevel)ast_verbose(" << AST_CONTROL_RADIO_UNKEY Radio Transmit Off. >> \n");
02154 break;
02155 default:
02156 ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", cond, c->name);
02157 return -1;
02158 }
02159
02160 if (res > -1)
02161 ring(o, res);
02162
02163 return 0;
02164 }
02165
02166
02167
02168
02169 static struct ast_channel *usbradio_new(struct chan_usbradio_pvt *o, char *ext, char *ctx, int state, const char *linkedid)
02170 {
02171 struct ast_channel *c;
02172
02173 c = ast_channel_alloc(1, state, o->cid_num, o->cid_name, "", ext, ctx, linkedid, 0, "Radio/%s", o->name);
02174 if (c == NULL)
02175 return NULL;
02176 c->tech = &usbradio_tech;
02177 if (o->sounddev < 0)
02178 setformat(o, O_RDWR);
02179 c->fds[0] = o->sounddev;
02180 c->nativeformats = AST_FORMAT_SLINEAR;
02181 c->readformat = AST_FORMAT_SLINEAR;
02182 c->writeformat = AST_FORMAT_SLINEAR;
02183 c->tech_pvt = o;
02184
02185 if (!ast_strlen_zero(o->language))
02186 ast_string_field_set(c, language, o->language);
02187
02188
02189 if (!ast_strlen_zero(o->cid_num)) {
02190 c->caller.ani.number.valid = 1;
02191 c->caller.ani.number.str = ast_strdup(o->cid_num);
02192 }
02193 if (!ast_strlen_zero(ext)) {
02194 c->dialed.number.str = ast_strdup(ext);
02195 }
02196
02197 o->owner = c;
02198 ast_module_ref(ast_module_info->self);
02199 ast_jb_configure(c, &global_jbconf);
02200 if (state != AST_STATE_DOWN) {
02201 if (ast_pbx_start(c)) {
02202 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", c->name);
02203 ast_hangup(c);
02204 o->owner = c = NULL;
02205
02206
02207 }
02208 }
02209
02210 return c;
02211 }
02212
02213
02214 static struct ast_channel *usbradio_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause)
02215 {
02216 struct ast_channel *c;
02217 struct chan_usbradio_pvt *o = find_desc(data);
02218
02219 TRACEO(1,("usbradio_request()\n"));
02220
02221 if (0)
02222 {
02223 ast_log(LOG_WARNING, "usbradio_request type <%s> data 0x%p <%s>\n", type, data, (char *) data);
02224 }
02225 if (o == NULL) {
02226 ast_log(LOG_NOTICE, "Device %s not found\n", (char *) data);
02227
02228 return NULL;
02229 }
02230 if ((format & AST_FORMAT_SLINEAR) == 0) {
02231 ast_log(LOG_NOTICE, "Format 0x%" PRIx64 " unsupported\n", format);
02232 return NULL;
02233 }
02234 if (o->owner) {
02235 ast_log(LOG_NOTICE, "Already have a call (chan %p) on the usb channel\n", o->owner);
02236 *cause = AST_CAUSE_BUSY;
02237 return NULL;
02238 }
02239 c = usbradio_new(o, NULL, NULL, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL);
02240 if (c == NULL) {
02241 ast_log(LOG_WARNING, "Unable to create new usb channel\n");
02242 return NULL;
02243 }
02244
02245 o->b.remoted=0;
02246 xpmr_config(o);
02247
02248 return c;
02249 }
02250
02251
02252 static int console_key(int fd, int argc, char *argv[])
02253 {
02254 struct chan_usbradio_pvt *o = find_desc(usbradio_active);
02255
02256 if (argc != 2)
02257 return RESULT_SHOWUSAGE;
02258 o->txtestkey = 1;
02259 return RESULT_SUCCESS;
02260 }
02261
02262
02263 static int console_unkey(int fd, int argc, char *argv[])
02264 {
02265 struct chan_usbradio_pvt *o = find_desc(usbradio_active);
02266
02267 if (argc != 2)
02268 return RESULT_SHOWUSAGE;
02269 o->txtestkey = 0;
02270 return RESULT_SUCCESS;
02271 }
02272
02273 static int radio_tune(int fd, int argc, char *argv[])
02274 {
02275 struct chan_usbradio_pvt *o = find_desc(usbradio_active);
02276 int i=0;
02277
02278 if ((argc < 2) || (argc > 4))
02279 return RESULT_SHOWUSAGE;
02280
02281 if (argc == 2)
02282 {
02283 ast_cli(fd,"Active radio interface is [%s]\n",usbradio_active);
02284 ast_cli(fd,"Output A is currently set to ");
02285 if(o->txmixa==TX_OUT_COMPOSITE)ast_cli(fd,"composite.\n");
02286 else if (o->txmixa==TX_OUT_VOICE)ast_cli(fd,"voice.\n");
02287 else if (o->txmixa==TX_OUT_LSD)ast_cli(fd,"tone.\n");
02288 else if (o->txmixa==TX_OUT_AUX)ast_cli(fd,"auxvoice.\n");
02289 else ast_cli(fd,"off.\n");
02290
02291 ast_cli(fd,"Output B is currently set to ");
02292 if(o->txmixb==TX_OUT_COMPOSITE)ast_cli(fd,"composite.\n");
02293 else if (o->txmixb==TX_OUT_VOICE)ast_cli(fd,"voice.\n");
02294 else if (o->txmixb==TX_OUT_LSD)ast_cli(fd,"tone.\n");
02295 else if (o->txmixb==TX_OUT_AUX)ast_cli(fd,"auxvoice.\n");
02296 else ast_cli(fd,"off.\n");
02297
02298 ast_cli(fd,"Tx Voice Level currently set to %d\n",o->txmixaset);
02299 ast_cli(fd,"Tx Tone Level currently set to %d\n",o->txctcssadj);
02300 ast_cli(fd,"Rx Squelch currently set to %d\n",o->rxsquelchadj);
02301 ast_cli(fd,"Device String is %s\n",o->devstr);
02302 return RESULT_SHOWUSAGE;
02303 }
02304
02305 o->pmrChan->b.tuning=1;
02306
02307 if (!strcasecmp(argv[2],"rxnoise")) tune_rxinput(fd,o);
02308 else if (!strcasecmp(argv[2],"rxvoice")) tune_rxvoice(fd,o);
02309 else if (!strcasecmp(argv[2],"rxtone")) tune_rxctcss(fd,o);
02310 else if (!strcasecmp(argv[2],"rxsquelch"))
02311 {
02312 if (argc == 3)
02313 {
02314 ast_cli(fd,"Current Signal Strength is %d\n",((32767-o->pmrChan->rxRssi)*1000/32767));
02315 ast_cli(fd,"Current Squelch setting is %d\n",o->rxsquelchadj);
02316
02317
02318 } else {
02319 i = atoi(argv[3]);
02320 if ((i < 0) || (i > 999)) return RESULT_SHOWUSAGE;
02321 ast_cli(fd,"Changed Squelch setting to %d\n",i);
02322 o->rxsquelchadj = i;
02323 *(o->pmrChan->prxSquelchAdjust)= ((999 - i) * 32767) / 1000;
02324 }
02325 }
02326 else if (!strcasecmp(argv[2],"txvoice")) {
02327 i = 0;
02328
02329 if( (o->txmixa!=TX_OUT_VOICE) && (o->txmixb!=TX_OUT_VOICE) &&
02330 (o->txmixa!=TX_OUT_COMPOSITE) && (o->txmixb!=TX_OUT_COMPOSITE)
02331 )
02332 {
02333 ast_log(LOG_ERROR,"No txvoice output configured.\n");
02334 }
02335 else if (argc == 3)
02336 {
02337 if((o->txmixa==TX_OUT_VOICE)||(o->txmixa==TX_OUT_COMPOSITE))
02338 ast_cli(fd,"Current txvoice setting on Channel A is %d\n",o->txmixaset);
02339 else
02340 ast_cli(fd,"Current txvoice setting on Channel B is %d\n",o->txmixbset);
02341 }
02342 else
02343 {
02344 i = atoi(argv[3]);
02345 if ((i < 0) || (i > 999)) return RESULT_SHOWUSAGE;
02346
02347 if((o->txmixa==TX_OUT_VOICE)||(o->txmixa==TX_OUT_COMPOSITE))
02348 {
02349 o->txmixaset=i;
02350 ast_cli(fd,"Changed txvoice setting on Channel A to %d\n",o->txmixaset);
02351 }
02352 else
02353 {
02354 o->txmixbset=i;
02355 ast_cli(fd,"Changed txvoice setting on Channel B to %d\n",o->txmixbset);
02356 }
02357 mixer_write(o);
02358 mult_set(o);
02359 ast_cli(fd,"Changed Tx Voice Output setting to %d\n",i);
02360 }
02361 o->pmrChan->b.txCtcssInhibit=1;
02362 tune_txoutput(o,i,fd);
02363 o->pmrChan->b.txCtcssInhibit=0;
02364 }
02365 else if (!strcasecmp(argv[2],"txall")) {
02366 i = 0;
02367
02368 if( (o->txmixa!=TX_OUT_VOICE) && (o->txmixb!=TX_OUT_VOICE) &&
02369 (o->txmixa!=TX_OUT_COMPOSITE) && (o->txmixb!=TX_OUT_COMPOSITE)
02370 )
02371 {
02372 ast_log(LOG_ERROR,"No txvoice output configured.\n");
02373 }
02374 else if (argc == 3)
02375 {
02376 if((o->txmixa==TX_OUT_VOICE)||(o->txmixa==TX_OUT_COMPOSITE))
02377 ast_cli(fd,"Current txvoice setting on Channel A is %d\n",o->txmixaset);
02378 else
02379 ast_cli(fd,"Current txvoice setting on Channel B is %d\n",o->txmixbset);
02380 }
02381 else
02382 {
02383 i = atoi(argv[3]);
02384 if ((i < 0) || (i > 999)) return RESULT_SHOWUSAGE;
02385
02386 if((o->txmixa==TX_OUT_VOICE)||(o->txmixa==TX_OUT_COMPOSITE))
02387 {
02388 o->txmixaset=i;
02389 ast_cli(fd,"Changed txvoice setting on Channel A to %d\n",o->txmixaset);
02390 }
02391 else
02392 {
02393 o->txmixbset=i;
02394 ast_cli(fd,"Changed txvoice setting on Channel B to %d\n",o->txmixbset);
02395 }
02396 mixer_write(o);
02397 mult_set(o);
02398 ast_cli(fd,"Changed Tx Voice Output setting to %d\n",i);
02399 }
02400 tune_txoutput(o,i,fd);
02401 }
02402 else if (!strcasecmp(argv[2],"auxvoice")) {
02403 i = 0;
02404 if( (o->txmixa!=TX_OUT_AUX) && (o->txmixb!=TX_OUT_AUX))
02405 {
02406 ast_log(LOG_WARNING,"No auxvoice output configured.\n");
02407 }
02408 else if (argc == 3)
02409 {
02410 if(o->txmixa==TX_OUT_AUX)
02411 ast_cli(fd,"Current auxvoice setting on Channel A is %d\n",o->txmixaset);
02412 else
02413 ast_cli(fd,"Current auxvoice setting on Channel B is %d\n",o->txmixbset);
02414 }
02415 else
02416 {
02417 i = atoi(argv[3]);
02418 if ((i < 0) || (i > 999)) return RESULT_SHOWUSAGE;
02419 if(o->txmixa==TX_OUT_AUX)
02420 {
02421 o->txmixbset=i;
02422 ast_cli(fd,"Changed auxvoice setting on Channel A to %d\n",o->txmixaset);
02423 }
02424 else
02425 {
02426 o->txmixbset=i;
02427 ast_cli(fd,"Changed auxvoice setting on Channel B to %d\n",o->txmixbset);
02428 }
02429 mixer_write(o);
02430 mult_set(o);
02431 }
02432
02433 }
02434 else if (!strcasecmp(argv[2],"txtone"))
02435 {
02436 if (argc == 3)
02437 ast_cli(fd,"Current Tx CTCSS modulation setting = %d\n",o->txctcssadj);
02438 else
02439 {
02440 i = atoi(argv[3]);
02441 if ((i < 0) || (i > 999)) return RESULT_SHOWUSAGE;
02442 o->txctcssadj = i;
02443 set_txctcss_level(o);
02444 ast_cli(fd,"Changed Tx CTCSS modulation setting to %i\n",i);
02445 }
02446 o->txtestkey=1;
02447 usleep(5000000);
02448 o->txtestkey=0;
02449 }
02450 else if (!strcasecmp(argv[2],"dump")) pmrdump(o);
02451 else if (!strcasecmp(argv[2],"nocap"))
02452 {
02453 ast_cli(fd,"File capture (trace) was rx=%d tx=%d and now off.\n",o->b.rxcap2,o->b.txcap2);
02454 ast_cli(fd,"File capture (raw) was rx=%d tx=%d and now off.\n",o->b.rxcapraw,o->b.txcapraw);
02455 o->b.rxcapraw=o->b.txcapraw=o->b.rxcap2=o->b.txcap2=o->pmrChan->b.rxCapture=o->pmrChan->b.txCapture=0;
02456 if (frxcapraw) { fclose(frxcapraw); frxcapraw = NULL; }
02457 if (frxcaptrace) { fclose(frxcaptrace); frxcaptrace = NULL; }
02458 if (frxoutraw) { fclose(frxoutraw); frxoutraw = NULL; }
02459 if (ftxcapraw) { fclose(ftxcapraw); ftxcapraw = NULL; }
02460 if (ftxcaptrace) { fclose(ftxcaptrace); ftxcaptrace = NULL; }
02461 if (ftxoutraw) { fclose(ftxoutraw); ftxoutraw = NULL; }
02462 }
02463 else if (!strcasecmp(argv[2],"rxtracecap"))
02464 {
02465 if (!frxcaptrace) frxcaptrace= fopen(RX_CAP_TRACE_FILE,"w");
02466 ast_cli(fd,"Trace rx on.\n");
02467 o->b.rxcap2=o->pmrChan->b.rxCapture=1;
02468 }
02469 else if (!strcasecmp(argv[2],"txtracecap"))
02470 {
02471 if (!ftxcaptrace) ftxcaptrace= fopen(TX_CAP_TRACE_FILE,"w");
02472 ast_cli(fd,"Trace tx on.\n");
02473 o->b.txcap2=o->pmrChan->b.txCapture=1;
02474 }
02475 else if (!strcasecmp(argv[2],"rxcap"))
02476 {
02477 if (!frxcapraw) frxcapraw = fopen(RX_CAP_RAW_FILE,"w");
02478 ast_cli(fd,"cap rx raw on.\n");
02479 o->b.rxcapraw=1;
02480 }
02481 else if (!strcasecmp(argv[2],"txcap"))
02482 {
02483 if (!ftxcapraw) ftxcapraw = fopen(TX_CAP_RAW_FILE,"w");
02484 ast_cli(fd,"cap tx raw on.\n");
02485 o->b.txcapraw=1;
02486 }
02487 else if (!strcasecmp(argv[2],"save"))
02488 {
02489 tune_write(o);
02490 ast_cli(fd,"Saved radio tuning settings to usbradio_tune_%s.conf\n",o->name);
02491 }
02492 else if (!strcasecmp(argv[2],"load"))
02493 {
02494 ast_mutex_lock(&o->eepromlock);
02495 while(o->eepromctl)
02496 {
02497 ast_mutex_unlock(&o->eepromlock);
02498 usleep(10000);
02499 ast_mutex_lock(&o->eepromlock);
02500 }
02501 o->eepromctl = 1;
02502 ast_mutex_unlock(&o->eepromlock);
02503
02504 ast_cli(fd,"Requesting loading of tuning settings from EEPROM for channel %s\n",o->name);
02505 }
02506 else
02507 {
02508 o->pmrChan->b.tuning=0;
02509 return RESULT_SHOWUSAGE;
02510 }
02511 o->pmrChan->b.tuning=0;
02512 return RESULT_SUCCESS;
02513 }
02514
02515
02516
02517
02518
02519
02520 static int set_txctcss_level(struct chan_usbradio_pvt *o)
02521 {
02522 if (o->txmixa == TX_OUT_LSD)
02523 {
02524
02525 o->txmixaset=o->txctcssadj;
02526 mixer_write(o);
02527 mult_set(o);
02528 }
02529 else if (o->txmixb == TX_OUT_LSD)
02530 {
02531
02532 o->txmixbset=o->txctcssadj;
02533 mixer_write(o);
02534 mult_set(o);
02535 }
02536 else
02537 {
02538 *o->pmrChan->ptxCtcssAdjust=(o->txctcssadj * M_Q8) / 1000;
02539 }
02540 return 0;
02541 }
02542
02543
02544
02545 static int radio_set_debug(int fd, int argc, char *argv[])
02546 {
02547 struct chan_usbradio_pvt *o = find_desc(usbradio_active);
02548
02549 o->debuglevel=1;
02550 ast_cli(fd,"usbradio debug on.\n");
02551 return RESULT_SUCCESS;
02552 }
02553
02554 static int radio_set_debug_off(int fd, int argc, char *argv[])
02555 {
02556 struct chan_usbradio_pvt *o = find_desc(usbradio_active);
02557
02558 o->debuglevel=0;
02559 ast_cli(fd,"usbradio debug off.\n");
02560 return RESULT_SUCCESS;
02561 }
02562
02563 static int radio_active(int fd, int argc, char *argv[])
02564 {
02565 if (argc == 2)
02566 ast_cli(fd, "active (command) USB Radio device is [%s]\n", usbradio_active);
02567 else if (argc != 3)
02568 return RESULT_SHOWUSAGE;
02569 else {
02570 struct chan_usbradio_pvt *o;
02571 if (strcmp(argv[2], "show") == 0) {
02572 for (o = usbradio_default.next; o; o = o->next)
02573 ast_cli(fd, "device [%s] exists\n", o->name);
02574 return RESULT_SUCCESS;
02575 }
02576 o = find_desc(argv[2]);
02577 if (o == NULL)
02578 ast_cli(fd, "No device [%s] exists\n", argv[2]);
02579 else
02580 {
02581 struct chan_usbradio_pvt *ao;
02582 for (ao = usbradio_default.next; ao && ao->name ; ao = ao->next)ao->pmrChan->b.radioactive=0;
02583 usbradio_active = o->name;
02584 o->pmrChan->b.radioactive=1;
02585 }
02586 }
02587 return RESULT_SUCCESS;
02588 }
02589
02590
02591
02592 static int radio_set_xpmr_debug(int fd, int argc, char *argv[])
02593 {
02594 struct chan_usbradio_pvt *o = find_desc(usbradio_active);
02595
02596 if (argc == 4)
02597 {
02598 int i;
02599 i = atoi(argv[3]);
02600 if ((i >= 0) && (i <= 100))
02601 {
02602 o->pmrChan->tracelevel=i;
02603 }
02604 }
02605
02606 ast_cli(fd,"usbradio xdebug on tracelevel %i\n",o->pmrChan->tracelevel);
02607
02608 return RESULT_SUCCESS;
02609 }
02610
02611
02612 static char key_usage[] =
02613 "Usage: radio key\n"
02614 " Simulates COR active.\n";
02615
02616 static char unkey_usage[] =
02617 "Usage: radio unkey\n"
02618 " Simulates COR un-active.\n";
02619
02620 static char active_usage[] =
02621 "Usage: radio active [device-name]\n"
02622 " If used without a parameter, displays which device is the current\n"
02623 "one being commanded. If a device is specified, the commanded radio device is changed\n"
02624 "to the device specified.\n";
02625
02626
02627
02628 static char radio_tune_usage[] =
02629 "Usage: radio tune <function>\n"
02630 " rxnoise\n"
02631 " rxvoice\n"
02632 " rxtone\n"
02633 " rxsquelch [newsetting]\n"
02634 " txvoice [newsetting]\n"
02635 " txtone [newsetting]\n"
02636 " auxvoice [newsetting]\n"
02637 " save (settings to tuning file)\n"
02638 " load (tuning settings from EEPROM)\n"
02639 "\n All [newsetting]'s are values 0-999\n\n";
02640
02641 #ifndef NEW_ASTERISK
02642
02643 static struct ast_cli_entry cli_usbradio[] = {
02644 { { "radio", "key", NULL },
02645 console_key, "Simulate Rx Signal Present",
02646 key_usage, NULL, NULL},
02647
02648 { { "radio", "unkey", NULL },
02649 console_unkey, "Simulate Rx Signal Lusb",
02650 unkey_usage, NULL, NULL },
02651
02652 { { "radio", "tune", NULL },
02653 radio_tune, "Radio Tune",
02654 radio_tune_usage, NULL, NULL },
02655
02656 { { "radio", "set", "debug", NULL },
02657 radio_set_debug, "Radio Debug",
02658 radio_tune_usage, NULL, NULL },
02659
02660 { { "radio", "set", "debug", "off", NULL },
02661 radio_set_debug_off, "Radio Debug",
02662 radio_tune_usage, NULL, NULL },
02663
02664 { { "radio", "active", NULL },
02665 radio_active, "Change commanded device",
02666 active_usage, NULL, NULL },
02667
02668 { { "radio", "set", "xdebug", NULL },
02669 radio_set_xpmr_debug, "Radio set xpmr debug level",
02670 active_usage, NULL, NULL },
02671
02672 };
02673 #endif
02674
02675
02676
02677
02678 #if 0
02679 static void store_callerid(struct chan_usbradio_pvt *o, char *s)
02680 {
02681 ast_callerid_split(s, o->cid_name, sizeof(o->cid_name), o->cid_num, sizeof(o->cid_num));
02682 }
02683 #endif
02684
02685 static void store_rxdemod(struct chan_usbradio_pvt *o, const char *s)
02686 {
02687 if (!strcasecmp(s,"no")){
02688 o->rxdemod = RX_AUDIO_NONE;
02689 }
02690 else if (!strcasecmp(s,"speaker")){
02691 o->rxdemod = RX_AUDIO_SPEAKER;
02692 }
02693 else if (!strcasecmp(s,"flat")){
02694 o->rxdemod = RX_AUDIO_FLAT;
02695 }
02696 else {
02697 ast_log(LOG_WARNING,"Unrecognized rxdemod parameter: %s\n",s);
02698 }
02699
02700
02701 }
02702
02703
02704 static void store_txmixa(struct chan_usbradio_pvt *o, const char *s)
02705 {
02706 if (!strcasecmp(s,"no")){
02707 o->txmixa = TX_OUT_OFF;
02708 }
02709 else if (!strcasecmp(s,"voice")){
02710 o->txmixa = TX_OUT_VOICE;
02711 }
02712 else if (!strcasecmp(s,"tone")){
02713 o->txmixa = TX_OUT_LSD;
02714 }
02715 else if (!strcasecmp(s,"composite")){
02716 o->txmixa = TX_OUT_COMPOSITE;
02717 }
02718 else if (!strcasecmp(s,"auxvoice")){
02719 o->txmixa = TX_OUT_AUX;
02720 }
02721 else {
02722 ast_log(LOG_WARNING,"Unrecognized txmixa parameter: %s\n",s);
02723 }
02724
02725
02726 }
02727
02728 static void store_txmixb(struct chan_usbradio_pvt *o, const char *s)
02729 {
02730 if (!strcasecmp(s,"no")){
02731 o->txmixb = TX_OUT_OFF;
02732 }
02733 else if (!strcasecmp(s,"voice")){
02734 o->txmixb = TX_OUT_VOICE;
02735 }
02736 else if (!strcasecmp(s,"tone")){
02737 o->txmixb = TX_OUT_LSD;
02738 }
02739 else if (!strcasecmp(s,"composite")){
02740 o->txmixb = TX_OUT_COMPOSITE;
02741 }
02742 else if (!strcasecmp(s,"auxvoice")){
02743 o->txmixb = TX_OUT_AUX;
02744 }
02745 else {
02746 ast_log(LOG_WARNING,"Unrecognized txmixb parameter: %s\n",s);
02747 }
02748
02749
02750 }
02751
02752
02753 static void store_rxcdtype(struct chan_usbradio_pvt *o, const char *s)
02754 {
02755 if (!strcasecmp(s,"no")){
02756 o->rxcdtype = CD_IGNORE;
02757 }
02758 else if (!strcasecmp(s,"usb")){
02759 o->rxcdtype = CD_HID;
02760 }
02761 else if (!strcasecmp(s,"dsp")){
02762 o->rxcdtype = CD_XPMR_NOISE;
02763 }
02764 else if (!strcasecmp(s,"vox")){
02765 o->rxcdtype = CD_XPMR_VOX;
02766 }
02767 else if (!strcasecmp(s,"usbinvert")){
02768 o->rxcdtype = CD_HID_INVERT;
02769 }
02770 else {
02771 ast_log(LOG_WARNING,"Unrecognized rxcdtype parameter: %s\n",s);
02772 }
02773
02774
02775 }
02776
02777
02778 static void store_rxsdtype(struct chan_usbradio_pvt *o, const char *s)
02779 {
02780 if (!strcasecmp(s,"no") || !strcasecmp(s,"SD_IGNORE")){
02781 o->rxsdtype = SD_IGNORE;
02782 }
02783 else if (!strcasecmp(s,"usb") || !strcasecmp(s,"SD_HID")){
02784 o->rxsdtype = SD_HID;
02785 }
02786 else if (!strcasecmp(s,"usbinvert") || !strcasecmp(s,"SD_HID_INVERT")){
02787 o->rxsdtype = SD_HID_INVERT;
02788 }
02789 else if (!strcasecmp(s,"software") || !strcasecmp(s,"SD_XPMR")){
02790 o->rxsdtype = SD_XPMR;
02791 }
02792 else {
02793 ast_log(LOG_WARNING,"Unrecognized rxsdtype parameter: %s\n",s);
02794 }
02795
02796
02797 }
02798
02799
02800 static void store_rxgain(struct chan_usbradio_pvt *o, const char *s)
02801 {
02802 float f;
02803 sscanf(s, "%30f", &f);
02804 o->rxgain = f;
02805
02806 }
02807
02808
02809 static void store_rxvoiceadj(struct chan_usbradio_pvt *o, const char *s)
02810 {
02811 float f;
02812 sscanf(s, "%30f", &f);
02813 o->rxvoiceadj = f;
02814
02815 }
02816
02817
02818 static void store_rxctcssadj(struct chan_usbradio_pvt *o, const char *s)
02819 {
02820 float f;
02821 sscanf(s, "%30f", &f);
02822 o->rxctcssadj = f;
02823
02824 }
02825
02826
02827 static void store_txtoctype(struct chan_usbradio_pvt *o, const char *s)
02828 {
02829 if (!strcasecmp(s,"no") || !strcasecmp(s,"TOC_NONE")){
02830 o->txtoctype = TOC_NONE;
02831 }
02832 else if (!strcasecmp(s,"phase") || !strcasecmp(s,"TOC_PHASE")){
02833 o->txtoctype = TOC_PHASE;
02834 }
02835 else if (!strcasecmp(s,"notone") || !strcasecmp(s,"TOC_NOTONE")){
02836 o->txtoctype = TOC_NOTONE;
02837 }
02838 else {
02839 ast_log(LOG_WARNING,"Unrecognized txtoctype parameter: %s\n",s);
02840 }
02841 }
02842
02843
02844 static void tune_txoutput(struct chan_usbradio_pvt *o, int value, int fd)
02845 {
02846 o->txtestkey=1;
02847 o->pmrChan->txPttIn=1;
02848 TxTestTone(o->pmrChan, 1);
02849 if (fd > 0) ast_cli(fd,"Tone output starting on channel %s...\n",o->name);
02850 usleep(5000000);
02851 TxTestTone(o->pmrChan, 0);
02852 if (fd > 0) ast_cli(fd,"Tone output ending on channel %s...\n",o->name);
02853 o->pmrChan->txPttIn=0;
02854 o->txtestkey=0;
02855 }
02856
02857
02858 static void tune_rxinput(int fd, struct chan_usbradio_pvt *o)
02859 {
02860 const int target=23000;
02861 const int tolerance=2000;
02862 const int settingmin=1;
02863 const int settingstart=2;
02864 const int maxtries=12;
02865
02866 float settingmax;
02867
02868 int setting=0, tries=0, tmpdiscfactor, meas;
02869 int tunetype=0;
02870
02871 settingmax = o->micmax;
02872
02873 if(o->pmrChan->rxDemod)tunetype=1;
02874 o->pmrChan->b.tuning=1;
02875
02876 setting = settingstart;
02877
02878 ast_cli(fd,"tune rxnoise maxtries=%i, target=%i, tolerance=%i\n",maxtries,target,tolerance);
02879
02880 while(tries<maxtries)
02881 {
02882 setamixer(o->devicenum,MIXER_PARAM_MIC_CAPTURE_VOL,setting,0);
02883 setamixer(o->devicenum,MIXER_PARAM_MIC_BOOST,o->rxboostset,0);
02884
02885 usleep(100000);
02886 if(o->rxcdtype!=CD_XPMR_NOISE || o->rxdemod==RX_AUDIO_SPEAKER)
02887 {
02888
02889 o->pmrChan->spsMeasure->source = o->pmrChan->spsRx->source;
02890 o->pmrChan->spsMeasure->discfactor=2000;
02891 o->pmrChan->spsMeasure->enabled=1;
02892 o->pmrChan->spsMeasure->amax = o->pmrChan->spsMeasure->amin = 0;
02893 usleep(400000);
02894 meas=o->pmrChan->spsMeasure->apeak;
02895 o->pmrChan->spsMeasure->enabled=0;
02896 }
02897 else
02898 {
02899
02900 tmpdiscfactor=o->pmrChan->spsRx->discfactor;
02901 o->pmrChan->spsRx->discfactor=(i16)2000;
02902 o->pmrChan->spsRx->discounteru=o->pmrChan->spsRx->discounterl=0;
02903 o->pmrChan->spsRx->amax=o->pmrChan->spsRx->amin=0;
02904 usleep(200000);
02905 meas=o->pmrChan->rxRssi;
02906 o->pmrChan->spsRx->discfactor=tmpdiscfactor;
02907 o->pmrChan->spsRx->discounteru=o->pmrChan->spsRx->discounterl=0;
02908 o->pmrChan->spsRx->amax=o->pmrChan->spsRx->amin=0;
02909 }
02910 if(!meas)meas++;
02911 ast_cli(fd,"tries=%i, setting=%i, meas=%i\n",tries,setting,meas);
02912
02913 if( meas<(target-tolerance) || meas>(target+tolerance) || tries<3){
02914 setting=setting*target/meas;
02915 }
02916 else if(tries>4 && meas>(target-tolerance) && meas<(target+tolerance) )
02917 {
02918 break;
02919 }
02920
02921 if(setting<settingmin)setting=settingmin;
02922 else if(setting>settingmax)setting=settingmax;
02923
02924 tries++;
02925 }
02926 ast_cli(fd,"DONE tries=%i, setting=%i, meas=%i\n",tries,
02927 (setting * 1000) / o->micmax,meas);
02928 if( meas<(target-tolerance) || meas>(target+tolerance) ){
02929 ast_cli(fd,"ERROR: RX INPUT ADJUST FAILED.\n");
02930 }else{
02931 ast_cli(fd,"INFO: RX INPUT ADJUST SUCCESS.\n");
02932 o->rxmixerset=(setting * 1000) / o->micmax;
02933 }
02934 o->pmrChan->b.tuning=0;
02935 }
02936
02937
02938 static void tune_rxvoice(int fd, struct chan_usbradio_pvt *o)
02939 {
02940 const int target=7200;
02941 const int tolerance=360;
02942 const float settingmin=0.1;
02943 const float settingmax=4;
02944 const float settingstart=1;
02945 const int maxtries=12;
02946
02947 float setting;
02948
02949 int tries=0, meas;
02950
02951 ast_cli(fd,"INFO: RX VOICE ADJUST START.\n");
02952 ast_cli(fd,"target=%i tolerance=%i \n",target,tolerance);
02953
02954 o->pmrChan->b.tuning=1;
02955 if(!o->pmrChan->spsMeasure)
02956 ast_cli(fd,"ERROR: NO MEASURE BLOCK.\n");
02957
02958 if(!o->pmrChan->spsMeasure->source || !o->pmrChan->prxVoiceAdjust )
02959 ast_cli(fd,"ERROR: NO SOURCE OR MEASURE SETTING.\n");
02960
02961 o->pmrChan->spsMeasure->source=o->pmrChan->spsRxOut->sink;
02962 o->pmrChan->spsMeasure->enabled=1;
02963 o->pmrChan->spsMeasure->discfactor=1000;
02964
02965 setting=settingstart;
02966
02967
02968
02969 while(tries<maxtries)
02970 {
02971 *(o->pmrChan->prxVoiceAdjust)=setting*M_Q8;
02972 usleep(10000);
02973 o->pmrChan->spsMeasure->amax = o->pmrChan->spsMeasure->amin = 0;
02974 usleep(1000000);
02975 meas = o->pmrChan->spsMeasure->apeak;
02976 ast_cli(fd,"tries=%i, setting=%f, meas=%i\n",tries,setting,meas);
02977
02978 if( meas<(target-tolerance) || meas>(target+tolerance) || tries<3){
02979 setting=setting*target/meas;
02980 }
02981 else if(tries>4 && meas>(target-tolerance) && meas<(target+tolerance) )
02982 {
02983 break;
02984 }
02985 if(setting<settingmin)setting=settingmin;
02986 else if(setting>settingmax)setting=settingmax;
02987
02988 tries++;
02989 }
02990
02991 o->pmrChan->spsMeasure->enabled=0;
02992
02993 ast_cli(fd,"DONE tries=%i, setting=%f, meas=%f\n",tries,setting,(float)meas);
02994 if( meas<(target-tolerance) || meas>(target+tolerance) ){
02995 ast_cli(fd,"ERROR: RX VOICE GAIN ADJUST FAILED.\n");
02996 }else{
02997 ast_cli(fd,"INFO: RX VOICE GAIN ADJUST SUCCESS.\n");
02998 o->rxvoiceadj=setting;
02999 }
03000 o->pmrChan->b.tuning=0;
03001 }
03002
03003
03004 static void tune_rxctcss(int fd, struct chan_usbradio_pvt *o)
03005 {
03006 const int target=2400;
03007 const int tolerance=100;
03008 const float settingmin=0.1;
03009 const float settingmax=8;
03010 const float settingstart=1;
03011 const int maxtries=12;
03012
03013 float setting;
03014 int tries=0, meas;
03015
03016 ast_cli(fd,"INFO: RX CTCSS ADJUST START.\n");
03017 ast_cli(fd,"target=%i tolerance=%i \n",target,tolerance);
03018
03019 o->pmrChan->b.tuning=1;
03020 o->pmrChan->spsMeasure->source=o->pmrChan->prxCtcssMeasure;
03021 o->pmrChan->spsMeasure->discfactor=400;
03022 o->pmrChan->spsMeasure->enabled=1;
03023
03024 setting=settingstart;
03025
03026 while(tries<maxtries)
03027 {
03028 *(o->pmrChan->prxCtcssAdjust)=setting*M_Q8;
03029 usleep(10000);
03030 o->pmrChan->spsMeasure->amax = o->pmrChan->spsMeasure->amin = 0;
03031 usleep(500000);
03032 meas = o->pmrChan->spsMeasure->apeak;
03033 ast_cli(fd,"tries=%i, setting=%f, meas=%i\n",tries,setting,meas);
03034
03035 if( meas<(target-tolerance) || meas>(target+tolerance) || tries<3){
03036 setting=setting*target/meas;
03037 }
03038 else if(tries>4 && meas>(target-tolerance) && meas<(target+tolerance) )
03039 {
03040 break;
03041 }
03042 if(setting<settingmin)setting=settingmin;
03043 else if(setting>settingmax)setting=settingmax;
03044
03045 tries++;
03046 }
03047 o->pmrChan->spsMeasure->enabled=0;
03048 ast_cli(fd,"DONE tries=%i, setting=%f, meas=%f\n",tries,setting,(float)meas);
03049 if( meas<(target-tolerance) || meas>(target+tolerance) ){
03050 ast_cli(fd,"ERROR: RX CTCSS GAIN ADJUST FAILED.\n");
03051 }else{
03052 ast_cli(fd,"INFO: RX CTCSS GAIN ADJUST SUCCESS.\n");
03053 o->rxctcssadj=setting;
03054 }
03055 o->pmrChan->b.tuning=0;
03056 }
03057
03058
03059
03060 static void tune_write(struct chan_usbradio_pvt *o)
03061 {
03062 FILE *fp;
03063 char fname[200];
03064
03065 snprintf(fname,sizeof(fname) - 1,"/etc/asterisk/usbradio_tune_%s.conf",o->name);
03066 fp = fopen(fname,"w");
03067
03068 fprintf(fp,"[%s]\n",o->name);
03069
03070 fprintf(fp,"; name=%s\n",o->name);
03071 fprintf(fp,"; devicenum=%i\n",o->devicenum);
03072 fprintf(fp,"devstr=%s\n",o->devstr);
03073 fprintf(fp,"rxmixerset=%i\n",o->rxmixerset);
03074 fprintf(fp,"txmixaset=%i\n",o->txmixaset);
03075 fprintf(fp,"txmixbset=%i\n",o->txmixbset);
03076 fprintf(fp,"rxvoiceadj=%f\n",o->rxvoiceadj);
03077 fprintf(fp,"rxctcssadj=%f\n",o->rxctcssadj);
03078 fprintf(fp,"txctcssadj=%i\n",o->txctcssadj);
03079 fprintf(fp,"rxsquelchadj=%i\n",o->rxsquelchadj);
03080 fclose(fp);
03081
03082 if(o->wanteeprom)
03083 {
03084 ast_mutex_lock(&o->eepromlock);
03085 while(o->eepromctl)
03086 {
03087 ast_mutex_unlock(&o->eepromlock);
03088 usleep(10000);
03089 ast_mutex_lock(&o->eepromlock);
03090 }
03091 o->eeprom[EEPROM_RXMIXERSET] = o->rxmixerset;
03092 o->eeprom[EEPROM_TXMIXASET] = o->txmixaset;
03093 o->eeprom[EEPROM_TXMIXBSET] = o->txmixbset;
03094 memcpy(&o->eeprom[EEPROM_RXVOICEADJ],&o->rxvoiceadj,sizeof(float));
03095 memcpy(&o->eeprom[EEPROM_RXCTCSSADJ],&o->rxctcssadj,sizeof(float));
03096 o->eeprom[EEPROM_TXCTCSSADJ] = o->txctcssadj;
03097 o->eeprom[EEPROM_RXSQUELCHADJ] = o->rxsquelchadj;
03098 o->eepromctl = 2;
03099 ast_mutex_unlock(&o->eepromlock);
03100 }
03101 }
03102
03103 static void mixer_write(struct chan_usbradio_pvt *o)
03104 {
03105 setamixer(o->devicenum,MIXER_PARAM_MIC_PLAYBACK_SW,0,0);
03106 setamixer(o->devicenum,MIXER_PARAM_MIC_PLAYBACK_VOL,0,0);
03107 setamixer(o->devicenum,MIXER_PARAM_SPKR_PLAYBACK_SW,1,0);
03108 setamixer(o->devicenum,MIXER_PARAM_SPKR_PLAYBACK_VOL,
03109 o->txmixaset * o->spkrmax / 1000,
03110 o->txmixbset * o->spkrmax / 1000);
03111 setamixer(o->devicenum,MIXER_PARAM_MIC_CAPTURE_VOL,
03112 o->rxmixerset * o->micmax / 1000,0);
03113 setamixer(o->devicenum,MIXER_PARAM_MIC_BOOST,o->rxboostset,0);
03114 setamixer(o->devicenum,MIXER_PARAM_MIC_CAPTURE_SW,1,0);
03115 }
03116
03117
03118
03119 static void mult_set(struct chan_usbradio_pvt *o)
03120 {
03121
03122 if(o->pmrChan->spsTxOutA) {
03123 o->pmrChan->spsTxOutA->outputGain =
03124 mult_calc((o->txmixaset * 152) / 1000);
03125 }
03126 if(o->pmrChan->spsTxOutB){
03127 o->pmrChan->spsTxOutB->outputGain =
03128 mult_calc((o->txmixbset * 152) / 1000);
03129 }
03130 }
03131
03132
03133
03134 static int mult_calc(int value)
03135 {
03136 const int multx=M_Q8;
03137 int pot,mult;
03138
03139 pot=((int)(value/4)*4)+2;
03140 mult = multx-( ( multx * (3-(value%4)) ) / (pot+2) );
03141 return(mult);
03142 }
03143
03144 #define pd(x) {printf(#x" = %d\n",x);}
03145 #define pp(x) {printf(#x" = %p\n",x);}
03146 #define ps(x) {printf(#x" = %s\n",x);}
03147 #define pf(x) {printf(#x" = %f\n",x);}
03148
03149
03150 #if 0
03151
03152
03153
03154
03155
03156
03157 static int usbhider(struct chan_usbradio_pvt *o, int opt)
03158 {
03159 unsigned char buf[4];
03160 char lastrx, txtmp;
03161
03162 if(opt)
03163 {
03164 struct usb_device *usb_dev;
03165
03166 usb_dev = hid_device_init(o->devstr);
03167 if (usb_dev == NULL) {
03168 ast_log(LOG_ERROR,"USB HID device not found\n");
03169 return -1;
03170 }
03171 o->usb_handle = usb_open(usb_dev);
03172 if (o->usb_handle == NULL) {
03173 ast_log(LOG_ERROR,"Not able to open USB device\n");
03174 return -1;
03175 }
03176 if (usb_claim_interface(o->usb_handle,C108_HID_INTERFACE) < 0)
03177 {
03178 if (usb_detach_kernel_driver_np(o->usb_handle,C108_HID_INTERFACE) < 0) {
03179 ast_log(LOG_ERROR,"Not able to detach the USB device\n");
03180 return -1;
03181 }
03182 if (usb_claim_interface(o->usb_handle,C108_HID_INTERFACE) < 0) {
03183 ast_log(LOG_ERROR,"Not able to claim the USB device\n");
03184 return -1;
03185 }
03186 }
03187
03188 memset(buf,0,sizeof(buf));
03189 buf[2] = o->hid_gpio_ctl;
03190 buf[1] = 0;
03191 hid_set_outputs(o->usb_handle,buf);
03192 memcpy(bufsave,buf,sizeof(buf));
03193
03194 buf[o->hid_gpio_ctl_loc] = o->hid_gpio_ctl;
03195 o->lasttx=0;
03196 }
03197
03198
03199 txtmp=o->pmrChan->txPttOut;
03200
03201 if (o->lasttx != txtmp)
03202 {
03203 o->pmrChan->txPttHid=o->lasttx = txtmp;
03204 if(o->debuglevel)printf("usbhid: tx set to %d\n",txtmp);
03205 buf[o->hid_gpio_loc] = 0;
03206 if (!o->invertptt)
03207 {
03208 if (txtmp) buf[o->hid_gpio_loc] = o->hid_io_ptt;
03209 }
03210 else
03211 {
03212 if (!txtmp) buf[o->hid_gpio_loc] = o->hid_io_ptt;
03213 }
03214 buf[o->hid_gpio_ctl_loc] = o->hid_gpio_ctl;
03215 hid_set_outputs(o->usb_handle,buf);
03216 }
03217
03218 return(0);
03219 }
03220 #endif
03221
03222
03223 static void pmrdump(struct chan_usbradio_pvt *o)
03224 {
03225 t_pmr_chan *p;
03226 int i;
03227
03228 p=o->pmrChan;
03229
03230 printf("\nodump()\n");
03231
03232 pd(o->devicenum);
03233 ps(o->devstr);
03234
03235 pd(o->micmax);
03236 pd(o->spkrmax);
03237
03238 pd(o->rxdemod);
03239 pd(o->rxcdtype);
03240 pd(o->rxsdtype);
03241 pd(o->txtoctype);
03242
03243 pd(o->rxmixerset);
03244 pd(o->rxboostset);
03245
03246 pf(o->rxvoiceadj);
03247 pf(o->rxctcssadj);
03248 pd(o->rxsquelchadj);
03249
03250 ps(o->txctcssdefault);
03251 ps(o->txctcssfreq);
03252
03253 pd(o->numrxctcssfreqs);
03254 if(o->numrxctcssfreqs>0)
03255 {
03256 for(i=0;i<o->numrxctcssfreqs;i++)
03257 {
03258 printf(" %i = %s %s\n",i,o->rxctcss[i],o->txctcss[i]);
03259 }
03260 }
03261
03262 pd(o->b.rxpolarity);
03263 pd(o->b.txpolarity);
03264
03265 pd(o->txprelim);
03266 pd(o->txmixa);
03267 pd(o->txmixb);
03268
03269 pd(o->txmixaset);
03270 pd(o->txmixbset);
03271
03272 printf("\npmrdump()\n");
03273
03274 pd(p->devicenum);
03275
03276 printf("prxSquelchAdjust=%i\n",*(o->pmrChan->prxSquelchAdjust));
03277
03278 pd(p->rxCarrierPoint);
03279 pd(p->rxCarrierHyst);
03280
03281 pd(*p->prxVoiceAdjust);
03282 pd(*p->prxCtcssAdjust);
03283
03284 pd(p->rxfreq);
03285 pd(p->txfreq);
03286
03287 pd(p->rxCtcss->relax);
03288
03289 pd(p->numrxcodes);
03290 if(o->pmrChan->numrxcodes>0)
03291 {
03292 for(i=0;i<o->pmrChan->numrxcodes;i++)
03293 {
03294 printf(" %i = %s\n",i,o->pmrChan->pRxCode[i]);
03295 }
03296 }
03297
03298 pd(p->txTocType);
03299 ps(p->pTxCodeDefault);
03300 pd(p->txcodedefaultsmode);
03301 pd(p->numtxcodes);
03302 if(o->pmrChan->numtxcodes>0)
03303 {
03304 for(i=0;i<o->pmrChan->numtxcodes;i++)
03305 {
03306 printf(" %i = %s\n",i,o->pmrChan->pTxCode[i]);
03307 }
03308 }
03309
03310 pd(p->b.rxpolarity);
03311 pd(p->b.txpolarity);
03312 pd(p->b.dcsrxpolarity);
03313 pd(p->b.dcstxpolarity);
03314 pd(p->b.lsdrxpolarity);
03315 pd(p->b.lsdtxpolarity);
03316
03317 pd(p->txMixA);
03318 pd(p->txMixB);
03319
03320 pd(p->rxDeEmpEnable);
03321 pd(p->rxCenterSlicerEnable);
03322 pd(p->rxCtcssDecodeEnable);
03323 pd(p->rxDcsDecodeEnable);
03324 pd(p->b.ctcssRxEnable);
03325 pd(p->b.dcsRxEnable);
03326 pd(p->b.lmrRxEnable);
03327 pd(p->b.dstRxEnable);
03328 pd(p->smode);
03329
03330 pd(p->txHpfEnable);
03331 pd(p->txLimiterEnable);
03332 pd(p->txPreEmpEnable);
03333 pd(p->txLpfEnable);
03334
03335 if(p->spsTxOutA)pd(p->spsTxOutA->outputGain);
03336 if(p->spsTxOutB)pd(p->spsTxOutB->outputGain);
03337 pd(p->txPttIn);
03338 pd(p->txPttOut);
03339
03340 pd(p->tracetype);
03341
03342 return;
03343 }
03344
03345
03346
03347
03348 static int xpmr_config(struct chan_usbradio_pvt *o)
03349 {
03350
03351
03352 TRACEO(1,("xpmr_config()\n"));
03353
03354 if(o->pmrChan==NULL)
03355 {
03356 ast_log(LOG_ERROR,"pmr channel structure NULL\n");
03357 return 1;
03358 }
03359
03360 o->pmrChan->rxCtcss->relax = o->rxctcssrelax;
03361 o->pmrChan->txpower=0;
03362
03363 if(o->b.remoted)
03364 {
03365 o->pmrChan->pTxCodeDefault = o->set_txctcssdefault;
03366 o->pmrChan->pRxCodeSrc=o->set_rxctcssfreqs;
03367 o->pmrChan->pTxCodeSrc=o->set_txctcssfreqs;
03368
03369 o->pmrChan->rxfreq=o->set_rxfreq;
03370 o->pmrChan->txfreq=o->set_txfreq;
03371
03372
03373 }
03374 else
03375 {
03376
03377
03378 o->pmrChan->pTxCodeDefault = o->txctcssdefault;
03379 o->pmrChan->pRxCodeSrc = o->rxctcssfreqs;
03380 o->pmrChan->pTxCodeSrc = o->txctcssfreqs;
03381
03382 o->pmrChan->rxfreq = o->rxfreq;
03383 o->pmrChan->txfreq = o->txfreq;
03384 }
03385
03386 code_string_parse(o->pmrChan);
03387 if(o->pmrChan->rxfreq) o->pmrChan->b.reprog=1;
03388
03389 return 0;
03390 }
03391
03392
03393
03394 static struct chan_usbradio_pvt *store_config(struct ast_config *cfg, char *ctg)
03395 {
03396 struct ast_variable *v;
03397 struct chan_usbradio_pvt *o;
03398 struct ast_config *cfg1;
03399 int i;
03400 char fname[200];
03401 #ifdef NEW_ASTERISK
03402 struct ast_flags zeroflag = {0};
03403 #endif
03404 if (ctg == NULL) {
03405 traceusb1((" store_config() ctg == NULL\n"));
03406 o = &usbradio_default;
03407 ctg = "general";
03408 } else {
03409
03410 if (strcmp(ctg, "general") == 0) {
03411 o = &usbradio_default;
03412 } else {
03413
03414 if (!(o = ast_calloc(1, sizeof(*o))))
03415 return NULL;
03416 *o = usbradio_default;
03417 o->name = ast_strdup(ctg);
03418 if (!usbradio_active)
03419 usbradio_active = o->name;
03420 }
03421 }
03422 ast_mutex_init(&o->eepromlock);
03423 strcpy(o->mohinterpret, "default");
03424
03425 for (v = ast_variable_browse(cfg, ctg); v; v = v->next) {
03426 M_START((char *)v->name, (char *)v->value);
03427
03428
03429 if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
03430 continue;
03431
03432 #if 0
03433 M_BOOL("autoanswer", o->autoanswer)
03434 M_BOOL("autohangup", o->autohangup)
03435 M_BOOL("overridecontext", o->overridecontext)
03436 M_STR("context", o->ctx)
03437 M_STR("language", o->language)
03438 M_STR("mohinterpret", o->mohinterpret)
03439 M_STR("extension", o->ext)
03440 M_F("callerid", store_callerid(o, v->value))
03441 #endif
03442 M_UINT("frags", o->frags)
03443 M_UINT("queuesize",o->queuesize)
03444 #if 0
03445 M_UINT("devicenum",o->devicenum)
03446 #endif
03447 M_UINT("debug", usbradio_debug)
03448 M_BOOL("rxcpusaver",o->rxcpusaver)
03449 M_BOOL("txcpusaver",o->txcpusaver)
03450 M_BOOL("invertptt",o->invertptt)
03451 M_F("rxdemod",store_rxdemod(o,(char *)v->value))
03452 M_BOOL("txprelim",o->txprelim);
03453 M_F("txmixa",store_txmixa(o,(char *)v->value))
03454 M_F("txmixb",store_txmixb(o,(char *)v->value))
03455 M_F("carrierfrom",store_rxcdtype(o,(char *)v->value))
03456 M_F("rxsdtype",store_rxsdtype(o,(char *)v->value))
03457 M_UINT("rxsqvox",o->rxsqvoxadj)
03458 M_STR("txctcssdefault",o->txctcssdefault)
03459 M_STR("rxctcssfreqs",o->rxctcssfreqs)
03460 M_STR("txctcssfreqs",o->txctcssfreqs)
03461 M_UINT("rxfreq",o->rxfreq)
03462 M_UINT("txfreq",o->txfreq)
03463 M_F("rxgain",store_rxgain(o,(char *)v->value))
03464 M_BOOL("rxboost",o->rxboostset)
03465 M_UINT("rxctcssrelax",o->rxctcssrelax)
03466 M_F("txtoctype",store_txtoctype(o,(char *)v->value))
03467 M_UINT("hdwtype",o->hdwtype)
03468 M_UINT("eeprom",o->wanteeprom)
03469 M_UINT("duplex",o->radioduplex)
03470 M_UINT("txsettletime",o->txsettletime)
03471 M_BOOL("rxpolarity",o->b.rxpolarity)
03472 M_BOOL("txpolarity",o->b.txpolarity)
03473 M_BOOL("dcsrxpolarity",o->b.dcsrxpolarity)
03474 M_BOOL("dcstxpolarity",o->b.dcstxpolarity)
03475 M_BOOL("lsdrxpolarity",o->b.lsdrxpolarity)
03476 M_BOOL("lsdtxpolarity",o->b.lsdtxpolarity)
03477 M_BOOL("loopback",o->b.loopback)
03478 M_BOOL("radioactive",o->b.radioactive)
03479 M_UINT("rptnum",o->rptnum)
03480 M_UINT("idleinterval",o->idleinterval)
03481 M_UINT("turnoffs",o->turnoffs)
03482 M_UINT("tracetype",o->tracetype)
03483 M_UINT("tracelevel",o->tracelevel)
03484 M_UINT("area",o->area)
03485 M_STR("ukey",o->ukey)
03486 M_END(;
03487 );
03488 }
03489
03490 o->debuglevel=0;
03491
03492 if (o == &usbradio_default)
03493 return NULL;
03494
03495 snprintf(fname,sizeof(fname) - 1,config1,o->name);
03496 #ifdef NEW_ASTERISK
03497 cfg1 = ast_config_load(fname,zeroflag);
03498 #else
03499 cfg1 = ast_config_load(fname);
03500 #endif
03501 o->rxmixerset = 500;
03502 o->txmixaset = 500;
03503 o->txmixbset = 500;
03504 o->rxvoiceadj = 0.5;
03505 o->rxctcssadj = 0.5;
03506 o->txctcssadj = 200;
03507 o->rxsquelchadj = 500;
03508 o->devstr[0] = 0;
03509 if (cfg1 && cfg1 != CONFIG_STATUS_FILEINVALID) {
03510 for (v = ast_variable_browse(cfg1, o->name); v; v = v->next) {
03511
03512 M_START((char *)v->name, (char *)v->value);
03513 M_UINT("rxmixerset", o->rxmixerset)
03514 M_UINT("txmixaset", o->txmixaset)
03515 M_UINT("txmixbset", o->txmixbset)
03516 M_F("rxvoiceadj",store_rxvoiceadj(o,(char *)v->value))
03517 M_F("rxctcssadj",store_rxctcssadj(o,(char *)v->value))
03518 M_UINT("txctcssadj",o->txctcssadj);
03519 M_UINT("rxsquelchadj", o->rxsquelchadj)
03520 M_STR("devstr", o->devstr)
03521 M_END(;
03522 );
03523 }
03524 ast_config_destroy(cfg1);
03525 } else ast_log(LOG_WARNING,"File %s not found, using default parameters.\n",fname);
03526
03527 if(o->wanteeprom)
03528 {
03529 ast_mutex_lock(&o->eepromlock);
03530 while(o->eepromctl)
03531 {
03532 ast_mutex_unlock(&o->eepromlock);
03533 usleep(10000);
03534 ast_mutex_lock(&o->eepromlock);
03535 }
03536 o->eepromctl = 1;
03537 ast_mutex_unlock(&o->eepromlock);
03538 }
03539
03540 if ((!usb_list_check(o->devstr)) || find_desc_usb(o->devstr))
03541 {
03542 char *s;
03543
03544 for(s = usb_device_list; *s; s += strlen(s) + 1)
03545 {
03546 if (!find_desc_usb(s)) break;
03547 }
03548 if (!*s)
03549 {
03550 ast_log(LOG_WARNING,"Unable to assign USB device for channel %s\n",o->name);
03551 goto error;
03552 }
03553 ast_log(LOG_NOTICE,"Assigned USB device %s to usbradio channel %s\n",s,o->name);
03554 strcpy(o->devstr,s);
03555 }
03556
03557 i = usb_get_usbdev(o->devstr);
03558 if (i < 0)
03559 {
03560 ast_log(LOG_ERROR,"Not able to find alsa USB device\n");
03561 goto error;
03562 }
03563 o->devicenum = i;
03564
03565 o->micmax = amixer_max(o->devicenum,MIXER_PARAM_MIC_CAPTURE_VOL);
03566 o->spkrmax = amixer_max(o->devicenum,MIXER_PARAM_SPKR_PLAYBACK_VOL);
03567 o->lastopen = ast_tvnow();
03568 o->dsp = ast_dsp_new();
03569 if (o->dsp)
03570 {
03571 #ifdef NEW_ASTERISK
03572 ast_dsp_set_features(o->dsp,DSP_FEATURE_DIGIT_DETECT);
03573 ast_dsp_set_digitmode(o->dsp,DSP_DIGITMODE_DTMF | DSP_DIGITMODE_MUTECONF | DSP_DIGITMODE_RELAXDTMF);
03574 #else
03575 ast_dsp_set_features(o->dsp,DSP_FEATURE_DTMF_DETECT);
03576 ast_dsp_digitmode(o->dsp,DSP_DIGITMODE_DTMF | DSP_DIGITMODE_MUTECONF | DSP_DIGITMODE_RELAXDTMF);
03577 #endif
03578 }
03579
03580 if(o->pmrChan==NULL)
03581 {
03582 t_pmr_chan tChan;
03583
03584
03585 memset(&tChan,0,sizeof(t_pmr_chan));
03586
03587 tChan.pTxCodeDefault = o->txctcssdefault;
03588 tChan.pRxCodeSrc = o->rxctcssfreqs;
03589 tChan.pTxCodeSrc = o->txctcssfreqs;
03590
03591 tChan.rxDemod=o->rxdemod;
03592 tChan.rxCdType=o->rxcdtype;
03593 tChan.rxSqVoxAdj=o->rxsqvoxadj;
03594
03595 if (o->txprelim)
03596 tChan.txMod = 2;
03597
03598 tChan.txMixA = o->txmixa;
03599 tChan.txMixB = o->txmixb;
03600
03601 tChan.rxCpuSaver=o->rxcpusaver;
03602 tChan.txCpuSaver=o->txcpusaver;
03603
03604 tChan.b.rxpolarity=o->b.rxpolarity;
03605 tChan.b.txpolarity=o->b.txpolarity;
03606
03607 tChan.b.dcsrxpolarity=o->b.dcsrxpolarity;
03608 tChan.b.dcstxpolarity=o->b.dcstxpolarity;
03609
03610 tChan.b.lsdrxpolarity=o->b.lsdrxpolarity;
03611 tChan.b.lsdtxpolarity=o->b.lsdtxpolarity;
03612
03613 tChan.tracetype=o->tracetype;
03614 tChan.tracelevel=o->tracelevel;
03615 tChan.rptnum=o->rptnum;
03616 tChan.idleinterval=o->idleinterval;
03617 tChan.turnoffs=o->turnoffs;
03618 tChan.area=o->area;
03619 tChan.ukey=o->ukey;
03620 tChan.name=o->name;
03621
03622 o->pmrChan=createPmrChannel(&tChan,FRAME_SIZE);
03623
03624 o->pmrChan->radioDuplex=o->radioduplex;
03625 o->pmrChan->b.loopback=0;
03626 o->pmrChan->txsettletime=o->txsettletime;
03627 o->pmrChan->rxCpuSaver=o->rxcpusaver;
03628 o->pmrChan->txCpuSaver=o->txcpusaver;
03629
03630 *(o->pmrChan->prxSquelchAdjust) =
03631 ((999 - o->rxsquelchadj) * 32767) / 1000;
03632
03633 *(o->pmrChan->prxVoiceAdjust)=o->rxvoiceadj*M_Q8;
03634 *(o->pmrChan->prxCtcssAdjust)=o->rxctcssadj*M_Q8;
03635 o->pmrChan->rxCtcss->relax=o->rxctcssrelax;
03636 o->pmrChan->txTocType = o->txtoctype;
03637
03638 if ( (o->txmixa == TX_OUT_LSD) ||
03639 (o->txmixa == TX_OUT_COMPOSITE) ||
03640 (o->txmixb == TX_OUT_LSD) ||
03641 (o->txmixb == TX_OUT_COMPOSITE))
03642 {
03643 set_txctcss_level(o);
03644 }
03645
03646 if( (o->txmixa!=TX_OUT_VOICE) && (o->txmixb!=TX_OUT_VOICE) &&
03647 (o->txmixa!=TX_OUT_COMPOSITE) && (o->txmixb!=TX_OUT_COMPOSITE)
03648 )
03649 {
03650 ast_log(LOG_ERROR,"No txvoice output configured.\n");
03651 }
03652
03653 if( o->txctcssfreq[0] &&
03654 o->txmixa!=TX_OUT_LSD && o->txmixa!=TX_OUT_COMPOSITE &&
03655 o->txmixb!=TX_OUT_LSD && o->txmixb!=TX_OUT_COMPOSITE
03656 )
03657 {
03658 ast_log(LOG_ERROR,"No txtone output configured.\n");
03659 }
03660
03661 if(o->b.radioactive)
03662 {
03663
03664
03665
03666
03667
03668 usbradio_active = o->name;
03669
03670
03671
03672 ast_log(LOG_NOTICE,"radio active set to [%s]\n",o->name);
03673 }
03674 }
03675
03676 xpmr_config(o);
03677
03678 TRACEO(1,("store_config() 120\n"));
03679 mixer_write(o);
03680 TRACEO(1,("store_config() 130\n"));
03681 mult_set(o);
03682 TRACEO(1,("store_config() 140\n"));
03683 hidhdwconfig(o);
03684
03685 TRACEO(1,("store_config() 200\n"));
03686
03687 #ifndef NEW_ASTERISK
03688 if (pipe(o->sndcmd) != 0) {
03689 ast_log(LOG_ERROR, "Unable to create pipe\n");
03690 goto error;
03691 }
03692
03693 ast_pthread_create_background(&o->sthread, NULL, sound_thread, o);
03694 #endif
03695
03696
03697 if (o != &usbradio_default) {
03698 o->next = usbradio_default.next;
03699 usbradio_default.next = o;
03700 }
03701 TRACEO(1,("store_config() complete\n"));
03702 return o;
03703
03704 error:
03705 if (o != &usbradio_default)
03706 free(o);
03707 return NULL;
03708 }
03709
03710
03711 #if DEBUG_FILETEST == 1
03712
03713
03714
03715 int RxTestIt(struct chan_usbradio_pvt *o)
03716 {
03717 const int numSamples = SAMPLES_PER_BLOCK;
03718 const int numChannels = 16;
03719
03720 i16 sample,i,ii;
03721
03722 i32 txHangTime;
03723
03724 i16 txEnable;
03725
03726 t_pmr_chan tChan;
03727 t_pmr_chan *pChan;
03728
03729 FILE *hInput=NULL, *hOutput=NULL, *hOutputTx=NULL;
03730
03731 i16 iBuff[numSamples*2*6], oBuff[numSamples];
03732
03733 printf("RxTestIt()\n");
03734
03735 pChan=o->pmrChan;
03736 pChan->b.txCapture=1;
03737 pChan->b.rxCapture=1;
03738
03739 txEnable = 0;
03740
03741 hInput = fopen("/usr/src/xpmr/testdata/rx_in.pcm","r");
03742 if(!hInput){
03743 printf(" RxTestIt() File Not Found.\n");
03744 return 0;
03745 }
03746 hOutput = fopen("/usr/src/xpmr/testdata/rx_debug.pcm","w");
03747
03748 printf(" RxTestIt() Working...\n");
03749
03750 while(!feof(hInput))
03751 {
03752 fread((void *)iBuff,2,numSamples*2*6,hInput);
03753
03754 if(txHangTime)txHangTime-=numSamples;
03755 if(txHangTime<0)txHangTime=0;
03756
03757 if(pChan->rxCtcss->decode)txHangTime=(8000/1000*2000);
03758
03759 if(pChan->rxCtcss->decode && !txEnable)
03760 {
03761 txEnable=1;
03762
03763 }
03764 else if(!pChan->rxCtcss->decode && txEnable)
03765 {
03766 txEnable=0;
03767 }
03768
03769 PmrRx(pChan,iBuff,oBuff);
03770
03771 if (fwrite((void *)pChan->prxDebug,2,numSamples*numChannels,hOutput) != numSamples * numChannels) {
03772 ast_log(LOG_ERROR, "fwrite() failed: %s\n", strerror(errno));
03773 }
03774 }
03775 pChan->b.txCapture=0;
03776 pChan->b.rxCapture=0;
03777
03778 if(hInput)fclose(hInput);
03779 if(hOutput)fclose(hOutput);
03780
03781 printf(" RxTestIt() Complete.\n");
03782
03783 return 0;
03784 }
03785 #endif
03786
03787 #ifdef NEW_ASTERISK
03788
03789 static char *res2cli(int r)
03790
03791 {
03792 switch (r)
03793 {
03794 case RESULT_SUCCESS:
03795 return(CLI_SUCCESS);
03796 case RESULT_SHOWUSAGE:
03797 return(CLI_SHOWUSAGE);
03798 default:
03799 return(CLI_FAILURE);
03800 }
03801 }
03802
03803 static char *handle_console_key(struct ast_cli_entry *e,
03804 int cmd, struct ast_cli_args *a)
03805 {
03806 char *argv[] = { "radio", "key", NULL };
03807
03808 switch (cmd) {
03809 case CLI_INIT:
03810 e->command = "radio key";
03811 e->usage = key_usage;
03812 return NULL;
03813 case CLI_GENERATE:
03814 return NULL;
03815 }
03816 return res2cli(console_key(a->fd, 2, argv));
03817 }
03818
03819 static char *handle_console_unkey(struct ast_cli_entry *e,
03820 int cmd, struct ast_cli_args *a)
03821 {
03822 char *argv[] = { "radio", "unkey", NULL };
03823 switch (cmd) {
03824 case CLI_INIT:
03825 e->command = "radio unkey";
03826 e->usage = unkey_usage;
03827 return NULL;
03828 case CLI_GENERATE:
03829 return NULL;
03830 }
03831 return res2cli(console_unkey(a->fd, 2, argv));
03832 }
03833
03834 static char *handle_radio_tune(struct ast_cli_entry *e,
03835 int cmd, struct ast_cli_args *a)
03836 {
03837 char *argv[5] = { "radio", "tune", a->argc > 2 ? (char *) a->argv[2] : NULL, a->argc > 3 ? (char *) a->argv[3] : NULL };
03838 switch (cmd) {
03839 case CLI_INIT:
03840 e->command = "radio tune";
03841 e->usage = radio_tune_usage;
03842 return NULL;
03843 case CLI_GENERATE:
03844 return NULL;
03845 }
03846 return res2cli(radio_tune(a->fd, a->argc, argv));
03847 }
03848
03849 static char *handle_radio_debug(struct ast_cli_entry *e,
03850 int cmd, struct ast_cli_args *a)
03851 {
03852 switch (cmd) {
03853 case CLI_INIT:
03854 e->command = "radio debug";
03855 e->usage = radio_tune_usage;
03856 return NULL;
03857 case CLI_GENERATE:
03858 return NULL;
03859 }
03860 return res2cli(radio_set_debug(a->fd, a->argc, NULL ));
03861 }
03862
03863 static char *handle_radio_debug_off(struct ast_cli_entry *e,
03864 int cmd, struct ast_cli_args *a)
03865 {
03866 switch (cmd) {
03867 case CLI_INIT:
03868 e->command = "radio debug off";
03869 e->usage = radio_tune_usage;
03870 return NULL;
03871 case CLI_GENERATE:
03872 return NULL;
03873 }
03874 return res2cli(radio_set_debug_off(a->fd, a->argc, NULL ));
03875 }
03876
03877 static char *handle_radio_active(struct ast_cli_entry *e,
03878 int cmd, struct ast_cli_args *a)
03879 {
03880 char *argv[4] = { "radio", "active", a->argc > 2 ? (char *) a->argv[2] : NULL, };
03881 switch (cmd) {
03882 case CLI_INIT:
03883 e->command = "radio active";
03884 e->usage = active_usage;
03885 return NULL;
03886 case CLI_GENERATE:
03887 return NULL;
03888 }
03889 return res2cli(radio_active(a->fd, a->argc, argv));
03890 }
03891
03892 static char *handle_set_xdebug(struct ast_cli_entry *e,
03893 int cmd, struct ast_cli_args *a)
03894 {
03895 char *argv[5] = { "radio", "set", "xdebug", a->argc == 4 ? (char *) a->argv[3] : NULL, };
03896 switch (cmd) {
03897 case CLI_INIT:
03898 e->command = "radio set xdebug";
03899 e->usage = active_usage;
03900 return NULL;
03901 case CLI_GENERATE:
03902 return NULL;
03903 }
03904 return res2cli(radio_set_xpmr_debug(a->fd, a->argc, argv));
03905 }
03906
03907
03908 static struct ast_cli_entry cli_usbradio[] = {
03909 AST_CLI_DEFINE(handle_console_key,"Simulate Rx Signal Present"),
03910 AST_CLI_DEFINE(handle_console_unkey,"Simulate Rx Signal Loss"),
03911 AST_CLI_DEFINE(handle_radio_tune,"Radio Tune"),
03912 AST_CLI_DEFINE(handle_radio_debug,"Radio Debug On"),
03913 AST_CLI_DEFINE(handle_radio_debug_off,"Radio Debug Off"),
03914 AST_CLI_DEFINE(handle_radio_active,"Change commanded device"),
03915 AST_CLI_DEFINE(handle_set_xdebug,"Radio set xpmr debug level")
03916 };
03917
03918 #endif
03919
03920 #include "./xpmr/xpmr.c"
03921 #ifdef HAVE_XPMRX
03922 #include "./xpmrx/xpmrx.c"
03923 #endif
03924
03925
03926
03927 static int load_module(void)
03928 {
03929 struct ast_config *cfg = NULL;
03930 char *ctg = NULL;
03931 #ifdef NEW_ASTERISK
03932 struct ast_flags zeroflag = {0};
03933 #endif
03934
03935 if (hid_device_mklist()) {
03936 ast_log(LOG_NOTICE, "Unable to make hid list\n");
03937 return AST_MODULE_LOAD_DECLINE;
03938 }
03939
03940 usb_list_check("");
03941
03942 usbradio_active = NULL;
03943
03944
03945 memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
03946
03947
03948 #ifdef NEW_ASTERISK
03949 if (!(cfg = ast_config_load(config,zeroflag)) || cfg == CONFIG_STATUS_FILEINVALID) {
03950 #else
03951 if (!(cfg = ast_config_load(config))) || cfg == CONFIG_STATUS_FILEINVALID {
03952 #endif
03953 ast_log(LOG_NOTICE, "Unable to load config %s\n", config);
03954 return AST_MODULE_LOAD_DECLINE;
03955 }
03956
03957 do {
03958 store_config(cfg, ctg);
03959 } while ( (ctg = ast_category_browse(cfg, ctg)) != NULL);
03960
03961 ast_config_destroy(cfg);
03962
03963 if (find_desc(usbradio_active) == NULL) {
03964 ast_log(LOG_NOTICE, "radio active device %s not found\n", usbradio_active);
03965
03966
03967 return AST_MODULE_LOAD_DECLINE;
03968 }
03969
03970 if (ast_channel_register(&usbradio_tech)) {
03971 ast_log(LOG_ERROR, "Unable to register channel type 'usb'\n");
03972 return AST_MODULE_LOAD_DECLINE;
03973 }
03974
03975 ast_cli_register_multiple(cli_usbradio, ARRAY_LEN(cli_usbradio));
03976
03977 return AST_MODULE_LOAD_SUCCESS;
03978 }
03979
03980
03981 static int unload_module(void)
03982 {
03983 struct chan_usbradio_pvt *o;
03984
03985 ast_log(LOG_WARNING, "unload_module() called\n");
03986
03987 ast_channel_unregister(&usbradio_tech);
03988 ast_cli_unregister_multiple(cli_usbradio, ARRAY_LEN(cli_usbradio));
03989
03990 for (o = usbradio_default.next; o; o = o->next) {
03991
03992 ast_log(LOG_WARNING, "destroyPmrChannel() called\n");
03993 if(o->pmrChan)destroyPmrChannel(o->pmrChan);
03994
03995 #if DEBUG_CAPTURES == 1
03996 if (frxcapraw) { fclose(frxcapraw); frxcapraw = NULL; }
03997 if (frxcaptrace) { fclose(frxcaptrace); frxcaptrace = NULL; }
03998 if (frxoutraw) { fclose(frxoutraw); frxoutraw = NULL; }
03999 if (ftxcapraw) { fclose(ftxcapraw); ftxcapraw = NULL; }
04000 if (ftxcaptrace) { fclose(ftxcaptrace); ftxcaptrace = NULL; }
04001 if (ftxoutraw) { fclose(ftxoutraw); ftxoutraw = NULL; }
04002 #endif
04003
04004 close(o->sounddev);
04005 #ifndef NEW_ASTERISK
04006 if (o->sndcmd[0] > 0) {
04007 close(o->sndcmd[0]);
04008 close(o->sndcmd[1]);
04009 }
04010 #endif
04011 if (o->dsp) ast_dsp_free(o->dsp);
04012 if (o->owner)
04013 ast_softhangup(o->owner, AST_SOFTHANGUP_APPUNLOAD);
04014 if (o->owner)
04015 return -1;
04016
04017
04018 }
04019 return 0;
04020 }
04021
04022 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "usb Console Channel Driver");
04023
04024
04025
04026