Merged revisions 126573 via svnmerge from
[asterisk-bristuff.git] / apps / app_rpt.c
blob707c4e169e331aa1e257fc314b049bded367c558
1 #define NEW_ASTERISK
2 /* #define OLD_ASTERISK */
3 /*
4 * Asterisk -- An open source telephony toolkit.
6 * Copyright (C) 2002-2008, Jim Dixon, WB6NIL
8 * Jim Dixon, WB6NIL <jim@lambdatel.com>
9 * Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
11 * See http://www.asterisk.org for more information about
12 * the Asterisk project. Please do not directly contact
13 * any of the maintainers of this project for assistance;
14 * the project provides a web site, mailing lists and IRC
15 * channels for your use.
17 * This program is free software, distributed under the terms of
18 * the GNU General Public License Version 2. See the LICENSE file
19 * at the top of the source tree.
21 /*! \file
23 * \brief Radio Repeater / Remote Base program
24 * version 0.115 5/12/08 2055 EDT
26 * \author Jim Dixon, WB6NIL <jim@lambdatel.com>
28 * \note Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
29 * \note Steven Henke, W9SH, <w9sh@arrl.net> added a few features here and there.
31 * See http://www.zapatatelephony.org/app_rpt.html
34 * Repeater / Remote Functions:
35 * "Simple" Mode: * - autopatch access, # - autopatch hangup
36 * Normal mode:
37 * See the function list in rpt.conf (autopatchup, autopatchdn)
38 * autopatchup can optionally take comma delimited setting=value pairs:
41 * context=string : Override default context with "string"
42 * dialtime=ms : Specify the max number of milliseconds between phone number digits (1000 milliseconds = 1 second)
43 * farenddisconnect=1 : Automatically disconnect when called party hangs up
44 * noct=1 : Don't send repeater courtesy tone during autopatch calls
45 * quiet=1 : Don't send dial tone, or connect messages. Do not send patch down message when called party hangs up
48 * Example: 123=autopatchup,dialtime=20000,noct=1,farenddisconnect=1
50 * To send an asterisk (*) while dialing or talking on phone,
51 * use the autopatch acess code.
54 * status cmds:
56 * 1 - Force ID (global)
57 * 2 - Give Time of Day (global)
58 * 3 - Give software Version (global)
59 * 11 - Force ID (local only)
60 * 12 - Give Time of Day (local only)
62 * cop (control operator) cmds:
64 * 1 - System warm boot
65 * 2 - System enable
66 * 3 - System disable
67 * 4 - Test Tone On/Off
68 * 5 - Dump System Variables on Console (debug)
69 * 6 - PTT (phone mode only)
70 * 7 - Time out timer enable
71 * 8 - Time out timer disable
72 * 9 - Autopatch enable
73 * 10 - Autopatch disable
74 * 11 - Link enable
75 * 12 - Link disable
76 * 13 - Query System State
77 * 14 - Change System State
78 * 15 - Scheduler Enable
79 * 16 - Scheduler Disable
80 * 17 - User functions (time, id, etc) enable
81 * 18 - User functions (time, id, etc) disable
82 * 19 - Select alternate hang timer
83 * 20 - Select standard hang timer
84 * 21 - Enable Parrot Mode
85 * 22 - Disable Parrot Mode
86 * 23 - Birdbath (Current Parrot Cleanup/Flush)
87 * 24 - Flush all telemetry
88 * 25 - Query last node un-keyed
89 * 26 - Query all nodes keyed/unkeyed
90 * 30 - Recall Memory Setting in Attached Xcvr
91 * 31 - Channel Selector for Parallel Programmed Xcvr
92 * 32 - Touchtone pad test: command + Digit string + # to playback all digits pressed
94 * ilink cmds:
96 * 1 - Disconnect specified link
97 * 2 - Connect specified link -- monitor only
98 * 3 - Connect specified link -- tranceive
99 * 4 - Enter command mode on specified link
100 * 5 - System status
101 * 6 - Disconnect all links
102 * 11 - Disconnect a previously permanently connected link
103 * 12 - Permanently connect specified link -- monitor only
104 * 13 - Permanently connect specified link -- tranceive
105 * 15 - Full system status (all nodes)
106 * 16 - Reconnect links disconnected with "disconnect all links"
107 * 200 thru 215 - (Send DTMF 0-9,*,#,A-D) (200=0, 201=1, 210=*, etc)
109 * remote cmds:
111 * 1 - Recall Memory MM (*000-*099) (Gets memory from rpt.conf)
112 * 2 - Set VFO MMMMM*KKK*O (Mhz digits, Khz digits, Offset)
113 * 3 - Set Rx PL Tone HHH*D*
114 * 4 - Set Tx PL Tone HHH*D* (Not currently implemented with DHE RBI-1)
115 * 5 - Link Status (long)
116 * 6 - Set operating mode M (FM, USB, LSB, AM, etc)
117 * 100 - RX PL off (Default)
118 * 101 - RX PL On
119 * 102 - TX PL Off (Default)
120 * 103 - TX PL On
121 * 104 - Low Power
122 * 105 - Med Power
123 * 106 - Hi Power
124 * 107 - Bump Down 20 Hz
125 * 108 - Bump Down 100 Hz
126 * 109 - Bump Down 500 Hz
127 * 110 - Bump Up 20 Hz
128 * 111 - Bump Up 100 Hz
129 * 112 - Bump Up 500 Hz
130 * 113 - Scan Down Slow
131 * 114 - Scan Down Medium
132 * 115 - Scan Down Fast
133 * 116 - Scan Up Slow
134 * 117 - Scan Up Medium
135 * 118 - Scan Up Fast
136 * 119 - Transmit allowing auto-tune
137 * 140 - Link Status (brief)
138 * 200 thru 215 - (Send DTMF 0-9,*,#,A-D) (200=0, 201=1, 210=*, etc)
140 * playback cmds:
141 * specify the name of the file to be played (for example, 25=rpt/foo)
144 * 'duplex' modes: (defaults to duplex=2)
146 * 0 - Only remote links key Tx and no main repeat audio.
147 * 1 - Everything other then main Rx keys Tx, no main repeat audio.
148 * 2 - Normal mode
149 * 3 - Normal except no main repeat audio.
150 * 4 - Normal except no main repeat audio during autopatch only
154 /*** MODULEINFO
155 <depend>dahdi</depend>
156 <depend>tonezone</depend>
157 <defaultenabled>no</defaultenabled>
158 ***/
160 /* Un-comment the following to include support for MDC-1200 digital tone
161 signalling protocol (using KA6SQG's GPL'ed implementation) */
162 /* #include "mdc_decode.c" */
164 /* Un-comment the following to include support for notch filters in the
165 rx audio stream (using Tony Fisher's mknotch (mkfilter) implementation) */
166 /* #include "rpt_notch.c" */
168 /* maximum digits in DTMF buffer, and seconds after * for DTMF command timeout */
170 #ifdef OLD_ASTERISK
171 #define ast_free free
172 #define ast_malloc malloc
173 #define ast_strdup strdup
174 #endif
177 #define MAXDTMF 32
178 #define MAXMACRO 2048
179 #define MAXLINKLIST 512
180 #define LINKLISTTIME 10000
181 #define LINKLISTSHORTTIME 200
182 #define LINKPOSTTIME 30000
183 #define LINKPOSTSHORTTIME 200
184 #define KEYPOSTTIME 30000
185 #define KEYPOSTSHORTTIME 200
186 #define MACROTIME 100
187 #define MACROPTIME 500
188 #define DTMF_TIMEOUT 3
189 #define KENWOOD_RETRIES 5
190 #define TOPKEYN 32
191 #define TOPKEYWAIT 3
192 #define TOPKEYMAXSTR 30
194 #define AUTHTELLTIME 7000
195 #define AUTHTXTIME 1000
196 #define AUTHLOGOUTTIME 25000
198 #ifdef __RPT_NOTCH
199 #define MAXFILTERS 10
200 #endif
202 #define DISC_TIME 10000 /* report disc after 10 seconds of no connect */
203 #define MAX_RETRIES 5
204 #define MAX_RETRIES_PERM 1000000000
206 #define REDUNDANT_TX_TIME 2000
208 #define RETRY_TIMER_MS 5000
210 #define PATCH_DIALPLAN_TIMEOUT 1500
212 #ifdef OLD_ASTERISK
213 #define START_DELAY 10
214 #else
215 #define START_DELAY 2
216 #endif
218 #define RPT_LOCKOUT_SECS 10
220 #define MAXPEERSTR 31
221 #define MAXREMSTR 15
223 #define DELIMCHR ','
224 #define QUOTECHR 34
226 #define MONITOR_DISK_BLOCKS_PER_MINUTE 38
228 #define DEFAULT_MONITOR_MIN_DISK_BLOCKS 10000
229 #define DEFAULT_REMOTE_INACT_TIMEOUT (15 * 60)
230 #define DEFAULT_REMOTE_TIMEOUT (60 * 60)
231 #define DEFAULT_REMOTE_TIMEOUT_WARNING (3 * 60)
232 #define DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ 30
234 #define NODES "nodes"
235 #define EXTNODES "extnodes"
236 #define MEMORY "memory"
237 #define MACRO "macro"
238 #define FUNCTIONS "functions"
239 #define TELEMETRY "telemetry"
240 #define MORSE "morse"
241 #define TONEMACRO "tonemacro"
242 #define FUNCCHAR '*'
243 #define ENDCHAR '#'
244 #define EXTNODEFILE "/var/lib/asterisk/rpt_extnodes"
245 #define NODENAMES "rpt/nodenames"
246 #define PARROTFILE "/tmp/parrot_%s_%u"
248 #define PARROTTIME 1000
250 #define DEFAULT_IOBASE 0x378
252 #define DEFAULT_CIV_ADDR 0x58
254 #define MAXCONNECTTIME 5000
256 #define MAXNODESTR 300
258 #define MAXNODELEN 16
260 #define MAXIDENTLEN 32
262 #define MAXPATCHCONTEXT 100
264 #define ACTIONSIZE 32
266 #define TELEPARAMSIZE 256
268 #define REM_SCANTIME 100
270 #define DTMF_LOCAL_TIME 250
271 #define DTMF_LOCAL_STARTTIME 500
273 #define IC706_PL_MEMORY_OFFSET 50
275 #define VOX_ON_DEBOUNCE_COUNT 3
276 #define VOX_OFF_DEBOUNCE_COUNT 20
277 #define VOX_MAX_THRESHOLD 10000.0
278 #define VOX_MIN_THRESHOLD 3000.0
279 #define VOX_TIMEOUT_MS 5000
280 #define VOX_RECOVER_MS 500
281 #define SIMPLEX_PATCH_DELAY 25
282 #define SIMPLEX_PHONE_DELAY 25
284 #define STATPOST_PROGRAM "/usr/bin/wget,-q,--output-document=/dev/null,--no-check-certificate"
286 #define ALLOW_LOCAL_CHANNELS
288 enum {REM_OFF,REM_MONITOR,REM_TX};
290 enum{ID,PROC,TERM,COMPLETE,UNKEY,REMDISC,REMALREADY,REMNOTFOUND,REMGO,
291 CONNECTED,CONNFAIL,STATUS,TIMEOUT,ID1, STATS_TIME, PLAYBACK,
292 STATS_VERSION, IDTALKOVER, ARB_ALPHA, TEST_TONE, REV_PATCH,
293 TAILMSG, MACRO_NOTFOUND, MACRO_BUSY, LASTNODEKEY, FULLSTATUS,
294 MEMNOTFOUND, INVFREQ, REMMODE, REMLOGIN, REMXXX, REMSHORTSTATUS,
295 REMLONGSTATUS, LOGINREQ, SCAN, SCANSTAT, TUNE, SETREMOTE, TOPKEY,
296 TIMEOUT_WARNING, ACT_TIMEOUT_WARNING, LINKUNKEY, UNAUTHTX, PARROT,
297 STATS_TIME_LOCAL};
300 enum {REM_SIMPLEX,REM_MINUS,REM_PLUS};
302 enum {REM_LOWPWR,REM_MEDPWR,REM_HIPWR};
304 enum {DC_INDETERMINATE, DC_REQ_FLUSH, DC_ERROR, DC_COMPLETE, DC_COMPLETEQUIET, DC_DOKEY};
306 enum {SOURCE_RPT, SOURCE_LNK, SOURCE_RMT, SOURCE_PHONE, SOURCE_DPHONE, SOURCE_ALT};
308 enum {DLY_TELEM, DLY_ID, DLY_UNKEY, DLY_CALLTERM, DLY_COMP, DLY_LINKUNKEY, DLY_PARROT};
310 enum {REM_MODE_FM,REM_MODE_USB,REM_MODE_LSB,REM_MODE_AM};
312 enum {HF_SCAN_OFF,HF_SCAN_DOWN_SLOW,HF_SCAN_DOWN_QUICK,
313 HF_SCAN_DOWN_FAST,HF_SCAN_UP_SLOW,HF_SCAN_UP_QUICK,HF_SCAN_UP_FAST};
315 #include "asterisk.h"
317 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
319 #include <signal.h>
320 #include <stdio.h>
321 #include <unistd.h>
322 #include <string.h>
323 #include <stdlib.h>
324 #include <search.h>
325 #include <sys/types.h>
326 #include <sys/stat.h>
327 #include <errno.h>
328 #include <dirent.h>
329 #include <ctype.h>
330 #include <sys/stat.h>
331 #include <sys/time.h>
332 #include <sys/file.h>
333 #include <sys/ioctl.h>
334 #include <sys/io.h>
335 #include <sys/vfs.h>
336 #include <math.h>
337 #include <dahdi/user.h>
338 #include <dahdi/tonezone.h>
339 #include <netinet/in.h>
340 #include <arpa/inet.h>
342 #include "asterisk/utils.h"
343 #include "asterisk/lock.h"
344 #include "asterisk/file.h"
345 #include "asterisk/logger.h"
346 #include "asterisk/channel.h"
347 #include "asterisk/callerid.h"
348 #include "asterisk/pbx.h"
349 #include "asterisk/module.h"
350 #include "asterisk/translate.h"
351 #include "asterisk/features.h"
352 #include "asterisk/options.h"
353 #include "asterisk/cli.h"
354 #include "asterisk/config.h"
355 #include "asterisk/say.h"
356 #include "asterisk/localtime.h"
357 #include "asterisk/cdr.h"
358 #include "asterisk/options.h"
359 #include "asterisk/manager.h"
360 #include <termios.h>
362 #ifdef NEW_ASTERISK
363 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
364 #endif
367 /* Start a tone-list going */
368 int ast_playtones_start(struct ast_channel *chan, int vol, const char* tonelist, int interruptible);
369 /*! Stop the tones from playing */
370 void ast_playtones_stop(struct ast_channel *chan);
372 static char *tdesc = "Radio Repeater / Remote Base version 0.115 5/12/2008";
374 static char *app = "Rpt";
376 static char *synopsis = "Radio Repeater/Remote Base Control System";
378 static char *descrip =
379 " Rpt(nodename[|options][|M][|*]): \n"
380 " Radio Remote Link or Remote Base Link Endpoint Process.\n"
381 "\n"
382 " Not specifying an option puts it in normal endpoint mode (where source\n"
383 " IP and nodename are verified).\n"
384 "\n"
385 " Options are as follows:\n"
386 "\n"
387 " X - Normal endpoint mode WITHOUT security check. Only specify\n"
388 " this if you have checked security already (like with an IAX2\n"
389 " user/password or something).\n"
390 "\n"
391 " Rannounce-string[|timeout[|timeout-destination]] - Amateur Radio\n"
392 " Reverse Autopatch. Caller is put on hold, and announcement (as\n"
393 " specified by the 'announce-string') is played on radio system.\n"
394 " Users of radio system can access autopatch, dial specified\n"
395 " code, and pick up call. Announce-string is list of names of\n"
396 " recordings, or \"PARKED\" to substitute code for un-parking,\n"
397 " or \"NODE\" to substitute node number.\n"
398 "\n"
399 " P - Phone Control mode. This allows a regular phone user to have\n"
400 " full control and audio access to the radio system. For the\n"
401 " user to have DTMF control, the 'phone_functions' parameter\n"
402 " must be specified for the node in 'rpt.conf'. An additional\n"
403 " function (cop,6) must be listed so that PTT control is available.\n"
404 "\n"
405 " D - Dumb Phone Control mode. This allows a regular phone user to\n"
406 " have full control and audio access to the radio system. In this\n"
407 " mode, the PTT is activated for the entire length of the call.\n"
408 " For the user to have DTMF control (not generally recomended in\n"
409 " this mode), the 'dphone_functions' parameter must be specified\n"
410 " for the node in 'rpt.conf'. Otherwise no DTMF control will be\n"
411 " available to the phone user.\n"
412 "\n"
413 " S - Simplex Dumb Phone Control mode. This allows a regular phone user\n"
414 " audio-only access to the radio system. In this mode, the\n"
415 " transmitter is toggled on and off when the phone user presses the\n"
416 " funcchar (*) key on the telephone set. In addition, the transmitter\n"
417 " will turn off if the endchar (#) key is pressed. When a user first\n"
418 " calls in, the transmitter will be off, and the user can listen for\n"
419 " radio traffic. When the user wants to transmit, they press the *\n"
420 " key, start talking, then press the * key again or the # key to turn\n"
421 " the transmitter off. No other functions can be executed by the\n"
422 " user on the phone when this mode is selected. Note: If your\n"
423 " radio system is full-duplex, we recommend using either P or D\n"
424 " modes as they provide more flexibility.\n"
425 "\n"
426 " q - Query Status. Sets channel variables and returns + 101 in plan.\n"
427 "\n"
428 " M - Memory Channel Steer as MXX where XX is the memory channel number.\n"
429 "\n"
430 " * - Alt Macro to execute (e.g. *7 for status)\n"
431 "\n";
434 static int debug = 0; /* Set this >0 for extra debug output */
435 static int nrpts = 0;
437 static char remdtmfstr[] = "0123456789*#ABCD";
439 enum {TOP_TOP,TOP_WON,WON_BEFREAD,BEFREAD_AFTERREAD};
441 int max_chan_stat [] = {22000,1000,22000,100,22000,2000,22000};
443 #define NRPTSTAT 7
445 struct rpt_chan_stat
447 struct timeval last;
448 long long total;
449 unsigned long count;
450 unsigned long largest;
451 struct timeval largest_time;
454 char *discstr = "!!DISCONNECT!!";
455 char *newkeystr = "!NEWKEY!";
456 static char *remote_rig_ft897="ft897";
457 static char *remote_rig_rbi="rbi";
458 static char *remote_rig_kenwood="kenwood";
459 static char *remote_rig_tm271="tm271";
460 static char *remote_rig_ic706="ic706";
461 static char *remote_rig_rtx150="rtx150";
462 static char *remote_rig_rtx450="rtx450";
463 static char *remote_rig_ppp16="ppp16"; // parallel port programmable 16 channels
465 #define ISRIG_RTX(x) ((!strcmp(x,remote_rig_rtx150)) || (!strcmp(x,remote_rig_rtx450)))
466 #define IS_XPMR(x) (!strncasecmp(x->rxchanname,"rad",3))
468 #ifdef OLD_ASTERISK
469 STANDARD_LOCAL_USER;
470 LOCAL_USER_DECL;
471 #endif
473 #define MSWAIT 200
474 #define HANGTIME 5000
475 #define TOTIME 180000
476 #define IDTIME 300000
477 #define MAXRPTS 20
478 #define MAX_STAT_LINKS 32
479 #define POLITEID 30000
480 #define FUNCTDELAY 1500
482 #define MAXXLAT 20
483 #define MAXXLATTIME 3
485 #define MAX_SYSSTATES 10
487 struct vox {
488 float speech_energy;
489 float noise_energy;
490 int enacount;
491 char voxena;
492 char lastvox;
493 int offdebcnt;
494 int ondebcnt;
497 #define mymax(x,y) ((x > y) ? x : y)
498 #define mymin(x,y) ((x < y) ? x : y)
500 struct rpt_topkey
502 char node[TOPKEYMAXSTR];
503 int timesince;
504 int keyed;
507 struct rpt_xlat
509 char funccharseq[MAXXLAT];
510 char endcharseq[MAXXLAT];
511 char passchars[MAXXLAT];
512 int funcindex;
513 int endindex;
514 time_t lastone;
517 static time_t starttime = 0;
519 static pthread_t rpt_master_thread;
521 struct rpt;
523 struct rpt_link
525 struct rpt_link *next;
526 struct rpt_link *prev;
527 char mode; /* 1 if in tx mode */
528 char isremote;
529 char phonemode;
530 char phonevox; /* vox the phone */
531 char name[MAXNODESTR]; /* identifier (routing) string */
532 char lasttx;
533 char lasttx1;
534 char lastrx;
535 char lastrealrx;
536 char lastrx1;
537 char connected;
538 char hasconnected;
539 char perma;
540 char thisconnected;
541 char outbound;
542 char disced;
543 char killme;
544 long elaptime;
545 long disctime;
546 long retrytimer;
547 long retxtimer;
548 long rerxtimer;
549 int retries;
550 int max_retries;
551 int reconnects;
552 long long connecttime;
553 struct ast_channel *chan;
554 struct ast_channel *pchan;
555 char linklist[MAXLINKLIST];
556 time_t linklistreceived;
557 long linklisttimer;
558 int dtmfed;
559 int linkunkeytocttimer;
560 struct timeval lastlinktv;
561 struct ast_frame *lastf1,*lastf2;
562 struct rpt_chan_stat chan_stat[NRPTSTAT];
563 struct vox vox;
564 char wasvox;
565 int voxtotimer;
566 char voxtostate;
567 char newkey;
568 #ifdef OLD_ASTERISK
569 AST_LIST_HEAD(, ast_frame) rxq;
570 #else
571 AST_LIST_HEAD_NOLOCK(, ast_frame) rxq;
572 #endif
575 struct rpt_lstat
577 struct rpt_lstat *next;
578 struct rpt_lstat *prev;
579 char peer[MAXPEERSTR];
580 char name[MAXNODESTR];
581 char mode;
582 char outbound;
583 char reconnects;
584 char thisconnected;
585 long long connecttime;
586 struct rpt_chan_stat chan_stat[NRPTSTAT];
589 struct rpt_tele
591 struct rpt_tele *next;
592 struct rpt_tele *prev;
593 struct rpt *rpt;
594 struct ast_channel *chan;
595 int mode;
596 struct rpt_link mylink;
597 char param[TELEPARAMSIZE];
598 int submode;
599 unsigned int parrot;
600 pthread_t threadid;
603 struct function_table_tag
605 char action[ACTIONSIZE];
606 int (*function)(struct rpt *myrpt, char *param, char *digitbuf,
607 int command_source, struct rpt_link *mylink);
610 /* Used to store the morse code patterns */
612 struct morse_bits
614 int len;
615 int ddcomb;
618 struct telem_defaults
620 char name[20];
621 char value[80];
625 struct sysstate
627 char txdisable;
628 char totdisable;
629 char linkfundisable;
630 char autopatchdisable;
631 char schedulerdisable;
632 char userfundisable;
633 char alternatetail;
636 /* rpt cmd support */
637 #define CMD_DEPTH 1
638 #define CMD_STATE_IDLE 0
639 #define CMD_STATE_BUSY 1
640 #define CMD_STATE_READY 2
641 #define CMD_STATE_EXECUTING 3
643 struct rpt_cmd_struct
645 int state;
646 int functionNumber;
647 char param[MAXDTMF];
648 char digits[MAXDTMF];
649 int command_source;
652 static struct rpt
654 ast_mutex_t lock;
655 ast_mutex_t remlock;
656 ast_mutex_t statpost_lock;
657 struct ast_config *cfg;
658 char reload;
659 char xlink; // cross link state of a share repeater/remote radio
660 unsigned int statpost_seqno;
662 char *name;
663 char *rxchanname;
664 char *txchanname;
665 char remote;
666 char *remoterig;
667 struct rpt_chan_stat chan_stat[NRPTSTAT];
668 unsigned int scram;
670 struct {
671 char *ourcontext;
672 char *ourcallerid;
673 char *acctcode;
674 char *ident;
675 char *tonezone;
676 char simple;
677 char *functions;
678 char *link_functions;
679 char *phone_functions;
680 char *dphone_functions;
681 char *alt_functions;
682 char *nodes;
683 char *extnodes;
684 char *extnodefile;
685 int hangtime;
686 int althangtime;
687 int totime;
688 int idtime;
689 int tailmessagetime;
690 int tailsquashedtime;
691 int duplex;
692 int politeid;
693 char *tailmessages[500];
694 int tailmessagemax;
695 char *memory;
696 char *macro;
697 char *tonemacro;
698 char *startupmacro;
699 int iobase;
700 char *ioport;
701 char funcchar;
702 char endchar;
703 char nobusyout;
704 char notelemtx;
705 char propagate_dtmf;
706 char propagate_phonedtmf;
707 char linktolink;
708 unsigned char civaddr;
709 struct rpt_xlat inxlat;
710 struct rpt_xlat outxlat;
711 char *archivedir;
712 int authlevel;
713 char *csstanzaname;
714 char *skedstanzaname;
715 char *txlimitsstanzaname;
716 long monminblocks;
717 int remoteinacttimeout;
718 int remotetimeout;
719 int remotetimeoutwarning;
720 int remotetimeoutwarningfreq;
721 int sysstate_cur;
722 struct sysstate s[MAX_SYSSTATES];
723 char parrotmode;
724 int parrottime;
725 char *rptnode;
726 char remote_mars;
727 int voxtimeout_ms;
728 int voxrecover_ms;
729 int simplexpatchdelay;
730 int simplexphonedelay;
731 char *statpost_program;
732 char *statpost_url;
733 } p;
734 struct rpt_link links;
735 int unkeytocttimer;
736 time_t lastkeyedtime;
737 time_t lasttxkeyedtime;
738 char keyed;
739 char txkeyed;
740 char exttx;
741 char localtx;
742 char remoterx;
743 char remotetx;
744 char remoteon;
745 char remtxfreqok;
746 char tounkeyed;
747 char tonotify;
748 char dtmfbuf[MAXDTMF];
749 char macrobuf[MAXMACRO];
750 char rem_dtmfbuf[MAXDTMF];
751 char lastdtmfcommand[MAXDTMF];
752 char cmdnode[50];
753 char nowchan; // channel now
754 char waschan; // channel selected initially or by command
755 char bargechan; // barge in channel
756 char macropatch; // autopatch via tonemacro state
757 char parrotstate;
758 int parrottimer;
759 unsigned int parrotcnt;
760 struct ast_channel *rxchannel,*txchannel, *monchannel, *parrotchannel;
761 struct ast_channel *pchannel,*txpchannel, *dahdirxchannel, *dahditxchannel;
762 struct ast_channel *voxchannel;
763 struct ast_frame *lastf1,*lastf2;
764 struct rpt_tele tele;
765 struct timeval lasttv,curtv;
766 pthread_t rpt_call_thread,rpt_thread;
767 time_t dtmf_time,rem_dtmf_time,dtmf_time_rem;
768 int calldigittimer;
769 int tailtimer,totimer,idtimer,txconf,conf,callmode,cidx,scantimer,tmsgtimer,skedtimer;
770 int mustid,tailid;
771 int tailevent;
772 int telemrefcount;
773 int dtmfidx,rem_dtmfidx;
774 int dailytxtime,dailykerchunks,totalkerchunks,dailykeyups,totalkeyups,timeouts;
775 int totalexecdcommands, dailyexecdcommands;
776 long retxtimer;
777 long rerxtimer;
778 long long totaltxtime;
779 char mydtmf;
780 char exten[AST_MAX_EXTENSION];
781 char freq[MAXREMSTR],rxpl[MAXREMSTR],txpl[MAXREMSTR];
782 char offset;
783 char powerlevel;
784 char txplon;
785 char rxplon;
786 char remmode;
787 char tunerequest;
788 char hfscanmode;
789 int hfscanstatus;
790 char hfscanstop;
791 char lastlinknode[MAXNODESTR];
792 char savednodes[MAXNODESTR];
793 int stopgen;
794 char patchfarenddisconnect;
795 char patchnoct;
796 char patchquiet;
797 char patchcontext[MAXPATCHCONTEXT];
798 int patchdialtime;
799 int macro_longest;
800 int phone_longestfunc;
801 int alt_longestfunc;
802 int dphone_longestfunc;
803 int link_longestfunc;
804 int longestfunc;
805 int longestnode;
806 int threadrestarts;
807 int tailmessagen;
808 time_t disgorgetime;
809 time_t lastthreadrestarttime;
810 long macrotimer;
811 char lastnodewhichkeyedusup[MAXNODESTR];
812 int dtmf_local_timer;
813 char dtmf_local_str[100];
814 struct ast_filestream *monstream,*parrotstream;
815 char loginuser[50];
816 char loginlevel[10];
817 long authtelltimer;
818 long authtimer;
819 int iofd;
820 time_t start_time,last_activity_time;
821 char lasttone[32];
822 struct rpt_tele *active_telem;
823 struct rpt_topkey topkey[TOPKEYN];
824 int topkeystate;
825 time_t topkeytime;
826 int topkeylong;
827 struct vox vox;
828 char wasvox;
829 int voxtotimer;
830 char voxtostate;
831 int linkposttimer;
832 int keyposttimer;
833 char newkey;
834 char inpadtest;
835 #ifdef OLD_ASTERISK
836 AST_LIST_HEAD(, ast_frame) txq;
837 #else
838 AST_LIST_HEAD_NOLOCK(, ast_frame) txq;
839 #endif
840 char txrealkeyed;
841 #ifdef __RPT_NOTCH
842 struct rptfilter
844 char desc[100];
845 float x0;
846 float x1;
847 float x2;
848 float y0;
849 float y1;
850 float y2;
851 float gain;
852 float const0;
853 float const1;
854 float const2;
855 } filters[MAXFILTERS];
856 #endif
857 #ifdef _MDC_DECODE_H_
858 mdc_decoder_t *mdc;
859 unsigned short lastunit;
860 #endif
861 struct rpt_cmd_struct cmdAction;
862 } rpt_vars[MAXRPTS];
864 struct nodelog {
865 struct nodelog *next;
866 struct nodelog *prev;
867 time_t timestamp;
868 char archivedir[MAXNODESTR];
869 char str[MAXNODESTR * 2];
870 } nodelog;
872 static int service_scan(struct rpt *myrpt);
873 static int set_mode_ft897(struct rpt *myrpt, char newmode);
874 static int set_mode_ic706(struct rpt *myrpt, char newmode);
875 static int simple_command_ft897(struct rpt *myrpt, char command);
876 static int setrem(struct rpt *myrpt);
877 static int setrtx_check(struct rpt *myrpt);
878 static int channel_revert(struct rpt *myrpt);
879 static int channel_steer(struct rpt *myrpt, char *data);
881 AST_MUTEX_DEFINE_STATIC(nodeloglock);
883 AST_MUTEX_DEFINE_STATIC(nodelookuplock);
885 #ifdef APP_RPT_LOCK_DEBUG
887 #warning COMPILING WITH LOCK-DEBUGGING ENABLED!!
889 #define MAXLOCKTHREAD 100
891 #define rpt_mutex_lock(x) _rpt_mutex_lock(x,myrpt,__LINE__)
892 #define rpt_mutex_unlock(x) _rpt_mutex_unlock(x,myrpt,__LINE__)
894 struct lockthread
896 pthread_t id;
897 int lockcount;
898 int lastlock;
899 int lastunlock;
900 } lockthreads[MAXLOCKTHREAD];
903 struct by_lightning
905 int line;
906 struct timeval tv;
907 struct rpt *rpt;
908 struct lockthread lockthread;
909 } lock_ring[32];
911 int lock_ring_index = 0;
913 AST_MUTEX_DEFINE_STATIC(locklock);
915 static struct lockthread *get_lockthread(pthread_t id)
917 int i;
919 for(i = 0; i < MAXLOCKTHREAD; i++)
921 if (lockthreads[i].id == id) return(&lockthreads[i]);
923 return(NULL);
926 static struct lockthread *put_lockthread(pthread_t id)
928 int i;
930 for(i = 0; i < MAXLOCKTHREAD; i++)
932 if (lockthreads[i].id == id)
933 return(&lockthreads[i]);
935 for(i = 0; i < MAXLOCKTHREAD; i++)
937 if (!lockthreads[i].id)
939 lockthreads[i].lockcount = 0;
940 lockthreads[i].lastlock = 0;
941 lockthreads[i].lastunlock = 0;
942 lockthreads[i].id = id;
943 return(&lockthreads[i]);
946 return(NULL);
950 static void rpt_mutex_spew(void)
952 struct by_lightning lock_ring_copy[32];
953 int lock_ring_index_copy;
954 int i,j;
955 long long diff;
956 char a[100];
957 struct timeval lasttv;
959 ast_mutex_lock(&locklock);
960 memcpy(&lock_ring_copy, &lock_ring, sizeof(lock_ring_copy));
961 lock_ring_index_copy = lock_ring_index;
962 ast_mutex_unlock(&locklock);
964 lasttv.tv_sec = lasttv.tv_usec = 0;
965 for(i = 0 ; i < 32 ; i++)
967 j = (i + lock_ring_index_copy) % 32;
968 strftime(a,sizeof(a) - 1,"%m/%d/%Y %H:%M:%S",
969 localtime(&lock_ring_copy[j].tv.tv_sec));
970 diff = 0;
971 if(lasttv.tv_sec)
973 diff = (lock_ring_copy[j].tv.tv_sec - lasttv.tv_sec)
974 * 1000000;
975 diff += (lock_ring_copy[j].tv.tv_usec - lasttv.tv_usec);
977 lasttv.tv_sec = lock_ring_copy[j].tv.tv_sec;
978 lasttv.tv_usec = lock_ring_copy[j].tv.tv_usec;
979 if (!lock_ring_copy[j].tv.tv_sec) continue;
980 if (lock_ring_copy[j].line < 0)
982 ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] UNLOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
983 i - 31,-lock_ring_copy[j].line,lock_ring_copy[j].rpt->name,(int) lock_ring_copy[j].lockthread.id,diff,a,(int)lock_ring_copy[j].tv.tv_usec);
985 else
987 ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] LOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
988 i - 31,lock_ring_copy[j].line,lock_ring_copy[j].rpt->name,(int) lock_ring_copy[j].lockthread.id,diff,a,(int)lock_ring_copy[j].tv.tv_usec);
994 static void _rpt_mutex_lock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
996 struct lockthread *t;
997 pthread_t id;
999 id = pthread_self();
1000 ast_mutex_lock(&locklock);
1001 t = put_lockthread(id);
1002 if (!t)
1004 ast_mutex_unlock(&locklock);
1005 return;
1007 if (t->lockcount)
1009 int lastline = t->lastlock;
1010 ast_mutex_unlock(&locklock);
1011 ast_log(LOG_NOTICE,"rpt_mutex_lock: Double lock request line %d node %s pid %x, last lock was line %d\n",line,myrpt->name,(int) t->id,lastline);
1012 rpt_mutex_spew();
1013 return;
1015 t->lastlock = line;
1016 t->lockcount = 1;
1017 gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
1018 lock_ring[lock_ring_index].rpt = myrpt;
1019 memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
1020 lock_ring[lock_ring_index++].line = line;
1021 if(lock_ring_index == 32)
1022 lock_ring_index = 0;
1023 ast_mutex_unlock(&locklock);
1024 ast_mutex_lock(lockp);
1028 static void _rpt_mutex_unlock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
1030 struct lockthread *t;
1031 pthread_t id;
1033 id = pthread_self();
1034 ast_mutex_lock(&locklock);
1035 t = put_lockthread(id);
1036 if (!t)
1038 ast_mutex_unlock(&locklock);
1039 return;
1041 if (!t->lockcount)
1043 int lastline = t->lastunlock;
1044 ast_mutex_unlock(&locklock);
1045 ast_log(LOG_NOTICE,"rpt_mutex_lock: Double un-lock request line %d node %s pid %x, last un-lock was line %d\n",line,myrpt->name,(int) t->id,lastline);
1046 rpt_mutex_spew();
1047 return;
1049 t->lastunlock = line;
1050 t->lockcount = 0;
1051 gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
1052 lock_ring[lock_ring_index].rpt = myrpt;
1053 memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
1054 lock_ring[lock_ring_index++].line = -line;
1055 if(lock_ring_index == 32)
1056 lock_ring_index = 0;
1057 ast_mutex_unlock(&locklock);
1058 ast_mutex_unlock(lockp);
1061 #else /* APP_RPT_LOCK_DEBUG */
1063 #define rpt_mutex_lock(x) ast_mutex_lock(x)
1064 #define rpt_mutex_unlock(x) ast_mutex_unlock(x)
1066 #endif /* APP_RPT_LOCK_DEBUG */
1069 * Return 1 if rig is multimode capable
1072 static int multimode_capable(struct rpt *myrpt)
1074 if(!strcmp(myrpt->remoterig, remote_rig_ft897))
1075 return 1;
1076 if(!strcmp(myrpt->remoterig, remote_rig_ic706))
1077 return 1;
1078 return 0;
1081 static void voxinit_rpt(struct rpt *myrpt,char enable)
1084 myrpt->vox.speech_energy = 0.0;
1085 myrpt->vox.noise_energy = 0.0;
1086 myrpt->vox.enacount = 0;
1087 myrpt->vox.voxena = 0;
1088 if (!enable) myrpt->vox.voxena = -1;
1089 myrpt->vox.lastvox = 0;
1090 myrpt->vox.ondebcnt = VOX_ON_DEBOUNCE_COUNT;
1091 myrpt->vox.offdebcnt = VOX_OFF_DEBOUNCE_COUNT;
1092 myrpt->wasvox = 0;
1093 myrpt->voxtotimer = 0;
1094 myrpt->voxtostate = 0;
1097 static void voxinit_link(struct rpt_link *mylink,char enable)
1100 mylink->vox.speech_energy = 0.0;
1101 mylink->vox.noise_energy = 0.0;
1102 mylink->vox.enacount = 0;
1103 mylink->vox.voxena = 0;
1104 if (!enable) mylink->vox.voxena = -1;
1105 mylink->vox.lastvox = 0;
1106 mylink->vox.ondebcnt = VOX_ON_DEBOUNCE_COUNT;
1107 mylink->vox.offdebcnt = VOX_OFF_DEBOUNCE_COUNT;
1108 mylink->wasvox = 0;
1109 mylink->voxtotimer = 0;
1110 mylink->voxtostate = 0;
1113 static int dovox(struct vox *v,short *buf,int bs)
1116 int i;
1117 float esquare = 0.0;
1118 float energy = 0.0;
1119 float threshold = 0.0;
1121 if (v->voxena < 0) return(v->lastvox);
1122 for(i = 0; i < bs; i++)
1124 esquare += (float) buf[i] * (float) buf[i];
1126 energy = sqrt(esquare);
1128 if (energy >= v->speech_energy)
1129 v->speech_energy += (energy - v->speech_energy) / 4;
1130 else
1131 v->speech_energy += (energy - v->speech_energy) / 64;
1133 if (energy >= v->noise_energy)
1134 v->noise_energy += (energy - v->noise_energy) / 64;
1135 else
1136 v->noise_energy += (energy - v->noise_energy) / 4;
1138 if (v->voxena) threshold = v->speech_energy / 8;
1139 else
1141 threshold = mymax(v->speech_energy / 16,v->noise_energy * 2);
1142 threshold = mymin(threshold,VOX_MAX_THRESHOLD);
1144 threshold = mymax(threshold,VOX_MIN_THRESHOLD);
1145 if (energy > threshold)
1147 if (v->voxena) v->noise_energy *= 0.75;
1148 v->voxena = 1;
1149 } else v->voxena = 0;
1150 if (v->lastvox != v->voxena)
1152 if (v->enacount++ >= ((v->lastvox) ? v->offdebcnt : v->ondebcnt))
1154 v->lastvox = v->voxena;
1155 v->enacount = 0;
1157 } else v->enacount = 0;
1158 return(v->lastvox);
1165 * CLI extensions
1168 /* Debug mode */
1169 static int rpt_do_debug(int fd, int argc, char *argv[]);
1170 static int rpt_do_dump(int fd, int argc, char *argv[]);
1171 static int rpt_do_stats(int fd, int argc, char *argv[]);
1172 static int rpt_do_lstats(int fd, int argc, char *argv[]);
1173 static int rpt_do_nodes(int fd, int argc, char *argv[]);
1174 static int rpt_do_local_nodes(int fd, int argc, char *argv[]);
1175 static int rpt_do_reload(int fd, int argc, char *argv[]);
1176 static int rpt_do_restart(int fd, int argc, char *argv[]);
1177 static int rpt_do_fun(int fd, int argc, char *argv[]);
1178 static int rpt_do_fun1(int fd, int argc, char *argv[]);
1179 static int rpt_do_cmd(int fd, int argc, char *argv[]);
1181 static char debug_usage[] =
1182 "Usage: rpt debug level {0-7}\n"
1183 " Enables debug messages in app_rpt\n";
1185 static char dump_usage[] =
1186 "Usage: rpt dump <nodename>\n"
1187 " Dumps struct debug info to log\n";
1189 static char dump_stats[] =
1190 "Usage: rpt stats <nodename>\n"
1191 " Dumps node statistics to console\n";
1193 static char dump_lstats[] =
1194 "Usage: rpt lstats <nodename>\n"
1195 " Dumps link statistics to console\n";
1197 static char dump_nodes[] =
1198 "Usage: rpt nodes <nodename>\n"
1199 " Dumps a list of directly and indirectly connected nodes to the console\n";
1201 static char usage_local_nodes[] =
1202 "Usage: rpt localnodes\n"
1203 " Dumps a list of the locally configured node numbers to the console.\n";
1205 static char reload_usage[] =
1206 "Usage: rpt reload\n"
1207 " Reloads app_rpt running config parameters\n";
1209 static char restart_usage[] =
1210 "Usage: rpt restart\n"
1211 " Restarts app_rpt\n";
1213 static char fun_usage[] =
1214 "Usage: rpt fun <nodename> <command>\n"
1215 " Send a DTMF function to a node\n";
1217 static char cmd_usage[] =
1218 "Usage: rpt cmd <nodename> <cmd-name> <cmd-index> <cmd-args.\n"
1219 " Send a command to a node.\n i.e. rpt cmd 2000 ilink 3 2001\n";
1221 #ifndef NEW_ASTERISK
1223 static struct ast_cli_entry cli_debug =
1224 { { "rpt", "debug", "level" }, rpt_do_debug,
1225 "Enable app_rpt debugging", debug_usage };
1227 static struct ast_cli_entry cli_dump =
1228 { { "rpt", "dump" }, rpt_do_dump,
1229 "Dump app_rpt structs for debugging", dump_usage };
1231 static struct ast_cli_entry cli_stats =
1232 { { "rpt", "stats" }, rpt_do_stats,
1233 "Dump node statistics", dump_stats };
1235 static struct ast_cli_entry cli_nodes =
1236 { { "rpt", "nodes" }, rpt_do_nodes,
1237 "Dump node list", dump_nodes };
1239 static struct ast_cli_entry cli_local_nodes =
1240 { { "rpt", "localnodes" }, rpt_do_local_nodes,
1241 "Dump list of local node numbers", usage_local_nodes };
1243 static struct ast_cli_entry cli_lstats =
1244 { { "rpt", "lstats" }, rpt_do_lstats,
1245 "Dump link statistics", dump_lstats };
1247 static struct ast_cli_entry cli_reload =
1248 { { "rpt", "reload" }, rpt_do_reload,
1249 "Reload app_rpt config", reload_usage };
1251 static struct ast_cli_entry cli_restart =
1252 { { "rpt", "restart" }, rpt_do_restart,
1253 "Restart app_rpt", restart_usage };
1255 static struct ast_cli_entry cli_fun =
1256 { { "rpt", "fun" }, rpt_do_fun,
1257 "Execute a DTMF function", fun_usage };
1259 static struct ast_cli_entry cli_fun1 =
1260 { { "rpt", "fun1" }, rpt_do_fun1,
1261 "Execute a DTMF function", fun_usage };
1263 static struct ast_cli_entry cli_cmd =
1264 { { "rpt", "cmd" }, rpt_do_cmd,
1265 "Execute a DTMF function", cmd_usage };
1267 #endif
1270 * Telemetry defaults
1274 static struct telem_defaults tele_defs[] = {
1275 {"ct1","|t(350,0,100,3072)(500,0,100,3072)(660,0,100,3072)"},
1276 {"ct2","|t(660,880,150,3072)"},
1277 {"ct3","|t(440,0,150,3072)"},
1278 {"ct4","|t(550,0,150,3072)"},
1279 {"ct5","|t(660,0,150,3072)"},
1280 {"ct6","|t(880,0,150,3072)"},
1281 {"ct7","|t(660,440,150,3072)"},
1282 {"ct8","|t(700,1100,150,3072)"},
1283 {"remotemon","|t(1600,0,75,2048)"},
1284 {"remotetx","|t(2000,0,75,2048)(0,0,75,0)(1600,0,75,2048)"},
1285 {"cmdmode","|t(900,904,200,2048)"},
1286 {"functcomplete","|t(1000,0,100,2048)(0,0,100,0)(1000,0,100,2048)"}
1290 * Forward decl's - these suppress compiler warnings when funcs coded further down the file than thier invokation
1293 static int setrbi(struct rpt *myrpt);
1294 static int set_ft897(struct rpt *myrpt);
1295 static int set_ic706(struct rpt *myrpt);
1296 static int setkenwood(struct rpt *myrpt);
1297 static int set_tm271(struct rpt *myrpt);
1298 static int setrbi_check(struct rpt *myrpt);
1303 * Define function protos for function table here
1306 static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1307 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1308 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1309 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1310 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1311 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1312 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1313 static int function_playback(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1315 * Function table
1318 static struct function_table_tag function_table[] = {
1319 {"cop", function_cop},
1320 {"autopatchup", function_autopatchup},
1321 {"autopatchdn", function_autopatchdn},
1322 {"ilink", function_ilink},
1323 {"status", function_status},
1324 {"remote", function_remote},
1325 {"macro", function_macro},
1326 {"playback", function_playback}
1329 static long diskavail(struct rpt *myrpt)
1331 struct statfs statfsbuf;
1333 if (!myrpt->p.archivedir) return(0);
1334 if (statfs(myrpt->p.archivedir,&statfsbuf) == -1)
1336 ast_log(LOG_WARNING,"Cannot get filesystem size for %s node %s\n",
1337 myrpt->p.archivedir,myrpt->name);
1338 return(-1);
1340 return(statfsbuf.f_bavail);
1343 static void flush_telem(struct rpt *myrpt)
1345 struct rpt_tele *telem;
1346 if(debug > 2)
1347 ast_log(LOG_NOTICE, "flush_telem()!!");
1348 rpt_mutex_lock(&myrpt->lock);
1349 telem = myrpt->tele.next;
1350 while(telem != &myrpt->tele)
1352 if (telem->mode != SETREMOTE) ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
1353 telem = telem->next;
1355 rpt_mutex_unlock(&myrpt->lock);
1358 return via error priority
1360 static int priority_jump(struct rpt *myrpt, struct ast_channel *chan)
1362 int res=0;
1364 // if (ast_test_flag(&flags,OPT_JUMP) && ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101) == 0){
1365 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101) == 0){
1366 res = 0;
1367 } else {
1368 res = -1;
1370 return res;
1374 static int linkcount(struct rpt *myrpt)
1376 struct rpt_link *l;
1377 char *reverse_patch_state;
1378 int numoflinks;
1380 reverse_patch_state = "DOWN";
1381 numoflinks = 0;
1382 l = myrpt->links.next;
1383 while(l && (l != &myrpt->links)){
1384 if(numoflinks >= MAX_STAT_LINKS){
1385 ast_log(LOG_WARNING,
1386 "maximum number of links exceeds %d in rpt_do_stats()!",MAX_STAT_LINKS);
1387 break;
1389 //if (l->name[0] == '0'){ /* Skip '0' nodes */
1390 // reverse_patch_state = "UP";
1391 // l = l->next;
1392 // continue;
1394 numoflinks++;
1396 l = l->next;
1398 ast_log(LOG_NOTICE, "numoflinks=%i\n",numoflinks);
1399 return numoflinks;
1402 * Retrieve a memory channel
1403 * Return 0 if sucessful,
1404 * -1 if channel not found,
1405 * 1 if parse error
1407 static int retreive_memory(struct rpt *myrpt, char *memory)
1409 char tmp[30], *s, *s1, *val;
1411 if (debug)ast_log(LOG_NOTICE, "memory=%s block=%s\n",memory,myrpt->p.memory);
1413 val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.memory, memory);
1414 if (!val){
1415 return -1;
1417 strncpy(tmp,val,sizeof(tmp) - 1);
1418 tmp[sizeof(tmp)-1] = 0;
1420 s = strchr(tmp,',');
1421 if (!s)
1422 return 1;
1423 *s++ = 0;
1424 s1 = strchr(s,',');
1425 if (!s1)
1426 return 1;
1427 *s1++ = 0;
1428 strncpy(myrpt->freq, tmp, sizeof(myrpt->freq) - 1);
1429 strncpy(myrpt->rxpl, s, sizeof(myrpt->rxpl) - 1);
1430 strncpy(myrpt->txpl, s, sizeof(myrpt->rxpl) - 1);
1431 myrpt->remmode = REM_MODE_FM;
1432 myrpt->offset = REM_SIMPLEX;
1433 myrpt->powerlevel = REM_MEDPWR;
1434 myrpt->txplon = myrpt->rxplon = 0;
1435 while(*s1){
1436 switch(*s1++){
1437 case 'A':
1438 case 'a':
1439 strcpy(myrpt->rxpl, "100.0");
1440 strcpy(myrpt->txpl, "100.0");
1441 myrpt->remmode = REM_MODE_AM;
1442 break;
1443 case 'B':
1444 case 'b':
1445 strcpy(myrpt->rxpl, "100.0");
1446 strcpy(myrpt->txpl, "100.0");
1447 myrpt->remmode = REM_MODE_LSB;
1448 break;
1449 case 'F':
1450 myrpt->remmode = REM_MODE_FM;
1451 break;
1452 case 'L':
1453 case 'l':
1454 myrpt->powerlevel = REM_LOWPWR;
1455 break;
1456 case 'H':
1457 case 'h':
1458 myrpt->powerlevel = REM_HIPWR;
1459 break;
1461 case 'M':
1462 case 'm':
1463 myrpt->powerlevel = REM_MEDPWR;
1464 break;
1466 case '-':
1467 myrpt->offset = REM_MINUS;
1468 break;
1470 case '+':
1471 myrpt->offset = REM_PLUS;
1472 break;
1474 case 'S':
1475 case 's':
1476 myrpt->offset = REM_SIMPLEX;
1477 break;
1479 case 'T':
1480 case 't':
1481 myrpt->txplon = 1;
1482 break;
1484 case 'R':
1485 case 'r':
1486 myrpt->rxplon = 1;
1487 break;
1489 case 'U':
1490 case 'u':
1491 strcpy(myrpt->rxpl, "100.0");
1492 strcpy(myrpt->txpl, "100.0");
1493 myrpt->remmode = REM_MODE_USB;
1494 break;
1495 default:
1496 return 1;
1499 return 0;
1504 static void birdbath(struct rpt *myrpt)
1506 struct rpt_tele *telem;
1507 if(debug > 2)
1508 ast_log(LOG_NOTICE, "birdbath!!");
1509 rpt_mutex_lock(&myrpt->lock);
1510 telem = myrpt->tele.next;
1511 while(telem != &myrpt->tele)
1513 if (telem->mode == PARROT) ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
1514 telem = telem->next;
1516 rpt_mutex_unlock(&myrpt->lock);
1519 static void do_dtmf_phone(struct rpt *myrpt, struct rpt_link *mylink, char c)
1521 struct rpt_link *l;
1523 l = myrpt->links.next;
1524 /* go thru all the links */
1525 while(l != &myrpt->links)
1527 if (!l->phonemode)
1529 l = l->next;
1530 continue;
1532 /* dont send to self */
1533 if (mylink && (l == mylink))
1535 l = l->next;
1536 continue;
1538 #ifdef NEW_ASTERISK
1539 if (l->chan) ast_senddigit(l->chan,c,0);
1540 #else
1541 if (l->chan) ast_senddigit(l->chan,c);
1542 #endif
1543 l = l->next;
1545 return;
1548 /* node logging function */
1549 static void donodelog(struct rpt *myrpt,char *str)
1551 struct nodelog *nodep;
1552 char datestr[100];
1554 if (!myrpt->p.archivedir) return;
1555 nodep = (struct nodelog *)ast_malloc(sizeof(struct nodelog));
1556 if (nodep == NULL)
1558 ast_log(LOG_ERROR,"Cannot get memory for node log");
1559 return;
1561 time(&nodep->timestamp);
1562 strncpy(nodep->archivedir,myrpt->p.archivedir,
1563 sizeof(nodep->archivedir) - 1);
1564 strftime(datestr,sizeof(datestr) - 1,"%Y%m%d%H%M%S",
1565 localtime(&nodep->timestamp));
1566 snprintf(nodep->str,sizeof(nodep->str) - 1,"%s %s,%s\n",
1567 myrpt->name,datestr,str);
1568 ast_mutex_lock(&nodeloglock);
1569 insque((struct qelem *) nodep, (struct qelem *) nodelog.prev);
1570 ast_mutex_unlock(&nodeloglock);
1573 /* must be called locked */
1574 static void do_dtmf_local(struct rpt *myrpt, char c)
1576 int i;
1577 char digit;
1578 static const char* dtmf_tones[] = {
1579 "!941+1336/200,!0/200", /* 0 */
1580 "!697+1209/200,!0/200", /* 1 */
1581 "!697+1336/200,!0/200", /* 2 */
1582 "!697+1477/200,!0/200", /* 3 */
1583 "!770+1209/200,!0/200", /* 4 */
1584 "!770+1336/200,!0/200", /* 5 */
1585 "!770+1477/200,!0/200", /* 6 */
1586 "!852+1209/200,!0/200", /* 7 */
1587 "!852+1336/200,!0/200", /* 8 */
1588 "!852+1477/200,!0/200", /* 9 */
1589 "!697+1633/200,!0/200", /* A */
1590 "!770+1633/200,!0/200", /* B */
1591 "!852+1633/200,!0/200", /* C */
1592 "!941+1633/200,!0/200", /* D */
1593 "!941+1209/200,!0/200", /* * */
1594 "!941+1477/200,!0/200" }; /* # */
1597 if (c)
1599 snprintf(myrpt->dtmf_local_str + strlen(myrpt->dtmf_local_str),sizeof(myrpt->dtmf_local_str) - 1,"%c",c);
1600 if (!myrpt->dtmf_local_timer)
1601 myrpt->dtmf_local_timer = DTMF_LOCAL_STARTTIME;
1603 /* if at timeout */
1604 if (myrpt->dtmf_local_timer == 1)
1606 if(debug > 6)
1607 ast_log(LOG_NOTICE,"time out dtmf_local_timer=%i\n",myrpt->dtmf_local_timer);
1609 /* if anything in the string */
1610 if (myrpt->dtmf_local_str[0])
1612 digit = myrpt->dtmf_local_str[0];
1613 myrpt->dtmf_local_str[0] = 0;
1614 for(i = 1; myrpt->dtmf_local_str[i]; i++)
1616 myrpt->dtmf_local_str[i - 1] =
1617 myrpt->dtmf_local_str[i];
1619 myrpt->dtmf_local_str[i - 1] = 0;
1620 myrpt->dtmf_local_timer = DTMF_LOCAL_TIME;
1621 rpt_mutex_unlock(&myrpt->lock);
1622 if (digit >= '0' && digit <='9')
1623 ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'0'], 0);
1624 else if (digit >= 'A' && digit <= 'D')
1625 ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'A'+10], 0);
1626 else if (digit == '*')
1627 ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[14], 0);
1628 else if (digit == '#')
1629 ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[15], 0);
1630 else {
1631 /* not handled */
1632 ast_log(LOG_DEBUG, "Unable to generate DTMF tone '%c' for '%s'\n", digit, myrpt->txchannel->name);
1634 rpt_mutex_lock(&myrpt->lock);
1636 else
1638 myrpt->dtmf_local_timer = 0;
1643 static int setdtr(int fd, int enable)
1645 struct termios mode;
1647 if (fd < 0) return -1;
1648 if (tcgetattr(fd, &mode)) {
1649 ast_log(LOG_WARNING, "Unable to get serial parameters for dtr: %s\n", strerror(errno));
1650 return -1;
1652 if (enable)
1654 cfsetspeed(&mode, B9600);
1656 else
1658 cfsetspeed(&mode, B0);
1659 usleep(100000);
1661 if (tcsetattr(fd, TCSADRAIN, &mode)) {
1662 ast_log(LOG_WARNING, "Unable to set serial parameters for dtr: %s\n", strerror(errno));
1663 return -1;
1665 if (enable) usleep(100000);
1666 return 0;
1669 static int openserial(struct rpt *myrpt,char *fname)
1671 struct termios mode;
1672 int fd;
1674 fd = open(fname,O_RDWR);
1675 if (fd == -1)
1677 ast_log(LOG_WARNING,"Cannot open serial port %s\n",fname);
1678 return -1;
1680 memset(&mode, 0, sizeof(mode));
1681 if (tcgetattr(fd, &mode)) {
1682 ast_log(LOG_WARNING, "Unable to get serial parameters on %s: %s\n", fname, strerror(errno));
1683 return -1;
1685 #ifndef SOLARIS
1686 cfmakeraw(&mode);
1687 #else
1688 mode.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
1689 |INLCR|IGNCR|ICRNL|IXON);
1690 mode.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
1691 mode.c_cflag &= ~(CSIZE|PARENB|CRTSCTS);
1692 mode.c_cflag |= CS8;
1693 mode.c_cc[VTIME] = 3;
1694 mode.c_cc[VMIN] = 1;
1695 #endif
1697 cfsetispeed(&mode, B9600);
1698 cfsetospeed(&mode, B9600);
1699 if (tcsetattr(fd, TCSANOW, &mode))
1700 ast_log(LOG_WARNING, "Unable to set serial parameters on %s: %s\n", fname, strerror(errno));
1701 if(!strcmp(myrpt->remoterig, remote_rig_kenwood)) setdtr(fd,0);
1702 usleep(100000);
1703 if (debug)ast_log(LOG_NOTICE,"Opened serial port %s\n",fname);
1704 return(fd);
1707 static void mdc1200_notify(struct rpt *myrpt,char *fromnode, unsigned int unit)
1709 if (!fromnode)
1711 ast_verbose("Got MDC-1200 ID %04X from local system (%s)\n",
1712 unit,myrpt->name);
1714 else
1716 ast_verbose("Got MDC-1200 ID %04X from node %s (%s)\n",
1717 unit,fromnode,myrpt->name);
1721 #ifdef _MDC_DECODE_H_
1723 static void mdc1200_send(struct rpt *myrpt, unsigned int unit)
1725 struct rpt_link *l;
1726 struct ast_frame wf;
1727 char str[200];
1730 sprintf(str,"I %s %04X",myrpt->name,unit);
1732 wf.frametype = AST_FRAME_TEXT;
1733 wf.subclass = 0;
1734 wf.offset = 0;
1735 wf.mallocd = 0;
1736 wf.datalen = strlen(str) + 1;
1737 wf.samples = 0;
1740 l = myrpt->links.next;
1741 /* otherwise, send it to all of em */
1742 while(l != &myrpt->links)
1744 if (l->name[0] == '0')
1746 l = l->next;
1747 continue;
1749 wf.data = str;
1750 if (l->chan) ast_write(l->chan,&wf);
1751 l = l->next;
1753 return;
1756 #endif
1758 static char func_xlat(struct rpt *myrpt,char c,struct rpt_xlat *xlat)
1760 time_t now;
1761 int gotone;
1763 time(&now);
1764 gotone = 0;
1765 /* if too much time, reset the skate machine */
1766 if ((now - xlat->lastone) > MAXXLATTIME)
1768 xlat->funcindex = xlat->endindex = 0;
1770 if (xlat->funccharseq[0] && (c == xlat->funccharseq[xlat->funcindex++]))
1772 time(&xlat->lastone);
1773 gotone = 1;
1774 if (!xlat->funccharseq[xlat->funcindex])
1776 xlat->funcindex = xlat->endindex = 0;
1777 return(myrpt->p.funcchar);
1779 } else xlat->funcindex = 0;
1780 if (xlat->endcharseq[0] && (c == xlat->endcharseq[xlat->endindex++]))
1782 time(&xlat->lastone);
1783 gotone = 1;
1784 if (!xlat->endcharseq[xlat->endindex])
1786 xlat->funcindex = xlat->endindex = 0;
1787 return(myrpt->p.endchar);
1789 } else xlat->endindex = 0;
1790 /* if in middle of decode seq, send nothing back */
1791 if (gotone) return(0);
1792 /* if no pass chars specified, return em all */
1793 if (!xlat->passchars[0]) return(c);
1794 /* if a "pass char", pass it */
1795 if (strchr(xlat->passchars,c)) return(c);
1796 return(0);
1800 * Return a pointer to the first non-whitespace character
1803 static char *eatwhite(char *s)
1805 while((*s == ' ') || (*s == 0x09)){ /* get rid of any leading white space */
1806 if(!*s)
1807 break;
1808 s++;
1810 return s;
1814 * Break up a delimited string into a table of substrings
1816 * str - delimited string ( will be modified )
1817 * strp- list of pointers to substrings (this is built by this function), NULL will be placed at end of list
1818 * limit- maximum number of substrings to process
1823 static int finddelim(char *str, char *strp[], int limit)
1825 int i,l,inquo;
1827 inquo = 0;
1828 i = 0;
1829 strp[i++] = str;
1830 if (!*str)
1832 strp[0] = 0;
1833 return(0);
1835 for(l = 0; *str && (l < limit) ; str++)
1837 if (*str == QUOTECHR)
1839 if (inquo)
1841 *str = 0;
1842 inquo = 0;
1844 else
1846 strp[i - 1] = str + 1;
1847 inquo = 1;
1850 if ((*str == DELIMCHR) && (!inquo))
1852 *str = 0;
1853 l++;
1854 strp[i++] = str + 1;
1857 strp[i] = 0;
1858 return(i);
1862 send asterisk frame text message on the current tx channel
1864 static int send_usb_txt(struct rpt *myrpt, char *txt)
1866 struct ast_frame wf;
1868 if (debug)ast_log(LOG_NOTICE, "send_usb_txt %s\n",txt);
1869 wf.frametype = AST_FRAME_TEXT;
1870 wf.subclass = 0;
1871 wf.offset = 0;
1872 wf.mallocd = 0;
1873 wf.datalen = strlen(txt) + 1;
1874 wf.data.ptr = txt;
1875 wf.samples = 0;
1876 ast_write(myrpt->txchannel,&wf);
1877 return 0;
1879 /* must be called locked */
1880 static void __mklinklist(struct rpt *myrpt, struct rpt_link *mylink, char *buf)
1882 struct rpt_link *l;
1883 char mode;
1884 int i,spos;
1886 buf[0] = 0; /* clear output buffer */
1887 if (myrpt->remote) return;
1888 /* go thru all links */
1889 for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
1891 /* if is not a real link, ignore it */
1892 if (l->name[0] == '0') continue;
1893 /* dont count our stuff */
1894 if (l == mylink) continue;
1895 if (mylink && (!strcmp(l->name,mylink->name))) continue;
1896 /* figure out mode to report */
1897 mode = 'T'; /* use Tranceive by default */
1898 if (!l->mode) mode = 'R'; /* indicate RX for our mode */
1899 if (!l->thisconnected) mode = 'C'; /* indicate connecting */
1900 spos = strlen(buf); /* current buf size (b4 we add our stuff) */
1901 if (spos)
1903 strcat(buf,",");
1904 spos++;
1906 /* add nodes into buffer */
1907 if (l->linklist[0])
1909 snprintf(buf + spos,MAXLINKLIST - spos,
1910 "%c%s,%s",mode,l->name,l->linklist);
1912 else /* if no nodes, add this node into buffer */
1914 snprintf(buf + spos,MAXLINKLIST - spos,
1915 "%c%s",mode,l->name);
1917 /* if we are in tranceive mode, let all modes stand */
1918 if (mode == 'T') continue;
1919 /* downgrade everyone on this node if appropriate */
1920 for(i = spos; buf[i]; i++)
1922 if (buf[i] == 'T') buf[i] = mode;
1923 if ((buf[i] == 'R') && (mode == 'C')) buf[i] = mode;
1926 return;
1929 /* must be called locked */
1930 static void __kickshort(struct rpt *myrpt)
1932 struct rpt_link *l;
1934 for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
1936 /* if is not a real link, ignore it */
1937 if (l->name[0] == '0') continue;
1938 l->linklisttimer = LINKLISTSHORTTIME;
1940 myrpt->linkposttimer = LINKPOSTSHORTTIME;
1941 return;
1944 static void statpost(struct rpt *myrpt,char *pairs)
1946 char *str,*astr;
1947 char *astrs[100];
1948 int n,pid;
1949 time_t now;
1950 unsigned int seq;
1952 if (!myrpt->p.statpost_url) return;
1953 str = ast_malloc(strlen(pairs) + strlen(myrpt->p.statpost_url) + 200);
1954 astr = ast_strdup(myrpt->p.statpost_program);
1955 if ((!str) || (!astr)) return;
1956 n = finddelim(astr,astrs,100);
1957 if (n < 1) return;
1958 ast_mutex_lock(&myrpt->statpost_lock);
1959 seq = ++myrpt->statpost_seqno;
1960 ast_mutex_unlock(&myrpt->statpost_lock);
1961 astrs[n++] = str;
1962 astrs[n] = NULL;
1963 time(&now);
1964 sprintf(str,"%s?node=%s&time=%u&seqno=%u",myrpt->p.statpost_url,
1965 myrpt->name,(unsigned int) now,seq);
1966 if (pairs) sprintf(str + strlen(str),"&%s",pairs);
1967 if (!(pid = fork()))
1969 execv(astrs[0],astrs);
1970 ast_log(LOG_ERROR, "exec of %s failed.\n", astrs[0]);
1971 perror("asterisk");
1972 exit(0);
1974 ast_free(astr);
1975 ast_free(str);
1976 return;
1979 static char *node_lookup(struct rpt *myrpt,char *digitbuf)
1982 char *val;
1983 int longestnode,j;
1984 struct stat mystat;
1985 static time_t last = 0;
1986 static struct ast_config *ourcfg = NULL;
1987 struct ast_variable *vp;
1989 /* try to look it up locally first */
1990 val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
1991 if (val) return(val);
1992 ast_mutex_lock(&nodelookuplock);
1993 /* if file does not exist */
1994 if (stat(myrpt->p.extnodefile,&mystat) == -1)
1996 if (ourcfg) ast_config_destroy(ourcfg);
1997 ourcfg = NULL;
1998 ast_mutex_unlock(&nodelookuplock);
1999 return(NULL);
2001 /* if we need to reload */
2002 if (mystat.st_mtime > last)
2004 if (ourcfg) ast_config_destroy(ourcfg);
2005 #ifdef NEW_ASTERISK
2006 ourcfg = ast_config_load(myrpt->p.extnodefile,config_flags);
2007 #else
2008 ourcfg = ast_config_load(myrpt->p.extnodefile);
2009 #endif
2010 /* if file not there, just bail */
2011 if (!ourcfg)
2013 ast_mutex_unlock(&nodelookuplock);
2014 return(NULL);
2016 /* reset "last" time */
2017 last = mystat.st_mtime;
2019 /* determine longest node length again */
2020 longestnode = 0;
2021 vp = ast_variable_browse(myrpt->cfg, myrpt->p.nodes);
2022 while(vp){
2023 j = strlen(vp->name);
2024 if (j > longestnode)
2025 longestnode = j;
2026 vp = vp->next;
2029 vp = ast_variable_browse(ourcfg, myrpt->p.extnodes);
2030 while(vp){
2031 j = strlen(vp->name);
2032 if (j > longestnode)
2033 longestnode = j;
2034 vp = vp->next;
2037 myrpt->longestnode = longestnode;
2039 val = NULL;
2040 if (ourcfg)
2041 val = (char *) ast_variable_retrieve(ourcfg, myrpt->p.extnodes, digitbuf);
2042 ast_mutex_unlock(&nodelookuplock);
2043 return(val);
2047 * Match a keyword in a list, and return index of string plus 1 if there was a match,* else return 0.
2048 * If param is passed in non-null, then it will be set to the first character past the match
2051 static int matchkeyword(char *string, char **param, char *keywords[])
2053 int i,ls;
2054 for( i = 0 ; keywords[i] ; i++){
2055 ls = strlen(keywords[i]);
2056 if(!ls){
2057 *param = NULL;
2058 return 0;
2060 if(!strncmp(string, keywords[i], ls)){
2061 if(param)
2062 *param = string + ls;
2063 return i + 1;
2066 *param = NULL;
2067 return 0;
2071 * Skip characters in string which are in charlist, and return a pointer to the
2072 * first non-matching character
2075 static char *skipchars(char *string, char *charlist)
2077 int i;
2078 while(*string){
2079 for(i = 0; charlist[i] ; i++){
2080 if(*string == charlist[i]){
2081 string++;
2082 break;
2085 if(!charlist[i])
2086 return string;
2088 return string;
2093 static int myatoi(char *str)
2095 int ret;
2097 if (str == NULL) return -1;
2098 /* leave this %i alone, non-base-10 input is useful here */
2099 if (sscanf(str,"%i",&ret) != 1) return -1;
2100 return ret;
2103 static int mycompar(const void *a, const void *b)
2105 char **x = (char **) a;
2106 char **y = (char **) b;
2107 int xoff,yoff;
2109 if ((**x < '0') || (**x > '9')) xoff = 1; else xoff = 0;
2110 if ((**y < '0') || (**y > '9')) yoff = 1; else yoff = 0;
2111 return(strcmp((*x) + xoff,(*y) + yoff));
2114 static int topcompar(const void *a, const void *b)
2116 struct rpt_topkey *x = (struct rpt_topkey *) a;
2117 struct rpt_topkey *y = (struct rpt_topkey *) b;
2119 return(x->timesince - y->timesince);
2122 #ifdef __RPT_NOTCH
2124 /* rpt filter routine */
2125 static void rpt_filter(struct rpt *myrpt, volatile short *buf, int len)
2127 int i,j;
2128 struct rptfilter *f;
2130 for(i = 0; i < len; i++)
2132 for(j = 0; j < MAXFILTERS; j++)
2134 f = &myrpt->filters[j];
2135 if (!*f->desc) continue;
2136 f->x0 = f->x1; f->x1 = f->x2;
2137 f->x2 = ((float)buf[i]) / f->gain;
2138 f->y0 = f->y1; f->y1 = f->y2;
2139 f->y2 = (f->x0 + f->x2) + f->const0 * f->x1
2140 + (f->const1 * f->y0) + (f->const2 * f->y1);
2141 buf[i] = (short)f->y2;
2146 #endif
2150 Get the time for the machine's time zone
2151 Note: Asterisk requires a copy of localtime
2152 in the /etc directory for this to work properly.
2153 If /etc/localtime is not present, you will get
2154 GMT time! This is especially important on systems
2155 running embedded linux distributions as they don't usually
2156 have support for locales.
2158 If OLD_ASTERISK is defined, then the older localtime_r
2159 function will be used. The /etc/localtime file is not
2160 required in this case. This provides backward compatibility
2161 with Asterisk 1.2 systems.
2165 #ifdef NEW_ASTERISK
2166 static void rpt_localtime( time_t * t, struct ast_tm *lt)
2168 struct timeval tv;
2170 tv.tv_sec = *t;
2171 tv.tv_usec = 0;
2172 ast_localtime(&tv, lt, NULL);
2176 #else
2177 static void rpt_localtime( time_t * t, struct tm *lt)
2179 #ifdef OLD_ASTERISK
2180 localtime_r(t, lt);
2181 #else
2182 ast_localtime(t, lt, NULL);
2183 #endif
2185 #endif
2188 /* Retrieve an int from a config file */
2190 static int retrieve_astcfgint(struct rpt *myrpt,char *category, char *name, int min, int max, int defl)
2192 char *var;
2193 int ret;
2194 char include_zero = 0;
2196 if(min < 0){ /* If min is negative, this means include 0 as a valid entry */
2197 min = -min;
2198 include_zero = 1;
2201 var = (char *) ast_variable_retrieve(myrpt->cfg, category, name);
2202 if(var){
2203 ret = myatoi(var);
2204 if(include_zero && !ret)
2205 return 0;
2206 if(ret < min)
2207 ret = min;
2208 if(ret > max)
2209 ret = max;
2211 else
2212 ret = defl;
2213 return ret;
2217 static void load_rpt_vars(int n,int init)
2219 char *this,*val;
2220 int i,j,longestnode;
2221 struct ast_variable *vp;
2222 struct ast_config *cfg;
2223 char *strs[100];
2224 char s1[256];
2225 static char *cs_keywords[] = {"rptena","rptdis","apena","apdis","lnkena","lnkdis","totena","totdis","skena","skdis",
2226 "ufena","ufdis","atena","atdis",NULL};
2228 if (option_verbose > 2)
2229 ast_verbose(VERBOSE_PREFIX_3 "%s config for repeater %s\n",
2230 (init) ? "Loading initial" : "Re-Loading",rpt_vars[n].name);
2231 ast_mutex_lock(&rpt_vars[n].lock);
2232 if (rpt_vars[n].cfg) ast_config_destroy(rpt_vars[n].cfg);
2233 #ifdef NEW_ASTERISK
2234 cfg = ast_config_load("rpt.conf",config_flags);
2235 #else
2236 cfg = ast_config_load("rpt.conf");
2237 #endif
2238 if (!cfg) {
2239 ast_mutex_unlock(&rpt_vars[n].lock);
2240 ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf. Radio Repeater disabled.\n");
2241 pthread_exit(NULL);
2243 rpt_vars[n].cfg = cfg;
2244 this = rpt_vars[n].name;
2245 memset(&rpt_vars[n].p,0,sizeof(rpt_vars[n].p));
2246 if (init)
2248 char *cp;
2249 int savearea = (char *)&rpt_vars[n].p - (char *)&rpt_vars[n];
2251 cp = (char *) &rpt_vars[n].p;
2252 memset(cp + sizeof(rpt_vars[n].p),0,
2253 sizeof(rpt_vars[n]) - (sizeof(rpt_vars[n].p) + savearea));
2254 rpt_vars[n].tele.next = &rpt_vars[n].tele;
2255 rpt_vars[n].tele.prev = &rpt_vars[n].tele;
2256 rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
2257 rpt_vars[n].tailmessagen = 0;
2259 #ifdef __RPT_NOTCH
2260 /* zot out filters stuff */
2261 memset(&rpt_vars[n].filters,0,sizeof(rpt_vars[n].filters));
2262 #endif
2263 val = (char *) ast_variable_retrieve(cfg,this,"context");
2264 if (val) rpt_vars[n].p.ourcontext = val;
2265 else rpt_vars[n].p.ourcontext = this;
2266 val = (char *) ast_variable_retrieve(cfg,this,"callerid");
2267 if (val) rpt_vars[n].p.ourcallerid = val;
2268 val = (char *) ast_variable_retrieve(cfg,this,"accountcode");
2269 if (val) rpt_vars[n].p.acctcode = val;
2270 val = (char *) ast_variable_retrieve(cfg,this,"idrecording");
2271 if (val) rpt_vars[n].p.ident = val;
2272 val = (char *) ast_variable_retrieve(cfg,this,"hangtime");
2273 if (val) rpt_vars[n].p.hangtime = atoi(val);
2274 else rpt_vars[n].p.hangtime = HANGTIME;
2275 val = (char *) ast_variable_retrieve(cfg,this,"althangtime");
2276 if (val) rpt_vars[n].p.althangtime = atoi(val);
2277 else rpt_vars[n].p.althangtime = HANGTIME;
2278 val = (char *) ast_variable_retrieve(cfg,this,"totime");
2279 if (val) rpt_vars[n].p.totime = atoi(val);
2280 else rpt_vars[n].p.totime = TOTIME;
2281 val = (char *) ast_variable_retrieve(cfg,this,"voxtimeout");
2282 if (val) rpt_vars[n].p.voxtimeout_ms = atoi(val);
2283 else rpt_vars[n].p.voxtimeout_ms = VOX_TIMEOUT_MS;
2284 val = (char *) ast_variable_retrieve(cfg,this,"voxrecover");
2285 if (val) rpt_vars[n].p.voxrecover_ms = atoi(val);
2286 else rpt_vars[n].p.voxrecover_ms = VOX_RECOVER_MS;
2287 val = (char *) ast_variable_retrieve(cfg,this,"simplexpatchdelay");
2288 if (val) rpt_vars[n].p.simplexpatchdelay = atoi(val);
2289 else rpt_vars[n].p.simplexpatchdelay = SIMPLEX_PATCH_DELAY;
2290 val = (char *) ast_variable_retrieve(cfg,this,"simplexphonedelay");
2291 if (val) rpt_vars[n].p.simplexphonedelay = atoi(val);
2292 else rpt_vars[n].p.simplexphonedelay = SIMPLEX_PHONE_DELAY;
2293 val = (char *) ast_variable_retrieve(cfg,this,"statpost_program");
2294 if (val) rpt_vars[n].p.statpost_program = val;
2295 else rpt_vars[n].p.statpost_program = STATPOST_PROGRAM;
2296 rpt_vars[n].p.statpost_url =
2297 (char *) ast_variable_retrieve(cfg,this,"statpost_url");
2298 rpt_vars[n].p.tailmessagetime = retrieve_astcfgint(&rpt_vars[n],this, "tailmessagetime", 0, 2400000, 0);
2299 rpt_vars[n].p.tailsquashedtime = retrieve_astcfgint(&rpt_vars[n],this, "tailsquashedtime", 0, 2400000, 0);
2300 rpt_vars[n].p.duplex = retrieve_astcfgint(&rpt_vars[n],this,"duplex",0,4,2);
2301 rpt_vars[n].p.idtime = retrieve_astcfgint(&rpt_vars[n],this, "idtime", -60000, 2400000, IDTIME); /* Enforce a min max including zero */
2302 rpt_vars[n].p.politeid = retrieve_astcfgint(&rpt_vars[n],this, "politeid", 30000, 300000, POLITEID); /* Enforce a min max */
2303 val = (char *) ast_variable_retrieve(cfg,this,"tonezone");
2304 if (val) rpt_vars[n].p.tonezone = val;
2305 rpt_vars[n].p.tailmessages[0] = 0;
2306 rpt_vars[n].p.tailmessagemax = 0;
2307 val = (char *) ast_variable_retrieve(cfg,this,"tailmessagelist");
2308 if (val) rpt_vars[n].p.tailmessagemax = finddelim(val, rpt_vars[n].p.tailmessages, 500);
2309 val = (char *) ast_variable_retrieve(cfg,this,"memory");
2310 if (!val) val = MEMORY;
2311 rpt_vars[n].p.memory = val;
2312 val = (char *) ast_variable_retrieve(cfg,this,"macro");
2313 if (!val) val = MACRO;
2314 rpt_vars[n].p.macro = val;
2315 val = (char *) ast_variable_retrieve(cfg,this,"tonemacro");
2316 if (!val) val = TONEMACRO;
2317 rpt_vars[n].p.tonemacro = val;
2318 val = (char *) ast_variable_retrieve(cfg,this,"startup_macro");
2319 if (val) rpt_vars[n].p.startupmacro = val;
2320 val = (char *) ast_variable_retrieve(cfg,this,"iobase");
2321 /* do not use atoi() here, we need to be able to have
2322 the input specified in hex or decimal so we use
2323 sscanf with a %i */
2324 if ((!val) || (sscanf(val,"%i",&rpt_vars[n].p.iobase) != 1))
2325 rpt_vars[n].p.iobase = DEFAULT_IOBASE;
2326 val = (char *) ast_variable_retrieve(cfg,this,"ioport");
2327 rpt_vars[n].p.ioport = val;
2328 val = (char *) ast_variable_retrieve(cfg,this,"functions");
2329 if (!val)
2331 val = FUNCTIONS;
2332 rpt_vars[n].p.simple = 1;
2334 rpt_vars[n].p.functions = val;
2335 val = (char *) ast_variable_retrieve(cfg,this,"link_functions");
2336 if (val) rpt_vars[n].p.link_functions = val;
2337 else
2338 rpt_vars[n].p.link_functions = rpt_vars[n].p.functions;
2339 val = (char *) ast_variable_retrieve(cfg,this,"phone_functions");
2340 if (val) rpt_vars[n].p.phone_functions = val;
2341 val = (char *) ast_variable_retrieve(cfg,this,"dphone_functions");
2342 if (val) rpt_vars[n].p.dphone_functions = val;
2343 val = (char *) ast_variable_retrieve(cfg,this,"alt_functions");
2344 if (val) rpt_vars[n].p.alt_functions = val;
2345 val = (char *) ast_variable_retrieve(cfg,this,"funcchar");
2346 if (!val) rpt_vars[n].p.funcchar = FUNCCHAR; else
2347 rpt_vars[n].p.funcchar = *val;
2348 val = (char *) ast_variable_retrieve(cfg,this,"endchar");
2349 if (!val) rpt_vars[n].p.endchar = ENDCHAR; else
2350 rpt_vars[n].p.endchar = *val;
2351 val = (char *) ast_variable_retrieve(cfg,this,"nobusyout");
2352 if (val) rpt_vars[n].p.nobusyout = ast_true(val);
2353 val = (char *) ast_variable_retrieve(cfg,this,"notelemtx");
2354 if (val) rpt_vars[n].p.notelemtx = ast_true(val);
2355 val = (char *) ast_variable_retrieve(cfg,this,"propagate_dtmf");
2356 if (val) rpt_vars[n].p.propagate_dtmf = ast_true(val);
2357 val = (char *) ast_variable_retrieve(cfg,this,"propagate_phonedtmf");
2358 if (val) rpt_vars[n].p.propagate_phonedtmf = ast_true(val);
2359 val = (char *) ast_variable_retrieve(cfg,this,"linktolink");
2360 if (val) rpt_vars[n].p.linktolink = ast_true(val);
2361 val = (char *) ast_variable_retrieve(cfg,this,"nodes");
2362 if (!val) val = NODES;
2363 rpt_vars[n].p.nodes = val;
2364 val = (char *) ast_variable_retrieve(cfg,this,"extnodes");
2365 if (!val) val = EXTNODES;
2366 rpt_vars[n].p.extnodes = val;
2367 val = (char *) ast_variable_retrieve(cfg,this,"extnodefile");
2368 if (!val) val = EXTNODEFILE;
2369 rpt_vars[n].p.extnodefile = val;
2370 val = (char *) ast_variable_retrieve(cfg,this,"archivedir");
2371 if (val) rpt_vars[n].p.archivedir = val;
2372 val = (char *) ast_variable_retrieve(cfg,this,"authlevel");
2373 if (val) rpt_vars[n].p.authlevel = atoi(val);
2374 else rpt_vars[n].p.authlevel = 0;
2375 val = (char *) ast_variable_retrieve(cfg,this,"parrot");
2376 if (val) rpt_vars[n].p.parrotmode = ast_true(val) * 2;
2377 else rpt_vars[n].p.parrotmode = 0;
2378 val = (char *) ast_variable_retrieve(cfg,this,"parrottime");
2379 if (val) rpt_vars[n].p.parrottime = atoi(val);
2380 else rpt_vars[n].p.parrottime = PARROTTIME;
2381 val = (char *) ast_variable_retrieve(cfg,this,"rptnode");
2382 rpt_vars[n].p.rptnode = val;
2383 val = (char *) ast_variable_retrieve(cfg,this,"mars");
2384 if (val) rpt_vars[n].p.remote_mars = atoi(val);
2385 else rpt_vars[n].p.remote_mars = 0;
2386 val = (char *) ast_variable_retrieve(cfg,this,"monminblocks");
2387 if (val) rpt_vars[n].p.monminblocks = atol(val);
2388 else rpt_vars[n].p.monminblocks = DEFAULT_MONITOR_MIN_DISK_BLOCKS;
2389 val = (char *) ast_variable_retrieve(cfg,this,"remote_inact_timeout");
2390 if (val) rpt_vars[n].p.remoteinacttimeout = atoi(val);
2391 else rpt_vars[n].p.remoteinacttimeout = DEFAULT_REMOTE_INACT_TIMEOUT;
2392 val = (char *) ast_variable_retrieve(cfg,this,"civaddr");
2393 if (val) rpt_vars[n].p.civaddr = atoi(val);
2394 else rpt_vars[n].p.civaddr = DEFAULT_CIV_ADDR;
2395 val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout");
2396 if (val) rpt_vars[n].p.remotetimeout = atoi(val);
2397 else rpt_vars[n].p.remotetimeout = DEFAULT_REMOTE_TIMEOUT;
2398 val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning");
2399 if (val) rpt_vars[n].p.remotetimeoutwarning = atoi(val);
2400 else rpt_vars[n].p.remotetimeoutwarning = DEFAULT_REMOTE_TIMEOUT_WARNING;
2401 val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning_freq");
2402 if (val) rpt_vars[n].p.remotetimeoutwarningfreq = atoi(val);
2403 else rpt_vars[n].p.remotetimeoutwarningfreq = DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ;
2404 #ifdef __RPT_NOTCH
2405 val = (char *) ast_variable_retrieve(cfg,this,"rxnotch");
2406 if (val) {
2407 i = finddelim(val,strs,MAXFILTERS * 2);
2408 i &= ~1; /* force an even number, rounded down */
2409 if (i >= 2) for(j = 0; j < i; j += 2)
2411 rpt_mknotch(atof(strs[j]),atof(strs[j + 1]),
2412 &rpt_vars[n].filters[j >> 1].gain,
2413 &rpt_vars[n].filters[j >> 1].const0,
2414 &rpt_vars[n].filters[j >> 1].const1,
2415 &rpt_vars[n].filters[j >> 1].const2);
2416 sprintf(rpt_vars[n].filters[j >> 1].desc,"%s Hz, BW = %s",
2417 strs[j],strs[j + 1]);
2421 #endif
2422 val = (char *) ast_variable_retrieve(cfg,this,"inxlat");
2423 if (val) {
2424 memset(&rpt_vars[n].p.inxlat,0,sizeof(struct rpt_xlat));
2425 i = finddelim(val,strs,3);
2426 if (i) strncpy(rpt_vars[n].p.inxlat.funccharseq,strs[0],MAXXLAT - 1);
2427 if (i > 1) strncpy(rpt_vars[n].p.inxlat.endcharseq,strs[1],MAXXLAT - 1);
2428 if (i > 2) strncpy(rpt_vars[n].p.inxlat.passchars,strs[2],MAXXLAT - 1);
2430 val = (char *) ast_variable_retrieve(cfg,this,"outxlat");
2431 if (val) {
2432 memset(&rpt_vars[n].p.outxlat,0,sizeof(struct rpt_xlat));
2433 i = finddelim(val,strs,3);
2434 if (i) strncpy(rpt_vars[n].p.outxlat.funccharseq,strs[0],MAXXLAT - 1);
2435 if (i > 1) strncpy(rpt_vars[n].p.outxlat.endcharseq,strs[1],MAXXLAT - 1);
2436 if (i > 2) strncpy(rpt_vars[n].p.outxlat.passchars,strs[2],MAXXLAT - 1);
2438 /* retreive the stanza name for the control states if there is one */
2439 val = (char *) ast_variable_retrieve(cfg,this,"controlstates");
2440 rpt_vars[n].p.csstanzaname = val;
2442 /* retreive the stanza name for the scheduler if there is one */
2443 val = (char *) ast_variable_retrieve(cfg,this,"scheduler");
2444 rpt_vars[n].p.skedstanzaname = val;
2446 /* retreive the stanza name for the txlimits */
2447 val = (char *) ast_variable_retrieve(cfg,this,"txlimits");
2448 rpt_vars[n].p.txlimitsstanzaname = val;
2450 longestnode = 0;
2452 vp = ast_variable_browse(cfg, rpt_vars[n].p.nodes);
2454 while(vp){
2455 j = strlen(vp->name);
2456 if (j > longestnode)
2457 longestnode = j;
2458 vp = vp->next;
2461 rpt_vars[n].longestnode = longestnode;
2464 * For this repeater, Determine the length of the longest function
2466 rpt_vars[n].longestfunc = 0;
2467 vp = ast_variable_browse(cfg, rpt_vars[n].p.functions);
2468 while(vp){
2469 j = strlen(vp->name);
2470 if (j > rpt_vars[n].longestfunc)
2471 rpt_vars[n].longestfunc = j;
2472 vp = vp->next;
2475 * For this repeater, Determine the length of the longest function
2477 rpt_vars[n].link_longestfunc = 0;
2478 vp = ast_variable_browse(cfg, rpt_vars[n].p.link_functions);
2479 while(vp){
2480 j = strlen(vp->name);
2481 if (j > rpt_vars[n].link_longestfunc)
2482 rpt_vars[n].link_longestfunc = j;
2483 vp = vp->next;
2485 rpt_vars[n].phone_longestfunc = 0;
2486 if (rpt_vars[n].p.phone_functions)
2488 vp = ast_variable_browse(cfg, rpt_vars[n].p.phone_functions);
2489 while(vp){
2490 j = strlen(vp->name);
2491 if (j > rpt_vars[n].phone_longestfunc)
2492 rpt_vars[n].phone_longestfunc = j;
2493 vp = vp->next;
2496 rpt_vars[n].dphone_longestfunc = 0;
2497 if (rpt_vars[n].p.dphone_functions)
2499 vp = ast_variable_browse(cfg, rpt_vars[n].p.dphone_functions);
2500 while(vp){
2501 j = strlen(vp->name);
2502 if (j > rpt_vars[n].dphone_longestfunc)
2503 rpt_vars[n].dphone_longestfunc = j;
2504 vp = vp->next;
2507 rpt_vars[n].alt_longestfunc = 0;
2508 if (rpt_vars[n].p.alt_functions)
2510 vp = ast_variable_browse(cfg, rpt_vars[n].p.alt_functions);
2511 while(vp){
2512 j = strlen(vp->name);
2513 if (j > rpt_vars[n].alt_longestfunc)
2514 rpt_vars[n].alt_longestfunc = j;
2515 vp = vp->next;
2518 rpt_vars[n].macro_longest = 1;
2519 vp = ast_variable_browse(cfg, rpt_vars[n].p.macro);
2520 while(vp){
2521 j = strlen(vp->name);
2522 if (j > rpt_vars[n].macro_longest)
2523 rpt_vars[n].macro_longest = j;
2524 vp = vp->next;
2527 /* Browse for control states */
2528 if(rpt_vars[n].p.csstanzaname)
2529 vp = ast_variable_browse(cfg, rpt_vars[n].p.csstanzaname);
2530 else
2531 vp = NULL;
2532 for( i = 0 ; vp && (i < MAX_SYSSTATES) ; i++){ /* Iterate over the number of control state lines in the stanza */
2533 int k,nukw,statenum;
2534 statenum=atoi(vp->name);
2535 strncpy(s1, vp->value, 255);
2536 s1[255] = 0;
2537 nukw = finddelim(s1,strs,32);
2539 for (k = 0 ; k < nukw ; k++){ /* for each user specified keyword */
2540 for(j = 0 ; cs_keywords[j] != NULL ; j++){ /* try to match to one in our internal table */
2541 if(!strcmp(strs[k],cs_keywords[j])){
2542 switch(j){
2543 case 0: /* rptena */
2544 rpt_vars[n].p.s[statenum].txdisable = 0;
2545 break;
2546 case 1: /* rptdis */
2547 rpt_vars[n].p.s[statenum].txdisable = 1;
2548 break;
2550 case 2: /* apena */
2551 rpt_vars[n].p.s[statenum].autopatchdisable = 0;
2552 break;
2554 case 3: /* apdis */
2555 rpt_vars[n].p.s[statenum].autopatchdisable = 1;
2556 break;
2558 case 4: /* lnkena */
2559 rpt_vars[n].p.s[statenum].linkfundisable = 0;
2560 break;
2562 case 5: /* lnkdis */
2563 rpt_vars[n].p.s[statenum].linkfundisable = 1;
2564 break;
2566 case 6: /* totena */
2567 rpt_vars[n].p.s[statenum].totdisable = 0;
2568 break;
2570 case 7: /* totdis */
2571 rpt_vars[n].p.s[statenum].totdisable = 1;
2572 break;
2574 case 8: /* skena */
2575 rpt_vars[n].p.s[statenum].schedulerdisable = 0;
2576 break;
2578 case 9: /* skdis */
2579 rpt_vars[n].p.s[statenum].schedulerdisable = 1;
2580 break;
2582 case 10: /* ufena */
2583 rpt_vars[n].p.s[statenum].userfundisable = 0;
2584 break;
2586 case 11: /* ufdis */
2587 rpt_vars[n].p.s[statenum].userfundisable = 1;
2588 break;
2590 case 12: /* atena */
2591 rpt_vars[n].p.s[statenum].alternatetail = 1;
2592 break;
2594 case 13: /* atdis */
2595 rpt_vars[n].p.s[statenum].alternatetail = 0;
2596 break;
2598 default:
2599 ast_log(LOG_WARNING,
2600 "Unhandled control state keyword %s", cs_keywords[i]);
2601 break;
2606 vp = vp->next;
2608 ast_mutex_unlock(&rpt_vars[n].lock);
2612 * Enable or disable debug output at a given level at the console
2615 static int rpt_do_debug(int fd, int argc, char *argv[])
2617 int newlevel;
2619 if (argc != 4)
2620 return RESULT_SHOWUSAGE;
2621 newlevel = myatoi(argv[3]);
2622 if((newlevel < 0) || (newlevel > 7))
2623 return RESULT_SHOWUSAGE;
2624 if(newlevel)
2625 ast_cli(fd, "app_rpt Debugging enabled, previous level: %d, new level: %d\n", debug, newlevel);
2626 else
2627 ast_cli(fd, "app_rpt Debugging disabled\n");
2629 debug = newlevel;
2630 return RESULT_SUCCESS;
2634 * Dump rpt struct debugging onto console
2637 static int rpt_do_dump(int fd, int argc, char *argv[])
2639 int i;
2641 if (argc != 3)
2642 return RESULT_SHOWUSAGE;
2644 for(i = 0; i < nrpts; i++)
2646 if (!strcmp(argv[2],rpt_vars[i].name))
2648 rpt_vars[i].disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
2649 ast_cli(fd, "app_rpt struct dump requested for node %s\n",argv[2]);
2650 return RESULT_SUCCESS;
2653 return RESULT_FAILURE;
2657 * Dump statistics onto console
2660 static int rpt_do_stats(int fd, int argc, char *argv[])
2662 int i,j,numoflinks;
2663 int dailytxtime, dailykerchunks;
2664 time_t now;
2665 int totalkerchunks, dailykeyups, totalkeyups, timeouts;
2666 int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
2667 int uptime;
2668 long long totaltxtime;
2669 struct rpt_link *l;
2670 char *listoflinks[MAX_STAT_LINKS];
2671 char *lastdtmfcommand,*parrot_ena;
2672 char *tot_state, *ider_state, *patch_state;
2673 char *reverse_patch_state, *sys_ena, *tot_ena, *link_ena, *patch_ena;
2674 char *sch_ena, *input_signal, *called_number, *user_funs, *tail_type;
2675 struct rpt *myrpt;
2677 static char *not_applicable = "N/A";
2679 if(argc != 3)
2680 return RESULT_SHOWUSAGE;
2682 tot_state = ider_state =
2683 patch_state = reverse_patch_state =
2684 input_signal = not_applicable;
2685 called_number = lastdtmfcommand = NULL;
2687 time(&now);
2688 for(i = 0; i < nrpts; i++)
2690 if (!strcmp(argv[2],rpt_vars[i].name)){
2691 /* Make a copy of all stat variables while locked */
2692 myrpt = &rpt_vars[i];
2693 rpt_mutex_lock(&myrpt->lock); /* LOCK */
2694 uptime = (int)(now - starttime);
2695 dailytxtime = myrpt->dailytxtime;
2696 totaltxtime = myrpt->totaltxtime;
2697 dailykeyups = myrpt->dailykeyups;
2698 totalkeyups = myrpt->totalkeyups;
2699 dailykerchunks = myrpt->dailykerchunks;
2700 totalkerchunks = myrpt->totalkerchunks;
2701 dailyexecdcommands = myrpt->dailyexecdcommands;
2702 totalexecdcommands = myrpt->totalexecdcommands;
2703 timeouts = myrpt->timeouts;
2705 /* Traverse the list of connected nodes */
2706 reverse_patch_state = "DOWN";
2707 numoflinks = 0;
2708 l = myrpt->links.next;
2709 while(l && (l != &myrpt->links)){
2710 if(numoflinks >= MAX_STAT_LINKS){
2711 ast_log(LOG_NOTICE,
2712 "maximum number of links exceeds %d in rpt_do_stats()!",MAX_STAT_LINKS);
2713 break;
2715 if (l->name[0] == '0'){ /* Skip '0' nodes */
2716 reverse_patch_state = "UP";
2717 l = l->next;
2718 continue;
2720 listoflinks[numoflinks] = ast_strdup(l->name);
2721 if(listoflinks[numoflinks] == NULL){
2722 break;
2724 else{
2725 numoflinks++;
2727 l = l->next;
2730 if(myrpt->keyed)
2731 input_signal = "YES";
2732 else
2733 input_signal = "NO";
2735 if(myrpt->p.parrotmode)
2736 parrot_ena = "ENABLED";
2737 else
2738 parrot_ena = "DISABLED";
2740 if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable)
2741 sys_ena = "DISABLED";
2742 else
2743 sys_ena = "ENABLED";
2745 if(myrpt->p.s[myrpt->p.sysstate_cur].totdisable)
2746 tot_ena = "DISABLED";
2747 else
2748 tot_ena = "ENABLED";
2750 if(myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable)
2751 link_ena = "DISABLED";
2752 else
2753 link_ena = "ENABLED";
2755 if(myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
2756 patch_ena = "DISABLED";
2757 else
2758 patch_ena = "ENABLED";
2760 if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable)
2761 sch_ena = "DISABLED";
2762 else
2763 sch_ena = "ENABLED";
2765 if(myrpt->p.s[myrpt->p.sysstate_cur].userfundisable)
2766 user_funs = "DISABLED";
2767 else
2768 user_funs = "ENABLED";
2770 if(myrpt->p.s[myrpt->p.sysstate_cur].alternatetail)
2771 tail_type = "ALTERNATE";
2772 else
2773 tail_type = "STANDARD";
2775 if(!myrpt->totimer)
2776 tot_state = "TIMED OUT!";
2777 else if(myrpt->totimer != myrpt->p.totime)
2778 tot_state = "ARMED";
2779 else
2780 tot_state = "RESET";
2782 if(myrpt->tailid)
2783 ider_state = "QUEUED IN TAIL";
2784 else if(myrpt->mustid)
2785 ider_state = "QUEUED FOR CLEANUP";
2786 else
2787 ider_state = "CLEAN";
2789 switch(myrpt->callmode){
2790 case 1:
2791 patch_state = "DIALING";
2792 break;
2793 case 2:
2794 patch_state = "CONNECTING";
2795 break;
2796 case 3:
2797 patch_state = "UP";
2798 break;
2800 case 4:
2801 patch_state = "CALL FAILED";
2802 break;
2804 default:
2805 patch_state = "DOWN";
2808 if(strlen(myrpt->exten)){
2809 called_number = ast_strdup(myrpt->exten);
2812 if(strlen(myrpt->lastdtmfcommand)){
2813 lastdtmfcommand = ast_strdup(myrpt->lastdtmfcommand);
2815 rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
2817 ast_cli(fd, "************************ NODE %s STATISTICS *************************\n\n", myrpt->name);
2818 ast_cli(fd, "Selected system state............................: %d\n", myrpt->p.sysstate_cur);
2819 ast_cli(fd, "Signal on input..................................: %s\n", input_signal);
2820 ast_cli(fd, "System...........................................: %s\n", sys_ena);
2821 ast_cli(fd, "Parrot Mode......................................: %s\n", parrot_ena);
2822 ast_cli(fd, "Scheduler........................................: %s\n", sch_ena);
2823 ast_cli(fd, "Tail Time........................................: %s\n", tail_type);
2824 ast_cli(fd, "Time out timer...................................: %s\n", tot_ena);
2825 ast_cli(fd, "Time out timer state.............................: %s\n", tot_state);
2826 ast_cli(fd, "Time outs since system initialization............: %d\n", timeouts);
2827 ast_cli(fd, "Identifier state.................................: %s\n", ider_state);
2828 ast_cli(fd, "Kerchunks today..................................: %d\n", dailykerchunks);
2829 ast_cli(fd, "Kerchunks since system initialization............: %d\n", totalkerchunks);
2830 ast_cli(fd, "Keyups today.....................................: %d\n", dailykeyups);
2831 ast_cli(fd, "Keyups since system initialization...............: %d\n", totalkeyups);
2832 ast_cli(fd, "DTMF commands today..............................: %d\n", dailyexecdcommands);
2833 ast_cli(fd, "DTMF commands since system initialization........: %d\n", totalexecdcommands);
2834 ast_cli(fd, "Last DTMF command executed.......................: %s\n",
2835 (lastdtmfcommand && strlen(lastdtmfcommand)) ? lastdtmfcommand : not_applicable);
2836 hours = dailytxtime/3600000;
2837 dailytxtime %= 3600000;
2838 minutes = dailytxtime/60000;
2839 dailytxtime %= 60000;
2840 seconds = dailytxtime/1000;
2841 dailytxtime %= 1000;
2843 ast_cli(fd, "TX time today....................................: %02d:%02d:%02d.%d\n",
2844 hours, minutes, seconds, dailytxtime);
2846 hours = (int) totaltxtime/3600000;
2847 totaltxtime %= 3600000;
2848 minutes = (int) totaltxtime/60000;
2849 totaltxtime %= 60000;
2850 seconds = (int) totaltxtime/1000;
2851 totaltxtime %= 1000;
2853 ast_cli(fd, "TX time since system initialization..............: %02d:%02d:%02d.%d\n",
2854 hours, minutes, seconds, (int) totaltxtime);
2856 hours = uptime/3600;
2857 uptime %= 3600;
2858 minutes = uptime/60;
2859 uptime %= 60;
2861 ast_cli(fd, "Uptime...........................................: %02d:%02d:%02d\n",
2862 hours, minutes, uptime);
2864 ast_cli(fd, "Nodes currently connected to us..................: ");
2865 if(!numoflinks){
2866 ast_cli(fd,"<NONE>");
2868 else{
2869 for(j = 0 ;j < numoflinks; j++){
2870 ast_cli(fd, "%s", listoflinks[j]);
2871 if(j % 4 == 3){
2872 ast_cli(fd, "\n");
2873 ast_cli(fd, " : ");
2875 else{
2876 if((numoflinks - 1) - j > 0)
2877 ast_cli(fd, ", ");
2881 ast_cli(fd,"\n");
2883 ast_cli(fd, "Autopatch........................................: %s\n", patch_ena);
2884 ast_cli(fd, "Autopatch state..................................: %s\n", patch_state);
2885 ast_cli(fd, "Autopatch called number..........................: %s\n",
2886 (called_number && strlen(called_number)) ? called_number : not_applicable);
2887 ast_cli(fd, "Reverse patch/IAXRPT connected...................: %s\n", reverse_patch_state);
2888 ast_cli(fd, "User linking commands............................: %s\n", link_ena);
2889 ast_cli(fd, "User functions...................................: %s\n\n", user_funs);
2891 for(j = 0; j < numoflinks; j++){ /* ast_free() all link names */
2892 ast_free(listoflinks[j]);
2894 if(called_number){
2895 ast_free(called_number);
2897 if(lastdtmfcommand){
2898 ast_free(lastdtmfcommand);
2900 return RESULT_SUCCESS;
2903 return RESULT_FAILURE;
2907 * Link stats function
2910 static int rpt_do_lstats(int fd, int argc, char *argv[])
2912 int i,j;
2913 char *connstate;
2914 struct rpt *myrpt;
2915 struct rpt_link *l;
2916 struct rpt_lstat *s,*t;
2917 struct rpt_lstat s_head;
2918 if(argc != 3)
2919 return RESULT_SHOWUSAGE;
2921 s = NULL;
2922 s_head.next = &s_head;
2923 s_head.prev = &s_head;
2925 for(i = 0; i < nrpts; i++)
2927 if (!strcmp(argv[2],rpt_vars[i].name)){
2928 /* Make a copy of all stat variables while locked */
2929 myrpt = &rpt_vars[i];
2930 rpt_mutex_lock(&myrpt->lock); /* LOCK */
2931 /* Traverse the list of connected nodes */
2932 j = 0;
2933 l = myrpt->links.next;
2934 while(l && (l != &myrpt->links)){
2935 if (l->name[0] == '0'){ /* Skip '0' nodes */
2936 l = l->next;
2937 continue;
2939 if((s = (struct rpt_lstat *) ast_malloc(sizeof(struct rpt_lstat))) == NULL){
2940 ast_log(LOG_ERROR, "Malloc failed in rpt_do_lstats\n");
2941 rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
2942 return RESULT_FAILURE;
2944 memset(s, 0, sizeof(struct rpt_lstat));
2945 strncpy(s->name, l->name, MAXREMSTR - 1);
2946 if (l->chan) pbx_substitute_variables_helper(l->chan, "${IAXPEER(CURRENTCHANNEL)}", s->peer, MAXPEERSTR - 1);
2947 else strcpy(s->peer,"(none)");
2948 s->mode = l->mode;
2949 s->outbound = l->outbound;
2950 s->reconnects = l->reconnects;
2951 s->connecttime = l->connecttime;
2952 s->thisconnected = l->thisconnected;
2953 memcpy(s->chan_stat,l->chan_stat,NRPTSTAT * sizeof(struct rpt_chan_stat));
2954 insque((struct qelem *) s, (struct qelem *) s_head.next);
2955 memset(l->chan_stat,0,NRPTSTAT * sizeof(struct rpt_chan_stat));
2956 l = l->next;
2958 rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
2959 ast_cli(fd, "NODE PEER RECONNECTS DIRECTION CONNECT TIME CONNECT STATE\n");
2960 ast_cli(fd, "---- ---- ---------- --------- ------------ -------------\n");
2962 for(s = s_head.next; s != &s_head; s = s->next){
2963 int hours, minutes, seconds;
2964 long long connecttime = s->connecttime;
2965 char conntime[21];
2966 hours = (int) connecttime/3600000;
2967 connecttime %= 3600000;
2968 minutes = (int) connecttime/60000;
2969 connecttime %= 60000;
2970 seconds = (int) connecttime/1000;
2971 connecttime %= 1000;
2972 snprintf(conntime, 20, "%02d:%02d:%02d.%d",
2973 hours, minutes, seconds, (int) connecttime);
2974 conntime[20] = 0;
2975 if(s->thisconnected)
2976 connstate = "ESTABLISHED";
2977 else
2978 connstate = "CONNECTING";
2979 ast_cli(fd, "%-10s%-20s%-12d%-11s%-20s%-20s\n",
2980 s->name, s->peer, s->reconnects, (s->outbound)? "OUT":"IN", conntime, connstate);
2982 /* destroy our local link queue */
2983 s = s_head.next;
2984 while(s != &s_head){
2985 t = s;
2986 s = s->next;
2987 remque((struct qelem *)t);
2988 ast_free(t);
2990 return RESULT_SUCCESS;
2993 return RESULT_FAILURE;
2997 * List all nodes connected, directly or indirectly
3000 static int rpt_do_nodes(int fd, int argc, char *argv[])
3002 int i,j;
3003 char ns;
3004 char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
3005 struct rpt *myrpt;
3006 if(argc != 3)
3007 return RESULT_SHOWUSAGE;
3009 for(i = 0; i < nrpts; i++)
3011 if (!strcmp(argv[2],rpt_vars[i].name)){
3012 /* Make a copy of all stat variables while locked */
3013 myrpt = &rpt_vars[i];
3014 rpt_mutex_lock(&myrpt->lock); /* LOCK */
3015 __mklinklist(myrpt,NULL,lbuf);
3016 rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
3017 /* parse em */
3018 ns = finddelim(lbuf,strs,MAXLINKLIST);
3019 /* sort em */
3020 if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar);
3021 ast_cli(fd,"\n");
3022 ast_cli(fd, "************************* CONNECTED NODES *************************\n\n");
3023 for(j = 0 ;; j++){
3024 if(!strs[j]){
3025 if(!j){
3026 ast_cli(fd,"<NONE>");
3028 break;
3030 ast_cli(fd, "%s", strs[j]);
3031 if(j % 8 == 7){
3032 ast_cli(fd, "\n");
3034 else{
3035 if(strs[j + 1])
3036 ast_cli(fd, ", ");
3039 ast_cli(fd,"\n\n");
3040 return RESULT_SUCCESS;
3043 return RESULT_FAILURE;
3047 * List all locally configured nodes
3050 static int rpt_do_local_nodes(int fd, int argc, char *argv[])
3053 int i;
3054 ast_cli(fd, "\nNode\n----\n");
3055 for (i=0; i< nrpts; i++)
3057 ast_cli(fd, "%s\n", rpt_vars[i].name);
3058 } /* for i */
3059 ast_cli(fd,"\n");
3060 return RESULT_SUCCESS;
3065 * reload vars
3068 static int rpt_do_reload(int fd, int argc, char *argv[])
3070 int n;
3072 if (argc > 2) return RESULT_SHOWUSAGE;
3074 for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
3076 return RESULT_FAILURE;
3080 * restart app_rpt
3083 static int rpt_do_restart(int fd, int argc, char *argv[])
3085 int i;
3087 if (argc > 2) return RESULT_SHOWUSAGE;
3088 for(i = 0; i < nrpts; i++)
3090 if (rpt_vars[i].rxchannel) ast_softhangup(rpt_vars[i].rxchannel,AST_SOFTHANGUP_DEV);
3092 return RESULT_FAILURE;
3097 * send an app_rpt DTMF function from the CLI
3100 static int rpt_do_fun(int fd, int argc, char *argv[])
3102 int i,busy=0;
3104 if (argc != 4) return RESULT_SHOWUSAGE;
3106 for(i = 0; i < nrpts; i++){
3107 if(!strcmp(argv[2], rpt_vars[i].name)){
3108 struct rpt *myrpt = &rpt_vars[i];
3109 rpt_mutex_lock(&myrpt->lock);
3110 if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(argv[3])){
3111 rpt_mutex_unlock(&myrpt->lock);
3112 busy=1;
3114 if(!busy){
3115 myrpt->macrotimer = MACROTIME;
3116 strncat(myrpt->macrobuf,argv[3],MAXMACRO - 1);
3118 rpt_mutex_unlock(&myrpt->lock);
3121 if(busy){
3122 ast_cli(fd, "Function decoder busy");
3124 return RESULT_FAILURE;
3127 the convention is that macros in the data from the rpt() application
3128 are all at the end of the data, separated by the | and start with a *
3129 when put into the macro buffer, the characters have their high bit
3130 set so the macro processor knows they came from the application data
3131 and to use the alt-functions table.
3132 sph:
3134 static int rpt_push_alt_macro(struct rpt *myrpt, char *sptr)
3136 int busy=0;
3138 rpt_mutex_lock(&myrpt->lock);
3139 if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(sptr)){
3140 rpt_mutex_unlock(&myrpt->lock);
3141 busy=1;
3143 if(!busy){
3144 int x;
3145 if (debug)ast_log(LOG_NOTICE, "rpt_push_alt_macro %s\n",sptr);
3146 myrpt->macrotimer = MACROTIME;
3147 for(x = 0; *(sptr + x); x++)
3148 myrpt->macrobuf[x] = *(sptr + x) | 0x80;
3149 *(sptr + x) = 0;
3151 rpt_mutex_unlock(&myrpt->lock);
3153 if(busy)ast_log(LOG_WARNING, "Function decoder busy on app_rpt command macro.\n");
3155 return busy;
3158 allows us to test rpt() application data commands
3160 static int rpt_do_fun1(int fd, int argc, char *argv[])
3162 int i;
3164 if (argc != 4) return RESULT_SHOWUSAGE;
3166 for(i = 0; i < nrpts; i++){
3167 if(!strcmp(argv[2], rpt_vars[i].name)){
3168 struct rpt *myrpt = &rpt_vars[i];
3169 rpt_push_alt_macro(myrpt,argv[3]);
3172 return RESULT_FAILURE;
3175 * send an app_rpt **command** from the CLI
3178 static int rpt_do_cmd(int fd, int argc, char *argv[])
3180 int i, l;
3181 int busy=0;
3182 int maxActions = sizeof(function_table)/sizeof(struct function_table_tag);
3184 int thisRpt = -1;
3185 int thisAction = -1;
3186 struct rpt *myrpt = NULL;
3187 if (argc != 6) return RESULT_SHOWUSAGE;
3189 for(i = 0; i < nrpts; i++)
3191 if(!strcmp(argv[2], rpt_vars[i].name))
3193 thisRpt = i;
3194 myrpt = &rpt_vars[i];
3195 break;
3196 } /* if !strcmp... */
3197 } /* for i */
3199 if (thisRpt < 0)
3201 ast_cli(fd, "Unknown node number %s.\n", argv[2]);
3202 return RESULT_FAILURE;
3203 } /* if thisRpt < 0 */
3205 /* Look up the action */
3206 l = strlen(argv[3]);
3207 for(i = 0 ; i < maxActions; i++)
3209 if(!strncasecmp(argv[3], function_table[i].action, l))
3211 thisAction = i;
3212 break;
3213 } /* if !strncasecmp... */
3214 } /* for i */
3216 if (thisAction < 0)
3218 ast_cli(fd, "Unknown action name %s.\n", argv[3]);
3219 return RESULT_FAILURE;
3220 } /* if thisAction < 0 */
3222 /* at this point, it looks like all the arguments make sense... */
3224 rpt_mutex_lock(&myrpt->lock);
3226 if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE)
3228 rpt_vars[thisRpt].cmdAction.state = CMD_STATE_BUSY;
3229 rpt_vars[thisRpt].cmdAction.functionNumber = thisAction;
3230 strncpy(rpt_vars[thisRpt].cmdAction.param, argv[4], MAXDTMF);
3231 strncpy(rpt_vars[thisRpt].cmdAction.digits, argv[5], MAXDTMF);
3232 rpt_vars[thisRpt].cmdAction.command_source = SOURCE_RPT;
3233 rpt_vars[thisRpt].cmdAction.state = CMD_STATE_READY;
3234 } /* if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE */
3235 else
3237 busy = 1;
3238 } /* if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE */
3239 rpt_mutex_unlock(&myrpt->lock);
3241 return (busy ? RESULT_FAILURE : RESULT_SUCCESS);
3242 } /* rpt_do_cmd() */
3244 static int play_tone_pair(struct ast_channel *chan, int f1, int f2, int duration, int amplitude)
3246 int res;
3248 if ((res = ast_tonepair_start(chan, f1, f2, duration, amplitude)))
3249 return res;
3251 while(chan->generatordata) {
3252 if (ast_safe_sleep(chan,1)) return -1;
3255 return 0;
3258 static int play_tone(struct ast_channel *chan, int freq, int duration, int amplitude)
3260 return play_tone_pair(chan, freq, 0, duration, amplitude);
3263 static int play_silence(struct ast_channel *chan, int duration)
3265 return play_tone_pair(chan, 0, 0, duration, 0);
3268 #ifdef NEW_ASTERISK
3270 static char *res2cli(int r)
3273 switch (r)
3275 case RESULT_SUCCESS:
3276 return(CLI_SUCCESS);
3277 case RESULT_SHOWUSAGE:
3278 return(CLI_SHOWUSAGE);
3279 default:
3280 return(CLI_FAILURE);
3284 static char *handle_cli_debug(struct ast_cli_entry *e,
3285 int cmd, struct ast_cli_args *a)
3287 switch (cmd) {
3288 case CLI_INIT:
3289 e->command = "rpt debug level";
3290 e->usage = debug_usage;
3291 return NULL;
3292 case CLI_GENERATE:
3293 return NULL;
3295 return res2cli(rpt_do_debug(a->fd,a->argc,a->argv));
3298 static char *handle_cli_dump(struct ast_cli_entry *e,
3299 int cmd, struct ast_cli_args *a)
3301 switch (cmd) {
3302 case CLI_INIT:
3303 e->command = "rpt dump level";
3304 e->usage = dump_usage;
3305 return NULL;
3306 case CLI_GENERATE:
3307 return NULL;
3309 return res2cli(rpt_do_dump(a->fd,a->argc,a->argv));
3313 static char *handle_cli_stats(struct ast_cli_entry *e,
3314 int cmd, struct ast_cli_args *a)
3316 switch (cmd) {
3317 case CLI_INIT:
3318 e->command = "rpt stats";
3319 e->usage = dump_stats;
3320 return NULL;
3321 case CLI_GENERATE:
3322 return NULL;
3324 return res2cli(rpt_do_stats(a->fd,a->argc,a->argv));
3327 static char *handle_cli_nodes(struct ast_cli_entry *e,
3328 int cmd, struct ast_cli_args *a)
3330 switch (cmd) {
3331 case CLI_INIT:
3332 e->command = "rpt nodes";
3333 e->usage = dump_nodes;
3334 return NULL;
3335 case CLI_GENERATE:
3336 return NULL;
3338 return res2cli(rpt_do_nodes(a->fd,a->argc,a->argv));
3341 static char *handle_cli_local_nodes(struct ast_cli_entry *e,
3342 int cmd, struct ast_cli_args *a)
3344 switch (cmd) {
3345 case CLI_INIT:
3346 e->command = "rpt localnodes";
3347 e->usage = usage_local_nodes;
3348 return NULL;
3349 case CLI_GENERATE:
3350 return NULL;
3352 return res2cli(rpt_do_local_nodes(a->fd,a->argc,a->argv));
3355 static char *handle_cli_lstats(struct ast_cli_entry *e,
3356 int cmd, struct ast_cli_args *a)
3358 switch (cmd) {
3359 case CLI_INIT:
3360 e->command = "rpt lstats";
3361 e->usage = dump_lstats;
3362 return NULL;
3363 case CLI_GENERATE:
3364 return NULL;
3366 return res2cli(rpt_do_lstats(a->fd,a->argc,a->argv));
3369 static char *handle_cli_reload(struct ast_cli_entry *e,
3370 int cmd, struct ast_cli_args *a)
3372 switch (cmd) {
3373 case CLI_INIT:
3374 e->command = "rpt reload";
3375 e->usage = reload_usage;
3376 return NULL;
3377 case CLI_GENERATE:
3378 return NULL;
3380 return res2cli(rpt_do_reload(a->fd,a->argc,a->argv));
3383 static char *handle_cli_restart(struct ast_cli_entry *e,
3384 int cmd, struct ast_cli_args *a)
3386 switch (cmd) {
3387 case CLI_INIT:
3388 e->command = "rpt restart";
3389 e->usage = restart_usage;
3390 return NULL;
3391 case CLI_GENERATE:
3392 return NULL;
3394 return res2cli(rpt_do_restart(a->fd,a->argc,a->argv));
3397 static char *handle_cli_fun(struct ast_cli_entry *e,
3398 int cmd, struct ast_cli_args *a)
3400 switch (cmd) {
3401 case CLI_INIT:
3402 e->command = "rpt fun";
3403 e->usage = fun_usage;
3404 return NULL;
3405 case CLI_GENERATE:
3406 return NULL;
3408 return res2cli(rpt_do_fun(a->fd,a->argc,a->argv));
3411 static char *handle_cli_fun1(struct ast_cli_entry *e,
3412 int cmd, struct ast_cli_args *a)
3414 switch (cmd) {
3415 case CLI_INIT:
3416 e->command = "rpt fun1";
3417 e->usage = fun_usage;
3418 return NULL;
3419 case CLI_GENERATE:
3420 return NULL;
3422 return res2cli(rpt_do_fun1(a->fd,a->argc,a->argv));
3425 static char *handle_cli_cmd(struct ast_cli_entry *e,
3426 int cmd, struct ast_cli_args *a)
3428 switch (cmd) {
3429 case CLI_INIT:
3430 e->command = "rpt cmd";
3431 e->usage = cmd_usage;
3432 return NULL;
3433 case CLI_GENERATE:
3434 return NULL;
3436 return res2cli(rpt_do_cmd(a->fd,a->argc,a->argv));
3439 static struct ast_cli_entry rpt_cli[] = {
3440 AST_CLI_DEFINE(handle_cli_debug,"Enable app_rpt debugging"),
3441 AST_CLI_DEFINE(handle_cli_dump,"Dump app_rpt structs for debugging"),
3442 AST_CLI_DEFINE(handle_cli_stats,"Dump node statistics"),
3443 AST_CLI_DEFINE(handle_cli_nodes,"Dump node list"),
3444 AST_CLI_DEFINE(handle_cli_local_nodes, "Dump list of local node numbers"),
3445 AST_CLI_DEFINE(handle_cli_lstats,"Dump link statistics"),
3446 AST_CLI_DEFINE(handle_cli_reload,"Reload app_rpt config"),
3447 AST_CLI_DEFINE(handle_cli_restart,"Restart app_rpt"),
3448 AST_CLI_DEFINE(handle_cli_fun,"Execute a DTMF function"),
3449 AST_CLI_DEFINE(handle_cli_fun1,"Execute a DTMF function"),
3450 AST_CLI_DEFINE(handle_cli_cmd,"Execute a DTMF function")
3453 #endif
3455 static int send_morse(struct ast_channel *chan, char *string, int speed, int freq, int amplitude)
3458 static struct morse_bits mbits[] = {
3459 {0, 0}, /* SPACE */
3460 {0, 0},
3461 {6, 18},/* " */
3462 {0, 0},
3463 {7, 72},/* $ */
3464 {0, 0},
3465 {0, 0},
3466 {6, 30},/* ' */
3467 {5, 13},/* ( */
3468 {6, 29},/* ) */
3469 {0, 0},
3470 {5, 10},/* + */
3471 {6, 51},/* , */
3472 {6, 33},/* - */
3473 {6, 42},/* . */
3474 {5, 9}, /* / */
3475 {5, 31},/* 0 */
3476 {5, 30},/* 1 */
3477 {5, 28},/* 2 */
3478 {5, 24},/* 3 */
3479 {5, 16},/* 4 */
3480 {5, 0}, /* 5 */
3481 {5, 1}, /* 6 */
3482 {5, 3}, /* 7 */
3483 {5, 7}, /* 8 */
3484 {5, 15},/* 9 */
3485 {6, 7}, /* : */
3486 {6, 21},/* ; */
3487 {0, 0},
3488 {5, 33},/* = */
3489 {0, 0},
3490 {6, 12},/* ? */
3491 {0, 0},
3492 {2, 2}, /* A */
3493 {4, 1}, /* B */
3494 {4, 5}, /* C */
3495 {3, 1}, /* D */
3496 {1, 0}, /* E */
3497 {4, 4}, /* F */
3498 {3, 3}, /* G */
3499 {4, 0}, /* H */
3500 {2, 0}, /* I */
3501 {4, 14},/* J */
3502 {3, 5}, /* K */
3503 {4, 2}, /* L */
3504 {2, 3}, /* M */
3505 {2, 1}, /* N */
3506 {3, 7}, /* O */
3507 {4, 6}, /* P */
3508 {4, 11},/* Q */
3509 {3, 2}, /* R */
3510 {3, 0}, /* S */
3511 {1, 1}, /* T */
3512 {3, 4}, /* U */
3513 {4, 8}, /* V */
3514 {3, 6}, /* W */
3515 {4, 9}, /* X */
3516 {4, 13},/* Y */
3517 {4, 3} /* Z */
3521 int dottime;
3522 int dashtime;
3523 int intralettertime;
3524 int interlettertime;
3525 int interwordtime;
3526 int len, ddcomb;
3527 int res;
3528 int c;
3529 int i;
3530 int flags;
3532 res = 0;
3534 /* Approximate the dot time from the speed arg. */
3536 dottime = 900/speed;
3538 /* Establish timing releationships */
3540 dashtime = 3 * dottime;
3541 intralettertime = dottime;
3542 interlettertime = dottime * 4 ;
3543 interwordtime = dottime * 7;
3545 for(;(*string) && (!res); string++){
3547 c = *string;
3549 /* Convert lower case to upper case */
3551 if((c >= 'a') && (c <= 'z'))
3552 c -= 0x20;
3554 /* Can't deal with any char code greater than Z, skip it */
3556 if(c > 'Z')
3557 continue;
3559 /* If space char, wait the inter word time */
3561 if(c == ' '){
3562 if(!res)
3563 res = play_silence(chan, interwordtime);
3564 continue;
3567 /* Subtract out control char offset to match our table */
3569 c -= 0x20;
3571 /* Get the character data */
3573 len = mbits[c].len;
3574 ddcomb = mbits[c].ddcomb;
3576 /* Send the character */
3578 for(; len ; len--){
3579 if(!res)
3580 res = play_tone(chan, freq, (ddcomb & 1) ? dashtime : dottime, amplitude);
3581 if(!res)
3582 res = play_silence(chan, intralettertime);
3583 ddcomb >>= 1;
3586 /* Wait the interletter time */
3588 if(!res)
3589 res = play_silence(chan, interlettertime - intralettertime);
3592 /* Wait for all the frames to be sent */
3594 if (!res)
3595 res = ast_waitstream(chan, "");
3596 ast_stopstream(chan);
3599 * Wait for the DAHDI driver to physically write the tone blocks to the hardware
3602 for(i = 0; i < 20 ; i++){
3603 flags = DAHDI_IOMUX_WRITEEMPTY | DAHDI_IOMUX_NOWAIT;
3604 res = ioctl(chan->fds[0], DAHDI_IOMUX, &flags);
3605 if(flags & DAHDI_IOMUX_WRITEEMPTY)
3606 break;
3607 if( ast_safe_sleep(chan, 50)){
3608 res = -1;
3609 break;
3614 return res;
3617 static int send_tone_telemetry(struct ast_channel *chan, char *tonestring)
3619 char *p,*stringp;
3620 char *tonesubset;
3621 int f1,f2;
3622 int duration;
3623 int amplitude;
3624 int res;
3625 int i;
3626 int flags;
3628 res = 0;
3630 if(!tonestring)
3631 return res;
3633 p = stringp = ast_strdup(tonestring);
3635 for(;tonestring;){
3636 tonesubset = strsep(&stringp,")");
3637 if(!tonesubset)
3638 break;
3639 if(sscanf(tonesubset,"(%d,%d,%d,%d", &f1, &f2, &duration, &amplitude) != 4)
3640 break;
3641 res = play_tone_pair(chan, f1, f2, duration, amplitude);
3642 if(res)
3643 break;
3645 if(p)
3646 ast_free(p);
3647 if(!res)
3648 res = play_tone_pair(chan, 0, 0, 100, 0); /* This is needed to ensure the last tone segment is timed correctly */
3650 if (!res)
3651 res = ast_waitstream(chan, "");
3653 ast_stopstream(chan);
3656 * Wait for the DAHDI driver to physically write the tone blocks to the hardware
3659 for(i = 0; i < 20 ; i++){
3660 flags = DAHDI_IOMUX_WRITEEMPTY | DAHDI_IOMUX_NOWAIT;
3661 res = ioctl(chan->fds[0], DAHDI_IOMUX, &flags);
3662 if(flags & DAHDI_IOMUX_WRITEEMPTY)
3663 break;
3664 if( ast_safe_sleep(chan, 50)){
3665 res = -1;
3666 break;
3670 return res;
3674 static int sayfile(struct ast_channel *mychannel,char *fname)
3676 int res;
3678 res = ast_streamfile(mychannel, fname, mychannel->language);
3679 if (!res)
3680 res = ast_waitstream(mychannel, "");
3681 else
3682 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3683 ast_stopstream(mychannel);
3684 return res;
3687 static int saycharstr(struct ast_channel *mychannel,char *str)
3689 int res;
3691 res = ast_say_character_str(mychannel,str,NULL,mychannel->language);
3692 if (!res)
3693 res = ast_waitstream(mychannel, "");
3694 else
3695 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3696 ast_stopstream(mychannel);
3697 return res;
3700 static int saynum(struct ast_channel *mychannel, int num)
3702 int res;
3703 res = ast_say_number(mychannel, num, NULL, mychannel->language, NULL);
3704 if(!res)
3705 res = ast_waitstream(mychannel, "");
3706 else
3707 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3708 ast_stopstream(mychannel);
3709 return res;
3712 /* say a node and nodename. Try to look in dir referred to by nodenames in
3713 config, and see if there's a custom node file to play, and if so, play it */
3715 static int saynode(struct rpt *myrpt, struct ast_channel *mychannel, char *name)
3717 int res;
3718 char *val,fname[300];
3720 val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "nodenames");
3721 if (!val) val = NODENAMES;
3722 snprintf(fname,sizeof(fname) - 1,"%s/%s",val,name);
3723 if (ast_fileexists(fname,NULL,mychannel->language) > 0)
3724 return(sayfile(mychannel,fname));
3725 res = sayfile(mychannel,"rpt/node");
3726 if (!res)
3727 res = ast_say_character_str(mychannel,name,NULL,mychannel->language);
3728 return res;
3731 static int telem_any(struct rpt *myrpt,struct ast_channel *chan, char *entry)
3733 int res;
3734 char c;
3736 static int morsespeed;
3737 static int morsefreq;
3738 static int morseampl;
3739 static int morseidfreq = 0;
3740 static int morseidampl;
3741 static char mcat[] = MORSE;
3743 res = 0;
3745 if(!morseidfreq){ /* Get the morse parameters if not already loaded */
3746 morsespeed = retrieve_astcfgint(myrpt, mcat, "speed", 5, 20, 20);
3747 morsefreq = retrieve_astcfgint(myrpt, mcat, "frequency", 300, 3000, 800);
3748 morseampl = retrieve_astcfgint(myrpt, mcat, "amplitude", 200, 8192, 4096);
3749 morseidampl = retrieve_astcfgint(myrpt, mcat, "idamplitude", 200, 8192, 2048);
3750 morseidfreq = retrieve_astcfgint(myrpt, mcat, "idfrequency", 300, 3000, 330);
3753 /* Is it a file, or a tone sequence? */
3755 if(entry[0] == '|'){
3756 c = entry[1];
3757 if((c >= 'a')&&(c <= 'z'))
3758 c -= 0x20;
3760 switch(c){
3761 case 'I': /* Morse ID */
3762 res = send_morse(chan, entry + 2, morsespeed, morseidfreq, morseidampl);
3763 break;
3765 case 'M': /* Morse Message */
3766 res = send_morse(chan, entry + 2, morsespeed, morsefreq, morseampl);
3767 break;
3769 case 'T': /* Tone sequence */
3770 res = send_tone_telemetry(chan, entry + 2);
3771 break;
3772 default:
3773 res = -1;
3776 else
3777 res = sayfile(chan, entry); /* File */
3778 return res;
3782 * This function looks up a telemetry name in the config file, and does a telemetry response as configured.
3784 * 4 types of telemtry are handled: Morse ID, Morse Message, Tone Sequence, and a File containing a recording.
3787 static int telem_lookup(struct rpt *myrpt,struct ast_channel *chan, char *node, char *name)
3790 int res;
3791 int i;
3792 char *entry;
3793 char *telemetry;
3794 char *telemetry_save;
3796 res = 0;
3797 telemetry_save = NULL;
3798 entry = NULL;
3800 /* Retrieve the section name for telemetry from the node section */
3801 telemetry = (char *) ast_variable_retrieve(myrpt->cfg, node, TELEMETRY);
3802 if(telemetry ){
3803 telemetry_save = ast_strdup(telemetry);
3804 if(!telemetry_save){
3805 ast_log(LOG_WARNING,"ast_strdup() failed in telem_lookup()\n");
3806 return res;
3808 entry = (char *) ast_variable_retrieve(myrpt->cfg, telemetry_save, name);
3811 /* Try to look up the telemetry name */
3813 if(!entry){
3814 /* Telemetry name wasn't found in the config file, use the default */
3815 for(i = 0; i < sizeof(tele_defs)/sizeof(struct telem_defaults) ; i++){
3816 if(!strcasecmp(tele_defs[i].name, name))
3817 entry = tele_defs[i].value;
3820 if(entry){
3821 if(strlen(entry))
3822 if (chan) telem_any(myrpt,chan, entry);
3824 else{
3825 res = -1;
3827 if(telemetry_save)
3828 ast_free(telemetry_save);
3829 return res;
3833 * Retrieve a wait interval
3836 static int get_wait_interval(struct rpt *myrpt, int type)
3838 int interval;
3839 char *wait_times;
3840 char *wait_times_save;
3842 wait_times_save = NULL;
3843 wait_times = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "wait_times");
3845 if(wait_times){
3846 wait_times_save = ast_strdup(wait_times);
3847 if(!wait_times_save)
3848 return 0;
3852 switch(type){
3853 case DLY_TELEM:
3854 if(wait_times)
3855 interval = retrieve_astcfgint(myrpt,wait_times_save, "telemwait", 500, 5000, 1000);
3856 else
3857 interval = 1000;
3858 break;
3860 case DLY_ID:
3861 if(wait_times)
3862 interval = retrieve_astcfgint(myrpt,wait_times_save, "idwait",250,5000,500);
3863 else
3864 interval = 500;
3865 break;
3867 case DLY_UNKEY:
3868 if(wait_times)
3869 interval = retrieve_astcfgint(myrpt,wait_times_save, "unkeywait",50,5000,1000);
3870 else
3871 interval = 1000;
3872 break;
3874 case DLY_LINKUNKEY:
3875 if(wait_times)
3876 interval = retrieve_astcfgint(myrpt,wait_times_save, "linkunkeywait",500,5000,1000);
3877 else
3878 interval = 1000;
3879 break;
3881 case DLY_CALLTERM:
3882 if(wait_times)
3883 interval = retrieve_astcfgint(myrpt,wait_times_save, "calltermwait",500,5000,1500);
3884 else
3885 interval = 1500;
3886 break;
3888 case DLY_COMP:
3889 if(wait_times)
3890 interval = retrieve_astcfgint(myrpt,wait_times_save, "compwait",500,5000,200);
3891 else
3892 interval = 200;
3893 break;
3895 case DLY_PARROT:
3896 if(wait_times)
3897 interval = retrieve_astcfgint(myrpt,wait_times_save, "parrotwait",500,5000,200);
3898 else
3899 interval = 200;
3900 break;
3902 default:
3903 interval = 0;
3904 break;
3906 if(wait_times_save)
3907 ast_free(wait_times_save);
3908 return interval;
3913 * Wait a configurable interval of time
3915 static void wait_interval(struct rpt *myrpt, int type, struct ast_channel *chan)
3917 int interval;
3918 interval = get_wait_interval(myrpt, type);
3919 if(debug)
3920 ast_log(LOG_NOTICE,"Delay interval = %d\n", interval);
3921 if(interval)
3922 ast_safe_sleep(chan,interval);
3923 if(debug)
3924 ast_log(LOG_NOTICE,"Delay complete\n");
3925 return;
3928 static int split_freq(char *mhz, char *decimals, char *freq);
3930 static void *rpt_tele_thread(void *this)
3932 DAHDI_CONFINFO ci; /* conference info */
3933 int res = 0,haslink,hastx,hasremote,imdone = 0, unkeys_queued, x;
3934 struct rpt_tele *mytele = (struct rpt_tele *)this;
3935 struct rpt_tele *tlist;
3936 struct rpt *myrpt;
3937 struct rpt_link *l,*l1,linkbase;
3938 struct ast_channel *mychannel;
3939 int id_malloc, vmajor, vminor, m;
3940 char *p,*ct,*ct_copy,*ident, *nodename,*cp;
3941 time_t t;
3942 #ifdef NEW_ASTERISK
3943 struct ast_tm localtm;
3944 #else
3945 struct tm localtm;
3946 #endif
3947 char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
3948 int i,ns,rbimode;
3949 char mhz[MAXREMSTR];
3950 char decimals[MAXREMSTR];
3951 char mystr[200];
3952 struct dahdi_params par;
3955 /* get a pointer to myrpt */
3956 myrpt = mytele->rpt;
3958 /* Snag copies of a few key myrpt variables */
3959 rpt_mutex_lock(&myrpt->lock);
3960 nodename = ast_strdup(myrpt->name);
3961 if(!nodename)
3963 fprintf(stderr,"rpt:Sorry unable strdup nodename\n");
3964 rpt_mutex_lock(&myrpt->lock);
3965 remque((struct qelem *)mytele);
3966 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
3967 rpt_mutex_unlock(&myrpt->lock);
3968 ast_free(mytele);
3969 pthread_exit(NULL);
3972 if (myrpt->p.ident){
3973 ident = ast_strdup(myrpt->p.ident);
3974 if(!ident)
3976 fprintf(stderr,"rpt:Sorry unable strdup ident\n");
3977 rpt_mutex_lock(&myrpt->lock);
3978 remque((struct qelem *)mytele);
3979 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",
3980 __LINE__, mytele->mode); /*@@@@@@@@@@@*/
3981 rpt_mutex_unlock(&myrpt->lock);
3982 ast_free(nodename);
3983 ast_free(mytele);
3984 pthread_exit(NULL);
3986 else{
3987 id_malloc = 1;
3990 else
3992 ident = "";
3993 id_malloc = 0;
3995 rpt_mutex_unlock(&myrpt->lock);
3999 /* allocate a pseudo-channel thru asterisk */
4000 mychannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
4001 if (!mychannel)
4003 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
4004 rpt_mutex_lock(&myrpt->lock);
4005 remque((struct qelem *)mytele);
4006 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
4007 rpt_mutex_unlock(&myrpt->lock);
4008 ast_free(nodename);
4009 if(id_malloc)
4010 ast_free(ident);
4011 ast_free(mytele);
4012 pthread_exit(NULL);
4014 #ifdef AST_CDR_FLAG_POST_DISABLED
4015 if (mychannel->cdr)
4016 ast_set_flag(mychannel->cdr,AST_CDR_FLAG_POST_DISABLED);
4017 #endif
4018 rpt_mutex_lock(&myrpt->lock);
4019 mytele->chan = mychannel;
4020 rpt_mutex_unlock(&myrpt->lock);
4022 while((mytele->mode != SETREMOTE) && (mytele->mode != UNKEY) &&
4023 (mytele->mode != LINKUNKEY))
4025 rpt_mutex_lock(&myrpt->lock);
4026 if (!myrpt->active_telem)
4028 myrpt->active_telem = mytele;
4029 rpt_mutex_unlock(&myrpt->lock);
4030 break;
4032 rpt_mutex_unlock(&myrpt->lock);
4033 usleep(100000);
4036 /* make a conference for the tx */
4037 ci.chan = 0;
4038 /* If the telemetry is only intended for a local audience, */
4039 /* only connect the ID audio to the local tx conference so */
4040 /* linked systems can't hear it */
4041 ci.confno = (((mytele->mode == ID) || (mytele->mode == IDTALKOVER) || (mytele->mode == UNKEY) ||
4042 (mytele->mode == TAILMSG) || (mytele->mode == LINKUNKEY) || (mytele->mode == TIMEOUT) ||
4043 (mytele->mode == PARROT) || (mytele->mode == STATS_TIME_LOCAL)) ?
4044 myrpt->txconf : myrpt->conf);
4045 ci.confmode = DAHDI_CONF_CONFANN;
4046 /* first put the channel on the conference in announce mode */
4047 if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
4049 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
4050 rpt_mutex_lock(&myrpt->lock);
4051 myrpt->active_telem = NULL;
4052 remque((struct qelem *)mytele);
4053 rpt_mutex_unlock(&myrpt->lock);
4054 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
4055 ast_free(nodename);
4056 if(id_malloc)
4057 ast_free(ident);
4058 ast_free(mytele);
4059 ast_hangup(mychannel);
4060 pthread_exit(NULL);
4062 ast_stopstream(mychannel);
4063 switch(mytele->mode)
4065 case ID:
4066 case ID1:
4067 /* wait a bit */
4068 wait_interval(myrpt, (mytele->mode == ID) ? DLY_ID : DLY_TELEM,mychannel);
4069 res = telem_any(myrpt,mychannel, ident);
4070 imdone=1;
4071 break;
4073 case TAILMSG:
4074 res = ast_streamfile(mychannel, myrpt->p.tailmessages[myrpt->tailmessagen], mychannel->language);
4075 break;
4077 case IDTALKOVER:
4078 p = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "idtalkover");
4079 if(p)
4080 res = telem_any(myrpt,mychannel, p);
4081 imdone=1;
4082 break;
4084 case PROC:
4085 /* wait a little bit longer */
4086 wait_interval(myrpt, DLY_TELEM, mychannel);
4087 res = telem_lookup(myrpt, mychannel, myrpt->name, "patchup");
4088 if(res < 0){ /* Then default message */
4089 res = ast_streamfile(mychannel, "rpt/callproceeding", mychannel->language);
4091 break;
4092 case TERM:
4093 /* wait a little bit longer */
4094 wait_interval(myrpt, DLY_CALLTERM, mychannel);
4095 res = telem_lookup(myrpt, mychannel, myrpt->name, "patchdown");
4096 if(res < 0){ /* Then default message */
4097 res = ast_streamfile(mychannel, "rpt/callterminated", mychannel->language);
4099 break;
4100 case COMPLETE:
4101 /* wait a little bit */
4102 wait_interval(myrpt, DLY_TELEM, mychannel);
4103 res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
4104 break;
4105 case MACRO_NOTFOUND:
4106 /* wait a little bit */
4107 wait_interval(myrpt, DLY_TELEM, mychannel);
4108 res = ast_streamfile(mychannel, "rpt/macro_notfound", mychannel->language);
4109 break;
4110 case MACRO_BUSY:
4111 /* wait a little bit */
4112 wait_interval(myrpt, DLY_TELEM, mychannel);
4113 res = ast_streamfile(mychannel, "rpt/macro_busy", mychannel->language);
4114 break;
4115 case UNKEY:
4116 if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
4117 imdone = 1;
4118 break;
4122 * Reset the Unkey to CT timer
4125 x = get_wait_interval(myrpt, DLY_UNKEY);
4126 rpt_mutex_lock(&myrpt->lock);
4127 myrpt->unkeytocttimer = x; /* Must be protected as it is changed below */
4128 rpt_mutex_unlock(&myrpt->lock);
4131 * If there's one already queued, don't do another
4134 tlist = myrpt->tele.next;
4135 unkeys_queued = 0;
4136 if (tlist != &myrpt->tele)
4138 rpt_mutex_lock(&myrpt->lock);
4139 while(tlist != &myrpt->tele){
4140 if (tlist->mode == UNKEY) unkeys_queued++;
4141 tlist = tlist->next;
4143 rpt_mutex_unlock(&myrpt->lock);
4145 if( unkeys_queued > 1){
4146 imdone = 1;
4147 break;
4150 /* Wait for the telemetry timer to expire */
4151 /* Periodically check the timer since it can be re-initialized above */
4152 while(myrpt->unkeytocttimer)
4154 int ctint;
4155 if(myrpt->unkeytocttimer > 100)
4156 ctint = 100;
4157 else
4158 ctint = myrpt->unkeytocttimer;
4159 ast_safe_sleep(mychannel, ctint);
4160 rpt_mutex_lock(&myrpt->lock);
4161 if(myrpt->unkeytocttimer < ctint)
4162 myrpt->unkeytocttimer = 0;
4163 else
4164 myrpt->unkeytocttimer -= ctint;
4165 rpt_mutex_unlock(&myrpt->lock);
4169 * Now, the carrier on the rptr rx should be gone.
4170 * If it re-appeared, then forget about sending the CT
4172 if(myrpt->keyed){
4173 imdone = 1;
4174 break;
4177 rpt_mutex_lock(&myrpt->lock); /* Update the kerchunk counters */
4178 myrpt->dailykerchunks++;
4179 myrpt->totalkerchunks++;
4180 rpt_mutex_unlock(&myrpt->lock);
4182 haslink = 0;
4183 hastx = 0;
4184 hasremote = 0;
4185 l = myrpt->links.next;
4186 if (l != &myrpt->links)
4188 rpt_mutex_lock(&myrpt->lock);
4189 while(l != &myrpt->links)
4191 if (l->name[0] == '0')
4193 l = l->next;
4194 continue;
4196 haslink = 1;
4197 if (l->mode) {
4198 hastx++;
4199 if (l->isremote) hasremote++;
4201 l = l->next;
4203 rpt_mutex_unlock(&myrpt->lock);
4205 if (haslink)
4208 res = telem_lookup(myrpt,mychannel, myrpt->name, (!hastx) ? "remotemon" : "remotetx");
4209 if(res)
4210 ast_log(LOG_WARNING, "telem_lookup:remotexx failed on %s\n", mychannel->name);
4213 /* if in remote cmd mode, indicate it */
4214 if (myrpt->cmdnode[0])
4216 ast_safe_sleep(mychannel,200);
4217 res = telem_lookup(myrpt,mychannel, myrpt->name, "cmdmode");
4218 if(res)
4219 ast_log(LOG_WARNING, "telem_lookup:cmdmode failed on %s\n", mychannel->name);
4220 ast_stopstream(mychannel);
4223 else if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "unlinkedct"))){ /* Unlinked Courtesy Tone */
4224 ct_copy = ast_strdup(ct);
4225 if(ct_copy)
4227 res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
4228 ast_free(ct_copy);
4230 else
4231 res = -1;
4232 if(res)
4233 ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);
4235 if (hasremote && (!myrpt->cmdnode[0]))
4237 /* set for all to hear */
4238 ci.chan = 0;
4239 ci.confno = myrpt->conf;
4240 ci.confmode = DAHDI_CONF_CONFANN;
4241 /* first put the channel on the conference in announce mode */
4242 if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
4244 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
4245 rpt_mutex_lock(&myrpt->lock);
4246 myrpt->active_telem = NULL;
4247 remque((struct qelem *)mytele);
4248 rpt_mutex_unlock(&myrpt->lock);
4249 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
4250 ast_free(nodename);
4251 if(id_malloc)
4252 ast_free(ident);
4253 ast_free(mytele);
4254 ast_hangup(mychannel);
4255 pthread_exit(NULL);
4257 if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "remotect"))){ /* Unlinked Courtesy Tone */
4258 ast_safe_sleep(mychannel,200);
4259 ct_copy = ast_strdup(ct);
4260 if(ct_copy)
4262 res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
4263 ast_free(ct_copy);
4265 else
4266 res = -1;
4268 if(res)
4269 ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);
4272 #if defined(_MDC_DECODE_H_) && defined(MDC_SAY_WHEN_DOING_CT)
4273 if (myrpt->lastunit)
4275 char mystr[10];
4277 ast_safe_sleep(mychannel,200);
4278 /* set for all to hear */
4279 ci.chan = 0;
4280 ci.confno = myrpt->txconf;
4281 ci.confmode = DAHDI_CONF_CONFANN;
4282 /* first put the channel on the conference in announce mode */
4283 if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
4285 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
4286 rpt_mutex_lock(&myrpt->lock);
4287 myrpt->active_telem = NULL;
4288 remque((struct qelem *)mytele);
4289 rpt_mutex_unlock(&myrpt->lock);
4290 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
4291 ast_free(nodename);
4292 if(id_malloc)
4293 ast_free(ident);
4294 ast_free(mytele);
4295 ast_hangup(mychannel);
4296 pthread_exit(NULL);
4298 sprintf(mystr,"%04x",myrpt->lastunit);
4299 myrpt->lastunit = 0;
4300 ast_say_character_str(mychannel,mystr,NULL,mychannel->language);
4301 break;
4303 #endif
4304 imdone = 1;
4305 break;
4306 case LINKUNKEY:
4307 if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
4308 imdone = 1;
4309 break;
4313 * Reset the Unkey to CT timer
4316 x = get_wait_interval(myrpt, DLY_LINKUNKEY);
4317 mytele->mylink.linkunkeytocttimer = x; /* Must be protected as it is changed below */
4320 * If there's one already queued, don't do another
4323 tlist = myrpt->tele.next;
4324 unkeys_queued = 0;
4325 if (tlist != &myrpt->tele)
4327 rpt_mutex_lock(&myrpt->lock);
4328 while(tlist != &myrpt->tele){
4329 if (tlist->mode == LINKUNKEY) unkeys_queued++;
4330 tlist = tlist->next;
4332 rpt_mutex_unlock(&myrpt->lock);
4334 if( unkeys_queued > 1){
4335 imdone = 1;
4336 break;
4339 /* Wait for the telemetry timer to expire */
4340 /* Periodically check the timer since it can be re-initialized above */
4341 while(mytele->mylink.linkunkeytocttimer)
4343 int ctint;
4344 if(mytele->mylink.linkunkeytocttimer > 100)
4345 ctint = 100;
4346 else
4347 ctint = mytele->mylink.linkunkeytocttimer;
4348 ast_safe_sleep(mychannel, ctint);
4349 rpt_mutex_lock(&myrpt->lock);
4350 if(mytele->mylink.linkunkeytocttimer < ctint)
4351 mytele->mylink.linkunkeytocttimer = 0;
4352 else
4353 mytele->mylink.linkunkeytocttimer -= ctint;
4354 rpt_mutex_unlock(&myrpt->lock);
4357 if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "linkunkeyct"))){ /* Unlinked Courtesy Tone */
4358 ct_copy = ast_strdup(ct);
4359 if(ct_copy){
4360 res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
4361 ast_free(ct_copy);
4363 else
4364 res = -1;
4365 if(res)
4366 ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);
4368 imdone = 1;
4369 break;
4370 case REMDISC:
4371 /* wait a little bit */
4372 wait_interval(myrpt, DLY_TELEM, mychannel);
4373 l = myrpt->links.next;
4374 haslink = 0;
4375 /* dont report if a link for this one still on system */
4376 if (l != &myrpt->links)
4378 rpt_mutex_lock(&myrpt->lock);
4379 while(l != &myrpt->links)
4381 if (l->name[0] == '0')
4383 l = l->next;
4384 continue;
4386 if (!strcmp(l->name,mytele->mylink.name))
4388 haslink = 1;
4389 break;
4391 l = l->next;
4393 rpt_mutex_unlock(&myrpt->lock);
4395 if (haslink)
4397 imdone = 1;
4398 break;
4400 res = saynode(myrpt,mychannel,mytele->mylink.name);
4401 if (!res)
4402 res = ast_streamfile(mychannel, ((mytele->mylink.hasconnected) ?
4403 "rpt/remote_disc" : "rpt/remote_busy"), mychannel->language);
4404 break;
4405 case REMALREADY:
4406 /* wait a little bit */
4407 wait_interval(myrpt, DLY_TELEM, mychannel);
4408 res = ast_streamfile(mychannel, "rpt/remote_already", mychannel->language);
4409 break;
4410 case REMNOTFOUND:
4411 /* wait a little bit */
4412 wait_interval(myrpt, DLY_TELEM, mychannel);
4413 res = ast_streamfile(mychannel, "rpt/remote_notfound", mychannel->language);
4414 break;
4415 case REMGO:
4416 /* wait a little bit */
4417 wait_interval(myrpt, DLY_TELEM, mychannel);
4418 res = ast_streamfile(mychannel, "rpt/remote_go", mychannel->language);
4419 break;
4420 case CONNECTED:
4421 /* wait a little bit */
4422 wait_interval(myrpt, DLY_TELEM, mychannel);
4423 res = saynode(myrpt,mychannel,mytele->mylink.name);
4424 if (!res)
4425 res = ast_streamfile(mychannel, "rpt/connected", mychannel->language);
4426 if (!res)
4427 res = ast_waitstream(mychannel, "");
4428 else
4429 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
4430 ast_stopstream(mychannel);
4431 res = ast_streamfile(mychannel, "digits/2", mychannel->language);
4432 if (!res)
4433 res = ast_waitstream(mychannel, "");
4434 else
4435 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
4436 ast_stopstream(mychannel);
4437 res = saynode(myrpt,mychannel,myrpt->name);
4438 imdone = 1;
4439 break;
4440 case CONNFAIL:
4441 res = saynode(myrpt,mychannel,mytele->mylink.name);
4442 if (!res)
4443 res = ast_streamfile(mychannel, "rpt/connection_failed", mychannel->language);
4444 break;
4445 case MEMNOTFOUND:
4446 /* wait a little bit */
4447 wait_interval(myrpt, DLY_TELEM, mychannel);
4448 res = ast_streamfile(mychannel, "rpt/memory_notfound", mychannel->language);
4449 break;
4450 case PLAYBACK:
4451 /* wait a little bit */
4452 wait_interval(myrpt, DLY_TELEM, mychannel);
4453 res = ast_streamfile(mychannel, mytele->param, mychannel->language);
4454 break;
4455 case TOPKEY:
4456 /* wait a little bit */
4457 wait_interval(myrpt, DLY_TELEM, mychannel);
4458 for(i = 0; i < TOPKEYN; i++)
4460 if (!myrpt->topkey[i].node[0]) continue;
4461 if ((!myrpt->topkeylong) && (myrpt->topkey[i].keyed)) continue;
4462 res = saynode(myrpt, mychannel, myrpt->topkey[i].node);
4463 if (!res) res = sayfile(mychannel,(myrpt->topkey[i].keyed) ?
4464 "rpt/keyedfor" : "rpt/unkeyedfor");
4465 if (!res) res = saynum(mychannel,
4466 myrpt->topkey[i].timesince);
4467 if (!res) res = sayfile(mychannel,"rpt/seconds");
4468 if (!myrpt->topkeylong) break;
4470 imdone = 1;
4471 break;
4472 case SETREMOTE:
4473 ast_mutex_lock(&myrpt->remlock);
4474 res = 0;
4475 if(!strcmp(myrpt->remoterig, remote_rig_ft897))
4477 res = set_ft897(myrpt);
4479 else if(!strcmp(myrpt->remoterig, remote_rig_tm271))
4481 res = set_tm271(myrpt);
4483 else if(!strcmp(myrpt->remoterig, remote_rig_ic706))
4485 res = set_ic706(myrpt);
4487 else if(!strcmp(myrpt->remoterig, remote_rig_rbi)||!strcmp(myrpt->remoterig, remote_rig_ppp16))
4489 if (ioperm(myrpt->p.iobase,1,1) == -1)
4491 rpt_mutex_unlock(&myrpt->lock);
4492 ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase);
4493 res = -1;
4495 else res = setrbi(myrpt);
4497 else if(!strcmp(myrpt->remoterig, remote_rig_kenwood))
4499 if (myrpt->iofd >= 0) setdtr(myrpt->iofd,1);
4500 res = setkenwood(myrpt);
4501 if (myrpt->iofd >= 0) setdtr(myrpt->iofd,0);
4502 if (ast_safe_sleep(mychannel,200) == -1)
4504 ast_mutex_unlock(&myrpt->remlock);
4505 res = -1;
4506 break;
4508 if (myrpt->iofd < 0)
4510 i = DAHDI_FLUSH_EVENT;
4511 if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_FLUSH,&i) == -1)
4513 ast_mutex_unlock(&myrpt->remlock);
4514 ast_log(LOG_ERROR,"Cant flush events");
4515 res = -1;
4516 break;
4518 if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_GET_PARAMS,&par) == -1)
4520 ast_mutex_unlock(&myrpt->remlock);
4521 ast_log(LOG_ERROR,"Cant get params");
4522 res = -1;
4523 break;
4525 myrpt->remoterx =
4526 (par.rxisoffhook || (myrpt->tele.next != &myrpt->tele));
4530 ast_mutex_unlock(&myrpt->remlock);
4531 if (!res)
4533 imdone = 1;
4534 break;
4536 /* fall thru to invalid freq */
4537 case INVFREQ:
4538 /* wait a little bit */
4539 wait_interval(myrpt, DLY_TELEM, mychannel);
4540 res = ast_streamfile(mychannel, "rpt/invalid-freq", mychannel->language);
4541 break;
4542 case REMMODE:
4543 cp = 0;
4544 wait_interval(myrpt, DLY_TELEM, mychannel);
4545 switch(myrpt->remmode)
4547 case REM_MODE_FM:
4548 saycharstr(mychannel,"FM");
4549 break;
4550 case REM_MODE_USB:
4551 saycharstr(mychannel,"USB");
4552 break;
4553 case REM_MODE_LSB:
4554 saycharstr(mychannel,"LSB");
4555 break;
4556 case REM_MODE_AM:
4557 saycharstr(mychannel,"AM");
4558 break;
4560 wait_interval(myrpt, DLY_COMP, mychannel);
4561 if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
4562 break;
4563 case LOGINREQ:
4564 wait_interval(myrpt, DLY_TELEM, mychannel);
4565 sayfile(mychannel,"rpt/login");
4566 saycharstr(mychannel,myrpt->name);
4567 break;
4568 case REMLOGIN:
4569 wait_interval(myrpt, DLY_TELEM, mychannel);
4570 saycharstr(mychannel,myrpt->loginuser);
4571 saynode(myrpt,mychannel,myrpt->name);
4572 wait_interval(myrpt, DLY_COMP, mychannel);
4573 if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
4574 break;
4575 case REMXXX:
4576 wait_interval(myrpt, DLY_TELEM, mychannel);
4577 res = 0;
4578 switch(mytele->submode)
4580 case 100: /* RX PL Off */
4581 sayfile(mychannel, "rpt/rxpl");
4582 sayfile(mychannel, "rpt/off");
4583 break;
4584 case 101: /* RX PL On */
4585 sayfile(mychannel, "rpt/rxpl");
4586 sayfile(mychannel, "rpt/on");
4587 break;
4588 case 102: /* TX PL Off */
4589 sayfile(mychannel, "rpt/txpl");
4590 sayfile(mychannel, "rpt/off");
4591 break;
4592 case 103: /* TX PL On */
4593 sayfile(mychannel, "rpt/txpl");
4594 sayfile(mychannel, "rpt/on");
4595 break;
4596 case 104: /* Low Power */
4597 sayfile(mychannel, "rpt/lopwr");
4598 break;
4599 case 105: /* Medium Power */
4600 sayfile(mychannel, "rpt/medpwr");
4601 break;
4602 case 106: /* Hi Power */
4603 sayfile(mychannel, "rpt/hipwr");
4604 break;
4605 case 113: /* Scan down slow */
4606 sayfile(mychannel,"rpt/down");
4607 sayfile(mychannel, "rpt/slow");
4608 break;
4609 case 114: /* Scan down quick */
4610 sayfile(mychannel,"rpt/down");
4611 sayfile(mychannel, "rpt/quick");
4612 break;
4613 case 115: /* Scan down fast */
4614 sayfile(mychannel,"rpt/down");
4615 sayfile(mychannel, "rpt/fast");
4616 break;
4617 case 116: /* Scan up slow */
4618 sayfile(mychannel,"rpt/up");
4619 sayfile(mychannel, "rpt/slow");
4620 break;
4621 case 117: /* Scan up quick */
4622 sayfile(mychannel,"rpt/up");
4623 sayfile(mychannel, "rpt/quick");
4624 break;
4625 case 118: /* Scan up fast */
4626 sayfile(mychannel,"rpt/up");
4627 sayfile(mychannel, "rpt/fast");
4628 break;
4629 default:
4630 res = -1;
4632 wait_interval(myrpt, DLY_COMP, mychannel);
4633 if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
4634 break;
4635 case SCAN:
4636 ast_mutex_lock(&myrpt->remlock);
4637 if (myrpt->hfscanstop)
4639 myrpt->hfscanstatus = 0;
4640 myrpt->hfscanmode = 0;
4641 myrpt->hfscanstop = 0;
4642 mytele->mode = SCANSTAT;
4643 ast_mutex_unlock(&myrpt->remlock);
4644 if (ast_safe_sleep(mychannel,1000) == -1) break;
4645 sayfile(mychannel, "rpt/stop");
4646 imdone = 1;
4647 break;
4649 if (myrpt->hfscanstatus > -2) service_scan(myrpt);
4650 i = myrpt->hfscanstatus;
4651 myrpt->hfscanstatus = 0;
4652 if (i) mytele->mode = SCANSTAT;
4653 ast_mutex_unlock(&myrpt->remlock);
4654 if (i < 0) sayfile(mychannel, "rpt/stop");
4655 else if (i > 0) saynum(mychannel,i);
4656 imdone = 1;
4657 break;
4658 case TUNE:
4659 ast_mutex_lock(&myrpt->remlock);
4660 if (!strcmp(myrpt->remoterig,remote_rig_ic706))
4662 set_mode_ic706(myrpt, REM_MODE_AM);
4663 if(play_tone(mychannel, 800, 6000, 8192) == -1) break;
4664 ast_safe_sleep(mychannel,500);
4665 set_mode_ic706(myrpt, myrpt->remmode);
4666 myrpt->tunerequest = 0;
4667 ast_mutex_unlock(&myrpt->remlock);
4668 imdone = 1;
4669 break;
4671 set_mode_ft897(myrpt, REM_MODE_AM);
4672 simple_command_ft897(myrpt, 8);
4673 if(play_tone(mychannel, 800, 6000, 8192) == -1) break;
4674 simple_command_ft897(myrpt, 0x88);
4675 ast_safe_sleep(mychannel,500);
4676 set_mode_ft897(myrpt, myrpt->remmode);
4677 myrpt->tunerequest = 0;
4678 ast_mutex_unlock(&myrpt->remlock);
4679 imdone = 1;
4680 break;
4681 case REMSHORTSTATUS:
4682 case REMLONGSTATUS:
4683 wait_interval(myrpt, DLY_TELEM, mychannel);
4684 res = saynode(myrpt,mychannel,myrpt->name);
4685 if(!res)
4686 res = sayfile(mychannel,"rpt/frequency");
4687 if(!res)
4688 res = split_freq(mhz, decimals, myrpt->freq);
4689 if (!multimode_capable(myrpt)) decimals[3] = 0;
4690 if(!res){
4691 m = atoi(mhz);
4692 if(m < 100)
4693 res = saynum(mychannel, m);
4694 else
4695 res = saycharstr(mychannel, mhz);
4697 if(!res)
4698 res = sayfile(mychannel, "letters/dot");
4699 if(!res)
4700 res = saycharstr(mychannel, decimals);
4702 if(res) break;
4703 if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */
4704 switch(myrpt->offset){
4706 case REM_MINUS:
4707 res = sayfile(mychannel,"rpt/minus");
4708 break;
4710 case REM_SIMPLEX:
4711 res = sayfile(mychannel,"rpt/simplex");
4712 break;
4714 case REM_PLUS:
4715 res = sayfile(mychannel,"rpt/plus");
4716 break;
4718 default:
4719 break;
4722 else{ /* Must be USB, LSB, or AM */
4723 switch(myrpt->remmode){
4725 case REM_MODE_USB:
4726 res = saycharstr(mychannel, "USB");
4727 break;
4729 case REM_MODE_LSB:
4730 res = saycharstr(mychannel, "LSB");
4731 break;
4733 case REM_MODE_AM:
4734 res = saycharstr(mychannel, "AM");
4735 break;
4738 default:
4739 break;
4743 if (res == -1) break;
4745 if(mytele->mode == REMSHORTSTATUS){ /* Short status? */
4746 wait_interval(myrpt, DLY_COMP, mychannel);
4747 if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
4748 break;
4751 if (strcmp(myrpt->remoterig,remote_rig_ic706))
4753 switch(myrpt->powerlevel){
4755 case REM_LOWPWR:
4756 res = sayfile(mychannel,"rpt/lopwr") ;
4757 break;
4758 case REM_MEDPWR:
4759 res = sayfile(mychannel,"rpt/medpwr");
4760 break;
4761 case REM_HIPWR:
4762 res = sayfile(mychannel,"rpt/hipwr");
4763 break;
4767 rbimode = ((!strncmp(myrpt->remoterig,remote_rig_rbi,3))
4768 || (!strncmp(myrpt->remoterig,remote_rig_ic706,3)));
4769 if (res || (sayfile(mychannel,"rpt/rxpl") == -1)) break;
4770 if (rbimode && (sayfile(mychannel,"rpt/txpl") == -1)) break;
4771 if ((sayfile(mychannel,"rpt/frequency") == -1) ||
4772 (saycharstr(mychannel,myrpt->rxpl) == -1)) break;
4773 if ((!rbimode) && ((sayfile(mychannel,"rpt/txpl") == -1) ||
4774 (sayfile(mychannel,"rpt/frequency") == -1) ||
4775 (saycharstr(mychannel,myrpt->txpl) == -1))) break;
4776 if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */
4777 if ((sayfile(mychannel,"rpt/rxpl") == -1) ||
4778 (sayfile(mychannel,((myrpt->rxplon) ? "rpt/on" : "rpt/off")) == -1) ||
4779 (sayfile(mychannel,"rpt/txpl") == -1) ||
4780 (sayfile(mychannel,((myrpt->txplon) ? "rpt/on" : "rpt/off")) == -1))
4782 break;
4785 wait_interval(myrpt, DLY_COMP, mychannel);
4786 if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
4787 break;
4788 case STATUS:
4789 /* wait a little bit */
4790 wait_interval(myrpt, DLY_TELEM, mychannel);
4791 hastx = 0;
4792 linkbase.next = &linkbase;
4793 linkbase.prev = &linkbase;
4794 rpt_mutex_lock(&myrpt->lock);
4795 /* make our own list of links */
4796 l = myrpt->links.next;
4797 while(l != &myrpt->links)
4799 if (l->name[0] == '0')
4801 l = l->next;
4802 continue;
4804 l1 = ast_malloc(sizeof(struct rpt_link));
4805 if (!l1)
4807 ast_log(LOG_WARNING, "Cannot alloc memory on %s\n", mychannel->name);
4808 remque((struct qelem *)mytele);
4809 myrpt->active_telem = NULL;
4810 rpt_mutex_unlock(&myrpt->lock);
4811 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
4812 ast_free(nodename);
4813 if(id_malloc)
4814 ast_free(ident);
4815 ast_free(mytele);
4816 ast_hangup(mychannel);
4817 pthread_exit(NULL);
4819 memcpy(l1,l,sizeof(struct rpt_link));
4820 l1->next = l1->prev = NULL;
4821 insque((struct qelem *)l1,(struct qelem *)linkbase.next);
4822 l = l->next;
4824 rpt_mutex_unlock(&myrpt->lock);
4825 res = saynode(myrpt,mychannel,myrpt->name);
4826 if (myrpt->callmode)
4828 hastx = 1;
4829 res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
4830 if (!res)
4831 res = ast_waitstream(mychannel, "");
4832 else
4833 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
4834 ast_stopstream(mychannel);
4836 l = linkbase.next;
4837 while(l != &linkbase)
4839 char *s;
4841 hastx = 1;
4842 res = saynode(myrpt,mychannel,l->name);
4843 s = "rpt/tranceive";
4844 if (!l->mode) s = "rpt/monitor";
4845 if (!l->thisconnected) s = "rpt/connecting";
4846 res = ast_streamfile(mychannel, s, mychannel->language);
4847 if (!res)
4848 res = ast_waitstream(mychannel, "");
4849 else
4850 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
4851 ast_stopstream(mychannel);
4852 l = l->next;
4854 if (!hastx)
4856 res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
4857 if (!res)
4858 res = ast_waitstream(mychannel, "");
4859 else
4860 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
4861 ast_stopstream(mychannel);
4863 /* destroy our local link queue */
4864 l = linkbase.next;
4865 while(l != &linkbase)
4867 l1 = l;
4868 l = l->next;
4869 remque((struct qelem *)l1);
4870 ast_free(l1);
4872 imdone = 1;
4873 break;
4874 case FULLSTATUS:
4875 rpt_mutex_lock(&myrpt->lock);
4876 /* get all the nodes */
4877 __mklinklist(myrpt,NULL,lbuf);
4878 rpt_mutex_unlock(&myrpt->lock);
4879 /* parse em */
4880 ns = finddelim(lbuf,strs,MAXLINKLIST);
4881 /* sort em */
4882 if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar);
4883 /* wait a little bit */
4884 wait_interval(myrpt, DLY_TELEM, mychannel);
4885 hastx = 0;
4886 res = saynode(myrpt,mychannel,myrpt->name);
4887 if (myrpt->callmode)
4889 hastx = 1;
4890 res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
4891 if (!res)
4892 res = ast_waitstream(mychannel, "");
4893 else
4894 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
4895 ast_stopstream(mychannel);
4897 /* go thru all the nodes in list */
4898 for(i = 0; i < ns; i++)
4900 char *s,mode = 'T';
4902 /* if a mode spec at first, handle it */
4903 if ((*strs[i] < '0') || (*strs[i] > '9'))
4905 mode = *strs[i];
4906 strs[i]++;
4909 hastx = 1;
4910 res = saynode(myrpt,mychannel,strs[i]);
4911 s = "rpt/tranceive";
4912 if (mode == 'R') s = "rpt/monitor";
4913 if (mode == 'C') s = "rpt/connecting";
4914 res = ast_streamfile(mychannel, s, mychannel->language);
4915 if (!res)
4916 res = ast_waitstream(mychannel, "");
4917 else
4918 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
4919 ast_stopstream(mychannel);
4921 if (!hastx)
4923 res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
4924 if (!res)
4925 res = ast_waitstream(mychannel, "");
4926 else
4927 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
4928 ast_stopstream(mychannel);
4930 imdone = 1;
4931 break;
4933 case LASTNODEKEY: /* Identify last node which keyed us up */
4934 rpt_mutex_lock(&myrpt->lock);
4935 if(myrpt->lastnodewhichkeyedusup){
4936 p = ast_strdup(myrpt->lastnodewhichkeyedusup); /* Make a local copy of the node name */
4937 if(!p){
4938 ast_log(LOG_WARNING, "ast_strdup failed in telemetery LASTNODEKEY");
4939 imdone = 1;
4940 break;
4943 else
4944 p = NULL;
4945 rpt_mutex_unlock(&myrpt->lock);
4946 if(!p){
4947 imdone = 1; /* no node previously keyed us up, or the node which did has been disconnected */
4948 break;
4950 wait_interval(myrpt, DLY_TELEM, mychannel);
4951 res = saynode(myrpt,mychannel,p);
4952 ast_free(p);
4953 imdone = 1;
4954 break;
4956 case UNAUTHTX: /* Say unauthorized transmit frequency */
4957 wait_interval(myrpt, DLY_TELEM, mychannel);
4958 res = ast_streamfile(mychannel, "rpt/unauthtx", mychannel->language);
4959 if (!res)
4960 res = ast_waitstream(mychannel, "");
4961 else
4962 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
4963 ast_stopstream(mychannel);
4964 imdone = 1;
4965 break;
4967 case PARROT: /* Repeat stuff */
4969 sprintf(mystr,PARROTFILE,myrpt->name,mytele->parrot);
4970 if (ast_fileexists(mystr,NULL,mychannel->language) <= 0)
4972 imdone = 1;
4973 myrpt->parrotstate = 0;
4974 break;
4976 wait_interval(myrpt, DLY_PARROT, mychannel);
4977 sprintf(mystr,PARROTFILE,myrpt->name,mytele->parrot);
4978 res = ast_streamfile(mychannel, mystr, mychannel->language);
4979 if (!res)
4980 res = ast_waitstream(mychannel, "");
4981 else
4982 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
4983 ast_stopstream(mychannel);
4984 sprintf(mystr,PARROTFILE,myrpt->name,mytele->parrot);
4985 strcat(mystr,".wav");
4986 unlink(mystr);
4987 imdone = 1;
4988 myrpt->parrotstate = 0;
4989 break;
4991 case TIMEOUT:
4992 res = saynode(myrpt,mychannel,myrpt->name);
4993 if (!res)
4994 res = ast_streamfile(mychannel, "rpt/timeout", mychannel->language);
4995 break;
4997 case TIMEOUT_WARNING:
4998 time(&t);
4999 res = saynode(myrpt,mychannel,myrpt->name);
5000 if (!res)
5001 res = ast_streamfile(mychannel, "rpt/timeout-warning", mychannel->language);
5002 if (!res)
5003 res = ast_waitstream(mychannel, "");
5004 else
5005 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
5006 ast_stopstream(mychannel);
5007 if(!res) /* Say number of seconds */
5008 ast_say_number(mychannel, myrpt->p.remotetimeout -
5009 (t - myrpt->last_activity_time),
5010 "", mychannel->language, (char *) NULL);
5011 if (!res)
5012 res = ast_waitstream(mychannel, "");
5013 ast_stopstream(mychannel);
5014 res = ast_streamfile(mychannel, "queue-seconds", mychannel->language);
5015 break;
5017 case ACT_TIMEOUT_WARNING:
5018 time(&t);
5019 res = saynode(myrpt,mychannel,myrpt->name);
5020 if (!res)
5021 res = ast_streamfile(mychannel, "rpt/act-timeout-warning", mychannel->language);
5022 if (!res)
5023 res = ast_waitstream(mychannel, "");
5024 else
5025 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
5026 ast_stopstream(mychannel);
5027 if(!res) /* Say number of seconds */
5028 ast_say_number(mychannel, myrpt->p.remoteinacttimeout -
5029 (t - myrpt->last_activity_time),
5030 "", mychannel->language, (char *) NULL);
5031 if (!res)
5032 res = ast_waitstream(mychannel, "");
5033 ast_stopstream(mychannel);
5034 res = ast_streamfile(mychannel, "queue-seconds", mychannel->language);
5035 break;
5037 case STATS_TIME:
5038 case STATS_TIME_LOCAL:
5039 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
5040 t = time(NULL);
5041 rpt_localtime(&t, &localtm);
5042 /* Say the phase of the day is before the time */
5043 if((localtm.tm_hour >= 0) && (localtm.tm_hour < 12))
5044 p = "rpt/goodmorning";
5045 else if((localtm.tm_hour >= 12) && (localtm.tm_hour < 18))
5046 p = "rpt/goodafternoon";
5047 else
5048 p = "rpt/goodevening";
5049 if (sayfile(mychannel,p) == -1)
5051 imdone = 1;
5052 break;
5054 /* Say the time is ... */
5055 if (sayfile(mychannel,"rpt/thetimeis") == -1)
5057 imdone = 1;
5058 break;
5060 /* Say the time */
5061 res = ast_say_time(mychannel, t, "", mychannel->language);
5062 if (!res)
5063 res = ast_waitstream(mychannel, "");
5064 ast_stopstream(mychannel);
5065 imdone = 1;
5066 break;
5067 case STATS_VERSION:
5068 p = strstr(tdesc, "version");
5069 if(!p)
5070 break;
5071 if(sscanf(p, "version %d.%d", &vmajor, &vminor) != 2)
5072 break;
5073 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
5074 /* Say "version" */
5075 if (sayfile(mychannel,"rpt/version") == -1)
5077 imdone = 1;
5078 break;
5080 if(!res) /* Say "X" */
5081 ast_say_number(mychannel, vmajor, "", mychannel->language, (char *) NULL);
5082 if (!res)
5083 res = ast_waitstream(mychannel, "");
5084 ast_stopstream(mychannel);
5085 if (saycharstr(mychannel,".") == -1)
5087 imdone = 1;
5088 break;
5090 if(!res) /* Say "Y" */
5091 ast_say_number(mychannel, vminor, "", mychannel->language, (char *) NULL);
5092 if (!res){
5093 res = ast_waitstream(mychannel, "");
5094 ast_stopstream(mychannel);
5096 else
5097 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
5098 imdone = 1;
5099 break;
5100 case ARB_ALPHA:
5101 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
5102 if(mytele->param)
5103 saycharstr(mychannel, mytele->param);
5104 imdone = 1;
5105 break;
5106 case REV_PATCH:
5107 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
5108 if(mytele->param) {
5110 /* Parts of this section taken from app_parkandannounce */
5111 char *tpl_working, *tpl_current;
5112 char *tmp[100], *myparm;
5113 int looptemp=0,i=0, dres = 0;
5116 tpl_working = ast_strdup(mytele->param);
5117 myparm = strsep(&tpl_working,",");
5118 tpl_current=strsep(&tpl_working, ":");
5120 while(tpl_current && looptemp < sizeof(tmp)) {
5121 tmp[looptemp]=tpl_current;
5122 looptemp++;
5123 tpl_current=strsep(&tpl_working,":");
5126 for(i=0; i<looptemp; i++) {
5127 if(!strcmp(tmp[i], "PARKED")) {
5128 ast_say_digits(mychannel, atoi(myparm), "", mychannel->language);
5129 } else if(!strcmp(tmp[i], "NODE")) {
5130 ast_say_digits(mychannel, atoi(myrpt->name), "", mychannel->language);
5131 } else {
5132 dres = ast_streamfile(mychannel, tmp[i], mychannel->language);
5133 if(!dres) {
5134 dres = ast_waitstream(mychannel, "");
5135 } else {
5136 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[i], mychannel->name);
5137 dres = 0;
5141 ast_free(tpl_working);
5143 imdone = 1;
5144 break;
5145 case TEST_TONE:
5146 imdone = 1;
5147 if (myrpt->stopgen) break;
5148 myrpt->stopgen = -1;
5149 if ((res = ast_tonepair_start(mychannel, 1004.0, 0, 99999999, 7200.0)))
5151 myrpt->stopgen = 0;
5152 break;
5154 while(mychannel->generatordata && (myrpt->stopgen <= 0)) {
5155 if (ast_safe_sleep(mychannel,1)) break;
5156 imdone = 1;
5158 myrpt->stopgen = 0;
5159 break;
5160 default:
5161 break;
5163 if (!imdone)
5165 if (!res)
5166 res = ast_waitstream(mychannel, "");
5167 else {
5168 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
5169 res = 0;
5172 ast_stopstream(mychannel);
5173 rpt_mutex_lock(&myrpt->lock);
5174 if (mytele->mode == TAILMSG)
5176 if (!res)
5178 myrpt->tailmessagen++;
5179 if(myrpt->tailmessagen >= myrpt->p.tailmessagemax) myrpt->tailmessagen = 0;
5181 else
5183 myrpt->tmsgtimer = myrpt->p.tailsquashedtime;
5186 remque((struct qelem *)mytele);
5187 myrpt->active_telem = NULL;
5188 rpt_mutex_unlock(&myrpt->lock);
5189 ast_free(nodename);
5190 if(id_malloc)
5191 ast_free(ident);
5192 ast_free(mytele);
5193 ast_hangup(mychannel);
5194 #ifdef APP_RPT_LOCK_DEBUG
5196 struct lockthread *t;
5198 sleep(5);
5199 ast_mutex_lock(&locklock);
5200 t = get_lockthread(pthread_self());
5201 if (t) memset(t,0,sizeof(struct lockthread));
5202 ast_mutex_unlock(&locklock);
5204 #endif
5205 pthread_exit(NULL);
5208 static void rpt_telemetry(struct rpt *myrpt,int mode, void *data)
5210 struct rpt_tele *tele;
5211 struct rpt_link *mylink = NULL;
5212 int res;
5213 pthread_attr_t attr;
5214 char *v1, *v2;
5216 if(debug > 6)
5217 ast_log(LOG_NOTICE,"mode=%i data=%s\n",mode, (char *)data);
5219 switch(mode)
5221 case UNKEY:
5222 /* if any of the following are defined, go ahead and do it,
5223 otherwise, dont bother */
5224 v1 = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name,
5225 "unlinkedct");
5226 v2 = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name,
5227 "remotect");
5228 if (telem_lookup(myrpt,NULL, myrpt->name, "remotemon") &&
5229 telem_lookup(myrpt,NULL, myrpt->name, "remotetx") &&
5230 telem_lookup(myrpt,NULL, myrpt->name, "cmdmode") &&
5231 (!(v1 && telem_lookup(myrpt,NULL, myrpt->name, v1))) &&
5232 (!(v2 && telem_lookup(myrpt,NULL, myrpt->name, v2)))) return;
5233 break;
5234 case LINKUNKEY:
5235 if (!ast_variable_retrieve(myrpt->cfg, myrpt->name, "linkunkeyct"))
5236 return;
5237 break;
5238 default:
5239 break;
5241 tele = ast_malloc(sizeof(struct rpt_tele));
5242 if (!tele)
5244 ast_log(LOG_WARNING, "Unable to allocate memory\n");
5245 pthread_exit(NULL);
5246 return;
5248 /* zero it out */
5249 memset((char *)tele,0,sizeof(struct rpt_tele));
5250 tele->rpt = myrpt;
5251 tele->mode = mode;
5252 if (mode == PARROT) tele->parrot = (unsigned int) data;
5253 else mylink = (struct rpt_link *) data;
5254 rpt_mutex_lock(&myrpt->lock);
5255 if((mode == CONNFAIL) || (mode == REMDISC) || (mode == CONNECTED) ||
5256 (mode == LINKUNKEY)){
5257 memset(&tele->mylink,0,sizeof(struct rpt_link));
5258 if (mylink){
5259 memcpy(&tele->mylink,mylink,sizeof(struct rpt_link));
5262 else if ((mode == ARB_ALPHA) || (mode == REV_PATCH) || (mode == PLAYBACK)) {
5263 strncpy(tele->param, (char *) data, TELEPARAMSIZE - 1);
5264 tele->param[TELEPARAMSIZE - 1] = 0;
5266 if (mode == REMXXX) tele->submode = (int) data;
5267 insque((struct qelem *)tele, (struct qelem *)myrpt->tele.next);
5268 rpt_mutex_unlock(&myrpt->lock);
5269 pthread_attr_init(&attr);
5270 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
5271 res = ast_pthread_create(&tele->threadid,&attr,rpt_tele_thread,(void *) tele);
5272 if(res < 0){
5273 rpt_mutex_lock(&myrpt->lock);
5274 remque((struct qlem *) tele); /* We don't like stuck transmitters, remove it from the queue */
5275 rpt_mutex_unlock(&myrpt->lock);
5276 ast_log(LOG_WARNING, "Could not create telemetry thread: %s",strerror(res));
5278 return;
5281 static void *rpt_call(void *this)
5283 DAHDI_CONFINFO ci; /* conference info */
5284 struct rpt *myrpt = (struct rpt *)this;
5285 int res;
5286 int stopped,congstarted,dialtimer,lastcidx,aborted;
5287 struct ast_channel *mychannel,*genchannel;
5289 myrpt->mydtmf = 0;
5290 /* allocate a pseudo-channel thru asterisk */
5291 mychannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
5292 if (!mychannel)
5294 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
5295 pthread_exit(NULL);
5297 #ifdef AST_CDR_FLAG_POST_DISABLED
5298 if (mychannel->cdr)
5299 ast_set_flag(mychannel->cdr,AST_CDR_FLAG_POST_DISABLED);
5300 #endif
5301 ci.chan = 0;
5302 ci.confno = myrpt->conf; /* use the pseudo conference */
5303 #if 0
5304 ci.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER
5305 | DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER;
5306 #endif
5307 ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
5308 /* first put the channel on the conference */
5309 if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
5311 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
5312 ast_hangup(mychannel);
5313 myrpt->callmode = 0;
5314 pthread_exit(NULL);
5316 /* allocate a pseudo-channel thru asterisk */
5317 genchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
5318 if (!genchannel)
5320 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
5321 ast_hangup(mychannel);
5322 pthread_exit(NULL);
5324 #ifdef AST_CDR_FLAG_POST_DISABLED
5325 if (genchannel->cdr)
5326 ast_set_flag(genchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
5327 #endif
5328 ci.chan = 0;
5329 ci.confno = myrpt->conf;
5330 ci.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER
5331 | DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER;
5332 /* first put the channel on the conference */
5333 if (ioctl(genchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
5335 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
5336 ast_hangup(mychannel);
5337 ast_hangup(genchannel);
5338 myrpt->callmode = 0;
5339 pthread_exit(NULL);
5341 if (myrpt->p.tonezone && (tone_zone_set_zone(mychannel->fds[0],myrpt->p.tonezone) == -1))
5343 ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
5344 ast_hangup(mychannel);
5345 ast_hangup(genchannel);
5346 myrpt->callmode = 0;
5347 pthread_exit(NULL);
5349 if (myrpt->p.tonezone && (tone_zone_set_zone(genchannel->fds[0],myrpt->p.tonezone) == -1))
5351 ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
5352 ast_hangup(mychannel);
5353 ast_hangup(genchannel);
5354 myrpt->callmode = 0;
5355 pthread_exit(NULL);
5357 /* start dialtone if patchquiet is 0. Special patch modes don't send dial tone */
5358 if ((!myrpt->patchquiet) && (tone_zone_play_tone(genchannel->fds[0],DAHDI_TONE_DIALTONE) < 0))
5360 ast_log(LOG_WARNING, "Cannot start dialtone\n");
5361 ast_hangup(mychannel);
5362 ast_hangup(genchannel);
5363 myrpt->callmode = 0;
5364 pthread_exit(NULL);
5366 stopped = 0;
5367 congstarted = 0;
5368 dialtimer = 0;
5369 lastcidx = 0;
5370 myrpt->calldigittimer = 0;
5371 aborted = 0;
5373 while ((myrpt->callmode == 1) || (myrpt->callmode == 4))
5375 if((myrpt->patchdialtime)&&(myrpt->callmode == 1)&&(myrpt->cidx != lastcidx)){
5376 dialtimer = 0;
5377 lastcidx = myrpt->cidx;
5380 if((myrpt->patchdialtime)&&(dialtimer >= myrpt->patchdialtime)){
5381 if(debug)
5382 ast_log(LOG_NOTICE, "dialtimer %i > patchdialtime %i\n", dialtimer,myrpt->patchdialtime);
5383 rpt_mutex_lock(&myrpt->lock);
5384 aborted = 1;
5385 myrpt->callmode = 0;
5386 rpt_mutex_unlock(&myrpt->lock);
5387 break;
5390 if ((!myrpt->patchquiet) && (!stopped) && (myrpt->callmode == 1) && (myrpt->cidx > 0))
5392 stopped = 1;
5393 /* stop dial tone */
5394 tone_zone_play_tone(genchannel->fds[0],-1);
5396 if (myrpt->callmode == 1)
5398 if(myrpt->calldigittimer > PATCH_DIALPLAN_TIMEOUT)
5400 myrpt->callmode = 2;
5401 break;
5403 /* bump timer if active */
5404 if (myrpt->calldigittimer)
5405 myrpt->calldigittimer += MSWAIT;
5407 if (myrpt->callmode == 4)
5409 if(!congstarted){
5410 congstarted = 1;
5411 /* start congestion tone */
5412 tone_zone_play_tone(genchannel->fds[0],DAHDI_TONE_CONGESTION);
5415 res = ast_safe_sleep(mychannel, MSWAIT);
5416 if (res < 0)
5418 if(debug)
5419 ast_log(LOG_NOTICE, "ast_safe_sleep=%i\n", res);
5420 ast_hangup(mychannel);
5421 ast_hangup(genchannel);
5422 rpt_mutex_lock(&myrpt->lock);
5423 myrpt->callmode = 0;
5424 rpt_mutex_unlock(&myrpt->lock);
5425 pthread_exit(NULL);
5427 dialtimer += MSWAIT;
5429 /* stop any tone generation */
5430 tone_zone_play_tone(genchannel->fds[0],-1);
5431 /* end if done */
5432 if (!myrpt->callmode)
5434 if(debug)
5435 ast_log(LOG_NOTICE, "callmode==0\n");
5436 ast_hangup(mychannel);
5437 ast_hangup(genchannel);
5438 rpt_mutex_lock(&myrpt->lock);
5439 myrpt->callmode = 0;
5440 myrpt->macropatch=0;
5441 channel_revert(myrpt);
5442 rpt_mutex_unlock(&myrpt->lock);
5443 if((!myrpt->patchquiet) && aborted)
5444 rpt_telemetry(myrpt, TERM, NULL);
5445 pthread_exit(NULL);
5448 if (myrpt->p.ourcallerid && *myrpt->p.ourcallerid){
5449 char *name, *loc, *instr;
5450 instr = ast_strdup(myrpt->p.ourcallerid);
5451 if(instr){
5452 ast_callerid_parse(instr, &name, &loc);
5453 if(loc){
5454 if(mychannel->cid.cid_num)
5455 ast_free(mychannel->cid.cid_num);
5456 mychannel->cid.cid_num = ast_strdup(loc);
5458 if(name){
5459 if(mychannel->cid.cid_name)
5460 ast_free(mychannel->cid.cid_name);
5461 mychannel->cid.cid_name = ast_strdup(name);
5463 ast_free(instr);
5467 ast_copy_string(mychannel->exten, myrpt->exten, sizeof(mychannel->exten) - 1);
5468 ast_copy_string(mychannel->context, myrpt->patchcontext, sizeof(mychannel->context) - 1);
5470 if (myrpt->p.acctcode)
5471 ast_cdr_setaccount(mychannel,myrpt->p.acctcode);
5472 mychannel->priority = 1;
5473 ast_channel_undefer_dtmf(mychannel);
5474 if (ast_pbx_start(mychannel) < 0)
5476 ast_log(LOG_WARNING, "Unable to start PBX!!\n");
5477 ast_hangup(mychannel);
5478 ast_hangup(genchannel);
5479 rpt_mutex_lock(&myrpt->lock);
5480 myrpt->callmode = 0;
5481 rpt_mutex_unlock(&myrpt->lock);
5482 pthread_exit(NULL);
5484 usleep(10000);
5485 rpt_mutex_lock(&myrpt->lock);
5486 myrpt->callmode = 3;
5487 /* set appropriate conference for the pseudo */
5488 ci.chan = 0;
5489 ci.confno = myrpt->conf;
5490 ci.confmode = (myrpt->p.duplex == 2) ? DAHDI_CONF_CONFANNMON :
5491 (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
5492 /* first put the channel on the conference in announce mode */
5493 if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
5495 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
5496 ast_hangup(mychannel);
5497 ast_hangup(genchannel);
5498 myrpt->callmode = 0;
5499 pthread_exit(NULL);
5501 /* get its channel number */
5502 if (ioctl(mychannel->fds[0],DAHDI_CHANNO,&res) == -1)
5504 ast_log(LOG_WARNING, "Unable to get autopatch channel number\n");
5505 ast_hangup(mychannel);
5506 myrpt->callmode = 0;
5507 pthread_exit(NULL);
5509 ci.chan = 0;
5510 ci.confno = res;
5511 ci.confmode = DAHDI_CONF_MONITOR;
5512 /* put vox channel monitoring on the channel */
5513 if (ioctl(myrpt->voxchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
5515 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
5516 ast_hangup(mychannel);
5517 myrpt->callmode = 0;
5518 pthread_exit(NULL);
5520 while(myrpt->callmode)
5522 if ((!mychannel->pbx) && (myrpt->callmode != 4))
5524 /* If patch is setup for far end disconnect */
5525 if(myrpt->patchfarenddisconnect || (myrpt->p.duplex < 2)){
5526 if(debug)ast_log(LOG_NOTICE,"callmode=%i, patchfarenddisconnect=%i, duplex=%i\n",\
5527 myrpt->callmode,myrpt->patchfarenddisconnect,myrpt->p.duplex);
5528 myrpt->callmode = 0;
5529 myrpt->macropatch=0;
5530 if(!myrpt->patchquiet){
5531 rpt_mutex_unlock(&myrpt->lock);
5532 rpt_telemetry(myrpt, TERM, NULL);
5533 rpt_mutex_lock(&myrpt->lock);
5536 else{ /* Send congestion until patch is downed by command */
5537 myrpt->callmode = 4;
5538 rpt_mutex_unlock(&myrpt->lock);
5539 /* start congestion tone */
5540 tone_zone_play_tone(genchannel->fds[0],DAHDI_TONE_CONGESTION);
5541 rpt_mutex_lock(&myrpt->lock);
5544 if (myrpt->mydtmf)
5546 struct ast_frame wf = {AST_FRAME_DTMF, } ;
5547 wf.subclass = myrpt->mydtmf;
5548 rpt_mutex_unlock(&myrpt->lock);
5549 ast_queue_frame(mychannel,&wf);
5550 #ifdef NEW_ASTERISK
5551 ast_senddigit(genchannel,myrpt->mydtmf,0);
5552 #else
5553 ast_senddigit(genchannel,myrpt->mydtmf);
5554 #endif
5555 rpt_mutex_lock(&myrpt->lock);
5556 myrpt->mydtmf = 0;
5558 rpt_mutex_unlock(&myrpt->lock);
5559 usleep(MSWAIT * 1000);
5560 rpt_mutex_lock(&myrpt->lock);
5562 if(debug)
5563 ast_log(LOG_NOTICE, "exit channel loop\n");
5564 rpt_mutex_unlock(&myrpt->lock);
5565 tone_zone_play_tone(genchannel->fds[0],-1);
5566 if (mychannel->pbx) ast_softhangup(mychannel,AST_SOFTHANGUP_DEV);
5567 ast_hangup(genchannel);
5568 rpt_mutex_lock(&myrpt->lock);
5569 myrpt->callmode = 0;
5570 myrpt->macropatch=0;
5571 channel_revert(myrpt);
5572 rpt_mutex_unlock(&myrpt->lock);
5573 /* set appropriate conference for the pseudo */
5574 ci.chan = 0;
5575 ci.confno = myrpt->conf;
5576 ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? DAHDI_CONF_CONFANNMON :
5577 (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
5578 /* first put the channel on the conference in announce mode */
5579 if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
5581 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
5583 pthread_exit(NULL);
5586 static void send_link_dtmf(struct rpt *myrpt,char c)
5588 char str[300];
5589 struct ast_frame wf;
5590 struct rpt_link *l;
5592 snprintf(str, sizeof(str), "D %s %s %d %c", myrpt->cmdnode, myrpt->name, ++(myrpt->dtmfidx), c);
5593 wf.frametype = AST_FRAME_TEXT;
5594 wf.subclass = 0;
5595 wf.offset = 0;
5596 wf.mallocd = 0;
5597 wf.datalen = strlen(str) + 1;
5598 wf.samples = 0;
5599 l = myrpt->links.next;
5600 /* first, see if our dude is there */
5601 while(l != &myrpt->links)
5603 if (l->name[0] == '0')
5605 l = l->next;
5606 continue;
5608 /* if we found it, write it and were done */
5609 if (!strcmp(l->name,myrpt->cmdnode))
5611 wf.data.ptr = str;
5612 if (l->chan) ast_write(l->chan,&wf);
5613 return;
5615 l = l->next;
5617 l = myrpt->links.next;
5618 /* if not, give it to everyone */
5619 while(l != &myrpt->links)
5621 wf.data.ptr = str;
5622 if (l->chan) ast_write(l->chan,&wf);
5623 l = l->next;
5625 return;
5628 static void send_link_keyquery(struct rpt *myrpt)
5630 char str[300];
5631 struct ast_frame wf;
5632 struct rpt_link *l;
5634 rpt_mutex_lock(&myrpt->lock);
5635 memset(myrpt->topkey,0,sizeof(myrpt->topkey));
5636 myrpt->topkeystate = 1;
5637 time(&myrpt->topkeytime);
5638 rpt_mutex_unlock(&myrpt->lock);
5639 snprintf(str, sizeof(str), "K? * %s 0 0", myrpt->name);
5640 wf.frametype = AST_FRAME_TEXT;
5641 wf.subclass = 0;
5642 wf.offset = 0;
5643 wf.mallocd = 0;
5644 wf.datalen = strlen(str) + 1;
5645 wf.samples = 0;
5646 l = myrpt->links.next;
5647 /* give it to everyone */
5648 while(l != &myrpt->links)
5650 wf.data.ptr = str;
5651 if (l->chan) ast_write(l->chan,&wf);
5652 l = l->next;
5654 return;
5657 /* send newkey request */
5659 static void send_newkey(struct ast_channel *chan)
5662 /* ast_safe_sleep(chan,10); */
5663 ast_sendtext(chan,newkeystr);
5664 return;
5669 * Connect a link
5671 * Return values:
5672 * -2: Attempt to connect to self
5673 * -1: No such node
5674 * 0: Success
5675 * 1: No match yet
5676 * 2: Already connected to this node
5679 static int connect_link(struct rpt *myrpt, char* node, int mode, int perma)
5681 char *val, *s, *s1, *s2, *tele;
5682 char lstr[MAXLINKLIST],*strs[MAXLINKLIST];
5683 char tmp[300], deststr[300] = "",modechange = 0;
5684 char sx[320],*sy;
5685 struct rpt_link *l;
5686 int reconnects = 0;
5687 int i,n;
5688 DAHDI_CONFINFO ci; /* conference info */
5690 val = node_lookup(myrpt,node);
5691 if (!val){
5692 if(strlen(node) >= myrpt->longestnode)
5693 return -1; /* No such node */
5694 return 1; /* No match yet */
5697 if(!strcmp(myrpt->name,node)) /* Do not allow connections to self */
5698 return -2;
5700 if(debug > 3){
5701 ast_log(LOG_NOTICE,"Connect attempt to node %s\n", node);
5702 ast_log(LOG_NOTICE,"Mode: %s\n",(mode)?"Transceive":"Monitor");
5703 ast_log(LOG_NOTICE,"Connection type: %s\n",(perma)?"Permalink":"Normal");
5706 strncpy(tmp,val,sizeof(tmp) - 1);
5707 s = tmp;
5708 s1 = strsep(&s,",");
5709 if (!strchr(s1,':') && strchr(s1,'/') && strncasecmp(s1, "local/", 6))
5711 sy = strchr(s1,'/');
5712 *sy = 0;
5713 sprintf(sx,"%s:4569/%s",s1,sy + 1);
5714 s1 = sx;
5716 s2 = strsep(&s,",");
5717 rpt_mutex_lock(&myrpt->lock);
5718 l = myrpt->links.next;
5719 /* try to find this one in queue */
5720 while(l != &myrpt->links){
5721 if (l->name[0] == '0')
5723 l = l->next;
5724 continue;
5726 /* if found matching string */
5727 if (!strcmp(l->name, node))
5728 break;
5729 l = l->next;
5731 /* if found */
5732 if (l != &myrpt->links){
5733 /* if already in this mode, just ignore */
5734 if ((l->mode) || (!l->chan)) {
5735 rpt_mutex_unlock(&myrpt->lock);
5736 return 2; /* Already linked */
5738 reconnects = l->reconnects;
5739 rpt_mutex_unlock(&myrpt->lock);
5740 if (l->chan) ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
5741 l->retries = l->max_retries + 1;
5742 l->disced = 2;
5743 modechange = 1;
5744 } else
5746 __mklinklist(myrpt,NULL,lstr);
5747 rpt_mutex_unlock(&myrpt->lock);
5748 n = finddelim(lstr,strs,MAXLINKLIST);
5749 for(i = 0; i < n; i++)
5751 if ((*strs[i] < '0') ||
5752 (*strs[i] > '9')) strs[i]++;
5753 if (!strcmp(strs[i],node))
5755 return 2; /* Already linked */
5759 strncpy(myrpt->lastlinknode,node,MAXNODESTR - 1);
5760 /* establish call */
5761 l = ast_malloc(sizeof(struct rpt_link));
5762 if (!l)
5764 ast_log(LOG_WARNING, "Unable to malloc\n");
5765 return -1;
5767 /* zero the silly thing */
5768 memset((char *)l,0,sizeof(struct rpt_link));
5769 l->mode = mode;
5770 l->outbound = 1;
5771 l->thisconnected = 0;
5772 voxinit_link(l,1);
5773 strncpy(l->name, node, MAXNODESTR - 1);
5774 l->isremote = (s && ast_true(s));
5775 if (modechange) l->connected = 1;
5776 l->hasconnected = l->perma = perma;
5777 #ifdef ALLOW_LOCAL_CHANNELS
5778 if ((strncasecmp(s1,"iax2/", 5) == 0) || (strncasecmp(s1, "local/", 6) == 0))
5779 strncpy(deststr, s1, sizeof(deststr));
5780 else
5781 snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
5782 #else
5783 snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
5784 #endif
5785 tele = strchr(deststr, '/');
5786 if (!tele){
5787 ast_log(LOG_WARNING,"link3:Dial number (%s) must be in format tech/number\n",deststr);
5788 ast_free(l);
5789 return -1;
5791 *tele++ = 0;
5792 l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL);
5793 if (l->chan){
5794 ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
5795 ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
5796 #ifdef AST_CDR_FLAG_POST_DISABLED
5797 if (l->chan->cdr)
5798 ast_set_flag(l->chan->cdr,AST_CDR_FLAG_POST_DISABLED);
5799 #endif
5800 #ifndef NEW_ASTERISK
5801 l->chan->whentohangup = 0;
5802 #endif
5803 l->chan->appl = "Apprpt";
5804 l->chan->data = "(Remote Rx)";
5805 if (debug > 3)
5806 ast_log(LOG_NOTICE, "rpt (remote) initiating call to %s/%s on %s\n",
5807 deststr, tele, l->chan->name);
5808 if(l->chan->cid.cid_num)
5809 ast_free(l->chan->cid.cid_num);
5810 l->chan->cid.cid_num = ast_strdup(myrpt->name);
5811 ast_call(l->chan,tele,999);
5813 else {
5814 if(debug > 3)
5815 ast_log(LOG_NOTICE, "Unable to place call to %s/%s on %s\n",
5816 deststr,tele,l->chan->name);
5817 if (myrpt->p.archivedir)
5819 char str[100];
5820 sprintf(str,"LINKFAIL,%s",l->name);
5821 donodelog(myrpt,str);
5823 ast_free(l);
5824 return -1;
5826 /* allocate a pseudo-channel thru asterisk */
5827 l->pchan = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
5828 if (!l->pchan){
5829 ast_log(LOG_WARNING,"rpt connect: Sorry unable to obtain pseudo channel\n");
5830 ast_hangup(l->chan);
5831 ast_free(l);
5832 return -1;
5834 ast_set_read_format(l->pchan, AST_FORMAT_SLINEAR);
5835 ast_set_write_format(l->pchan, AST_FORMAT_SLINEAR);
5836 #ifdef AST_CDR_FLAG_POST_DISABLED
5837 if (l->pchan->cdr)
5838 ast_set_flag(l->pchan->cdr,AST_CDR_FLAG_POST_DISABLED);
5839 #endif
5840 /* make a conference for the tx */
5841 ci.chan = 0;
5842 ci.confno = myrpt->conf;
5843 ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER;
5844 /* first put the channel on the conference in proper mode */
5845 if (ioctl(l->pchan->fds[0], DAHDI_SETCONF, &ci) == -1)
5847 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
5848 ast_hangup(l->chan);
5849 ast_hangup(l->pchan);
5850 ast_free(l);
5851 return -1;
5853 rpt_mutex_lock(&myrpt->lock);
5854 l->reconnects = reconnects;
5855 /* insert at end of queue */
5856 l->max_retries = MAX_RETRIES;
5857 if (perma)
5858 l->max_retries = MAX_RETRIES_PERM;
5859 if (l->isremote) l->retries = l->max_retries + 1;
5860 insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
5861 __kickshort(myrpt);
5862 rpt_mutex_unlock(&myrpt->lock);
5863 if (!l->phonemode) send_newkey(l->chan);
5864 return 0;
5870 * Internet linking function
5873 static int function_ilink(struct rpt *myrpt, char *param, char *digits, int command_source, struct rpt_link *mylink)
5876 char *val, *s, *s1, *s2;
5877 char tmp[300];
5878 char digitbuf[MAXNODESTR],*strs[MAXLINKLIST];
5879 char mode,perma;
5880 char sx[320],*sy;
5881 struct rpt_link *l;
5882 int i,r;
5884 if(!param)
5885 return DC_ERROR;
5888 if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable )
5889 return DC_ERROR;
5891 strncpy(digitbuf,digits,MAXNODESTR - 1);
5893 if(debug > 6)
5894 printf("@@@@ ilink param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
5896 switch(myatoi(param)){
5897 case 11: /* Perm Link off */
5898 case 1: /* Link off */
5899 if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
5900 strcpy(digitbuf,myrpt->lastlinknode);
5901 val = node_lookup(myrpt,digitbuf);
5902 if (!val){
5903 if(strlen(digitbuf) >= myrpt->longestnode)
5904 return DC_ERROR;
5905 break;
5907 strncpy(tmp,val,sizeof(tmp) - 1);
5908 s = tmp;
5909 s1 = strsep(&s,",");
5910 if (!strchr(s1,':') && strchr(s1,'/') && strncasecmp(s1, "local/", 6))
5912 sy = strchr(s1,'/');
5913 *sy = 0;
5914 sprintf(sx,"%s:4569/%s",s1,sy + 1);
5915 s1 = sx;
5917 s2 = strsep(&s,",");
5918 rpt_mutex_lock(&myrpt->lock);
5919 l = myrpt->links.next;
5920 /* try to find this one in queue */
5921 while(l != &myrpt->links){
5922 if (l->name[0] == '0')
5924 l = l->next;
5925 continue;
5927 /* if found matching string */
5928 if (!strcmp(l->name, digitbuf))
5929 break;
5930 l = l->next;
5932 if (l != &myrpt->links){ /* if found */
5933 struct ast_frame wf;
5935 /* must use perm command on perm link */
5936 if ((myatoi(param) < 10) &&
5937 (l->max_retries > MAX_RETRIES))
5939 rpt_mutex_unlock(&myrpt->lock);
5940 return DC_COMPLETE;
5942 strncpy(myrpt->lastlinknode,digitbuf,MAXNODESTR - 1);
5943 l->retries = l->max_retries + 1;
5944 l->disced = 1;
5945 rpt_mutex_unlock(&myrpt->lock);
5946 wf.frametype = AST_FRAME_TEXT;
5947 wf.subclass = 0;
5948 wf.offset = 0;
5949 wf.mallocd = 0;
5950 wf.datalen = strlen(discstr) + 1;
5951 wf.samples = 0;
5952 wf.data.ptr = discstr;
5953 if (l->chan)
5955 ast_write(l->chan,&wf);
5956 if (ast_safe_sleep(l->chan,250) == -1) return DC_ERROR;
5957 ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
5959 rpt_telemetry(myrpt, COMPLETE, NULL);
5960 return DC_COMPLETE;
5962 rpt_mutex_unlock(&myrpt->lock);
5963 return DC_COMPLETE;
5964 case 2: /* Link Monitor */
5965 case 3: /* Link transceive */
5966 case 12: /* Link Monitor permanent */
5967 case 13: /* Link transceive permanent */
5968 if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
5969 strcpy(digitbuf,myrpt->lastlinknode);
5970 /* Attempt connection */
5971 perma = (atoi(param) > 10) ? 1 : 0;
5972 mode = (atoi(param) & 1) ? 1 : 0;
5973 r = connect_link(myrpt, digitbuf, mode, perma);
5974 switch(r){
5975 case -2: /* Attempt to connect to self */
5976 return DC_COMPLETE; /* Silent error */
5978 case 0:
5979 rpt_telemetry(myrpt, COMPLETE, NULL);
5980 return DC_COMPLETE;
5982 case 1:
5983 break;
5985 case 2:
5986 rpt_telemetry(myrpt, REMALREADY, NULL);
5987 return DC_COMPLETE;
5989 default:
5990 rpt_telemetry(myrpt, CONNFAIL, NULL);
5991 return DC_COMPLETE;
5993 break;
5995 case 4: /* Enter Command Mode */
5997 /* if doesnt allow link cmd, or no links active, return */
5998 if (((command_source != SOURCE_RPT) &&
5999 (command_source != SOURCE_PHONE) &&
6000 (command_source != SOURCE_ALT) &&
6001 (command_source != SOURCE_DPHONE)) ||
6002 (myrpt->links.next == &myrpt->links))
6003 return DC_COMPLETE;
6005 /* if already in cmd mode, or selected self, fughetabahtit */
6006 if ((myrpt->cmdnode[0]) || (!strcmp(myrpt->name, digitbuf))){
6008 rpt_telemetry(myrpt, REMALREADY, NULL);
6009 return DC_COMPLETE;
6011 if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
6012 strcpy(digitbuf,myrpt->lastlinknode);
6013 /* node must at least exist in list */
6014 val = node_lookup(myrpt,digitbuf);
6015 if (!val){
6016 if(strlen(digitbuf) >= myrpt->longestnode)
6017 return DC_ERROR;
6018 break;
6021 rpt_mutex_lock(&myrpt->lock);
6022 strcpy(myrpt->lastlinknode,digitbuf);
6023 strncpy(myrpt->cmdnode, digitbuf, sizeof(myrpt->cmdnode) - 1);
6024 rpt_mutex_unlock(&myrpt->lock);
6025 rpt_telemetry(myrpt, REMGO, NULL);
6026 return DC_COMPLETE;
6028 case 5: /* Status */
6029 rpt_telemetry(myrpt, STATUS, NULL);
6030 return DC_COMPLETE;
6032 case 15: /* Full Status */
6033 rpt_telemetry(myrpt, FULLSTATUS, NULL);
6034 return DC_COMPLETE;
6037 case 6: /* All Links Off, including permalinks */
6038 rpt_mutex_lock(&myrpt->lock);
6039 myrpt->savednodes[0] = 0;
6040 l = myrpt->links.next;
6041 /* loop through all links */
6042 while(l != &myrpt->links){
6043 struct ast_frame wf;
6044 if (l->name[0] == '0') /* Skip any IAXRPT monitoring */
6046 l = l->next;
6047 continue;
6049 /* Make a string of disconnected nodes for possible restoration */
6050 sprintf(tmp,"%c%c%s",(l->mode) ? 'X' : 'M',(l->perma) ? 'P':'T',l->name);
6051 if(strlen(tmp) + strlen(myrpt->savednodes) + 1 < MAXNODESTR){
6052 if(myrpt->savednodes[0])
6053 strcat(myrpt->savednodes, ",");
6054 strcat(myrpt->savednodes, tmp);
6056 l->retries = l->max_retries + 1;
6057 l->disced = 2; /* Silently disconnect */
6058 rpt_mutex_unlock(&myrpt->lock);
6059 /* ast_log(LOG_NOTICE,"dumping link %s\n",l->name); */
6061 wf.frametype = AST_FRAME_TEXT;
6062 wf.subclass = 0;
6063 wf.offset = 0;
6064 wf.mallocd = 0;
6065 wf.datalen = strlen(discstr) + 1;
6066 wf.samples = 0;
6067 wf.data.ptr = discstr;
6068 if (l->chan)
6070 ast_write(l->chan,&wf);
6071 ast_safe_sleep(l->chan,250); /* It's dead already, why check the return value? */
6072 ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
6074 rpt_mutex_lock(&myrpt->lock);
6075 l = l->next;
6077 rpt_mutex_unlock(&myrpt->lock);
6078 if(debug > 3)
6079 ast_log(LOG_NOTICE,"Nodes disconnected: %s\n",myrpt->savednodes);
6080 rpt_telemetry(myrpt, COMPLETE, NULL);
6081 return DC_COMPLETE;
6083 case 7: /* Identify last node which keyed us up */
6084 rpt_telemetry(myrpt, LASTNODEKEY, NULL);
6085 break;
6088 #ifdef _MDC_DECODE_H_
6089 case 8:
6090 myrpt->lastunit = 0xd00d;
6091 mdc1200_notify(myrpt,NULL,myrpt->lastunit);
6092 mdc1200_send(myrpt,myrpt->lastunit);
6093 break;
6094 #endif
6096 case 16: /* Restore links disconnected with "disconnect all links" command */
6097 strcpy(tmp, myrpt->savednodes); /* Make a copy */
6098 finddelim(tmp, strs, MAXLINKLIST); /* convert into substrings */
6099 for(i = 0; tmp[0] && strs[i] != NULL && i < MAXLINKLIST; i++){
6100 s1 = strs[i];
6101 mode = (s1[0] == 'X') ? 1 : 0;
6102 perma = (s1[1] == 'P') ? 1 : 0;
6103 connect_link(myrpt, s1 + 2, mode, perma); /* Try to reconnect */
6105 rpt_telemetry(myrpt, COMPLETE, NULL);
6106 break;
6108 case 200:
6109 case 201:
6110 case 202:
6111 case 203:
6112 case 204:
6113 case 205:
6114 case 206:
6115 case 207:
6116 case 208:
6117 case 209:
6118 case 210:
6119 case 211:
6120 case 212:
6121 case 213:
6122 case 214:
6123 case 215:
6124 if (((myrpt->p.propagate_dtmf) &&
6125 (command_source == SOURCE_LNK)) ||
6126 ((myrpt->p.propagate_phonedtmf) &&
6127 ((command_source == SOURCE_PHONE) ||
6128 (command_source == SOURCE_ALT) ||
6129 (command_source == SOURCE_DPHONE))))
6130 do_dtmf_local(myrpt,
6131 remdtmfstr[myatoi(param) - 200]);
6132 default:
6133 return DC_ERROR;
6137 return DC_INDETERMINATE;
6141 * Autopatch up
6144 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
6146 pthread_attr_t attr;
6147 int i, index, paramlength;
6148 char *lparam;
6149 char *value = NULL;
6150 char *paramlist[20];
6152 static char *keywords[] = {
6153 "context",
6154 "dialtime",
6155 "farenddisconnect",
6156 "noct",
6157 "quiet",
6158 NULL
6161 if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
6162 return DC_ERROR;
6164 if(debug)
6165 printf("@@@@ Autopatch up\n");
6167 if(!myrpt->callmode){
6168 /* Set defaults */
6169 myrpt->patchnoct = 0;
6170 myrpt->patchdialtime = 0;
6171 myrpt->patchfarenddisconnect = 0;
6172 myrpt->patchquiet = 0;
6173 strncpy(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
6175 if(param){
6176 /* Process parameter list */
6177 lparam = ast_strdup(param);
6178 if(!lparam){
6179 ast_log(LOG_ERROR,"App_rpt out of memory on line %d\n",__LINE__);
6180 return DC_ERROR;
6182 paramlength = finddelim(lparam, paramlist, 20);
6183 for(i = 0; i < paramlength; i++){
6184 index = matchkeyword(paramlist[i], &value, keywords);
6185 if(value)
6186 value = skipchars(value, "= ");
6187 switch(index){
6189 case 1: /* context */
6190 strncpy(myrpt->patchcontext, value, MAXPATCHCONTEXT - 1) ;
6191 break;
6193 case 2: /* dialtime */
6194 myrpt->patchdialtime = atoi(value);
6195 break;
6197 case 3: /* farenddisconnect */
6198 myrpt->patchfarenddisconnect = atoi(value);
6199 break;
6201 case 4: /* noct */
6202 myrpt->patchnoct = atoi(value);
6203 break;
6205 case 5: /* quiet */
6206 myrpt->patchquiet = atoi(value);
6207 break;
6209 default:
6210 break;
6213 ast_free(lparam);
6217 rpt_mutex_lock(&myrpt->lock);
6219 /* if on call, force * into current audio stream */
6221 if ((myrpt->callmode == 2) || (myrpt->callmode == 3)){
6222 myrpt->mydtmf = myrpt->p.endchar;
6224 if (myrpt->callmode){
6225 rpt_mutex_unlock(&myrpt->lock);
6226 return DC_COMPLETE;
6228 myrpt->callmode = 1;
6229 myrpt->cidx = 0;
6230 myrpt->exten[myrpt->cidx] = 0;
6231 rpt_mutex_unlock(&myrpt->lock);
6232 pthread_attr_init(&attr);
6233 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
6234 ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *) myrpt);
6235 return DC_COMPLETE;
6239 * Autopatch down
6242 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
6244 if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
6245 return DC_ERROR;
6247 if(debug)
6248 printf("@@@@ Autopatch down\n");
6250 rpt_mutex_lock(&myrpt->lock);
6252 myrpt->macropatch=0;
6254 if (!myrpt->callmode){
6255 rpt_mutex_unlock(&myrpt->lock);
6256 return DC_COMPLETE;
6259 myrpt->callmode = 0;
6260 channel_revert(myrpt);
6261 rpt_mutex_unlock(&myrpt->lock);
6262 rpt_telemetry(myrpt, TERM, NULL);
6263 return DC_COMPLETE;
6267 * Status
6270 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
6273 if (!param)
6274 return DC_ERROR;
6276 if ((myrpt->p.s[myrpt->p.sysstate_cur].txdisable) || (myrpt->p.s[myrpt->p.sysstate_cur].userfundisable))
6277 return DC_ERROR;
6279 if(debug)
6280 printf("@@@@ status param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
6282 switch(myatoi(param)){
6283 case 1: /* System ID */
6284 rpt_telemetry(myrpt, ID1, NULL);
6285 return DC_COMPLETE;
6286 case 2: /* System Time */
6287 rpt_telemetry(myrpt, STATS_TIME, NULL);
6288 return DC_COMPLETE;
6289 case 3: /* app_rpt.c version */
6290 rpt_telemetry(myrpt, STATS_VERSION, NULL);
6291 return DC_COMPLETE;
6292 case 11: /* System ID (local only)*/
6293 rpt_telemetry(myrpt, ID , NULL);
6294 return DC_COMPLETE;
6295 case 12: /* System Time (local only)*/
6296 rpt_telemetry(myrpt, STATS_TIME_LOCAL, NULL);
6297 return DC_COMPLETE;
6298 default:
6299 return DC_ERROR;
6301 return DC_INDETERMINATE;
6304 * Macro-oni (without Salami)
6306 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
6308 char *val;
6309 int i;
6310 if (myrpt->remote)
6311 return DC_ERROR;
6313 if(debug)
6314 printf("@@@@ macro-oni param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
6316 if(strlen(digitbuf) < 1) /* needs 1 digit */
6317 return DC_INDETERMINATE;
6319 for(i = 0 ; i < digitbuf[i] ; i++) {
6320 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
6321 return DC_ERROR;
6324 if (*digitbuf == '0') val = myrpt->p.startupmacro;
6325 else val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, digitbuf);
6326 /* param was 1 for local buf */
6327 if (!val){
6328 if (strlen(digitbuf) < myrpt->macro_longest)
6329 return DC_INDETERMINATE;
6330 rpt_telemetry(myrpt, MACRO_NOTFOUND, NULL);
6331 return DC_COMPLETE;
6333 rpt_mutex_lock(&myrpt->lock);
6334 if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val))
6336 rpt_mutex_unlock(&myrpt->lock);
6337 rpt_telemetry(myrpt, MACRO_BUSY, NULL);
6338 return DC_ERROR;
6340 myrpt->macrotimer = MACROTIME;
6341 strncat(myrpt->macrobuf,val,MAXMACRO - 1);
6342 rpt_mutex_unlock(&myrpt->lock);
6343 return DC_COMPLETE;
6347 * Playback a recording
6350 static int function_playback(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
6353 if (myrpt->remote)
6354 return DC_ERROR;
6356 if(debug)
6357 printf("@@@@ playback param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
6359 if (ast_fileexists(param,NULL,myrpt->rxchannel->language) <= 0)
6360 return DC_ERROR;
6362 rpt_telemetry(myrpt,PLAYBACK,param);
6363 return DC_COMPLETE;
6367 * COP - Control operator
6370 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
6372 char string[16];
6374 int i, r;
6376 if(!param)
6377 return DC_ERROR;
6379 switch(myatoi(param)){
6380 case 1: /* System reset */
6381 system("killall -9 asterisk");
6382 return DC_COMPLETE;
6384 case 2:
6385 myrpt->p.s[myrpt->p.sysstate_cur].txdisable = 0;
6386 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "RPTENA");
6387 return DC_COMPLETE;
6389 case 3:
6390 myrpt->p.s[myrpt->p.sysstate_cur].txdisable = 1;
6391 return DC_COMPLETE;
6393 case 4: /* test tone on */
6394 if (myrpt->stopgen < 0)
6396 myrpt->stopgen = 1;
6398 else
6400 myrpt->stopgen = 0;
6401 rpt_telemetry(myrpt, TEST_TONE, NULL);
6403 return DC_COMPLETE;
6405 case 5: /* Disgorge variables to log for debug purposes */
6406 myrpt->disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
6407 return DC_COMPLETE;
6409 case 6: /* Simulate COR being activated (phone only) */
6410 if (command_source != SOURCE_PHONE) return DC_INDETERMINATE;
6411 return DC_DOKEY;
6414 case 7: /* Time out timer enable */
6415 myrpt->p.s[myrpt->p.sysstate_cur].totdisable = 0;
6416 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "TOTENA");
6417 return DC_COMPLETE;
6419 case 8: /* Time out timer disable */
6420 myrpt->p.s[myrpt->p.sysstate_cur].totdisable = 1;
6421 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "TOTDIS");
6422 return DC_COMPLETE;
6424 case 9: /* Autopatch enable */
6425 myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable = 0;
6426 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "APENA");
6427 return DC_COMPLETE;
6429 case 10: /* Autopatch disable */
6430 myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable = 1;
6431 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "APDIS");
6432 return DC_COMPLETE;
6434 case 11: /* Link Enable */
6435 myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable = 0;
6436 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "LNKENA");
6437 return DC_COMPLETE;
6439 case 12: /* Link Disable */
6440 myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable = 1;
6441 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "LNKDIS");
6442 return DC_COMPLETE;
6444 case 13: /* Query System State */
6445 string[0] = string[1] = 'S';
6446 string[2] = myrpt->p.sysstate_cur + '0';
6447 string[3] = '\0';
6448 rpt_telemetry(myrpt, ARB_ALPHA, (void *) string);
6449 return DC_COMPLETE;
6451 case 14: /* Change System State */
6452 if(strlen(digitbuf) == 0)
6453 break;
6454 if((digitbuf[0] < '0') || (digitbuf[0] > '9'))
6455 return DC_ERROR;
6456 myrpt->p.sysstate_cur = digitbuf[0] - '0';
6457 string[0] = string[1] = 'S';
6458 string[2] = myrpt->p.sysstate_cur + '0';
6459 string[3] = '\0';
6460 rpt_telemetry(myrpt, ARB_ALPHA, (void *) string);
6461 return DC_COMPLETE;
6463 case 15: /* Scheduler Enable */
6464 myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable = 0;
6465 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "SKENA");
6466 return DC_COMPLETE;
6468 case 16: /* Scheduler Disable */
6469 myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable = 1;
6470 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "SKDIS");
6471 return DC_COMPLETE;
6473 case 17: /* User functions Enable */
6474 myrpt->p.s[myrpt->p.sysstate_cur].userfundisable = 0;
6475 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "UFENA");
6476 return DC_COMPLETE;
6478 case 18: /* User Functions Disable */
6479 myrpt->p.s[myrpt->p.sysstate_cur].userfundisable = 1;
6480 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "UFDIS");
6481 return DC_COMPLETE;
6483 case 19: /* Alternate Tail Enable */
6484 myrpt->p.s[myrpt->p.sysstate_cur].alternatetail = 1;
6485 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "ATENA");
6486 return DC_COMPLETE;
6488 case 20: /* Alternate Tail Disable */
6489 myrpt->p.s[myrpt->p.sysstate_cur].alternatetail = 0;
6490 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "ATDIS");
6491 return DC_COMPLETE;
6493 case 21: /* Parrot Mode Disable */
6494 birdbath(myrpt);
6495 if (myrpt->p.parrotmode < 2)
6497 myrpt->p.parrotmode = 0;
6498 rpt_telemetry(myrpt,COMPLETE,NULL);
6499 return DC_COMPLETE;
6501 break;
6503 case 22: /* Parrot Mode Enable */
6504 birdbath(myrpt);
6505 if (myrpt->p.parrotmode < 2)
6507 myrpt->p.parrotmode = 1;
6508 rpt_telemetry(myrpt,COMPLETE,NULL);
6509 return DC_COMPLETE;
6511 break;
6512 case 23: /* flush parrot in progress */
6513 birdbath(myrpt);
6514 rpt_telemetry(myrpt,COMPLETE,NULL);
6515 return DC_COMPLETE;
6516 case 24: /* flush all telemetry */
6517 flush_telem(myrpt);
6518 rpt_telemetry(myrpt,COMPLETE,NULL);
6519 return DC_COMPLETE;
6520 case 25: /* request keying info (brief) */
6521 send_link_keyquery(myrpt);
6522 myrpt->topkeylong = 0;
6523 rpt_telemetry(myrpt,COMPLETE,NULL);
6524 return DC_COMPLETE;
6525 case 26: /* request keying info (full) */
6526 send_link_keyquery(myrpt);
6527 myrpt->topkeylong = 1;
6528 rpt_telemetry(myrpt,COMPLETE,NULL);
6529 return DC_COMPLETE;
6531 case 30: /* recall memory location on programmable radio */
6533 if(strlen(digitbuf) < 2) /* needs 2 digits */
6534 break;
6536 for(i = 0 ; i < 2 ; i++){
6537 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
6538 return DC_ERROR;
6541 r = retreive_memory(myrpt, digitbuf);
6542 if (r < 0){
6543 rpt_telemetry(myrpt,MEMNOTFOUND,NULL);
6544 return DC_COMPLETE;
6546 if (r > 0){
6547 return DC_ERROR;
6549 if (setrem(myrpt) == -1) return DC_ERROR;
6550 return DC_COMPLETE;
6552 case 31:
6553 /* set channel. note that it's going to change channel
6554 then confirm on the new channel! */
6555 if(strlen(digitbuf) < 2) /* needs 2 digits */
6556 break;
6558 for(i = 0 ; i < 2 ; i++){
6559 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
6560 return DC_ERROR;
6562 channel_steer(myrpt,digitbuf);
6563 return DC_COMPLETE;
6565 case 32: /* Touch Tone Pad Test */
6566 i = strlen(digitbuf);
6567 if(!i){
6568 if(debug > 3)
6569 ast_log(LOG_NOTICE,"Padtest entered");
6570 myrpt->inpadtest = 1;
6572 else{
6573 if(debug > 3)
6574 ast_log(LOG_NOTICE,"Padtest len= %d digits=%s",i,digitbuf);
6575 if(digitbuf[i-1] != myrpt->p.endchar)
6576 break;
6577 rpt_telemetry(myrpt, ARB_ALPHA, digitbuf);
6578 myrpt->inpadtest = 0;
6579 if(debug > 3)
6580 ast_log(LOG_NOTICE,"Padtest exited");
6581 return DC_COMPLETE;
6584 return DC_INDETERMINATE;
6587 * Collect digits one by one until something matches
6589 static int collect_function_digits(struct rpt *myrpt, char *digits,
6590 int command_source, struct rpt_link *mylink)
6592 int i,rv;
6593 char *stringp,*action,*param,*functiondigits;
6594 char function_table_name[30] = "";
6595 char workstring[200];
6597 struct ast_variable *vp;
6599 if (debug > 6) ast_log(LOG_NOTICE,"digits=%s source=%d\n",digits, command_source);
6601 //if(debug)
6602 // printf("@@@@ Digits collected: %s, source: %d\n", digits, command_source);
6604 if (command_source == SOURCE_DPHONE) {
6605 if (!myrpt->p.dphone_functions) return DC_INDETERMINATE;
6606 strncpy(function_table_name, myrpt->p.dphone_functions, sizeof(function_table_name) - 1);
6608 else if (command_source == SOURCE_ALT) {
6609 if (!myrpt->p.alt_functions) return DC_INDETERMINATE;
6610 strncpy(function_table_name, myrpt->p.alt_functions, sizeof(function_table_name) - 1);
6612 else if (command_source == SOURCE_PHONE) {
6613 if (!myrpt->p.phone_functions) return DC_INDETERMINATE;
6614 strncpy(function_table_name, myrpt->p.phone_functions, sizeof(function_table_name) - 1);
6616 else if (command_source == SOURCE_LNK)
6617 strncpy(function_table_name, myrpt->p.link_functions, sizeof(function_table_name) - 1);
6618 else
6619 strncpy(function_table_name, myrpt->p.functions, sizeof(function_table_name) - 1);
6620 /* find context for function table in rpt.conf file */
6621 vp = ast_variable_browse(myrpt->cfg, function_table_name);
6622 while(vp) {
6623 if(!strncasecmp(vp->name, digits, strlen(vp->name)))
6624 break;
6625 vp = vp->next;
6627 /* if function context not found */
6628 if(!vp) {
6629 int n;
6631 n = myrpt->longestfunc;
6632 if (command_source == SOURCE_LNK) n = myrpt->link_longestfunc;
6633 else
6634 if (command_source == SOURCE_PHONE) n = myrpt->phone_longestfunc;
6635 else
6636 if (command_source == SOURCE_ALT) n = myrpt->alt_longestfunc;
6637 else
6638 if (command_source == SOURCE_DPHONE) n = myrpt->dphone_longestfunc;
6640 if(strlen(digits) >= n)
6641 return DC_ERROR;
6642 else
6643 return DC_INDETERMINATE;
6645 /* Found a match, retrieve value part and parse */
6646 strncpy(workstring, vp->value, sizeof(workstring) - 1 );
6647 stringp = workstring;
6648 action = strsep(&stringp, ",");
6649 param = stringp;
6650 if(debug)
6651 printf("@@@@ action: %s, param = %s\n",action, (param) ? param : "(null)");
6652 /* Look up the action */
6653 for(i = 0 ; i < (sizeof(function_table)/sizeof(struct function_table_tag)); i++){
6654 if(!strncasecmp(action, function_table[i].action, strlen(action)))
6655 break;
6657 if(debug)
6658 printf("@@@@ table index i = %d\n",i);
6659 if(i == (sizeof(function_table)/sizeof(struct function_table_tag))){
6660 /* Error, action not in table */
6661 return DC_ERROR;
6663 if(function_table[i].function == NULL){
6664 /* Error, function undefined */
6665 if(debug)
6666 printf("@@@@ NULL for action: %s\n",action);
6667 return DC_ERROR;
6669 functiondigits = digits + strlen(vp->name);
6670 rv=(*function_table[i].function)(myrpt, param, functiondigits, command_source, mylink);
6671 if (debug > 6) ast_log(LOG_NOTICE,"rv=%i\n",rv);
6672 return(rv);
6676 static void handle_link_data(struct rpt *myrpt, struct rpt_link *mylink,
6677 char *str)
6679 char tmp[512],tmp1[512],cmd[300] = "",dest[300],src[300],c;
6680 int i,seq, res, ts;
6681 struct rpt_link *l;
6682 struct ast_frame wf;
6684 wf.frametype = AST_FRAME_TEXT;
6685 wf.subclass = 0;
6686 wf.offset = 0;
6687 wf.mallocd = 0;
6688 wf.datalen = strlen(str) + 1;
6689 wf.samples = 0;
6690 /* put string in our buffer */
6691 strncpy(tmp,str,sizeof(tmp) - 1);
6693 if (!strcmp(tmp,discstr))
6695 mylink->disced = 1;
6696 mylink->retries = mylink->max_retries + 1;
6697 ast_softhangup(mylink->chan,AST_SOFTHANGUP_DEV);
6698 return;
6700 if (!strcmp(tmp,newkeystr))
6702 mylink->newkey = 1;
6703 return;
6705 if (tmp[0] == 'L')
6707 rpt_mutex_lock(&myrpt->lock);
6708 strcpy(mylink->linklist,tmp + 2);
6709 time(&mylink->linklistreceived);
6710 rpt_mutex_unlock(&myrpt->lock);
6711 if (debug > 6) ast_log(LOG_NOTICE,"@@@@ node %s recieved node list %s from node %s\n",
6712 myrpt->name,tmp,mylink->name);
6713 return;
6715 if (tmp[0] == 'K')
6717 if (sscanf(tmp,"%s %s %s %d %d",cmd,dest,src,&seq,&ts) != 5)
6719 ast_log(LOG_WARNING, "Unable to parse keying string %s\n",str);
6720 return;
6722 if (dest[0] == '0')
6724 strcpy(dest,myrpt->name);
6726 /* if not for me, redistribute to all links */
6727 if (strcmp(dest,myrpt->name))
6729 l = myrpt->links.next;
6730 /* see if this is one in list */
6731 while(l != &myrpt->links)
6733 if (l->name[0] == '0')
6735 l = l->next;
6736 continue;
6738 /* dont send back from where it came */
6739 if ((l == mylink) || (!strcmp(l->name,mylink->name)))
6741 l = l->next;
6742 continue;
6744 /* if it is, send it and we're done */
6745 if (!strcmp(l->name,dest))
6747 /* send, but not to src */
6748 if (strcmp(l->name,src)) {
6749 wf.data.ptr = str;
6750 if (l->chan) ast_write(l->chan,&wf);
6752 return;
6754 l = l->next;
6757 /* if not for me, or is broadcast, redistribute to all links */
6758 if ((strcmp(dest,myrpt->name)) || (dest[0] == '*'))
6760 l = myrpt->links.next;
6761 /* otherwise, send it to all of em */
6762 while(l != &myrpt->links)
6764 if (l->name[0] == '0')
6766 l = l->next;
6767 continue;
6769 /* dont send back from where it came */
6770 if ((l == mylink) || (!strcmp(l->name,mylink->name)))
6772 l = l->next;
6773 continue;
6775 /* send, but not to src */
6776 if (strcmp(l->name,src)) {
6777 wf.data.ptr = str;
6778 if (l->chan) ast_write(l->chan,&wf);
6780 l = l->next;
6783 /* if not for me, end here */
6784 if (strcmp(dest,myrpt->name) && (dest[0] != '*')) return;
6785 if (cmd[1] == '?')
6787 time_t now;
6788 int n = 0;
6790 time(&now);
6791 if (myrpt->lastkeyedtime)
6793 n = (int)(now - myrpt->lastkeyedtime);
6795 sprintf(tmp1,"K %s %s %d %d",src,myrpt->name,myrpt->keyed,n);
6796 wf.data.ptr = tmp1;
6797 wf.datalen = strlen(tmp1) + 1;
6798 if (mylink->chan) ast_write(mylink->chan,&wf);
6799 return;
6801 if (myrpt->topkeystate != 1) return;
6802 rpt_mutex_lock(&myrpt->lock);
6803 for(i = 0; i < TOPKEYN; i++)
6805 if (!strcmp(myrpt->topkey[i].node,src)) break;
6807 if (i >= TOPKEYN)
6809 for(i = 0; i < TOPKEYN; i++)
6811 if (!myrpt->topkey[i].node[0]) break;
6814 if (i < TOPKEYN)
6816 strncpy(myrpt->topkey[i].node,src,TOPKEYMAXSTR - 1);
6817 myrpt->topkey[i].timesince = ts;
6818 myrpt->topkey[i].keyed = seq;
6820 rpt_mutex_unlock(&myrpt->lock);
6821 return;
6823 if (tmp[0] == 'I')
6825 if (sscanf(tmp,"%s %s %x",cmd,src,&seq) != 3)
6827 ast_log(LOG_WARNING, "Unable to parse ident string %s\n",str);
6828 return;
6830 mdc1200_notify(myrpt,src,seq);
6831 strcpy(dest,"*");
6833 else
6835 if (sscanf(tmp,"%s %s %s %d %c",cmd,dest,src,&seq,&c) != 5)
6837 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
6838 return;
6840 if (strcmp(cmd,"D"))
6842 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
6843 return;
6846 if (dest[0] == '0')
6848 strcpy(dest,myrpt->name);
6851 /* if not for me, redistribute to all links */
6852 if (strcmp(dest,myrpt->name))
6854 l = myrpt->links.next;
6855 /* see if this is one in list */
6856 while(l != &myrpt->links)
6858 if (l->name[0] == '0')
6860 l = l->next;
6861 continue;
6863 /* dont send back from where it came */
6864 if ((l == mylink) || (!strcmp(l->name,mylink->name)))
6866 l = l->next;
6867 continue;
6869 /* if it is, send it and we're done */
6870 if (!strcmp(l->name,dest))
6872 /* send, but not to src */
6873 if (strcmp(l->name,src)) {
6874 wf.data.ptr = str;
6875 if (l->chan) ast_write(l->chan,&wf);
6877 return;
6879 l = l->next;
6881 l = myrpt->links.next;
6882 /* otherwise, send it to all of em */
6883 while(l != &myrpt->links)
6885 if (l->name[0] == '0')
6887 l = l->next;
6888 continue;
6890 /* dont send back from where it came */
6891 if ((l == mylink) || (!strcmp(l->name,mylink->name)))
6893 l = l->next;
6894 continue;
6896 /* send, but not to src */
6897 if (strcmp(l->name,src)) {
6898 wf.data.ptr = str;
6899 if (l->chan) ast_write(l->chan,&wf);
6901 l = l->next;
6903 return;
6905 if (myrpt->p.archivedir)
6907 char str[100];
6909 sprintf(str,"DTMF,%s,%c",mylink->name,c);
6910 donodelog(myrpt,str);
6912 c = func_xlat(myrpt,c,&myrpt->p.outxlat);
6913 if (!c) return;
6914 rpt_mutex_lock(&myrpt->lock);
6915 if (c == myrpt->p.endchar) myrpt->stopgen = 1;
6916 if (myrpt->callmode == 1)
6918 myrpt->exten[myrpt->cidx++] = c;
6919 myrpt->exten[myrpt->cidx] = 0;
6920 /* if this exists */
6921 if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
6923 /* if this really it, end now */
6924 if (!ast_matchmore_extension(myrpt->pchannel,myrpt->patchcontext,
6925 myrpt->exten,1,NULL))
6927 myrpt->callmode = 2;
6928 if(!myrpt->patchquiet)
6930 rpt_mutex_unlock(&myrpt->lock);
6931 rpt_telemetry(myrpt,PROC,NULL);
6932 rpt_mutex_lock(&myrpt->lock);
6935 else /* othewise, reset timer */
6937 myrpt->calldigittimer = 1;
6940 /* if can continue, do so */
6941 if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
6943 /* call has failed, inform user */
6944 myrpt->callmode = 4;
6947 if ((!myrpt->inpadtest) &&(c == myrpt->p.funcchar))
6949 myrpt->rem_dtmfidx = 0;
6950 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
6951 time(&myrpt->rem_dtmf_time);
6952 rpt_mutex_unlock(&myrpt->lock);
6953 return;
6955 else if (myrpt->rem_dtmfidx < 0)
6957 if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
6959 myrpt->mydtmf = c;
6961 if (myrpt->p.propagate_dtmf) do_dtmf_local(myrpt,c);
6962 if (myrpt->p.propagate_phonedtmf) do_dtmf_phone(myrpt,mylink,c);
6963 rpt_mutex_unlock(&myrpt->lock);
6964 return;
6966 else if (((myrpt->inpadtest) || (c != myrpt->p.endchar)) && (myrpt->rem_dtmfidx >= 0))
6968 time(&myrpt->rem_dtmf_time);
6969 if (myrpt->rem_dtmfidx < MAXDTMF)
6971 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
6972 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
6974 rpt_mutex_unlock(&myrpt->lock);
6975 strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
6976 res = collect_function_digits(myrpt, cmd, SOURCE_LNK, mylink);
6977 rpt_mutex_lock(&myrpt->lock);
6979 switch(res){
6981 case DC_INDETERMINATE:
6982 break;
6984 case DC_REQ_FLUSH:
6985 myrpt->rem_dtmfidx = 0;
6986 myrpt->rem_dtmfbuf[0] = 0;
6987 break;
6990 case DC_COMPLETE:
6991 case DC_COMPLETEQUIET:
6992 myrpt->totalexecdcommands++;
6993 myrpt->dailyexecdcommands++;
6994 strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
6995 myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
6996 myrpt->rem_dtmfbuf[0] = 0;
6997 myrpt->rem_dtmfidx = -1;
6998 myrpt->rem_dtmf_time = 0;
6999 break;
7001 case DC_ERROR:
7002 default:
7003 myrpt->rem_dtmfbuf[0] = 0;
7004 myrpt->rem_dtmfidx = -1;
7005 myrpt->rem_dtmf_time = 0;
7006 break;
7011 rpt_mutex_unlock(&myrpt->lock);
7012 return;
7015 static void handle_link_phone_dtmf(struct rpt *myrpt, struct rpt_link *mylink,
7016 char c)
7019 char cmd[300];
7020 int res;
7022 if (myrpt->p.archivedir)
7024 char str[100];
7026 sprintf(str,"DTMF(P),%s,%c",mylink->name,c);
7027 donodelog(myrpt,str);
7029 rpt_mutex_lock(&myrpt->lock);
7031 if (mylink->phonemode == 3) /*If in simplex dumb phone mode */
7033 if(c == myrpt->p.endchar) /* If end char */
7035 mylink->lastrealrx = 0; /* Keying state = off */
7036 rpt_mutex_unlock(&myrpt->lock);
7037 return;
7040 if(c == myrpt->p.funcchar) /* If lead-in char */
7042 mylink->lastrealrx = !mylink->lastrealrx; /* Toggle keying state */
7043 rpt_mutex_unlock(&myrpt->lock);
7044 return;
7047 else
7049 if (c == myrpt->p.endchar)
7051 if (mylink->lastrx)
7053 mylink->lastrealrx = 0;
7054 rpt_mutex_unlock(&myrpt->lock);
7055 return;
7057 myrpt->stopgen = 1;
7058 if (myrpt->cmdnode[0])
7060 myrpt->cmdnode[0] = 0;
7061 myrpt->dtmfidx = -1;
7062 myrpt->dtmfbuf[0] = 0;
7063 rpt_mutex_unlock(&myrpt->lock);
7064 rpt_telemetry(myrpt,COMPLETE,NULL);
7065 return;
7069 if (myrpt->cmdnode[0])
7071 rpt_mutex_unlock(&myrpt->lock);
7072 send_link_dtmf(myrpt,c);
7073 return;
7075 if (myrpt->callmode == 1)
7077 myrpt->exten[myrpt->cidx++] = c;
7078 myrpt->exten[myrpt->cidx] = 0;
7079 /* if this exists */
7080 if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
7082 /* if this really it, end now */
7083 if (!ast_matchmore_extension(myrpt->pchannel,myrpt->patchcontext,
7084 myrpt->exten,1,NULL))
7086 myrpt->callmode = 2;
7087 if(!myrpt->patchquiet)
7089 rpt_mutex_unlock(&myrpt->lock);
7090 rpt_telemetry(myrpt,PROC,NULL);
7091 rpt_mutex_lock(&myrpt->lock);
7094 else /* othewise, reset timer */
7096 myrpt->calldigittimer = 1;
7099 /* if can continue, do so */
7100 if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
7102 /* call has failed, inform user */
7103 myrpt->callmode = 4;
7106 if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
7108 myrpt->mydtmf = c;
7110 if ((!myrpt->inpadtest) && (c == myrpt->p.funcchar))
7112 myrpt->rem_dtmfidx = 0;
7113 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
7114 time(&myrpt->rem_dtmf_time);
7115 rpt_mutex_unlock(&myrpt->lock);
7116 return;
7118 else if (((myrpt->inpadtest) || (c != myrpt->p.endchar)) && (myrpt->rem_dtmfidx >= 0))
7120 time(&myrpt->rem_dtmf_time);
7121 if (myrpt->rem_dtmfidx < MAXDTMF)
7123 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
7124 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
7126 rpt_mutex_unlock(&myrpt->lock);
7127 strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
7128 switch(mylink->phonemode)
7130 case 1:
7131 res = collect_function_digits(myrpt, cmd,
7132 SOURCE_PHONE, mylink);
7133 break;
7134 case 2:
7135 res = collect_function_digits(myrpt, cmd,
7136 SOURCE_DPHONE,mylink);
7137 break;
7138 case 4:
7139 res = collect_function_digits(myrpt, cmd,
7140 SOURCE_ALT,mylink);
7141 break;
7142 default:
7143 res = collect_function_digits(myrpt, cmd,
7144 SOURCE_LNK, mylink);
7145 break;
7148 rpt_mutex_lock(&myrpt->lock);
7150 switch(res){
7152 case DC_INDETERMINATE:
7153 break;
7155 case DC_DOKEY:
7156 mylink->lastrealrx = 1;
7157 break;
7159 case DC_REQ_FLUSH:
7160 myrpt->rem_dtmfidx = 0;
7161 myrpt->rem_dtmfbuf[0] = 0;
7162 break;
7165 case DC_COMPLETE:
7166 case DC_COMPLETEQUIET:
7167 myrpt->totalexecdcommands++;
7168 myrpt->dailyexecdcommands++;
7169 strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
7170 myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
7171 myrpt->rem_dtmfbuf[0] = 0;
7172 myrpt->rem_dtmfidx = -1;
7173 myrpt->rem_dtmf_time = 0;
7174 break;
7176 case DC_ERROR:
7177 default:
7178 myrpt->rem_dtmfbuf[0] = 0;
7179 myrpt->rem_dtmfidx = -1;
7180 myrpt->rem_dtmf_time = 0;
7181 break;
7186 rpt_mutex_unlock(&myrpt->lock);
7187 return;
7190 /* Doug Hall RBI-1 serial data definitions:
7192 * Byte 0: Expansion external outputs
7193 * Byte 1:
7194 * Bits 0-3 are BAND as follows:
7195 * Bits 4-5 are POWER bits as follows:
7196 * 00 - Low Power
7197 * 01 - Hi Power
7198 * 02 - Med Power
7199 * Bits 6-7 are always set
7200 * Byte 2:
7201 * Bits 0-3 MHZ in BCD format
7202 * Bits 4-5 are offset as follows:
7203 * 00 - minus
7204 * 01 - plus
7205 * 02 - simplex
7206 * 03 - minus minus (whatever that is)
7207 * Bit 6 is the 0/5 KHZ bit
7208 * Bit 7 is always set
7209 * Byte 3:
7210 * Bits 0-3 are 10 KHZ in BCD format
7211 * Bits 4-7 are 100 KHZ in BCD format
7212 * Byte 4: PL Tone code and encode/decode enable bits
7213 * Bits 0-5 are PL tone code (comspec binary codes)
7214 * Bit 6 is encode enable/disable
7215 * Bit 7 is decode enable/disable
7218 /* take the frequency from the 10 mhz digits (and up) and convert it
7219 to a band number */
7221 static int rbi_mhztoband(char *str)
7223 int i;
7225 i = atoi(str) / 10; /* get the 10's of mhz */
7226 switch(i)
7228 case 2:
7229 return 10;
7230 case 5:
7231 return 11;
7232 case 14:
7233 return 2;
7234 case 22:
7235 return 3;
7236 case 44:
7237 return 4;
7238 case 124:
7239 return 0;
7240 case 125:
7241 return 1;
7242 case 126:
7243 return 8;
7244 case 127:
7245 return 5;
7246 case 128:
7247 return 6;
7248 case 129:
7249 return 7;
7250 default:
7251 break;
7253 return -1;
7256 /* take a PL frequency and turn it into a code */
7257 static int rbi_pltocode(char *str)
7259 int i;
7260 char *s;
7262 s = strchr(str,'.');
7263 i = 0;
7264 if (s) i = atoi(s + 1);
7265 i += atoi(str) * 10;
7266 switch(i)
7268 case 670:
7269 return 0;
7270 case 719:
7271 return 1;
7272 case 744:
7273 return 2;
7274 case 770:
7275 return 3;
7276 case 797:
7277 return 4;
7278 case 825:
7279 return 5;
7280 case 854:
7281 return 6;
7282 case 885:
7283 return 7;
7284 case 915:
7285 return 8;
7286 case 948:
7287 return 9;
7288 case 974:
7289 return 10;
7290 case 1000:
7291 return 11;
7292 case 1035:
7293 return 12;
7294 case 1072:
7295 return 13;
7296 case 1109:
7297 return 14;
7298 case 1148:
7299 return 15;
7300 case 1188:
7301 return 16;
7302 case 1230:
7303 return 17;
7304 case 1273:
7305 return 18;
7306 case 1318:
7307 return 19;
7308 case 1365:
7309 return 20;
7310 case 1413:
7311 return 21;
7312 case 1462:
7313 return 22;
7314 case 1514:
7315 return 23;
7316 case 1567:
7317 return 24;
7318 case 1622:
7319 return 25;
7320 case 1679:
7321 return 26;
7322 case 1738:
7323 return 27;
7324 case 1799:
7325 return 28;
7326 case 1862:
7327 return 29;
7328 case 1928:
7329 return 30;
7330 case 2035:
7331 return 31;
7332 case 2107:
7333 return 32;
7334 case 2181:
7335 return 33;
7336 case 2257:
7337 return 34;
7338 case 2336:
7339 return 35;
7340 case 2418:
7341 return 36;
7342 case 2503:
7343 return 37;
7345 return -1;
7349 * Shift out a formatted serial bit stream
7352 static void rbi_out_parallel(struct rpt *myrpt,unsigned char *data)
7354 #ifdef __i386__
7355 int i,j;
7356 unsigned char od,d;
7357 static volatile long long delayvar;
7359 for(i = 0 ; i < 5 ; i++){
7360 od = *data++;
7361 for(j = 0 ; j < 8 ; j++){
7362 d = od & 1;
7363 outb(d,myrpt->p.iobase);
7364 /* >= 15 us */
7365 for(delayvar = 1; delayvar < 15000; delayvar++);
7366 od >>= 1;
7367 outb(d | 2,myrpt->p.iobase);
7368 /* >= 30 us */
7369 for(delayvar = 1; delayvar < 30000; delayvar++);
7370 outb(d,myrpt->p.iobase);
7371 /* >= 10 us */
7372 for(delayvar = 1; delayvar < 10000; delayvar++);
7375 /* >= 50 us */
7376 for(delayvar = 1; delayvar < 50000; delayvar++);
7377 #endif
7380 static void rbi_out(struct rpt *myrpt,unsigned char *data)
7382 struct dahdi_radio_param r;
7384 memset(&r,0,sizeof(struct dahdi_radio_param));
7385 r.radpar = DAHDI_RADPAR_REMMODE;
7386 r.data = DAHDI_RADPAR_REM_RBI1;
7387 /* if setparam ioctl fails, its probably not a pciradio card */
7388 if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&r) == -1)
7390 rbi_out_parallel(myrpt,data);
7391 return;
7393 r.radpar = DAHDI_RADPAR_REMCOMMAND;
7394 memcpy(&r.data,data,5);
7395 if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&r) == -1)
7397 ast_log(LOG_WARNING,"Cannot send RBI command for channel %s\n",myrpt->dahdirxchannel->name);
7398 return;
7402 static int serial_remote_io(struct rpt *myrpt, unsigned char *txbuf, int txbytes,
7403 unsigned char *rxbuf, int rxmaxbytes, int asciiflag)
7405 int i,j,index,oldmode,olddata;
7406 struct dahdi_radio_param prm;
7407 char c;
7409 if(debug) {
7410 ast_log(LOG_NOTICE, "ioport=%s iofd=0x%x\n",myrpt->p.ioport,myrpt->iofd);
7411 printf("String output was:\n");
7412 for(i = 0; i < txbytes; i++)
7413 printf("%02X ", (unsigned char ) txbuf[i]);
7414 printf("\n");
7417 if (myrpt->iofd >= 0) /* if to do out a serial port */
7419 if (write(myrpt->iofd,txbuf,txbytes) != txbytes)
7421 return -1;
7423 if ((!rxmaxbytes) || (rxbuf == NULL))
7425 return(0);
7427 memset(rxbuf,0,rxmaxbytes);
7428 for(i = 0; i < rxmaxbytes; i++)
7430 j = read(myrpt->iofd,&c,1);
7431 if (j < 1)
7433 return(i);
7435 rxbuf[i] = c;
7436 if (asciiflag & 1)
7438 rxbuf[i + 1] = 0;
7439 if (c == '\r') break;
7442 if(debug) {
7443 printf("String returned was:\n");
7444 for(j = 0; j < i; j++)
7445 printf("%02X ", (unsigned char ) rxbuf[j]);
7446 printf("\n");
7448 return(i);
7451 /* if not a DAHDI channel, cant use pciradio stuff */
7452 if (myrpt->rxchannel != myrpt->dahdirxchannel) return -1;
7454 prm.radpar = DAHDI_RADPAR_UIOMODE;
7455 if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_GETPARAM,&prm) == -1) return -1;
7456 oldmode = prm.data;
7457 prm.radpar = DAHDI_RADPAR_UIODATA;
7458 if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_GETPARAM,&prm) == -1) return -1;
7459 olddata = prm.data;
7460 prm.radpar = DAHDI_RADPAR_REMMODE;
7461 if (asciiflag & 1) prm.data = DAHDI_RADPAR_REM_SERIAL_ASCII;
7462 else prm.data = DAHDI_RADPAR_REM_SERIAL;
7463 if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
7464 if (asciiflag & 2)
7466 i = DAHDI_ONHOOK;
7467 if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_HOOK,&i) == -1) return -1;
7468 usleep(100000);
7470 prm.radpar = DAHDI_RADPAR_REMCOMMAND;
7471 prm.data = rxmaxbytes;
7472 memcpy(prm.buf,txbuf,txbytes);
7473 prm.index = txbytes;
7474 if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
7475 if (rxbuf)
7477 *rxbuf = 0;
7478 memcpy(rxbuf,prm.buf,prm.index);
7480 index = prm.index;
7481 prm.radpar = DAHDI_RADPAR_REMMODE;
7482 prm.data = DAHDI_RADPAR_REM_NONE;
7483 if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
7484 if (asciiflag & 2)
7486 i = DAHDI_OFFHOOK;
7487 if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_HOOK,&i) == -1) return -1;
7489 prm.radpar = DAHDI_RADPAR_UIOMODE;
7490 prm.data = oldmode;
7491 if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
7492 prm.radpar = DAHDI_RADPAR_UIODATA;
7493 prm.data = olddata;
7494 if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
7495 return(index);
7498 static int civ_cmd(struct rpt *myrpt,unsigned char *cmd, int cmdlen)
7500 unsigned char rxbuf[100];
7501 int i,rv ;
7503 rv = serial_remote_io(myrpt,cmd,cmdlen,rxbuf,cmdlen + 6,0);
7504 if (rv == -1) return(-1);
7505 if (rv != (cmdlen + 6)) return(1);
7506 for(i = 0; i < 6; i++)
7507 if (rxbuf[i] != cmd[i]) return(1);
7508 if (rxbuf[cmdlen] != 0xfe) return(1);
7509 if (rxbuf[cmdlen + 1] != 0xfe) return(1);
7510 if (rxbuf[cmdlen + 4] != 0xfb) return(1);
7511 if (rxbuf[cmdlen + 5] != 0xfd) return(1);
7512 return(0);
7515 static int sendkenwood(struct rpt *myrpt,char *txstr, char *rxstr)
7517 int i;
7519 ast_log(LOG_NOTICE,"Sent to kenwood: %s\n",txstr);
7520 if (debug) printf("Send to kenwood: %s\n",txstr);
7521 i = serial_remote_io(myrpt, (unsigned char *)txstr, strlen(txstr),
7522 (unsigned char *)rxstr,RAD_SERIAL_BUFLEN - 1,3);
7523 if (i < 0) return -1;
7524 if ((i > 0) && (rxstr[i - 1] == '\r'))
7525 rxstr[i-- - 1] = 0;
7526 if (debug) printf("Got from kenwood: %s\n",rxstr);
7527 ast_log(LOG_NOTICE,"Got from kenwood: %s\n",rxstr);
7528 return(i);
7531 /* take a PL frequency and turn it into a code */
7532 static int kenwood_pltocode(char *str)
7534 int i;
7535 char *s;
7537 s = strchr(str,'.');
7538 i = 0;
7539 if (s) i = atoi(s + 1);
7540 i += atoi(str) * 10;
7541 switch(i)
7543 case 670:
7544 return 1;
7545 case 719:
7546 return 3;
7547 case 744:
7548 return 4;
7549 case 770:
7550 return 5;
7551 case 797:
7552 return 6;
7553 case 825:
7554 return 7;
7555 case 854:
7556 return 8;
7557 case 885:
7558 return 9;
7559 case 915:
7560 return 10;
7561 case 948:
7562 return 11;
7563 case 974:
7564 return 12;
7565 case 1000:
7566 return 13;
7567 case 1035:
7568 return 14;
7569 case 1072:
7570 return 15;
7571 case 1109:
7572 return 16;
7573 case 1148:
7574 return 17;
7575 case 1188:
7576 return 18;
7577 case 1230:
7578 return 19;
7579 case 1273:
7580 return 20;
7581 case 1318:
7582 return 21;
7583 case 1365:
7584 return 22;
7585 case 1413:
7586 return 23;
7587 case 1462:
7588 return 24;
7589 case 1514:
7590 return 25;
7591 case 1567:
7592 return 26;
7593 case 1622:
7594 return 27;
7595 case 1679:
7596 return 28;
7597 case 1738:
7598 return 29;
7599 case 1799:
7600 return 30;
7601 case 1862:
7602 return 31;
7603 case 1928:
7604 return 32;
7605 case 2035:
7606 return 33;
7607 case 2107:
7608 return 34;
7609 case 2181:
7610 return 35;
7611 case 2257:
7612 return 36;
7613 case 2336:
7614 return 37;
7615 case 2418:
7616 return 38;
7617 case 2503:
7618 return 39;
7620 return -1;
7623 static int sendrxkenwood(struct rpt *myrpt, char *txstr, char *rxstr,
7624 char *cmpstr)
7626 int i,j;
7628 for(i = 0;i < KENWOOD_RETRIES;i++)
7630 j = sendkenwood(myrpt,txstr,rxstr);
7631 if (j < 0) return(j);
7632 if (j == 0) continue;
7633 if (!strncmp(rxstr,cmpstr,strlen(cmpstr))) return(0);
7635 return(-1);
7638 static int setkenwood(struct rpt *myrpt)
7640 char rxstr[RAD_SERIAL_BUFLEN],txstr[RAD_SERIAL_BUFLEN],freq[20];
7641 char mhz[MAXREMSTR],offset[20],band,decimals[MAXREMSTR],band1,band2;
7642 int myrxpl;
7644 int offsets[] = {0,2,1};
7645 int powers[] = {2,1,0};
7647 if (sendrxkenwood(myrpt,"VMC 0,0\r",rxstr,"VMC") < 0) return -1;
7648 split_freq(mhz, decimals, myrpt->freq);
7649 if (atoi(mhz) > 400)
7651 band = '6';
7652 band1 = '1';
7653 band2 = '5';
7654 strcpy(offset,"005000000");
7656 else
7658 band = '2';
7659 band1 = '0';
7660 band2 = '2';
7661 strcpy(offset,"000600000");
7663 strcpy(freq,"000000");
7664 strncpy(freq,decimals,strlen(decimals));
7665 myrxpl = myrpt->rxplon;
7666 if (IS_XPMR(myrpt)) myrxpl = 0;
7667 sprintf(txstr,"VW %c,%05d%s,0,%d,0,%d,%d,,%02d,,%02d,%s\r",
7668 band,atoi(mhz),freq,offsets[(int)myrpt->offset],
7669 (myrpt->txplon != 0),myrxpl,
7670 kenwood_pltocode(myrpt->txpl),kenwood_pltocode(myrpt->rxpl),
7671 offset);
7672 if (sendrxkenwood(myrpt,txstr,rxstr,"VW") < 0) return -1;
7673 sprintf(txstr,"RBN %c\r",band2);
7674 if (sendrxkenwood(myrpt,txstr,rxstr,"RBN") < 0) return -1;
7675 sprintf(txstr,"PC %c,%d\r",band1,powers[(int)myrpt->powerlevel]);
7676 if (sendrxkenwood(myrpt,txstr,rxstr,"PC") < 0) return -1;
7677 return 0;
7680 static int set_tm271(struct rpt *myrpt)
7682 char rxstr[RAD_SERIAL_BUFLEN],txstr[RAD_SERIAL_BUFLEN],freq[20];
7683 char mhz[MAXREMSTR],decimals[MAXREMSTR];
7685 int offsets[] = {0,2,1};
7686 int powers[] = {2,1,0};
7688 split_freq(mhz, decimals, myrpt->freq);
7689 strcpy(freq,"000000");
7690 strncpy(freq,decimals,strlen(decimals));
7692 sprintf(txstr,"VF %04d%s,4,%d,0,%d,0,0,%d,%d,000,00600000,0,0\r",
7693 atoi(mhz),freq,offsets[(int)myrpt->offset],
7694 (myrpt->txplon != 0),kenwood_pltocode(myrpt->txpl),
7695 kenwood_pltocode(myrpt->rxpl));
7697 if (sendrxkenwood(myrpt,txstr,rxstr,"VF") < 0) return -1;
7698 if (sendrxkenwood(myrpt,"VM 0\r",rxstr,"VM") < 0) return -1;
7699 sprintf(txstr,"PC %d\r",powers[(int)myrpt->powerlevel]);
7700 if (sendrxkenwood(myrpt,txstr,rxstr,"PC") < 0) return -1;
7701 return 0;
7704 static int setrbi(struct rpt *myrpt)
7706 char tmp[MAXREMSTR] = "",*s;
7707 unsigned char rbicmd[5];
7708 int band,txoffset = 0,txpower = 0,rxpl;
7710 /* must be a remote system */
7711 if (!myrpt->remoterig) return(0);
7712 if (!myrpt->remoterig[0]) return(0);
7713 /* must have rbi hardware */
7714 if (strncmp(myrpt->remoterig,remote_rig_rbi,3)) return(0);
7715 if (setrbi_check(myrpt) == -1) return(-1);
7716 strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
7717 s = strchr(tmp,'.');
7718 /* if no decimal, is invalid */
7720 if (s == NULL){
7721 if(debug)
7722 printf("@@@@ Frequency needs a decimal\n");
7723 return -1;
7726 *s++ = 0;
7727 if (strlen(tmp) < 2){
7728 if(debug)
7729 printf("@@@@ Bad MHz digits: %s\n", tmp);
7730 return -1;
7733 if (strlen(s) < 3){
7734 if(debug)
7735 printf("@@@@ Bad KHz digits: %s\n", s);
7736 return -1;
7739 if ((s[2] != '0') && (s[2] != '5')){
7740 if(debug)
7741 printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
7742 return -1;
7745 band = rbi_mhztoband(tmp);
7746 if (band == -1){
7747 if(debug)
7748 printf("@@@@ Bad Band: %s\n", tmp);
7749 return -1;
7752 rxpl = rbi_pltocode(myrpt->rxpl);
7754 if (rxpl == -1){
7755 if(debug)
7756 printf("@@@@ Bad TX PL: %s\n", myrpt->rxpl);
7757 return -1;
7761 switch(myrpt->offset)
7763 case REM_MINUS:
7764 txoffset = 0;
7765 break;
7766 case REM_PLUS:
7767 txoffset = 0x10;
7768 break;
7769 case REM_SIMPLEX:
7770 txoffset = 0x20;
7771 break;
7773 switch(myrpt->powerlevel)
7775 case REM_LOWPWR:
7776 txpower = 0;
7777 break;
7778 case REM_MEDPWR:
7779 txpower = 0x20;
7780 break;
7781 case REM_HIPWR:
7782 txpower = 0x10;
7783 break;
7785 rbicmd[0] = 0;
7786 rbicmd[1] = band | txpower | 0xc0;
7787 rbicmd[2] = (*(s - 2) - '0') | txoffset | 0x80;
7788 if (s[2] == '5') rbicmd[2] |= 0x40;
7789 rbicmd[3] = ((*s - '0') << 4) + (s[1] - '0');
7790 rbicmd[4] = rxpl;
7791 if (myrpt->txplon) rbicmd[4] |= 0x40;
7792 if (myrpt->rxplon) rbicmd[4] |= 0x80;
7793 rbi_out(myrpt,rbicmd);
7794 return 0;
7797 static int setrtx(struct rpt *myrpt)
7799 char tmp[MAXREMSTR] = "",*s,rigstr[200],pwr,res = 0;
7800 int band,txoffset = 0,txpower = 0,rxpl,txpl;
7801 float ofac;
7802 double txfreq;
7804 /* must be a remote system */
7805 if (!myrpt->remoterig) return(0);
7806 if (!myrpt->remoterig[0]) return(0);
7807 /* must have rtx hardware */
7808 if (!ISRIG_RTX(myrpt->remoterig)) return(0);
7809 /* must be a usbradio interface type */
7810 if (!IS_XPMR(myrpt)) return(0);
7811 strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
7812 s = strchr(tmp,'.');
7813 /* if no decimal, is invalid */
7815 if(debug)printf("setrtx() %s %s\n",myrpt->name,myrpt->remoterig);
7817 if (s == NULL){
7818 if(debug)
7819 printf("@@@@ Frequency needs a decimal\n");
7820 return -1;
7822 *s++ = 0;
7823 if (strlen(tmp) < 2){
7824 if(debug)
7825 printf("@@@@ Bad MHz digits: %s\n", tmp);
7826 return -1;
7829 if (strlen(s) < 3){
7830 if(debug)
7831 printf("@@@@ Bad KHz digits: %s\n", s);
7832 return -1;
7835 if ((s[2] != '0') && (s[2] != '5')){
7836 if(debug)
7837 printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
7838 return -1;
7841 band = rbi_mhztoband(tmp);
7842 if (band == -1){
7843 if(debug)
7844 printf("@@@@ Bad Band: %s\n", tmp);
7845 return -1;
7848 rxpl = rbi_pltocode(myrpt->rxpl);
7850 if (rxpl == -1){
7851 if(debug)
7852 printf("@@@@ Bad RX PL: %s\n", myrpt->rxpl);
7853 return -1;
7856 txpl = rbi_pltocode(myrpt->txpl);
7858 if (txpl == -1){
7859 if(debug)
7860 printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
7861 return -1;
7864 switch(myrpt->offset)
7866 case REM_MINUS:
7867 txoffset = 0;
7868 break;
7869 case REM_PLUS:
7870 txoffset = 0x10;
7871 break;
7872 case REM_SIMPLEX:
7873 txoffset = 0x20;
7874 break;
7876 switch(myrpt->powerlevel)
7878 case REM_LOWPWR:
7879 txpower = 0;
7880 break;
7881 case REM_MEDPWR:
7882 txpower = 0x20;
7883 break;
7884 case REM_HIPWR:
7885 txpower = 0x10;
7886 break;
7889 res = setrtx_check(myrpt);
7890 if (res < 0) return res;
7891 ofac = 0.0;
7892 if (myrpt->offset == REM_MINUS) ofac = -1.0;
7893 if (myrpt->offset == REM_PLUS) ofac = 1.0;
7895 if (!strcmp(myrpt->remoterig,remote_rig_rtx450))
7896 txfreq = atof(myrpt->freq) + (ofac * 5.0);
7897 else
7898 txfreq = atof(myrpt->freq) + (ofac * 0.6);
7900 pwr = 'L';
7901 if (myrpt->powerlevel == REM_HIPWR) pwr = 'H';
7902 if (!res)
7904 sprintf(rigstr,"SETFREQ %s %f %s %s %c",myrpt->freq,txfreq,
7905 (myrpt->rxplon) ? myrpt->rxpl : "0.0",
7906 (myrpt->txplon) ? myrpt->txpl : "0.0",pwr);
7907 send_usb_txt(myrpt,rigstr);
7908 rpt_telemetry(myrpt,COMPLETE,NULL);
7909 res = 0;
7911 return 0;
7913 #if 0
7915 sets current signaling code for xpmr routines
7916 under development for new radios.
7918 static int setxpmr(struct rpt *myrpt)
7920 char rigstr[200];
7921 int rxpl,txpl;
7923 /* must be a remote system */
7924 if (!myrpt->remoterig) return(0);
7925 if (!myrpt->remoterig[0]) return(0);
7926 /* must not have rtx hardware */
7927 if (ISRIG_RTX(myrpt->remoterig)) return(0);
7928 /* must be a usbradio interface type */
7929 if (!IS_XPMR(myrpt)) return(0);
7931 if(debug)printf("setxpmr() %s %s\n",myrpt->name,myrpt->remoterig );
7933 rxpl = rbi_pltocode(myrpt->rxpl);
7935 if (rxpl == -1){
7936 if(debug)
7937 printf("@@@@ Bad RX PL: %s\n", myrpt->rxpl);
7938 return -1;
7941 txpl = rbi_pltocode(myrpt->txpl);
7942 if (txpl == -1){
7943 if(debug)
7944 printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
7945 return -1;
7947 sprintf(rigstr,"SETFREQ 0.0 0.0 %s %s L",
7948 (myrpt->rxplon) ? myrpt->rxpl : "0.0",
7949 (myrpt->txplon) ? myrpt->txpl : "0.0");
7950 send_usb_txt(myrpt,rigstr);
7951 return 0;
7953 #endif
7955 static int setrbi_check(struct rpt *myrpt)
7957 char tmp[MAXREMSTR] = "",*s;
7958 int band,txpl;
7960 /* must be a remote system */
7961 if (!myrpt->remote) return(0);
7962 /* must have rbi hardware */
7963 if (strncmp(myrpt->remoterig,remote_rig_rbi,3)) return(0);
7964 strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
7965 s = strchr(tmp,'.');
7966 /* if no decimal, is invalid */
7968 if (s == NULL){
7969 if(debug)
7970 printf("@@@@ Frequency needs a decimal\n");
7971 return -1;
7974 *s++ = 0;
7975 if (strlen(tmp) < 2){
7976 if(debug)
7977 printf("@@@@ Bad MHz digits: %s\n", tmp);
7978 return -1;
7981 if (strlen(s) < 3){
7982 if(debug)
7983 printf("@@@@ Bad KHz digits: %s\n", s);
7984 return -1;
7987 if ((s[2] != '0') && (s[2] != '5')){
7988 if(debug)
7989 printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
7990 return -1;
7993 band = rbi_mhztoband(tmp);
7994 if (band == -1){
7995 if(debug)
7996 printf("@@@@ Bad Band: %s\n", tmp);
7997 return -1;
8000 txpl = rbi_pltocode(myrpt->txpl);
8002 if (txpl == -1){
8003 if(debug)
8004 printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
8005 return -1;
8007 return 0;
8010 static int setrtx_check(struct rpt *myrpt)
8012 char tmp[MAXREMSTR] = "",*s;
8013 int band,txpl,rxpl;
8015 /* must be a remote system */
8016 if (!myrpt->remote) return(0);
8017 /* must have rbi hardware */
8018 if (strncmp(myrpt->remoterig,remote_rig_rbi,3)) return(0);
8019 strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
8020 s = strchr(tmp,'.');
8021 /* if no decimal, is invalid */
8023 if (s == NULL){
8024 if(debug)
8025 printf("@@@@ Frequency needs a decimal\n");
8026 return -1;
8029 *s++ = 0;
8030 if (strlen(tmp) < 2){
8031 if(debug)
8032 printf("@@@@ Bad MHz digits: %s\n", tmp);
8033 return -1;
8036 if (strlen(s) < 3){
8037 if(debug)
8038 printf("@@@@ Bad KHz digits: %s\n", s);
8039 return -1;
8042 if ((s[2] != '0') && (s[2] != '5')){
8043 if(debug)
8044 printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
8045 return -1;
8048 band = rbi_mhztoband(tmp);
8049 if (band == -1){
8050 if(debug)
8051 printf("@@@@ Bad Band: %s\n", tmp);
8052 return -1;
8055 txpl = rbi_pltocode(myrpt->txpl);
8057 if (txpl == -1){
8058 if(debug)
8059 printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
8060 return -1;
8063 rxpl = rbi_pltocode(myrpt->rxpl);
8065 if (rxpl == -1){
8066 if(debug)
8067 printf("@@@@ Bad RX PL: %s\n", myrpt->rxpl);
8068 return -1;
8070 return 0;
8073 static int check_freq_kenwood(int m, int d, int *defmode)
8075 int dflmd = REM_MODE_FM;
8077 if (m == 144){ /* 2 meters */
8078 if(d < 10100)
8079 return -1;
8081 else if((m >= 145) && (m < 148)){
8084 else if((m >= 430) && (m < 450)){ /* 70 centimeters */
8087 else
8088 return -1;
8090 if(defmode)
8091 *defmode = dflmd;
8094 return 0;
8098 static int check_freq_tm271(int m, int d, int *defmode)
8100 int dflmd = REM_MODE_FM;
8102 if (m == 144){ /* 2 meters */
8103 if(d < 10100)
8104 return -1;
8106 else if((m >= 145) && (m < 148)){
8109 return -1;
8111 if(defmode)
8112 *defmode = dflmd;
8115 return 0;
8119 /* Check for valid rbi frequency */
8120 /* Hard coded limits now, configurable later, maybe? */
8122 static int check_freq_rbi(int m, int d, int *defmode)
8124 int dflmd = REM_MODE_FM;
8126 if(m == 50){ /* 6 meters */
8127 if(d < 10100)
8128 return -1;
8130 else if((m >= 51) && ( m < 54)){
8133 else if(m == 144){ /* 2 meters */
8134 if(d < 10100)
8135 return -1;
8137 else if((m >= 145) && (m < 148)){
8140 else if((m >= 222) && (m < 225)){ /* 1.25 meters */
8143 else if((m >= 430) && (m < 450)){ /* 70 centimeters */
8146 else if((m >= 1240) && (m < 1300)){ /* 23 centimeters */
8149 else
8150 return -1;
8152 if(defmode)
8153 *defmode = dflmd;
8156 return 0;
8159 /* Check for valid rtx frequency */
8160 /* Hard coded limits now, configurable later, maybe? */
8162 static int check_freq_rtx(int m, int d, int *defmode, struct rpt *myrpt)
8164 int dflmd = REM_MODE_FM;
8166 if (!strcmp(myrpt->remoterig,remote_rig_rtx150))
8169 if(m == 144){ /* 2 meters */
8170 if(d < 10100)
8171 return -1;
8173 else if((m >= 145) && (m < 148)){
8176 else
8177 return -1;
8179 else
8181 if((m >= 430) && (m < 450)){ /* 70 centimeters */
8184 else
8185 return -1;
8187 if(defmode)
8188 *defmode = dflmd;
8191 return 0;
8195 * Convert decimals of frequency to int
8198 static int decimals2int(char *fraction)
8200 int i;
8201 char len = strlen(fraction);
8202 int multiplier = 100000;
8203 int res = 0;
8205 if(!len)
8206 return 0;
8207 for( i = 0 ; i < len ; i++, multiplier /= 10)
8208 res += (fraction[i] - '0') * multiplier;
8209 return res;
8214 * Split frequency into mhz and decimals
8217 static int split_freq(char *mhz, char *decimals, char *freq)
8219 char freq_copy[MAXREMSTR];
8220 char *decp;
8222 decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
8223 if(decp){
8224 *decp++ = 0;
8225 strncpy(mhz, freq_copy, MAXREMSTR);
8226 strcpy(decimals, "00000");
8227 strncpy(decimals, decp, strlen(decp));
8228 decimals[5] = 0;
8229 return 0;
8231 else
8232 return -1;
8237 * Split ctcss frequency into hertz and decimal
8240 static int split_ctcss_freq(char *hertz, char *decimal, char *freq)
8242 char freq_copy[MAXREMSTR];
8243 char *decp;
8245 decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
8246 if(decp){
8247 *decp++ = 0;
8248 strncpy(hertz, freq_copy, MAXREMSTR);
8249 strncpy(decimal, decp, strlen(decp));
8250 decimal[strlen(decp)] = '\0';
8251 return 0;
8253 else
8254 return -1;
8260 * FT-897 I/O handlers
8263 /* Check to see that the frequency is valid */
8264 /* Hard coded limits now, configurable later, maybe? */
8267 static int check_freq_ft897(int m, int d, int *defmode)
8269 int dflmd = REM_MODE_FM;
8271 if(m == 1){ /* 160 meters */
8272 dflmd = REM_MODE_LSB;
8273 if(d < 80000)
8274 return -1;
8276 else if(m == 3){ /* 80 meters */
8277 dflmd = REM_MODE_LSB;
8278 if(d < 50000)
8279 return -1;
8281 else if(m == 7){ /* 40 meters */
8282 dflmd = REM_MODE_LSB;
8283 if(d > 30000)
8284 return -1;
8286 else if(m == 14){ /* 20 meters */
8287 dflmd = REM_MODE_USB;
8288 if(d > 35000)
8289 return -1;
8291 else if(m == 18){ /* 17 meters */
8292 dflmd = REM_MODE_USB;
8293 if((d < 6800) || (d > 16800))
8294 return -1;
8296 else if(m == 21){ /* 15 meters */
8297 dflmd = REM_MODE_USB;
8298 if((d < 20000) || (d > 45000))
8299 return -1;
8301 else if(m == 24){ /* 12 meters */
8302 dflmd = REM_MODE_USB;
8303 if((d < 89000) || (d > 99000))
8304 return -1;
8306 else if(m == 28){ /* 10 meters */
8307 dflmd = REM_MODE_USB;
8309 else if(m == 29){
8310 if(d >= 51000)
8311 dflmd = REM_MODE_FM;
8312 else
8313 dflmd = REM_MODE_USB;
8314 if(d > 70000)
8315 return -1;
8317 else if(m == 50){ /* 6 meters */
8318 if(d >= 30000)
8319 dflmd = REM_MODE_FM;
8320 else
8321 dflmd = REM_MODE_USB;
8324 else if((m >= 51) && ( m < 54)){
8325 dflmd = REM_MODE_FM;
8327 else if(m == 144){ /* 2 meters */
8328 if(d >= 30000)
8329 dflmd = REM_MODE_FM;
8330 else
8331 dflmd = REM_MODE_USB;
8333 else if((m >= 145) && (m < 148)){
8334 dflmd = REM_MODE_FM;
8336 else if((m >= 430) && (m < 450)){ /* 70 centimeters */
8337 if(m < 438)
8338 dflmd = REM_MODE_USB;
8339 else
8340 dflmd = REM_MODE_FM;
8343 else
8344 return -1;
8346 if(defmode)
8347 *defmode = dflmd;
8349 return 0;
8353 * Set a new frequency for the FT897
8356 static int set_freq_ft897(struct rpt *myrpt, char *newfreq)
8358 unsigned char cmdstr[5];
8359 int fd,m,d;
8360 char mhz[MAXREMSTR];
8361 char decimals[MAXREMSTR];
8363 fd = 0;
8364 if(debug)
8365 printf("New frequency: %s\n",newfreq);
8367 if(split_freq(mhz, decimals, newfreq))
8368 return -1;
8370 m = atoi(mhz);
8371 d = atoi(decimals);
8373 /* The FT-897 likes packed BCD frequencies */
8375 cmdstr[0] = ((m / 100) << 4) + ((m % 100)/10); /* 100MHz 10Mhz */
8376 cmdstr[1] = ((m % 10) << 4) + (d / 10000); /* 1MHz 100KHz */
8377 cmdstr[2] = (((d % 10000)/1000) << 4) + ((d % 1000)/ 100); /* 10KHz 1KHz */
8378 cmdstr[3] = (((d % 100)/10) << 4) + (d % 10); /* 100Hz 10Hz */
8379 cmdstr[4] = 0x01; /* command */
8381 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
8385 /* ft-897 simple commands */
8387 static int simple_command_ft897(struct rpt *myrpt, char command)
8389 unsigned char cmdstr[5];
8391 memset(cmdstr, 0, 5);
8393 cmdstr[4] = command;
8395 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
8399 /* ft-897 offset */
8401 static int set_offset_ft897(struct rpt *myrpt, char offset)
8403 unsigned char cmdstr[5];
8405 memset(cmdstr, 0, 5);
8407 switch(offset){
8408 case REM_SIMPLEX:
8409 cmdstr[0] = 0x89;
8410 break;
8412 case REM_MINUS:
8413 cmdstr[0] = 0x09;
8414 break;
8416 case REM_PLUS:
8417 cmdstr[0] = 0x49;
8418 break;
8420 default:
8421 return -1;
8424 cmdstr[4] = 0x09;
8426 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
8429 /* ft-897 mode */
8431 static int set_mode_ft897(struct rpt *myrpt, char newmode)
8433 unsigned char cmdstr[5];
8435 memset(cmdstr, 0, 5);
8437 switch(newmode){
8438 case REM_MODE_FM:
8439 cmdstr[0] = 0x08;
8440 break;
8442 case REM_MODE_USB:
8443 cmdstr[0] = 0x01;
8444 break;
8446 case REM_MODE_LSB:
8447 cmdstr[0] = 0x00;
8448 break;
8450 case REM_MODE_AM:
8451 cmdstr[0] = 0x04;
8452 break;
8454 default:
8455 return -1;
8457 cmdstr[4] = 0x07;
8459 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
8462 /* Set tone encode and decode modes */
8464 static int set_ctcss_mode_ft897(struct rpt *myrpt, char txplon, char rxplon)
8466 unsigned char cmdstr[5];
8468 memset(cmdstr, 0, 5);
8470 if(rxplon && txplon)
8471 cmdstr[0] = 0x2A; /* Encode and Decode */
8472 else if (!rxplon && txplon)
8473 cmdstr[0] = 0x4A; /* Encode only */
8474 else if (rxplon && !txplon)
8475 cmdstr[0] = 0x3A; /* Encode only */
8476 else
8477 cmdstr[0] = 0x8A; /* OFF */
8479 cmdstr[4] = 0x0A;
8481 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
8485 /* Set transmit and receive ctcss tone frequencies */
8487 static int set_ctcss_freq_ft897(struct rpt *myrpt, char *txtone, char *rxtone)
8489 unsigned char cmdstr[5];
8490 char hertz[MAXREMSTR],decimal[MAXREMSTR];
8491 int h,d;
8493 memset(cmdstr, 0, 5);
8495 if(split_ctcss_freq(hertz, decimal, txtone))
8496 return -1;
8498 h = atoi(hertz);
8499 d = atoi(decimal);
8501 cmdstr[0] = ((h / 100) << 4) + (h % 100)/ 10;
8502 cmdstr[1] = ((h % 10) << 4) + (d % 10);
8504 if(rxtone){
8506 if(split_ctcss_freq(hertz, decimal, rxtone))
8507 return -1;
8509 h = atoi(hertz);
8510 d = atoi(decimal);
8512 cmdstr[2] = ((h / 100) << 4) + (h % 100)/ 10;
8513 cmdstr[3] = ((h % 10) << 4) + (d % 10);
8515 cmdstr[4] = 0x0B;
8517 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
8522 static int set_ft897(struct rpt *myrpt)
8524 int res;
8526 if(debug)
8527 printf("@@@@ lock on\n");
8529 res = simple_command_ft897(myrpt, 0x00); /* LOCK on */
8531 if(debug)
8532 printf("@@@@ ptt off\n");
8534 if(!res)
8535 res = simple_command_ft897(myrpt, 0x88); /* PTT off */
8537 if(debug)
8538 printf("Modulation mode\n");
8540 if(!res)
8541 res = set_mode_ft897(myrpt, myrpt->remmode); /* Modulation mode */
8543 if(debug)
8544 printf("Split off\n");
8546 if(!res)
8547 simple_command_ft897(myrpt, 0x82); /* Split off */
8549 if(debug)
8550 printf("Frequency\n");
8552 if(!res)
8553 res = set_freq_ft897(myrpt, myrpt->freq); /* Frequency */
8554 if((myrpt->remmode == REM_MODE_FM)){
8555 if(debug)
8556 printf("Offset\n");
8557 if(!res)
8558 res = set_offset_ft897(myrpt, myrpt->offset); /* Offset if FM */
8559 if((!res)&&(myrpt->rxplon || myrpt->txplon)){
8560 if(debug)
8561 printf("CTCSS tone freqs.\n");
8562 res = set_ctcss_freq_ft897(myrpt, myrpt->txpl, myrpt->rxpl); /* CTCSS freqs if CTCSS is enabled */
8564 if(!res){
8565 if(debug)
8566 printf("CTCSS mode\n");
8567 res = set_ctcss_mode_ft897(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */
8570 if((myrpt->remmode == REM_MODE_USB)||(myrpt->remmode == REM_MODE_LSB)){
8571 if(debug)
8572 printf("Clarifier off\n");
8573 simple_command_ft897(myrpt, 0x85); /* Clarifier off if LSB or USB */
8575 return res;
8578 static int closerem_ft897(struct rpt *myrpt)
8580 simple_command_ft897(myrpt, 0x88); /* PTT off */
8581 return 0;
8585 * Bump frequency up or down by a small amount
8586 * Return 0 if the new frequnecy is valid, or -1 if invalid
8587 * Interval is in Hz, resolution is 10Hz
8590 static int multimode_bump_freq_ft897(struct rpt *myrpt, int interval)
8592 int m,d;
8593 char mhz[MAXREMSTR], decimals[MAXREMSTR];
8595 if(debug)
8596 printf("Before bump: %s\n", myrpt->freq);
8598 if(split_freq(mhz, decimals, myrpt->freq))
8599 return -1;
8601 m = atoi(mhz);
8602 d = atoi(decimals);
8604 d += (interval / 10); /* 10Hz resolution */
8605 if(d < 0){
8606 m--;
8607 d += 100000;
8609 else if(d >= 100000){
8610 m++;
8611 d -= 100000;
8614 if(check_freq_ft897(m, d, NULL)){
8615 if(debug)
8616 printf("Bump freq invalid\n");
8617 return -1;
8620 snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d);
8622 if(debug)
8623 printf("After bump: %s\n", myrpt->freq);
8625 return set_freq_ft897(myrpt, myrpt->freq);
8631 * IC-706 I/O handlers
8634 /* Check to see that the frequency is valid */
8635 /* returns 0 if frequency is valid */
8637 static int check_freq_ic706(int m, int d, int *defmode, char mars)
8639 int dflmd = REM_MODE_FM;
8640 int rv=0;
8642 if(debug > 6)
8643 ast_log(LOG_NOTICE,"(%i,%i,%i,%i)\n",m,d,*defmode,mars);
8645 /* first test for standard amateur radio bands */
8647 if(m == 1){ /* 160 meters */
8648 dflmd = REM_MODE_LSB;
8649 if(d < 80000)rv=-1;
8651 else if(m == 3){ /* 80 meters */
8652 dflmd = REM_MODE_LSB;
8653 if(d < 50000)rv=-1;
8655 else if(m == 7){ /* 40 meters */
8656 dflmd = REM_MODE_LSB;
8657 if(d > 30000)rv=-1;
8659 else if(m == 14){ /* 20 meters */
8660 dflmd = REM_MODE_USB;
8661 if(d > 35000)rv=-1;
8663 else if(m == 18){ /* 17 meters */
8664 dflmd = REM_MODE_USB;
8665 if((d < 6800) || (d > 16800))rv=-1;
8667 else if(m == 21){ /* 15 meters */
8668 dflmd = REM_MODE_USB;
8669 if((d < 20000) || (d > 45000))rv=-1;
8671 else if(m == 24){ /* 12 meters */
8672 dflmd = REM_MODE_USB;
8673 if((d < 89000) || (d > 99000))rv=-1;
8675 else if(m == 28){ /* 10 meters */
8676 dflmd = REM_MODE_USB;
8678 else if(m == 29){
8679 if(d >= 51000)
8680 dflmd = REM_MODE_FM;
8681 else
8682 dflmd = REM_MODE_USB;
8683 if(d > 70000)rv=-1;
8685 else if(m == 50){ /* 6 meters */
8686 if(d >= 30000)
8687 dflmd = REM_MODE_FM;
8688 else
8689 dflmd = REM_MODE_USB;
8691 else if((m >= 51) && ( m < 54)){
8692 dflmd = REM_MODE_FM;
8694 else if(m == 144){ /* 2 meters */
8695 if(d >= 30000)
8696 dflmd = REM_MODE_FM;
8697 else
8698 dflmd = REM_MODE_USB;
8700 else if((m >= 145) && (m < 148)){
8701 dflmd = REM_MODE_FM;
8703 else if((m >= 430) && (m < 450)){ /* 70 centimeters */
8704 if(m < 438)
8705 dflmd = REM_MODE_USB;
8706 else
8707 dflmd = REM_MODE_FM;
8710 /* check expanded coverage */
8711 if(mars && rv<0){
8712 if((m >= 450) && (m < 470)){ /* LMR */
8713 dflmd = REM_MODE_FM;
8714 rv=0;
8716 else if((m >= 148) && (m < 174)){ /* LMR */
8717 dflmd = REM_MODE_FM;
8718 rv=0;
8720 else if((m >= 138) && (m < 144)){ /* VHF-AM AIRCRAFT */
8721 dflmd = REM_MODE_AM;
8722 rv=0;
8724 else if((m >= 108) && (m < 138)){ /* VHF-AM AIRCRAFT */
8725 dflmd = REM_MODE_AM;
8726 rv=0;
8728 else if( (m==0 && d>=55000) || (m==1 && d<=75000) ){ /* AM BCB*/
8729 dflmd = REM_MODE_AM;
8730 rv=0;
8732 else if( (m == 1 && d>75000) || (m>1 && m<30) ){ /* HF SWL*/
8733 dflmd = REM_MODE_AM;
8734 rv=0;
8738 if(defmode)
8739 *defmode = dflmd;
8741 if(debug > 1)
8742 ast_log(LOG_NOTICE,"(%i,%i,%i,%i) returning %i\n",m,d,*defmode,mars,rv);
8744 return rv;
8747 /* take a PL frequency and turn it into a code */
8748 static int ic706_pltocode(char *str)
8750 int i;
8751 char *s;
8752 int rv=-1;
8754 s = strchr(str,'.');
8755 i = 0;
8756 if (s) i = atoi(s + 1);
8757 i += atoi(str) * 10;
8758 switch(i)
8760 case 670:
8761 rv=0;
8762 case 693:
8763 rv=1;
8764 case 719:
8765 rv=2;
8766 case 744:
8767 rv=3;
8768 case 770:
8769 rv=4;
8770 case 797:
8771 rv=5;
8772 case 825:
8773 rv=6;
8774 case 854:
8775 rv=7;
8776 case 885:
8777 rv=8;
8778 case 915:
8779 rv=9;
8780 case 948:
8781 rv=10;
8782 case 974:
8783 rv=11;
8784 case 1000:
8785 rv=12;
8786 case 1035:
8787 rv=13;
8788 case 1072:
8789 rv=14;
8790 case 1109:
8791 rv=15;
8792 case 1148:
8793 rv=16;
8794 case 1188:
8795 rv=17;
8796 case 1230:
8797 rv=18;
8798 case 1273:
8799 rv=19;
8800 case 1318:
8801 rv=20;
8802 case 1365:
8803 rv=21;
8804 case 1413:
8805 rv=22;
8806 case 1462:
8807 rv=23;
8808 case 1514:
8809 rv=24;
8810 case 1567:
8811 rv=25;
8812 case 1598:
8813 rv=26;
8814 case 1622:
8815 rv=27;
8816 case 1655:
8817 rv=28;
8818 case 1679:
8819 rv=29;
8820 case 1713:
8821 rv=30;
8822 case 1738:
8823 rv=31;
8824 case 1773:
8825 rv=32;
8826 case 1799:
8827 rv=33;
8828 case 1835:
8829 rv=34;
8830 case 1862:
8831 rv=35;
8832 case 1899:
8833 rv=36;
8834 case 1928:
8835 rv=37;
8836 case 1966:
8837 rv=38;
8838 case 1995:
8839 rv=39;
8840 case 2035:
8841 rv=40;
8842 case 2065:
8843 rv=41;
8844 case 2107:
8845 rv=42;
8846 case 2181:
8847 rv=43;
8848 case 2257:
8849 rv=44;
8850 case 2291:
8851 rv=45;
8852 case 2336:
8853 rv=46;
8854 case 2418:
8855 rv=47;
8856 case 2503:
8857 rv=48;
8858 case 2541:
8859 rv=49;
8861 if(debug > 1)
8862 ast_log(LOG_NOTICE,"%i rv=%i\n",i, rv);
8864 return rv;
8867 /* ic-706 simple commands */
8869 static int simple_command_ic706(struct rpt *myrpt, char command, char subcommand)
8871 unsigned char cmdstr[10];
8873 cmdstr[0] = cmdstr[1] = 0xfe;
8874 cmdstr[2] = myrpt->p.civaddr;
8875 cmdstr[3] = 0xe0;
8876 cmdstr[4] = command;
8877 cmdstr[5] = subcommand;
8878 cmdstr[6] = 0xfd;
8880 return(civ_cmd(myrpt,cmdstr,7));
8884 * Set a new frequency for the ic706
8887 static int set_freq_ic706(struct rpt *myrpt, char *newfreq)
8889 unsigned char cmdstr[20];
8890 char mhz[MAXREMSTR], decimals[MAXREMSTR];
8891 int fd,m,d;
8893 fd = 0;
8894 if(debug)
8895 ast_log(LOG_NOTICE,"newfreq:%s\n",newfreq);
8897 if(split_freq(mhz, decimals, newfreq))
8898 return -1;
8900 m = atoi(mhz);
8901 d = atoi(decimals);
8903 /* The ic-706 likes packed BCD frequencies */
8905 cmdstr[0] = cmdstr[1] = 0xfe;
8906 cmdstr[2] = myrpt->p.civaddr;
8907 cmdstr[3] = 0xe0;
8908 cmdstr[4] = 5;
8909 cmdstr[5] = ((d % 10) << 4);
8910 cmdstr[6] = (((d % 1000)/ 100) << 4) + ((d % 100)/10);
8911 cmdstr[7] = ((d / 10000) << 4) + ((d % 10000)/1000);
8912 cmdstr[8] = (((m % 100)/10) << 4) + (m % 10);
8913 cmdstr[9] = (m / 100);
8914 cmdstr[10] = 0xfd;
8916 return(civ_cmd(myrpt,cmdstr,11));
8919 /* ic-706 offset */
8921 static int set_offset_ic706(struct rpt *myrpt, char offset)
8923 unsigned char c;
8925 if(debug > 6)
8926 ast_log(LOG_NOTICE,"offset=%i\n",offset);
8928 switch(offset){
8929 case REM_SIMPLEX:
8930 c = 0x10;
8931 break;
8933 case REM_MINUS:
8934 c = 0x11;
8935 break;
8937 case REM_PLUS:
8938 c = 0x12;
8939 break;
8941 default:
8942 return -1;
8945 return simple_command_ic706(myrpt,0x0f,c);
8949 /* ic-706 mode */
8951 static int set_mode_ic706(struct rpt *myrpt, char newmode)
8953 unsigned char c;
8955 if(debug > 6)
8956 ast_log(LOG_NOTICE,"newmode=%i\n",newmode);
8958 switch(newmode){
8959 case REM_MODE_FM:
8960 c = 5;
8961 break;
8963 case REM_MODE_USB:
8964 c = 1;
8965 break;
8967 case REM_MODE_LSB:
8968 c = 0;
8969 break;
8971 case REM_MODE_AM:
8972 c = 2;
8973 break;
8975 default:
8976 return -1;
8978 return simple_command_ic706(myrpt,6,c);
8981 /* Set tone encode and decode modes */
8983 static int set_ctcss_mode_ic706(struct rpt *myrpt, char txplon, char rxplon)
8985 unsigned char cmdstr[10];
8986 int rv;
8988 if(debug > 6)
8989 ast_log(LOG_NOTICE,"txplon=%i rxplon=%i \n",txplon,rxplon);
8991 cmdstr[0] = cmdstr[1] = 0xfe;
8992 cmdstr[2] = myrpt->p.civaddr;
8993 cmdstr[3] = 0xe0;
8994 cmdstr[4] = 0x16;
8995 cmdstr[5] = 0x42;
8996 cmdstr[6] = (txplon != 0);
8997 cmdstr[7] = 0xfd;
8999 rv = civ_cmd(myrpt,cmdstr,8);
9000 if (rv) return(-1);
9002 cmdstr[0] = cmdstr[1] = 0xfe;
9003 cmdstr[2] = myrpt->p.civaddr;
9004 cmdstr[3] = 0xe0;
9005 cmdstr[4] = 0x16;
9006 cmdstr[5] = 0x43;
9007 cmdstr[6] = (rxplon != 0);
9008 cmdstr[7] = 0xfd;
9010 return(civ_cmd(myrpt,cmdstr,8));
9013 #if 0
9014 /* Set transmit and receive ctcss tone frequencies */
9016 static int set_ctcss_freq_ic706(struct rpt *myrpt, char *txtone, char *rxtone)
9018 unsigned char cmdstr[10];
9019 char hertz[MAXREMSTR],decimal[MAXREMSTR];
9020 int h,d,rv;
9022 memset(cmdstr, 0, 5);
9024 if(debug > 6)
9025 ast_log(LOG_NOTICE,"txtone=%s rxtone=%s \n",txtone,rxtone);
9027 if(split_ctcss_freq(hertz, decimal, txtone))
9028 return -1;
9030 h = atoi(hertz);
9031 d = atoi(decimal);
9033 cmdstr[0] = cmdstr[1] = 0xfe;
9034 cmdstr[2] = myrpt->p.civaddr;
9035 cmdstr[3] = 0xe0;
9036 cmdstr[4] = 0x1b;
9037 cmdstr[5] = 0;
9038 cmdstr[6] = ((h / 100) << 4) + (h % 100)/ 10;
9039 cmdstr[7] = ((h % 10) << 4) + (d % 10);
9040 cmdstr[8] = 0xfd;
9042 rv = civ_cmd(myrpt,cmdstr,9);
9043 if (rv) return(-1);
9045 if (!rxtone) return(0);
9047 if(split_ctcss_freq(hertz, decimal, rxtone))
9048 return -1;
9050 h = atoi(hertz);
9051 d = atoi(decimal);
9053 cmdstr[0] = cmdstr[1] = 0xfe;
9054 cmdstr[2] = myrpt->p.civaddr;
9055 cmdstr[3] = 0xe0;
9056 cmdstr[4] = 0x1b;
9057 cmdstr[5] = 1;
9058 cmdstr[6] = ((h / 100) << 4) + (h % 100)/ 10;
9059 cmdstr[7] = ((h % 10) << 4) + (d % 10);
9060 cmdstr[8] = 0xfd;
9061 return(civ_cmd(myrpt,cmdstr,9));
9063 #endif
9065 static int vfo_ic706(struct rpt *myrpt)
9067 unsigned char cmdstr[10];
9069 cmdstr[0] = cmdstr[1] = 0xfe;
9070 cmdstr[2] = myrpt->p.civaddr;
9071 cmdstr[3] = 0xe0;
9072 cmdstr[4] = 7;
9073 cmdstr[5] = 0xfd;
9075 return(civ_cmd(myrpt,cmdstr,6));
9078 static int mem2vfo_ic706(struct rpt *myrpt)
9080 unsigned char cmdstr[10];
9082 cmdstr[0] = cmdstr[1] = 0xfe;
9083 cmdstr[2] = myrpt->p.civaddr;
9084 cmdstr[3] = 0xe0;
9085 cmdstr[4] = 0x0a;
9086 cmdstr[5] = 0xfd;
9088 return(civ_cmd(myrpt,cmdstr,6));
9091 static int select_mem_ic706(struct rpt *myrpt, int slot)
9093 unsigned char cmdstr[10];
9095 cmdstr[0] = cmdstr[1] = 0xfe;
9096 cmdstr[2] = myrpt->p.civaddr;
9097 cmdstr[3] = 0xe0;
9098 cmdstr[4] = 8;
9099 cmdstr[5] = 0;
9100 cmdstr[6] = ((slot / 10) << 4) + (slot % 10);
9101 cmdstr[7] = 0xfd;
9103 return(civ_cmd(myrpt,cmdstr,8));
9106 static int set_ic706(struct rpt *myrpt)
9108 int res = 0,i;
9110 if(debug)ast_log(LOG_NOTICE, "Set to VFO A iobase=%i\n",myrpt->p.iobase);
9112 if (!res)
9113 res = simple_command_ic706(myrpt,7,0);
9115 if((myrpt->remmode == REM_MODE_FM))
9117 i = ic706_pltocode(myrpt->rxpl);
9118 if (i == -1) return -1;
9119 if(debug)
9120 printf("Select memory number\n");
9121 if (!res)
9122 res = select_mem_ic706(myrpt,i + IC706_PL_MEMORY_OFFSET);
9123 if(debug)
9124 printf("Transfer memory to VFO\n");
9125 if (!res)
9126 res = mem2vfo_ic706(myrpt);
9129 if(debug)
9130 printf("Set to VFO\n");
9132 if (!res)
9133 res = vfo_ic706(myrpt);
9135 if(debug)
9136 printf("Modulation mode\n");
9138 if (!res)
9139 res = set_mode_ic706(myrpt, myrpt->remmode); /* Modulation mode */
9141 if(debug)
9142 printf("Split off\n");
9144 if(!res)
9145 simple_command_ic706(myrpt, 0x82,0); /* Split off */
9147 if(debug)
9148 printf("Frequency\n");
9150 if(!res)
9151 res = set_freq_ic706(myrpt, myrpt->freq); /* Frequency */
9152 if((myrpt->remmode == REM_MODE_FM)){
9153 if(debug)
9154 printf("Offset\n");
9155 if(!res)
9156 res = set_offset_ic706(myrpt, myrpt->offset); /* Offset if FM */
9157 if(!res){
9158 if(debug)
9159 printf("CTCSS mode\n");
9160 res = set_ctcss_mode_ic706(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */
9163 return res;
9167 * Bump frequency up or down by a small amount
9168 * Return 0 if the new frequnecy is valid, or -1 if invalid
9169 * Interval is in Hz, resolution is 10Hz
9172 static int multimode_bump_freq_ic706(struct rpt *myrpt, int interval)
9174 int m,d;
9175 char mhz[MAXREMSTR], decimals[MAXREMSTR];
9176 unsigned char cmdstr[20];
9178 if(debug)
9179 printf("Before bump: %s\n", myrpt->freq);
9181 if(split_freq(mhz, decimals, myrpt->freq))
9182 return -1;
9184 m = atoi(mhz);
9185 d = atoi(decimals);
9187 d += (interval / 10); /* 10Hz resolution */
9188 if(d < 0){
9189 m--;
9190 d += 100000;
9192 else if(d >= 100000){
9193 m++;
9194 d -= 100000;
9197 if(check_freq_ic706(m, d, NULL,myrpt->p.remote_mars)){
9198 if(debug)
9199 printf("Bump freq invalid\n");
9200 return -1;
9203 snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d);
9205 if(debug)
9206 printf("After bump: %s\n", myrpt->freq);
9208 /* The ic-706 likes packed BCD frequencies */
9210 cmdstr[0] = cmdstr[1] = 0xfe;
9211 cmdstr[2] = myrpt->p.civaddr;
9212 cmdstr[3] = 0xe0;
9213 cmdstr[4] = 0;
9214 cmdstr[5] = ((d % 10) << 4);
9215 cmdstr[6] = (((d % 1000)/ 100) << 4) + ((d % 100)/10);
9216 cmdstr[7] = ((d / 10000) << 4) + ((d % 10000)/1000);
9217 cmdstr[8] = (((m % 100)/10) << 4) + (m % 10);
9218 cmdstr[9] = (m / 100);
9219 cmdstr[10] = 0xfd;
9221 return(serial_remote_io(myrpt,cmdstr,11,NULL,0,0));
9227 * Dispatch to correct I/O handler
9229 static int setrem(struct rpt *myrpt)
9231 char str[300];
9232 char *offsets[] = {"SIMPLEX","MINUS","PLUS"};
9233 char *powerlevels[] = {"LOW","MEDIUM","HIGH"};
9234 char *modes[] = {"FM","USB","LSB","AM"};
9235 int res = -1;
9237 #if 0
9238 printf("FREQ,%s,%s,%s,%s,%s,%s,%d,%d\n",myrpt->freq,
9239 modes[(int)myrpt->remmode],
9240 myrpt->txpl,myrpt->rxpl,offsets[(int)myrpt->offset],
9241 powerlevels[(int)myrpt->powerlevel],myrpt->txplon,
9242 myrpt->rxplon);
9243 #endif
9244 if (myrpt->p.archivedir)
9246 sprintf(str,"FREQ,%s,%s,%s,%s,%s,%s,%d,%d",myrpt->freq,
9247 modes[(int)myrpt->remmode],
9248 myrpt->txpl,myrpt->rxpl,offsets[(int)myrpt->offset],
9249 powerlevels[(int)myrpt->powerlevel],myrpt->txplon,
9250 myrpt->rxplon);
9251 donodelog(myrpt,str);
9253 if(!strcmp(myrpt->remoterig, remote_rig_ft897))
9255 rpt_telemetry(myrpt,SETREMOTE,NULL);
9256 res = 0;
9258 if(!strcmp(myrpt->remoterig, remote_rig_ic706))
9260 rpt_telemetry(myrpt,SETREMOTE,NULL);
9261 res = 0;
9263 if(!strcmp(myrpt->remoterig, remote_rig_tm271))
9265 rpt_telemetry(myrpt,SETREMOTE,NULL);
9266 res = 0;
9268 else if(!strcmp(myrpt->remoterig, remote_rig_rbi))
9270 res = setrbi_check(myrpt);
9271 if (!res)
9273 rpt_telemetry(myrpt,SETREMOTE,NULL);
9274 res = 0;
9277 else if(ISRIG_RTX(myrpt->remoterig))
9279 setrtx(myrpt);
9280 res = 0;
9282 else if(!strcmp(myrpt->remoterig, remote_rig_kenwood)) {
9283 rpt_telemetry(myrpt,SETREMOTE,NULL);
9284 res = 0;
9286 else
9287 res = 0;
9289 if (res < 0) ast_log(LOG_ERROR,"Unable to send remote command on node %s\n",myrpt->name);
9291 return res;
9294 static int closerem(struct rpt *myrpt)
9296 if(!strcmp(myrpt->remoterig, remote_rig_ft897))
9297 return closerem_ft897(myrpt);
9298 else
9299 return 0;
9303 * Dispatch to correct RX frequency checker
9306 static int check_freq(struct rpt *myrpt, int m, int d, int *defmode)
9308 if(!strcmp(myrpt->remoterig, remote_rig_ft897))
9309 return check_freq_ft897(m, d, defmode);
9310 else if(!strcmp(myrpt->remoterig, remote_rig_ic706))
9311 return check_freq_ic706(m, d, defmode,myrpt->p.remote_mars);
9312 else if(!strcmp(myrpt->remoterig, remote_rig_rbi))
9313 return check_freq_rbi(m, d, defmode);
9314 else if(!strcmp(myrpt->remoterig, remote_rig_kenwood))
9315 return check_freq_kenwood(m, d, defmode);
9316 else if(!strcmp(myrpt->remoterig, remote_rig_tm271))
9317 return check_freq_tm271(m, d, defmode);
9318 else if(ISRIG_RTX(myrpt->remoterig))
9319 return check_freq_rtx(m, d, defmode, myrpt);
9320 else
9321 return -1;
9325 * Check TX frequency before transmitting
9326 rv=1 if tx frequency in ok.
9329 static char check_tx_freq(struct rpt *myrpt)
9331 int i,rv=0;
9332 int radio_mhz, radio_decimals, ulimit_mhz, ulimit_decimals, llimit_mhz, llimit_decimals;
9333 char radio_mhz_char[MAXREMSTR];
9334 char radio_decimals_char[MAXREMSTR];
9335 char limit_mhz_char[MAXREMSTR];
9336 char limit_decimals_char[MAXREMSTR];
9337 char limits[256];
9338 char *limit_ranges[40];
9339 struct ast_variable *limitlist;
9341 if(debug > 3){
9342 ast_log(LOG_NOTICE, "myrpt->freq = %s\n", myrpt->freq);
9345 /* Must have user logged in and tx_limits defined */
9347 if(!myrpt->p.txlimitsstanzaname || !myrpt->loginuser[0] || !myrpt->loginlevel[0]){
9348 if(debug > 3){
9349 ast_log(LOG_NOTICE, "No tx band table defined, or no user logged in. rv=1\n");
9351 rv=1;
9352 return 1; /* Assume it's ok otherwise */
9355 /* Retrieve the band table for the loginlevel */
9356 limitlist = ast_variable_browse(myrpt->cfg, myrpt->p.txlimitsstanzaname);
9358 if(!limitlist){
9359 ast_log(LOG_WARNING, "No entries in %s band table stanza. rv=0\n", myrpt->p.txlimitsstanzaname);
9360 rv=0;
9361 return 0;
9364 split_freq(radio_mhz_char, radio_decimals_char, myrpt->freq);
9365 radio_mhz = atoi(radio_mhz_char);
9366 radio_decimals = decimals2int(radio_decimals_char);
9368 if(debug > 3){
9369 ast_log(LOG_NOTICE, "Login User = %s, login level = %s\n", myrpt->loginuser, myrpt->loginlevel);
9372 /* Find our entry */
9374 for(;limitlist; limitlist=limitlist->next){
9375 if(!strcmp(limitlist->name, myrpt->loginlevel))
9376 break;
9379 if(!limitlist){
9380 ast_log(LOG_WARNING, "Can't find %s entry in band table stanza %s. rv=0\n", myrpt->loginlevel, myrpt->p.txlimitsstanzaname);
9381 rv=0;
9382 return 0;
9385 if(debug > 3){
9386 ast_log(LOG_NOTICE, "Auth: %s = %s\n", limitlist->name, limitlist->value);
9389 /* Parse the limits */
9391 strncpy(limits, limitlist->value, 256);
9392 limits[255] = 0;
9393 finddelim(limits, limit_ranges, 40);
9394 for(i = 0; i < 40 && limit_ranges[i] ; i++){
9395 char range[40];
9396 char *r,*s;
9397 strncpy(range, limit_ranges[i], 40);
9398 range[39] = 0;
9399 if(debug > 3)
9400 ast_log(LOG_NOTICE, "Check %s within %s\n", myrpt->freq, range);
9402 r = strchr(range, '-');
9403 if(!r){
9404 ast_log(LOG_WARNING, "Malformed range in %s tx band table entry. rv=0\n", limitlist->name);
9405 rv=0;
9406 break;
9408 *r++ = 0;
9409 s = eatwhite(range);
9410 r = eatwhite(r);
9411 split_freq(limit_mhz_char, limit_decimals_char, s);
9412 llimit_mhz = atoi(limit_mhz_char);
9413 llimit_decimals = decimals2int(limit_decimals_char);
9414 split_freq(limit_mhz_char, limit_decimals_char, r);
9415 ulimit_mhz = atoi(limit_mhz_char);
9416 ulimit_decimals = decimals2int(limit_decimals_char);
9418 if((radio_mhz >= llimit_mhz) && (radio_mhz <= ulimit_mhz)){
9419 if(radio_mhz == llimit_mhz){ /* CASE 1: TX freq is in llimit mhz portion of band */
9420 if(radio_decimals >= llimit_decimals){ /* Cannot be below llimit decimals */
9421 if(llimit_mhz == ulimit_mhz){ /* If bandwidth < 1Mhz, check ulimit decimals */
9422 if(radio_decimals <= ulimit_decimals){
9423 rv=1;
9424 break;
9426 else{
9427 if(debug > 3)
9428 ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 1\n");
9429 rv=0;
9430 break;
9433 else{
9434 rv=1;
9435 break;
9438 else{ /* Is below llimit decimals */
9439 if(debug > 3)
9440 ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 2\n");
9441 rv=0;
9442 break;
9445 else if(radio_mhz == ulimit_mhz){ /* CASE 2: TX freq not in llimit mhz portion of band */
9446 if(radio_decimals <= ulimit_decimals){
9447 if(debug > 3)
9448 ast_log(LOG_NOTICE, "radio_decimals <= ulimit_decimals\n");
9449 rv=1;
9450 break;
9452 else{ /* Is above ulimit decimals */
9453 if(debug > 3)
9454 ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 3\n");
9455 rv=0;
9456 break;
9459 else /* CASE 3: TX freq within a multi-Mhz band and ok */
9460 if(debug > 3)
9461 ast_log(LOG_NOTICE, "Valid TX freq within a multi-Mhz band and ok.\n");
9462 rv=1;
9463 break;
9466 if(debug > 3)
9467 ast_log(LOG_NOTICE, "rv=%i\n",rv);
9469 return rv;
9474 * Dispatch to correct frequency bumping function
9477 static int multimode_bump_freq(struct rpt *myrpt, int interval)
9479 if(!strcmp(myrpt->remoterig, remote_rig_ft897))
9480 return multimode_bump_freq_ft897(myrpt, interval);
9481 else if(!strcmp(myrpt->remoterig, remote_rig_ic706))
9482 return multimode_bump_freq_ic706(myrpt, interval);
9483 else
9484 return -1;
9489 * Queue announcment that scan has been stopped
9492 static void stop_scan(struct rpt *myrpt)
9494 myrpt->hfscanstop = 1;
9495 rpt_telemetry(myrpt,SCAN,0);
9499 * This is called periodically when in scan mode
9503 static int service_scan(struct rpt *myrpt)
9505 int res, interval;
9506 char mhz[MAXREMSTR], decimals[MAXREMSTR], k10=0i, k100=0;
9508 switch(myrpt->hfscanmode){
9510 case HF_SCAN_DOWN_SLOW:
9511 interval = -10; /* 100Hz /sec */
9512 break;
9514 case HF_SCAN_DOWN_QUICK:
9515 interval = -50; /* 500Hz /sec */
9516 break;
9518 case HF_SCAN_DOWN_FAST:
9519 interval = -200; /* 2KHz /sec */
9520 break;
9522 case HF_SCAN_UP_SLOW:
9523 interval = 10; /* 100Hz /sec */
9524 break;
9526 case HF_SCAN_UP_QUICK:
9527 interval = 50; /* 500 Hz/sec */
9528 break;
9530 case HF_SCAN_UP_FAST:
9531 interval = 200; /* 2KHz /sec */
9532 break;
9534 default:
9535 myrpt->hfscanmode = 0; /* Huh? */
9536 return -1;
9539 res = split_freq(mhz, decimals, myrpt->freq);
9541 if(!res){
9542 k100 =decimals[0];
9543 k10 = decimals[1];
9544 res = multimode_bump_freq(myrpt, interval);
9547 if(!res)
9548 res = split_freq(mhz, decimals, myrpt->freq);
9551 if(res){
9552 myrpt->hfscanmode = 0;
9553 myrpt->hfscanstatus = -2;
9554 return -1;
9557 /* Announce 10KHz boundaries */
9558 if(k10 != decimals[1]){
9559 int myhund = (interval < 0) ? k100 : decimals[0];
9560 int myten = (interval < 0) ? k10 : decimals[1];
9561 myrpt->hfscanstatus = (myten == '0') ? (myhund - '0') * 100 : (myten - '0') * 10;
9562 } else myrpt->hfscanstatus = 0;
9563 return res;
9567 retrieve memory setting and set radio
9569 static int get_mem_set(struct rpt *myrpt, char *digitbuf)
9571 int res=0;
9572 if(debug)ast_log(LOG_NOTICE," digitbuf=%s\n", digitbuf);
9573 res = retreive_memory(myrpt, digitbuf);
9574 if(!res)res=setrem(myrpt);
9575 if(debug)ast_log(LOG_NOTICE," freq=%s res=%i\n", myrpt->freq, res);
9576 return res;
9579 steer the radio selected channel to either one programmed into the radio
9580 or if the radio is VFO agile, to an rpt.conf memory location.
9582 static int channel_steer(struct rpt *myrpt, char *data)
9584 int res=0;
9586 if(debug)ast_log(LOG_NOTICE,"remoterig=%s, data=%s\n",myrpt->remoterig,data);
9587 if (!myrpt->remoterig) return(0);
9588 if(data<=0)
9590 res=-1;
9592 else
9594 myrpt->nowchan=strtod(data,NULL);
9595 if(!strcmp(myrpt->remoterig, remote_rig_ppp16))
9597 char string[16];
9598 sprintf(string,"SETCHAN %d ",myrpt->nowchan);
9599 send_usb_txt(myrpt,string);
9601 else
9603 if(get_mem_set(myrpt, data))res=-1;
9606 if(debug)ast_log(LOG_NOTICE,"nowchan=%i res=%i\n",myrpt->nowchan, res);
9607 return res;
9611 static int channel_revert(struct rpt *myrpt)
9613 int res=0;
9614 if(debug)ast_log(LOG_NOTICE,"remoterig=%s, nowchan=%02d, waschan=%02d\n",myrpt->remoterig,myrpt->nowchan,myrpt->waschan);
9615 if (!myrpt->remoterig) return(0);
9616 if(myrpt->nowchan!=myrpt->waschan)
9618 char data[8];
9619 if(debug)ast_log(LOG_NOTICE,"reverting.\n");
9620 sprintf(data,"%02d",myrpt->waschan);
9621 myrpt->nowchan=myrpt->waschan;
9622 channel_steer(myrpt,data);
9623 res=1;
9625 return(res);
9628 * Remote base function
9631 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
9633 char *s,*s1,*s2;
9634 int i,j,p,r,ht,k,l,ls2,m,d,offset,offsave, modesave, defmode;
9635 char multimode = 0;
9636 char oc,*cp,*cp1,*cp2;
9637 char tmp[20], freq[20] = "", savestr[20] = "";
9638 char mhz[MAXREMSTR], decimals[MAXREMSTR];
9640 if(debug > 6) {
9641 ast_log(LOG_NOTICE,"%s param=%s digitbuf=%s source=%i\n",myrpt->name,param,digitbuf,command_source);
9644 if((!param) || (command_source == SOURCE_RPT) || (command_source == SOURCE_LNK))
9645 return DC_ERROR;
9647 p = myatoi(param);
9649 if ((p != 99) && (p != 5) && (p != 140) && myrpt->p.authlevel &&
9650 (!myrpt->loginlevel[0])) return DC_ERROR;
9651 multimode = multimode_capable(myrpt);
9653 switch(p){
9655 case 1: /* retrieve memory */
9656 if(strlen(digitbuf) < 2) /* needs 2 digits */
9657 break;
9659 for(i = 0 ; i < 2 ; i++){
9660 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
9661 return DC_ERROR;
9663 r=get_mem_set(myrpt, digitbuf);
9664 if (r < 0){
9665 rpt_telemetry(myrpt,MEMNOTFOUND,NULL);
9666 return DC_COMPLETE;
9668 else if (r > 0){
9669 return DC_ERROR;
9671 return DC_COMPLETE;
9673 case 2: /* set freq and offset */
9676 for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for M+*K+*O or M+*H+* depending on mode */
9677 if(digitbuf[i] == '*'){
9678 j++;
9679 continue;
9681 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
9682 goto invalid_freq;
9683 else{
9684 if(j == 0)
9685 l++; /* # of digits before first * */
9686 if(j == 1)
9687 k++; /* # of digits after first * */
9691 i = strlen(digitbuf) - 1;
9692 if(multimode){
9693 if((j > 2) || (l > 3) || (k > 6))
9694 goto invalid_freq; /* &^@#! */
9696 else{
9697 if((j > 2) || (l > 4) || (k > 3))
9698 goto invalid_freq; /* &^@#! */
9701 /* Wait for M+*K+* */
9703 if(j < 2)
9704 break; /* Not yet */
9706 /* We have a frequency */
9708 strncpy(tmp, digitbuf ,sizeof(tmp) - 1);
9710 s = tmp;
9711 s1 = strsep(&s, "*"); /* Pick off MHz */
9712 s2 = strsep(&s,"*"); /* Pick off KHz and Hz */
9713 ls2 = strlen(s2);
9715 switch(ls2){ /* Allow partial entry of khz and hz digits for laziness support */
9716 case 1:
9717 ht = 0;
9718 k = 100 * atoi(s2);
9719 break;
9721 case 2:
9722 ht = 0;
9723 k = 10 * atoi(s2);
9724 break;
9726 case 3:
9727 if(!multimode){
9728 if((s2[2] != '0')&&(s2[2] != '5'))
9729 goto invalid_freq;
9731 ht = 0;
9732 k = atoi(s2);
9733 break;
9734 case 4:
9735 k = atoi(s2)/10;
9736 ht = 10 * (atoi(s2+(ls2-1)));
9737 break;
9739 case 5:
9740 k = atoi(s2)/100;
9741 ht = (atoi(s2+(ls2-2)));
9742 break;
9744 default:
9745 goto invalid_freq;
9748 /* Check frequency for validity and establish a default mode */
9750 snprintf(freq, sizeof(freq), "%s.%03d%02d",s1, k, ht);
9752 if(debug)
9753 ast_log(LOG_NOTICE, "New frequency: %s\n", freq);
9755 split_freq(mhz, decimals, freq);
9756 m = atoi(mhz);
9757 d = atoi(decimals);
9759 if(check_freq(myrpt, m, d, &defmode)) /* Check to see if frequency entered is legit */
9760 goto invalid_freq;
9763 if((defmode == REM_MODE_FM) && (digitbuf[i] == '*')) /* If FM, user must enter and additional offset digit */
9764 break; /* Not yet */
9767 offset = REM_SIMPLEX; /* Assume simplex */
9769 if(defmode == REM_MODE_FM){
9770 oc = *s; /* Pick off offset */
9772 if (oc){
9773 switch(oc){
9774 case '1':
9775 offset = REM_MINUS;
9776 break;
9778 case '2':
9779 offset = REM_SIMPLEX;
9780 break;
9782 case '3':
9783 offset = REM_PLUS;
9784 break;
9786 default:
9787 goto invalid_freq;
9791 offsave = myrpt->offset;
9792 modesave = myrpt->remmode;
9793 strncpy(savestr, myrpt->freq, sizeof(savestr) - 1);
9794 strncpy(myrpt->freq, freq, sizeof(myrpt->freq) - 1);
9795 myrpt->offset = offset;
9796 myrpt->remmode = defmode;
9798 if (setrem(myrpt) == -1){
9799 myrpt->offset = offsave;
9800 myrpt->remmode = modesave;
9801 strncpy(myrpt->freq, savestr, sizeof(myrpt->freq) - 1);
9802 goto invalid_freq;
9805 return DC_COMPLETE;
9807 invalid_freq:
9808 rpt_telemetry(myrpt,INVFREQ,NULL);
9809 return DC_ERROR;
9811 case 3: /* set rx PL tone */
9812 for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
9813 if(digitbuf[i] == '*'){
9814 j++;
9815 continue;
9817 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
9818 return DC_ERROR;
9819 else{
9820 if(j)
9821 l++;
9822 else
9823 k++;
9826 if((j > 1) || (k > 3) || (l > 1))
9827 return DC_ERROR; /* &$@^! */
9828 i = strlen(digitbuf) - 1;
9829 if((j != 1) || (k < 2)|| (l != 1))
9830 break; /* Not yet */
9831 if(debug)
9832 printf("PL digits entered %s\n", digitbuf);
9834 strncpy(tmp, digitbuf, sizeof(tmp) - 1);
9835 /* see if we have at least 1 */
9836 s = strchr(tmp,'*');
9837 if(s)
9838 *s = '.';
9839 strncpy(savestr, myrpt->rxpl, sizeof(savestr) - 1);
9840 strncpy(myrpt->rxpl, tmp, sizeof(myrpt->rxpl) - 1);
9841 if(!strcmp(myrpt->remoterig, remote_rig_rbi))
9843 strncpy(myrpt->txpl, tmp, sizeof(myrpt->txpl) - 1);
9845 if (setrem(myrpt) == -1){
9846 strncpy(myrpt->rxpl, savestr, sizeof(myrpt->rxpl) - 1);
9847 return DC_ERROR;
9849 return DC_COMPLETE;
9851 case 4: /* set tx PL tone */
9852 /* cant set tx tone on RBI (rx tone does both) */
9853 if(!strcmp(myrpt->remoterig, remote_rig_rbi))
9854 return DC_ERROR;
9855 /* eventually for the ic706 instead of just throwing the exception
9856 we can check if we are in encode only mode and allow the tx
9857 ctcss code to be changed. but at least the warning message is
9858 issued for now.
9860 if(!strcmp(myrpt->remoterig, remote_rig_ic706))
9862 if(debug)
9863 ast_log(LOG_WARNING,"Setting IC706 Tx CTCSS Code Not Supported. Set Rx Code for both.\n");
9864 return DC_ERROR;
9866 for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
9867 if(digitbuf[i] == '*'){
9868 j++;
9869 continue;
9871 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
9872 return DC_ERROR;
9873 else{
9874 if(j)
9875 l++;
9876 else
9877 k++;
9880 if((j > 1) || (k > 3) || (l > 1))
9881 return DC_ERROR; /* &$@^! */
9882 i = strlen(digitbuf) - 1;
9883 if((j != 1) || (k < 2)|| (l != 1))
9884 break; /* Not yet */
9885 if(debug)
9886 printf("PL digits entered %s\n", digitbuf);
9888 strncpy(tmp, digitbuf, sizeof(tmp) - 1);
9889 /* see if we have at least 1 */
9890 s = strchr(tmp,'*');
9891 if(s)
9892 *s = '.';
9893 strncpy(savestr, myrpt->txpl, sizeof(savestr) - 1);
9894 strncpy(myrpt->txpl, tmp, sizeof(myrpt->txpl) - 1);
9896 if (setrem(myrpt) == -1){
9897 strncpy(myrpt->txpl, savestr, sizeof(myrpt->txpl) - 1);
9898 return DC_ERROR;
9900 return DC_COMPLETE;
9903 case 6: /* MODE (FM,USB,LSB,AM) */
9904 if(strlen(digitbuf) < 1)
9905 break;
9907 if(!multimode)
9908 return DC_ERROR; /* Multimode radios only */
9910 switch(*digitbuf){
9911 case '1':
9912 split_freq(mhz, decimals, myrpt->freq);
9913 m=atoi(mhz);
9914 if(m < 29) /* No FM allowed below 29MHz! */
9915 return DC_ERROR;
9916 myrpt->remmode = REM_MODE_FM;
9918 rpt_telemetry(myrpt,REMMODE,NULL);
9919 break;
9921 case '2':
9922 myrpt->remmode = REM_MODE_USB;
9923 rpt_telemetry(myrpt,REMMODE,NULL);
9924 break;
9926 case '3':
9927 myrpt->remmode = REM_MODE_LSB;
9928 rpt_telemetry(myrpt,REMMODE,NULL);
9929 break;
9931 case '4':
9932 myrpt->remmode = REM_MODE_AM;
9933 rpt_telemetry(myrpt,REMMODE,NULL);
9934 break;
9936 default:
9937 return DC_ERROR;
9940 if(setrem(myrpt))
9941 return DC_ERROR;
9942 return DC_COMPLETEQUIET;
9943 case 99:
9944 /* cant log in when logged in */
9945 if (myrpt->loginlevel[0])
9946 return DC_ERROR;
9947 *myrpt->loginuser = 0;
9948 myrpt->loginlevel[0] = 0;
9949 cp = ast_strdup(param);
9950 cp1 = strchr(cp,',');
9951 ast_mutex_lock(&myrpt->lock);
9952 if (cp1)
9954 *cp1 = 0;
9955 cp2 = strchr(cp1 + 1,',');
9956 if (cp2)
9958 *cp2 = 0;
9959 strncpy(myrpt->loginlevel,cp2 + 1,
9960 sizeof(myrpt->loginlevel) - 1);
9962 strncpy(myrpt->loginuser,cp1 + 1,sizeof(myrpt->loginuser));
9963 ast_mutex_unlock(&myrpt->lock);
9964 if (myrpt->p.archivedir)
9966 char str[100];
9968 sprintf(str,"LOGIN,%s,%s",
9969 myrpt->loginuser,myrpt->loginlevel);
9970 donodelog(myrpt,str);
9972 if (debug)
9973 printf("loginuser %s level %s\n",myrpt->loginuser,myrpt->loginlevel);
9974 rpt_telemetry(myrpt,REMLOGIN,NULL);
9976 ast_free(cp);
9977 return DC_COMPLETEQUIET;
9978 case 100: /* RX PL Off */
9979 myrpt->rxplon = 0;
9980 setrem(myrpt);
9981 rpt_telemetry(myrpt,REMXXX,(void *)p);
9982 return DC_COMPLETEQUIET;
9983 case 101: /* RX PL On */
9984 myrpt->rxplon = 1;
9985 setrem(myrpt);
9986 rpt_telemetry(myrpt,REMXXX,(void *)p);
9987 return DC_COMPLETEQUIET;
9988 case 102: /* TX PL Off */
9989 myrpt->txplon = 0;
9990 setrem(myrpt);
9991 rpt_telemetry(myrpt,REMXXX,(void *)p);
9992 return DC_COMPLETEQUIET;
9993 case 103: /* TX PL On */
9994 myrpt->txplon = 1;
9995 setrem(myrpt);
9996 rpt_telemetry(myrpt,REMXXX,(void *)p);
9997 return DC_COMPLETEQUIET;
9998 case 104: /* Low Power */
9999 if(!strcmp(myrpt->remoterig, remote_rig_ic706))
10000 return DC_ERROR;
10001 myrpt->powerlevel = REM_LOWPWR;
10002 setrem(myrpt);
10003 rpt_telemetry(myrpt,REMXXX,(void *)p);
10004 return DC_COMPLETEQUIET;
10005 case 105: /* Medium Power */
10006 if(!strcmp(myrpt->remoterig, remote_rig_ic706))
10007 return DC_ERROR;
10008 if (ISRIG_RTX(myrpt->remoterig)) return DC_ERROR;
10009 myrpt->powerlevel = REM_MEDPWR;
10010 setrem(myrpt);
10011 rpt_telemetry(myrpt,REMXXX,(void *)p);
10012 return DC_COMPLETEQUIET;
10013 case 106: /* Hi Power */
10014 if(!strcmp(myrpt->remoterig, remote_rig_ic706))
10015 return DC_ERROR;
10016 myrpt->powerlevel = REM_HIPWR;
10017 setrem(myrpt);
10018 rpt_telemetry(myrpt,REMXXX,(void *)p);
10019 return DC_COMPLETEQUIET;
10020 case 107: /* Bump down 20Hz */
10021 multimode_bump_freq(myrpt, -20);
10022 return DC_COMPLETE;
10023 case 108: /* Bump down 100Hz */
10024 multimode_bump_freq(myrpt, -100);
10025 return DC_COMPLETE;
10026 case 109: /* Bump down 500Hz */
10027 multimode_bump_freq(myrpt, -500);
10028 return DC_COMPLETE;
10029 case 110: /* Bump up 20Hz */
10030 multimode_bump_freq(myrpt, 20);
10031 return DC_COMPLETE;
10032 case 111: /* Bump up 100Hz */
10033 multimode_bump_freq(myrpt, 100);
10034 return DC_COMPLETE;
10035 case 112: /* Bump up 500Hz */
10036 multimode_bump_freq(myrpt, 500);
10037 return DC_COMPLETE;
10038 case 113: /* Scan down slow */
10039 myrpt->scantimer = REM_SCANTIME;
10040 myrpt->hfscanmode = HF_SCAN_DOWN_SLOW;
10041 rpt_telemetry(myrpt,REMXXX,(void *)p);
10042 return DC_COMPLETEQUIET;
10043 case 114: /* Scan down quick */
10044 myrpt->scantimer = REM_SCANTIME;
10045 myrpt->hfscanmode = HF_SCAN_DOWN_QUICK;
10046 rpt_telemetry(myrpt,REMXXX,(void *)p);
10047 return DC_COMPLETEQUIET;
10048 case 115: /* Scan down fast */
10049 myrpt->scantimer = REM_SCANTIME;
10050 myrpt->hfscanmode = HF_SCAN_DOWN_FAST;
10051 rpt_telemetry(myrpt,REMXXX,(void *)p);
10052 return DC_COMPLETEQUIET;
10053 case 116: /* Scan up slow */
10054 myrpt->scantimer = REM_SCANTIME;
10055 myrpt->hfscanmode = HF_SCAN_UP_SLOW;
10056 rpt_telemetry(myrpt,REMXXX,(void *)p);
10057 return DC_COMPLETEQUIET;
10058 case 117: /* Scan up quick */
10059 myrpt->scantimer = REM_SCANTIME;
10060 myrpt->hfscanmode = HF_SCAN_UP_QUICK;
10061 rpt_telemetry(myrpt,REMXXX,(void *)p);
10062 return DC_COMPLETEQUIET;
10063 case 118: /* Scan up fast */
10064 myrpt->scantimer = REM_SCANTIME;
10065 myrpt->hfscanmode = HF_SCAN_UP_FAST;
10066 rpt_telemetry(myrpt,REMXXX,(void *)p);
10067 return DC_COMPLETEQUIET;
10068 case 119: /* Tune Request */
10069 if(debug > 3)
10070 ast_log(LOG_NOTICE,"TUNE REQUEST\n");
10071 /* if not currently going, and valid to do */
10072 if((!myrpt->tunerequest) &&
10073 ((!strcmp(myrpt->remoterig, remote_rig_ft897) ||
10074 !strcmp(myrpt->remoterig, remote_rig_ic706)) )) {
10075 myrpt->remotetx = 0;
10076 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
10077 myrpt->tunerequest = 1;
10078 rpt_telemetry(myrpt,TUNE,NULL);
10079 return DC_COMPLETEQUIET;
10081 return DC_ERROR;
10082 case 5: /* Long Status */
10083 rpt_telemetry(myrpt,REMLONGSTATUS,NULL);
10084 return DC_COMPLETEQUIET;
10085 case 140: /* Short Status */
10086 rpt_telemetry(myrpt,REMSHORTSTATUS,NULL);
10087 return DC_COMPLETEQUIET;
10088 case 200:
10089 case 201:
10090 case 202:
10091 case 203:
10092 case 204:
10093 case 205:
10094 case 206:
10095 case 207:
10096 case 208:
10097 case 209:
10098 case 210:
10099 case 211:
10100 case 212:
10101 case 213:
10102 case 214:
10103 case 215:
10104 do_dtmf_local(myrpt,remdtmfstr[p - 200]);
10105 return DC_COMPLETEQUIET;
10106 default:
10107 break;
10109 return DC_INDETERMINATE;
10113 static int handle_remote_dtmf_digit(struct rpt *myrpt,char c, char *keyed, int phonemode)
10115 time_t now;
10116 int ret,res = 0,src;
10118 if(debug > 6)
10119 ast_log(LOG_NOTICE,"c=%c phonemode=%i dtmfidx=%i\n",c,phonemode,myrpt->dtmfidx);
10121 time(&myrpt->last_activity_time);
10122 /* Stop scan mode if in scan mode */
10123 if(myrpt->hfscanmode){
10124 stop_scan(myrpt);
10125 return 0;
10128 time(&now);
10129 /* if timed-out */
10130 if ((myrpt->dtmf_time_rem + DTMF_TIMEOUT) < now)
10132 myrpt->dtmfidx = -1;
10133 myrpt->dtmfbuf[0] = 0;
10134 myrpt->dtmf_time_rem = 0;
10136 /* if decode not active */
10137 if (myrpt->dtmfidx == -1)
10139 /* if not lead-in digit, dont worry */
10140 if (c != myrpt->p.funcchar)
10142 if (!myrpt->p.propagate_dtmf)
10144 rpt_mutex_lock(&myrpt->lock);
10145 do_dtmf_local(myrpt,c);
10146 rpt_mutex_unlock(&myrpt->lock);
10148 return 0;
10150 myrpt->dtmfidx = 0;
10151 myrpt->dtmfbuf[0] = 0;
10152 myrpt->dtmf_time_rem = now;
10153 return 0;
10155 /* if too many in buffer, start over */
10156 if (myrpt->dtmfidx >= MAXDTMF)
10158 myrpt->dtmfidx = 0;
10159 myrpt->dtmfbuf[0] = 0;
10160 myrpt->dtmf_time_rem = now;
10162 if (c == myrpt->p.funcchar)
10164 /* if star at beginning, or 2 together, erase buffer */
10165 if ((myrpt->dtmfidx < 1) ||
10166 (myrpt->dtmfbuf[myrpt->dtmfidx - 1] == myrpt->p.funcchar))
10168 myrpt->dtmfidx = 0;
10169 myrpt->dtmfbuf[0] = 0;
10170 myrpt->dtmf_time_rem = now;
10171 return 0;
10174 myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
10175 myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
10176 myrpt->dtmf_time_rem = now;
10179 src = SOURCE_RMT;
10180 if (phonemode == 2) src = SOURCE_DPHONE;
10181 else if (phonemode) src = SOURCE_PHONE;
10182 else if (phonemode == 4) src = SOURCE_ALT;
10183 ret = collect_function_digits(myrpt, myrpt->dtmfbuf, src, NULL);
10185 switch(ret){
10187 case DC_INDETERMINATE:
10188 res = 0;
10189 break;
10191 case DC_DOKEY:
10192 if (keyed) *keyed = 1;
10193 res = 0;
10194 break;
10196 case DC_REQ_FLUSH:
10197 myrpt->dtmfidx = 0;
10198 myrpt->dtmfbuf[0] = 0;
10199 res = 0;
10200 break;
10203 case DC_COMPLETE:
10204 res = 1;
10205 case DC_COMPLETEQUIET:
10206 myrpt->totalexecdcommands++;
10207 myrpt->dailyexecdcommands++;
10208 strncpy(myrpt->lastdtmfcommand, myrpt->dtmfbuf, MAXDTMF-1);
10209 myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
10210 myrpt->dtmfbuf[0] = 0;
10211 myrpt->dtmfidx = -1;
10212 myrpt->dtmf_time_rem = 0;
10213 break;
10215 case DC_ERROR:
10216 default:
10217 myrpt->dtmfbuf[0] = 0;
10218 myrpt->dtmfidx = -1;
10219 myrpt->dtmf_time_rem = 0;
10220 res = 0;
10221 break;
10224 return res;
10227 static int handle_remote_data(struct rpt *myrpt, char *str)
10229 char tmp[300],cmd[300],dest[300],src[300],c;
10230 int seq,res;
10232 /* put string in our buffer */
10233 strncpy(tmp,str,sizeof(tmp) - 1);
10234 if (!strcmp(tmp,discstr)) return 0;
10235 if (!strcmp(tmp,newkeystr))
10237 myrpt->newkey = 1;
10238 return 0;
10241 #ifndef DO_NOT_NOTIFY_MDC1200_ON_REMOTE_BASES
10242 if (tmp[0] == 'I')
10244 if (sscanf(tmp,"%s %s %x",cmd,src,&seq) != 3)
10246 ast_log(LOG_WARNING, "Unable to parse ident string %s\n",str);
10247 return 0;
10249 mdc1200_notify(myrpt,src,seq);
10250 return 0;
10252 #endif
10253 if (sscanf(tmp,"%s %s %s %d %c",cmd,dest,src,&seq,&c) != 5)
10255 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
10256 return 0;
10258 if (strcmp(cmd,"D"))
10260 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
10261 return 0;
10263 /* if not for me, ignore */
10264 if (strcmp(dest,myrpt->name)) return 0;
10265 if (myrpt->p.archivedir)
10267 char str[100];
10269 sprintf(str,"DTMF,%c",c);
10270 donodelog(myrpt,str);
10272 c = func_xlat(myrpt,c,&myrpt->p.outxlat);
10273 if (!c) return(0);
10274 res = handle_remote_dtmf_digit(myrpt,c, NULL, 0);
10275 if (res != 1)
10276 return res;
10277 rpt_telemetry(myrpt,COMPLETE,NULL);
10278 return 0;
10281 static int handle_remote_phone_dtmf(struct rpt *myrpt, char c, char *keyed, int phonemode)
10283 int res;
10286 if(phonemode == 3) /* simplex phonemode, funcchar key/unkey toggle */
10288 if (keyed && *keyed && ((c == myrpt->p.funcchar) || (c == myrpt->p.endchar)))
10290 *keyed = 0; /* UNKEY */
10291 return 0;
10293 else if (keyed && !*keyed && (c = myrpt->p.funcchar))
10295 *keyed = 1; /* KEY */
10296 return 0;
10299 else /* endchar unkey */
10302 if (keyed && *keyed && (c == myrpt->p.endchar))
10304 *keyed = 0;
10305 return DC_INDETERMINATE;
10308 if (myrpt->p.archivedir)
10310 char str[100];
10312 sprintf(str,"DTMF(P),%c",c);
10313 donodelog(myrpt,str);
10315 res = handle_remote_dtmf_digit(myrpt,c,keyed, phonemode);
10316 if (res != 1)
10317 return res;
10318 rpt_telemetry(myrpt,COMPLETE,NULL);
10319 return 0;
10322 static int attempt_reconnect(struct rpt *myrpt, struct rpt_link *l)
10324 char *val, *s, *s1, *s2, *tele;
10325 char tmp[300], deststr[300] = "";
10326 char sx[320],*sy;
10329 val = node_lookup(myrpt,l->name);
10330 if (!val)
10332 fprintf(stderr,"attempt_reconnect: cannot find node %s\n",l->name);
10333 return -1;
10336 rpt_mutex_lock(&myrpt->lock);
10337 /* remove from queue */
10338 remque((struct qelem *) l);
10339 rpt_mutex_unlock(&myrpt->lock);
10340 strncpy(tmp,val,sizeof(tmp) - 1);
10341 s = tmp;
10342 s1 = strsep(&s,",");
10343 if (!strchr(s1,':') && strchr(s1,'/') && strncasecmp(s1, "local/", 6))
10345 sy = strchr(s1,'/');
10346 *sy = 0;
10347 sprintf(sx,"%s:4569/%s",s1,sy + 1);
10348 s1 = sx;
10350 s2 = strsep(&s,",");
10351 snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
10352 tele = strchr(deststr, '/');
10353 if (!tele) {
10354 fprintf(stderr,"attempt_reconnect:Dial number (%s) must be in format tech/number\n",deststr);
10355 return -1;
10357 *tele++ = 0;
10358 l->elaptime = 0;
10359 l->connecttime = 0;
10360 l->thisconnected = 0;
10361 l->newkey = 0;
10362 l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL);
10363 if (l->chan){
10364 ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
10365 ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
10366 #ifndef NEW_ASTERISK
10367 l->chan->whentohangup = 0;
10368 #endif
10369 l->chan->appl = "Apprpt";
10370 l->chan->data = "(Remote Rx)";
10371 if (option_verbose > 2)
10372 ast_verbose(VERBOSE_PREFIX_3 "rpt (attempt_reconnect) initiating call to %s/%s on %s\n",
10373 deststr, tele, l->chan->name);
10374 if(l->chan->cid.cid_num)
10375 ast_free(l->chan->cid.cid_num);
10376 l->chan->cid.cid_num = ast_strdup(myrpt->name);
10377 ast_call(l->chan,tele,999);
10380 else
10382 if (option_verbose > 2)
10383 ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
10384 deststr,tele,l->chan->name);
10385 return -1;
10387 rpt_mutex_lock(&myrpt->lock);
10388 /* put back in queue */
10389 insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
10390 rpt_mutex_unlock(&myrpt->lock);
10391 ast_log(LOG_WARNING,"Reconnect Attempt to %s in process\n",l->name);
10392 if (!l->phonemode) send_newkey(l->chan);
10393 return 0;
10396 /* 0 return=continue, 1 return = break, -1 return = error */
10397 static void local_dtmf_helper(struct rpt *myrpt,char c_in)
10399 int res;
10400 pthread_attr_t attr;
10401 char cmd[MAXDTMF+1] = "",c;
10404 c = c_in & 0x7f;
10405 if (myrpt->p.archivedir)
10407 char str[100];
10409 sprintf(str,"DTMF,MAIN,%c",c);
10410 donodelog(myrpt,str);
10412 if (c == myrpt->p.endchar)
10414 /* if in simple mode, kill autopatch */
10415 if (myrpt->p.simple && myrpt->callmode)
10417 if(debug)
10418 ast_log(LOG_WARNING, "simple mode autopatch kill\n");
10419 rpt_mutex_lock(&myrpt->lock);
10420 myrpt->callmode = 0;
10421 myrpt->macropatch=0;
10422 channel_revert(myrpt);
10423 rpt_mutex_unlock(&myrpt->lock);
10424 rpt_telemetry(myrpt,TERM,NULL);
10425 return;
10427 rpt_mutex_lock(&myrpt->lock);
10428 myrpt->stopgen = 1;
10429 if (myrpt->cmdnode[0])
10431 myrpt->cmdnode[0] = 0;
10432 myrpt->dtmfidx = -1;
10433 myrpt->dtmfbuf[0] = 0;
10434 rpt_mutex_unlock(&myrpt->lock);
10435 rpt_telemetry(myrpt,COMPLETE,NULL);
10436 return;
10438 else if(!myrpt->inpadtest)
10440 rpt_mutex_unlock(&myrpt->lock);
10441 if (myrpt->p.propagate_phonedtmf)
10442 do_dtmf_phone(myrpt,NULL,c);
10443 return;
10445 else
10446 rpt_mutex_unlock(&myrpt->lock);
10448 rpt_mutex_lock(&myrpt->lock);
10449 if (myrpt->cmdnode[0])
10451 rpt_mutex_unlock(&myrpt->lock);
10452 send_link_dtmf(myrpt,c);
10453 return;
10455 if (!myrpt->p.simple)
10457 if ((!myrpt->inpadtest)&&(c == myrpt->p.funcchar))
10459 myrpt->dtmfidx = 0;
10460 myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
10461 rpt_mutex_unlock(&myrpt->lock);
10462 time(&myrpt->dtmf_time);
10463 return;
10465 else if (((myrpt->inpadtest)||(c != myrpt->p.endchar)) && (myrpt->dtmfidx >= 0))
10467 time(&myrpt->dtmf_time);
10469 if (myrpt->dtmfidx < MAXDTMF)
10471 int src;
10473 myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
10474 myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
10476 strncpy(cmd, myrpt->dtmfbuf, sizeof(cmd) - 1);
10478 rpt_mutex_unlock(&myrpt->lock);
10479 src = SOURCE_RPT;
10480 if (c_in & 0x80) src = SOURCE_ALT;
10481 res = collect_function_digits(myrpt, cmd, src, NULL);
10482 rpt_mutex_lock(&myrpt->lock);
10483 switch(res){
10484 case DC_INDETERMINATE:
10485 break;
10486 case DC_REQ_FLUSH:
10487 myrpt->dtmfidx = 0;
10488 myrpt->dtmfbuf[0] = 0;
10489 break;
10490 case DC_COMPLETE:
10491 case DC_COMPLETEQUIET:
10492 myrpt->totalexecdcommands++;
10493 myrpt->dailyexecdcommands++;
10494 strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
10495 myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
10496 myrpt->dtmfbuf[0] = 0;
10497 myrpt->dtmfidx = -1;
10498 myrpt->dtmf_time = 0;
10499 break;
10501 case DC_ERROR:
10502 default:
10503 myrpt->dtmfbuf[0] = 0;
10504 myrpt->dtmfidx = -1;
10505 myrpt->dtmf_time = 0;
10506 break;
10508 if(res != DC_INDETERMINATE) {
10509 rpt_mutex_unlock(&myrpt->lock);
10510 return;
10515 else /* if simple */
10517 if ((!myrpt->callmode) && (c == myrpt->p.funcchar))
10519 myrpt->callmode = 1;
10520 myrpt->patchnoct = 0;
10521 myrpt->patchquiet = 0;
10522 myrpt->patchfarenddisconnect = 0;
10523 myrpt->patchdialtime = 0;
10524 strncpy(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
10525 myrpt->cidx = 0;
10526 myrpt->exten[myrpt->cidx] = 0;
10527 rpt_mutex_unlock(&myrpt->lock);
10528 pthread_attr_init(&attr);
10529 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
10530 ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *)myrpt);
10531 return;
10534 if (myrpt->callmode == 1)
10536 myrpt->exten[myrpt->cidx++] = c;
10537 myrpt->exten[myrpt->cidx] = 0;
10538 /* if this exists */
10539 if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
10541 /* if this really it, end now */
10542 if (!ast_matchmore_extension(myrpt->pchannel,myrpt->patchcontext,
10543 myrpt->exten,1,NULL))
10545 myrpt->callmode = 2;
10546 rpt_mutex_unlock(&myrpt->lock);
10547 if(!myrpt->patchquiet)
10548 rpt_telemetry(myrpt,PROC,NULL);
10549 return;
10551 else /* othewise, reset timer */
10553 myrpt->calldigittimer = 1;
10556 /* if can continue, do so */
10557 if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
10559 /* call has failed, inform user */
10560 myrpt->callmode = 4;
10562 rpt_mutex_unlock(&myrpt->lock);
10563 return;
10565 if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
10567 myrpt->mydtmf = c;
10569 rpt_mutex_unlock(&myrpt->lock);
10570 if ((myrpt->dtmfidx < 0) && myrpt->p.propagate_phonedtmf)
10571 do_dtmf_phone(myrpt,NULL,c);
10572 return;
10576 /* place an ID event in the telemetry queue */
10578 static void queue_id(struct rpt *myrpt)
10580 if(myrpt->p.idtime){ /* ID time must be non-zero */
10581 myrpt->mustid = myrpt->tailid = 0;
10582 myrpt->idtimer = myrpt->p.idtime; /* Reset our ID timer */
10583 rpt_mutex_unlock(&myrpt->lock);
10584 rpt_telemetry(myrpt,ID,NULL);
10585 rpt_mutex_lock(&myrpt->lock);
10589 /* Scheduler */
10590 /* must be called locked */
10592 static void do_scheduler(struct rpt *myrpt)
10594 int i,res;
10596 #ifdef NEW_ASTERISK
10597 struct ast_tm tmnow;
10598 #else
10599 struct tm tmnow;
10600 #endif
10601 struct ast_variable *skedlist;
10602 char *strs[5],*vp,*val,value[100];
10604 memcpy(&myrpt->lasttv, &myrpt->curtv, sizeof(struct timeval));
10606 if( (res = gettimeofday(&myrpt->curtv, NULL)) < 0)
10607 ast_log(LOG_NOTICE, "Scheduler gettime of day returned: %s\n", strerror(res));
10609 /* Try to get close to a 1 second resolution */
10611 if(myrpt->lasttv.tv_sec == myrpt->curtv.tv_sec)
10612 return;
10614 rpt_localtime(&myrpt->curtv.tv_sec, &tmnow);
10616 /* If midnight, then reset all daily statistics */
10618 if((tmnow.tm_hour == 0)&&(tmnow.tm_min == 0)&&(tmnow.tm_sec == 0)){
10619 myrpt->dailykeyups = 0;
10620 myrpt->dailytxtime = 0;
10621 myrpt->dailykerchunks = 0;
10622 myrpt->dailyexecdcommands = 0;
10625 if(tmnow.tm_sec != 0)
10626 return;
10628 /* Code below only executes once per minute */
10631 /* Don't schedule if remote */
10633 if (myrpt->remote)
10634 return;
10636 /* Don't schedule if disabled */
10638 if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable){
10639 if(debug > 6)
10640 ast_log(LOG_NOTICE, "Scheduler disabled\n");
10641 return;
10644 if(!myrpt->p.skedstanzaname){ /* No stanza means we do nothing */
10645 if(debug > 6)
10646 ast_log(LOG_NOTICE,"No stanza for scheduler in rpt.conf\n");
10647 return;
10650 /* get pointer to linked list of scheduler entries */
10651 skedlist = ast_variable_browse(myrpt->cfg, myrpt->p.skedstanzaname);
10653 if(debug > 6){
10654 ast_log(LOG_NOTICE, "Time now: %02d:%02d %02d %02d %02d\n",
10655 tmnow.tm_hour,tmnow.tm_min,tmnow.tm_mday,tmnow.tm_mon + 1, tmnow.tm_wday);
10657 /* walk the list */
10658 for(; skedlist; skedlist = skedlist->next){
10659 if(debug > 6)
10660 ast_log(LOG_NOTICE, "Scheduler entry %s = %s being considered\n",skedlist->name, skedlist->value);
10661 strncpy(value,skedlist->value,99);
10662 value[99] = 0;
10663 /* point to the substrings for minute, hour, dom, month, and dow */
10664 for( i = 0, vp = value ; i < 5; i++){
10665 if(!*vp)
10666 break;
10667 while((*vp == ' ') || (*vp == 0x09)) /* get rid of any leading white space */
10668 vp++;
10669 strs[i] = vp; /* save pointer to beginning of substring */
10670 while((*vp != ' ') && (*vp != 0x09) && (*vp != 0)) /* skip over substring */
10671 vp++;
10672 if(*vp)
10673 *vp++ = 0; /* mark end of substring */
10675 if(debug > 6)
10676 ast_log(LOG_NOTICE, "i = %d, min = %s, hour = %s, mday=%s, mon=%s, wday=%s\n",i,
10677 strs[0], strs[1], strs[2], strs[3], strs[4]);
10678 if(i == 5){
10679 if((*strs[0] != '*')&&(atoi(strs[0]) != tmnow.tm_min))
10680 continue;
10681 if((*strs[1] != '*')&&(atoi(strs[1]) != tmnow.tm_hour))
10682 continue;
10683 if((*strs[2] != '*')&&(atoi(strs[2]) != tmnow.tm_mday))
10684 continue;
10685 if((*strs[3] != '*')&&(atoi(strs[3]) != tmnow.tm_mon + 1))
10686 continue;
10687 if(atoi(strs[4]) == 7)
10688 strs[4] = "0";
10689 if((*strs[4] != '*')&&(atoi(strs[4]) != tmnow.tm_wday))
10690 continue;
10691 if(debug)
10692 ast_log(LOG_NOTICE, "Executing scheduler entry %s = %s\n", skedlist->name, skedlist->value);
10693 if(atoi(skedlist->name) == 0)
10694 return; /* Zero is reserved for the startup macro */
10695 val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, skedlist->name);
10696 if (!val){
10697 ast_log(LOG_WARNING,"Scheduler could not find macro %s\n",skedlist->name);
10698 return; /* Macro not found */
10700 if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val)){
10701 ast_log(LOG_WARNING, "Scheduler could not execute macro %s: Macro buffer full\n",
10702 skedlist->name);
10703 return; /* Macro buffer full */
10705 myrpt->macrotimer = MACROTIME;
10706 strncat(myrpt->macrobuf,val,MAXMACRO - 1);
10708 else{
10709 ast_log(LOG_WARNING,"Malformed scheduler entry in rpt.conf: %s = %s\n",
10710 skedlist->name, skedlist->value);
10716 /* single thread with one file (request) to dial */
10717 static void *rpt(void *this)
10719 struct rpt *myrpt = (struct rpt *)this;
10720 char *tele,*idtalkover,c,myfirst,*p;
10721 int ms = MSWAIT,i,lasttx=0,val,remrx=0,identqueued,othertelemqueued;
10722 int tailmessagequeued,ctqueued,dtmfed,lastmyrx,localmsgqueued;
10723 struct ast_channel *who;
10724 DAHDI_CONFINFO ci; /* conference info */
10725 time_t t;
10726 struct rpt_link *l,*m;
10727 struct rpt_tele *telem;
10728 char tmpstr[300],lstr[MAXLINKLIST];
10731 if (myrpt->p.archivedir) mkdir(myrpt->p.archivedir,0600);
10732 sprintf(tmpstr,"%s/%s",myrpt->p.archivedir,myrpt->name);
10733 mkdir(tmpstr,0600);
10734 rpt_mutex_lock(&myrpt->lock);
10736 telem = myrpt->tele.next;
10737 while(telem != &myrpt->tele)
10739 ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
10740 telem = telem->next;
10742 rpt_mutex_unlock(&myrpt->lock);
10743 /* find our index, and load the vars initially */
10744 for(i = 0; i < nrpts; i++)
10746 if (&rpt_vars[i] == myrpt)
10748 load_rpt_vars(i,0);
10749 break;
10753 rpt_mutex_lock(&myrpt->lock);
10754 while(myrpt->xlink)
10756 myrpt->xlink = 3;
10757 rpt_mutex_unlock(&myrpt->lock);
10758 usleep(100000);
10759 rpt_mutex_lock(&myrpt->lock);
10761 if ((!strcmp(myrpt->remoterig, remote_rig_rbi)) &&
10762 (ioperm(myrpt->p.iobase,1,1) == -1))
10764 rpt_mutex_unlock(&myrpt->lock);
10765 ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase);
10766 myrpt->rpt_thread = AST_PTHREADT_STOP;
10767 pthread_exit(NULL);
10769 strncpy(tmpstr,myrpt->rxchanname,sizeof(tmpstr) - 1);
10770 tele = strchr(tmpstr,'/');
10771 if (!tele)
10773 fprintf(stderr,"rpt:Rxchannel Dial number (%s) must be in format tech/number\n",myrpt->rxchanname);
10774 rpt_mutex_unlock(&myrpt->lock);
10775 myrpt->rpt_thread = AST_PTHREADT_STOP;
10776 pthread_exit(NULL);
10778 *tele++ = 0;
10779 myrpt->rxchannel = ast_request(tmpstr,AST_FORMAT_SLINEAR,tele,NULL);
10780 myrpt->dahdirxchannel = NULL;
10781 if (!strcasecmp(tmpstr,"DAHDI"))
10782 myrpt->dahdirxchannel = myrpt->rxchannel;
10783 if (myrpt->rxchannel)
10785 if (myrpt->rxchannel->_state == AST_STATE_BUSY)
10787 fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
10788 rpt_mutex_unlock(&myrpt->lock);
10789 ast_hangup(myrpt->rxchannel);
10790 myrpt->rpt_thread = AST_PTHREADT_STOP;
10791 pthread_exit(NULL);
10793 ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
10794 ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
10795 #ifdef AST_CDR_FLAG_POST_DISABLED
10796 if (myrpt->rxchannel->cdr)
10797 ast_set_flag(myrpt->rxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10798 #endif
10799 #ifndef NEW_ASTERISK
10800 myrpt->rxchannel->whentohangup = 0;
10801 #endif
10802 myrpt->rxchannel->appl = "Apprpt";
10803 myrpt->rxchannel->data = "(Repeater Rx)";
10804 if (option_verbose > 2)
10805 ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
10806 tmpstr,tele,myrpt->rxchannel->name);
10807 ast_call(myrpt->rxchannel,tele,999);
10808 if (myrpt->rxchannel->_state != AST_STATE_UP)
10810 rpt_mutex_unlock(&myrpt->lock);
10811 ast_hangup(myrpt->rxchannel);
10812 myrpt->rpt_thread = AST_PTHREADT_STOP;
10813 pthread_exit(NULL);
10816 else
10818 fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
10819 rpt_mutex_unlock(&myrpt->lock);
10820 myrpt->rpt_thread = AST_PTHREADT_STOP;
10821 pthread_exit(NULL);
10823 myrpt->dahditxchannel = NULL;
10824 if (myrpt->txchanname)
10826 strncpy(tmpstr,myrpt->txchanname,sizeof(tmpstr) - 1);
10827 tele = strchr(tmpstr,'/');
10828 if (!tele)
10830 fprintf(stderr,"rpt:Txchannel Dial number (%s) must be in format tech/number\n",myrpt->txchanname);
10831 rpt_mutex_unlock(&myrpt->lock);
10832 ast_hangup(myrpt->rxchannel);
10833 myrpt->rpt_thread = AST_PTHREADT_STOP;
10834 pthread_exit(NULL);
10836 *tele++ = 0;
10837 myrpt->txchannel = ast_request(tmpstr,AST_FORMAT_SLINEAR,tele,NULL);
10838 if (!strcasecmp(tmpstr,"DAHDI"))
10839 myrpt->dahditxchannel = myrpt->txchannel;
10840 if (myrpt->txchannel)
10842 if (myrpt->txchannel->_state == AST_STATE_BUSY)
10844 fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
10845 rpt_mutex_unlock(&myrpt->lock);
10846 ast_hangup(myrpt->txchannel);
10847 ast_hangup(myrpt->rxchannel);
10848 myrpt->rpt_thread = AST_PTHREADT_STOP;
10849 pthread_exit(NULL);
10851 ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
10852 ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
10853 #ifdef AST_CDR_FLAG_POST_DISABLED
10854 if (myrpt->txchannel->cdr)
10855 ast_set_flag(myrpt->txchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10856 #endif
10857 #ifndef NEW_ASTERISK
10858 myrpt->txchannel->whentohangup = 0;
10859 #endif
10860 myrpt->txchannel->appl = "Apprpt";
10861 myrpt->txchannel->data = "(Repeater Tx)";
10862 if (option_verbose > 2)
10863 ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
10864 tmpstr,tele,myrpt->txchannel->name);
10865 ast_call(myrpt->txchannel,tele,999);
10866 if (myrpt->rxchannel->_state != AST_STATE_UP)
10868 rpt_mutex_unlock(&myrpt->lock);
10869 ast_hangup(myrpt->rxchannel);
10870 ast_hangup(myrpt->txchannel);
10871 myrpt->rpt_thread = AST_PTHREADT_STOP;
10872 pthread_exit(NULL);
10875 else
10877 fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
10878 rpt_mutex_unlock(&myrpt->lock);
10879 ast_hangup(myrpt->rxchannel);
10880 myrpt->rpt_thread = AST_PTHREADT_STOP;
10881 pthread_exit(NULL);
10884 else
10886 myrpt->txchannel = myrpt->rxchannel;
10887 if (!strncasecmp(myrpt->rxchanname,"DAHDI",3))
10888 myrpt->dahditxchannel = myrpt->txchannel;
10890 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
10891 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
10892 /* allocate a pseudo-channel thru asterisk */
10893 myrpt->pchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
10894 if (!myrpt->pchannel)
10896 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
10897 rpt_mutex_unlock(&myrpt->lock);
10898 if (myrpt->txchannel != myrpt->rxchannel)
10899 ast_hangup(myrpt->txchannel);
10900 ast_hangup(myrpt->rxchannel);
10901 myrpt->rpt_thread = AST_PTHREADT_STOP;
10902 pthread_exit(NULL);
10904 #ifdef AST_CDR_FLAG_POST_DISABLED
10905 if (myrpt->pchannel->cdr)
10906 ast_set_flag(myrpt->pchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10907 #endif
10908 if (!myrpt->dahdirxchannel) myrpt->dahdirxchannel = myrpt->pchannel;
10909 if (!myrpt->dahditxchannel)
10911 /* allocate a pseudo-channel thru asterisk */
10912 myrpt->dahditxchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
10913 if (!myrpt->dahditxchannel)
10915 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
10916 rpt_mutex_unlock(&myrpt->lock);
10917 if (myrpt->txchannel != myrpt->rxchannel)
10918 ast_hangup(myrpt->txchannel);
10919 ast_hangup(myrpt->rxchannel);
10920 myrpt->rpt_thread = AST_PTHREADT_STOP;
10921 pthread_exit(NULL);
10923 ast_set_read_format(myrpt->dahditxchannel,AST_FORMAT_SLINEAR);
10924 ast_set_write_format(myrpt->dahditxchannel,AST_FORMAT_SLINEAR);
10925 #ifdef AST_CDR_FLAG_POST_DISABLED
10926 if (myrpt->dahditxchannel->cdr)
10927 ast_set_flag(myrpt->dahditxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10928 #endif
10930 /* allocate a pseudo-channel thru asterisk */
10931 myrpt->monchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
10932 if (!myrpt->monchannel)
10934 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
10935 rpt_mutex_unlock(&myrpt->lock);
10936 if (myrpt->txchannel != myrpt->rxchannel)
10937 ast_hangup(myrpt->txchannel);
10938 ast_hangup(myrpt->rxchannel);
10939 myrpt->rpt_thread = AST_PTHREADT_STOP;
10940 pthread_exit(NULL);
10942 ast_set_read_format(myrpt->monchannel,AST_FORMAT_SLINEAR);
10943 ast_set_write_format(myrpt->monchannel,AST_FORMAT_SLINEAR);
10944 #ifdef AST_CDR_FLAG_POST_DISABLED
10945 if (myrpt->monchannel->cdr)
10946 ast_set_flag(myrpt->monchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10947 #endif
10948 /* make a conference for the tx */
10949 ci.chan = 0;
10950 ci.confno = -1; /* make a new conf */
10951 ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER;
10952 /* first put the channel on the conference in proper mode */
10953 if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
10955 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
10956 rpt_mutex_unlock(&myrpt->lock);
10957 ast_hangup(myrpt->pchannel);
10958 ast_hangup(myrpt->monchannel);
10959 if (myrpt->txchannel != myrpt->rxchannel)
10960 ast_hangup(myrpt->txchannel);
10961 ast_hangup(myrpt->rxchannel);
10962 myrpt->rpt_thread = AST_PTHREADT_STOP;
10963 pthread_exit(NULL);
10965 /* save tx conference number */
10966 myrpt->txconf = ci.confno;
10967 /* make a conference for the pseudo */
10968 ci.chan = 0;
10969 ci.confno = -1; /* make a new conf */
10970 ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? DAHDI_CONF_CONFANNMON :
10971 (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
10972 /* first put the channel on the conference in announce mode */
10973 if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
10975 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
10976 rpt_mutex_unlock(&myrpt->lock);
10977 ast_hangup(myrpt->pchannel);
10978 ast_hangup(myrpt->monchannel);
10979 if (myrpt->txchannel != myrpt->rxchannel)
10980 ast_hangup(myrpt->txchannel);
10981 ast_hangup(myrpt->rxchannel);
10982 myrpt->rpt_thread = AST_PTHREADT_STOP;
10983 pthread_exit(NULL);
10985 /* save pseudo channel conference number */
10986 myrpt->conf = ci.confno;
10987 /* make a conference for the pseudo */
10988 ci.chan = 0;
10989 if ((strstr(myrpt->txchannel->name,"pseudo") == NULL) &&
10990 (myrpt->dahditxchannel == myrpt->txchannel))
10992 /* get tx channel's port number */
10993 if (ioctl(myrpt->txchannel->fds[0],DAHDI_CHANNO,&ci.confno) == -1)
10995 ast_log(LOG_WARNING, "Unable to set tx channel's chan number\n");
10996 rpt_mutex_unlock(&myrpt->lock);
10997 ast_hangup(myrpt->pchannel);
10998 ast_hangup(myrpt->monchannel);
10999 if (myrpt->txchannel != myrpt->rxchannel)
11000 ast_hangup(myrpt->txchannel);
11001 ast_hangup(myrpt->rxchannel);
11002 myrpt->rpt_thread = AST_PTHREADT_STOP;
11003 pthread_exit(NULL);
11005 ci.confmode = DAHDI_CONF_MONITORTX;
11007 else
11009 ci.confno = myrpt->txconf;
11010 ci.confmode = DAHDI_CONF_CONFANNMON;
11012 /* first put the channel on the conference in announce mode */
11013 if (ioctl(myrpt->monchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11015 ast_log(LOG_WARNING, "Unable to set conference mode for monitor\n");
11016 rpt_mutex_unlock(&myrpt->lock);
11017 ast_hangup(myrpt->pchannel);
11018 ast_hangup(myrpt->monchannel);
11019 if (myrpt->txchannel != myrpt->rxchannel)
11020 ast_hangup(myrpt->txchannel);
11021 ast_hangup(myrpt->rxchannel);
11022 myrpt->rpt_thread = AST_PTHREADT_STOP;
11023 pthread_exit(NULL);
11025 /* allocate a pseudo-channel thru asterisk */
11026 myrpt->parrotchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
11027 if (!myrpt->parrotchannel)
11029 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
11030 rpt_mutex_unlock(&myrpt->lock);
11031 if (myrpt->txchannel != myrpt->rxchannel)
11032 ast_hangup(myrpt->txchannel);
11033 ast_hangup(myrpt->rxchannel);
11034 myrpt->rpt_thread = AST_PTHREADT_STOP;
11035 pthread_exit(NULL);
11037 ast_set_read_format(myrpt->parrotchannel,AST_FORMAT_SLINEAR);
11038 ast_set_write_format(myrpt->parrotchannel,AST_FORMAT_SLINEAR);
11039 #ifdef AST_CDR_FLAG_POST_DISABLED
11040 if (myrpt->parrotchannel->cdr)
11041 ast_set_flag(myrpt->parrotchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11042 #endif
11043 /* allocate a pseudo-channel thru asterisk */
11044 myrpt->voxchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
11045 if (!myrpt->voxchannel)
11047 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
11048 rpt_mutex_unlock(&myrpt->lock);
11049 if (myrpt->txchannel != myrpt->rxchannel)
11050 ast_hangup(myrpt->txchannel);
11051 ast_hangup(myrpt->rxchannel);
11052 myrpt->rpt_thread = AST_PTHREADT_STOP;
11053 pthread_exit(NULL);
11055 ast_set_read_format(myrpt->voxchannel,AST_FORMAT_SLINEAR);
11056 ast_set_write_format(myrpt->voxchannel,AST_FORMAT_SLINEAR);
11057 #ifdef AST_CDR_FLAG_POST_DISABLED
11058 if (myrpt->voxchannel->cdr)
11059 ast_set_flag(myrpt->voxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11060 #endif
11061 /* allocate a pseudo-channel thru asterisk */
11062 myrpt->txpchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
11063 if (!myrpt->txpchannel)
11065 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
11066 rpt_mutex_unlock(&myrpt->lock);
11067 ast_hangup(myrpt->pchannel);
11068 ast_hangup(myrpt->monchannel);
11069 if (myrpt->txchannel != myrpt->rxchannel)
11070 ast_hangup(myrpt->txchannel);
11071 ast_hangup(myrpt->rxchannel);
11072 myrpt->rpt_thread = AST_PTHREADT_STOP;
11073 pthread_exit(NULL);
11075 #ifdef AST_CDR_FLAG_POST_DISABLED
11076 if (myrpt->txpchannel->cdr)
11077 ast_set_flag(myrpt->txpchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11078 #endif
11079 /* make a conference for the tx */
11080 ci.chan = 0;
11081 ci.confno = myrpt->txconf;
11082 ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER ;
11083 /* first put the channel on the conference in proper mode */
11084 if (ioctl(myrpt->txpchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11086 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
11087 rpt_mutex_unlock(&myrpt->lock);
11088 ast_hangup(myrpt->txpchannel);
11089 ast_hangup(myrpt->monchannel);
11090 if (myrpt->txchannel != myrpt->rxchannel)
11091 ast_hangup(myrpt->txchannel);
11092 ast_hangup(myrpt->rxchannel);
11093 myrpt->rpt_thread = AST_PTHREADT_STOP;
11094 pthread_exit(NULL);
11096 /* if serial io port, open it */
11097 myrpt->iofd = -1;
11098 if (myrpt->p.ioport && ((myrpt->iofd = openserial(myrpt,myrpt->p.ioport)) == -1))
11100 ast_log(LOG_ERROR, "Unable to open %s\n",myrpt->p.ioport);
11101 rpt_mutex_unlock(&myrpt->lock);
11102 ast_hangup(myrpt->pchannel);
11103 if (myrpt->txchannel != myrpt->rxchannel)
11104 ast_hangup(myrpt->txchannel);
11105 ast_hangup(myrpt->rxchannel);
11106 pthread_exit(NULL);
11108 /* Now, the idea here is to copy from the physical rx channel buffer
11109 into the pseudo tx buffer, and from the pseudo rx buffer into the
11110 tx channel buffer */
11111 myrpt->links.next = &myrpt->links;
11112 myrpt->links.prev = &myrpt->links;
11113 myrpt->tailtimer = 0;
11114 myrpt->totimer = 0;
11115 myrpt->tmsgtimer = myrpt->p.tailmessagetime;
11116 myrpt->idtimer = myrpt->p.politeid;
11117 myrpt->mustid = myrpt->tailid = 0;
11118 myrpt->callmode = 0;
11119 myrpt->tounkeyed = 0;
11120 myrpt->tonotify = 0;
11121 myrpt->retxtimer = 0;
11122 myrpt->rerxtimer = 0;
11123 myrpt->skedtimer = 0;
11124 myrpt->tailevent = 0;
11125 lasttx = 0;
11126 myrpt->keyed = 0;
11127 myrpt->txkeyed = 0;
11128 time(&myrpt->lastkeyedtime);
11129 myrpt->lastkeyedtime -= RPT_LOCKOUT_SECS;
11130 time(&myrpt->lasttxkeyedtime);
11131 myrpt->lasttxkeyedtime -= RPT_LOCKOUT_SECS;
11132 idtalkover = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "idtalkover");
11133 myrpt->dtmfidx = -1;
11134 myrpt->dtmfbuf[0] = 0;
11135 myrpt->rem_dtmfidx = -1;
11136 myrpt->rem_dtmfbuf[0] = 0;
11137 myrpt->dtmf_time = 0;
11138 myrpt->rem_dtmf_time = 0;
11139 myrpt->inpadtest = 0;
11140 myrpt->disgorgetime = 0;
11141 myrpt->lastnodewhichkeyedusup[0] = '\0';
11142 myrpt->dailytxtime = 0;
11143 myrpt->totaltxtime = 0;
11144 myrpt->dailykeyups = 0;
11145 myrpt->totalkeyups = 0;
11146 myrpt->dailykerchunks = 0;
11147 myrpt->totalkerchunks = 0;
11148 myrpt->dailyexecdcommands = 0;
11149 myrpt->totalexecdcommands = 0;
11150 myrpt->timeouts = 0;
11151 myrpt->exten[0] = '\0';
11152 myrpt->lastdtmfcommand[0] = '\0';
11153 voxinit_rpt(myrpt,1);
11154 myrpt->wasvox = 0;
11155 if (myrpt->p.startupmacro)
11157 snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
11159 rpt_mutex_unlock(&myrpt->lock);
11160 val = 1;
11161 ast_channel_setoption(myrpt->rxchannel,AST_OPTION_RELAXDTMF,&val,sizeof(char),0);
11162 val = 1;
11163 ast_channel_setoption(myrpt->rxchannel,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0);
11164 if (myrpt->p.archivedir) donodelog(myrpt,"STARTUP");
11165 dtmfed = 0;
11166 if (myrpt->remoterig && !ISRIG_RTX(myrpt->remoterig)) setrem(myrpt);
11167 lastmyrx = 0;
11168 myfirst = 0;
11169 while (ms >= 0)
11171 struct ast_frame *f,*f1,*f2;
11172 struct ast_channel *cs[300],*cs1[300];
11173 int totx=0,elap=0,n,x,toexit=0;
11175 /* DEBUG Dump */
11176 if((myrpt->disgorgetime) && (time(NULL) >= myrpt->disgorgetime)){
11177 struct rpt_link *dl;
11178 struct rpt_tele *dt;
11180 myrpt->disgorgetime = 0;
11181 ast_log(LOG_NOTICE,"********** Variable Dump Start (app_rpt) **********\n");
11182 ast_log(LOG_NOTICE,"totx = %d\n",totx);
11183 ast_log(LOG_NOTICE,"remrx = %d\n",remrx);
11184 ast_log(LOG_NOTICE,"lasttx = %d\n",lasttx);
11185 ast_log(LOG_NOTICE,"elap = %d\n",elap);
11186 ast_log(LOG_NOTICE,"toexit = %d\n",toexit);
11188 ast_log(LOG_NOTICE,"myrpt->keyed = %d\n",myrpt->keyed);
11189 ast_log(LOG_NOTICE,"myrpt->localtx = %d\n",myrpt->localtx);
11190 ast_log(LOG_NOTICE,"myrpt->callmode = %d\n",myrpt->callmode);
11191 ast_log(LOG_NOTICE,"myrpt->mustid = %d\n",myrpt->mustid);
11192 ast_log(LOG_NOTICE,"myrpt->tounkeyed = %d\n",myrpt->tounkeyed);
11193 ast_log(LOG_NOTICE,"myrpt->tonotify = %d\n",myrpt->tonotify);
11194 ast_log(LOG_NOTICE,"myrpt->retxtimer = %ld\n",myrpt->retxtimer);
11195 ast_log(LOG_NOTICE,"myrpt->totimer = %d\n",myrpt->totimer);
11196 ast_log(LOG_NOTICE,"myrpt->tailtimer = %d\n",myrpt->tailtimer);
11197 ast_log(LOG_NOTICE,"myrpt->tailevent = %d\n",myrpt->tailevent);
11199 dl = myrpt->links.next;
11200 while(dl != &myrpt->links){
11201 ast_log(LOG_NOTICE,"*** Link Name: %s ***\n",dl->name);
11202 ast_log(LOG_NOTICE," link->lasttx %d\n",dl->lasttx);
11203 ast_log(LOG_NOTICE," link->lastrx %d\n",dl->lastrx);
11204 ast_log(LOG_NOTICE," link->connected %d\n",dl->connected);
11205 ast_log(LOG_NOTICE," link->hasconnected %d\n",dl->hasconnected);
11206 ast_log(LOG_NOTICE," link->outbound %d\n",dl->outbound);
11207 ast_log(LOG_NOTICE," link->disced %d\n",dl->disced);
11208 ast_log(LOG_NOTICE," link->killme %d\n",dl->killme);
11209 ast_log(LOG_NOTICE," link->disctime %ld\n",dl->disctime);
11210 ast_log(LOG_NOTICE," link->retrytimer %ld\n",dl->retrytimer);
11211 ast_log(LOG_NOTICE," link->retries = %d\n",dl->retries);
11212 ast_log(LOG_NOTICE," link->reconnects = %d\n",dl->reconnects);
11213 ast_log(LOG_NOTICE," link->newkey = %d\n",dl->newkey);
11214 dl = dl->next;
11217 dt = myrpt->tele.next;
11218 if(dt != &myrpt->tele)
11219 ast_log(LOG_NOTICE,"*** Telemetry Queue ***\n");
11220 while(dt != &myrpt->tele){
11221 ast_log(LOG_NOTICE," Telemetry mode: %d\n",dt->mode);
11222 dt = dt->next;
11224 ast_log(LOG_NOTICE,"******* Variable Dump End (app_rpt) *******\n");
11229 if (myrpt->reload)
11231 struct rpt_tele *telem;
11233 rpt_mutex_lock(&myrpt->lock);
11234 telem = myrpt->tele.next;
11235 while(telem != &myrpt->tele)
11237 ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
11238 telem = telem->next;
11240 myrpt->reload = 0;
11241 rpt_mutex_unlock(&myrpt->lock);
11242 usleep(10000);
11243 /* find our index, and load the vars */
11244 for(i = 0; i < nrpts; i++)
11246 if (&rpt_vars[i] == myrpt)
11248 load_rpt_vars(i,0);
11249 break;
11254 rpt_mutex_lock(&myrpt->lock);
11255 if (ast_check_hangup(myrpt->rxchannel)) break;
11256 if (ast_check_hangup(myrpt->txchannel)) break;
11257 if (ast_check_hangup(myrpt->pchannel)) break;
11258 if (ast_check_hangup(myrpt->monchannel)) break;
11259 if (myrpt->parrotchannel &&
11260 ast_check_hangup(myrpt->parrotchannel)) break;
11261 if (myrpt->voxchannel &&
11262 ast_check_hangup(myrpt->voxchannel)) break;
11263 if (ast_check_hangup(myrpt->txpchannel)) break;
11264 if (myrpt->dahditxchannel && ast_check_hangup(myrpt->dahditxchannel)) break;
11266 /* Set local tx with keyed */
11267 myrpt->localtx = myrpt->keyed;
11268 /* If someone's connected, and they're transmitting from their end to us, set remrx true */
11269 l = myrpt->links.next;
11270 remrx = 0;
11271 while(l != &myrpt->links)
11273 if (l->lastrx){
11274 remrx = 1;
11275 if(l->name[0] != '0') /* Ignore '0' nodes */
11276 strcpy(myrpt->lastnodewhichkeyedusup, l->name); /* Note the node which is doing the key up */
11278 l = l->next;
11280 /* Create a "must_id" flag for the cleanup ID */
11281 if(myrpt->p.idtime) /* ID time must be non-zero */
11282 myrpt->mustid |= (myrpt->idtimer) && (myrpt->keyed || remrx) ;
11283 /* Build a fresh totx from myrpt->keyed and autopatch activated */
11284 /* If full duplex, add local tx to totx */
11285 if (myrpt->p.duplex > 1)
11287 totx = myrpt->callmode;
11288 totx = totx || myrpt->localtx;
11290 else
11292 int myrx = myrpt->localtx || remrx || (!myrpt->callmode);
11294 if (lastmyrx != myrx)
11296 voxinit_rpt(myrpt,!myrx);
11297 lastmyrx = myrx;
11299 totx = 0;
11300 if (myrpt->callmode && (myrpt->voxtotimer <= 0))
11302 if (myrpt->voxtostate)
11304 myrpt->voxtotimer = myrpt->p.voxtimeout_ms;
11305 myrpt->voxtostate = 0;
11307 else
11309 myrpt->voxtotimer = myrpt->p.voxrecover_ms;
11310 myrpt->voxtostate = 1;
11313 if (!myrpt->voxtostate)
11314 totx = myrpt->callmode && myrpt->wasvox;
11316 /* Traverse the telemetry list to see what's queued */
11317 identqueued = 0;
11318 localmsgqueued = 0;
11319 othertelemqueued = 0;
11320 tailmessagequeued = 0;
11321 ctqueued = 0;
11322 telem = myrpt->tele.next;
11323 while(telem != &myrpt->tele)
11325 if((telem->mode == ID) || (telem->mode == IDTALKOVER)){
11326 identqueued = 1; /* Identification telemetry */
11328 else if(telem->mode == TAILMSG)
11330 tailmessagequeued = 1; /* Tail message telemetry */
11332 else if(telem->mode == STATS_TIME_LOCAL)
11334 localmsgqueued = 1; /* Local message */
11336 else
11338 if ((telem->mode != UNKEY) && (telem->mode != LINKUNKEY))
11339 othertelemqueued = 1; /* Other telemetry */
11340 else
11341 ctqueued = 1; /* Courtesy tone telemetry */
11343 telem = telem->next;
11346 /* Add in any "other" telemetry, unless specified otherwise */
11347 if (!myrpt->p.notelemtx) totx = totx || othertelemqueued;
11348 /* Update external (to links) transmitter PTT state with everything but */
11349 /* ID, CT, local messages, and tailmessage telemetry */
11350 myrpt->exttx = totx;
11351 totx = totx || myrpt->dtmf_local_timer;
11352 /* If half or 3/4 duplex, add localtx to external link tx */
11353 if (myrpt->p.duplex < 2) myrpt->exttx = myrpt->exttx || myrpt->localtx;
11354 /* Add in ID telemetry to local transmitter */
11355 totx = totx || remrx;
11356 /* If 3/4 or full duplex, add in ident, CT telemetry, and local messages */
11357 if (myrpt->p.duplex > 0)
11358 totx = totx || identqueued || ctqueued || localmsgqueued;
11359 /* If full duplex, add local dtmf stuff active */
11360 if (myrpt->p.duplex > 1)
11362 totx = totx || (myrpt->dtmfidx > -1) ||
11363 myrpt->cmdnode[0];
11365 /* add in parrot stuff */
11366 totx = totx || (myrpt->parrotstate > 1);
11367 /* Reset time out timer variables if there is no activity */
11368 if (!totx)
11370 myrpt->totimer = myrpt->p.totime;
11371 myrpt->tounkeyed = 0;
11372 myrpt->tonotify = 0;
11374 else{
11375 myrpt->tailtimer = myrpt->p.s[myrpt->p.sysstate_cur].alternatetail ?
11376 myrpt->p.althangtime : /* Initialize tail timer */
11377 myrpt->p.hangtime;
11379 /* Disable the local transmitter if we are timed out */
11380 totx = totx && myrpt->totimer;
11381 /* if timed-out and not said already, say it */
11382 if ((!myrpt->totimer) && (!myrpt->tonotify))
11384 myrpt->tonotify = 1;
11385 myrpt->timeouts++;
11386 rpt_mutex_unlock(&myrpt->lock);
11387 rpt_telemetry(myrpt,TIMEOUT,NULL);
11388 rpt_mutex_lock(&myrpt->lock);
11391 /* If unkey and re-key, reset time out timer */
11392 if ((!totx) && (!myrpt->totimer) && (!myrpt->tounkeyed) && (!myrpt->keyed))
11394 myrpt->tounkeyed = 1;
11396 if ((!totx) && (!myrpt->totimer) && myrpt->tounkeyed && myrpt->keyed)
11398 myrpt->totimer = myrpt->p.totime;
11399 myrpt->tounkeyed = 0;
11400 myrpt->tonotify = 0;
11401 rpt_mutex_unlock(&myrpt->lock);
11402 continue;
11404 /* if timed-out and in circuit busy after call */
11405 if ((!totx) && (!myrpt->totimer) && (myrpt->callmode == 4))
11407 if(debug)
11408 ast_log(LOG_NOTICE, "timed-out and in circuit busy after call\n");
11409 myrpt->callmode = 0;
11410 myrpt->macropatch=0;
11411 channel_revert(myrpt);
11413 /* get rid of tail if timed out */
11414 if (!myrpt->totimer) myrpt->tailtimer = 0;
11415 /* if not timed-out, add in tail */
11416 if (myrpt->totimer) totx = totx || myrpt->tailtimer;
11417 /* If user or links key up or are keyed up over standard ID, switch to talkover ID, if one is defined */
11418 /* If tail message, kill the message if someone keys up over it */
11419 if ((myrpt->keyed || remrx) && ((identqueued && idtalkover) || (tailmessagequeued))) {
11420 int hasid = 0,hastalkover = 0;
11422 telem = myrpt->tele.next;
11423 while(telem != &myrpt->tele){
11424 if(telem->mode == ID){
11425 if (telem->chan) ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
11426 hasid = 1;
11428 if(telem->mode == TAILMSG){
11429 if (telem->chan) ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
11431 if (telem->mode == IDTALKOVER) hastalkover = 1;
11432 telem = telem->next;
11434 rpt_mutex_unlock(&myrpt->lock);
11435 if (hasid && (!hastalkover)) rpt_telemetry(myrpt, IDTALKOVER, NULL); /* Start Talkover ID */
11436 rpt_mutex_lock(&myrpt->lock);
11438 /* Try to be polite */
11439 /* If the repeater has been inactive for longer than the ID time, do an initial ID in the tail*/
11440 /* If within 30 seconds of the time to ID, try do it in the tail */
11441 /* else if at ID time limit, do it right over the top of them */
11442 /* Lastly, if the repeater has been keyed, and the ID timer is expired, do a clean up ID */
11443 if(myrpt->mustid && (!myrpt->idtimer))
11444 queue_id(myrpt);
11446 if ((myrpt->p.idtime && totx && (!myrpt->exttx) &&
11447 (myrpt->idtimer <= myrpt->p.politeid) && myrpt->tailtimer)) /* ID time must be non-zero */
11449 myrpt->tailid = 1;
11452 /* If tail timer expires, then check for tail messages */
11454 if(myrpt->tailevent){
11455 myrpt->tailevent = 0;
11456 if(myrpt->tailid){
11457 totx = 1;
11458 queue_id(myrpt);
11460 else if ((myrpt->p.tailmessages[0]) &&
11461 (myrpt->p.tailmessagetime) && (myrpt->tmsgtimer == 0)){
11462 totx = 1;
11463 myrpt->tmsgtimer = myrpt->p.tailmessagetime;
11464 rpt_mutex_unlock(&myrpt->lock);
11465 rpt_telemetry(myrpt, TAILMSG, NULL);
11466 rpt_mutex_lock(&myrpt->lock);
11470 /* Main TX control */
11472 /* let telemetry transmit anyway (regardless of timeout) */
11473 if (myrpt->p.duplex > 0) totx = totx || (myrpt->tele.next != &myrpt->tele);
11474 totx = totx && !myrpt->p.s[myrpt->p.sysstate_cur].txdisable;
11475 myrpt->txrealkeyed = totx;
11476 totx = totx || (!AST_LIST_EMPTY(&myrpt->txq));
11477 if (totx && (!lasttx))
11479 char mydate[100],myfname[100];
11480 time_t myt;
11482 if (myrpt->monstream) ast_closestream(myrpt->monstream);
11483 if (myrpt->p.archivedir)
11485 long blocksleft;
11487 time(&myt);
11488 strftime(mydate,sizeof(mydate) - 1,"%Y%m%d%H%M%S",
11489 localtime(&myt));
11490 sprintf(myfname,"%s/%s/%s",myrpt->p.archivedir,
11491 myrpt->name,mydate);
11492 myrpt->monstream = ast_writefile(myfname,"wav49",
11493 "app_rpt Air Archive",O_CREAT | O_APPEND,0,0600);
11494 if (myrpt->p.monminblocks)
11496 blocksleft = diskavail(myrpt);
11497 if (blocksleft >= myrpt->p.monminblocks)
11498 donodelog(myrpt,"TXKEY,MAIN");
11499 } else donodelog(myrpt,"TXKEY,MAIN");
11501 lasttx = 1;
11502 myrpt->txkeyed = 1;
11503 time(&myrpt->lasttxkeyedtime);
11504 myrpt->dailykeyups++;
11505 myrpt->totalkeyups++;
11506 rpt_mutex_unlock(&myrpt->lock);
11507 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
11508 rpt_mutex_lock(&myrpt->lock);
11510 if ((!totx) && lasttx)
11512 if (myrpt->monstream) ast_closestream(myrpt->monstream);
11513 myrpt->monstream = NULL;
11515 lasttx = 0;
11516 myrpt->txkeyed = 0;
11517 time(&myrpt->lasttxkeyedtime);
11518 rpt_mutex_unlock(&myrpt->lock);
11519 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
11520 rpt_mutex_lock(&myrpt->lock);
11521 donodelog(myrpt,"TXUNKEY,MAIN");
11523 time(&t);
11524 /* if DTMF timeout */
11525 if ((!myrpt->cmdnode[0]) && (myrpt->dtmfidx >= 0) && ((myrpt->dtmf_time + DTMF_TIMEOUT) < t))
11527 myrpt->inpadtest = 0;
11528 myrpt->dtmfidx = -1;
11529 myrpt->dtmfbuf[0] = 0;
11531 /* if remote DTMF timeout */
11532 if ((myrpt->rem_dtmfidx >= 0) && ((myrpt->rem_dtmf_time + DTMF_TIMEOUT) < t))
11534 myrpt->inpadtest = 0;
11535 myrpt->rem_dtmfidx = -1;
11536 myrpt->rem_dtmfbuf[0] = 0;
11539 if (myrpt->exttx && myrpt->parrotchannel &&
11540 myrpt->p.parrotmode && (!myrpt->parrotstate))
11542 char myfname[300];
11544 ci.confno = myrpt->conf;
11545 ci.confmode = DAHDI_CONF_CONFANNMON;
11546 ci.chan = 0;
11548 /* first put the channel on the conference in announce mode */
11549 if (ioctl(myrpt->parrotchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11551 ast_log(LOG_WARNING, "Unable to set conference mode for parrot\n");
11552 break;
11555 sprintf(myfname,PARROTFILE,myrpt->name,myrpt->parrotcnt);
11556 strcat(myfname,".wav");
11557 unlink(myfname);
11558 sprintf(myfname,PARROTFILE,myrpt->name,myrpt->parrotcnt);
11559 myrpt->parrotstate = 1;
11560 myrpt->parrottimer = myrpt->p.parrottime;
11561 if (myrpt->parrotstream)
11562 ast_closestream(myrpt->parrotstream);
11563 myrpt->parrotstream = NULL;
11564 myrpt->parrotstream = ast_writefile(myfname,"wav",
11565 "app_rpt Parrot",O_CREAT | O_TRUNC,0,0600);
11568 /* Reconnect */
11570 l = myrpt->links.next;
11571 while(l != &myrpt->links)
11573 if (l->killme)
11575 /* remove from queue */
11576 remque((struct qelem *) l);
11577 if (!strcmp(myrpt->cmdnode,l->name))
11578 myrpt->cmdnode[0] = 0;
11579 rpt_mutex_unlock(&myrpt->lock);
11580 /* hang-up on call to device */
11581 if (l->chan) ast_hangup(l->chan);
11582 ast_hangup(l->pchan);
11583 ast_free(l);
11584 rpt_mutex_lock(&myrpt->lock);
11585 /* re-start link traversal */
11586 l = myrpt->links.next;
11587 continue;
11589 l = l->next;
11591 n = 0;
11592 cs[n++] = myrpt->rxchannel;
11593 cs[n++] = myrpt->pchannel;
11594 cs[n++] = myrpt->monchannel;
11595 if (myrpt->parrotchannel) cs[n++] = myrpt->parrotchannel;
11596 if (myrpt->voxchannel) cs[n++] = myrpt->voxchannel;
11597 cs[n++] = myrpt->txpchannel;
11598 if (myrpt->txchannel != myrpt->rxchannel) cs[n++] = myrpt->txchannel;
11599 if (myrpt->dahditxchannel != myrpt->txchannel)
11600 cs[n++] = myrpt->dahditxchannel;
11601 l = myrpt->links.next;
11602 while(l != &myrpt->links)
11604 if ((!l->killme) && (!l->disctime) && l->chan)
11606 cs[n++] = l->chan;
11607 cs[n++] = l->pchan;
11609 l = l->next;
11611 if ((myrpt->topkeystate == 1) &&
11612 ((t - myrpt->topkeytime) > TOPKEYWAIT))
11614 myrpt->topkeystate = 2;
11615 qsort(myrpt->topkey,TOPKEYN,sizeof(struct rpt_topkey),
11616 topcompar);
11618 rpt_mutex_unlock(&myrpt->lock);
11620 if (myrpt->topkeystate == 2)
11622 rpt_telemetry(myrpt,TOPKEY,NULL);
11623 myrpt->topkeystate = 3;
11625 ms = MSWAIT;
11626 for(x = 0; x < n; x++)
11628 int s = -(-x - myrpt->scram - 1) % n;
11629 cs1[x] = cs[s];
11631 myrpt->scram++;
11632 who = ast_waitfor_n(cs1,n,&ms);
11633 if (who == NULL) ms = 0;
11634 elap = MSWAIT - ms;
11635 rpt_mutex_lock(&myrpt->lock);
11636 l = myrpt->links.next;
11637 while(l != &myrpt->links)
11639 int myrx;
11641 if (l->voxtotimer) l->voxtotimer -= elap;
11642 if (l->voxtotimer < 0) l->voxtotimer = 0;
11644 if (l->lasttx != l->lasttx1)
11646 voxinit_link(l,!l->lasttx);
11647 l->lasttx1 = l->lasttx;
11649 myrx = l->lastrealrx;
11650 if ((l->phonemode) && (l->phonevox))
11652 myrx = myrx || (!AST_LIST_EMPTY(&l->rxq));
11653 if (l->voxtotimer <= 0)
11655 if (l->voxtostate)
11657 l->voxtotimer = myrpt->p.voxtimeout_ms;
11658 l->voxtostate = 0;
11660 else
11662 l->voxtotimer = myrpt->p.voxrecover_ms;
11663 l->voxtostate = 1;
11666 if (!l->voxtostate)
11667 myrx = myrx || l->wasvox ;
11669 l->lastrx = myrx;
11670 if (l->linklisttimer)
11672 l->linklisttimer -= elap;
11673 if (l->linklisttimer < 0) l->linklisttimer = 0;
11675 if ((!l->linklisttimer) && (l->name[0] != '0') && (!l->isremote))
11677 struct ast_frame lf;
11679 memset(&lf,0,sizeof(lf));
11680 lf.frametype = AST_FRAME_TEXT;
11681 lf.subclass = 0;
11682 lf.offset = 0;
11683 lf.mallocd = 0;
11684 lf.samples = 0;
11685 l->linklisttimer = LINKLISTTIME;
11686 strcpy(lstr,"L ");
11687 __mklinklist(myrpt,l,lstr + 2);
11688 if (l->chan)
11690 lf.datalen = strlen(lstr) + 1;
11691 lf.data.ptr = lstr;
11692 ast_write(l->chan,&lf);
11693 if (debug > 6) ast_log(LOG_NOTICE,
11694 "@@@@ node %s sent node string %s to node %s\n",
11695 myrpt->name,lstr,l->name);
11698 if (l->newkey)
11700 if ((l->retxtimer += elap) >= REDUNDANT_TX_TIME)
11702 l->retxtimer = 0;
11703 if (l->chan && l->phonemode == 0)
11705 if (l->lasttx)
11706 ast_indicate(l->chan,AST_CONTROL_RADIO_KEY);
11707 else
11708 ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
11711 if ((l->rerxtimer += elap) >= (REDUNDANT_TX_TIME * 5))
11713 if (debug == 7) printf("@@@@ rx un-key\n");
11714 l->lastrealrx = 0;
11715 l->rerxtimer = 0;
11716 if (l->lastrx1)
11718 if (myrpt->p.archivedir)
11720 char str[100];
11722 sprintf(str,"RXUNKEY(T),%s",l->name);
11723 donodelog(myrpt,str);
11725 if(myrpt->p.duplex)
11726 rpt_telemetry(myrpt,LINKUNKEY,l);
11727 l->lastrx1 = 0;
11731 if (l->disctime) /* Disconnect timer active on a channel ? */
11733 l->disctime -= elap;
11734 if (l->disctime <= 0) /* Disconnect timer expired on inbound channel ? */
11735 l->disctime = 0; /* Yep */
11738 if (l->retrytimer)
11740 l->retrytimer -= elap;
11741 if (l->retrytimer < 0) l->retrytimer = 0;
11744 /* Tally connect time */
11745 l->connecttime += elap;
11747 /* ignore non-timing channels */
11748 if (l->elaptime < 0)
11750 l = l->next;
11751 continue;
11753 l->elaptime += elap;
11754 /* if connection has taken too long */
11755 if ((l->elaptime > MAXCONNECTTIME) &&
11756 ((!l->chan) || (l->chan->_state != AST_STATE_UP)))
11758 l->elaptime = 0;
11759 rpt_mutex_unlock(&myrpt->lock);
11760 if (l->chan) ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
11761 rpt_mutex_lock(&myrpt->lock);
11762 break;
11764 if ((!l->chan) && (!l->retrytimer) && l->outbound &&
11765 (l->retries++ < l->max_retries) && (l->hasconnected))
11767 if (l->chan) ast_hangup(l->chan);
11768 l->chan = 0;
11769 rpt_mutex_unlock(&myrpt->lock);
11770 if ((l->name[0] != '0') && (!l->isremote))
11772 if (attempt_reconnect(myrpt,l) == -1)
11774 l->retrytimer = RETRY_TIMER_MS;
11777 else
11779 l->retrytimer = l->max_retries + 1;
11782 rpt_mutex_lock(&myrpt->lock);
11783 break;
11785 if ((!l->chan) && (!l->retrytimer) && l->outbound &&
11786 (l->retries >= l->max_retries))
11788 /* remove from queue */
11789 remque((struct qelem *) l);
11790 if (!strcmp(myrpt->cmdnode,l->name))
11791 myrpt->cmdnode[0] = 0;
11792 rpt_mutex_unlock(&myrpt->lock);
11793 if (l->name[0] != '0')
11795 if (!l->hasconnected)
11796 rpt_telemetry(myrpt,CONNFAIL,l);
11797 else rpt_telemetry(myrpt,REMDISC,l);
11799 if (myrpt->p.archivedir)
11801 char str[100];
11803 if (!l->hasconnected)
11804 sprintf(str,"LINKFAIL,%s",l->name);
11805 else
11806 sprintf(str,"LINKDISC,%s",l->name);
11807 donodelog(myrpt,str);
11809 /* hang-up on call to device */
11810 ast_hangup(l->pchan);
11811 ast_free(l);
11812 rpt_mutex_lock(&myrpt->lock);
11813 break;
11815 if ((!l->chan) && (!l->disctime) && (!l->outbound))
11817 if(debug)ast_log(LOG_NOTICE, "LINKDISC AA\n");
11818 /* remove from queue */
11819 remque((struct qelem *) l);
11820 if(myrpt->links.next==&myrpt->links)channel_revert(myrpt);
11821 if (!strcmp(myrpt->cmdnode,l->name))myrpt->cmdnode[0] = 0;
11822 rpt_mutex_unlock(&myrpt->lock);
11823 if (l->name[0] != '0')
11825 rpt_telemetry(myrpt,REMDISC,l);
11827 if (myrpt->p.archivedir)
11829 char str[100];
11830 sprintf(str,"LINKDISC,%s",l->name);
11831 donodelog(myrpt,str);
11833 /* hang-up on call to device */
11834 ast_hangup(l->pchan);
11835 ast_free(l);
11836 rpt_mutex_lock(&myrpt->lock);
11837 break;
11839 l = l->next;
11841 if (myrpt->linkposttimer)
11843 myrpt->linkposttimer -= elap;
11844 if (myrpt->linkposttimer < 0) myrpt->linkposttimer = 0;
11846 if (myrpt->linkposttimer <= 0)
11848 int nstr;
11849 char lst,*str;
11850 time_t now;
11852 myrpt->linkposttimer = LINKPOSTTIME;
11853 nstr = 0;
11854 for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
11856 /* if is not a real link, ignore it */
11857 if (l->name[0] == '0') continue;
11858 nstr += strlen(l->name) + 1;
11860 str = ast_malloc(nstr + 256);
11861 if (!str)
11863 ast_log(LOG_NOTICE,"Cannot ast_malloc()\n");
11864 break;
11866 nstr = 0;
11867 strcpy(str,"nodes=");
11868 for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
11870 /* if is not a real link, ignore it */
11871 if (l->name[0] == '0') continue;
11872 lst = 'T';
11873 if (!l->mode) lst = 'R';
11874 if (!l->thisconnected) lst = 'C';
11875 if (nstr) strcat(str,",");
11876 sprintf(str + strlen(str),"%c%s",lst,l->name);
11877 nstr = 1;
11879 p = strstr(tdesc, "version");
11880 if(p){
11881 int vmajor,vminor;
11882 if(sscanf(p, "version %d.%d", &vmajor, &vminor) == 2)
11883 sprintf(str + strlen(str),"&apprptvers=%d.%d",vmajor,vminor);
11885 time(&now);
11886 sprintf(str + strlen(str),"&apprptuptime=%d",(int)(now-starttime));
11887 sprintf(str + strlen(str),
11888 "&totalkerchunks=%d&totalkeyups=%d&totaltxtime=%d&timeouts=%d&totalexecdcommands=%d",
11889 myrpt->totalkerchunks,myrpt->totalkeyups,(int) myrpt->totaltxtime/1000,
11890 myrpt->timeouts,myrpt->totalexecdcommands);
11891 rpt_mutex_unlock(&myrpt->lock);
11892 statpost(myrpt,str);
11893 rpt_mutex_lock(&myrpt->lock);
11894 ast_free(str);
11896 if (myrpt->keyposttimer)
11898 myrpt->keyposttimer -= elap;
11899 if (myrpt->keyposttimer < 0) myrpt->keyposttimer = 0;
11901 if (myrpt->keyposttimer <= 0)
11903 char str[100];
11904 int n = 0;
11905 time_t now;
11907 myrpt->keyposttimer = KEYPOSTTIME;
11908 time(&now);
11909 if (myrpt->lastkeyedtime)
11911 n = (int)(now - myrpt->lastkeyedtime);
11913 sprintf(str,"keyed=%d&keytime=%d",myrpt->keyed,n);
11914 rpt_mutex_unlock(&myrpt->lock);
11915 statpost(myrpt,str);
11916 rpt_mutex_lock(&myrpt->lock);
11918 if(totx){
11919 myrpt->dailytxtime += elap;
11920 myrpt->totaltxtime += elap;
11922 i = myrpt->tailtimer;
11923 if (myrpt->tailtimer) myrpt->tailtimer -= elap;
11924 if (myrpt->tailtimer < 0) myrpt->tailtimer = 0;
11925 if((i) && (myrpt->tailtimer == 0))
11926 myrpt->tailevent = 1;
11927 if ((!myrpt->p.s[myrpt->p.sysstate_cur].totdisable) && myrpt->totimer) myrpt->totimer -= elap;
11928 if (myrpt->totimer < 0) myrpt->totimer = 0;
11929 if (myrpt->idtimer) myrpt->idtimer -= elap;
11930 if (myrpt->idtimer < 0) myrpt->idtimer = 0;
11931 if (myrpt->tmsgtimer) myrpt->tmsgtimer -= elap;
11932 if (myrpt->tmsgtimer < 0) myrpt->tmsgtimer = 0;
11933 if (myrpt->voxtotimer) myrpt->voxtotimer -= elap;
11934 if (myrpt->voxtotimer < 0) myrpt->voxtotimer = 0;
11935 if (myrpt->exttx)
11937 myrpt->parrottimer = myrpt->p.parrottime;
11939 else
11941 if (myrpt->parrottimer) myrpt->parrottimer -= elap;
11942 if (myrpt->parrottimer < 0) myrpt->parrottimer = 0;
11944 /* do macro timers */
11945 if (myrpt->macrotimer) myrpt->macrotimer -= elap;
11946 if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
11947 /* do local dtmf timer */
11948 if (myrpt->dtmf_local_timer)
11950 if (myrpt->dtmf_local_timer > 1) myrpt->dtmf_local_timer -= elap;
11951 if (myrpt->dtmf_local_timer < 1) myrpt->dtmf_local_timer = 1;
11953 do_dtmf_local(myrpt,0);
11954 /* Execute scheduler appx. every 2 tenths of a second */
11955 if (myrpt->skedtimer <= 0){
11956 myrpt->skedtimer = 200;
11957 do_scheduler(myrpt);
11959 else
11960 myrpt->skedtimer -=elap;
11961 if (!ms)
11963 rpt_mutex_unlock(&myrpt->lock);
11964 continue;
11966 if (myrpt->p.parrotmode && (myrpt->parrotstate == 1) &&
11967 (myrpt->parrottimer <= 0))
11970 ci.confno = 0;
11971 ci.confmode = 0;
11972 ci.chan = 0;
11974 /* first put the channel on the conference in announce mode */
11975 if (ioctl(myrpt->parrotchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11977 ast_log(LOG_WARNING, "Unable to set conference mode for parrot\n");
11978 break;
11980 if (myrpt->parrotstream)
11981 ast_closestream(myrpt->parrotstream);
11982 myrpt->parrotstream = NULL;
11983 myrpt->parrotstate = 2;
11984 rpt_telemetry(myrpt,PARROT,(struct rpt_link *) myrpt->parrotcnt++);
11986 if (myrpt->cmdAction.state == CMD_STATE_READY)
11987 { /* there is a command waiting to be processed */
11988 int status;
11989 myrpt->cmdAction.state = CMD_STATE_EXECUTING;
11990 // lose the lock
11991 rpt_mutex_unlock(&myrpt->lock);
11992 // do the function
11993 status = (*function_table[myrpt->cmdAction.functionNumber].function)(myrpt,myrpt->cmdAction.param, myrpt->cmdAction.digits, myrpt->cmdAction.command_source, NULL);
11994 // get the lock again
11995 rpt_mutex_lock(&myrpt->lock);
11996 myrpt->cmdAction.state = CMD_STATE_IDLE;
11997 } /* if myrpt->cmdAction.state == CMD_STATE_READY */
11999 c = myrpt->macrobuf[0];
12000 time(&t);
12001 if (c && (!myrpt->macrotimer) &&
12002 starttime && (t > (starttime + START_DELAY)))
12004 char cin = c & 0x7f;
12005 myrpt->macrotimer = MACROTIME;
12006 memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1);
12007 if ((cin == 'p') || (cin == 'P'))
12008 myrpt->macrotimer = MACROPTIME;
12009 rpt_mutex_unlock(&myrpt->lock);
12010 if (myrpt->p.archivedir)
12012 char str[100];
12014 sprintf(str,"DTMF(M),MAIN,%c",cin);
12015 donodelog(myrpt,str);
12017 local_dtmf_helper(myrpt,c);
12018 } else rpt_mutex_unlock(&myrpt->lock);
12019 if (who == myrpt->rxchannel) /* if it was a read from rx */
12021 int ismuted;
12023 f = ast_read(myrpt->rxchannel);
12024 if (!f)
12026 if (debug) printf("@@@@ rpt:Hung Up\n");
12027 break;
12029 if (f->frametype == AST_FRAME_VOICE)
12031 #ifdef _MDC_DECODE_H_
12032 unsigned char ubuf[2560];
12033 short *sp;
12034 int n;
12035 #endif
12037 if ((!myrpt->localtx) && (!myrpt->p.linktolink)) {
12038 memset(f->data.ptr,0,f->datalen);
12041 #ifdef _MDC_DECODE_H_
12042 sp = (short *) f->data;
12043 /* convert block to unsigned char */
12044 for(n = 0; n < f->datalen / 2; n++)
12046 ubuf[n] = (*sp++ >> 8) + 128;
12048 n = mdc_decoder_process_samples(myrpt->mdc,ubuf,f->datalen / 2);
12049 if (n == 1)
12051 unsigned char op,arg;
12052 unsigned short unitID;
12054 mdc_decoder_get_packet(myrpt->mdc,&op,&arg,&unitID);
12055 if (debug > 2)
12057 ast_log(LOG_NOTICE,"Got (single-length) packet:\n");
12058 ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
12059 op & 255,arg & 255,unitID);
12061 if ((op == 1) && (arg == 0))
12063 myrpt->lastunit = unitID;
12064 mdc1200_notify(myrpt,NULL,myrpt->lastunit);
12065 mdc1200_send(myrpt,myrpt->lastunit);
12068 if ((debug > 2) && (i == 2))
12070 unsigned char op,arg,ex1,ex2,ex3,ex4;
12071 unsigned short unitID;
12073 mdc_decoder_get_double_packet(myrpt->mdc,&op,&arg,&unitID,
12074 &ex1,&ex2,&ex3,&ex4);
12075 ast_log(LOG_NOTICE,"Got (double-length) packet:\n");
12076 ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
12077 op & 255,arg & 255,unitID);
12078 ast_log(LOG_NOTICE,"ex1: %02x, ex2: %02x, ex3: %02x, ex4: %02x\n",
12079 ex1 & 255, ex2 & 255, ex3 & 255, ex4 & 255);
12081 #endif
12082 #ifdef __RPT_NOTCH
12083 /* apply inbound filters, if any */
12084 rpt_filter(myrpt,f->data,f->datalen / 2);
12085 #endif
12086 if (ioctl(myrpt->dahdirxchannel->fds[0], DAHDI_GETCONFMUTE, &ismuted) == -1)
12088 ismuted = 0;
12090 if (dtmfed) ismuted = 1;
12091 dtmfed = 0;
12092 if (ismuted)
12094 memset(f->data.ptr,0,f->datalen);
12095 if (myrpt->lastf1)
12096 memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
12097 if (myrpt->lastf2)
12098 memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
12100 if (f) f2 = ast_frdup(f);
12101 else f2 = NULL;
12102 f1 = myrpt->lastf2;
12103 myrpt->lastf2 = myrpt->lastf1;
12104 myrpt->lastf1 = f2;
12105 if (ismuted)
12107 if (myrpt->lastf1)
12108 memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
12109 if (myrpt->lastf2)
12110 memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
12112 if (f1)
12114 ast_write(myrpt->pchannel,f1);
12115 ast_frfree(f1);
12118 #ifndef OLD_ASTERISK
12119 else if (f->frametype == AST_FRAME_DTMF_BEGIN)
12121 if (myrpt->lastf1)
12122 memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
12123 if (myrpt->lastf2)
12124 memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
12125 dtmfed = 1;
12127 #endif
12128 else if (f->frametype == AST_FRAME_DTMF)
12130 c = (char) f->subclass; /* get DTMF char */
12131 ast_frfree(f);
12132 if (myrpt->lastf1)
12133 memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
12134 if (myrpt->lastf2)
12135 memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
12136 dtmfed = 1;
12137 if (!myrpt->keyed) continue;
12138 c = func_xlat(myrpt,c,&myrpt->p.inxlat);
12139 if (c) local_dtmf_helper(myrpt,c);
12140 continue;
12142 else if (f->frametype == AST_FRAME_CONTROL)
12144 if (f->subclass == AST_CONTROL_HANGUP)
12146 if (debug) printf("@@@@ rpt:Hung Up\n");
12147 ast_frfree(f);
12148 break;
12150 /* if RX key */
12151 if (f->subclass == AST_CONTROL_RADIO_KEY)
12153 if ((!lasttx) || (myrpt->p.duplex > 1) || (myrpt->p.linktolink))
12155 if (debug == 7) printf("@@@@ rx key\n");
12156 myrpt->keyed = 1;
12157 time(&myrpt->lastkeyedtime);
12158 myrpt->keyposttimer = KEYPOSTSHORTTIME;
12160 if (myrpt->p.archivedir)
12162 donodelog(myrpt,"RXKEY,MAIN");
12164 if (f->datalen && f->data.ptr)
12166 char *val, busy = 0;
12168 if (debug) ast_log(LOG_NOTICE,"Got PL %s on node %s\n",(char *)f->data.ptr,myrpt->name);
12169 // ctcss code autopatch initiate
12170 if (strstr((char *)f->data.ptr,"/M/")&& !myrpt->macropatch)
12172 char val[16];
12173 strcat(val,"*6");
12174 myrpt->macropatch=1;
12175 rpt_mutex_lock(&myrpt->lock);
12176 if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val)){
12177 rpt_mutex_unlock(&myrpt->lock);
12178 busy=1;
12180 if(!busy){
12181 myrpt->macrotimer = MACROTIME;
12182 strncat(myrpt->macrobuf,val,MAXMACRO - 1);
12183 if (!busy) strcpy(myrpt->lasttone,(char*)f->data.ptr);
12185 rpt_mutex_unlock(&myrpt->lock);
12187 else if (strcmp((char *)f->data.ptr,myrpt->lasttone))
12189 val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.tonemacro, (char *)f->data.ptr);
12190 if (val)
12192 if (debug) ast_log(LOG_NOTICE,"Tone %s doing %s on node %s\n",(char *) f->data.ptr,val,myrpt->name);
12193 rpt_mutex_lock(&myrpt->lock);
12194 if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val)){
12195 rpt_mutex_unlock(&myrpt->lock);
12196 busy=1;
12198 if(!busy){
12199 myrpt->macrotimer = MACROTIME;
12200 strncat(myrpt->macrobuf,val,MAXMACRO - 1);
12202 rpt_mutex_unlock(&myrpt->lock);
12204 if (!busy) strcpy(myrpt->lasttone,(char*)f->data.ptr);
12206 } else myrpt->lasttone[0] = 0;
12208 /* if RX un-key */
12209 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
12211 if ((!lasttx) || (myrpt->p.duplex > 1) || (myrpt->p.linktolink))
12213 if (debug == 7) printf("@@@@ rx un-key\n");
12214 if(myrpt->p.duplex && myrpt->keyed) {
12215 rpt_telemetry(myrpt,UNKEY,NULL);
12218 myrpt->keyed = 0;
12219 time(&myrpt->lastkeyedtime);
12220 myrpt->keyposttimer = KEYPOSTSHORTTIME;
12221 if (myrpt->p.archivedir)
12223 donodelog(myrpt,"RXUNKEY,MAIN");
12227 ast_frfree(f);
12228 continue;
12230 if (who == myrpt->pchannel) /* if it was a read from pseudo */
12232 f = ast_read(myrpt->pchannel);
12233 if (!f)
12235 if (debug) printf("@@@@ rpt:Hung Up\n");
12236 break;
12238 if (f->frametype == AST_FRAME_VOICE)
12240 ast_write(myrpt->txpchannel,f);
12242 if (f->frametype == AST_FRAME_CONTROL)
12244 if (f->subclass == AST_CONTROL_HANGUP)
12246 if (debug) printf("@@@@ rpt:Hung Up\n");
12247 ast_frfree(f);
12248 break;
12251 ast_frfree(f);
12252 continue;
12254 if (who == myrpt->txchannel) /* if it was a read from tx */
12256 f = ast_read(myrpt->txchannel);
12257 if (!f)
12259 if (debug) printf("@@@@ rpt:Hung Up\n");
12260 break;
12262 if (f->frametype == AST_FRAME_CONTROL)
12264 if (f->subclass == AST_CONTROL_HANGUP)
12266 if (debug) printf("@@@@ rpt:Hung Up\n");
12267 ast_frfree(f);
12268 break;
12271 ast_frfree(f);
12272 continue;
12274 if (who == myrpt->dahditxchannel) /* if it was a read from pseudo-tx */
12276 f = ast_read(myrpt->dahditxchannel);
12277 if (!f)
12279 if (debug) printf("@@@@ rpt:Hung Up\n");
12280 break;
12282 if (f->frametype == AST_FRAME_VOICE)
12284 struct ast_frame *f1;
12286 if (myrpt->p.duplex < 2)
12288 if (myrpt->txrealkeyed)
12290 if ((!myfirst) && myrpt->callmode)
12292 x = 0;
12293 AST_LIST_TRAVERSE(&myrpt->txq, f1,
12294 frame_list) x++;
12295 for(;x < myrpt->p.simplexpatchdelay; x++)
12297 f1 = ast_frdup(f);
12298 memset(f1->data.ptr,0,f1->datalen);
12299 AST_LIST_INSERT_TAIL(&myrpt->txq,f1,frame_list);
12301 myfirst = 1;
12303 f1 = ast_frdup(f);
12304 AST_LIST_INSERT_TAIL(&myrpt->txq,
12305 f1,frame_list);
12306 } else myfirst = 0;
12307 x = 0;
12308 AST_LIST_TRAVERSE(&myrpt->txq, f1,
12309 frame_list) x++;
12310 if (!x)
12312 memset(f->data.ptr,0,f->datalen);
12314 else
12316 ast_frfree(f);
12317 f = AST_LIST_REMOVE_HEAD(&myrpt->txq,
12318 frame_list);
12321 else
12323 while((f1 = AST_LIST_REMOVE_HEAD(&myrpt->txq,
12324 frame_list))) ast_frfree(f1);
12326 ast_write(myrpt->txchannel,f);
12328 if (f->frametype == AST_FRAME_CONTROL)
12330 if (f->subclass == AST_CONTROL_HANGUP)
12332 if (debug) printf("@@@@ rpt:Hung Up\n");
12333 ast_frfree(f);
12334 break;
12337 ast_frfree(f);
12338 continue;
12340 toexit = 0;
12341 rpt_mutex_lock(&myrpt->lock);
12342 l = myrpt->links.next;
12343 while(l != &myrpt->links)
12345 int remnomute;
12346 struct timeval now;
12348 if (l->disctime)
12350 l = l->next;
12351 continue;
12354 remrx = 0;
12355 /* see if any other links are receiving */
12356 m = myrpt->links.next;
12357 while(m != &myrpt->links)
12359 /* if not us, count it */
12360 if ((m != l) && (m->lastrx)) remrx = 1;
12361 m = m->next;
12363 rpt_mutex_unlock(&myrpt->lock);
12364 now = ast_tvnow();
12365 if ((who == l->chan) || (!l->lastlinktv.tv_sec) ||
12366 (ast_tvdiff_ms(now,l->lastlinktv) >= 19))
12368 l->lastlinktv = now;
12369 remnomute = myrpt->localtx &&
12370 (!(myrpt->cmdnode[0] ||
12371 (myrpt->dtmfidx > -1)));
12372 totx = (((l->isremote) ? (remnomute) :
12373 myrpt->exttx) || remrx) && l->mode;
12374 if (l->phonemode == 0 && l->chan && (l->lasttx != totx))
12376 if (totx)
12378 ast_indicate(l->chan,AST_CONTROL_RADIO_KEY);
12380 else
12382 ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
12384 if (myrpt->p.archivedir)
12386 char str[100];
12388 if (totx)
12389 sprintf(str,"TXKEY,%s",l->name);
12390 else
12391 sprintf(str,"TXUNKEY,%s",l->name);
12392 donodelog(myrpt,str);
12395 l->lasttx = totx;
12397 rpt_mutex_lock(&myrpt->lock);
12398 if (who == l->chan) /* if it was a read from rx */
12400 rpt_mutex_unlock(&myrpt->lock);
12401 f = ast_read(l->chan);
12402 if (!f)
12404 rpt_mutex_lock(&myrpt->lock);
12405 __kickshort(myrpt);
12406 rpt_mutex_unlock(&myrpt->lock);
12407 if ((!l->disced) && (!l->outbound))
12409 if ((l->name[0] == '0') || l->isremote)
12410 l->disctime = 1;
12411 else
12412 l->disctime = DISC_TIME;
12413 rpt_mutex_lock(&myrpt->lock);
12414 ast_hangup(l->chan);
12415 l->chan = 0;
12416 break;
12419 if (l->retrytimer)
12421 ast_hangup(l->chan);
12422 l->chan = 0;
12423 rpt_mutex_lock(&myrpt->lock);
12424 break;
12426 if (l->outbound && (l->retries++ < l->max_retries) && (l->hasconnected))
12428 rpt_mutex_lock(&myrpt->lock);
12429 if (l->chan) ast_hangup(l->chan);
12430 l->chan = 0;
12431 l->hasconnected = 1;
12432 l->retrytimer = RETRY_TIMER_MS;
12433 l->elaptime = 0;
12434 l->connecttime = 0;
12435 l->thisconnected = 0;
12436 break;
12438 rpt_mutex_lock(&myrpt->lock);
12439 /* remove from queue */
12440 remque((struct qelem *) l);
12441 if (!strcmp(myrpt->cmdnode,l->name))
12442 myrpt->cmdnode[0] = 0;
12443 __kickshort(myrpt);
12444 rpt_mutex_unlock(&myrpt->lock);
12445 if (!l->hasconnected)
12446 rpt_telemetry(myrpt,CONNFAIL,l);
12447 else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
12448 if (myrpt->p.archivedir)
12450 char str[100];
12452 if (!l->hasconnected)
12453 sprintf(str,"LINKFAIL,%s",l->name);
12454 else
12455 sprintf(str,"LINKDISC,%s",l->name);
12456 donodelog(myrpt,str);
12458 if (l->lastf1) ast_frfree(l->lastf1);
12459 l->lastf1 = NULL;
12460 if (l->lastf2) ast_frfree(l->lastf2);
12461 l->lastf2 = NULL;
12462 /* hang-up on call to device */
12463 ast_hangup(l->chan);
12464 ast_hangup(l->pchan);
12465 ast_free(l);
12466 rpt_mutex_lock(&myrpt->lock);
12467 break;
12469 if (f->frametype == AST_FRAME_VOICE)
12471 int ismuted,n1;
12473 if ((l->phonemode) && (l->phonevox))
12475 n1 = dovox(&l->vox,
12476 f->data.ptr,f->datalen / 2);
12477 if (n1 != l->wasvox)
12479 if (debug)ast_log(LOG_DEBUG,"Link Node %s, vox %d\n",l->name,n1);
12480 l->wasvox = n1;
12481 l->voxtostate = 0;
12482 if (n1) l->voxtotimer = myrpt->p.voxtimeout_ms;
12483 else l->voxtotimer = 0;
12485 if (l->lastrealrx || n1)
12487 if (!myfirst)
12489 x = 0;
12490 AST_LIST_TRAVERSE(&l->rxq, f1,
12491 frame_list) x++;
12492 for(;x < myrpt->p.simplexphonedelay; x++)
12494 f1 = ast_frdup(f);
12495 memset(f1->data.ptr,0,f1->datalen);
12496 AST_LIST_INSERT_TAIL(&l->rxq,
12497 f1,frame_list);
12499 myfirst = 1;
12501 f1 = ast_frdup(f);
12502 AST_LIST_INSERT_TAIL(&l->rxq,f1,frame_list);
12503 } else myfirst = 0;
12504 x = 0;
12505 AST_LIST_TRAVERSE(&l->rxq, f1,frame_list) x++;
12506 if (!x)
12508 memset(f->data.ptr,0,f->datalen);
12510 else
12512 ast_frfree(f);
12513 f = AST_LIST_REMOVE_HEAD(&l->rxq,frame_list);
12515 if (ioctl(l->chan->fds[0], DAHDI_GETCONFMUTE, &ismuted) == -1)
12517 ismuted = 0;
12519 /* if not receiving, zero-out audio */
12520 ismuted |= (!l->lastrx);
12521 if (l->dtmfed && l->phonemode) ismuted = 1;
12522 l->dtmfed = 0;
12523 if (ismuted)
12525 memset(f->data.ptr,0,f->datalen);
12526 if (l->lastf1)
12527 memset(l->lastf1->data.ptr,0,l->lastf1->datalen);
12528 if (l->lastf2)
12529 memset(l->lastf2->data.ptr,0,l->lastf2->datalen);
12531 if (f) f2 = ast_frdup(f);
12532 else f2 = NULL;
12533 f1 = l->lastf2;
12534 l->lastf2 = l->lastf1;
12535 l->lastf1 = f2;
12536 if (ismuted)
12538 if (l->lastf1)
12539 memset(l->lastf1->data.ptr,0,l->lastf1->datalen);
12540 if (l->lastf2)
12541 memset(l->lastf2->data.ptr,0,l->lastf2->datalen);
12543 if (f1)
12545 ast_write(l->pchan,f1);
12546 ast_frfree(f1);
12549 else
12551 if (!l->lastrx)
12552 memset(f->data.ptr,0,f->datalen);
12553 ast_write(l->pchan,f);
12556 #ifndef OLD_ASTERISK
12557 else if (f->frametype == AST_FRAME_DTMF_BEGIN)
12559 if (l->lastf1)
12560 memset(l->lastf1->data.ptr,0,l->lastf1->datalen);
12561 if (l->lastf2)
12562 memset(l->lastf2->data.ptr,0,l->lastf2->datalen);
12563 l->dtmfed = 1;
12565 #endif
12566 if (f->frametype == AST_FRAME_TEXT)
12568 handle_link_data(myrpt,l,f->data.ptr);
12570 if (f->frametype == AST_FRAME_DTMF)
12572 if (l->lastf1)
12573 memset(l->lastf1->data.ptr,0,l->lastf1->datalen);
12574 if (l->lastf2)
12575 memset(l->lastf2->data.ptr,0,l->lastf2->datalen);
12576 l->dtmfed = 1;
12577 handle_link_phone_dtmf(myrpt,l,f->subclass);
12579 if (f->frametype == AST_FRAME_CONTROL)
12581 if (f->subclass == AST_CONTROL_ANSWER)
12583 char lconnected = l->connected;
12585 __kickshort(myrpt);
12586 l->connected = 1;
12587 l->hasconnected = 1;
12588 l->thisconnected = 1;
12589 l->elaptime = -1;
12590 if (!l->phonemode) send_newkey(l->chan);
12591 if (!l->isremote) l->retries = 0;
12592 if (!lconnected)
12594 rpt_telemetry(myrpt,CONNECTED,l);
12595 if (myrpt->p.archivedir)
12597 char str[100];
12599 if (l->mode)
12600 sprintf(str,"LINKTRX,%s",l->name);
12601 else
12602 sprintf(str,"LINKMONITOR,%s",l->name);
12603 donodelog(myrpt,str);
12606 else
12607 l->reconnects++;
12609 /* if RX key */
12610 if (f->subclass == AST_CONTROL_RADIO_KEY)
12612 if (debug == 7 ) printf("@@@@ rx key\n");
12613 l->lastrealrx = 1;
12614 l->rerxtimer = 0;
12615 if (!l->lastrx1)
12617 if (myrpt->p.archivedir)
12619 char str[100];
12621 sprintf(str,"RXKEY,%s",l->name);
12622 donodelog(myrpt,str);
12624 l->lastrx1 = 1;
12627 /* if RX un-key */
12628 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
12630 if (debug == 7) printf("@@@@ rx un-key\n");
12631 l->lastrealrx = 0;
12632 l->rerxtimer = 0;
12633 if (l->lastrx1)
12635 if (myrpt->p.archivedir)
12637 char str[100];
12639 sprintf(str,"RXUNKEY,%s",l->name);
12640 donodelog(myrpt,str);
12642 l->lastrx1 = 0;
12643 if(myrpt->p.duplex)
12644 rpt_telemetry(myrpt,LINKUNKEY,l);
12647 if (f->subclass == AST_CONTROL_HANGUP)
12649 ast_frfree(f);
12650 rpt_mutex_lock(&myrpt->lock);
12651 __kickshort(myrpt);
12652 rpt_mutex_unlock(&myrpt->lock);
12653 if ((!l->outbound) && (!l->disced))
12655 if ((l->name[0] == '0') || l->isremote)
12656 l->disctime = 1;
12657 else
12658 l->disctime = DISC_TIME;
12659 rpt_mutex_lock(&myrpt->lock);
12660 ast_hangup(l->chan);
12661 l->chan = 0;
12662 break;
12664 if (l->retrytimer)
12666 if (l->chan) ast_hangup(l->chan);
12667 l->chan = 0;
12668 rpt_mutex_lock(&myrpt->lock);
12669 break;
12671 if (l->outbound && (l->retries++ < l->max_retries) && (l->hasconnected))
12673 rpt_mutex_lock(&myrpt->lock);
12674 if (l->chan) ast_hangup(l->chan);
12675 l->chan = 0;
12676 l->hasconnected = 1;
12677 l->elaptime = 0;
12678 l->retrytimer = RETRY_TIMER_MS;
12679 l->connecttime = 0;
12680 l->thisconnected = 0;
12681 break;
12683 rpt_mutex_lock(&myrpt->lock);
12684 /* remove from queue */
12685 remque((struct qelem *) l);
12686 if (!strcmp(myrpt->cmdnode,l->name))
12687 myrpt->cmdnode[0] = 0;
12688 __kickshort(myrpt);
12689 rpt_mutex_unlock(&myrpt->lock);
12690 if (!l->hasconnected)
12691 rpt_telemetry(myrpt,CONNFAIL,l);
12692 else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
12693 if (myrpt->p.archivedir)
12695 char str[100];
12697 if (!l->hasconnected)
12698 sprintf(str,"LINKFAIL,%s",l->name);
12699 else
12700 sprintf(str,"LINKDISC,%s",l->name);
12701 donodelog(myrpt,str);
12703 if (l->lastf1) ast_frfree(l->lastf1);
12704 l->lastf1 = NULL;
12705 if (l->lastf2) ast_frfree(l->lastf2);
12706 l->lastf2 = NULL;
12707 /* hang-up on call to device */
12708 ast_hangup(l->chan);
12709 ast_hangup(l->pchan);
12710 ast_free(l);
12711 rpt_mutex_lock(&myrpt->lock);
12712 break;
12715 ast_frfree(f);
12716 rpt_mutex_lock(&myrpt->lock);
12717 break;
12719 if (who == l->pchan)
12721 rpt_mutex_unlock(&myrpt->lock);
12722 f = ast_read(l->pchan);
12723 if (!f)
12725 if (debug) printf("@@@@ rpt:Hung Up\n");
12726 toexit = 1;
12727 rpt_mutex_lock(&myrpt->lock);
12728 break;
12730 if (f->frametype == AST_FRAME_VOICE)
12732 if (l->chan) ast_write(l->chan,f);
12734 if (f->frametype == AST_FRAME_CONTROL)
12736 if (f->subclass == AST_CONTROL_HANGUP)
12738 if (debug) printf("@@@@ rpt:Hung Up\n");
12739 ast_frfree(f);
12740 toexit = 1;
12741 rpt_mutex_lock(&myrpt->lock);
12742 break;
12745 ast_frfree(f);
12746 rpt_mutex_lock(&myrpt->lock);
12747 break;
12749 l = l->next;
12751 rpt_mutex_unlock(&myrpt->lock);
12752 if (toexit) break;
12753 if (who == myrpt->monchannel)
12755 f = ast_read(myrpt->monchannel);
12756 if (!f)
12758 if (debug) printf("@@@@ rpt:Hung Up\n");
12759 break;
12761 if (f->frametype == AST_FRAME_VOICE)
12763 if (myrpt->monstream)
12764 ast_writestream(myrpt->monstream,f);
12766 if (f->frametype == AST_FRAME_CONTROL)
12768 if (f->subclass == AST_CONTROL_HANGUP)
12770 if (debug) printf("@@@@ rpt:Hung Up\n");
12771 ast_frfree(f);
12772 break;
12775 ast_frfree(f);
12776 continue;
12778 if (myrpt->parrotchannel && (who == myrpt->parrotchannel))
12780 f = ast_read(myrpt->parrotchannel);
12781 if (!f)
12783 if (debug) printf("@@@@ rpt:Hung Up\n");
12784 break;
12786 if (!myrpt->p.parrotmode)
12788 char myfname[300];
12790 if (myrpt->parrotstream)
12792 ast_closestream(myrpt->parrotstream);
12793 myrpt->parrotstream = 0;
12795 sprintf(myfname,PARROTFILE,myrpt->name,myrpt->parrotcnt);
12796 strcat(myfname,".wav");
12797 unlink(myfname);
12798 } else if (f->frametype == AST_FRAME_VOICE)
12800 if (myrpt->parrotstream)
12801 ast_writestream(myrpt->parrotstream,f);
12803 if (f->frametype == AST_FRAME_CONTROL)
12805 if (f->subclass == AST_CONTROL_HANGUP)
12807 if (debug) printf("@@@@ rpt:Hung Up\n");
12808 ast_frfree(f);
12809 break;
12812 ast_frfree(f);
12813 continue;
12815 if (myrpt->voxchannel && (who == myrpt->voxchannel))
12817 f = ast_read(myrpt->voxchannel);
12818 if (!f)
12820 if (debug) printf("@@@@ rpt:Hung Up\n");
12821 break;
12823 if (f->frametype == AST_FRAME_VOICE)
12825 n = dovox(&myrpt->vox,f->data.ptr,f->datalen / 2);
12826 if (n != myrpt->wasvox)
12828 if (debug) ast_log(LOG_DEBUG,"Node %s, vox %d\n",myrpt->name,n);
12829 myrpt->wasvox = n;
12830 myrpt->voxtostate = 0;
12831 if (n) myrpt->voxtotimer = myrpt->p.voxtimeout_ms;
12832 else myrpt->voxtotimer = 0;
12835 if (f->frametype == AST_FRAME_CONTROL)
12837 if (f->subclass == AST_CONTROL_HANGUP)
12839 if (debug) printf("@@@@ rpt:Hung Up\n");
12840 ast_frfree(f);
12841 break;
12844 ast_frfree(f);
12845 continue;
12847 if (who == myrpt->txpchannel) /* if it was a read from remote tx */
12849 f = ast_read(myrpt->txpchannel);
12850 if (!f)
12852 if (debug) printf("@@@@ rpt:Hung Up\n");
12853 break;
12855 if (f->frametype == AST_FRAME_CONTROL)
12857 if (f->subclass == AST_CONTROL_HANGUP)
12859 if (debug) printf("@@@@ rpt:Hung Up\n");
12860 ast_frfree(f);
12861 break;
12864 ast_frfree(f);
12865 continue;
12868 usleep(100000);
12869 ast_hangup(myrpt->pchannel);
12870 ast_hangup(myrpt->monchannel);
12871 if (myrpt->parrotchannel) ast_hangup(myrpt->parrotchannel);
12872 myrpt->parrotstate = 0;
12873 if (myrpt->voxchannel) ast_hangup(myrpt->voxchannel);
12874 ast_hangup(myrpt->txpchannel);
12875 if (myrpt->txchannel != myrpt->rxchannel) ast_hangup(myrpt->txchannel);
12876 if (myrpt->dahditxchannel != myrpt->txchannel) ast_hangup(myrpt->dahditxchannel);
12877 if (myrpt->lastf1) ast_frfree(myrpt->lastf1);
12878 myrpt->lastf1 = NULL;
12879 if (myrpt->lastf2) ast_frfree(myrpt->lastf2);
12880 myrpt->lastf2 = NULL;
12881 ast_hangup(myrpt->rxchannel);
12882 rpt_mutex_lock(&myrpt->lock);
12883 l = myrpt->links.next;
12884 while(l != &myrpt->links)
12886 struct rpt_link *ll = l;
12887 /* remove from queue */
12888 remque((struct qelem *) l);
12889 /* hang-up on call to device */
12890 if (l->chan) ast_hangup(l->chan);
12891 ast_hangup(l->pchan);
12892 l = l->next;
12893 ast_free(ll);
12895 if (myrpt->xlink == 1) myrpt->xlink = 2;
12896 rpt_mutex_unlock(&myrpt->lock);
12897 if (debug) printf("@@@@ rpt:Hung up channel\n");
12898 myrpt->rpt_thread = AST_PTHREADT_STOP;
12899 pthread_exit(NULL);
12900 return NULL;
12904 static void *rpt_master(void *ignore)
12906 int i,n;
12907 pthread_attr_t attr;
12908 struct ast_config *cfg;
12909 char *this,*val;
12911 /* init nodelog queue */
12912 nodelog.next = nodelog.prev = &nodelog;
12913 /* go thru all the specified repeaters */
12914 this = NULL;
12915 n = 0;
12916 #ifndef OLD_ASTERISK
12917 /* wait until asterisk starts */
12918 while(!ast_test_flag(&ast_options,AST_OPT_FLAG_FULLY_BOOTED))
12919 usleep(250000);
12920 #endif
12921 #ifdef NEW_ASTERISK
12922 rpt_vars[n].cfg = ast_config_load("rpt.conf",config_flags);
12923 #else
12924 rpt_vars[n].cfg = ast_config_load("rpt.conf");
12925 #endif
12926 cfg = rpt_vars[n].cfg;
12927 if (!cfg) {
12928 ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf. Radio Repeater disabled.\n");
12929 pthread_exit(NULL);
12931 while((this = ast_category_browse(cfg,this)) != NULL)
12933 for(i = 0 ; i < strlen(this) ; i++){
12934 if((this[i] < '0') || (this[i] > '9'))
12935 break;
12937 if(i != strlen(this)) continue; /* Not a node defn */
12938 memset(&rpt_vars[n],0,sizeof(rpt_vars[n]));
12939 rpt_vars[n].name = ast_strdup(this);
12940 val = (char *) ast_variable_retrieve(cfg,this,"rxchannel");
12941 if (val) rpt_vars[n].rxchanname = ast_strdup(val);
12942 val = (char *) ast_variable_retrieve(cfg,this,"txchannel");
12943 if (val) rpt_vars[n].txchanname = ast_strdup(val);
12944 rpt_vars[n].remote = 0;
12945 rpt_vars[n].remoterig = "";
12946 val = (char *) ast_variable_retrieve(cfg,this,"remote");
12947 if (val)
12949 rpt_vars[n].remoterig = ast_strdup(val);
12950 rpt_vars[n].remote = 1;
12952 val = (char *) ast_variable_retrieve(cfg,this,"radiotype");
12953 if (val) rpt_vars[n].remoterig = ast_strdup(val);
12954 ast_mutex_init(&rpt_vars[n].lock);
12955 ast_mutex_init(&rpt_vars[n].remlock);
12956 ast_mutex_init(&rpt_vars[n].statpost_lock);
12957 rpt_vars[n].tele.next = &rpt_vars[n].tele;
12958 rpt_vars[n].tele.prev = &rpt_vars[n].tele;
12959 rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
12960 rpt_vars[n].tailmessagen = 0;
12961 #ifdef _MDC_DECODE_H_
12962 rpt_vars[n].mdc = mdc_decoder_new(8000);
12963 #endif
12964 n++;
12966 nrpts = n;
12967 ast_config_destroy(cfg);
12969 /* start em all */
12970 for(i = 0; i < n; i++)
12972 load_rpt_vars(i,1);
12974 /* if is a remote, dont start one for it */
12975 if (rpt_vars[i].remote)
12977 if(retreive_memory(&rpt_vars[i],"init")){ /* Try to retreive initial memory channel */
12978 if (!strcmp(rpt_vars[i].remoterig,remote_rig_rtx450))
12979 strncpy(rpt_vars[i].freq, "446.500", sizeof(rpt_vars[i].freq) - 1);
12980 else
12981 strncpy(rpt_vars[i].freq, "146.580", sizeof(rpt_vars[i].freq) - 1);
12982 strncpy(rpt_vars[i].rxpl, "100.0", sizeof(rpt_vars[i].rxpl) - 1);
12984 strncpy(rpt_vars[i].txpl, "100.0", sizeof(rpt_vars[i].txpl) - 1);
12985 rpt_vars[i].remmode = REM_MODE_FM;
12986 rpt_vars[i].offset = REM_SIMPLEX;
12987 rpt_vars[i].powerlevel = REM_LOWPWR;
12989 continue;
12991 else /* is a normal repeater */
12993 rpt_vars[i].p.memory = rpt_vars[i].name;
12994 if(retreive_memory(&rpt_vars[i],"radiofreq")){ /* Try to retreive initial memory channel */
12995 if (!strcmp(rpt_vars[i].remoterig,remote_rig_rtx450))
12996 strncpy(rpt_vars[i].freq, "446.500", sizeof(rpt_vars[i].freq) - 1);
12997 else if (!strcmp(rpt_vars[i].remoterig,remote_rig_rtx150))
12998 strncpy(rpt_vars[i].freq, "146.580", sizeof(rpt_vars[i].freq) - 1);
12999 strncpy(rpt_vars[i].rxpl, "100.0", sizeof(rpt_vars[i].rxpl) - 1);
13001 strncpy(rpt_vars[i].txpl, "100.0", sizeof(rpt_vars[i].txpl) - 1);
13002 rpt_vars[i].remmode = REM_MODE_FM;
13003 rpt_vars[i].offset = REM_SIMPLEX;
13004 rpt_vars[i].powerlevel = REM_LOWPWR;
13006 ast_log(LOG_NOTICE,"Normal Repeater Init %s %s %s\n",rpt_vars[i].name, rpt_vars[i].remoterig, rpt_vars[i].freq);
13008 if (!rpt_vars[i].p.ident)
13010 ast_log(LOG_WARNING,"Did not specify ident for node %s\n",rpt_vars[i].name);
13011 ast_config_destroy(cfg);
13012 pthread_exit(NULL);
13014 pthread_attr_init(&attr);
13015 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
13016 ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]);
13018 usleep(500000);
13019 time(&starttime);
13020 for(;;)
13022 /* Now monitor each thread, and restart it if necessary */
13023 for(i = 0; i < n; i++)
13025 int rv;
13026 if (rpt_vars[i].remote) continue;
13027 if (rpt_vars[i].rpt_thread == AST_PTHREADT_STOP)
13028 rv = -1;
13029 else
13030 rv = pthread_kill(rpt_vars[i].rpt_thread,0);
13031 if (rv)
13033 if(time(NULL) - rpt_vars[i].lastthreadrestarttime <= 15)
13035 if(rpt_vars[i].threadrestarts >= 5)
13037 ast_log(LOG_ERROR,"Continual RPT thread restarts, killing Asterisk\n");
13038 exit(1); /* Stuck in a restart loop, kill Asterisk and start over */
13040 else
13042 ast_log(LOG_NOTICE,"RPT thread restarted on %s\n",rpt_vars[i].name);
13043 rpt_vars[i].threadrestarts++;
13046 else
13047 rpt_vars[i].threadrestarts = 0;
13049 rpt_vars[i].lastthreadrestarttime = time(NULL);
13050 pthread_attr_init(&attr);
13051 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
13052 ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]);
13053 /* if (!rpt_vars[i].xlink) */
13054 ast_log(LOG_WARNING, "rpt_thread restarted on node %s\n", rpt_vars[i].name);
13058 for(;;)
13060 struct nodelog *nodep;
13061 char *space,datestr[100],fname[300];
13062 int fd;
13064 ast_mutex_lock(&nodeloglock);
13065 nodep = nodelog.next;
13066 if(nodep == &nodelog) /* if nothing in queue */
13068 ast_mutex_unlock(&nodeloglock);
13069 break;
13071 remque((struct qelem *)nodep);
13072 ast_mutex_unlock(&nodeloglock);
13073 space = strchr(nodep->str,' ');
13074 if (!space)
13076 ast_free(nodep);
13077 continue;
13079 *space = 0;
13080 strftime(datestr,sizeof(datestr) - 1,"%Y%m%d",
13081 localtime(&nodep->timestamp));
13082 sprintf(fname,"%s/%s/%s.txt",nodep->archivedir,
13083 nodep->str,datestr);
13084 fd = open(fname,O_WRONLY | O_CREAT | O_APPEND,0600);
13085 if (fd == -1)
13087 ast_log(LOG_ERROR,"Cannot open node log file %s for write",space + 1);
13088 ast_free(nodep);
13089 continue;
13091 if (write(fd,space + 1,strlen(space + 1)) !=
13092 strlen(space + 1))
13094 ast_log(LOG_ERROR,"Cannot write node log file %s for write",space + 1);
13095 ast_free(nodep);
13096 continue;
13098 close(fd);
13099 ast_free(nodep);
13101 sleep(2);
13103 ast_config_destroy(cfg);
13104 pthread_exit(NULL);
13107 static int rpt_exec(struct ast_channel *chan, void *data)
13109 int res=-1,i,rem_totx,rem_rx,remkeyed,n,phone_mode = 0;
13110 int iskenwood_pci4,authtold,authreq,setting,notremming,reming;
13111 int ismuted,dtmfed,phone_vox = 0;
13112 #ifdef OLD_ASTERISK
13113 struct localuser *u;
13114 #endif
13115 char tmp[256], keyed = 0,keyed1 = 0;
13116 char *options,*stringp,*tele,c,*altp,*memp;
13117 char sx[320],*sy;
13118 struct rpt *myrpt;
13119 struct ast_frame *f,*f1,*f2;
13120 struct ast_channel *who;
13121 struct ast_channel *cs[20];
13122 struct rpt_link *l;
13123 DAHDI_CONFINFO ci; /* conference info */
13124 DAHDI_PARAMS par;
13125 int ms,elap,nullfd;
13126 time_t t,last_timeout_warning;
13127 struct dahdi_radio_param z;
13128 struct rpt_tele *telem;
13129 int numlinks;
13131 nullfd = open("/dev/null",O_RDWR);
13132 if (ast_strlen_zero(data)) {
13133 ast_log(LOG_WARNING, "Rpt requires an argument (system node)\n");
13134 return -1;
13137 strncpy(tmp, (char *)data, sizeof(tmp)-1);
13138 time(&t);
13139 /* if time has externally shifted negative, screw it */
13140 if (t < starttime) t = starttime + START_DELAY;
13141 if ((!starttime) || (t < (starttime + START_DELAY)))
13143 ast_log(LOG_NOTICE,"Node %s rejecting call: too soon!\n",tmp);
13144 ast_safe_sleep(chan,3000);
13145 return -1;
13148 ast_log(LOG_NOTICE,"parsing argument=%s \n",tmp);
13150 altp=strstr(tmp, "|*");
13151 if(altp){
13152 altp[0]=0;
13153 altp++;
13156 memp=strstr(tmp, "|M");
13157 if(memp){
13158 memp[0]=0;
13159 memp+=2;
13162 stringp=tmp;
13163 strsep(&stringp, "|");
13164 options = stringp;
13166 ast_log(LOG_NOTICE,"options=%s \n",options);
13167 if(memp>0)ast_log(LOG_NOTICE,"memp=%s \n",memp);
13168 if(altp>0)ast_log(LOG_NOTICE,"altp=%s \n",altp);
13170 myrpt = NULL;
13171 /* see if we can find our specified one */
13172 for(i = 0; i < nrpts; i++)
13174 /* if name matches, assign it and exit loop */
13175 if (!strcmp(tmp,rpt_vars[i].name))
13177 myrpt = &rpt_vars[i];
13178 break;
13182 pbx_builtin_setvar_helper(chan, "RPT_STAT_ERR", "");
13184 if (myrpt == NULL)
13186 pbx_builtin_setvar_helper(chan, "RPT_STAT_ERR", "NODE_NOT_FOUND");
13187 ast_log(LOG_WARNING, "Cannot find specified system node %s\n",tmp);
13188 return (priority_jump(NULL,chan));
13191 numlinks=linkcount(myrpt);
13193 if(options && *options == 'q')
13195 int res=0;
13196 char buf2[128];
13198 if(myrpt->keyed)
13199 pbx_builtin_setvar_helper(chan, "RPT_STAT_RXKEYED", "1");
13200 else
13201 pbx_builtin_setvar_helper(chan, "RPT_STAT_RXKEYED", "0");
13203 if(myrpt->txkeyed)
13204 pbx_builtin_setvar_helper(chan, "RPT_STAT_TXKEYED", "1");
13205 else
13206 pbx_builtin_setvar_helper(chan, "RPT_STAT_TXKEYED", "0");
13208 snprintf(buf2,sizeof(buf2),"%s=%i", "RPT_STAT_XLINK", myrpt->xlink);
13209 pbx_builtin_setvar(chan, buf2);
13210 snprintf(buf2,sizeof(buf2),"%s=%i", "RPT_STAT_LINKS", numlinks);
13211 pbx_builtin_setvar(chan, buf2);
13212 snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_WASCHAN", myrpt->waschan);
13213 pbx_builtin_setvar(chan, buf2);
13214 snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_NOWCHAN", myrpt->nowchan);
13215 pbx_builtin_setvar(chan, buf2);
13216 snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_DUPLEX", myrpt->p.duplex);
13217 pbx_builtin_setvar(chan, buf2);
13218 snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_PARROT", myrpt->p.parrotmode);
13219 pbx_builtin_setvar(chan, buf2);
13220 //snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_PHONEVOX", myrpt->phonevox);
13221 //pbx_builtin_setvar(chan, buf2);
13222 //snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_CONNECTED", myrpt->connected);
13223 //pbx_builtin_setvar(chan, buf2);
13224 snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_CALLMODE", myrpt->callmode);
13225 pbx_builtin_setvar(chan, buf2);
13226 snprintf(buf2,sizeof(buf2),"%s=%s", "RPT_STAT_LASTTONE", myrpt->lasttone);
13227 pbx_builtin_setvar(chan, buf2);
13229 res=priority_jump(myrpt,chan);
13230 return res;
13233 if(options && *options == 'o')
13235 return(channel_revert(myrpt));
13238 #if 0
13239 if((altp)&&(*options == 'Z'))
13241 rpt_push_alt_macro(myrpt,altp);
13242 return 0;
13244 #endif
13247 /* if not phone access, must be an IAX connection */
13248 if (options && ((*options == 'P') || (*options == 'D') || (*options == 'R') || (*options == 'S')))
13250 int val;
13252 pbx_builtin_setvar_helper(chan, "RPT_STAT_BUSY", "0");
13254 myrpt->bargechan=0;
13255 if(options && strstr(options, "f")>0)
13257 myrpt->bargechan=1;
13260 if(memp>0)
13262 char radiochan;
13263 radiochan=strtod(data,NULL);
13264 // if(myrpt->nowchan!=0 && radiochan!=myrpt->nowchan && !myrpt->bargechan)
13266 if(numlinks>0 && radiochan!=myrpt->nowchan && !myrpt->bargechan)
13268 pbx_builtin_setvar_helper(chan, "RPT_STAT_BUSY", "1");
13269 ast_log(LOG_NOTICE, "Radio Channel Busy.\n");
13270 return (priority_jump(myrpt,chan));
13272 else if(radiochan!=myrpt->nowchan || myrpt->bargechan)
13274 channel_steer(myrpt,memp);
13277 if(altp)rpt_push_alt_macro(myrpt,altp);
13278 phone_mode = 1;
13279 if (*options == 'D') phone_mode = 2;
13280 if (*options == 'S') phone_mode = 3;
13281 ast_set_callerid(chan,"0","app_rpt user","0");
13282 val = 1;
13283 ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0);
13284 if ((*(options + 1) == 'V') || (*(options + 1) == 'v')) phone_vox = 1;
13286 else
13288 #ifdef ALLOW_LOCAL_CHANNELS
13289 /* Check to insure the connection is IAX2 or Local*/
13290 if ( (strncmp(chan->name,"IAX2",4)) && (strncmp(chan->name,"Local",5)) ) {
13291 ast_log(LOG_WARNING, "We only accept links via IAX2 or Local!!\n");
13292 return -1;
13294 #else
13295 if (strncmp(chan->name,"IAX2",4))
13297 ast_log(LOG_WARNING, "We only accept links via IAX2!!\n");
13298 return -1;
13300 #endif
13301 if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable){ /* Do not allow incoming radio connections if disabled */
13302 ast_log(LOG_NOTICE, "Connect attempt to node %s with tx disabled", myrpt->name);
13303 return -1;
13306 if (options && (*options == 'R'))
13308 /* Parts of this section taken from app_parkandannounce */
13309 char *return_context;
13310 int l, m, lot, timeout = 0;
13311 char tmp[256],*template;
13312 char *working, *context, *exten, *priority;
13313 char *s,*orig_s;
13315 rpt_mutex_lock(&myrpt->lock);
13316 m = myrpt->callmode;
13317 rpt_mutex_unlock(&myrpt->lock);
13319 if ((!myrpt->p.nobusyout) && m)
13321 if (chan->_state != AST_STATE_UP)
13323 ast_indicate(chan,AST_CONTROL_BUSY);
13325 while(ast_safe_sleep(chan,10000) != -1);
13326 return -1;
13329 if (chan->_state != AST_STATE_UP)
13331 ast_answer(chan);
13332 if (!phone_mode) send_newkey(chan);
13335 l=strlen(options)+2;
13336 orig_s=ast_malloc(l);
13337 if(!orig_s) {
13338 ast_log(LOG_WARNING, "Out of memory\n");
13339 return -1;
13341 s=orig_s;
13342 strncpy(s,options,l);
13344 template=strsep(&s,"|");
13345 if(!template) {
13346 ast_log(LOG_WARNING, "An announce template must be defined\n");
13347 ast_free(orig_s);
13348 return -1;
13351 if(s) {
13352 timeout = atoi(strsep(&s, "|"));
13353 timeout *= 1000;
13356 return_context = s;
13358 if(return_context != NULL) {
13359 /* set the return context. Code borrowed from the Goto builtin */
13361 working = return_context;
13362 context = strsep(&working, "|");
13363 exten = strsep(&working, "|");
13364 if(!exten) {
13365 /* Only a priority in this one */
13366 priority = context;
13367 exten = NULL;
13368 context = NULL;
13369 } else {
13370 priority = strsep(&working, "|");
13371 if(!priority) {
13372 /* Only an extension and priority in this one */
13373 priority = exten;
13374 exten = context;
13375 context = NULL;
13378 if(atoi(priority) < 0) {
13379 ast_log(LOG_WARNING, "Priority '%s' must be a number > 0\n", priority);
13380 ast_free(orig_s);
13381 return -1;
13383 /* At this point we have a priority and maybe an extension and a context */
13384 chan->priority = atoi(priority);
13385 #ifdef OLD_ASTERISK
13386 if(exten && strcasecmp(exten, "BYEXTENSION"))
13387 #else
13388 if(exten)
13389 #endif
13390 strncpy(chan->exten, exten, sizeof(chan->exten)-1);
13391 if(context)
13392 strncpy(chan->context, context, sizeof(chan->context)-1);
13393 } else { /* increment the priority by default*/
13394 chan->priority++;
13397 if(option_verbose > 2) {
13398 ast_verbose( VERBOSE_PREFIX_3 "Return Context: (%s,%s,%d) ID: %s\n", chan->context,chan->exten, chan->priority, chan->cid.cid_num);
13399 if(!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) {
13400 ast_verbose( VERBOSE_PREFIX_3 "Warning: Return Context Invalid, call will return to default|s\n");
13404 /* we are using masq_park here to protect * from touching the channel once we park it. If the channel comes out of timeout
13405 before we are done announcing and the channel is messed with, Kablooeee. So we use Masq to prevent this. */
13407 ast_masq_park_call(chan, NULL, timeout, &lot);
13409 if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "Call Parking Called, lot: %d, timeout: %d, context: %s\n", lot, timeout, return_context);
13411 snprintf(tmp,sizeof(tmp) - 1,"%d,%s",lot,template + 1);
13413 rpt_telemetry(myrpt,REV_PATCH,tmp);
13415 ast_free(orig_s);
13417 return 0;
13421 if (!options)
13423 struct ast_hostent ahp;
13424 struct hostent *hp;
13425 struct in_addr ia;
13426 char hisip[100],nodeip[100],*val, *s, *s1, *s2, *s3, *b,*b1;
13428 /* look at callerid to see what node this comes from */
13429 if (!chan->cid.cid_num) /* if doesn't have caller id */
13431 ast_log(LOG_WARNING, "Does not have callerid on %s\n",tmp);
13432 return -1;
13434 /* get his IP from IAX2 module */
13435 memset(hisip,0,sizeof(hisip));
13436 #ifdef ALLOW_LOCAL_CHANNELS
13437 /* set IP address if this is a local connection*/
13438 if (strncmp(chan->name,"Local",5)==0) {
13439 strcpy(hisip,"127.0.0.1");
13440 } else {
13441 pbx_substitute_variables_helper(chan,"${IAXPEER(CURRENTCHANNEL)}",hisip,sizeof(hisip) - 1);
13443 #else
13444 pbx_substitute_variables_helper(chan,"${IAXPEER(CURRENTCHANNEL)}",hisip,sizeof(hisip) - 1);
13445 #endif
13447 if (!hisip[0])
13449 ast_log(LOG_WARNING, "Link IP address cannot be determined!!\n");
13450 return -1;
13453 ast_callerid_parse(chan->cid.cid_num,&b,&b1);
13454 ast_shrink_phone_number(b1);
13455 if (!strcmp(myrpt->name,b1))
13457 ast_log(LOG_WARNING, "Trying to link to self!!\n");
13458 return -1;
13461 if (*b1 < '1')
13463 ast_log(LOG_WARNING, "Node %s Invalid for connection here!!\n",b1);
13464 return -1;
13468 /* look for his reported node string */
13469 val = node_lookup(myrpt,b1);
13470 if (!val)
13472 ast_log(LOG_WARNING, "Reported node %s cannot be found!!\n",b1);
13473 return -1;
13475 strncpy(tmp,val,sizeof(tmp) - 1);
13476 s = tmp;
13477 s1 = strsep(&s,",");
13478 if (!strchr(s1,':') && strchr(s1,'/') && strncasecmp(s1, "local/", 6))
13480 sy = strchr(s1,'/');
13481 *sy = 0;
13482 sprintf(sx,"%s:4569/%s",s1,sy + 1);
13483 s1 = sx;
13485 s2 = strsep(&s,",");
13486 if (!s2)
13488 ast_log(LOG_WARNING, "Reported node %s not in correct format!!\n",b1);
13489 return -1;
13491 if (strcmp(s2,"NONE")) {
13492 hp = ast_gethostbyname(s2, &ahp);
13493 if (!hp)
13495 ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n",b1,s2);
13496 return -1;
13498 memcpy(&ia,hp->h_addr,sizeof(in_addr_t));
13499 #ifdef OLD_ASTERISK
13500 ast_inet_ntoa(nodeip,sizeof(nodeip) - 1,ia);
13501 #else
13502 strncpy(nodeip,ast_inet_ntoa(ia),sizeof(nodeip) - 1);
13503 #endif
13504 s3 = strchr(hisip,':');
13505 if (s3) *s3 = 0;
13506 if (strcmp(hisip,nodeip))
13508 s3 = strchr(s1,'@');
13509 if (s3) s1 = s3 + 1;
13510 s3 = strchr(s1,'/');
13511 if (s3) *s3 = 0;
13512 s3 = strchr(s1,':');
13513 if (s3) *s3 = 0;
13514 hp = ast_gethostbyname(s1, &ahp);
13515 if (!hp)
13517 ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n",b1,s1);
13518 return -1;
13520 memcpy(&ia,hp->h_addr,sizeof(in_addr_t));
13521 #ifdef OLD_ASTERISK
13522 ast_inet_ntoa(nodeip,sizeof(nodeip) - 1,ia);
13523 #else
13524 strncpy(nodeip,ast_inet_ntoa(ia),sizeof(nodeip) - 1);
13525 #endif
13526 if (strcmp(hisip,nodeip))
13528 ast_log(LOG_WARNING, "Node %s IP %s does not match link IP %s!!\n",b1,nodeip,hisip);
13529 return -1;
13535 /* if is not a remote */
13536 if (!myrpt->remote)
13538 char *b,*b1;
13539 int reconnects = 0;
13541 rpt_mutex_lock(&myrpt->lock);
13542 i = myrpt->xlink;
13543 rpt_mutex_unlock(&myrpt->lock);
13544 if (i)
13546 ast_log(LOG_WARNING, "Cannot connect to node %s, system busy\n",myrpt->name);
13547 return -1;
13549 /* look at callerid to see what node this comes from */
13550 if (!chan->cid.cid_num) /* if doesn't have caller id */
13552 ast_log(LOG_WARNING, "Doesnt have callerid on %s\n",tmp);
13553 return -1;
13556 ast_callerid_parse(chan->cid.cid_num,&b,&b1);
13557 ast_shrink_phone_number(b1);
13558 if (!strcmp(myrpt->name,b1))
13560 ast_log(LOG_WARNING, "Trying to link to self!!\n");
13561 return -1;
13563 rpt_mutex_lock(&myrpt->lock);
13564 l = myrpt->links.next;
13565 /* try to find this one in queue */
13566 while(l != &myrpt->links)
13568 if (l->name[0] == '0')
13570 l = l->next;
13571 continue;
13573 /* if found matching string */
13574 if (!strcmp(l->name,b1)) break;
13575 l = l->next;
13577 /* if found */
13578 if (l != &myrpt->links)
13580 l->killme = 1;
13581 l->retries = l->max_retries + 1;
13582 l->disced = 2;
13583 reconnects = l->reconnects;
13584 reconnects++;
13585 rpt_mutex_unlock(&myrpt->lock);
13586 usleep(500000);
13587 } else
13588 rpt_mutex_unlock(&myrpt->lock);
13589 /* establish call in tranceive mode */
13590 l = ast_malloc(sizeof(struct rpt_link));
13591 if (!l)
13593 ast_log(LOG_WARNING, "Unable to malloc\n");
13594 pthread_exit(NULL);
13596 /* zero the silly thing */
13597 memset((char *)l,0,sizeof(struct rpt_link));
13598 l->mode = 1;
13599 strncpy(l->name,b1,MAXNODESTR - 1);
13600 l->isremote = 0;
13601 l->chan = chan;
13602 l->connected = 1;
13603 l->thisconnected = 1;
13604 l->hasconnected = 1;
13605 l->reconnects = reconnects;
13606 l->phonemode = phone_mode;
13607 l->phonevox = phone_vox;
13608 l->lastf1 = NULL;
13609 l->lastf2 = NULL;
13610 l->dtmfed = 0;
13611 voxinit_link(l,1);
13612 ast_set_read_format(l->chan,AST_FORMAT_SLINEAR);
13613 ast_set_write_format(l->chan,AST_FORMAT_SLINEAR);
13614 /* allocate a pseudo-channel thru asterisk */
13615 l->pchan = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
13616 if (!l->pchan)
13618 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
13619 pthread_exit(NULL);
13621 ast_set_read_format(l->pchan,AST_FORMAT_SLINEAR);
13622 ast_set_write_format(l->pchan,AST_FORMAT_SLINEAR);
13623 #ifdef AST_CDR_FLAG_POST_DISABLED
13624 if (l->pchan->cdr)
13625 ast_set_flag(l->pchan->cdr,AST_CDR_FLAG_POST_DISABLED);
13626 #endif
13627 /* make a conference for the tx */
13628 ci.chan = 0;
13629 ci.confno = myrpt->conf;
13630 ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER;
13631 /* first put the channel on the conference in proper mode */
13632 if (ioctl(l->pchan->fds[0],DAHDI_SETCONF,&ci) == -1)
13634 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
13635 pthread_exit(NULL);
13637 rpt_mutex_lock(&myrpt->lock);
13638 if ((phone_mode == 2) && (!phone_vox)) l->lastrealrx = 1;
13639 l->max_retries = MAX_RETRIES;
13640 /* insert at end of queue */
13641 insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
13642 __kickshort(myrpt);
13643 rpt_mutex_unlock(&myrpt->lock);
13644 if (chan->_state != AST_STATE_UP) {
13645 ast_answer(chan);
13646 if (!phone_mode) send_newkey(chan);
13648 if (myrpt->p.archivedir)
13650 char str[100];
13652 if (l->phonemode)
13653 sprintf(str,"LINK(P),%s",l->name);
13654 else
13655 sprintf(str,"LINK,%s",l->name);
13656 donodelog(myrpt,str);
13658 if (!phone_mode) send_newkey(chan);
13659 return AST_PBX_KEEPALIVE;
13661 /* well, then it is a remote */
13662 rpt_mutex_lock(&myrpt->lock);
13663 /* if remote, error if anyone else already linked */
13664 if (myrpt->remoteon)
13666 rpt_mutex_unlock(&myrpt->lock);
13667 usleep(500000);
13668 if (myrpt->remoteon)
13670 ast_log(LOG_WARNING, "Trying to use busy link on %s\n",tmp);
13671 #ifdef AST_CDR_FLAG_POST_DISABLED
13672 if (chan->cdr)
13673 ast_set_flag(chan->cdr,AST_CDR_FLAG_POST_DISABLED);
13674 #endif
13675 return -1;
13677 rpt_mutex_lock(&myrpt->lock);
13679 if (myrpt->p.rptnode)
13681 char killedit = 0;
13682 time_t now;
13684 time(&now);
13685 for(i = 0; i < nrpts; i++)
13687 if (!strcasecmp(rpt_vars[i].name,myrpt->p.rptnode))
13689 if ((rpt_vars[i].links.next != &rpt_vars[i].links) ||
13690 rpt_vars[i].keyed ||
13691 ((rpt_vars[i].lastkeyedtime + RPT_LOCKOUT_SECS) > now) ||
13692 rpt_vars[i].txkeyed ||
13693 ((rpt_vars[i].lasttxkeyedtime + RPT_LOCKOUT_SECS) > now))
13695 rpt_mutex_unlock(&myrpt->lock);
13696 ast_log(LOG_WARNING, "Trying to use busy link (repeater node %s) on %s\n",rpt_vars[i].name,tmp);
13697 #ifdef AST_CDR_FLAG_POST_DISABLED
13698 if (chan->cdr)
13699 ast_set_flag(chan->cdr,AST_CDR_FLAG_POST_DISABLED);
13700 #endif
13701 return -1;
13703 while(rpt_vars[i].xlink != 3)
13705 if (!killedit)
13707 ast_softhangup(rpt_vars[i].rxchannel,AST_SOFTHANGUP_DEV);
13708 rpt_vars[i].xlink = 1;
13709 killedit = 1;
13711 rpt_mutex_unlock(&myrpt->lock);
13712 if (ast_safe_sleep(chan,500) == -1)
13714 #ifdef AST_CDR_FLAG_POST_DISABLED
13715 if (chan->cdr)
13716 ast_set_flag(chan->cdr,AST_CDR_FLAG_POST_DISABLED);
13717 #endif
13718 return -1;
13720 rpt_mutex_lock(&myrpt->lock);
13722 break;
13727 if ( (!strcmp(myrpt->remoterig, remote_rig_rbi)||!strcmp(myrpt->remoterig, remote_rig_ppp16)) &&
13728 (ioperm(myrpt->p.iobase,1,1) == -1))
13730 rpt_mutex_unlock(&myrpt->lock);
13731 ast_log(LOG_WARNING, "Can't get io permission on IO port %x hex\n",myrpt->p.iobase);
13732 return -1;
13734 myrpt->remoteon = 1;
13735 #ifdef OLD_ASTERISK
13736 LOCAL_USER_ADD(u);
13737 #endif
13738 rpt_mutex_unlock(&myrpt->lock);
13739 /* find our index, and load the vars initially */
13740 for(i = 0; i < nrpts; i++)
13742 if (&rpt_vars[i] == myrpt)
13744 load_rpt_vars(i,0);
13745 break;
13748 rpt_mutex_lock(&myrpt->lock);
13749 tele = strchr(myrpt->rxchanname,'/');
13750 if (!tele)
13752 fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
13753 rpt_mutex_unlock(&myrpt->lock);
13754 pthread_exit(NULL);
13756 *tele++ = 0;
13757 myrpt->rxchannel = ast_request(myrpt->rxchanname,AST_FORMAT_SLINEAR,tele,NULL);
13758 myrpt->dahdirxchannel = NULL;
13759 if (!strcasecmp(myrpt->rxchanname,"DAHDI"))
13760 myrpt->dahdirxchannel = myrpt->rxchannel;
13761 if (myrpt->rxchannel)
13763 ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
13764 ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
13765 #ifdef AST_CDR_FLAG_POST_DISABLED
13766 if (myrpt->rxchannel->cdr)
13767 ast_set_flag(myrpt->rxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
13768 #endif
13769 #ifndef NEW_ASTERISK
13770 myrpt->rxchannel->whentohangup = 0;
13771 #endif
13772 myrpt->rxchannel->appl = "Apprpt";
13773 myrpt->rxchannel->data = "(Link Rx)";
13774 if (option_verbose > 2)
13775 ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
13776 myrpt->rxchanname,tele,myrpt->rxchannel->name);
13777 rpt_mutex_unlock(&myrpt->lock);
13778 ast_call(myrpt->rxchannel,tele,999);
13779 rpt_mutex_lock(&myrpt->lock);
13781 else
13783 fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
13784 rpt_mutex_unlock(&myrpt->lock);
13785 pthread_exit(NULL);
13787 *--tele = '/';
13788 myrpt->dahditxchannel = NULL;
13789 if (myrpt->txchanname)
13791 tele = strchr(myrpt->txchanname,'/');
13792 if (!tele)
13794 fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
13795 rpt_mutex_unlock(&myrpt->lock);
13796 ast_hangup(myrpt->rxchannel);
13797 pthread_exit(NULL);
13799 *tele++ = 0;
13800 myrpt->txchannel = ast_request(myrpt->txchanname,AST_FORMAT_SLINEAR,tele,NULL);
13801 if (!strncasecmp(myrpt->txchanname,"DAHDI",3))
13802 myrpt->dahditxchannel = myrpt->txchannel;
13803 if (myrpt->txchannel)
13805 ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
13806 ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
13807 #ifdef AST_CDR_FLAG_POST_DISABLED
13808 if (myrpt->txchannel->cdr)
13809 ast_set_flag(myrpt->txchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
13810 #endif
13811 #ifndef NEW_ASTERISK
13812 myrpt->txchannel->whentohangup = 0;
13813 #endif
13814 myrpt->txchannel->appl = "Apprpt";
13815 myrpt->txchannel->data = "(Link Tx)";
13816 if (option_verbose > 2)
13817 ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
13818 myrpt->txchanname,tele,myrpt->txchannel->name);
13819 rpt_mutex_unlock(&myrpt->lock);
13820 ast_call(myrpt->txchannel,tele,999);
13821 rpt_mutex_lock(&myrpt->lock);
13823 else
13825 fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
13826 rpt_mutex_unlock(&myrpt->lock);
13827 ast_hangup(myrpt->rxchannel);
13828 pthread_exit(NULL);
13830 *--tele = '/';
13832 else
13834 myrpt->txchannel = myrpt->rxchannel;
13835 if (!strncasecmp(myrpt->rxchanname,"DAHDI",3))
13836 myrpt->dahditxchannel = myrpt->rxchannel;
13838 /* allocate a pseudo-channel thru asterisk */
13839 myrpt->pchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
13840 if (!myrpt->pchannel)
13842 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
13843 rpt_mutex_unlock(&myrpt->lock);
13844 if (myrpt->txchannel != myrpt->rxchannel)
13845 ast_hangup(myrpt->txchannel);
13846 ast_hangup(myrpt->rxchannel);
13847 pthread_exit(NULL);
13849 ast_set_read_format(myrpt->pchannel,AST_FORMAT_SLINEAR);
13850 ast_set_write_format(myrpt->pchannel,AST_FORMAT_SLINEAR);
13851 #ifdef AST_CDR_FLAG_POST_DISABLED
13852 if (myrpt->pchannel->cdr)
13853 ast_set_flag(myrpt->pchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
13854 #endif
13855 if (!myrpt->dahdirxchannel) myrpt->dahdirxchannel = myrpt->pchannel;
13856 if (!myrpt->dahditxchannel) myrpt->dahditxchannel = myrpt->pchannel;
13857 /* make a conference for the pseudo */
13858 ci.chan = 0;
13859 ci.confno = -1; /* make a new conf */
13860 ci.confmode = DAHDI_CONF_CONFANNMON ;
13861 /* first put the channel on the conference in announce/monitor mode */
13862 if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
13864 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
13865 rpt_mutex_unlock(&myrpt->lock);
13866 ast_hangup(myrpt->pchannel);
13867 if (myrpt->txchannel != myrpt->rxchannel)
13868 ast_hangup(myrpt->txchannel);
13869 ast_hangup(myrpt->rxchannel);
13870 pthread_exit(NULL);
13872 /* save pseudo channel conference number */
13873 myrpt->conf = myrpt->txconf = ci.confno;
13874 /* if serial io port, open it */
13875 myrpt->iofd = -1;
13876 if (myrpt->p.ioport && ((myrpt->iofd = openserial(myrpt,myrpt->p.ioport)) == -1))
13878 rpt_mutex_unlock(&myrpt->lock);
13879 ast_hangup(myrpt->pchannel);
13880 if (myrpt->txchannel != myrpt->rxchannel)
13881 ast_hangup(myrpt->txchannel);
13882 ast_hangup(myrpt->rxchannel);
13883 pthread_exit(NULL);
13885 iskenwood_pci4 = 0;
13886 memset(&z,0,sizeof(z));
13887 if ((myrpt->iofd < 1) && (myrpt->txchannel == myrpt->dahditxchannel))
13889 z.radpar = DAHDI_RADPAR_REMMODE;
13890 z.data = DAHDI_RADPAR_REM_NONE;
13891 res = ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z);
13892 /* if PCIRADIO and kenwood selected */
13893 if ((!res) && (!strcmp(myrpt->remoterig,remote_rig_kenwood)))
13895 z.radpar = DAHDI_RADPAR_UIOMODE;
13896 z.data = 1;
13897 if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
13899 ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
13900 return -1;
13902 z.radpar = DAHDI_RADPAR_UIODATA;
13903 z.data = 3;
13904 if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
13906 ast_log(LOG_ERROR,"Cannot set UIODATA\n");
13907 return -1;
13909 i = DAHDI_OFFHOOK;
13910 if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_HOOK,&i) == -1)
13912 ast_log(LOG_ERROR,"Cannot set hook\n");
13913 return -1;
13915 iskenwood_pci4 = 1;
13918 if (myrpt->txchannel == myrpt->dahditxchannel)
13920 i = DAHDI_ONHOOK;
13921 ioctl(myrpt->dahditxchannel->fds[0],DAHDI_HOOK,&i);
13922 /* if PCIRADIO and Yaesu ft897/ICOM IC-706 selected */
13923 if ((myrpt->iofd < 1) && (!res) &&
13924 ((!strcmp(myrpt->remoterig,remote_rig_ft897)) ||
13925 (!strcmp(myrpt->remoterig,remote_rig_ic706)) ||
13926 (!strcmp(myrpt->remoterig,remote_rig_tm271))))
13928 z.radpar = DAHDI_RADPAR_UIOMODE;
13929 z.data = 1;
13930 if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
13932 ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
13933 return -1;
13935 z.radpar = DAHDI_RADPAR_UIODATA;
13936 z.data = 3;
13937 if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
13939 ast_log(LOG_ERROR,"Cannot set UIODATA\n");
13940 return -1;
13944 myrpt->remoterx = 0;
13945 myrpt->remotetx = 0;
13946 myrpt->retxtimer = 0;
13947 myrpt->rerxtimer = 0;
13948 myrpt->remoteon = 1;
13949 myrpt->dtmfidx = -1;
13950 myrpt->dtmfbuf[0] = 0;
13951 myrpt->dtmf_time_rem = 0;
13952 myrpt->hfscanmode = 0;
13953 myrpt->hfscanstatus = 0;
13954 if (myrpt->p.startupmacro)
13956 snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
13958 time(&myrpt->start_time);
13959 myrpt->last_activity_time = myrpt->start_time;
13960 last_timeout_warning = 0;
13961 myrpt->reload = 0;
13962 myrpt->tele.next = &myrpt->tele;
13963 myrpt->tele.prev = &myrpt->tele;
13964 myrpt->newkey = 0;
13965 rpt_mutex_unlock(&myrpt->lock);
13966 ast_set_write_format(chan, AST_FORMAT_SLINEAR);
13967 ast_set_read_format(chan, AST_FORMAT_SLINEAR);
13968 rem_rx = 0;
13969 remkeyed = 0;
13970 /* if we are on 2w loop and are a remote, turn EC on */
13971 if (myrpt->remote && (myrpt->rxchannel == myrpt->txchannel))
13973 i = 128;
13974 ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_ECHOCANCEL,&i);
13976 if (chan->_state != AST_STATE_UP) {
13977 ast_answer(chan);
13978 if (!phone_mode) send_newkey(chan);
13981 if (myrpt->rxchannel == myrpt->dahdirxchannel)
13983 if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_GET_PARAMS,&par) != -1)
13985 if (par.rxisoffhook)
13987 ast_indicate(chan,AST_CONTROL_RADIO_KEY);
13988 myrpt->remoterx = 1;
13989 remkeyed = 1;
13993 if (myrpt->p.archivedir)
13995 char mycmd[100],mydate[100],*b,*b1;
13996 time_t myt;
13997 long blocksleft;
14000 mkdir(myrpt->p.archivedir,0600);
14001 sprintf(mycmd,"%s/%s",myrpt->p.archivedir,myrpt->name);
14002 mkdir(mycmd,0600);
14003 time(&myt);
14004 strftime(mydate,sizeof(mydate) - 1,"%Y%m%d%H%M%S",
14005 localtime(&myt));
14006 sprintf(mycmd,"mixmonitor start %s %s/%s/%s.wav49 a",chan->name,
14007 myrpt->p.archivedir,myrpt->name,mydate);
14008 if (myrpt->p.monminblocks)
14010 blocksleft = diskavail(myrpt);
14011 if (myrpt->p.remotetimeout)
14013 blocksleft -= (myrpt->p.remotetimeout *
14014 MONITOR_DISK_BLOCKS_PER_MINUTE) / 60;
14016 if (blocksleft >= myrpt->p.monminblocks)
14017 ast_cli_command(nullfd,mycmd);
14018 } else ast_cli_command(nullfd,mycmd);
14019 /* look at callerid to see what node this comes from */
14020 if (!chan->cid.cid_num) /* if doesn't have caller id */
14022 b1 = "0";
14023 } else {
14024 ast_callerid_parse(chan->cid.cid_num,&b,&b1);
14025 ast_shrink_phone_number(b1);
14027 sprintf(mycmd,"CONNECT,%s",b1);
14028 donodelog(myrpt,mycmd);
14030 myrpt->loginuser[0] = 0;
14031 myrpt->loginlevel[0] = 0;
14032 myrpt->authtelltimer = 0;
14033 myrpt->authtimer = 0;
14034 authtold = 0;
14035 authreq = 0;
14036 if (myrpt->p.authlevel > 1) authreq = 1;
14037 setrem(myrpt);
14038 n = 0;
14039 dtmfed = 0;
14040 cs[n++] = chan;
14041 cs[n++] = myrpt->rxchannel;
14042 cs[n++] = myrpt->pchannel;
14043 if (myrpt->rxchannel != myrpt->txchannel)
14044 cs[n++] = myrpt->txchannel;
14045 if (!phone_mode) send_newkey(chan);
14046 /* start un-locked */
14047 for(;;)
14049 if (ast_check_hangup(chan)) break;
14050 if (ast_check_hangup(myrpt->rxchannel)) break;
14051 notremming = 0;
14052 setting = 0;
14053 reming = 0;
14054 telem = myrpt->tele.next;
14055 while(telem != &myrpt->tele)
14057 if (telem->mode == SETREMOTE) setting = 1;
14058 if ((telem->mode == SETREMOTE) ||
14059 (telem->mode == SCAN) ||
14060 (telem->mode == TUNE)) reming = 1;
14061 else notremming = 1;
14062 telem = telem->next;
14064 if (myrpt->reload)
14066 myrpt->reload = 0;
14067 /* find our index, and load the vars */
14068 for(i = 0; i < nrpts; i++)
14070 if (&rpt_vars[i] == myrpt)
14072 load_rpt_vars(i,0);
14073 break;
14077 time(&t);
14078 if (myrpt->p.remotetimeout)
14080 time_t r;
14082 r = (t - myrpt->start_time);
14083 if (r >= myrpt->p.remotetimeout)
14085 saynode(myrpt,chan,myrpt->name);
14086 sayfile(chan,"rpt/timeout");
14087 ast_safe_sleep(chan,1000);
14088 break;
14090 if ((myrpt->p.remotetimeoutwarning) &&
14091 (r >= (myrpt->p.remotetimeout -
14092 myrpt->p.remotetimeoutwarning)) &&
14093 (r <= (myrpt->p.remotetimeout -
14094 myrpt->p.remotetimeoutwarningfreq)))
14096 if (myrpt->p.remotetimeoutwarningfreq)
14098 if ((t - last_timeout_warning) >=
14099 myrpt->p.remotetimeoutwarningfreq)
14101 time(&last_timeout_warning);
14102 rpt_telemetry(myrpt,TIMEOUT_WARNING,0);
14105 else
14107 if (!last_timeout_warning)
14109 time(&last_timeout_warning);
14110 rpt_telemetry(myrpt,TIMEOUT_WARNING,0);
14115 if (myrpt->p.remoteinacttimeout && myrpt->last_activity_time)
14117 time_t r;
14119 r = (t - myrpt->last_activity_time);
14120 if (r >= myrpt->p.remoteinacttimeout)
14122 saynode(myrpt,chan,myrpt->name);
14123 ast_safe_sleep(chan,1000);
14124 break;
14126 if ((myrpt->p.remotetimeoutwarning) &&
14127 (r >= (myrpt->p.remoteinacttimeout -
14128 myrpt->p.remotetimeoutwarning)) &&
14129 (r <= (myrpt->p.remoteinacttimeout -
14130 myrpt->p.remotetimeoutwarningfreq)))
14132 if (myrpt->p.remotetimeoutwarningfreq)
14134 if ((t - last_timeout_warning) >=
14135 myrpt->p.remotetimeoutwarningfreq)
14137 time(&last_timeout_warning);
14138 rpt_telemetry(myrpt,ACT_TIMEOUT_WARNING,0);
14141 else
14143 if (!last_timeout_warning)
14145 time(&last_timeout_warning);
14146 rpt_telemetry(myrpt,ACT_TIMEOUT_WARNING,0);
14151 ms = MSWAIT;
14152 who = ast_waitfor_n(cs,n,&ms);
14153 if (who == NULL) ms = 0;
14154 elap = MSWAIT - ms;
14155 if (myrpt->macrotimer) myrpt->macrotimer -= elap;
14156 if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
14157 if (!ms) continue;
14158 /* do local dtmf timer */
14159 if (myrpt->dtmf_local_timer)
14161 if (myrpt->dtmf_local_timer > 1) myrpt->dtmf_local_timer -= elap;
14162 if (myrpt->dtmf_local_timer < 1) myrpt->dtmf_local_timer = 1;
14164 rpt_mutex_lock(&myrpt->lock);
14165 do_dtmf_local(myrpt,0);
14166 rpt_mutex_unlock(&myrpt->lock);
14168 rem_totx = myrpt->dtmf_local_timer && (!phone_mode);
14169 rem_totx |= keyed && (!myrpt->tunerequest);
14170 rem_rx = (remkeyed && (!setting)) || (myrpt->tele.next != &myrpt->tele);
14171 if(!strcmp(myrpt->remoterig, remote_rig_ic706))
14172 rem_totx |= myrpt->tunerequest;
14174 if((debug > 6) && rem_totx) {
14175 ast_log(LOG_NOTICE,"Set rem_totx=%i. dtmf_local_timer=%i phone_mode=%i keyed=%i tunerequest=%i\n",rem_totx,myrpt->dtmf_local_timer,phone_mode,keyed,myrpt->tunerequest);
14177 if (keyed && (!keyed1))
14179 keyed1 = 1;
14182 if (!keyed && (keyed1))
14184 time_t myt;
14186 keyed1 = 0;
14187 time(&myt);
14188 /* if login necessary, and not too soon */
14189 if ((myrpt->p.authlevel) &&
14190 (!myrpt->loginlevel[0]) &&
14191 (myt > (t + 3)))
14193 authreq = 1;
14194 authtold = 0;
14195 myrpt->authtelltimer = AUTHTELLTIME - AUTHTXTIME;
14199 if (rem_rx && (!myrpt->remoterx))
14201 myrpt->remoterx = 1;
14202 ast_indicate(chan,AST_CONTROL_RADIO_KEY);
14204 if ((!rem_rx) && (myrpt->remoterx))
14206 myrpt->remoterx = 0;
14207 ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
14209 /* if auth requested, and not authed yet */
14210 if (authreq && (!myrpt->loginlevel[0]))
14212 if ((!authtold) && ((myrpt->authtelltimer += elap)
14213 >= AUTHTELLTIME))
14215 authtold = 1;
14216 rpt_telemetry(myrpt,LOGINREQ,NULL);
14218 if ((myrpt->authtimer += elap) >= AUTHLOGOUTTIME)
14220 break; /* if not logged in, hang up after a time */
14223 if (myrpt->newkey)
14225 if ((myrpt->retxtimer += elap) >= REDUNDANT_TX_TIME)
14227 myrpt->retxtimer = 0;
14228 if ((myrpt->remoterx) && (!myrpt->remotetx))
14229 ast_indicate(chan,AST_CONTROL_RADIO_KEY);
14230 else
14231 ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
14234 if ((myrpt->rerxtimer += elap) >= (REDUNDANT_TX_TIME * 2))
14236 keyed = 0;
14237 myrpt->rerxtimer = 0;
14240 if (rem_totx && (!myrpt->remotetx))
14242 /* if not authed, and needed, do not transmit */
14243 if ((!myrpt->p.authlevel) || myrpt->loginlevel[0])
14245 if(debug > 6)
14246 ast_log(LOG_NOTICE,"Handle rem_totx=%i. dtmf_local_timer=%i tunerequest=%i\n",rem_totx,myrpt->dtmf_local_timer,myrpt->tunerequest);
14248 myrpt->remotetx = 1;
14249 /* asdf maw ??? is this really what you want? Doesn't it always get executed? */
14250 if((myrpt->remtxfreqok = check_tx_freq(myrpt)))
14252 time(&myrpt->last_activity_time);
14253 if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->dahditxchannel))
14255 z.radpar = DAHDI_RADPAR_UIODATA;
14256 z.data = 1;
14257 if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
14259 ast_log(LOG_ERROR,"Cannot set UIODATA\n");
14260 return -1;
14263 else
14265 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
14267 if (myrpt->p.archivedir) donodelog(myrpt,"TXKEY");
14271 if ((!rem_totx) && myrpt->remotetx) /* Remote base radio TX unkey */
14273 myrpt->remotetx = 0;
14274 if(!myrpt->remtxfreqok){
14275 rpt_telemetry(myrpt,UNAUTHTX,NULL);
14277 if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->dahditxchannel))
14279 z.radpar = DAHDI_RADPAR_UIODATA;
14280 z.data = 3;
14281 if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
14283 ast_log(LOG_ERROR,"Cannot set UIODATA\n");
14284 return -1;
14287 else
14289 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
14291 if (myrpt->p.archivedir) donodelog(myrpt,"TXUNKEY");
14293 if (myrpt->hfscanmode){
14294 myrpt->scantimer -= elap;
14295 if(myrpt->scantimer <= 0){
14296 if (!reming)
14298 myrpt->scantimer = REM_SCANTIME;
14299 rpt_telemetry(myrpt,SCAN,0);
14300 } else myrpt->scantimer = 1;
14303 rpt_mutex_lock(&myrpt->lock);
14304 c = myrpt->macrobuf[0];
14305 if (c && (!myrpt->macrotimer))
14307 myrpt->macrotimer = MACROTIME;
14308 memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1);
14309 if ((c == 'p') || (c == 'P'))
14310 myrpt->macrotimer = MACROPTIME;
14311 rpt_mutex_unlock(&myrpt->lock);
14312 if (myrpt->p.archivedir)
14314 char str[100];
14315 sprintf(str,"DTMF(M),%c",c);
14316 donodelog(myrpt,str);
14318 if (handle_remote_dtmf_digit(myrpt,c,&keyed,0) == -1) break;
14319 continue;
14320 } else rpt_mutex_unlock(&myrpt->lock);
14321 if (who == chan) /* if it was a read from incomming */
14323 f = ast_read(chan);
14324 if (!f)
14326 if (debug) printf("@@@@ link:Hung Up\n");
14327 break;
14329 if (f->frametype == AST_FRAME_VOICE)
14331 if (ioctl(chan->fds[0], DAHDI_GETCONFMUTE, &ismuted) == -1)
14333 ismuted = 0;
14335 /* if not transmitting, zero-out audio */
14336 ismuted |= (!myrpt->remotetx);
14337 if (dtmfed && phone_mode) ismuted = 1;
14338 dtmfed = 0;
14339 if (ismuted)
14341 memset(f->data.ptr,0,f->datalen);
14342 if (myrpt->lastf1)
14343 memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
14344 if (myrpt->lastf2)
14345 memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
14347 if (f) f2 = ast_frdup(f);
14348 else f2 = NULL;
14349 f1 = myrpt->lastf2;
14350 myrpt->lastf2 = myrpt->lastf1;
14351 myrpt->lastf1 = f2;
14352 if (ismuted)
14354 if (myrpt->lastf1)
14355 memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
14356 if (myrpt->lastf2)
14357 memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
14359 if (f1)
14361 if (phone_mode)
14362 ast_write(myrpt->txchannel,f1);
14363 else
14364 ast_write(myrpt->txchannel,f);
14365 ast_frfree(f1);
14368 #ifndef OLD_ASTERISK
14369 else if (f->frametype == AST_FRAME_DTMF_BEGIN)
14371 if (myrpt->lastf1)
14372 memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
14373 if (myrpt->lastf2)
14374 memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
14375 dtmfed = 1;
14377 #endif
14378 if (f->frametype == AST_FRAME_DTMF)
14380 if (myrpt->lastf1)
14381 memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
14382 if (myrpt->lastf2)
14383 memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
14384 dtmfed = 1;
14385 if (handle_remote_phone_dtmf(myrpt,f->subclass,&keyed,phone_mode) == -1)
14387 if (debug) printf("@@@@ rpt:Hung Up\n");
14388 ast_frfree(f);
14389 break;
14392 if (f->frametype == AST_FRAME_TEXT)
14394 if (handle_remote_data(myrpt,f->data.ptr) == -1)
14396 if (debug) printf("@@@@ rpt:Hung Up\n");
14397 ast_frfree(f);
14398 break;
14401 if (f->frametype == AST_FRAME_CONTROL)
14403 if (f->subclass == AST_CONTROL_HANGUP)
14405 if (debug) printf("@@@@ rpt:Hung Up\n");
14406 ast_frfree(f);
14407 break;
14409 /* if RX key */
14410 if (f->subclass == AST_CONTROL_RADIO_KEY)
14412 if (debug == 7) printf("@@@@ rx key\n");
14413 keyed = 1;
14414 myrpt->rerxtimer = 0;
14416 /* if RX un-key */
14417 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
14419 myrpt->rerxtimer = 0;
14420 if (debug == 7) printf("@@@@ rx un-key\n");
14421 keyed = 0;
14424 ast_frfree(f);
14425 continue;
14427 if (who == myrpt->rxchannel) /* if it was a read from radio */
14429 f = ast_read(myrpt->rxchannel);
14430 if (!f)
14432 if (debug) printf("@@@@ link:Hung Up\n");
14433 break;
14435 if (f->frametype == AST_FRAME_VOICE)
14437 int myreming = 0;
14439 if(!strcmp(myrpt->remoterig, remote_rig_kenwood))
14440 myreming = reming;
14442 if (myreming || (!remkeyed) ||
14443 ((myrpt->remote) && (myrpt->remotetx)) ||
14444 ((myrpt->remmode != REM_MODE_FM) &&
14445 notremming))
14446 memset(f->data.ptr,0,f->datalen);
14447 ast_write(myrpt->pchannel,f);
14449 else if (f->frametype == AST_FRAME_CONTROL)
14451 if (f->subclass == AST_CONTROL_HANGUP)
14453 if (debug) printf("@@@@ rpt:Hung Up\n");
14454 ast_frfree(f);
14455 break;
14457 /* if RX key */
14458 if (f->subclass == AST_CONTROL_RADIO_KEY)
14460 if (debug == 7) printf("@@@@ remote rx key\n");
14461 if (!myrpt->remotetx)
14463 remkeyed = 1;
14466 /* if RX un-key */
14467 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
14469 if (debug == 7) printf("@@@@ remote rx un-key\n");
14470 if (!myrpt->remotetx)
14472 remkeyed = 0;
14476 ast_frfree(f);
14477 continue;
14479 if (who == myrpt->pchannel) /* if is remote mix output */
14481 f = ast_read(myrpt->pchannel);
14482 if (!f)
14484 if (debug) printf("@@@@ link:Hung Up\n");
14485 break;
14487 if (f->frametype == AST_FRAME_VOICE)
14489 ast_write(chan,f);
14491 if (f->frametype == AST_FRAME_CONTROL)
14493 if (f->subclass == AST_CONTROL_HANGUP)
14495 if (debug) printf("@@@@ rpt:Hung Up\n");
14496 ast_frfree(f);
14497 break;
14500 ast_frfree(f);
14501 continue;
14503 if ((myrpt->rxchannel != myrpt->txchannel) &&
14504 (who == myrpt->txchannel)) /* do this cuz you have to */
14506 f = ast_read(myrpt->txchannel);
14507 if (!f)
14509 if (debug) printf("@@@@ link:Hung Up\n");
14510 break;
14512 if (f->frametype == AST_FRAME_CONTROL)
14514 if (f->subclass == AST_CONTROL_HANGUP)
14516 if (debug) printf("@@@@ rpt:Hung Up\n");
14517 ast_frfree(f);
14518 break;
14521 ast_frfree(f);
14522 continue;
14525 if (myrpt->p.archivedir)
14527 char mycmd[100],*b,*b1;
14529 /* look at callerid to see what node this comes from */
14530 if (!chan->cid.cid_num) /* if doesn't have caller id */
14532 b1 = "0";
14533 } else {
14534 ast_callerid_parse(chan->cid.cid_num,&b,&b1);
14535 ast_shrink_phone_number(b1);
14537 sprintf(mycmd,"DISCONNECT,%s",b1);
14538 donodelog(myrpt,mycmd);
14540 /* wait for telem to be done */
14541 while(myrpt->tele.next != &myrpt->tele) usleep(100000);
14542 sprintf(tmp,"mixmonitor stop %s",chan->name);
14543 ast_cli_command(nullfd,tmp);
14544 close(nullfd);
14545 rpt_mutex_lock(&myrpt->lock);
14546 myrpt->hfscanmode = 0;
14547 myrpt->hfscanstatus = 0;
14548 myrpt->remoteon = 0;
14549 rpt_mutex_unlock(&myrpt->lock);
14550 if (myrpt->lastf1) ast_frfree(myrpt->lastf1);
14551 myrpt->lastf1 = NULL;
14552 if (myrpt->lastf2) ast_frfree(myrpt->lastf2);
14553 myrpt->lastf2 = NULL;
14554 if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->dahditxchannel))
14556 z.radpar = DAHDI_RADPAR_UIOMODE;
14557 z.data = 3;
14558 if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
14560 ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
14561 return -1;
14563 z.radpar = DAHDI_RADPAR_UIODATA;
14564 z.data = 3;
14565 if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
14567 ast_log(LOG_ERROR,"Cannot set UIODATA\n");
14568 return -1;
14570 i = DAHDI_OFFHOOK;
14571 if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_HOOK,&i) == -1)
14573 ast_log(LOG_ERROR,"Cannot set hook\n");
14574 return -1;
14577 if (myrpt->iofd) close(myrpt->iofd);
14578 myrpt->iofd = -1;
14579 ast_hangup(myrpt->pchannel);
14580 if (myrpt->rxchannel != myrpt->txchannel) ast_hangup(myrpt->txchannel);
14581 ast_hangup(myrpt->rxchannel);
14582 closerem(myrpt);
14583 if (myrpt->p.rptnode)
14585 rpt_mutex_lock(&myrpt->lock);
14586 for(i = 0; i < nrpts; i++)
14588 if (!strcasecmp(rpt_vars[i].name,myrpt->p.rptnode))
14590 rpt_vars[i].xlink = 0;
14591 break;
14594 rpt_mutex_unlock(&myrpt->lock);
14596 #ifdef OLD_ASTERISK
14597 LOCAL_USER_REMOVE(u);
14598 #endif
14599 return res;
14602 #ifndef OLD_ASTERISK
14603 /*!\brief callback to display list of locally configured nodes
14604 \addtogroup Group_AMI
14606 static int manager_rpt_local_nodes(struct mansession *s, const struct message *m)
14608 int i;
14609 astman_append(s, "<?xml version=\"1.0\"?>\r\n");
14610 astman_append(s, "<nodes>\r\n");
14611 for (i=0; i< nrpts; i++)
14613 astman_append(s, " <node>%s</node>\r\n", rpt_vars[i].name);
14614 } /* for i */
14615 astman_append(s, "</nodes>\r\n");
14616 astman_append(s, "\r\n"); /* Properly terminate Manager output */
14617 return RESULT_SUCCESS;
14618 } /* manager_rpt_local_nodes() */
14623 * Append Success and ActionID to manager response message
14626 static void rpt_manager_success(struct mansession *s, const struct message *m)
14628 const char *id = astman_get_header(m, "ActionID");
14629 if (!ast_strlen_zero(id))
14630 astman_append(s, "ActionID: %s\r\n", id);
14631 astman_append(s, "Response: Success\r\n");
14635 * Dump statistics to manager session
14638 static int rpt_manager_do_stats(struct mansession *s, const struct message *m, char *str)
14640 int i,j,numoflinks;
14641 int dailytxtime, dailykerchunks;
14642 time_t now;
14643 int totalkerchunks, dailykeyups, totalkeyups, timeouts;
14644 int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
14645 long long totaltxtime;
14646 struct rpt_link *l;
14647 char *listoflinks[MAX_STAT_LINKS];
14648 char *lastdtmfcommand,*parrot_ena;
14649 char *tot_state, *ider_state, *patch_state;
14650 char *reverse_patch_state, *sys_ena, *tot_ena, *link_ena, *patch_ena;
14651 char *sch_ena, *input_signal, *called_number, *user_funs, *tail_type;
14652 char *transmitterkeyed;
14653 const char *node = astman_get_header(m, "Node");
14654 struct rpt *myrpt;
14656 static char *not_applicable = "N/A";
14658 tot_state = ider_state =
14659 patch_state = reverse_patch_state =
14660 input_signal = not_applicable;
14661 called_number = lastdtmfcommand = transmitterkeyed = NULL;
14663 time(&now);
14664 for(i = 0; i < nrpts; i++)
14666 if ((node)&&(!strcmp(node,rpt_vars[i].name))){
14667 rpt_manager_success(s,m);
14669 myrpt = &rpt_vars[i];
14671 if(myrpt->remote){ /* Remote base ? */
14672 char *loginuser, *loginlevel, *freq, *rxpl, *txpl, *modestr;
14673 char offset,powerlevel,rxplon,txplon,remoteon,remmode,reportfmstuff;
14674 char offsetc,powerlevelc;
14676 loginuser = loginlevel = freq = rxpl = txpl = NULL;
14677 /* Make a copy of all stat variables while locked */
14678 rpt_mutex_lock(&myrpt->lock); /* LOCK */
14679 if((remoteon = myrpt->remoteon)){
14680 if(!ast_strlen_zero(myrpt->loginuser))
14681 loginuser = ast_strdup(myrpt->loginuser);
14682 if(!ast_strlen_zero(myrpt->loginlevel))
14683 loginlevel = ast_strdup(myrpt->loginlevel);
14684 if(!ast_strlen_zero(myrpt->freq))
14685 freq = ast_strdup(myrpt->freq);
14686 if(!ast_strlen_zero(myrpt->rxpl))
14687 rxpl = ast_strdup(myrpt->rxpl);
14688 if(!ast_strlen_zero(myrpt->txpl))
14689 txpl = ast_strdup(myrpt->txpl);
14690 remmode = myrpt->remmode;
14691 offset = myrpt->offset;
14692 powerlevel = myrpt->powerlevel;
14693 rxplon = myrpt->rxplon;
14694 txplon = myrpt->txplon;
14696 rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
14697 astman_append(s, "IsRemoteBase: YES\r\n");
14698 astman_append(s, "RemoteOn: %s\r\n",(remoteon) ? "YES": "NO");
14699 if(remoteon){
14700 if(loginuser){
14701 astman_append(s, "LogInUser: %s\r\n", loginuser);
14702 ast_free(loginuser);
14704 if(loginlevel){
14705 astman_append(s, "LogInLevel: %s\r\n", loginlevel);
14706 ast_free(loginlevel);
14708 if(freq){
14709 astman_append(s, "Freq: %s\r\n", freq);
14710 ast_free(freq);
14712 reportfmstuff = 0;
14713 switch(remmode){
14714 case REM_MODE_FM:
14715 modestr = "FM";
14716 reportfmstuff = 1;
14717 break;
14718 case REM_MODE_AM:
14719 modestr = "AM";
14720 break;
14721 case REM_MODE_USB:
14722 modestr = "USB";
14723 break;
14724 default:
14725 modestr = "LSB";
14726 break;
14728 astman_append(s, "RemMode: %s\r\n", modestr);
14729 if(reportfmstuff){
14730 switch(offset){
14731 case REM_SIMPLEX:
14732 offsetc = 'S';
14733 break;
14734 case REM_MINUS:
14735 offsetc = '-';
14736 break;
14737 default:
14738 offsetc = '+';
14739 break;
14741 astman_append(s, "RemOffset: %c\r\n", offsetc);
14742 if(rxplon && rxpl){
14743 astman_append(s, "RxPl: %s\r\n",rxpl);
14744 free(rxpl);
14746 if(txplon && txpl){
14747 astman_append(s, "TxPl: %s\r\n",txpl);
14748 free(txpl);
14751 switch(powerlevel){
14752 case REM_LOWPWR:
14753 powerlevelc = 'L';
14754 break;
14755 case REM_MEDPWR:
14756 powerlevelc = 'M';
14757 break;
14758 default:
14759 powerlevelc = 'H';
14760 break;
14762 astman_append(s,"PowerLevel: %c\r\n", powerlevelc);
14764 astman_append(s, "\r\n");
14765 return 0; /* End of remote base status reporting */
14768 /* ELSE Process as a repeater node */
14769 /* Make a copy of all stat variables while locked */
14770 rpt_mutex_lock(&myrpt->lock); /* LOCK */
14771 dailytxtime = myrpt->dailytxtime;
14772 totaltxtime = myrpt->totaltxtime;
14773 dailykeyups = myrpt->dailykeyups;
14774 totalkeyups = myrpt->totalkeyups;
14775 dailykerchunks = myrpt->dailykerchunks;
14776 totalkerchunks = myrpt->totalkerchunks;
14777 dailyexecdcommands = myrpt->dailyexecdcommands;
14778 totalexecdcommands = myrpt->totalexecdcommands;
14779 timeouts = myrpt->timeouts;
14782 /* Traverse the list of connected nodes */
14783 reverse_patch_state = "DOWN";
14784 numoflinks = 0;
14785 l = myrpt->links.next;
14786 while(l && (l != &myrpt->links)){
14787 if(numoflinks >= MAX_STAT_LINKS){
14788 ast_log(LOG_NOTICE,
14789 "maximum number of links exceeds %d in rpt_do_stats()!",MAX_STAT_LINKS);
14790 break;
14792 if (l->name[0] == '0'){ /* Skip '0' nodes */
14793 reverse_patch_state = "UP";
14794 l = l->next;
14795 continue;
14797 listoflinks[numoflinks] = ast_strdup(l->name);
14798 if(listoflinks[numoflinks] == NULL){
14799 break;
14801 else{
14802 numoflinks++;
14804 l = l->next;
14807 if(myrpt->keyed)
14808 input_signal = "YES";
14809 else
14810 input_signal = "NO";
14812 if(myrpt->txkeyed)
14813 transmitterkeyed = "YES";
14814 else
14815 transmitterkeyed = "NO";
14817 if(myrpt->p.parrotmode)
14818 parrot_ena = "ENABLED";
14819 else
14820 parrot_ena = "DISABLED";
14822 if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable)
14823 sys_ena = "DISABLED";
14824 else
14825 sys_ena = "ENABLED";
14827 if(myrpt->p.s[myrpt->p.sysstate_cur].totdisable)
14828 tot_ena = "DISABLED";
14829 else
14830 tot_ena = "ENABLED";
14832 if(myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable)
14833 link_ena = "DISABLED";
14834 else
14835 link_ena = "ENABLED";
14837 if(myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
14838 patch_ena = "DISABLED";
14839 else
14840 patch_ena = "ENABLED";
14842 if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable)
14843 sch_ena = "DISABLED";
14844 else
14845 sch_ena = "ENABLED";
14847 if(myrpt->p.s[myrpt->p.sysstate_cur].userfundisable)
14848 user_funs = "DISABLED";
14849 else
14850 user_funs = "ENABLED";
14852 if(myrpt->p.s[myrpt->p.sysstate_cur].alternatetail)
14853 tail_type = "ALTERNATE";
14854 else
14855 tail_type = "STANDARD";
14857 if(!myrpt->totimer)
14858 tot_state = "TIMED OUT!";
14859 else if(myrpt->totimer != myrpt->p.totime)
14860 tot_state = "ARMED";
14861 else
14862 tot_state = "RESET";
14864 if(myrpt->tailid)
14865 ider_state = "QUEUED IN TAIL";
14866 else if(myrpt->mustid)
14867 ider_state = "QUEUED FOR CLEANUP";
14868 else
14869 ider_state = "CLEAN";
14871 switch(myrpt->callmode){
14872 case 1:
14873 patch_state = "DIALING";
14874 break;
14875 case 2:
14876 patch_state = "CONNECTING";
14877 break;
14878 case 3:
14879 patch_state = "UP";
14880 break;
14882 case 4:
14883 patch_state = "CALL FAILED";
14884 break;
14886 default:
14887 patch_state = "DOWN";
14890 if(strlen(myrpt->exten)){
14891 called_number = ast_strdup(myrpt->exten);
14894 if(strlen(myrpt->lastdtmfcommand)){
14895 lastdtmfcommand = ast_strdup(myrpt->lastdtmfcommand);
14897 rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
14899 astman_append(s, "IsRemoteBase: NO\r\n");
14900 astman_append(s, "NodeState: %d\r\n", myrpt->p.sysstate_cur);
14901 astman_append(s, "SignalOnInput: %s\r\n", input_signal);
14902 astman_append(s, "TransmitterKeyed: %s\r\n", transmitterkeyed);
14903 astman_append(s, "Transmitter: %s\r\n", sys_ena);
14904 astman_append(s, "Parrot: %s\r\n", parrot_ena);
14905 astman_append(s, "Scheduler: %s\r\n", sch_ena);
14906 astman_append(s, "TailLength: %s\r\n", tail_type);
14907 astman_append(s, "TimeOutTimer: %s\r\n", tot_ena);
14908 astman_append(s, "TimeOutTimerState: %s\r\n", tot_state);
14909 astman_append(s, "TimeOutsSinceSystemInitialization: %d\r\n", timeouts);
14910 astman_append(s, "IdentifierState: %s\r\n", ider_state);
14911 astman_append(s, "KerchunksToday: %d\r\n", dailykerchunks);
14912 astman_append(s, "KerchunksSinceSystemInitialization: %d\r\n", totalkerchunks);
14913 astman_append(s, "KeyupsToday: %d\r\n", dailykeyups);
14914 astman_append(s, "KeyupsSinceSystemInitialization: %d\r\n", totalkeyups);
14915 astman_append(s, "DtmfCommandsToday: %d\r\n", dailyexecdcommands);
14916 astman_append(s, "DtmfCommandsSinceSystemInitialization: %d\r\n", totalexecdcommands);
14917 astman_append(s, "LastDtmfCommandExecuted: %s\r\n",
14918 (lastdtmfcommand && strlen(lastdtmfcommand)) ? lastdtmfcommand : not_applicable);
14919 hours = dailytxtime/3600000;
14920 dailytxtime %= 3600000;
14921 minutes = dailytxtime/60000;
14922 dailytxtime %= 60000;
14923 seconds = dailytxtime/1000;
14924 dailytxtime %= 1000;
14926 astman_append(s, "TxTimeToday: %02d:%02d:%02d.%d\r\n",
14927 hours, minutes, seconds, dailytxtime);
14929 hours = (int) totaltxtime/3600000;
14930 totaltxtime %= 3600000;
14931 minutes = (int) totaltxtime/60000;
14932 totaltxtime %= 60000;
14933 seconds = (int) totaltxtime/1000;
14934 totaltxtime %= 1000;
14936 astman_append(s, "TxTimeSinceSystemInitialization: %02d:%02d:%02d.%d\r\n",
14937 hours, minutes, seconds, (int) totaltxtime);
14939 sprintf(str, "NodesCurrentlyConnectedToUs: ");
14940 if(!numoflinks){
14941 strcat(str,"<NONE>");
14943 else{
14944 for(j = 0 ;j < numoflinks; j++){
14945 sprintf(str+strlen(str), "%s", listoflinks[j]);
14946 if(j < numoflinks - 1)
14947 strcat(str,",");
14950 astman_append(s,"%s\r\n", str);
14952 astman_append(s, "Autopatch: %s\r\n", patch_ena);
14953 astman_append(s, "AutopatchState: %s\r\n", patch_state);
14954 astman_append(s, "AutopatchCalledNumber: %s\r\n",
14955 (called_number && strlen(called_number)) ? called_number : not_applicable);
14956 astman_append(s, "ReversePatchIaxrptConnected: %s\r\n", reverse_patch_state);
14957 astman_append(s, "UserLinkingCommands: %s\r\n", link_ena);
14958 astman_append(s, "UserFunctions: %s\r\n", user_funs);
14960 for(j = 0; j < numoflinks; j++){ /* ast_free() all link names */
14961 ast_free(listoflinks[j]);
14963 if(called_number){
14964 ast_free(called_number);
14966 if(lastdtmfcommand){
14967 ast_free(lastdtmfcommand);
14969 astman_append(s, "\r\n"); /* We're Done! */
14970 return 0;
14973 astman_send_error(s, m, "RptStatus unknown or missing node");
14974 return -1;
14980 * Implement the RptStatus Manager Interface
14983 static int manager_rpt_status(struct mansession *s, const struct message *m)
14985 int i,res,len,index;
14986 int uptime,hours,minutes;
14987 time_t now;
14988 const char *cmd = astman_get_header(m, "Command");
14989 char *str;
14990 enum {MGRCMD_RPTSTAT,MGRCMD_NODESTAT};
14991 struct mgrcmdtbl{
14992 const char *cmd;
14993 int index;
14995 static struct mgrcmdtbl mct[] = {
14996 {"RptStat",MGRCMD_RPTSTAT},
14997 {"NodeStat",MGRCMD_NODESTAT},
14998 {NULL,0} /* NULL marks end of command table */
15001 time(&now);
15003 len = 1024; /* Allocate a working buffer */
15004 if(!(str = ast_malloc(len)))
15005 return -1;
15007 /* Check for Command */
15008 if(ast_strlen_zero(cmd)){
15009 astman_send_error(s, m, "RptStatus missing command");
15010 ast_free(str);
15011 return 0;
15013 /* Try to find the command in the table */
15014 for(i = 0 ; mct[i].cmd ; i++){
15015 if(!strcmp(mct[i].cmd, cmd))
15016 break;
15019 if(!mct[i].cmd){ /* Found or not found ? */
15020 astman_send_error(s, m, "RptStatus unknown command");
15021 ast_free(str);
15022 return 0;
15024 else
15025 index = mct[i].index;
15027 switch(index){ /* Use the index to go to the correct command */
15029 case MGRCMD_RPTSTAT:
15030 /* Return Nodes: and a comma separated list of nodes */
15031 if((res = snprintf(str, len, "Nodes: ")) > -1)
15032 len -= res;
15033 else{
15034 ast_free(str);
15035 return 0;
15037 for(i = 0; i < nrpts; i++){
15038 if(i < nrpts - 1){
15039 if((res = snprintf(str+strlen(str), len, "%s,",rpt_vars[i].name)) < 0){
15040 ast_free(str);
15041 return 0;
15044 else{
15045 if((res = snprintf(str+strlen(str), len, "%s",rpt_vars[i].name)) < 0){
15046 ast_free(str);
15047 return 0;
15050 len -= res;
15053 rpt_manager_success(s,m);
15055 if(!nrpts)
15056 astman_append(s, "<NONE>\r\n");
15057 else
15058 astman_append(s, "%s\r\n", str);
15060 uptime = (int)(now - starttime);
15061 hours = uptime/3600;
15062 uptime %= 3600;
15063 minutes = uptime/60;
15064 uptime %= 60;
15066 astman_append(s, "RptUptime: %02d:%02d:%02d\r\n",
15067 hours, minutes, uptime);
15069 astman_append(s, "\r\n");
15070 break;
15072 case MGRCMD_NODESTAT:
15073 res = rpt_manager_do_stats(s,m,str);
15074 ast_free(str);
15075 return res;
15077 default:
15078 astman_send_error(s, m, "RptStatus invalid command");
15079 break;
15081 ast_free(str);
15082 return 0;
15085 #endif
15087 #ifdef OLD_ASTERISK
15088 int unload_module()
15089 #else
15090 static int unload_module(void)
15091 #endif
15093 int i, res;
15095 #ifdef OLD_ASTERISK
15096 STANDARD_HANGUP_LOCALUSERS;
15097 #endif
15098 for(i = 0; i < nrpts; i++) {
15099 if (!strcmp(rpt_vars[i].name,rpt_vars[i].p.nodes)) continue;
15100 ast_mutex_destroy(&rpt_vars[i].lock);
15101 ast_mutex_destroy(&rpt_vars[i].remlock);
15103 res = ast_unregister_application(app);
15105 #ifdef NEW_ASTERISK
15106 ast_cli_unregister_multiple(rpt_cli,sizeof(rpt_cli) /
15107 sizeof(struct ast_cli_entry));
15108 #else
15109 /* Unregister cli extensions */
15110 ast_cli_unregister(&cli_debug);
15111 ast_cli_unregister(&cli_dump);
15112 ast_cli_unregister(&cli_stats);
15113 ast_cli_unregister(&cli_lstats);
15114 ast_cli_unregister(&cli_nodes);
15115 ast_cli_unregister(&cli_local_nodes);
15116 ast_cli_unregister(&cli_reload);
15117 ast_cli_unregister(&cli_restart);
15118 ast_cli_unregister(&cli_fun);
15119 ast_cli_unregister(&cli_fun1);
15120 res |= ast_cli_unregister(&cli_cmd);
15121 #endif
15122 #ifndef OLD_ASTERISK
15123 res |= ast_manager_unregister("RptLocalNodes");
15124 res |= ast_manager_unregister("RptStatus");
15125 #endif
15126 return res;
15129 #ifdef OLD_ASTERISK
15130 int load_module()
15131 #else
15132 static int load_module(void)
15133 #endif
15135 int res;
15136 ast_pthread_create(&rpt_master_thread,NULL,rpt_master,NULL);
15138 #ifdef NEW_ASTERISK
15139 ast_cli_register_multiple(rpt_cli,sizeof(rpt_cli) /
15140 sizeof(struct ast_cli_entry));
15141 res = 0;
15142 #else
15143 /* Register cli extensions */
15144 ast_cli_register(&cli_debug);
15145 ast_cli_register(&cli_dump);
15146 ast_cli_register(&cli_stats);
15147 ast_cli_register(&cli_lstats);
15148 ast_cli_register(&cli_nodes);
15149 ast_cli_register(&cli_local_nodes);
15150 ast_cli_register(&cli_reload);
15151 ast_cli_register(&cli_restart);
15152 ast_cli_register(&cli_fun);
15153 ast_cli_register(&cli_fun1);
15154 res = ast_cli_register(&cli_cmd);
15155 #endif
15156 #ifndef OLD_ASTERISK
15157 res |= ast_manager_register("RptLocalNodes", 0, manager_rpt_local_nodes, "List local node numbers");
15158 res |= ast_manager_register("RptStatus", 0, manager_rpt_status, "Return Rpt Status for CGI");
15160 #endif
15161 res |= ast_register_application(app, rpt_exec, synopsis, descrip);
15162 return res;
15165 #ifdef OLD_ASTERISK
15166 char *description()
15168 return tdesc;
15170 int usecount(void)
15172 int res;
15173 STANDARD_USECOUNT(res);
15174 return res;
15177 char *key()
15179 return ASTERISK_GPL_KEY;
15181 #endif
15183 #ifdef OLD_ASTERISK
15184 int reload()
15185 #else
15186 static int reload(void)
15187 #endif
15189 int n;
15191 for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
15192 return(0);
15196 #ifndef OLD_ASTERISK
15197 /* STD_MOD(MOD_1, reload, NULL, NULL); */
15198 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Radio Repeater/Remote Base Application",
15199 .load = load_module,
15200 .unload = unload_module,
15201 .reload = reload,
15203 #endif