Let's also include aclocal.m4
[asterisk-bristuff.git] / apps / app_rpt.c
blob305161df47ccd581a8e01112dbc52b4aacf40ea1
1 /* #define OLD_ASTERISK */
2 #define OLDKEY
3 /*
4 * Asterisk -- An open source telephony toolkit.
6 * Copyright (C) 2002-2007, 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.73 09/04/07
26 * \author Jim Dixon, WB6NIL <jim@lambdatel.com>
28 * \note Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
30 * See http://www.zapatatelephony.org/app_rpt.html
33 * Repeater / Remote Functions:
34 * "Simple" Mode: * - autopatch access, # - autopatch hangup
35 * Normal mode:
36 * See the function list in rpt.conf (autopatchup, autopatchdn)
37 * autopatchup can optionally take comma delimited setting=value pairs:
40 * context=string : Override default context with "string"
41 * dialtime=ms : Specify the max number of milliseconds between phone number digits (1000 milliseconds = 1 second)
42 * farenddisconnect=1 : Automatically disconnect when called party hangs up
43 * noct=1 : Don't send repeater courtesy tone during autopatch calls
44 * quiet=1 : Don't send dial tone, or connect messages. Do not send patch down message when called party hangs up
47 * Example: 123=autopatchup,dialtime=20000,noct=1,farenddisconnect=1
49 * To send an asterisk (*) while dialing or talking on phone,
50 * use the autopatch acess code.
53 * status cmds:
55 * 1 - Force ID
56 * 2 - Give Time of Day
57 * 3 - Give software Version
59 * cop (control operator) cmds:
61 * 1 - System warm boot
62 * 2 - System enable
63 * 3 - System disable
64 * 4 - Test Tone On/Off
65 * 5 - Dump System Variables on Console (debug)
66 * 6 - PTT (phone mode only)
67 * 7 - Time out timer enable
68 * 8 - Time out timer disable
69 * 9 - Autopatch enable
70 * 10 - Autopatch disable
71 * 11 - Link enable
72 * 12 - Link disable
73 * 13 - Query System State
74 * 14 - Change System State
75 * 15 - Scheduler Enable
76 * 16 - Scheduler Disable
77 * 17 - User functions (time, id, etc) enable
78 * 18 - User functions (time, id, etc) disable
79 * 19 - Select alternate hang timer
80 * 20 - Select standard hang timer
82 * ilink cmds:
84 * 1 - Disconnect specified link
85 * 2 - Connect specified link -- monitor only
86 * 3 - Connect specified link -- tranceive
87 * 4 - Enter command mode on specified link
88 * 5 - System status
89 * 6 - Disconnect all links
90 * 11 - Disconnect a previously permanently connected link
91 * 12 - Permanently connect specified link -- monitor only
92 * 13 - Permanently connect specified link -- tranceive
93 * 15 - Full system status (all nodes)
94 * 16 - Reconnect links disconnected with "disconnect all links"
95 * 200 thru 215 - (Send DTMF 0-9,*,#,A-D) (200=0, 201=1, 210=*, etc)
97 * remote cmds:
99 * 1 - Recall Memory MM (*000-*099) (Gets memory from rpt.conf)
100 * 2 - Set VFO MMMMM*KKK*O (Mhz digits, Khz digits, Offset)
101 * 3 - Set Rx PL Tone HHH*D*
102 * 4 - Set Tx PL Tone HHH*D* (Not currently implemented with DHE RBI-1)
103 * 5 - Link Status (long)
104 * 6 - Set operating mode M (FM, USB, LSB, AM, etc)
105 * 100 - RX PL off (Default)
106 * 101 - RX PL On
107 * 102 - TX PL Off (Default)
108 * 103 - TX PL On
109 * 104 - Low Power
110 * 105 - Med Power
111 * 106 - Hi Power
112 * 107 - Bump Down 20 Hz
113 * 108 - Bump Down 100 Hz
114 * 109 - Bump Down 500 Hz
115 * 110 - Bump Up 20 Hz
116 * 111 - Bump Up 100 Hz
117 * 112 - Bump Up 500 Hz
118 * 113 - Scan Down Slow
119 * 114 - Scan Down Medium
120 * 115 - Scan Down Fast
121 * 116 - Scan Up Slow
122 * 117 - Scan Up Medium
123 * 118 - Scan Up Fast
124 * 119 - Transmit allowing auto-tune
125 * 140 - Link Status (brief)
126 * 200 thru 215 - (Send DTMF 0-9,*,#,A-D) (200=0, 201=1, 210=*, etc)
129 * 'duplex' modes: (defaults to duplex=2)
131 * 0 - Only remote links key Tx and no main repeat audio.
132 * 1 - Everything other then main Rx keys Tx, no main repeat audio.
133 * 2 - Normal mode
134 * 3 - Normal except no main repeat audio.
135 * 4 - Normal except no main repeat audio during autopatch only
139 /*** MODULEINFO
140 <depend>dahdi</depend>
141 <depend>tonezone</depend>
142 <defaultenabled>no</defaultenabled>
143 ***/
145 /* Un-comment the following to include support for MDC-1200 digital tone
146 signalling protocol (using KA6SQG's GPL'ed implementation) */
147 /* #include "mdc_decode.c" */
149 /* Un-comment the following to include support for notch filters in the
150 rx audio stream (using Tony Fisher's mknotch (mkfilter) implementation) */
151 /* #include "rpt_notch.c" */
153 /* maximum digits in DTMF buffer, and seconds after * for DTMF command timeout */
155 #define MAXDTMF 32
156 #define MAXMACRO 2048
157 #define MAXLINKLIST 512
158 #define LINKLISTTIME 10000
159 #define LINKLISTSHORTTIME 200
160 #define MACROTIME 100
161 #define MACROPTIME 500
162 #define DTMF_TIMEOUT 3
163 #define KENWOOD_RETRIES 5
165 #define AUTHTELLTIME 7000
166 #define AUTHTXTIME 1000
167 #define AUTHLOGOUTTIME 25000
169 #ifdef __RPT_NOTCH
170 #define MAXFILTERS 10
171 #endif
173 #define DISC_TIME 10000 /* report disc after 10 seconds of no connect */
174 #define MAX_RETRIES 5
175 #define MAX_RETRIES_PERM 1000000000
177 #define REDUNDANT_TX_TIME 2000
179 #define RETRY_TIMER_MS 5000
181 #define START_DELAY 2
183 #define MAXPEERSTR 31
184 #define MAXREMSTR 15
186 #define DELIMCHR ','
187 #define QUOTECHR 34
189 #define MONITOR_DISK_BLOCKS_PER_MINUTE 38
191 #define DEFAULT_MONITOR_MIN_DISK_BLOCKS 10000
192 #define DEFAULT_REMOTE_INACT_TIMEOUT (15 * 60)
193 #define DEFAULT_REMOTE_TIMEOUT (60 * 60)
194 #define DEFAULT_REMOTE_TIMEOUT_WARNING (3 * 60)
195 #define DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ 30
197 #define NODES "nodes"
198 #define EXTNODES "extnodes"
199 #define MEMORY "memory"
200 #define MACRO "macro"
201 #define FUNCTIONS "functions"
202 #define TELEMETRY "telemetry"
203 #define MORSE "morse"
204 #define FUNCCHAR '*'
205 #define ENDCHAR '#'
206 #define EXTNODEFILE "/var/lib/asterisk/rpt_extnodes"
208 #define DEFAULT_IOBASE 0x378
210 #define DEFAULT_CIV_ADDR 0x58
212 #define MAXCONNECTTIME 5000
214 #define MAXNODESTR 300
216 #define MAXPATCHCONTEXT 100
218 #define ACTIONSIZE 32
220 #define TELEPARAMSIZE 256
222 #define REM_SCANTIME 100
224 #define DTMF_LOCAL_TIME 250
225 #define DTMF_LOCAL_STARTTIME 500
227 #define IC706_PL_MEMORY_OFFSET 50
229 #define ALLOW_LOCAL_CHANNELS
231 enum {REM_OFF,REM_MONITOR,REM_TX};
233 enum{ID,PROC,TERM,COMPLETE,UNKEY,REMDISC,REMALREADY,REMNOTFOUND,REMGO,
234 CONNECTED,CONNFAIL,STATUS,TIMEOUT,ID1, STATS_TIME,
235 STATS_VERSION, IDTALKOVER, ARB_ALPHA, TEST_TONE, REV_PATCH,
236 TAILMSG, MACRO_NOTFOUND, MACRO_BUSY, LASTNODEKEY, FULLSTATUS,
237 MEMNOTFOUND, INVFREQ, REMMODE, REMLOGIN, REMXXX, REMSHORTSTATUS,
238 REMLONGSTATUS, LOGINREQ, SCAN, SCANSTAT, TUNE, SETREMOTE,
239 TIMEOUT_WARNING, ACT_TIMEOUT_WARNING, LINKUNKEY, UNAUTHTX};
242 enum {REM_SIMPLEX,REM_MINUS,REM_PLUS};
244 enum {REM_LOWPWR,REM_MEDPWR,REM_HIPWR};
246 enum {DC_INDETERMINATE, DC_REQ_FLUSH, DC_ERROR, DC_COMPLETE, DC_COMPLETEQUIET, DC_DOKEY};
248 enum {SOURCE_RPT, SOURCE_LNK, SOURCE_RMT, SOURCE_PHONE, SOURCE_DPHONE};
250 enum {DLY_TELEM, DLY_ID, DLY_UNKEY, DLY_CALLTERM, DLY_COMP, DLY_LINKUNKEY};
252 enum {REM_MODE_FM,REM_MODE_USB,REM_MODE_LSB,REM_MODE_AM};
254 enum {HF_SCAN_OFF,HF_SCAN_DOWN_SLOW,HF_SCAN_DOWN_QUICK,
255 HF_SCAN_DOWN_FAST,HF_SCAN_UP_SLOW,HF_SCAN_UP_QUICK,HF_SCAN_UP_FAST};
257 #include "asterisk.h"
259 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
261 #include <signal.h>
262 #include <stdio.h>
263 #include <unistd.h>
264 #include <string.h>
265 #include <stdlib.h>
266 #include <search.h>
267 #include <sys/types.h>
268 #include <sys/stat.h>
269 #include <errno.h>
270 #include <dirent.h>
271 #include <ctype.h>
272 #include <sys/stat.h>
273 #include <sys/time.h>
274 #include <sys/file.h>
275 #include <sys/ioctl.h>
276 #include <sys/io.h>
277 #include <sys/vfs.h>
278 #include <math.h>
279 #include <netinet/in.h>
280 #include <arpa/inet.h>
281 #include <termios.h>
283 #include "asterisk/utils.h"
284 #include "asterisk/lock.h"
285 #include "asterisk/file.h"
286 #include "asterisk/logger.h"
287 #include "asterisk/channel.h"
288 #include "asterisk/callerid.h"
289 #include "asterisk/pbx.h"
290 #include "asterisk/module.h"
291 #include "asterisk/translate.h"
292 #include "asterisk/features.h"
293 #include "asterisk/options.h"
294 #include "asterisk/cli.h"
295 #include "asterisk/config.h"
296 #include "asterisk/say.h"
297 #include "asterisk/localtime.h"
298 #include "asterisk/cdr.h"
299 #include "asterisk/options.h"
301 #include "asterisk/dahdi_compat.h"
302 #include "asterisk/tonezone_compat.h"
304 /* Start a tone-list going */
305 int ast_playtones_start(struct ast_channel *chan, int vol, const char* tonelist, int interruptible);
306 /*! Stop the tones from playing */
307 void ast_playtones_stop(struct ast_channel *chan);
309 static char *tdesc = "Radio Repeater / Remote Base version 0.73 09/04/2007";
311 static char *app = "Rpt";
313 static char *synopsis = "Radio Repeater/Remote Base Control System";
315 static char *descrip =
316 " Rpt(nodename[|options]): Radio Remote Link or Remote Base Link Endpoint Process.\n"
317 "\n"
318 " Not specifying an option puts it in normal endpoint mode (where source\n"
319 " IP and nodename are verified).\n"
320 "\n"
321 " Options are as follows:\n"
322 "\n"
323 " X - Normal endpoint mode WITHOUT security check. Only specify\n"
324 " this if you have checked security already (like with an IAX2\n"
325 " user/password or something).\n"
326 "\n"
327 " Rannounce-string[|timeout[|timeout-destination]] - Amateur Radio\n"
328 " Reverse Autopatch. Caller is put on hold, and announcement (as\n"
329 " specified by the 'announce-string') is played on radio system.\n"
330 " Users of radio system can access autopatch, dial specified\n"
331 " code, and pick up call. Announce-string is list of names of\n"
332 " recordings, or \"PARKED\" to substitute code for un-parking,\n"
333 " or \"NODE\" to substitute node number.\n"
334 "\n"
335 " P - Phone Control mode. This allows a regular phone user to have\n"
336 " full control and audio access to the radio system. For the\n"
337 " user to have DTMF control, the 'phone_functions' parameter\n"
338 " must be specified for the node in 'rpt.conf'. An additional\n"
339 " function (cop,6) must be listed so that PTT control is available.\n"
340 "\n"
341 " D - Dumb Phone Control mode. This allows a regular phone user to\n"
342 " have full control and audio access to the radio system. In this\n"
343 " mode, the PTT is activated for the entire length of the call.\n"
344 " For the user to have DTMF control (not generally recomended in\n"
345 " this mode), the 'dphone_functions' parameter must be specified\n"
346 " for the node in 'rpt.conf'. Otherwise no DTMF control will be\n"
347 " available to the phone user.\n"
348 "\n";
350 static int debug = 0; /* Set this >0 for extra debug output */
351 static int nrpts = 0;
353 static char remdtmfstr[] = "0123456789*#ABCD";
355 enum {TOP_TOP,TOP_WON,WON_BEFREAD,BEFREAD_AFTERREAD};
357 int max_chan_stat [] = {22000,1000,22000,100,22000,2000,22000};
359 #define NRPTSTAT 7
361 struct rpt_chan_stat
363 struct timeval last;
364 long long total;
365 unsigned long count;
366 unsigned long largest;
367 struct timeval largest_time;
370 char *discstr = "!!DISCONNECT!!";
371 static char *remote_rig_ft897="ft897";
372 static char *remote_rig_rbi="rbi";
373 static char *remote_rig_kenwood="kenwood";
374 static char *remote_rig_ic706="ic706";
376 #ifdef OLD_ASTERISK
377 STANDARD_LOCAL_USER;
378 LOCAL_USER_DECL;
379 #endif
381 #define MSWAIT 200
382 #define HANGTIME 5000
383 #define TOTIME 180000
384 #define IDTIME 300000
385 #define MAXRPTS 20
386 #define MAX_STAT_LINKS 32
387 #define POLITEID 30000
388 #define FUNCTDELAY 1500
390 #define MAXXLAT 20
391 #define MAXXLATTIME 3
393 #define MAX_SYSSTATES 10
395 struct rpt_xlat
397 char funccharseq[MAXXLAT];
398 char endcharseq[MAXXLAT];
399 char passchars[MAXXLAT];
400 int funcindex;
401 int endindex;
402 time_t lastone;
405 static time_t starttime = 0;
407 static pthread_t rpt_master_thread;
409 struct rpt;
411 struct rpt_link
413 struct rpt_link *next;
414 struct rpt_link *prev;
415 char mode; /* 1 if in tx mode */
416 char isremote;
417 char phonemode;
418 char name[MAXNODESTR]; /* identifier (routing) string */
419 char lasttx;
420 char lastrx;
421 char lastrx1;
422 char connected;
423 char hasconnected;
424 char perma;
425 char thisconnected;
426 char outbound;
427 char disced;
428 char killme;
429 long elaptime;
430 long disctime;
431 long retrytimer;
432 long retxtimer;
433 long rerxtimer;
434 int retries;
435 int max_retries;
436 int reconnects;
437 long long connecttime;
438 struct ast_channel *chan;
439 struct ast_channel *pchan;
440 char linklist[MAXLINKLIST];
441 time_t linklistreceived;
442 long linklisttimer;
443 int dtmfed;
444 int linkunkeytocttimer;
445 struct ast_frame *lastf1,*lastf2;
446 struct rpt_chan_stat chan_stat[NRPTSTAT];
449 struct rpt_lstat
451 struct rpt_lstat *next;
452 struct rpt_lstat *prev;
453 char peer[MAXPEERSTR];
454 char name[MAXNODESTR];
455 char mode;
456 char outbound;
457 char reconnects;
458 char thisconnected;
459 long long connecttime;
460 struct rpt_chan_stat chan_stat[NRPTSTAT];
463 struct rpt_tele
465 struct rpt_tele *next;
466 struct rpt_tele *prev;
467 struct rpt *rpt;
468 struct ast_channel *chan;
469 int mode;
470 struct rpt_link mylink;
471 char param[TELEPARAMSIZE];
472 int submode;
473 pthread_t threadid;
476 struct function_table_tag
478 char action[ACTIONSIZE];
479 int (*function)(struct rpt *myrpt, char *param, char *digitbuf,
480 int command_source, struct rpt_link *mylink);
483 /* Used to store the morse code patterns */
485 struct morse_bits
487 int len;
488 int ddcomb;
491 struct telem_defaults
493 char name[20];
494 char value[80];
498 struct sysstate
500 char txdisable;
501 char totdisable;
502 char linkfundisable;
503 char autopatchdisable;
504 char schedulerdisable;
505 char userfundisable;
506 char alternatetail;
509 static struct rpt
511 ast_mutex_t lock;
512 ast_mutex_t remlock;
513 struct ast_config *cfg;
514 char reload;
516 char *name;
517 char *rxchanname;
518 char *txchanname;
519 char *remote;
520 struct rpt_chan_stat chan_stat[NRPTSTAT];
521 unsigned int scram;
523 struct {
524 char *ourcontext;
525 char *ourcallerid;
526 char *acctcode;
527 char *ident;
528 char *tonezone;
529 char simple;
530 char *functions;
531 char *link_functions;
532 char *phone_functions;
533 char *dphone_functions;
534 char *nodes;
535 char *extnodes;
536 char *extnodefile;
537 int hangtime;
538 int althangtime;
539 int totime;
540 int idtime;
541 int tailmessagetime;
542 int tailsquashedtime;
543 int duplex;
544 int politeid;
545 char *tailmessages[500];
546 int tailmessagemax;
547 char *memory;
548 char *macro;
549 char *startupmacro;
550 int iobase;
551 char *ioport;
552 char funcchar;
553 char endchar;
554 char nobusyout;
555 char notelemtx;
556 char propagate_dtmf;
557 char propagate_phonedtmf;
558 char linktolink;
559 unsigned char civaddr;
560 struct rpt_xlat inxlat;
561 struct rpt_xlat outxlat;
562 char *archivedir;
563 int authlevel;
564 char *csstanzaname;
565 char *skedstanzaname;
566 char *txlimitsstanzaname;
567 long monminblocks;
568 int remoteinacttimeout;
569 int remotetimeout;
570 int remotetimeoutwarning;
571 int remotetimeoutwarningfreq;
572 int sysstate_cur;
573 struct sysstate s[MAX_SYSSTATES];
574 } p;
575 struct rpt_link links;
576 int unkeytocttimer;
577 char keyed;
578 char exttx;
579 char localtx;
580 char remoterx;
581 char remotetx;
582 char remoteon;
583 char remtxfreqok;
584 char tounkeyed;
585 char tonotify;
586 char dtmfbuf[MAXDTMF];
587 char macrobuf[MAXMACRO];
588 char rem_dtmfbuf[MAXDTMF];
589 char lastdtmfcommand[MAXDTMF];
590 char cmdnode[50];
591 struct ast_channel *rxchannel,*txchannel, *monchannel;
592 struct ast_channel *pchannel,*txpchannel, *zaprxchannel, *zaptxchannel;
593 struct ast_frame *lastf1,*lastf2;
594 struct rpt_tele tele;
595 struct timeval lasttv,curtv;
596 pthread_t rpt_call_thread,rpt_thread;
597 time_t dtmf_time,rem_dtmf_time,dtmf_time_rem;
598 int tailtimer,totimer,idtimer,txconf,conf,callmode,cidx,scantimer,tmsgtimer,skedtimer;
599 int mustid,tailid;
600 int tailevent;
601 int telemrefcount;
602 int dtmfidx,rem_dtmfidx;
603 int dailytxtime,dailykerchunks,totalkerchunks,dailykeyups,totalkeyups,timeouts;
604 int totalexecdcommands, dailyexecdcommands;
605 long retxtimer;
606 long rerxtimer;
607 long long totaltxtime;
608 char mydtmf;
609 char exten[AST_MAX_EXTENSION];
610 char freq[MAXREMSTR],rxpl[MAXREMSTR],txpl[MAXREMSTR];
611 char offset;
612 char powerlevel;
613 char txplon;
614 char rxplon;
615 char remmode;
616 char tunerequest;
617 char hfscanmode;
618 int hfscanstatus;
619 char hfscanstop;
620 char lastlinknode[MAXNODESTR];
621 char savednodes[MAXNODESTR];
622 int stopgen;
623 char patchfarenddisconnect;
624 char patchnoct;
625 char patchquiet;
626 char patchcontext[MAXPATCHCONTEXT];
627 int patchdialtime;
628 int macro_longest;
629 int phone_longestfunc;
630 int dphone_longestfunc;
631 int link_longestfunc;
632 int longestfunc;
633 int longestnode;
634 int threadrestarts;
635 int tailmessagen;
636 time_t disgorgetime;
637 time_t lastthreadrestarttime;
638 long macrotimer;
639 char lastnodewhichkeyedusup[MAXNODESTR];
640 int dtmf_local_timer;
641 char dtmf_local_str[100];
642 struct ast_filestream *monstream;
643 char loginuser[50];
644 char loginlevel[10];
645 long authtelltimer;
646 long authtimer;
647 int iofd;
648 time_t start_time,last_activity_time;
649 #ifdef __RPT_NOTCH
650 struct rptfilter
652 char desc[100];
653 float x0;
654 float x1;
655 float x2;
656 float y0;
657 float y1;
658 float y2;
659 float gain;
660 float const0;
661 float const1;
662 float const2;
663 } filters[MAXFILTERS];
664 #endif
665 #ifdef _MDC_DECODE_H_
666 mdc_decoder_t *mdc;
667 unsigned short lastunit;
668 #endif
669 } rpt_vars[MAXRPTS];
671 struct nodelog {
672 struct nodelog *next;
673 struct nodelog *prev;
674 time_t timestamp;
675 char archivedir[MAXNODESTR];
676 char str[MAXNODESTR * 2];
677 } nodelog;
679 static int service_scan(struct rpt *myrpt);
680 static int set_mode_ft897(struct rpt *myrpt, char newmode);
681 static int set_mode_ic706(struct rpt *myrpt, char newmode);
682 static int simple_command_ft897(struct rpt *myrpt, char command);
683 static int setrem(struct rpt *myrpt);
685 AST_MUTEX_DEFINE_STATIC(nodeloglock);
687 AST_MUTEX_DEFINE_STATIC(nodelookuplock);
689 #ifdef APP_RPT_LOCK_DEBUG
691 #warning COMPILING WITH LOCK-DEBUGGING ENABLED!!
693 #define MAXLOCKTHREAD 100
695 #define rpt_mutex_lock(x) _rpt_mutex_lock(x,myrpt,__LINE__)
696 #define rpt_mutex_unlock(x) _rpt_mutex_unlock(x,myrpt,__LINE__)
698 struct lockthread
700 pthread_t id;
701 int lockcount;
702 int lastlock;
703 int lastunlock;
704 } lockthreads[MAXLOCKTHREAD];
707 struct by_lightning
709 int line;
710 struct timeval tv;
711 struct rpt *rpt;
712 struct lockthread lockthread;
713 } lock_ring[32];
715 int lock_ring_index = 0;
717 AST_MUTEX_DEFINE_STATIC(locklock);
719 static struct lockthread *get_lockthread(pthread_t id)
721 int i;
723 for(i = 0; i < MAXLOCKTHREAD; i++)
725 if (lockthreads[i].id == id) return(&lockthreads[i]);
727 return(NULL);
730 static struct lockthread *put_lockthread(pthread_t id)
732 int i;
734 for(i = 0; i < MAXLOCKTHREAD; i++)
736 if (lockthreads[i].id == id)
737 return(&lockthreads[i]);
739 for(i = 0; i < MAXLOCKTHREAD; i++)
741 if (!lockthreads[i].id)
743 lockthreads[i].lockcount = 0;
744 lockthreads[i].lastlock = 0;
745 lockthreads[i].lastunlock = 0;
746 lockthreads[i].id = id;
747 return(&lockthreads[i]);
750 return(NULL);
754 static void rpt_mutex_spew(void)
756 struct by_lightning lock_ring_copy[32];
757 int lock_ring_index_copy;
758 int i,j;
759 long long diff;
760 char a[100];
761 struct timeval lasttv;
763 ast_mutex_lock(&locklock);
764 memcpy(&lock_ring_copy, &lock_ring, sizeof(lock_ring_copy));
765 lock_ring_index_copy = lock_ring_index;
766 ast_mutex_unlock(&locklock);
768 lasttv.tv_sec = lasttv.tv_usec = 0;
769 for(i = 0 ; i < 32 ; i++)
771 j = (i + lock_ring_index_copy) % 32;
772 strftime(a,sizeof(a) - 1,"%m/%d/%Y %H:%M:%S",
773 localtime(&lock_ring_copy[j].tv.tv_sec));
774 diff = 0;
775 if(lasttv.tv_sec)
777 diff = (lock_ring_copy[j].tv.tv_sec - lasttv.tv_sec)
778 * 1000000;
779 diff += (lock_ring_copy[j].tv.tv_usec - lasttv.tv_usec);
781 lasttv.tv_sec = lock_ring_copy[j].tv.tv_sec;
782 lasttv.tv_usec = lock_ring_copy[j].tv.tv_usec;
783 if (!lock_ring_copy[j].tv.tv_sec) continue;
784 if (lock_ring_copy[j].line < 0)
786 ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] UNLOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
787 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);
789 else
791 ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] LOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
792 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);
798 static void _rpt_mutex_lock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
800 struct lockthread *t;
801 pthread_t id;
803 id = pthread_self();
804 ast_mutex_lock(&locklock);
805 t = put_lockthread(id);
806 if (!t)
808 ast_mutex_unlock(&locklock);
809 return;
811 if (t->lockcount)
813 int lastline = t->lastlock;
814 ast_mutex_unlock(&locklock);
815 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);
816 rpt_mutex_spew();
817 return;
819 t->lastlock = line;
820 t->lockcount = 1;
821 gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
822 lock_ring[lock_ring_index].rpt = myrpt;
823 memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
824 lock_ring[lock_ring_index++].line = line;
825 if(lock_ring_index == 32)
826 lock_ring_index = 0;
827 ast_mutex_unlock(&locklock);
828 ast_mutex_lock(lockp);
832 static void _rpt_mutex_unlock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
834 struct lockthread *t;
835 pthread_t id;
837 id = pthread_self();
838 ast_mutex_lock(&locklock);
839 t = put_lockthread(id);
840 if (!t)
842 ast_mutex_unlock(&locklock);
843 return;
845 if (!t->lockcount)
847 int lastline = t->lastunlock;
848 ast_mutex_unlock(&locklock);
849 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);
850 rpt_mutex_spew();
851 return;
853 t->lastunlock = line;
854 t->lockcount = 0;
855 gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
856 lock_ring[lock_ring_index].rpt = myrpt;
857 memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
858 lock_ring[lock_ring_index++].line = -line;
859 if(lock_ring_index == 32)
860 lock_ring_index = 0;
861 ast_mutex_unlock(&locklock);
862 ast_mutex_unlock(lockp);
865 #else /* APP_RPT_LOCK_DEBUG */
867 #define rpt_mutex_lock(x) ast_mutex_lock(x)
868 #define rpt_mutex_unlock(x) ast_mutex_unlock(x)
870 #endif /* APP_RPT_LOCK_DEBUG */
873 * Return 1 if rig is multimode capable
876 static int multimode_capable(struct rpt *myrpt)
878 if(!strcmp(myrpt->remote, remote_rig_ft897))
879 return 1;
880 if(!strcmp(myrpt->remote, remote_rig_ic706))
881 return 1;
882 return 0;
886 * CLI extensions
889 /* Debug mode */
890 static int rpt_do_debug(int fd, int argc, char *argv[]);
891 static int rpt_do_dump(int fd, int argc, char *argv[]);
892 static int rpt_do_stats(int fd, int argc, char *argv[]);
893 static int rpt_do_lstats(int fd, int argc, char *argv[]);
894 static int rpt_do_nodes(int fd, int argc, char *argv[]);
895 static int rpt_do_reload(int fd, int argc, char *argv[]);
896 static int rpt_do_restart(int fd, int argc, char *argv[]);
897 static int rpt_do_fun(int fd, int argc, char *argv[]);
899 static char debug_usage[] =
900 "Usage: rpt debug level {0-7}\n"
901 " Enables debug messages in app_rpt\n";
903 static char dump_usage[] =
904 "Usage: rpt dump <nodename>\n"
905 " Dumps struct debug info to log\n";
907 static char dump_stats[] =
908 "Usage: rpt stats <nodename>\n"
909 " Dumps node statistics to console\n";
911 static char dump_lstats[] =
912 "Usage: rpt lstats <nodename>\n"
913 " Dumps link statistics to console\n";
915 static char dump_nodes[] =
916 "Usage: rpt nodes <nodename>\n"
917 " Dumps a list of directly and indirectly connected nodes to the console\n";
919 static char reload_usage[] =
920 "Usage: rpt reload\n"
921 " Reloads app_rpt running config parameters\n";
923 static char restart_usage[] =
924 "Usage: rpt restart\n"
925 " Restarts app_rpt\n";
927 static char fun_usage[] =
928 "Usage: rpt fun <nodename> <command>\n"
929 " Send a DTMF function to a node\n";
932 static struct ast_cli_entry cli_debug =
933 { { "rpt", "debug", "level" }, rpt_do_debug,
934 "Enable app_rpt debugging", debug_usage };
936 static struct ast_cli_entry cli_dump =
937 { { "rpt", "dump" }, rpt_do_dump,
938 "Dump app_rpt structs for debugging", dump_usage };
940 static struct ast_cli_entry cli_stats =
941 { { "rpt", "stats" }, rpt_do_stats,
942 "Dump node statistics", dump_stats };
944 static struct ast_cli_entry cli_nodes =
945 { { "rpt", "nodes" }, rpt_do_nodes,
946 "Dump node list", dump_nodes };
948 static struct ast_cli_entry cli_lstats =
949 { { "rpt", "lstats" }, rpt_do_lstats,
950 "Dump link statistics", dump_lstats };
952 static struct ast_cli_entry cli_reload =
953 { { "rpt", "reload" }, rpt_do_reload,
954 "Reload app_rpt config", reload_usage };
956 static struct ast_cli_entry cli_restart =
957 { { "rpt", "restart" }, rpt_do_restart,
958 "Restart app_rpt", restart_usage };
960 static struct ast_cli_entry cli_fun =
961 { { "rpt", "fun" }, rpt_do_fun,
962 "Execute a DTMF function", fun_usage };
965 * Telemetry defaults
969 static struct telem_defaults tele_defs[] = {
970 {"ct1","|t(350,0,100,3072)(500,0,100,3072)(660,0,100,3072)"},
971 {"ct2","|t(660,880,150,3072)"},
972 {"ct3","|t(440,0,150,3072)"},
973 {"ct4","|t(550,0,150,3072)"},
974 {"ct5","|t(660,0,150,3072)"},
975 {"ct6","|t(880,0,150,3072)"},
976 {"ct7","|t(660,440,150,3072)"},
977 {"ct8","|t(700,1100,150,3072)"},
978 {"remotemon","|t(1600,0,75,2048)"},
979 {"remotetx","|t(2000,0,75,2048)(0,0,75,0)(1600,0,75,2048)"},
980 {"cmdmode","|t(900,904,200,2048)"},
981 {"functcomplete","|t(1000,0,100,2048)(0,0,100,0)(1000,0,100,2048)"}
985 * Forward decl's - these suppress compiler warnings when funcs coded further down the file than thier invokation
988 static int setrbi(struct rpt *myrpt);
989 static int set_ft897(struct rpt *myrpt);
990 static int set_ic706(struct rpt *myrpt);
991 static int setkenwood(struct rpt *myrpt);
992 static int setrbi_check(struct rpt *myrpt);
997 * Define function protos for function table here
1000 static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1001 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1002 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1003 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1004 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1005 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1006 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1008 * Function table
1011 static struct function_table_tag function_table[] = {
1012 {"cop", function_cop},
1013 {"autopatchup", function_autopatchup},
1014 {"autopatchdn", function_autopatchdn},
1015 {"ilink", function_ilink},
1016 {"status", function_status},
1017 {"remote", function_remote},
1018 {"macro", function_macro}
1021 static long diskavail(struct rpt *myrpt)
1023 struct statfs statfsbuf;
1025 if (!myrpt->p.archivedir) return(0);
1026 if (statfs(myrpt->p.archivedir,&statfsbuf) == -1)
1028 ast_log(LOG_WARNING,"Cannot get filesystem size for %s node %s\n",
1029 myrpt->p.archivedir,myrpt->name);
1030 return(-1);
1032 return(statfsbuf.f_bavail);
1035 static void do_dtmf_phone(struct rpt *myrpt, struct rpt_link *mylink, char c)
1037 struct rpt_link *l;
1039 l = myrpt->links.next;
1040 /* go thru all the links */
1041 while(l != &myrpt->links)
1043 if (!l->phonemode)
1045 l = l->next;
1046 continue;
1048 /* dont send to self */
1049 if (mylink && (l == mylink))
1051 l = l->next;
1052 continue;
1054 if (l->chan) ast_senddigit(l->chan,c);
1055 l = l->next;
1057 return;
1060 /* node logging function */
1061 static void donodelog(struct rpt *myrpt,char *str)
1063 struct nodelog *nodep;
1064 char datestr[100];
1066 if (!myrpt->p.archivedir) return;
1067 nodep = (struct nodelog *)malloc(sizeof(struct nodelog));
1068 if (nodep == NULL)
1070 ast_log(LOG_ERROR,"Cannot get memory for node log");
1071 return;
1073 time(&nodep->timestamp);
1074 strncpy(nodep->archivedir,myrpt->p.archivedir,
1075 sizeof(nodep->archivedir) - 1);
1076 strftime(datestr,sizeof(datestr) - 1,"%Y%m%d%H%M%S",
1077 localtime(&nodep->timestamp));
1078 snprintf(nodep->str,sizeof(nodep->str) - 1,"%s %s,%s\n",
1079 myrpt->name,datestr,str);
1080 ast_mutex_lock(&nodeloglock);
1081 insque((struct qelem *) nodep, (struct qelem *) nodelog.prev);
1082 ast_mutex_unlock(&nodeloglock);
1085 /* must be called locked */
1086 static void do_dtmf_local(struct rpt *myrpt, char c)
1088 int i;
1089 char digit;
1090 static const char* dtmf_tones[] = {
1091 "!941+1336/200,!0/200", /* 0 */
1092 "!697+1209/200,!0/200", /* 1 */
1093 "!697+1336/200,!0/200", /* 2 */
1094 "!697+1477/200,!0/200", /* 3 */
1095 "!770+1209/200,!0/200", /* 4 */
1096 "!770+1336/200,!0/200", /* 5 */
1097 "!770+1477/200,!0/200", /* 6 */
1098 "!852+1209/200,!0/200", /* 7 */
1099 "!852+1336/200,!0/200", /* 8 */
1100 "!852+1477/200,!0/200", /* 9 */
1101 "!697+1633/200,!0/200", /* A */
1102 "!770+1633/200,!0/200", /* B */
1103 "!852+1633/200,!0/200", /* C */
1104 "!941+1633/200,!0/200", /* D */
1105 "!941+1209/200,!0/200", /* * */
1106 "!941+1477/200,!0/200" }; /* # */
1109 if (c)
1111 snprintf(myrpt->dtmf_local_str + strlen(myrpt->dtmf_local_str),sizeof(myrpt->dtmf_local_str) - 1,"%c",c);
1112 if (!myrpt->dtmf_local_timer)
1113 myrpt->dtmf_local_timer = DTMF_LOCAL_STARTTIME;
1115 /* if at timeout */
1116 if (myrpt->dtmf_local_timer == 1)
1118 /* if anything in the string */
1119 if (myrpt->dtmf_local_str[0])
1121 digit = myrpt->dtmf_local_str[0];
1122 myrpt->dtmf_local_str[0] = 0;
1123 for(i = 1; myrpt->dtmf_local_str[i]; i++)
1125 myrpt->dtmf_local_str[i - 1] =
1126 myrpt->dtmf_local_str[i];
1128 myrpt->dtmf_local_str[i - 1] = 0;
1129 myrpt->dtmf_local_timer = DTMF_LOCAL_TIME;
1130 rpt_mutex_unlock(&myrpt->lock);
1131 if (digit >= '0' && digit <='9')
1132 ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'0'], 0);
1133 else if (digit >= 'A' && digit <= 'D')
1134 ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'A'+10], 0);
1135 else if (digit == '*')
1136 ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[14], 0);
1137 else if (digit == '#')
1138 ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[15], 0);
1139 else {
1140 /* not handled */
1141 ast_log(LOG_DEBUG, "Unable to generate DTMF tone '%c' for '%s'\n", digit, myrpt->txchannel->name);
1143 rpt_mutex_lock(&myrpt->lock);
1145 else
1147 myrpt->dtmf_local_timer = 0;
1152 static int openserial(char *fname)
1154 struct termios mode;
1155 int fd;
1157 fd = open(fname,O_RDWR);
1158 if (fd == -1)
1160 ast_log(LOG_WARNING,"Cannot open serial port %s\n",fname);
1161 return -1;
1163 memset(&mode, 0, sizeof(mode));
1164 if (tcgetattr(fd, &mode)) {
1165 ast_log(LOG_WARNING, "Unable to get serial parameters on %s: %s\n", fname, strerror(errno));
1166 return -1;
1168 #ifndef SOLARIS
1169 cfmakeraw(&mode);
1170 #else
1171 mode.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
1172 |INLCR|IGNCR|ICRNL|IXON);
1173 mode.c_oflag &= ~OPOST;
1174 mode.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
1175 mode.c_cflag &= ~(CSIZE|PARENB|CRTSCTS);
1176 mode.c_cflag |= CS8;
1177 mode.c_cc[TIME] = 3;
1178 mode.c_cc[MAX] = 1;
1179 #endif
1181 cfsetispeed(&mode, B9600);
1182 cfsetospeed(&mode, B9600);
1183 if (tcsetattr(fd, TCSANOW, &mode))
1184 ast_log(LOG_WARNING, "Unable to set serial parameters on %s: %s\n", fname, strerror(errno));
1185 return(fd);
1188 static void mdc1200_notify(struct rpt *myrpt,char *fromnode, unsigned int unit)
1190 if (!fromnode)
1192 ast_verbose("Got MDC-1200 ID %04X from local system (%s)\n",
1193 unit,myrpt->name);
1195 else
1197 ast_verbose("Got MDC-1200 ID %04X from node %s (%s)\n",
1198 unit,fromnode,myrpt->name);
1202 #ifdef _MDC_DECODE_H_
1204 static void mdc1200_send(struct rpt *myrpt, unsigned int unit)
1206 struct rpt_link *l;
1207 struct ast_frame wf;
1208 char str[200];
1211 sprintf(str,"I %s %04X",myrpt->name,unit);
1213 wf.frametype = AST_FRAME_TEXT;
1214 wf.subclass = 0;
1215 wf.offset = 0;
1216 wf.mallocd = 0;
1217 wf.datalen = strlen(str) + 1;
1218 wf.samples = 0;
1221 l = myrpt->links.next;
1222 /* otherwise, send it to all of em */
1223 while(l != &myrpt->links)
1225 if (l->name[0] == '0')
1227 l = l->next;
1228 continue;
1230 wf.data = str;
1231 if (l->chan) ast_write(l->chan,&wf);
1232 l = l->next;
1234 return;
1237 #endif
1239 static char func_xlat(struct rpt *myrpt,char c,struct rpt_xlat *xlat)
1241 time_t now;
1242 int gotone;
1244 time(&now);
1245 gotone = 0;
1246 /* if too much time, reset the skate machine */
1247 if ((now - xlat->lastone) > MAXXLATTIME)
1249 xlat->funcindex = xlat->endindex = 0;
1251 if (xlat->funccharseq[0] && (c == xlat->funccharseq[xlat->funcindex++]))
1253 time(&xlat->lastone);
1254 gotone = 1;
1255 if (!xlat->funccharseq[xlat->funcindex])
1257 xlat->funcindex = xlat->endindex = 0;
1258 return(myrpt->p.funcchar);
1260 } else xlat->funcindex = 0;
1261 if (xlat->endcharseq[0] && (c == xlat->endcharseq[xlat->endindex++]))
1263 time(&xlat->lastone);
1264 gotone = 1;
1265 if (!xlat->endcharseq[xlat->endindex])
1267 xlat->funcindex = xlat->endindex = 0;
1268 return(myrpt->p.endchar);
1270 } else xlat->endindex = 0;
1271 /* if in middle of decode seq, send nothing back */
1272 if (gotone) return(0);
1273 /* if no pass chars specified, return em all */
1274 if (!xlat->passchars[0]) return(c);
1275 /* if a "pass char", pass it */
1276 if (strchr(xlat->passchars,c)) return(c);
1277 return(0);
1281 * Return a pointer to the first non-whitespace character
1284 static char *eatwhite(char *s)
1286 while((*s == ' ') || (*s == 0x09)){ /* get rid of any leading white space */
1287 if(!*s)
1288 break;
1289 s++;
1291 return s;
1295 * Break up a delimited string into a table of substrings
1297 * str - delimited string ( will be modified )
1298 * strp- list of pointers to substrings (this is built by this function), NULL will be placed at end of list
1299 * limit- maximum number of substrings to process
1304 static int finddelim(char *str, char *strp[], int limit)
1306 int i,l,inquo;
1308 inquo = 0;
1309 i = 0;
1310 strp[i++] = str;
1311 if (!*str)
1313 strp[0] = 0;
1314 return(0);
1316 for(l = 0; *str && (l < limit) ; str++)
1318 if (*str == QUOTECHR)
1320 if (inquo)
1322 *str = 0;
1323 inquo = 0;
1325 else
1327 strp[i - 1] = str + 1;
1328 inquo = 1;
1331 if ((*str == DELIMCHR) && (!inquo))
1333 *str = 0;
1334 l++;
1335 strp[i++] = str + 1;
1338 strp[i] = 0;
1339 return(i);
1343 /* must be called locked */
1344 static void __mklinklist(struct rpt *myrpt, struct rpt_link *mylink, char *buf)
1346 struct rpt_link *l;
1347 char mode;
1348 int i,spos;
1350 buf[0] = 0; /* clear output buffer */
1351 /* go thru all links */
1352 for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
1354 /* if is not a real link, ignore it */
1355 if (l->name[0] == '0') continue;
1356 /* dont count our stuff */
1357 if (l == mylink) continue;
1358 if (mylink && (!strcmp(l->name,mylink->name))) continue;
1359 /* figure out mode to report */
1360 mode = 'T'; /* use Tranceive by default */
1361 if (!l->mode) mode = 'R'; /* indicate RX for our mode */
1362 if (!l->thisconnected) mode = 'C'; /* indicate connecting */
1363 spos = strlen(buf); /* current buf size (b4 we add our stuff) */
1364 if (spos)
1366 strcat(buf,",");
1367 spos++;
1369 /* add nodes into buffer */
1370 if (l->linklist[0])
1372 snprintf(buf + spos,MAXLINKLIST - spos,
1373 "%c%s,%s",mode,l->name,l->linklist);
1375 else /* if no nodes, add this node into buffer */
1377 snprintf(buf + spos,MAXLINKLIST - spos,
1378 "%c%s",mode,l->name);
1380 /* if we are in tranceive mode, let all modes stand */
1381 if (mode == 'T') continue;
1382 /* downgrade everyone on this node if appropriate */
1383 for(i = spos; buf[i]; i++)
1385 if (buf[i] == 'T') buf[i] = mode;
1386 if ((buf[i] == 'R') && (mode == 'C')) buf[i] = mode;
1389 return;
1392 /* must be called locked */
1393 static void __kickshort(struct rpt *myrpt)
1395 struct rpt_link *l;
1397 for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
1399 /* if is not a real link, ignore it */
1400 if (l->name[0] == '0') continue;
1401 l->linklisttimer = LINKLISTSHORTTIME;
1403 return;
1406 static char *node_lookup(struct rpt *myrpt,char *digitbuf)
1409 char *val;
1410 int longestnode,j;
1411 struct stat mystat;
1412 static time_t last = 0;
1413 static struct ast_config *ourcfg = NULL;
1414 struct ast_variable *vp;
1416 /* try to look it up locally first */
1417 val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
1418 if (val) return(val);
1419 ast_mutex_lock(&nodelookuplock);
1420 /* if file does not exist */
1421 if (stat(myrpt->p.extnodefile,&mystat) == -1)
1423 if (ourcfg) ast_config_destroy(ourcfg);
1424 ourcfg = NULL;
1425 ast_mutex_unlock(&nodelookuplock);
1426 return(NULL);
1428 /* if we need to reload */
1429 if (mystat.st_mtime > last)
1431 if (ourcfg) ast_config_destroy(ourcfg);
1432 ourcfg = ast_config_load(myrpt->p.extnodefile);
1433 /* if file not there, just bail */
1434 if (!ourcfg)
1436 ast_mutex_unlock(&nodelookuplock);
1437 return(NULL);
1439 /* reset "last" time */
1440 last = mystat.st_mtime;
1442 /* determine longest node length again */
1443 longestnode = 0;
1444 vp = ast_variable_browse(myrpt->cfg, myrpt->p.nodes);
1445 while(vp){
1446 j = strlen(vp->name);
1447 if (j > longestnode)
1448 longestnode = j;
1449 vp = vp->next;
1452 vp = ast_variable_browse(ourcfg, myrpt->p.extnodes);
1453 while(vp){
1454 j = strlen(vp->name);
1455 if (j > longestnode)
1456 longestnode = j;
1457 vp = vp->next;
1460 myrpt->longestnode = longestnode;
1462 val = NULL;
1463 if (ourcfg)
1464 val = (char *) ast_variable_retrieve(ourcfg, myrpt->p.extnodes, digitbuf);
1465 ast_mutex_unlock(&nodelookuplock);
1466 return(val);
1470 * Match a keyword in a list, and return index of string plus 1 if there was a match,* else return 0.
1471 * If param is passed in non-null, then it will be set to the first character past the match
1474 static int matchkeyword(char *string, char **param, char *keywords[])
1476 int i,ls;
1477 for( i = 0 ; keywords[i] ; i++){
1478 ls = strlen(keywords[i]);
1479 if(!ls){
1480 *param = NULL;
1481 return 0;
1483 if(!strncmp(string, keywords[i], ls)){
1484 if(param)
1485 *param = string + ls;
1486 return i + 1;
1489 param = NULL;
1490 return 0;
1494 * Skip characters in string which are in charlist, and return a pointer to the
1495 * first non-matching character
1498 static char *skipchars(char *string, char *charlist)
1500 int i;
1501 while(*string){
1502 for(i = 0; charlist[i] ; i++){
1503 if(*string == charlist[i]){
1504 string++;
1505 break;
1508 if(!charlist[i])
1509 return string;
1511 return string;
1516 static int myatoi(char *str)
1518 int ret;
1520 if (str == NULL) return -1;
1521 /* leave this %i alone, non-base-10 input is useful here */
1522 if (sscanf(str,"%i",&ret) != 1) return -1;
1523 return ret;
1526 static int mycompar(const void *a, const void *b)
1528 char **x = (char **) a;
1529 char **y = (char **) b;
1530 int xoff,yoff;
1532 if ((**x < '0') || (**x > '9')) xoff = 1; else xoff = 0;
1533 if ((**y < '0') || (**y > '9')) yoff = 1; else yoff = 0;
1534 return(strcmp((*x) + xoff,(*y) + yoff));
1537 #ifdef __RPT_NOTCH
1539 /* rpt filter routine */
1540 static void rpt_filter(struct rpt *myrpt, volatile short *buf, int len)
1542 int i,j;
1543 struct rptfilter *f;
1545 for(i = 0; i < len; i++)
1547 for(j = 0; j < MAXFILTERS; j++)
1549 f = &myrpt->filters[j];
1550 if (!*f->desc) continue;
1551 f->x0 = f->x1; f->x1 = f->x2;
1552 f->x2 = ((float)buf[i]) / f->gain;
1553 f->y0 = f->y1; f->y1 = f->y2;
1554 f->y2 = (f->x0 + f->x2) + f->const0 * f->x1
1555 + (f->const1 * f->y0) + (f->const2 * f->y1);
1556 buf[i] = (short)f->y2;
1561 #endif
1565 Get the time for the machine's time zone
1566 Note: Asterisk requires a copy of localtime
1567 in the /etc directory for this to work properly.
1568 If /etc/localtime is not present, you will get
1569 GMT time! This is especially important on systems
1570 running embedded linux distributions as they don't usually
1571 have support for locales.
1573 If OLD_ASTERISK is defined, then the older localtime_r
1574 function will be used. The /etc/localtime file is not
1575 required in this case. This provides backward compatibility
1576 with Asterisk 1.2 systems.
1580 static void rpt_localtime( time_t * t, struct tm *lt)
1582 #ifdef OLD_ASTERISK
1583 localtime_r(t, lt);
1584 #else
1585 ast_localtime(t, lt, NULL);
1586 #endif
1589 /* Retrieve an int from a config file */
1591 static int retrieve_astcfgint(struct rpt *myrpt,char *category, char *name, int min, int max, int defl)
1593 char *var;
1594 int ret;
1595 char include_zero = 0;
1597 if(min < 0){ /* If min is negative, this means include 0 as a valid entry */
1598 min = -min;
1599 include_zero = 1;
1602 var = (char *) ast_variable_retrieve(myrpt->cfg, category, name);
1603 if(var){
1604 ret = myatoi(var);
1605 if(include_zero && !ret)
1606 return 0;
1607 if(ret < min)
1608 ret = min;
1609 if(ret > max)
1610 ret = max;
1612 else
1613 ret = defl;
1614 return ret;
1618 static void load_rpt_vars(int n,int init)
1620 char *this,*val;
1621 int i,j,longestnode;
1622 struct ast_variable *vp;
1623 struct ast_config *cfg;
1624 char *strs[100];
1625 char s1[256];
1626 static char *cs_keywords[] = {"rptena","rptdis","apena","apdis","lnkena","lnkdis","totena","totdis","skena","skdis",
1627 "ufena","ufdis","atena","atdis",NULL};
1629 if (option_verbose > 2)
1630 ast_verbose(VERBOSE_PREFIX_3 "%s config for repeater %s\n",
1631 (init) ? "Loading initial" : "Re-Loading",rpt_vars[n].name);
1632 ast_mutex_lock(&rpt_vars[n].lock);
1633 if (rpt_vars[n].cfg) ast_config_destroy(rpt_vars[n].cfg);
1634 cfg = ast_config_load("rpt.conf");
1635 if (!cfg) {
1636 ast_mutex_unlock(&rpt_vars[n].lock);
1637 ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf. Radio Repeater disabled.\n");
1638 pthread_exit(NULL);
1640 rpt_vars[n].cfg = cfg;
1641 this = rpt_vars[n].name;
1642 memset(&rpt_vars[n].p,0,sizeof(rpt_vars[n].p));
1643 if (init)
1645 /* clear all the fields in the structure after 'p' */
1646 memset(&rpt_vars[n].p + sizeof(rpt_vars[0].p), 0, sizeof(rpt_vars[0]) - sizeof(rpt_vars[0].p) - offsetof(typeof(rpt_vars[0]), p));
1647 rpt_vars[n].tele.next = &rpt_vars[n].tele;
1648 rpt_vars[n].tele.prev = &rpt_vars[n].tele;
1649 rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
1650 rpt_vars[n].tailmessagen = 0;
1652 #ifdef __RPT_NOTCH
1653 /* zot out filters stuff */
1654 memset(&rpt_vars[n].filters,0,sizeof(rpt_vars[n].filters));
1655 #endif
1656 val = (char *) ast_variable_retrieve(cfg,this,"context");
1657 if (val) rpt_vars[n].p.ourcontext = val;
1658 else rpt_vars[n].p.ourcontext = this;
1659 val = (char *) ast_variable_retrieve(cfg,this,"callerid");
1660 if (val) rpt_vars[n].p.ourcallerid = val;
1661 val = (char *) ast_variable_retrieve(cfg,this,"accountcode");
1662 if (val) rpt_vars[n].p.acctcode = val;
1663 val = (char *) ast_variable_retrieve(cfg,this,"idrecording");
1664 if (val) rpt_vars[n].p.ident = val;
1665 val = (char *) ast_variable_retrieve(cfg,this,"hangtime");
1666 if (val) rpt_vars[n].p.hangtime = atoi(val);
1667 else rpt_vars[n].p.hangtime = HANGTIME;
1668 val = (char *) ast_variable_retrieve(cfg,this,"althangtime");
1669 if (val) rpt_vars[n].p.althangtime = atoi(val);
1670 else rpt_vars[n].p.althangtime = HANGTIME;
1671 val = (char *) ast_variable_retrieve(cfg,this,"totime");
1672 if (val) rpt_vars[n].p.totime = atoi(val);
1673 else rpt_vars[n].p.totime = TOTIME;
1674 rpt_vars[n].p.tailmessagetime = retrieve_astcfgint(&rpt_vars[n],this, "tailmessagetime", 0, 2400000, 0);
1675 rpt_vars[n].p.tailsquashedtime = retrieve_astcfgint(&rpt_vars[n],this, "tailsquashedtime", 0, 2400000, 0);
1676 rpt_vars[n].p.duplex = retrieve_astcfgint(&rpt_vars[n],this,"duplex",0,4,2);
1677 rpt_vars[n].p.idtime = retrieve_astcfgint(&rpt_vars[n],this, "idtime", -60000, 2400000, IDTIME); /* Enforce a min max including zero */
1678 rpt_vars[n].p.politeid = retrieve_astcfgint(&rpt_vars[n],this, "politeid", 30000, 300000, POLITEID); /* Enforce a min max */
1679 val = (char *) ast_variable_retrieve(cfg,this,"tonezone");
1680 if (val) rpt_vars[n].p.tonezone = val;
1681 rpt_vars[n].p.tailmessages[0] = 0;
1682 rpt_vars[n].p.tailmessagemax = 0;
1683 val = (char *) ast_variable_retrieve(cfg,this,"tailmessagelist");
1684 if (val) rpt_vars[n].p.tailmessagemax = finddelim(val, rpt_vars[n].p.tailmessages, 500);
1685 val = (char *) ast_variable_retrieve(cfg,this,"memory");
1686 if (!val) val = MEMORY;
1687 rpt_vars[n].p.memory = val;
1688 val = (char *) ast_variable_retrieve(cfg,this,"macro");
1689 if (!val) val = MACRO;
1690 rpt_vars[n].p.macro = val;
1691 val = (char *) ast_variable_retrieve(cfg,this,"startup_macro");
1692 if (val) rpt_vars[n].p.startupmacro = val;
1693 val = (char *) ast_variable_retrieve(cfg,this,"iobase");
1694 /* do not use atoi() here, we need to be able to have
1695 the input specified in hex or decimal so we use
1696 sscanf with a %i */
1697 if ((!val) || (sscanf(val,"%i",&rpt_vars[n].p.iobase) != 1))
1698 rpt_vars[n].p.iobase = DEFAULT_IOBASE;
1699 val = (char *) ast_variable_retrieve(cfg,this,"ioport");
1700 rpt_vars[n].p.ioport = val;
1701 val = (char *) ast_variable_retrieve(cfg,this,"functions");
1702 if (!val)
1704 val = FUNCTIONS;
1705 rpt_vars[n].p.simple = 1;
1707 rpt_vars[n].p.functions = val;
1708 val = (char *) ast_variable_retrieve(cfg,this,"link_functions");
1709 if (val) rpt_vars[n].p.link_functions = val;
1710 else
1711 rpt_vars[n].p.link_functions = rpt_vars[n].p.functions;
1712 val = (char *) ast_variable_retrieve(cfg,this,"phone_functions");
1713 if (val) rpt_vars[n].p.phone_functions = val;
1714 val = (char *) ast_variable_retrieve(cfg,this,"dphone_functions");
1715 if (val) rpt_vars[n].p.dphone_functions = val;
1716 val = (char *) ast_variable_retrieve(cfg,this,"funcchar");
1717 if (!val) rpt_vars[n].p.funcchar = FUNCCHAR; else
1718 rpt_vars[n].p.funcchar = *val;
1719 val = (char *) ast_variable_retrieve(cfg,this,"endchar");
1720 if (!val) rpt_vars[n].p.endchar = ENDCHAR; else
1721 rpt_vars[n].p.endchar = *val;
1722 val = (char *) ast_variable_retrieve(cfg,this,"nobusyout");
1723 if (val) rpt_vars[n].p.nobusyout = ast_true(val);
1724 val = (char *) ast_variable_retrieve(cfg,this,"notelemtx");
1725 if (val) rpt_vars[n].p.notelemtx = ast_true(val);
1726 val = (char *) ast_variable_retrieve(cfg,this,"propagate_dtmf");
1727 if (val) rpt_vars[n].p.propagate_dtmf = ast_true(val);
1728 val = (char *) ast_variable_retrieve(cfg,this,"propagate_phonedtmf");
1729 if (val) rpt_vars[n].p.propagate_phonedtmf = ast_true(val);
1730 val = (char *) ast_variable_retrieve(cfg,this,"linktolink");
1731 if (val) rpt_vars[n].p.linktolink = ast_true(val);
1732 val = (char *) ast_variable_retrieve(cfg,this,"nodes");
1733 if (!val) val = NODES;
1734 rpt_vars[n].p.nodes = val;
1735 val = (char *) ast_variable_retrieve(cfg,this,"extnodes");
1736 if (!val) val = EXTNODES;
1737 rpt_vars[n].p.extnodes = val;
1738 val = (char *) ast_variable_retrieve(cfg,this,"extnodefile");
1739 if (!val) val = EXTNODEFILE;
1740 rpt_vars[n].p.extnodefile = val;
1741 val = (char *) ast_variable_retrieve(cfg,this,"archivedir");
1742 if (val) rpt_vars[n].p.archivedir = val;
1743 val = (char *) ast_variable_retrieve(cfg,this,"authlevel");
1744 if (val) rpt_vars[n].p.authlevel = atoi(val);
1745 else rpt_vars[n].p.authlevel = 0;
1746 val = (char *) ast_variable_retrieve(cfg,this,"monminblocks");
1747 if (val) rpt_vars[n].p.monminblocks = atol(val);
1748 else rpt_vars[n].p.monminblocks = DEFAULT_MONITOR_MIN_DISK_BLOCKS;
1749 val = (char *) ast_variable_retrieve(cfg,this,"remote_inact_timeout");
1750 if (val) rpt_vars[n].p.remoteinacttimeout = atoi(val);
1751 else rpt_vars[n].p.remoteinacttimeout = DEFAULT_REMOTE_INACT_TIMEOUT;
1752 val = (char *) ast_variable_retrieve(cfg,this,"civaddr");
1753 if (val) rpt_vars[n].p.civaddr = atoi(val);
1754 else rpt_vars[n].p.civaddr = DEFAULT_CIV_ADDR;
1755 val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout");
1756 if (val) rpt_vars[n].p.remotetimeout = atoi(val);
1757 else rpt_vars[n].p.remotetimeout = DEFAULT_REMOTE_TIMEOUT;
1758 val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning");
1759 if (val) rpt_vars[n].p.remotetimeoutwarning = atoi(val);
1760 else rpt_vars[n].p.remotetimeoutwarning = DEFAULT_REMOTE_TIMEOUT_WARNING;
1761 val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning_freq");
1762 if (val) rpt_vars[n].p.remotetimeoutwarningfreq = atoi(val);
1763 else rpt_vars[n].p.remotetimeoutwarningfreq = DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ;
1764 #ifdef __RPT_NOTCH
1765 val = (char *) ast_variable_retrieve(cfg,this,"rxnotch");
1766 if (val) {
1767 i = finddelim(val,strs,MAXFILTERS * 2);
1768 i &= ~1; /* force an even number, rounded down */
1769 if (i >= 2) for(j = 0; j < i; j += 2)
1771 rpt_mknotch(atof(strs[j]),atof(strs[j + 1]),
1772 &rpt_vars[n].filters[j >> 1].gain,
1773 &rpt_vars[n].filters[j >> 1].const0,
1774 &rpt_vars[n].filters[j >> 1].const1,
1775 &rpt_vars[n].filters[j >> 1].const2);
1776 sprintf(rpt_vars[n].filters[j >> 1].desc,"%s Hz, BW = %s",
1777 strs[j],strs[j + 1]);
1781 #endif
1782 val = (char *) ast_variable_retrieve(cfg,this,"inxlat");
1783 if (val) {
1784 memset(&rpt_vars[n].p.inxlat,0,sizeof(struct rpt_xlat));
1785 i = finddelim(val,strs,3);
1786 if (i) strncpy(rpt_vars[n].p.inxlat.funccharseq,strs[0],MAXXLAT - 1);
1787 if (i > 1) strncpy(rpt_vars[n].p.inxlat.endcharseq,strs[1],MAXXLAT - 1);
1788 if (i > 2) strncpy(rpt_vars[n].p.inxlat.passchars,strs[2],MAXXLAT - 1);
1790 val = (char *) ast_variable_retrieve(cfg,this,"outxlat");
1791 if (val) {
1792 memset(&rpt_vars[n].p.outxlat,0,sizeof(struct rpt_xlat));
1793 i = finddelim(val,strs,3);
1794 if (i) strncpy(rpt_vars[n].p.outxlat.funccharseq,strs[0],MAXXLAT - 1);
1795 if (i > 1) strncpy(rpt_vars[n].p.outxlat.endcharseq,strs[1],MAXXLAT - 1);
1796 if (i > 2) strncpy(rpt_vars[n].p.outxlat.passchars,strs[2],MAXXLAT - 1);
1798 /* retreive the stanza name for the control states if there is one */
1799 val = (char *) ast_variable_retrieve(cfg,this,"controlstates");
1800 rpt_vars[n].p.csstanzaname = val;
1802 /* retreive the stanza name for the scheduler if there is one */
1803 val = (char *) ast_variable_retrieve(cfg,this,"scheduler");
1804 rpt_vars[n].p.skedstanzaname = val;
1806 /* retreive the stanza name for the txlimits */
1807 val = (char *) ast_variable_retrieve(cfg,this,"txlimits");
1808 rpt_vars[n].p.txlimitsstanzaname = val;
1810 longestnode = 0;
1812 vp = ast_variable_browse(cfg, rpt_vars[n].p.nodes);
1814 while(vp){
1815 j = strlen(vp->name);
1816 if (j > longestnode)
1817 longestnode = j;
1818 vp = vp->next;
1821 rpt_vars[n].longestnode = longestnode;
1824 * For this repeater, Determine the length of the longest function
1826 rpt_vars[n].longestfunc = 0;
1827 vp = ast_variable_browse(cfg, rpt_vars[n].p.functions);
1828 while(vp){
1829 j = strlen(vp->name);
1830 if (j > rpt_vars[n].longestfunc)
1831 rpt_vars[n].longestfunc = j;
1832 vp = vp->next;
1835 * For this repeater, Determine the length of the longest function
1837 rpt_vars[n].link_longestfunc = 0;
1838 vp = ast_variable_browse(cfg, rpt_vars[n].p.link_functions);
1839 while(vp){
1840 j = strlen(vp->name);
1841 if (j > rpt_vars[n].link_longestfunc)
1842 rpt_vars[n].link_longestfunc = j;
1843 vp = vp->next;
1845 rpt_vars[n].phone_longestfunc = 0;
1846 if (rpt_vars[n].p.phone_functions)
1848 vp = ast_variable_browse(cfg, rpt_vars[n].p.phone_functions);
1849 while(vp){
1850 j = strlen(vp->name);
1851 if (j > rpt_vars[n].phone_longestfunc)
1852 rpt_vars[n].phone_longestfunc = j;
1853 vp = vp->next;
1856 rpt_vars[n].dphone_longestfunc = 0;
1857 if (rpt_vars[n].p.dphone_functions)
1859 vp = ast_variable_browse(cfg, rpt_vars[n].p.dphone_functions);
1860 while(vp){
1861 j = strlen(vp->name);
1862 if (j > rpt_vars[n].dphone_longestfunc)
1863 rpt_vars[n].dphone_longestfunc = j;
1864 vp = vp->next;
1867 rpt_vars[n].macro_longest = 1;
1868 vp = ast_variable_browse(cfg, rpt_vars[n].p.macro);
1869 while(vp){
1870 j = strlen(vp->name);
1871 if (j > rpt_vars[n].macro_longest)
1872 rpt_vars[n].macro_longest = j;
1873 vp = vp->next;
1876 /* Browse for control states */
1877 if(rpt_vars[n].p.csstanzaname)
1878 vp = ast_variable_browse(cfg, rpt_vars[n].p.csstanzaname);
1879 else
1880 vp = NULL;
1881 for( i = 0 ; vp && (i < MAX_SYSSTATES) ; i++){ /* Iterate over the number of control state lines in the stanza */
1882 int k,nukw,statenum;
1883 statenum=atoi(vp->name);
1884 strncpy(s1, vp->value, 255);
1885 s1[255] = 0;
1886 nukw = finddelim(s1,strs,32);
1888 for (k = 0 ; k < nukw ; k++){ /* for each user specified keyword */
1889 for(j = 0 ; cs_keywords[j] != NULL ; j++){ /* try to match to one in our internal table */
1890 if(!strcmp(strs[k],cs_keywords[j])){
1891 switch(j){
1892 case 0: /* rptena */
1893 rpt_vars[n].p.s[statenum].txdisable = 0;
1894 break;
1895 case 1: /* rptdis */
1896 rpt_vars[n].p.s[statenum].txdisable = 1;
1897 break;
1899 case 2: /* apena */
1900 rpt_vars[n].p.s[statenum].autopatchdisable = 0;
1901 break;
1903 case 3: /* apdis */
1904 rpt_vars[n].p.s[statenum].autopatchdisable = 1;
1905 break;
1907 case 4: /* lnkena */
1908 rpt_vars[n].p.s[statenum].linkfundisable = 0;
1909 break;
1911 case 5: /* lnkdis */
1912 rpt_vars[n].p.s[statenum].linkfundisable = 1;
1913 break;
1915 case 6: /* totena */
1916 rpt_vars[n].p.s[statenum].totdisable = 0;
1917 break;
1919 case 7: /* totdis */
1920 rpt_vars[n].p.s[statenum].totdisable = 1;
1921 break;
1923 case 8: /* skena */
1924 rpt_vars[n].p.s[statenum].schedulerdisable = 0;
1925 break;
1927 case 9: /* skdis */
1928 rpt_vars[n].p.s[statenum].schedulerdisable = 1;
1929 break;
1931 case 10: /* ufena */
1932 rpt_vars[n].p.s[statenum].userfundisable = 0;
1933 break;
1935 case 11: /* ufdis */
1936 rpt_vars[n].p.s[statenum].userfundisable = 1;
1937 break;
1939 case 12: /* atena */
1940 rpt_vars[n].p.s[statenum].alternatetail = 1;
1941 break;
1943 case 13: /* atdis */
1944 rpt_vars[n].p.s[statenum].alternatetail = 0;
1945 break;
1947 default:
1948 ast_log(LOG_WARNING,
1949 "Unhandled control state keyword %s", cs_keywords[i]);
1950 break;
1955 vp = vp->next;
1957 ast_mutex_unlock(&rpt_vars[n].lock);
1961 * Enable or disable debug output at a given level at the console
1964 static int rpt_do_debug(int fd, int argc, char *argv[])
1966 int newlevel;
1968 if (argc != 4)
1969 return RESULT_SHOWUSAGE;
1970 newlevel = myatoi(argv[3]);
1971 if((newlevel < 0) || (newlevel > 7))
1972 return RESULT_SHOWUSAGE;
1973 if(newlevel)
1974 ast_cli(fd, "app_rpt Debugging enabled, previous level: %d, new level: %d\n", debug, newlevel);
1975 else
1976 ast_cli(fd, "app_rpt Debugging disabled\n");
1978 debug = newlevel;
1979 return RESULT_SUCCESS;
1983 * Dump rpt struct debugging onto console
1986 static int rpt_do_dump(int fd, int argc, char *argv[])
1988 int i;
1990 if (argc != 3)
1991 return RESULT_SHOWUSAGE;
1993 for(i = 0; i < nrpts; i++)
1995 if (!strcmp(argv[2],rpt_vars[i].name))
1997 rpt_vars[i].disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
1998 ast_cli(fd, "app_rpt struct dump requested for node %s\n",argv[2]);
1999 return RESULT_SUCCESS;
2002 return RESULT_FAILURE;
2006 * Dump statistics onto console
2009 static int rpt_do_stats(int fd, int argc, char *argv[])
2011 int i,j;
2012 int dailytxtime, dailykerchunks;
2013 int totalkerchunks, dailykeyups, totalkeyups, timeouts;
2014 int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
2015 long long totaltxtime;
2016 struct rpt_link *l;
2017 char *listoflinks[MAX_STAT_LINKS];
2018 char *lastnodewhichkeyedusup, *lastdtmfcommand;
2019 char *tot_state, *ider_state, *patch_state;
2020 char *reverse_patch_state, *sys_ena, *tot_ena, *link_ena, *patch_ena;
2021 char *sch_ena, *input_signal, *called_number, *user_funs, *tail_type;
2022 struct rpt *myrpt;
2024 static char *not_applicable = "N/A";
2026 if(argc != 3)
2027 return RESULT_SHOWUSAGE;
2029 for(i = 0 ; i < MAX_STAT_LINKS; i++)
2030 listoflinks[i] = NULL;
2032 tot_state = ider_state =
2033 patch_state = reverse_patch_state =
2034 input_signal = called_number =
2035 lastdtmfcommand = not_applicable;
2037 for(i = 0; i < nrpts; i++)
2039 if (!strcmp(argv[2],rpt_vars[i].name)){
2040 /* Make a copy of all stat variables while locked */
2041 myrpt = &rpt_vars[i];
2042 rpt_mutex_lock(&myrpt->lock); /* LOCK */
2044 dailytxtime = myrpt->dailytxtime;
2045 totaltxtime = myrpt->totaltxtime;
2046 dailykeyups = myrpt->dailykeyups;
2047 totalkeyups = myrpt->totalkeyups;
2048 dailykerchunks = myrpt->dailykerchunks;
2049 totalkerchunks = myrpt->totalkerchunks;
2050 dailyexecdcommands = myrpt->dailyexecdcommands;
2051 totalexecdcommands = myrpt->totalexecdcommands;
2052 timeouts = myrpt->timeouts;
2054 /* Traverse the list of connected nodes */
2055 reverse_patch_state = "DOWN";
2056 j = 0;
2057 l = myrpt->links.next;
2058 while(l && (l != &myrpt->links)){
2059 if (l->name[0] == '0'){ /* Skip '0' nodes */
2060 reverse_patch_state = "UP";
2061 l = l->next;
2062 continue;
2064 listoflinks[j] = ast_strdupa(l->name);
2065 if(listoflinks[j])
2066 j++;
2067 l = l->next;
2070 lastnodewhichkeyedusup = ast_strdupa(myrpt->lastnodewhichkeyedusup);
2071 if((!lastnodewhichkeyedusup) || (!strlen(lastnodewhichkeyedusup)))
2072 lastnodewhichkeyedusup = not_applicable;
2074 if(myrpt->keyed)
2075 input_signal = "YES";
2076 else
2077 input_signal = "NO";
2079 if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable)
2080 sys_ena = "DISABLED";
2081 else
2082 sys_ena = "ENABLED";
2084 if(myrpt->p.s[myrpt->p.sysstate_cur].totdisable)
2085 tot_ena = "DISABLED";
2086 else
2087 tot_ena = "ENABLED";
2089 if(myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable)
2090 link_ena = "DISABLED";
2091 else
2092 link_ena = "ENABLED";
2094 if(myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
2095 patch_ena = "DISABLED";
2096 else
2097 patch_ena = "ENABLED";
2099 if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable)
2100 sch_ena = "DISABLED";
2101 else
2102 sch_ena = "ENABLED";
2104 if(myrpt->p.s[myrpt->p.sysstate_cur].userfundisable)
2105 user_funs = "DISABLED";
2106 else
2107 user_funs = "ENABLED";
2109 if(myrpt->p.s[myrpt->p.sysstate_cur].alternatetail)
2110 tail_type = "ALTERNATE";
2111 else
2112 tail_type = "STANDARD";
2114 if(!myrpt->totimer)
2115 tot_state = "TIMED OUT!";
2116 else if(myrpt->totimer != myrpt->p.totime)
2117 tot_state = "ARMED";
2118 else
2119 tot_state = "RESET";
2121 if(myrpt->tailid)
2122 ider_state = "QUEUED IN TAIL";
2123 else if(myrpt->mustid)
2124 ider_state = "QUEUED FOR CLEANUP";
2125 else
2126 ider_state = "CLEAN";
2128 switch(myrpt->callmode){
2129 case 1:
2130 patch_state = "DIALING";
2131 break;
2132 case 2:
2133 patch_state = "CONNECTING";
2134 break;
2135 case 3:
2136 patch_state = "UP";
2137 break;
2139 case 4:
2140 patch_state = "CALL FAILED";
2141 break;
2143 default:
2144 patch_state = "DOWN";
2147 if(strlen(myrpt->exten)){
2148 called_number = ast_strdupa(myrpt->exten);
2149 if(!called_number)
2150 called_number = not_applicable;
2153 if(strlen(myrpt->lastdtmfcommand)){
2154 lastdtmfcommand = ast_strdupa(myrpt->lastdtmfcommand);
2155 if(!lastdtmfcommand)
2156 lastdtmfcommand = not_applicable;
2159 rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
2161 ast_cli(fd, "************************ NODE %s STATISTICS *************************\n\n", myrpt->name);
2162 ast_cli(fd, "Selected system state............................: %d\n", myrpt->p.sysstate_cur);
2163 ast_cli(fd, "Signal on input..................................: %s\n", input_signal);
2164 ast_cli(fd, "System...........................................: %s\n", sys_ena);
2165 ast_cli(fd, "Scheduler........................................: %s\n", sch_ena);
2166 ast_cli(fd, "Tail Time........................................: %s\n", tail_type);
2167 ast_cli(fd, "Time out timer...................................: %s\n", tot_ena);
2168 ast_cli(fd, "Time out timer state.............................: %s\n", tot_state);
2169 ast_cli(fd, "Time outs since system initialization............: %d\n", timeouts);
2170 ast_cli(fd, "Identifier state.................................: %s\n", ider_state);
2171 ast_cli(fd, "Kerchunks today..................................: %d\n", dailykerchunks);
2172 ast_cli(fd, "Kerchunks since system initialization............: %d\n", totalkerchunks);
2173 ast_cli(fd, "Keyups today.....................................: %d\n", dailykeyups);
2174 ast_cli(fd, "Keyups since system initialization...............: %d\n", totalkeyups);
2175 ast_cli(fd, "DTMF commands today..............................: %d\n", dailyexecdcommands);
2176 ast_cli(fd, "DTMF commands since system initialization........: %d\n", totalexecdcommands);
2177 ast_cli(fd, "Last DTMF command executed.......................: %s\n", lastdtmfcommand);
2178 hours = dailytxtime/3600000;
2179 dailytxtime %= 3600000;
2180 minutes = dailytxtime/60000;
2181 dailytxtime %= 60000;
2182 seconds = dailytxtime/1000;
2183 dailytxtime %= 1000;
2185 ast_cli(fd, "TX time today ...................................: %02d:%02d:%02d.%d\n",
2186 hours, minutes, seconds, dailytxtime);
2188 hours = (int) totaltxtime/3600000;
2189 totaltxtime %= 3600000;
2190 minutes = (int) totaltxtime/60000;
2191 totaltxtime %= 60000;
2192 seconds = (int) totaltxtime/1000;
2193 totaltxtime %= 1000;
2195 ast_cli(fd, "TX time since system initialization..............: %02d:%02d:%02d.%d\n",
2196 hours, minutes, seconds, (int) totaltxtime);
2197 ast_cli(fd, "Nodes currently connected to us..................: ");
2198 for(j = 0 ;; j++){
2199 if(!listoflinks[j]){
2200 if(!j){
2201 ast_cli(fd,"<NONE>");
2203 break;
2205 ast_cli(fd, "%s", listoflinks[j]);
2206 if(j % 4 == 3){
2207 ast_cli(fd, "\n");
2208 ast_cli(fd, " : ");
2210 else{
2211 if(listoflinks[j + 1])
2212 ast_cli(fd, ", ");
2215 ast_cli(fd,"\n");
2217 ast_cli(fd, "Last node which transmitted to us................: %s\n", lastnodewhichkeyedusup);
2218 ast_cli(fd, "Autopatch........................................: %s\n", patch_ena);
2219 ast_cli(fd, "Autopatch state..................................: %s\n", patch_state);
2220 ast_cli(fd, "Autopatch called number..........................: %s\n", called_number);
2221 ast_cli(fd, "Reverse patch/IAXRPT connected...................: %s\n", reverse_patch_state);
2222 ast_cli(fd, "User linking commands............................: %s\n", link_ena);
2223 ast_cli(fd, "User functions...................................: %s\n\n", user_funs);
2224 return RESULT_SUCCESS;
2227 return RESULT_FAILURE;
2231 * Link stats function
2234 static int rpt_do_lstats(int fd, int argc, char *argv[])
2236 int i,j;
2237 char *connstate;
2238 struct rpt *myrpt;
2239 struct rpt_link *l;
2240 struct rpt_lstat *s,*t;
2241 struct rpt_lstat s_head;
2242 if(argc != 3)
2243 return RESULT_SHOWUSAGE;
2245 s = NULL;
2246 s_head.next = &s_head;
2247 s_head.prev = &s_head;
2249 for(i = 0; i < nrpts; i++)
2251 if (!strcmp(argv[2],rpt_vars[i].name)){
2252 /* Make a copy of all stat variables while locked */
2253 myrpt = &rpt_vars[i];
2254 rpt_mutex_lock(&myrpt->lock); /* LOCK */
2255 /* Traverse the list of connected nodes */
2256 j = 0;
2257 l = myrpt->links.next;
2258 while(l && (l != &myrpt->links)){
2259 if (l->name[0] == '0'){ /* Skip '0' nodes */
2260 l = l->next;
2261 continue;
2263 if((s = (struct rpt_lstat *) malloc(sizeof(struct rpt_lstat))) == NULL){
2264 ast_log(LOG_ERROR, "Malloc failed in rpt_do_lstats\n");
2265 rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
2266 return RESULT_FAILURE;
2268 memset(s, 0, sizeof(struct rpt_lstat));
2269 strncpy(s->name, l->name, MAXREMSTR - 1);
2270 if (l->chan) pbx_substitute_variables_helper(l->chan, "${IAXPEER(CURRENTCHANNEL)}", s->peer, MAXPEERSTR - 1);
2271 else strcpy(s->peer,"(none)");
2272 s->mode = l->mode;
2273 s->outbound = l->outbound;
2274 s->reconnects = l->reconnects;
2275 s->connecttime = l->connecttime;
2276 s->thisconnected = l->thisconnected;
2277 memcpy(s->chan_stat,l->chan_stat,NRPTSTAT * sizeof(struct rpt_chan_stat));
2278 insque((struct qelem *) s, (struct qelem *) s_head.next);
2279 memset(l->chan_stat,0,NRPTSTAT * sizeof(struct rpt_chan_stat));
2280 l = l->next;
2282 rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
2283 ast_cli(fd, "NODE PEER RECONNECTS DIRECTION CONNECT TIME CONNECT STATE\n");
2284 ast_cli(fd, "---- ---- ---------- --------- ------------ -------------\n");
2286 for(s = s_head.next; s != &s_head; s = s->next){
2287 int hours, minutes, seconds;
2288 long long connecttime = s->connecttime;
2289 char conntime[21];
2290 hours = (int) connecttime/3600000;
2291 connecttime %= 3600000;
2292 minutes = (int) connecttime/60000;
2293 connecttime %= 60000;
2294 seconds = (int) connecttime/1000;
2295 connecttime %= 1000;
2296 snprintf(conntime, 20, "%02d:%02d:%02d.%d",
2297 hours, minutes, seconds, (int) connecttime);
2298 conntime[20] = 0;
2299 if(s->thisconnected)
2300 connstate = "ESTABLISHED";
2301 else
2302 connstate = "CONNECTING";
2303 ast_cli(fd, "%-10s%-20s%-12d%-11s%-20s%-20s\n",
2304 s->name, s->peer, s->reconnects, (s->outbound)? "OUT":"IN", conntime, connstate);
2306 /* destroy our local link queue */
2307 s = s_head.next;
2308 while(s != &s_head){
2309 t = s;
2310 s = s->next;
2311 remque((struct qelem *)t);
2312 free(t);
2314 return RESULT_SUCCESS;
2317 return RESULT_FAILURE;
2321 * List all nodes connected, directly or indirectly
2324 static int rpt_do_nodes(int fd, int argc, char *argv[])
2326 int i,j;
2327 char ns;
2328 char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
2329 struct rpt *myrpt;
2330 if(argc != 3)
2331 return RESULT_SHOWUSAGE;
2333 for(i = 0; i < nrpts; i++)
2335 if (!strcmp(argv[2],rpt_vars[i].name)){
2336 /* Make a copy of all stat variables while locked */
2337 myrpt = &rpt_vars[i];
2338 rpt_mutex_lock(&myrpt->lock); /* LOCK */
2339 __mklinklist(myrpt,NULL,lbuf);
2340 rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
2341 /* parse em */
2342 ns = finddelim(lbuf,strs,MAXLINKLIST);
2343 /* sort em */
2344 if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar);
2345 ast_cli(fd,"\n");
2346 ast_cli(fd, "************************* CONNECTED NODES *************************\n\n");
2347 for(j = 0 ;; j++){
2348 if(!strs[j]){
2349 if(!j){
2350 ast_cli(fd,"<NONE>");
2352 break;
2354 ast_cli(fd, "%s", strs[j]);
2355 if(j % 8 == 7){
2356 ast_cli(fd, "\n");
2358 else{
2359 if(strs[j + 1])
2360 ast_cli(fd, ", ");
2363 ast_cli(fd,"\n\n");
2364 return RESULT_SUCCESS;
2367 return RESULT_FAILURE;
2371 * reload vars
2374 static int rpt_do_reload(int fd, int argc, char *argv[])
2376 int n;
2378 if (argc > 2) return RESULT_SHOWUSAGE;
2380 for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
2382 return RESULT_FAILURE;
2386 * restart app_rpt
2389 static int rpt_do_restart(int fd, int argc, char *argv[])
2391 int i;
2393 if (argc > 2) return RESULT_SHOWUSAGE;
2394 for(i = 0; i < nrpts; i++)
2396 if (rpt_vars[i].rxchannel) ast_softhangup(rpt_vars[i].rxchannel,AST_SOFTHANGUP_DEV);
2398 return RESULT_FAILURE;
2403 * send an app_rpt DTMF function from the CLI
2406 static int rpt_do_fun(int fd, int argc, char *argv[])
2408 int i,busy=0;
2410 if (argc != 4) return RESULT_SHOWUSAGE;
2412 for(i = 0; i < nrpts; i++){
2413 if(!strcmp(argv[2], rpt_vars[i].name)){
2414 struct rpt *myrpt = &rpt_vars[i];
2415 rpt_mutex_lock(&myrpt->lock);
2416 if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(argv[3])){
2417 rpt_mutex_unlock(&myrpt->lock);
2418 busy=1;
2420 if(!busy){
2421 myrpt->macrotimer = MACROTIME;
2422 strncat(myrpt->macrobuf, argv[3], MAXMACRO - strlen(myrpt->macrobuf) - 1);
2424 rpt_mutex_unlock(&myrpt->lock);
2427 if(busy){
2428 ast_cli(fd, "Function decoder busy");
2430 return RESULT_FAILURE;
2435 static int play_tone_pair(struct ast_channel *chan, int f1, int f2, int duration, int amplitude)
2437 int res;
2439 if ((res = ast_tonepair_start(chan, f1, f2, duration, amplitude)))
2440 return res;
2442 while(chan->generatordata) {
2443 if (ast_safe_sleep(chan,1)) return -1;
2446 return 0;
2449 static int play_tone(struct ast_channel *chan, int freq, int duration, int amplitude)
2451 return play_tone_pair(chan, freq, 0, duration, amplitude);
2454 static int play_silence(struct ast_channel *chan, int duration)
2456 return play_tone_pair(chan, 0, 0, duration, 0);
2460 static int send_morse(struct ast_channel *chan, char *string, int speed, int freq, int amplitude)
2463 static struct morse_bits mbits[] = {
2464 {0, 0}, /* SPACE */
2465 {0, 0},
2466 {6, 18},/* " */
2467 {0, 0},
2468 {7, 72},/* $ */
2469 {0, 0},
2470 {0, 0},
2471 {6, 30},/* ' */
2472 {5, 13},/* ( */
2473 {6, 29},/* ) */
2474 {0, 0},
2475 {5, 10},/* + */
2476 {6, 51},/* , */
2477 {6, 33},/* - */
2478 {6, 42},/* . */
2479 {5, 9}, /* / */
2480 {5, 31},/* 0 */
2481 {5, 30},/* 1 */
2482 {5, 28},/* 2 */
2483 {5, 24},/* 3 */
2484 {5, 16},/* 4 */
2485 {5, 0}, /* 5 */
2486 {5, 1}, /* 6 */
2487 {5, 3}, /* 7 */
2488 {5, 7}, /* 8 */
2489 {5, 15},/* 9 */
2490 {6, 7}, /* : */
2491 {6, 21},/* ; */
2492 {0, 0},
2493 {5, 33},/* = */
2494 {0, 0},
2495 {6, 12},/* ? */
2496 {0, 0},
2497 {2, 2}, /* A */
2498 {4, 1}, /* B */
2499 {4, 5}, /* C */
2500 {3, 1}, /* D */
2501 {1, 0}, /* E */
2502 {4, 4}, /* F */
2503 {3, 3}, /* G */
2504 {4, 0}, /* H */
2505 {2, 0}, /* I */
2506 {4, 14},/* J */
2507 {3, 5}, /* K */
2508 {4, 2}, /* L */
2509 {2, 3}, /* M */
2510 {2, 1}, /* N */
2511 {3, 7}, /* O */
2512 {4, 6}, /* P */
2513 {4, 11},/* Q */
2514 {3, 2}, /* R */
2515 {3, 0}, /* S */
2516 {1, 1}, /* T */
2517 {3, 4}, /* U */
2518 {4, 8}, /* V */
2519 {3, 6}, /* W */
2520 {4, 9}, /* X */
2521 {4, 13},/* Y */
2522 {4, 3} /* Z */
2526 int dottime;
2527 int dashtime;
2528 int intralettertime;
2529 int interlettertime;
2530 int interwordtime;
2531 int len, ddcomb;
2532 int res;
2533 int c;
2534 int i;
2535 int flags;
2537 res = 0;
2539 /* Approximate the dot time from the speed arg. */
2541 dottime = 900/speed;
2543 /* Establish timing releationships */
2545 dashtime = 3 * dottime;
2546 intralettertime = dottime;
2547 interlettertime = dottime * 4 ;
2548 interwordtime = dottime * 7;
2550 for(;(*string) && (!res); string++){
2552 c = *string;
2554 /* Convert lower case to upper case */
2556 if((c >= 'a') && (c <= 'z'))
2557 c -= 0x20;
2559 /* Can't deal with any char code greater than Z, skip it */
2561 if(c > 'Z')
2562 continue;
2564 /* If space char, wait the inter word time */
2566 if(c == ' '){
2567 if(!res)
2568 res = play_silence(chan, interwordtime);
2569 continue;
2572 /* Subtract out control char offset to match our table */
2574 c -= 0x20;
2576 /* Get the character data */
2578 len = mbits[c].len;
2579 ddcomb = mbits[c].ddcomb;
2581 /* Send the character */
2583 for(; len ; len--){
2584 if(!res)
2585 res = play_tone(chan, freq, (ddcomb & 1) ? dashtime : dottime, amplitude);
2586 if(!res)
2587 res = play_silence(chan, intralettertime);
2588 ddcomb >>= 1;
2591 /* Wait the interletter time */
2593 if(!res)
2594 res = play_silence(chan, interlettertime - intralettertime);
2597 /* Wait for all the frames to be sent */
2599 if (!res)
2600 res = ast_waitstream(chan, "");
2601 ast_stopstream(chan);
2604 * Wait for the zaptel driver to physically write the tone blocks to the hardware
2607 for(i = 0; i < 20 ; i++){
2608 flags = DAHDI_IOMUX_WRITEEMPTY | DAHDI_IOMUX_NOWAIT;
2609 res = ioctl(chan->fds[0], DAHDI_IOMUX, &flags);
2610 if(flags & DAHDI_IOMUX_WRITEEMPTY)
2611 break;
2612 if( ast_safe_sleep(chan, 50)){
2613 res = -1;
2614 break;
2619 return res;
2622 static int send_tone_telemetry(struct ast_channel *chan, char *tonestring)
2624 char *stringp;
2625 char *tonesubset;
2626 int f1,f2;
2627 int duration;
2628 int amplitude;
2629 int res;
2630 int i;
2631 int flags;
2633 res = 0;
2635 stringp = ast_strdupa(tonestring);
2637 for(;tonestring;){
2638 tonesubset = strsep(&stringp,")");
2639 if(!tonesubset)
2640 break;
2641 if(sscanf(tonesubset,"(%d,%d,%d,%d", &f1, &f2, &duration, &amplitude) != 4)
2642 break;
2643 res = play_tone_pair(chan, f1, f2, duration, amplitude);
2644 if(res)
2645 break;
2647 if(!res)
2648 res = play_tone_pair(chan, 0, 0, 100, 0); /* This is needed to ensure the last tone segment is timed correctly */
2650 if (!res)
2651 res = ast_waitstream(chan, "");
2652 ast_stopstream(chan);
2655 * Wait for the zaptel driver to physically write the tone blocks to the hardware
2658 for(i = 0; i < 20 ; i++){
2659 flags = DAHDI_IOMUX_WRITEEMPTY | DAHDI_IOMUX_NOWAIT;
2660 res = ioctl(chan->fds[0], DAHDI_IOMUX, &flags);
2661 if(flags & DAHDI_IOMUX_WRITEEMPTY)
2662 break;
2663 if( ast_safe_sleep(chan, 50)){
2664 res = -1;
2665 break;
2669 return res;
2673 static int sayfile(struct ast_channel *mychannel,char *fname)
2675 int res;
2677 res = ast_streamfile(mychannel, fname, mychannel->language);
2678 if (!res)
2679 res = ast_waitstream(mychannel, "");
2680 else
2681 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2682 ast_stopstream(mychannel);
2683 return res;
2686 static int saycharstr(struct ast_channel *mychannel,char *str)
2688 int res;
2690 res = ast_say_character_str(mychannel,str,NULL,mychannel->language);
2691 if (!res)
2692 res = ast_waitstream(mychannel, "");
2693 else
2694 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2695 ast_stopstream(mychannel);
2696 return res;
2699 static int saynum(struct ast_channel *mychannel, int num)
2701 int res;
2702 res = ast_say_number(mychannel, num, NULL, mychannel->language, NULL);
2703 if(!res)
2704 res = ast_waitstream(mychannel, "");
2705 else
2706 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2707 ast_stopstream(mychannel);
2708 return res;
2712 static int telem_any(struct rpt *myrpt,struct ast_channel *chan, char *entry)
2714 int res;
2715 char c;
2717 static int morsespeed;
2718 static int morsefreq;
2719 static int morseampl;
2720 static int morseidfreq = 0;
2721 static int morseidampl;
2722 static char mcat[] = MORSE;
2724 res = 0;
2726 if(!morseidfreq){ /* Get the morse parameters if not already loaded */
2727 morsespeed = retrieve_astcfgint(myrpt, mcat, "speed", 5, 20, 20);
2728 morsefreq = retrieve_astcfgint(myrpt, mcat, "frequency", 300, 3000, 800);
2729 morseampl = retrieve_astcfgint(myrpt, mcat, "amplitude", 200, 8192, 4096);
2730 morseidampl = retrieve_astcfgint(myrpt, mcat, "idamplitude", 200, 8192, 2048);
2731 morseidfreq = retrieve_astcfgint(myrpt, mcat, "idfrequency", 300, 3000, 330);
2734 /* Is it a file, or a tone sequence? */
2736 if(entry[0] == '|'){
2737 c = entry[1];
2738 if((c >= 'a')&&(c <= 'z'))
2739 c -= 0x20;
2741 switch(c){
2742 case 'I': /* Morse ID */
2743 res = send_morse(chan, entry + 2, morsespeed, morseidfreq, morseidampl);
2744 break;
2746 case 'M': /* Morse Message */
2747 res = send_morse(chan, entry + 2, morsespeed, morsefreq, morseampl);
2748 break;
2750 case 'T': /* Tone sequence */
2751 res = send_tone_telemetry(chan, entry + 2);
2752 break;
2753 default:
2754 res = -1;
2757 else
2758 res = sayfile(chan, entry); /* File */
2759 return res;
2763 * This function looks up a telemetry name in the config file, and does a telemetry response as configured.
2765 * 4 types of telemtry are handled: Morse ID, Morse Message, Tone Sequence, and a File containing a recording.
2768 static int telem_lookup(struct rpt *myrpt,struct ast_channel *chan, char *node, char *name)
2771 int res;
2772 int i;
2773 char *entry;
2774 char *telemetry;
2775 char *telemetry_save;
2777 res = 0;
2778 telemetry_save = NULL;
2779 entry = NULL;
2781 /* Retrieve the section name for telemetry from the node section */
2782 telemetry = (char *) ast_variable_retrieve(myrpt->cfg, node, TELEMETRY);
2783 if(telemetry ){
2784 telemetry_save = ast_strdupa(telemetry);
2785 if(!telemetry_save){
2786 ast_log(LOG_WARNING,"ast_strdupa() failed in telem_lookup()\n");
2787 return res;
2789 entry = (char *) ast_variable_retrieve(myrpt->cfg, telemetry_save, name);
2792 /* Try to look up the telemetry name */
2794 if(!entry){
2795 /* Telemetry name wasn't found in the config file, use the default */
2796 for(i = 0; i < sizeof(tele_defs)/sizeof(struct telem_defaults) ; i++){
2797 if(!strcasecmp(tele_defs[i].name, name))
2798 entry = tele_defs[i].value;
2801 if(entry){
2802 if(strlen(entry))
2803 telem_any(myrpt,chan, entry);
2805 else{
2806 res = -1;
2808 return res;
2812 * Retrieve a wait interval
2815 static int get_wait_interval(struct rpt *myrpt, int type)
2817 int interval;
2818 char *wait_times;
2819 char *wait_times_save;
2821 wait_times_save = NULL;
2822 wait_times = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "wait_times");
2824 if(wait_times){
2825 wait_times_save = ast_strdupa(wait_times);
2826 if(!wait_times_save){
2827 ast_log(LOG_WARNING, "Out of memory in wait_interval()\n");
2828 wait_times = NULL;
2832 switch(type){
2833 case DLY_TELEM:
2834 if(wait_times)
2835 interval = retrieve_astcfgint(myrpt,wait_times_save, "telemwait", 500, 5000, 1000);
2836 else
2837 interval = 1000;
2838 break;
2840 case DLY_ID:
2841 if(wait_times)
2842 interval = retrieve_astcfgint(myrpt,wait_times_save, "idwait",250,5000,500);
2843 else
2844 interval = 500;
2845 break;
2847 case DLY_UNKEY:
2848 if(wait_times)
2849 interval = retrieve_astcfgint(myrpt,wait_times_save, "unkeywait",500,5000,1000);
2850 else
2851 interval = 1000;
2852 break;
2854 case DLY_LINKUNKEY:
2855 if(wait_times)
2856 interval = retrieve_astcfgint(myrpt,wait_times_save, "linkunkeywait",500,5000,1000);
2857 else
2858 interval = 1000;
2859 break;
2861 case DLY_CALLTERM:
2862 if(wait_times)
2863 interval = retrieve_astcfgint(myrpt,wait_times_save, "calltermwait",500,5000,1500);
2864 else
2865 interval = 1500;
2866 break;
2868 case DLY_COMP:
2869 if(wait_times)
2870 interval = retrieve_astcfgint(myrpt,wait_times_save, "compwait",500,5000,200);
2871 else
2872 interval = 200;
2873 break;
2875 default:
2876 return 0;
2878 return interval;
2883 * Wait a configurable interval of time
2887 static void wait_interval(struct rpt *myrpt, int type, struct ast_channel *chan)
2889 int interval;
2890 interval = get_wait_interval(myrpt, type);
2891 if(debug)
2892 ast_log(LOG_NOTICE," Delay interval = %d\n", interval);
2893 if(interval)
2894 ast_safe_sleep(chan,interval);
2895 if(debug)
2896 ast_log(LOG_NOTICE,"Delay complete\n");
2897 return;
2900 static int split_freq(char *mhz, char *decimals, char *freq);
2902 static void *rpt_tele_thread(void *this)
2904 struct dahdi_confinfo ci; /* conference info */
2905 int res = 0,haslink,hastx,hasremote,imdone = 0, unkeys_queued, x;
2906 struct rpt_tele *mytele = (struct rpt_tele *)this;
2907 struct rpt_tele *tlist;
2908 struct rpt *myrpt;
2909 struct rpt_link *l,*l1,linkbase;
2910 struct ast_channel *mychannel;
2911 int vmajor, vminor, m;
2912 char *p,*ct,*ct_copy,*ident, *nodename,*cp;
2913 time_t t;
2914 struct tm localtm;
2915 char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
2916 int i,ns,rbimode;
2917 char mhz[MAXREMSTR];
2918 char decimals[MAXREMSTR];
2919 struct dahdi_params par;
2922 /* get a pointer to myrpt */
2923 myrpt = mytele->rpt;
2925 /* Snag copies of a few key myrpt variables */
2926 rpt_mutex_lock(&myrpt->lock);
2927 nodename = ast_strdupa(myrpt->name);
2928 if (myrpt->p.ident) ident = ast_strdupa(myrpt->p.ident);
2929 else ident = "";
2930 rpt_mutex_unlock(&myrpt->lock);
2932 /* allocate a pseudo-channel thru asterisk */
2933 mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
2934 if (!mychannel)
2936 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
2937 rpt_mutex_lock(&myrpt->lock);
2938 remque((struct qelem *)mytele);
2939 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
2940 rpt_mutex_unlock(&myrpt->lock);
2941 free(mytele);
2942 pthread_exit(NULL);
2944 #ifdef AST_CDR_FLAG_POST_DISABLED
2945 ast_set_flag(mychannel->cdr,AST_CDR_FLAG_POST_DISABLED);
2946 #endif
2947 rpt_mutex_lock(&myrpt->lock);
2948 mytele->chan = mychannel;
2949 rpt_mutex_unlock(&myrpt->lock);
2950 /* make a conference for the tx */
2951 ci.chan = 0;
2952 /* If there's an ID queued, or tail message queued, */
2953 /* only connect the ID audio to the local tx conference so */
2954 /* linked systems can't hear it */
2955 ci.confno = (((mytele->mode == ID) || (mytele->mode == IDTALKOVER) || (mytele->mode == UNKEY) ||
2956 (mytele->mode == TAILMSG) || (mytele->mode == LINKUNKEY)) || (mytele->mode == TIMEOUT) ?
2957 myrpt->txconf : myrpt->conf);
2958 ci.confmode = DAHDI_CONF_CONFANN;
2959 /* first put the channel on the conference in announce mode */
2960 if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
2962 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2963 rpt_mutex_lock(&myrpt->lock);
2964 remque((struct qelem *)mytele);
2965 rpt_mutex_unlock(&myrpt->lock);
2966 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
2967 free(mytele);
2968 ast_hangup(mychannel);
2969 pthread_exit(NULL);
2971 ast_stopstream(mychannel);
2972 switch(mytele->mode)
2974 case ID:
2975 case ID1:
2976 /* wait a bit */
2977 wait_interval(myrpt, (mytele->mode == ID) ? DLY_ID : DLY_TELEM,mychannel);
2978 res = telem_any(myrpt,mychannel, ident);
2979 imdone=1;
2980 break;
2982 case TAILMSG:
2983 res = ast_streamfile(mychannel, myrpt->p.tailmessages[myrpt->tailmessagen], mychannel->language);
2984 break;
2986 case IDTALKOVER:
2987 p = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "idtalkover");
2988 if(p)
2989 res = telem_any(myrpt,mychannel, p);
2990 imdone=1;
2991 break;
2993 case PROC:
2994 /* wait a little bit longer */
2995 wait_interval(myrpt, DLY_TELEM, mychannel);
2996 res = telem_lookup(myrpt, mychannel, myrpt->name, "patchup");
2997 if(res < 0){ /* Then default message */
2998 res = ast_streamfile(mychannel, "rpt/callproceeding", mychannel->language);
3000 break;
3001 case TERM:
3002 /* wait a little bit longer */
3003 wait_interval(myrpt, DLY_CALLTERM, mychannel);
3004 res = telem_lookup(myrpt, mychannel, myrpt->name, "patchdown");
3005 if(res < 0){ /* Then default message */
3006 res = ast_streamfile(mychannel, "rpt/callterminated", mychannel->language);
3008 break;
3009 case COMPLETE:
3010 /* wait a little bit */
3011 wait_interval(myrpt, DLY_TELEM, mychannel);
3012 res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
3013 break;
3014 case MACRO_NOTFOUND:
3015 /* wait a little bit */
3016 wait_interval(myrpt, DLY_TELEM, mychannel);
3017 res = ast_streamfile(mychannel, "rpt/macro_notfound", mychannel->language);
3018 break;
3019 case MACRO_BUSY:
3020 /* wait a little bit */
3021 wait_interval(myrpt, DLY_TELEM, mychannel);
3022 res = ast_streamfile(mychannel, "rpt/macro_busy", mychannel->language);
3023 break;
3024 case UNKEY:
3025 if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
3026 imdone = 1;
3027 break;
3031 * Reset the Unkey to CT timer
3034 x = get_wait_interval(myrpt, DLY_UNKEY);
3035 rpt_mutex_lock(&myrpt->lock);
3036 myrpt->unkeytocttimer = x; /* Must be protected as it is changed below */
3037 rpt_mutex_unlock(&myrpt->lock);
3040 * If there's one already queued, don't do another
3043 tlist = myrpt->tele.next;
3044 unkeys_queued = 0;
3045 if (tlist != &myrpt->tele)
3047 rpt_mutex_lock(&myrpt->lock);
3048 while(tlist != &myrpt->tele){
3049 if (tlist->mode == UNKEY) unkeys_queued++;
3050 tlist = tlist->next;
3052 rpt_mutex_unlock(&myrpt->lock);
3054 if( unkeys_queued > 1){
3055 imdone = 1;
3056 break;
3059 /* Wait for the telemetry timer to expire */
3060 /* Periodically check the timer since it can be re-initialized above */
3061 while(myrpt->unkeytocttimer)
3063 int ctint;
3064 if(myrpt->unkeytocttimer > 100)
3065 ctint = 100;
3066 else
3067 ctint = myrpt->unkeytocttimer;
3068 ast_safe_sleep(mychannel, ctint);
3069 rpt_mutex_lock(&myrpt->lock);
3070 if(myrpt->unkeytocttimer < ctint)
3071 myrpt->unkeytocttimer = 0;
3072 else
3073 myrpt->unkeytocttimer -= ctint;
3074 rpt_mutex_unlock(&myrpt->lock);
3078 * Now, the carrier on the rptr rx should be gone.
3079 * If it re-appeared, then forget about sending the CT
3081 if(myrpt->keyed){
3082 imdone = 1;
3083 break;
3086 rpt_mutex_lock(&myrpt->lock); /* Update the kerchunk counters */
3087 myrpt->dailykerchunks++;
3088 myrpt->totalkerchunks++;
3089 rpt_mutex_unlock(&myrpt->lock);
3091 haslink = 0;
3092 hastx = 0;
3093 hasremote = 0;
3094 l = myrpt->links.next;
3095 if (l != &myrpt->links)
3097 rpt_mutex_lock(&myrpt->lock);
3098 while(l != &myrpt->links)
3100 if (l->name[0] == '0')
3102 l = l->next;
3103 continue;
3105 haslink = 1;
3106 if (l->mode) {
3107 hastx++;
3108 if (l->isremote) hasremote++;
3110 l = l->next;
3112 rpt_mutex_unlock(&myrpt->lock);
3114 if (haslink)
3117 res = telem_lookup(myrpt,mychannel, myrpt->name, (!hastx) ? "remotemon" : "remotetx");
3118 if(res)
3119 ast_log(LOG_WARNING, "telem_lookup:remotexx failed on %s\n", mychannel->name);
3122 /* if in remote cmd mode, indicate it */
3123 if (myrpt->cmdnode[0])
3125 ast_safe_sleep(mychannel,200);
3126 res = telem_lookup(myrpt,mychannel, myrpt->name, "cmdmode");
3127 if(res)
3128 ast_log(LOG_WARNING, "telem_lookup:cmdmode failed on %s\n", mychannel->name);
3129 ast_stopstream(mychannel);
3132 else if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "unlinkedct"))){ /* Unlinked Courtesy Tone */
3133 ct_copy = ast_strdupa(ct);
3134 res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
3135 if(res)
3136 ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);
3138 if (hasremote && (!myrpt->cmdnode[0]))
3140 /* set for all to hear */
3141 ci.chan = 0;
3142 ci.confno = myrpt->conf;
3143 ci.confmode = DAHDI_CONF_CONFANN;
3144 /* first put the channel on the conference in announce mode */
3145 if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
3147 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
3148 rpt_mutex_lock(&myrpt->lock);
3149 remque((struct qelem *)mytele);
3150 rpt_mutex_unlock(&myrpt->lock);
3151 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
3152 free(mytele);
3153 ast_hangup(mychannel);
3154 pthread_exit(NULL);
3156 if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "remotect"))){ /* Unlinked Courtesy Tone */
3157 ast_safe_sleep(mychannel,200);
3158 ct_copy = ast_strdupa(ct);
3159 res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
3160 if(res)
3161 ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);
3164 #if defined(_MDC_DECODE_H_) && defined(MDC_SAY_WHEN_DOING_CT)
3165 if (myrpt->lastunit)
3167 char mystr[10];
3169 ast_safe_sleep(mychannel,200);
3170 /* set for all to hear */
3171 ci.chan = 0;
3172 ci.confno = myrpt->txconf;
3173 ci.confmode = DAHDI_CONF_CONFANN;
3174 /* first put the channel on the conference in announce mode */
3175 if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
3177 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
3178 rpt_mutex_lock(&myrpt->lock);
3179 remque((struct qelem *)mytele);
3180 rpt_mutex_unlock(&myrpt->lock);
3181 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
3182 free(mytele);
3183 ast_hangup(mychannel);
3184 pthread_exit(NULL);
3186 sprintf(mystr,"%04x",myrpt->lastunit);
3187 myrpt->lastunit = 0;
3188 ast_say_character_str(mychannel,mystr,NULL,mychannel->language);
3189 break;
3191 #endif
3192 imdone = 1;
3193 break;
3194 case LINKUNKEY:
3195 if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
3196 imdone = 1;
3197 break;
3201 * Reset the Unkey to CT timer
3204 x = get_wait_interval(myrpt, DLY_LINKUNKEY);
3205 mytele->mylink.linkunkeytocttimer = x; /* Must be protected as it is changed below */
3208 * If there's one already queued, don't do another
3211 tlist = myrpt->tele.next;
3212 unkeys_queued = 0;
3213 if (tlist != &myrpt->tele)
3215 rpt_mutex_lock(&myrpt->lock);
3216 while(tlist != &myrpt->tele){
3217 if (tlist->mode == LINKUNKEY) unkeys_queued++;
3218 tlist = tlist->next;
3220 rpt_mutex_unlock(&myrpt->lock);
3222 if( unkeys_queued > 1){
3223 imdone = 1;
3224 break;
3227 /* Wait for the telemetry timer to expire */
3228 /* Periodically check the timer since it can be re-initialized above */
3229 while(mytele->mylink.linkunkeytocttimer)
3231 int ctint;
3232 if(mytele->mylink.linkunkeytocttimer > 100)
3233 ctint = 100;
3234 else
3235 ctint = mytele->mylink.linkunkeytocttimer;
3236 ast_safe_sleep(mychannel, ctint);
3237 rpt_mutex_lock(&myrpt->lock);
3238 if(mytele->mylink.linkunkeytocttimer < ctint)
3239 mytele->mylink.linkunkeytocttimer = 0;
3240 else
3241 mytele->mylink.linkunkeytocttimer -= ctint;
3242 rpt_mutex_unlock(&myrpt->lock);
3245 if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "linkunkeyct"))){ /* Unlinked Courtesy Tone */
3246 ct_copy = ast_strdupa(ct);
3247 res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
3248 if(res)
3249 ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);
3251 imdone = 1;
3252 break;
3253 case REMDISC:
3254 /* wait a little bit */
3255 wait_interval(myrpt, DLY_TELEM, mychannel);
3256 l = myrpt->links.next;
3257 haslink = 0;
3258 /* dont report if a link for this one still on system */
3259 if (l != &myrpt->links)
3261 rpt_mutex_lock(&myrpt->lock);
3262 while(l != &myrpt->links)
3264 if (l->name[0] == '0')
3266 l = l->next;
3267 continue;
3269 if (!strcmp(l->name,mytele->mylink.name))
3271 haslink = 1;
3272 break;
3274 l = l->next;
3276 rpt_mutex_unlock(&myrpt->lock);
3278 if (haslink)
3280 imdone = 1;
3281 break;
3283 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3284 if (!res)
3285 res = ast_waitstream(mychannel, "");
3286 else
3287 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3288 ast_stopstream(mychannel);
3289 ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
3290 res = ast_streamfile(mychannel, ((mytele->mylink.hasconnected) ?
3291 "rpt/remote_disc" : "rpt/remote_busy"), mychannel->language);
3292 break;
3293 case REMALREADY:
3294 /* wait a little bit */
3295 wait_interval(myrpt, DLY_TELEM, mychannel);
3296 res = ast_streamfile(mychannel, "rpt/remote_already", mychannel->language);
3297 break;
3298 case REMNOTFOUND:
3299 /* wait a little bit */
3300 wait_interval(myrpt, DLY_TELEM, mychannel);
3301 res = ast_streamfile(mychannel, "rpt/remote_notfound", mychannel->language);
3302 break;
3303 case REMGO:
3304 /* wait a little bit */
3305 wait_interval(myrpt, DLY_TELEM, mychannel);
3306 res = ast_streamfile(mychannel, "rpt/remote_go", mychannel->language);
3307 break;
3308 case CONNECTED:
3309 /* wait a little bit */
3310 wait_interval(myrpt, DLY_TELEM, mychannel);
3311 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3312 if (!res)
3313 res = ast_waitstream(mychannel, "");
3314 else
3315 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3316 ast_stopstream(mychannel);
3317 ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
3318 res = ast_streamfile(mychannel, "rpt/connected", mychannel->language);
3319 if (!res)
3320 res = ast_waitstream(mychannel, "");
3321 else
3322 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3323 ast_stopstream(mychannel);
3324 res = ast_streamfile(mychannel, "digits/2", mychannel->language);
3325 if (!res)
3326 res = ast_waitstream(mychannel, "");
3327 else
3328 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3329 ast_stopstream(mychannel);
3330 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3331 if (!res)
3332 res = ast_waitstream(mychannel, "");
3333 else
3334 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3335 ast_stopstream(mychannel);
3336 ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
3337 imdone = 1;
3338 break;
3339 case CONNFAIL:
3340 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3341 if (!res)
3342 res = ast_waitstream(mychannel, "");
3343 else
3344 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3345 ast_stopstream(mychannel);
3346 ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
3347 res = ast_streamfile(mychannel, "rpt/connection_failed", mychannel->language);
3348 break;
3349 case MEMNOTFOUND:
3350 /* wait a little bit */
3351 wait_interval(myrpt, DLY_TELEM, mychannel);
3352 res = ast_streamfile(mychannel, "rpt/memory_notfound", mychannel->language);
3353 break;
3354 case SETREMOTE:
3355 ast_mutex_lock(&myrpt->remlock);
3356 res = 0;
3357 if(!strcmp(myrpt->remote, remote_rig_ft897))
3359 res = set_ft897(myrpt);
3361 if(!strcmp(myrpt->remote, remote_rig_ic706))
3363 res = set_ic706(myrpt);
3365 else if(!strcmp(myrpt->remote, remote_rig_rbi))
3367 if (ioperm(myrpt->p.iobase,1,1) == -1)
3369 rpt_mutex_unlock(&myrpt->lock);
3370 ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase);
3371 res = -1;
3373 else res = setrbi(myrpt);
3375 else if(!strcmp(myrpt->remote, remote_rig_kenwood))
3377 res = setkenwood(myrpt);
3378 if (ast_safe_sleep(mychannel,200) == -1)
3380 ast_mutex_unlock(&myrpt->remlock);
3381 res = -1;
3382 break;
3384 i = DAHDI_FLUSH_EVENT;
3385 if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_FLUSH,&i) == -1)
3387 ast_mutex_unlock(&myrpt->remlock);
3388 ast_log(LOG_ERROR,"Cant flush events");
3389 res = -1;
3390 break;
3392 if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_GET_PARAMS,&par) == -1)
3394 ast_mutex_unlock(&myrpt->remlock);
3395 ast_log(LOG_ERROR,"Cant get params");
3396 res = -1;
3397 break;
3399 myrpt->remoterx =
3400 (par.rxisoffhook || (myrpt->tele.next != &myrpt->tele));
3402 ast_mutex_unlock(&myrpt->remlock);
3403 if (!res)
3405 imdone = 1;
3406 break;
3408 /* fall thru to invalid freq */
3409 case INVFREQ:
3410 /* wait a little bit */
3411 wait_interval(myrpt, DLY_TELEM, mychannel);
3412 res = ast_streamfile(mychannel, "rpt/invalid-freq", mychannel->language);
3413 break;
3414 case REMMODE:
3415 cp = 0;
3416 wait_interval(myrpt, DLY_TELEM, mychannel);
3417 switch(myrpt->remmode)
3419 case REM_MODE_FM:
3420 saycharstr(mychannel,"FM");
3421 break;
3422 case REM_MODE_USB:
3423 saycharstr(mychannel,"USB");
3424 break;
3425 case REM_MODE_LSB:
3426 saycharstr(mychannel,"LSB");
3427 break;
3428 case REM_MODE_AM:
3429 saycharstr(mychannel,"AM");
3430 break;
3432 wait_interval(myrpt, DLY_COMP, mychannel);
3433 if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
3434 break;
3435 case LOGINREQ:
3436 wait_interval(myrpt, DLY_TELEM, mychannel);
3437 sayfile(mychannel,"rpt/login");
3438 saycharstr(mychannel,myrpt->name);
3439 break;
3440 case REMLOGIN:
3441 wait_interval(myrpt, DLY_TELEM, mychannel);
3442 saycharstr(mychannel,myrpt->loginuser);
3443 sayfile(mychannel,"rpt/node");
3444 saycharstr(mychannel,myrpt->name);
3445 wait_interval(myrpt, DLY_COMP, mychannel);
3446 if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
3447 break;
3448 case REMXXX:
3449 wait_interval(myrpt, DLY_TELEM, mychannel);
3450 res = 0;
3451 switch(mytele->submode)
3453 case 100: /* RX PL Off */
3454 sayfile(mychannel, "rpt/rxpl");
3455 sayfile(mychannel, "rpt/off");
3456 break;
3457 case 101: /* RX PL On */
3458 sayfile(mychannel, "rpt/rxpl");
3459 sayfile(mychannel, "rpt/on");
3460 break;
3461 case 102: /* TX PL Off */
3462 sayfile(mychannel, "rpt/txpl");
3463 sayfile(mychannel, "rpt/off");
3464 break;
3465 case 103: /* TX PL On */
3466 sayfile(mychannel, "rpt/txpl");
3467 sayfile(mychannel, "rpt/on");
3468 break;
3469 case 104: /* Low Power */
3470 sayfile(mychannel, "rpt/lopwr");
3471 break;
3472 case 105: /* Medium Power */
3473 sayfile(mychannel, "rpt/medpwr");
3474 break;
3475 case 106: /* Hi Power */
3476 sayfile(mychannel, "rpt/hipwr");
3477 break;
3478 case 113: /* Scan down slow */
3479 sayfile(mychannel,"rpt/down");
3480 sayfile(mychannel, "rpt/slow");
3481 break;
3482 case 114: /* Scan down quick */
3483 sayfile(mychannel,"rpt/down");
3484 sayfile(mychannel, "rpt/quick");
3485 break;
3486 case 115: /* Scan down fast */
3487 sayfile(mychannel,"rpt/down");
3488 sayfile(mychannel, "rpt/fast");
3489 break;
3490 case 116: /* Scan up slow */
3491 sayfile(mychannel,"rpt/up");
3492 sayfile(mychannel, "rpt/slow");
3493 break;
3494 case 117: /* Scan up quick */
3495 sayfile(mychannel,"rpt/up");
3496 sayfile(mychannel, "rpt/quick");
3497 break;
3498 case 118: /* Scan up fast */
3499 sayfile(mychannel,"rpt/up");
3500 sayfile(mychannel, "rpt/fast");
3501 break;
3502 default:
3503 res = -1;
3505 wait_interval(myrpt, DLY_COMP, mychannel);
3506 if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
3507 break;
3508 case SCAN:
3509 ast_mutex_lock(&myrpt->remlock);
3510 if (myrpt->hfscanstop)
3512 myrpt->hfscanstatus = 0;
3513 myrpt->hfscanmode = 0;
3514 myrpt->hfscanstop = 0;
3515 mytele->mode = SCANSTAT;
3516 ast_mutex_unlock(&myrpt->remlock);
3517 if (ast_safe_sleep(mychannel,1000) == -1) break;
3518 sayfile(mychannel, "rpt/stop");
3519 imdone = 1;
3520 break;
3522 if (myrpt->hfscanstatus > -2) service_scan(myrpt);
3523 i = myrpt->hfscanstatus;
3524 myrpt->hfscanstatus = 0;
3525 if (i) mytele->mode = SCANSTAT;
3526 ast_mutex_unlock(&myrpt->remlock);
3527 if (i < 0) sayfile(mychannel, "rpt/stop");
3528 else if (i > 0) saynum(mychannel,i);
3529 imdone = 1;
3530 break;
3531 case TUNE:
3532 ast_mutex_lock(&myrpt->remlock);
3533 if (!strcmp(myrpt->remote,remote_rig_ic706))
3535 set_mode_ic706(myrpt, REM_MODE_AM);
3536 if(play_tone(mychannel, 800, 6000, 8192) == -1) break;
3537 ast_safe_sleep(mychannel,500);
3538 set_mode_ic706(myrpt, myrpt->remmode);
3539 myrpt->tunerequest = 0;
3540 ast_mutex_unlock(&myrpt->remlock);
3541 imdone = 1;
3542 break;
3544 set_mode_ft897(myrpt, REM_MODE_AM);
3545 simple_command_ft897(myrpt, 8);
3546 if(play_tone(mychannel, 800, 6000, 8192) == -1) break;
3547 simple_command_ft897(myrpt, 0x88);
3548 ast_safe_sleep(mychannel,500);
3549 set_mode_ft897(myrpt, myrpt->remmode);
3550 myrpt->tunerequest = 0;
3551 ast_mutex_unlock(&myrpt->remlock);
3552 imdone = 1;
3553 break;
3554 case REMSHORTSTATUS:
3555 case REMLONGSTATUS:
3556 wait_interval(myrpt, DLY_TELEM, mychannel);
3557 res = sayfile(mychannel,"rpt/node");
3558 if(!res)
3559 res = saycharstr(mychannel, myrpt->name);
3560 if(!res)
3561 res = sayfile(mychannel,"rpt/frequency");
3562 if(!res)
3563 res = split_freq(mhz, decimals, myrpt->freq);
3564 if (!multimode_capable(myrpt)) decimals[3] = 0;
3565 if(!res){
3566 m = atoi(mhz);
3567 if(m < 100)
3568 res = saynum(mychannel, m);
3569 else
3570 res = saycharstr(mychannel, mhz);
3572 if(!res)
3573 res = sayfile(mychannel, "letters/dot");
3574 if(!res)
3575 res = saycharstr(mychannel, decimals);
3577 if(res) break;
3578 if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */
3579 switch(myrpt->offset){
3581 case REM_MINUS:
3582 res = sayfile(mychannel,"rpt/minus");
3583 break;
3585 case REM_SIMPLEX:
3586 res = sayfile(mychannel,"rpt/simplex");
3587 break;
3589 case REM_PLUS:
3590 res = sayfile(mychannel,"rpt/plus");
3591 break;
3593 default:
3594 break;
3597 else{ /* Must be USB, LSB, or AM */
3598 switch(myrpt->remmode){
3600 case REM_MODE_USB:
3601 res = saycharstr(mychannel, "USB");
3602 break;
3604 case REM_MODE_LSB:
3605 res = saycharstr(mychannel, "LSB");
3606 break;
3608 case REM_MODE_AM:
3609 res = saycharstr(mychannel, "AM");
3610 break;
3613 default:
3614 break;
3618 if (res == -1) break;
3620 if(mytele->mode == REMSHORTSTATUS){ /* Short status? */
3621 wait_interval(myrpt, DLY_COMP, mychannel);
3622 if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
3623 break;
3626 if (strcmp(myrpt->remote,remote_rig_ic706))
3628 switch(myrpt->powerlevel){
3630 case REM_LOWPWR:
3631 res = sayfile(mychannel,"rpt/lopwr") ;
3632 break;
3633 case REM_MEDPWR:
3634 res = sayfile(mychannel,"rpt/medpwr");
3635 break;
3636 case REM_HIPWR:
3637 res = sayfile(mychannel,"rpt/hipwr");
3638 break;
3642 rbimode = ((!strncmp(myrpt->remote,remote_rig_rbi,3))
3643 || (!strncmp(myrpt->remote,remote_rig_ic706,3)));
3644 if (res || (sayfile(mychannel,"rpt/rxpl") == -1)) break;
3645 if (rbimode && (sayfile(mychannel,"rpt/txpl") == -1)) break;
3646 if ((sayfile(mychannel,"rpt/frequency") == -1) ||
3647 (saycharstr(mychannel,myrpt->rxpl) == -1)) break;
3648 if ((!rbimode) && ((sayfile(mychannel,"rpt/txpl") == -1) ||
3649 (sayfile(mychannel,"rpt/frequency") == -1) ||
3650 (saycharstr(mychannel,myrpt->txpl) == -1))) break;
3651 if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */
3652 if ((sayfile(mychannel,"rpt/rxpl") == -1) ||
3653 (sayfile(mychannel,((myrpt->rxplon) ? "rpt/on" : "rpt/off")) == -1) ||
3654 (sayfile(mychannel,"rpt/txpl") == -1) ||
3655 (sayfile(mychannel,((myrpt->txplon) ? "rpt/on" : "rpt/off")) == -1))
3657 break;
3660 wait_interval(myrpt, DLY_COMP, mychannel);
3661 if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
3662 break;
3663 case STATUS:
3664 /* wait a little bit */
3665 wait_interval(myrpt, DLY_TELEM, mychannel);
3666 hastx = 0;
3667 linkbase.next = &linkbase;
3668 linkbase.prev = &linkbase;
3669 rpt_mutex_lock(&myrpt->lock);
3670 /* make our own list of links */
3671 l = myrpt->links.next;
3672 while(l != &myrpt->links)
3674 if (l->name[0] == '0')
3676 l = l->next;
3677 continue;
3679 l1 = malloc(sizeof(struct rpt_link));
3680 if (!l1)
3682 ast_log(LOG_WARNING, "Cannot alloc memory on %s\n", mychannel->name);
3683 remque((struct qelem *)mytele);
3684 rpt_mutex_unlock(&myrpt->lock);
3685 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
3686 free(mytele);
3687 ast_hangup(mychannel);
3688 pthread_exit(NULL);
3690 memcpy(l1,l,sizeof(struct rpt_link));
3691 l1->next = l1->prev = NULL;
3692 insque((struct qelem *)l1,(struct qelem *)linkbase.next);
3693 l = l->next;
3695 rpt_mutex_unlock(&myrpt->lock);
3696 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3697 if (!res)
3698 res = ast_waitstream(mychannel, "");
3699 else
3700 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3701 ast_stopstream(mychannel);
3702 ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
3703 if (!res)
3704 res = ast_waitstream(mychannel, "");
3705 else
3706 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3707 ast_stopstream(mychannel);
3708 if (myrpt->callmode)
3710 hastx = 1;
3711 res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
3712 if (!res)
3713 res = ast_waitstream(mychannel, "");
3714 else
3715 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3716 ast_stopstream(mychannel);
3718 l = linkbase.next;
3719 while(l != &linkbase)
3721 char *s;
3723 hastx = 1;
3724 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3725 if (!res)
3726 res = ast_waitstream(mychannel, "");
3727 else
3728 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3729 ast_stopstream(mychannel);
3730 ast_say_character_str(mychannel,l->name,NULL,mychannel->language);
3731 if (!res)
3732 res = ast_waitstream(mychannel, "");
3733 else
3734 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3735 ast_stopstream(mychannel);
3736 s = "rpt/tranceive";
3737 if (!l->mode) s = "rpt/monitor";
3738 if (!l->thisconnected) s = "rpt/connecting";
3739 res = ast_streamfile(mychannel, s, mychannel->language);
3740 if (!res)
3741 res = ast_waitstream(mychannel, "");
3742 else
3743 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3744 ast_stopstream(mychannel);
3745 l = l->next;
3747 if (!hastx)
3749 res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
3750 if (!res)
3751 res = ast_waitstream(mychannel, "");
3752 else
3753 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3754 ast_stopstream(mychannel);
3756 /* destroy our local link queue */
3757 l = linkbase.next;
3758 while(l != &linkbase)
3760 l1 = l;
3761 l = l->next;
3762 remque((struct qelem *)l1);
3763 free(l1);
3765 imdone = 1;
3766 break;
3767 case FULLSTATUS:
3768 rpt_mutex_lock(&myrpt->lock);
3769 /* get all the nodes */
3770 __mklinklist(myrpt,NULL,lbuf);
3771 rpt_mutex_unlock(&myrpt->lock);
3772 /* parse em */
3773 ns = finddelim(lbuf,strs,MAXLINKLIST);
3774 /* sort em */
3775 if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar);
3776 /* wait a little bit */
3777 wait_interval(myrpt, DLY_TELEM, mychannel);
3778 hastx = 0;
3779 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3780 if (!res)
3781 res = ast_waitstream(mychannel, "");
3782 else
3783 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3784 ast_stopstream(mychannel);
3785 ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
3786 if (!res)
3787 res = ast_waitstream(mychannel, "");
3788 else
3789 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3790 ast_stopstream(mychannel);
3791 if (myrpt->callmode)
3793 hastx = 1;
3794 res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
3795 if (!res)
3796 res = ast_waitstream(mychannel, "");
3797 else
3798 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3799 ast_stopstream(mychannel);
3801 /* go thru all the nodes in list */
3802 for(i = 0; i < ns; i++)
3804 char *s,mode = 'T';
3806 /* if a mode spec at first, handle it */
3807 if ((*strs[i] < '0') || (*strs[i] > '9'))
3809 mode = *strs[i];
3810 strs[i]++;
3813 hastx = 1;
3814 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3815 if (!res)
3816 res = ast_waitstream(mychannel, "");
3817 else
3818 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3819 ast_stopstream(mychannel);
3820 ast_say_character_str(mychannel,strs[i],NULL,mychannel->language);
3821 if (!res)
3822 res = ast_waitstream(mychannel, "");
3823 else
3824 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3825 ast_stopstream(mychannel);
3826 s = "rpt/tranceive";
3827 if (mode == 'R') s = "rpt/monitor";
3828 if (mode == 'C') s = "rpt/connecting";
3829 res = ast_streamfile(mychannel, s, mychannel->language);
3830 if (!res)
3831 res = ast_waitstream(mychannel, "");
3832 else
3833 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3834 ast_stopstream(mychannel);
3836 if (!hastx)
3838 res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
3839 if (!res)
3840 res = ast_waitstream(mychannel, "");
3841 else
3842 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3843 ast_stopstream(mychannel);
3845 imdone = 1;
3846 break;
3848 case LASTNODEKEY: /* Identify last node which keyed us up */
3849 rpt_mutex_lock(&myrpt->lock);
3850 if(myrpt->lastnodewhichkeyedusup)
3851 p = ast_strdupa(myrpt->lastnodewhichkeyedusup); /* Make a local copy of the node name */
3852 else
3853 p = NULL;
3854 rpt_mutex_unlock(&myrpt->lock);
3855 if(!p){
3856 imdone = 1; /* no node previously keyed us up, or the node which did has been disconnected */
3857 break;
3859 wait_interval(myrpt, DLY_TELEM, mychannel);
3860 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3861 if (!res)
3862 res = ast_waitstream(mychannel, "");
3863 else
3864 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3865 ast_stopstream(mychannel);
3866 ast_say_character_str(mychannel, p, NULL, mychannel->language);
3867 if (!res)
3868 res = ast_waitstream(mychannel, "");
3869 else
3870 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3871 ast_stopstream(mychannel);
3872 imdone = 1;
3873 break;
3875 case UNAUTHTX: /* Say unauthorized transmit frequency */
3876 wait_interval(myrpt, DLY_TELEM, mychannel);
3877 res = ast_streamfile(mychannel, "rpt/unauthtx", mychannel->language);
3878 if (!res)
3879 res = ast_waitstream(mychannel, "");
3880 else
3881 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3882 ast_stopstream(mychannel);
3883 imdone = 1;
3884 break;
3887 case TIMEOUT:
3888 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3889 if (!res)
3890 res = ast_waitstream(mychannel, "");
3891 else
3892 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3893 ast_stopstream(mychannel);
3894 ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
3895 res = ast_streamfile(mychannel, "rpt/timeout", mychannel->language);
3896 break;
3898 case TIMEOUT_WARNING:
3899 time(&t);
3900 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3901 if (!res)
3902 res = ast_waitstream(mychannel, "");
3903 else
3904 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3905 ast_stopstream(mychannel);
3906 ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
3907 res = ast_streamfile(mychannel, "rpt/timeout-warning", mychannel->language);
3908 if (!res)
3909 res = ast_waitstream(mychannel, "");
3910 else
3911 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3912 ast_stopstream(mychannel);
3913 if(!res) /* Say number of seconds */
3914 ast_say_number(mychannel, myrpt->p.remotetimeout -
3915 (t - myrpt->last_activity_time),
3916 "", mychannel->language, (char *) NULL);
3917 if (!res)
3918 res = ast_waitstream(mychannel, "");
3919 ast_stopstream(mychannel);
3920 res = ast_streamfile(mychannel, "queue-seconds", mychannel->language);
3921 break;
3923 case ACT_TIMEOUT_WARNING:
3924 time(&t);
3925 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3926 if (!res)
3927 res = ast_waitstream(mychannel, "");
3928 else
3929 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3930 ast_stopstream(mychannel);
3931 ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
3932 res = ast_streamfile(mychannel, "rpt/act-timeout-warning", mychannel->language);
3933 if (!res)
3934 res = ast_waitstream(mychannel, "");
3935 else
3936 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3937 ast_stopstream(mychannel);
3938 if(!res) /* Say number of seconds */
3939 ast_say_number(mychannel, myrpt->p.remoteinacttimeout -
3940 (t - myrpt->last_activity_time),
3941 "", mychannel->language, (char *) NULL);
3942 if (!res)
3943 res = ast_waitstream(mychannel, "");
3944 ast_stopstream(mychannel);
3945 res = ast_streamfile(mychannel, "queue-seconds", mychannel->language);
3946 break;
3948 case STATS_TIME:
3949 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
3950 t = time(NULL);
3951 rpt_localtime(&t, &localtm);
3952 /* Say the phase of the day is before the time */
3953 if((localtm.tm_hour >= 0) && (localtm.tm_hour < 12))
3954 p = "rpt/goodmorning";
3955 else if((localtm.tm_hour >= 12) && (localtm.tm_hour < 18))
3956 p = "rpt/goodafternoon";
3957 else
3958 p = "rpt/goodevening";
3959 if (sayfile(mychannel,p) == -1)
3961 imdone = 1;
3962 break;
3964 /* Say the time is ... */
3965 if (sayfile(mychannel,"rpt/thetimeis") == -1)
3967 imdone = 1;
3968 break;
3970 /* Say the time */
3971 res = ast_say_time(mychannel, t, "", mychannel->language);
3972 if (!res)
3973 res = ast_waitstream(mychannel, "");
3974 ast_stopstream(mychannel);
3975 imdone = 1;
3976 break;
3977 case STATS_VERSION:
3978 p = strstr(tdesc, "version");
3979 if(!p)
3980 break;
3981 if(sscanf(p, "version %d.%d", &vmajor, &vminor) != 2)
3982 break;
3983 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
3984 /* Say "version" */
3985 if (sayfile(mychannel,"rpt/version") == -1)
3987 imdone = 1;
3988 break;
3990 if(!res) /* Say "X" */
3991 ast_say_number(mychannel, vmajor, "", mychannel->language, (char *) NULL);
3992 if (!res)
3993 res = ast_waitstream(mychannel, "");
3994 ast_stopstream(mychannel);
3995 if (saycharstr(mychannel,".") == -1)
3997 imdone = 1;
3998 break;
4000 if(!res) /* Say "Y" */
4001 ast_say_number(mychannel, vminor, "", mychannel->language, (char *) NULL);
4002 if (!res){
4003 res = ast_waitstream(mychannel, "");
4004 ast_stopstream(mychannel);
4006 else
4007 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
4008 imdone = 1;
4009 break;
4010 case ARB_ALPHA:
4011 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
4012 if(mytele->param)
4013 saycharstr(mychannel, mytele->param);
4014 imdone = 1;
4015 break;
4016 case REV_PATCH:
4017 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
4018 if(mytele->param) {
4020 /* Parts of this section taken from app_parkandannounce */
4021 char *tpl_working, *tpl_current;
4022 char *tmp[100], *myparm;
4023 int looptemp=0,i=0, dres = 0;
4026 tpl_working = strdupa(mytele->param);
4027 myparm = strsep(&tpl_working,",");
4028 tpl_current=strsep(&tpl_working, ":");
4030 while(tpl_current && looptemp < sizeof(tmp)) {
4031 tmp[looptemp]=tpl_current;
4032 looptemp++;
4033 tpl_current=strsep(&tpl_working,":");
4036 for(i=0; i<looptemp; i++) {
4037 if(!strcmp(tmp[i], "PARKED")) {
4038 ast_say_digits(mychannel, atoi(myparm), "", mychannel->language);
4039 } else if(!strcmp(tmp[i], "NODE")) {
4040 ast_say_digits(mychannel, atoi(myrpt->name), "", mychannel->language);
4041 } else {
4042 dres = ast_streamfile(mychannel, tmp[i], mychannel->language);
4043 if(!dres) {
4044 dres = ast_waitstream(mychannel, "");
4045 } else {
4046 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[i], mychannel->name);
4047 dres = 0;
4052 imdone = 1;
4053 break;
4054 case TEST_TONE:
4055 imdone = 1;
4056 if (myrpt->stopgen) break;
4057 myrpt->stopgen = -1;
4058 if ((res = ast_tonepair_start(mychannel, 1004.0, 0, 99999999, 7200.0)))
4060 myrpt->stopgen = 0;
4061 break;
4063 while(mychannel->generatordata && (myrpt->stopgen <= 0)) {
4064 if (ast_safe_sleep(mychannel,1)) break;
4065 imdone = 1;
4067 myrpt->stopgen = 0;
4068 break;
4069 default:
4070 break;
4072 if (!imdone)
4074 if (!res)
4075 res = ast_waitstream(mychannel, "");
4076 else {
4077 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
4078 res = 0;
4081 ast_stopstream(mychannel);
4082 rpt_mutex_lock(&myrpt->lock);
4083 if (mytele->mode == TAILMSG)
4085 if (!res)
4087 myrpt->tailmessagen++;
4088 if(myrpt->tailmessagen >= myrpt->p.tailmessagemax) myrpt->tailmessagen = 0;
4090 else
4092 myrpt->tmsgtimer = myrpt->p.tailsquashedtime;
4095 remque((struct qelem *)mytele);
4096 rpt_mutex_unlock(&myrpt->lock);
4097 free(mytele);
4098 ast_hangup(mychannel);
4099 #ifdef APP_RPT_LOCK_DEBUG
4101 struct lockthread *t;
4103 sleep(5);
4104 ast_mutex_lock(&locklock);
4105 t = get_lockthread(pthread_self());
4106 if (t) memset(t,0,sizeof(struct lockthread));
4107 ast_mutex_unlock(&locklock);
4109 #endif
4110 pthread_exit(NULL);
4113 static void rpt_telemetry(struct rpt *myrpt,int mode, void *data)
4115 struct rpt_tele *tele;
4116 struct rpt_link *mylink = (struct rpt_link *) data;
4117 int res;
4118 pthread_attr_t attr;
4120 tele = malloc(sizeof(struct rpt_tele));
4121 if (!tele)
4123 ast_log(LOG_WARNING, "Unable to allocate memory\n");
4124 pthread_exit(NULL);
4125 return;
4127 /* zero it out */
4128 memset((char *)tele,0,sizeof(struct rpt_tele));
4129 tele->rpt = myrpt;
4130 tele->mode = mode;
4131 rpt_mutex_lock(&myrpt->lock);
4132 if((mode == CONNFAIL) || (mode == REMDISC) || (mode == CONNECTED) ||
4133 (mode == LINKUNKEY)){
4134 memset(&tele->mylink,0,sizeof(struct rpt_link));
4135 if (mylink){
4136 memcpy(&tele->mylink,mylink,sizeof(struct rpt_link));
4139 else if ((mode == ARB_ALPHA) || (mode == REV_PATCH)) {
4140 strncpy(tele->param, (char *) data, TELEPARAMSIZE - 1);
4141 tele->param[TELEPARAMSIZE - 1] = 0;
4143 if (mode == REMXXX) tele->submode = (int) data;
4144 insque((struct qelem *)tele, (struct qelem *)myrpt->tele.next);
4145 rpt_mutex_unlock(&myrpt->lock);
4146 pthread_attr_init(&attr);
4147 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
4148 res = ast_pthread_create(&tele->threadid,&attr,rpt_tele_thread,(void *) tele);
4149 if(res < 0){
4150 rpt_mutex_lock(&myrpt->lock);
4151 remque((struct qlem *) tele); /* We don't like stuck transmitters, remove it from the queue */
4152 rpt_mutex_unlock(&myrpt->lock);
4153 ast_log(LOG_WARNING, "Could not create telemetry thread: %s",strerror(res));
4155 return;
4158 static void *rpt_call(void *this)
4160 struct dahdi_confinfo ci; /* conference info */
4161 struct rpt *myrpt = (struct rpt *)this;
4162 int res;
4163 int stopped,congstarted,dialtimer,lastcidx,aborted;
4164 struct ast_channel *mychannel,*genchannel;
4167 myrpt->mydtmf = 0;
4168 /* allocate a pseudo-channel thru asterisk */
4169 mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
4170 if (!mychannel)
4172 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
4173 pthread_exit(NULL);
4175 #ifdef AST_CDR_FLAG_POST_DISABLED
4176 ast_set_flag(mychannel->cdr,AST_CDR_FLAG_POST_DISABLED);
4177 #endif
4178 ci.chan = 0;
4179 ci.confno = myrpt->conf; /* use the pseudo conference */
4180 ci.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER
4181 | DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER;
4182 /* first put the channel on the conference */
4183 if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
4185 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
4186 ast_hangup(mychannel);
4187 myrpt->callmode = 0;
4188 pthread_exit(NULL);
4190 /* allocate a pseudo-channel thru asterisk */
4191 genchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
4192 if (!genchannel)
4194 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
4195 ast_hangup(mychannel);
4196 pthread_exit(NULL);
4198 #ifdef AST_CDR_FLAG_POST_DISABLED
4199 ast_set_flag(genchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
4200 #endif
4201 ci.chan = 0;
4202 ci.confno = myrpt->conf;
4203 ci.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER
4204 | DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER;
4205 /* first put the channel on the conference */
4206 if (ioctl(genchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
4208 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
4209 ast_hangup(mychannel);
4210 ast_hangup(genchannel);
4211 myrpt->callmode = 0;
4212 pthread_exit(NULL);
4214 if (myrpt->p.tonezone && (tone_zone_set_zone(mychannel->fds[0],myrpt->p.tonezone) == -1))
4216 ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
4217 ast_hangup(mychannel);
4218 ast_hangup(genchannel);
4219 myrpt->callmode = 0;
4220 pthread_exit(NULL);
4222 if (myrpt->p.tonezone && (tone_zone_set_zone(genchannel->fds[0],myrpt->p.tonezone) == -1))
4224 ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
4225 ast_hangup(mychannel);
4226 ast_hangup(genchannel);
4227 myrpt->callmode = 0;
4228 pthread_exit(NULL);
4230 /* start dialtone if patchquiet is 0. Special patch modes don't send dial tone */
4231 if ((!myrpt->patchquiet) && (tone_zone_play_tone(mychannel->fds[0],DAHDI_TONE_DIALTONE) < 0))
4233 ast_log(LOG_WARNING, "Cannot start dialtone\n");
4234 ast_hangup(mychannel);
4235 ast_hangup(genchannel);
4236 myrpt->callmode = 0;
4237 pthread_exit(NULL);
4239 stopped = 0;
4240 congstarted = 0;
4241 dialtimer = 0;
4242 lastcidx = 0;
4243 aborted = 0;
4246 while ((myrpt->callmode == 1) || (myrpt->callmode == 4))
4249 if((myrpt->patchdialtime)&&(myrpt->callmode == 1)&&(myrpt->cidx != lastcidx)){
4250 dialtimer = 0;
4251 lastcidx = myrpt->cidx;
4254 if((myrpt->patchdialtime)&&(dialtimer >= myrpt->patchdialtime)){
4255 rpt_mutex_lock(&myrpt->lock);
4256 aborted = 1;
4257 myrpt->callmode = 0;
4258 rpt_mutex_unlock(&myrpt->lock);
4259 break;
4262 if ((!myrpt->patchquiet) && (!stopped) && (myrpt->callmode == 1) && (myrpt->cidx > 0))
4264 stopped = 1;
4265 /* stop dial tone */
4266 tone_zone_play_tone(mychannel->fds[0],-1);
4268 if (myrpt->callmode == 4)
4270 if(!congstarted){
4271 congstarted = 1;
4272 /* start congestion tone */
4273 tone_zone_play_tone(mychannel->fds[0],DAHDI_TONE_CONGESTION);
4276 res = ast_safe_sleep(mychannel, MSWAIT);
4277 if (res < 0)
4279 ast_hangup(mychannel);
4280 ast_hangup(genchannel);
4281 rpt_mutex_lock(&myrpt->lock);
4282 myrpt->callmode = 0;
4283 rpt_mutex_unlock(&myrpt->lock);
4284 pthread_exit(NULL);
4286 dialtimer += MSWAIT;
4288 /* stop any tone generation */
4289 tone_zone_play_tone(mychannel->fds[0],-1);
4290 /* end if done */
4291 if (!myrpt->callmode)
4293 ast_hangup(mychannel);
4294 ast_hangup(genchannel);
4295 rpt_mutex_lock(&myrpt->lock);
4296 myrpt->callmode = 0;
4297 rpt_mutex_unlock(&myrpt->lock);
4298 if((!myrpt->patchquiet) && aborted)
4299 rpt_telemetry(myrpt, TERM, NULL);
4300 pthread_exit(NULL);
4303 if (myrpt->p.ourcallerid && *myrpt->p.ourcallerid){
4304 char *name, *loc, *instr;
4305 instr = strdup(myrpt->p.ourcallerid);
4306 if(instr){
4307 ast_callerid_parse(instr, &name, &loc);
4308 if(loc){
4309 if(mychannel->cid.cid_num)
4310 free(mychannel->cid.cid_num);
4311 mychannel->cid.cid_num = strdup(loc);
4313 if(name){
4314 if(mychannel->cid.cid_name)
4315 free(mychannel->cid.cid_name);
4316 mychannel->cid.cid_name = strdup(name);
4318 free(instr);
4322 ast_copy_string(mychannel->exten, myrpt->exten, sizeof(mychannel->exten) - 1);
4323 ast_copy_string(mychannel->context, myrpt->patchcontext, sizeof(mychannel->context) - 1);
4325 if (myrpt->p.acctcode)
4326 ast_cdr_setaccount(mychannel,myrpt->p.acctcode);
4327 mychannel->priority = 1;
4328 ast_channel_undefer_dtmf(mychannel);
4329 if (ast_pbx_start(mychannel) < 0)
4331 ast_log(LOG_WARNING, "Unable to start PBX!!\n");
4332 ast_hangup(mychannel);
4333 ast_hangup(genchannel);
4334 rpt_mutex_lock(&myrpt->lock);
4335 myrpt->callmode = 0;
4336 rpt_mutex_unlock(&myrpt->lock);
4337 pthread_exit(NULL);
4339 usleep(10000);
4340 rpt_mutex_lock(&myrpt->lock);
4341 myrpt->callmode = 3;
4342 /* set appropriate conference for the pseudo */
4343 ci.chan = 0;
4344 ci.confno = myrpt->conf;
4345 ci.confmode = (myrpt->p.duplex == 2) ? DAHDI_CONF_CONFANNMON :
4346 (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
4347 /* first put the channel on the conference in announce mode */
4348 if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
4350 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
4351 ast_hangup(mychannel);
4352 ast_hangup(genchannel);
4353 myrpt->callmode = 0;
4354 pthread_exit(NULL);
4356 while(myrpt->callmode)
4358 if ((!mychannel->pbx) && (myrpt->callmode != 4))
4360 if(myrpt->patchfarenddisconnect){ /* If patch is setup for far end disconnect */
4361 myrpt->callmode = 0;
4362 if(!myrpt->patchquiet){
4363 rpt_mutex_unlock(&myrpt->lock);
4364 rpt_telemetry(myrpt, TERM, NULL);
4365 rpt_mutex_lock(&myrpt->lock);
4368 else{ /* Send congestion until patch is downed by command */
4369 myrpt->callmode = 4;
4370 rpt_mutex_unlock(&myrpt->lock);
4371 /* start congestion tone */
4372 tone_zone_play_tone(genchannel->fds[0],DAHDI_TONE_CONGESTION);
4373 rpt_mutex_lock(&myrpt->lock);
4376 if (myrpt->mydtmf)
4378 struct ast_frame wf = {AST_FRAME_DTMF, } ;
4379 wf.subclass = myrpt->mydtmf;
4380 rpt_mutex_unlock(&myrpt->lock);
4381 ast_queue_frame(mychannel,&wf);
4382 ast_senddigit(genchannel,myrpt->mydtmf);
4383 rpt_mutex_lock(&myrpt->lock);
4384 myrpt->mydtmf = 0;
4386 rpt_mutex_unlock(&myrpt->lock);
4387 usleep(MSWAIT * 1000);
4388 rpt_mutex_lock(&myrpt->lock);
4390 rpt_mutex_unlock(&myrpt->lock);
4391 tone_zone_play_tone(genchannel->fds[0],-1);
4392 if (mychannel->pbx) ast_softhangup(mychannel,AST_SOFTHANGUP_DEV);
4393 ast_hangup(genchannel);
4394 rpt_mutex_lock(&myrpt->lock);
4395 myrpt->callmode = 0;
4396 rpt_mutex_unlock(&myrpt->lock);
4397 /* set appropriate conference for the pseudo */
4398 ci.chan = 0;
4399 ci.confno = myrpt->conf;
4400 ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? DAHDI_CONF_CONFANNMON :
4401 (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
4402 /* first put the channel on the conference in announce mode */
4403 if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
4405 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
4407 pthread_exit(NULL);
4410 static void send_link_dtmf(struct rpt *myrpt,char c)
4412 char str[300];
4413 struct ast_frame wf;
4414 struct rpt_link *l;
4416 snprintf(str, sizeof(str), "D %s %s %d %c", myrpt->cmdnode, myrpt->name, ++(myrpt->dtmfidx), c);
4417 wf.frametype = AST_FRAME_TEXT;
4418 wf.subclass = 0;
4419 wf.offset = 0;
4420 wf.mallocd = 0;
4421 wf.datalen = strlen(str) + 1;
4422 wf.samples = 0;
4423 l = myrpt->links.next;
4424 /* first, see if our dude is there */
4425 while(l != &myrpt->links)
4427 if (l->name[0] == '0')
4429 l = l->next;
4430 continue;
4432 /* if we found it, write it and were done */
4433 if (!strcmp(l->name,myrpt->cmdnode))
4435 wf.data = str;
4436 if (l->chan) ast_write(l->chan,&wf);
4437 return;
4439 l = l->next;
4441 l = myrpt->links.next;
4442 /* if not, give it to everyone */
4443 while(l != &myrpt->links)
4445 wf.data = str;
4446 if (l->chan) ast_write(l->chan,&wf);
4447 l = l->next;
4449 return;
4453 * Connect a link
4455 * Return values:
4456 * -1: Error
4457 * 0: Success
4458 * 1: No match yet
4459 * 2: Already connected to this node
4462 static int connect_link(struct rpt *myrpt, char* node, int mode, int perma)
4464 char *val, *s, *s1, *s2, *tele;
4465 char lstr[MAXLINKLIST],*strs[MAXLINKLIST];
4466 char tmp[300], deststr[300] = "",modechange = 0;
4467 struct rpt_link *l;
4468 int reconnects = 0;
4469 int i,n;
4470 struct dahdi_confinfo ci; /* conference info */
4472 val = node_lookup(myrpt,node);
4473 if (!val){
4474 if(strlen(node) >= myrpt->longestnode)
4475 return -1; /* No such node */
4476 return 1; /* No match yet */
4478 if(debug > 3){
4479 ast_log(LOG_NOTICE,"Connect attempt to node %s\n", node);
4480 ast_log(LOG_NOTICE,"Mode: %s\n",(mode)?"Transceive":"Monitor");
4481 ast_log(LOG_NOTICE,"Connection type: %s\n",(perma)?"Permalink":"Normal");
4484 strncpy(tmp,val,sizeof(tmp) - 1);
4485 s = tmp;
4486 s1 = strsep(&s,",");
4487 s2 = strsep(&s,",");
4488 rpt_mutex_lock(&myrpt->lock);
4489 l = myrpt->links.next;
4490 /* try to find this one in queue */
4491 while(l != &myrpt->links){
4492 if (l->name[0] == '0')
4494 l = l->next;
4495 continue;
4497 /* if found matching string */
4498 if (!strcmp(l->name, node))
4499 break;
4500 l = l->next;
4502 /* if found */
4503 if (l != &myrpt->links){
4504 /* if already in this mode, just ignore */
4505 if ((l->mode) || (!l->chan)) {
4506 rpt_mutex_unlock(&myrpt->lock);
4507 return 2; /* Already linked */
4509 reconnects = l->reconnects;
4510 rpt_mutex_unlock(&myrpt->lock);
4511 if (l->chan) ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
4512 l->retries = l->max_retries + 1;
4513 l->disced = 2;
4514 modechange = 1;
4515 } else
4517 __mklinklist(myrpt,NULL,lstr);
4518 rpt_mutex_unlock(&myrpt->lock);
4519 n = finddelim(lstr,strs,MAXLINKLIST);
4520 for(i = 0; i < n; i++)
4522 if ((*strs[i] < '0') ||
4523 (*strs[i] > '9')) strs[i]++;
4524 if (!strcmp(strs[i],node))
4526 return 2; /* Already linked */
4530 strncpy(myrpt->lastlinknode,node,MAXNODESTR - 1);
4531 /* establish call */
4532 l = malloc(sizeof(struct rpt_link));
4533 if (!l)
4535 ast_log(LOG_WARNING, "Unable to malloc\n");
4536 return -1;
4538 /* zero the silly thing */
4539 memset((char *)l,0,sizeof(struct rpt_link));
4540 l->mode = mode;
4541 l->outbound = 1;
4542 l->thisconnected = 0;
4543 strncpy(l->name, node, MAXNODESTR - 1);
4544 l->isremote = (s && ast_true(s));
4545 if (modechange) l->connected = 1;
4546 l->hasconnected = l->perma = perma;
4547 #ifdef ALLOW_LOCAL_CHANNELS
4548 if ((strncasecmp(s1,"iax2/", 5) == 0) || (strncasecmp(s1, "local/", 6) == 0))
4549 strncpy(deststr, s1, sizeof(deststr));
4550 else
4551 snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
4552 #else
4553 snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
4554 #endif
4555 tele = strchr(deststr, '/');
4556 if (!tele){
4557 ast_log(LOG_WARNING,"link3:Dial number (%s) must be in format tech/number\n",deststr);
4558 free(l);
4559 return -1;
4561 *tele++ = 0;
4562 l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL);
4563 if (l->chan){
4564 ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
4565 ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
4566 #ifdef AST_CDR_FLAG_POST_DISABLED
4567 ast_set_flag(l->chan->cdr,AST_CDR_FLAG_POST_DISABLED);
4568 #endif
4569 l->chan->whentohangup = 0;
4570 l->chan->appl = "Apprpt";
4571 l->chan->data = "(Remote Rx)";
4572 if (debug > 3)
4573 ast_log(LOG_NOTICE, "rpt (remote) initiating call to %s/%s on %s\n",
4574 deststr, tele, l->chan->name);
4575 if(l->chan->cid.cid_num)
4576 free(l->chan->cid.cid_num);
4577 l->chan->cid.cid_num = strdup(myrpt->name);
4578 ast_call(l->chan,tele,999);
4580 else {
4581 if(debug > 3)
4582 ast_log(LOG_NOTICE, "Unable to place call to %s/%s on %s\n",
4583 deststr,tele,l->chan->name);
4584 if (myrpt->p.archivedir)
4586 char str[100];
4587 sprintf(str,"LINKFAIL,%s",l->name);
4588 donodelog(myrpt,str);
4590 free(l);
4591 return -1;
4593 /* allocate a pseudo-channel thru asterisk */
4594 l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
4595 if (!l->pchan){
4596 ast_log(LOG_WARNING,"rpt connect: Sorry unable to obtain pseudo channel\n");
4597 ast_hangup(l->chan);
4598 free(l);
4599 return -1;
4601 ast_set_read_format(l->pchan, AST_FORMAT_SLINEAR);
4602 ast_set_write_format(l->pchan, AST_FORMAT_SLINEAR);
4603 #ifdef AST_CDR_FLAG_POST_DISABLED
4604 ast_set_flag(l->pchan->cdr,AST_CDR_FLAG_POST_DISABLED);
4605 #endif
4606 /* make a conference for the tx */
4607 ci.chan = 0;
4608 ci.confno = myrpt->conf;
4609 ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER;
4610 /* first put the channel on the conference in proper mode */
4611 if (ioctl(l->pchan->fds[0], DAHDI_SETCONF, &ci) == -1)
4613 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
4614 ast_hangup(l->chan);
4615 ast_hangup(l->pchan);
4616 free(l);
4617 return -1;
4619 rpt_mutex_lock(&myrpt->lock);
4620 l->reconnects = reconnects;
4621 /* insert at end of queue */
4622 l->max_retries = MAX_RETRIES;
4623 if (perma)
4624 l->max_retries = MAX_RETRIES_PERM;
4625 if (l->isremote) l->retries = l->max_retries + 1;
4626 insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
4627 __kickshort(myrpt);
4628 rpt_mutex_unlock(&myrpt->lock);
4629 return 0;
4635 * Internet linking function
4638 static int function_ilink(struct rpt *myrpt, char *param, char *digits, int command_source, struct rpt_link *mylink)
4641 char *val, *s, *s1, *s2;
4642 char tmp[300];
4643 char digitbuf[MAXNODESTR],*strs[MAXLINKLIST];
4644 char mode,perma;
4645 struct rpt_link *l;
4646 int i,r;
4648 if(!param)
4649 return DC_ERROR;
4652 if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable )
4653 return DC_ERROR;
4655 strncpy(digitbuf,digits,MAXNODESTR - 1);
4657 if(debug > 6)
4658 printf("@@@@ ilink param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
4660 switch(myatoi(param)){
4661 case 11: /* Perm Link off */
4662 case 1: /* Link off */
4663 if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
4664 strcpy(digitbuf,myrpt->lastlinknode);
4665 val = node_lookup(myrpt,digitbuf);
4666 if (!val){
4667 if(strlen(digitbuf) >= myrpt->longestnode)
4668 return DC_ERROR;
4669 break;
4671 strncpy(tmp,val,sizeof(tmp) - 1);
4672 s = tmp;
4673 s1 = strsep(&s,",");
4674 s2 = strsep(&s,",");
4675 rpt_mutex_lock(&myrpt->lock);
4676 l = myrpt->links.next;
4677 /* try to find this one in queue */
4678 while(l != &myrpt->links){
4679 if (l->name[0] == '0')
4681 l = l->next;
4682 continue;
4684 /* if found matching string */
4685 if (!strcmp(l->name, digitbuf))
4686 break;
4687 l = l->next;
4689 if (l != &myrpt->links){ /* if found */
4690 struct ast_frame wf;
4692 /* must use perm command on perm link */
4693 if ((myatoi(param) < 10) &&
4694 (l->max_retries > MAX_RETRIES))
4696 rpt_mutex_unlock(&myrpt->lock);
4697 return DC_COMPLETE;
4699 strncpy(myrpt->lastlinknode,digitbuf,MAXNODESTR - 1);
4700 l->retries = l->max_retries + 1;
4701 l->disced = 1;
4702 rpt_mutex_unlock(&myrpt->lock);
4703 wf.frametype = AST_FRAME_TEXT;
4704 wf.subclass = 0;
4705 wf.offset = 0;
4706 wf.mallocd = 0;
4707 wf.datalen = strlen(discstr) + 1;
4708 wf.samples = 0;
4709 wf.data = discstr;
4710 if (l->chan)
4712 ast_write(l->chan,&wf);
4713 if (ast_safe_sleep(l->chan,250) == -1) return DC_ERROR;
4714 ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
4716 rpt_telemetry(myrpt, COMPLETE, NULL);
4717 return DC_COMPLETE;
4719 rpt_mutex_unlock(&myrpt->lock);
4720 return DC_COMPLETE;
4721 case 2: /* Link Monitor */
4722 case 3: /* Link transceive */
4723 case 12: /* Link Monitor permanent */
4724 case 13: /* Link transceive permanent */
4725 if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
4726 strcpy(digitbuf,myrpt->lastlinknode);
4727 /* Attempt connection */
4728 perma = (atoi(param) > 10) ? 1 : 0;
4729 mode = (atoi(param) & 1) ? 1 : 0;
4730 r = connect_link(myrpt, digitbuf, mode, perma);
4731 switch(r){
4732 case 0:
4733 rpt_telemetry(myrpt, COMPLETE, NULL);
4734 return DC_COMPLETE;
4736 case 1:
4737 break;
4739 case 2:
4740 rpt_telemetry(myrpt, REMALREADY, NULL);
4741 return DC_COMPLETE;
4743 default:
4744 rpt_telemetry(myrpt, CONNFAIL, NULL);
4745 return DC_COMPLETE;
4747 break;
4749 case 4: /* Enter Command Mode */
4751 /* if doesnt allow link cmd, or no links active, return */
4752 if (((command_source != SOURCE_RPT) &&
4753 (command_source != SOURCE_PHONE) &&
4754 (command_source != SOURCE_DPHONE)) ||
4755 (myrpt->links.next == &myrpt->links))
4756 return DC_COMPLETE;
4758 /* if already in cmd mode, or selected self, fughetabahtit */
4759 if ((myrpt->cmdnode[0]) || (!strcmp(myrpt->name, digitbuf))){
4761 rpt_telemetry(myrpt, REMALREADY, NULL);
4762 return DC_COMPLETE;
4764 if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
4765 strcpy(digitbuf,myrpt->lastlinknode);
4766 /* node must at least exist in list */
4767 val = node_lookup(myrpt,digitbuf);
4768 if (!val){
4769 if(strlen(digitbuf) >= myrpt->longestnode)
4770 return DC_ERROR;
4771 break;
4774 rpt_mutex_lock(&myrpt->lock);
4775 strcpy(myrpt->lastlinknode,digitbuf);
4776 strncpy(myrpt->cmdnode, digitbuf, sizeof(myrpt->cmdnode) - 1);
4777 rpt_mutex_unlock(&myrpt->lock);
4778 rpt_telemetry(myrpt, REMGO, NULL);
4779 return DC_COMPLETE;
4781 case 5: /* Status */
4782 rpt_telemetry(myrpt, STATUS, NULL);
4783 return DC_COMPLETE;
4785 case 15: /* Full Status */
4786 rpt_telemetry(myrpt, FULLSTATUS, NULL);
4787 return DC_COMPLETE;
4790 case 6: /* All Links Off, including permalinks */
4791 rpt_mutex_lock(&myrpt->lock);
4792 myrpt->savednodes[0] = 0;
4793 l = myrpt->links.next;
4794 /* loop through all links */
4795 while(l != &myrpt->links){
4796 struct ast_frame wf;
4797 if (l->name[0] == '0') /* Skip any IAXRPT monitoring */
4799 l = l->next;
4800 continue;
4802 /* Make a string of disconnected nodes for possible restoration */
4803 sprintf(tmp,"%c%c%s",(l->mode) ? 'X' : 'M',(l->perma) ? 'P':'T',l->name);
4804 if(strlen(tmp) + strlen(myrpt->savednodes) + 1 < MAXNODESTR){
4805 if(myrpt->savednodes[0])
4806 strcat(myrpt->savednodes, ",");
4807 strcat(myrpt->savednodes, tmp);
4809 l->retries = l->max_retries + 1;
4810 l->disced = 2; /* Silently disconnect */
4811 rpt_mutex_unlock(&myrpt->lock);
4812 /* ast_log(LOG_NOTICE,"dumping link %s\n",l->name); */
4814 wf.frametype = AST_FRAME_TEXT;
4815 wf.subclass = 0;
4816 wf.offset = 0;
4817 wf.mallocd = 0;
4818 wf.datalen = strlen(discstr) + 1;
4819 wf.samples = 0;
4820 wf.data = discstr;
4821 if (l->chan)
4823 ast_write(l->chan,&wf);
4824 ast_safe_sleep(l->chan,250); /* It's dead already, why check the return value? */
4825 ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
4827 rpt_mutex_lock(&myrpt->lock);
4828 l = l->next;
4830 rpt_mutex_unlock(&myrpt->lock);
4831 if(debug > 3)
4832 ast_log(LOG_NOTICE,"Nodes disconnected: %s\n",myrpt->savednodes);
4833 rpt_telemetry(myrpt, COMPLETE, NULL);
4834 return DC_COMPLETE;
4836 case 7: /* Identify last node which keyed us up */
4837 rpt_telemetry(myrpt, LASTNODEKEY, NULL);
4838 break;
4841 #ifdef _MDC_DECODE_H_
4842 case 8:
4843 myrpt->lastunit = 0xd00d;
4844 mdc1200_notify(myrpt,NULL,myrpt->lastunit);
4845 mdc1200_send(myrpt,myrpt->lastunit);
4846 break;
4847 #endif
4849 case 16: /* Restore links disconnected with "disconnect all links" command */
4850 strcpy(tmp, myrpt->savednodes); /* Make a copy */
4851 finddelim(tmp, strs, MAXLINKLIST); /* convert into substrings */
4852 for(i = 0; tmp[0] && strs[i] != NULL && i < MAXLINKLIST; i++){
4853 s1 = strs[i];
4854 mode = (s1[0] == 'X') ? 1 : 0;
4855 perma = (s1[1] == 'P') ? 1 : 0;
4856 connect_link(myrpt, s1 + 2, mode, perma); /* Try to reconnect */
4858 rpt_telemetry(myrpt, COMPLETE, NULL);
4859 break;
4861 case 200:
4862 case 201:
4863 case 202:
4864 case 203:
4865 case 204:
4866 case 205:
4867 case 206:
4868 case 207:
4869 case 208:
4870 case 209:
4871 case 210:
4872 case 211:
4873 case 212:
4874 case 213:
4875 case 214:
4876 case 215:
4877 if (((myrpt->p.propagate_dtmf) &&
4878 (command_source == SOURCE_LNK)) ||
4879 ((myrpt->p.propagate_phonedtmf) &&
4880 ((command_source == SOURCE_PHONE) ||
4881 (command_source == SOURCE_DPHONE))))
4882 do_dtmf_local(myrpt,
4883 remdtmfstr[myatoi(param) - 200]);
4884 default:
4885 return DC_ERROR;
4889 return DC_INDETERMINATE;
4893 * Autopatch up
4896 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
4898 pthread_attr_t attr;
4899 int i, index, paramlength;
4900 char *lparam;
4901 char *value = NULL;
4902 char *paramlist[20];
4904 static char *keywords[] = {
4905 "context",
4906 "dialtime",
4907 "farenddisconnect",
4908 "noct",
4909 "quiet",
4910 NULL
4913 if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
4914 return DC_ERROR;
4916 if(debug)
4917 printf("@@@@ Autopatch up\n");
4919 if(!myrpt->callmode){
4920 /* Set defaults */
4921 myrpt->patchnoct = 0;
4922 myrpt->patchdialtime = 0;
4923 myrpt->patchfarenddisconnect = 0;
4924 myrpt->patchquiet = 0;
4925 strncpy(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
4927 if(param){
4928 /* Process parameter list */
4929 lparam = ast_strdupa(param);
4930 if(!lparam){
4931 ast_log(LOG_ERROR,"App_rpt out of memory on line %d\n",__LINE__);
4932 return DC_ERROR;
4934 paramlength = finddelim(lparam, paramlist, 20);
4935 for(i = 0; i < paramlength; i++){
4936 index = matchkeyword(paramlist[i], &value, keywords);
4937 if(value)
4938 value = skipchars(value, "= ");
4939 switch(index){
4941 case 1: /* context */
4942 strncpy(myrpt->patchcontext, value, MAXPATCHCONTEXT - 1) ;
4943 break;
4945 case 2: /* dialtime */
4946 myrpt->patchdialtime = atoi(value);
4947 break;
4949 case 3: /* farenddisconnect */
4950 myrpt->patchfarenddisconnect = atoi(value);
4951 break;
4953 case 4: /* noct */
4954 myrpt->patchnoct = atoi(value);
4955 break;
4957 case 5: /* quiet */
4958 myrpt->patchquiet = atoi(value);
4959 break;
4961 default:
4962 break;
4968 rpt_mutex_lock(&myrpt->lock);
4970 /* if on call, force * into current audio stream */
4972 if ((myrpt->callmode == 2) || (myrpt->callmode == 3)){
4973 myrpt->mydtmf = myrpt->p.endchar;
4975 if (myrpt->callmode){
4976 rpt_mutex_unlock(&myrpt->lock);
4977 return DC_COMPLETE;
4979 myrpt->callmode = 1;
4980 myrpt->cidx = 0;
4981 myrpt->exten[myrpt->cidx] = 0;
4982 rpt_mutex_unlock(&myrpt->lock);
4983 pthread_attr_init(&attr);
4984 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
4985 ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *) myrpt);
4986 return DC_COMPLETE;
4990 * Autopatch down
4993 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
4995 if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
4996 return DC_ERROR;
4998 if(debug)
4999 printf("@@@@ Autopatch down\n");
5001 rpt_mutex_lock(&myrpt->lock);
5003 if (!myrpt->callmode){
5004 rpt_mutex_unlock(&myrpt->lock);
5005 return DC_COMPLETE;
5008 myrpt->callmode = 0;
5009 rpt_mutex_unlock(&myrpt->lock);
5010 rpt_telemetry(myrpt, TERM, NULL);
5011 return DC_COMPLETE;
5015 * Status
5018 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
5021 if (!param)
5022 return DC_ERROR;
5024 if ((myrpt->p.s[myrpt->p.sysstate_cur].txdisable) || (myrpt->p.s[myrpt->p.sysstate_cur].userfundisable))
5025 return DC_ERROR;
5027 if(debug)
5028 printf("@@@@ status param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
5030 switch(myatoi(param)){
5031 case 1: /* System ID */
5032 rpt_telemetry(myrpt, ID1, NULL);
5033 return DC_COMPLETE;
5034 case 2: /* System Time */
5035 rpt_telemetry(myrpt, STATS_TIME, NULL);
5036 return DC_COMPLETE;
5037 case 3: /* app_rpt.c version */
5038 rpt_telemetry(myrpt, STATS_VERSION, NULL);
5039 default:
5040 return DC_ERROR;
5042 return DC_INDETERMINATE;
5046 * Macro-oni (without Salami)
5049 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
5052 char *val;
5053 int i;
5054 if (myrpt->remote)
5055 return DC_ERROR;
5057 if(debug)
5058 printf("@@@@ macro-oni param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
5060 if(strlen(digitbuf) < 1) /* needs 1 digit */
5061 return DC_INDETERMINATE;
5063 for(i = 0 ; i < digitbuf[i] ; i++) {
5064 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
5065 return DC_ERROR;
5068 if (*digitbuf == '0') val = myrpt->p.startupmacro;
5069 else val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, digitbuf);
5070 /* param was 1 for local buf */
5071 if (!val){
5072 if (strlen(digitbuf) < myrpt->macro_longest)
5073 return DC_INDETERMINATE;
5074 rpt_telemetry(myrpt, MACRO_NOTFOUND, NULL);
5075 return DC_COMPLETE;
5077 rpt_mutex_lock(&myrpt->lock);
5078 if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val))
5080 rpt_mutex_unlock(&myrpt->lock);
5081 rpt_telemetry(myrpt, MACRO_BUSY, NULL);
5082 return DC_ERROR;
5084 myrpt->macrotimer = MACROTIME;
5085 strncat(myrpt->macrobuf, val, MAXMACRO - strlen(myrpt->macrobuf) - 1);
5086 rpt_mutex_unlock(&myrpt->lock);
5087 return DC_COMPLETE;
5091 * COP - Control operator
5094 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
5096 char string[16];
5098 if(!param)
5099 return DC_ERROR;
5101 switch(myatoi(param)){
5102 case 1: /* System reset */
5103 system("killall -9 asterisk");
5104 return DC_COMPLETE;
5106 case 2:
5107 myrpt->p.s[myrpt->p.sysstate_cur].txdisable = 0;
5108 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "RPTENA");
5109 return DC_COMPLETE;
5111 case 3:
5112 myrpt->p.s[myrpt->p.sysstate_cur].txdisable = 1;
5113 return DC_COMPLETE;
5115 case 4: /* test tone on */
5116 if (myrpt->stopgen < 0)
5118 myrpt->stopgen = 1;
5120 else
5122 myrpt->stopgen = 0;
5123 rpt_telemetry(myrpt, TEST_TONE, NULL);
5125 return DC_COMPLETE;
5127 case 5: /* Disgorge variables to log for debug purposes */
5128 myrpt->disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
5129 return DC_COMPLETE;
5131 case 6: /* Simulate COR being activated (phone only) */
5132 if (command_source != SOURCE_PHONE) return DC_INDETERMINATE;
5133 return DC_DOKEY;
5136 case 7: /* Time out timer enable */
5137 myrpt->p.s[myrpt->p.sysstate_cur].totdisable = 0;
5138 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "TOTENA");
5139 return DC_COMPLETE;
5141 case 8: /* Time out timer disable */
5142 myrpt->p.s[myrpt->p.sysstate_cur].totdisable = 1;
5143 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "TOTDIS");
5144 return DC_COMPLETE;
5146 case 9: /* Autopatch enable */
5147 myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable = 0;
5148 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "APENA");
5149 return DC_COMPLETE;
5151 case 10: /* Autopatch disable */
5152 myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable = 1;
5153 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "APDIS");
5154 return DC_COMPLETE;
5156 case 11: /* Link Enable */
5157 myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable = 0;
5158 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "LNKENA");
5159 return DC_COMPLETE;
5161 case 12: /* Link Disable */
5162 myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable = 1;
5163 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "LNKDIS");
5164 return DC_COMPLETE;
5166 case 13: /* Query System State */
5167 string[0] = string[1] = 'S';
5168 string[2] = myrpt->p.sysstate_cur + '0';
5169 string[3] = '\0';
5170 rpt_telemetry(myrpt, ARB_ALPHA, (void *) string);
5171 return DC_COMPLETE;
5173 case 14: /* Change System State */
5174 if(strlen(digitbuf) == 0)
5175 break;
5176 if((digitbuf[0] < '0') || (digitbuf[0] > '9'))
5177 return DC_ERROR;
5178 myrpt->p.sysstate_cur = digitbuf[0] - '0';
5179 string[0] = string[1] = 'S';
5180 string[2] = myrpt->p.sysstate_cur + '0';
5181 string[3] = '\0';
5182 rpt_telemetry(myrpt, ARB_ALPHA, (void *) string);
5183 return DC_COMPLETE;
5185 case 15: /* Scheduler Enable */
5186 myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable = 0;
5187 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "SKENA");
5188 return DC_COMPLETE;
5190 case 16: /* Scheduler Disable */
5191 myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable = 1;
5192 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "SKDIS");
5193 return DC_COMPLETE;
5195 case 17: /* User functions Enable */
5196 myrpt->p.s[myrpt->p.sysstate_cur].userfundisable = 0;
5197 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "UFENA");
5198 return DC_COMPLETE;
5200 case 18: /* User Functions Disable */
5201 myrpt->p.s[myrpt->p.sysstate_cur].userfundisable = 1;
5202 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "UFDIS");
5203 return DC_COMPLETE;
5205 case 19: /* Alternate Tail Enable */
5206 myrpt->p.s[myrpt->p.sysstate_cur].alternatetail = 1;
5207 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "ATENA");
5208 return DC_COMPLETE;
5210 case 20: /* Alternate Tail Disable */
5211 myrpt->p.s[myrpt->p.sysstate_cur].alternatetail = 0;
5212 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "ATDIS");
5213 return DC_COMPLETE;
5215 return DC_INDETERMINATE;
5219 * Collect digits one by one until something matches
5222 static int collect_function_digits(struct rpt *myrpt, char *digits,
5223 int command_source, struct rpt_link *mylink)
5225 int i;
5226 char *stringp,*action,*param,*functiondigits;
5227 char function_table_name[30] = "";
5228 char workstring[200];
5230 struct ast_variable *vp;
5232 if(debug)
5233 printf("@@@@ Digits collected: %s, source: %d\n", digits, command_source);
5235 if (command_source == SOURCE_DPHONE) {
5236 if (!myrpt->p.dphone_functions) return DC_INDETERMINATE;
5237 strncpy(function_table_name, myrpt->p.dphone_functions, sizeof(function_table_name) - 1);
5239 else if (command_source == SOURCE_PHONE) {
5240 if (!myrpt->p.phone_functions) return DC_INDETERMINATE;
5241 strncpy(function_table_name, myrpt->p.phone_functions, sizeof(function_table_name) - 1);
5243 else if (command_source == SOURCE_LNK)
5244 strncpy(function_table_name, myrpt->p.link_functions, sizeof(function_table_name) - 1);
5245 else
5246 strncpy(function_table_name, myrpt->p.functions, sizeof(function_table_name) - 1);
5247 vp = ast_variable_browse(myrpt->cfg, function_table_name);
5248 while(vp) {
5249 if(!strncasecmp(vp->name, digits, strlen(vp->name)))
5250 break;
5251 vp = vp->next;
5253 if(!vp) {
5254 int n;
5256 n = myrpt->longestfunc;
5257 if (command_source == SOURCE_LNK) n = myrpt->link_longestfunc;
5258 else
5259 if (command_source == SOURCE_PHONE) n = myrpt->phone_longestfunc;
5260 else
5261 if (command_source == SOURCE_DPHONE) n = myrpt->dphone_longestfunc;
5263 if(strlen(digits) >= n)
5264 return DC_ERROR;
5265 else
5266 return DC_INDETERMINATE;
5268 /* Found a match, retrieve value part and parse */
5269 strncpy(workstring, vp->value, sizeof(workstring) - 1 );
5270 stringp = workstring;
5271 action = strsep(&stringp, ",");
5272 param = stringp;
5273 if(debug)
5274 printf("@@@@ action: %s, param = %s\n",action, (param) ? param : "(null)");
5275 /* Look up the action */
5276 for(i = 0 ; i < (sizeof(function_table)/sizeof(struct function_table_tag)); i++){
5277 if(!strncasecmp(action, function_table[i].action, strlen(action)))
5278 break;
5280 if(debug)
5281 printf("@@@@ table index i = %d\n",i);
5282 if(i == (sizeof(function_table)/sizeof(struct function_table_tag))){
5283 /* Error, action not in table */
5284 return DC_ERROR;
5286 if(function_table[i].function == NULL){
5287 /* Error, function undefined */
5288 if(debug)
5289 printf("@@@@ NULL for action: %s\n",action);
5290 return DC_ERROR;
5292 functiondigits = digits + strlen(vp->name);
5293 return (*function_table[i].function)(myrpt, param, functiondigits, command_source, mylink);
5297 static void handle_link_data(struct rpt *myrpt, struct rpt_link *mylink,
5298 char *str)
5300 char tmp[512],cmd[300] = "",dest[300],src[300],c;
5301 int seq, res;
5302 struct rpt_link *l;
5303 struct ast_frame wf;
5305 wf.frametype = AST_FRAME_TEXT;
5306 wf.subclass = 0;
5307 wf.offset = 0;
5308 wf.mallocd = 0;
5309 wf.datalen = strlen(str) + 1;
5310 wf.samples = 0;
5311 /* put string in our buffer */
5312 strncpy(tmp,str,sizeof(tmp) - 1);
5314 if (!strcmp(tmp,discstr))
5316 mylink->disced = 1;
5317 mylink->retries = mylink->max_retries + 1;
5318 ast_softhangup(mylink->chan,AST_SOFTHANGUP_DEV);
5319 return;
5321 if (tmp[0] == 'L')
5323 rpt_mutex_lock(&myrpt->lock);
5324 strcpy(mylink->linklist,tmp + 2);
5325 time(&mylink->linklistreceived);
5326 rpt_mutex_unlock(&myrpt->lock);
5327 if (debug > 6) ast_log(LOG_NOTICE,"@@@@ node %s recieved node list %s from node %s\n",
5328 myrpt->name,tmp,mylink->name);
5329 return;
5331 if (tmp[0] == 'I')
5333 if (sscanf(tmp,"%s %s %x",cmd,src,&seq) != 3)
5335 ast_log(LOG_WARNING, "Unable to parse ident string %s\n",str);
5336 return;
5338 mdc1200_notify(myrpt,src,seq);
5339 strcpy(dest,"*");
5341 else
5343 if (sscanf(tmp,"%s %s %s %d %c",cmd,dest,src,&seq,&c) != 5)
5345 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
5346 return;
5348 if (strcmp(cmd,"D"))
5350 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
5351 return;
5354 if (dest[0] == '0')
5356 strcpy(dest,myrpt->name);
5359 /* if not for me, redistribute to all links */
5360 if (strcmp(dest,myrpt->name))
5362 l = myrpt->links.next;
5363 /* see if this is one in list */
5364 while(l != &myrpt->links)
5366 if (l->name[0] == '0')
5368 l = l->next;
5369 continue;
5371 /* dont send back from where it came */
5372 if ((l == mylink) || (!strcmp(l->name,mylink->name)))
5374 l = l->next;
5375 continue;
5377 /* if it is, send it and we're done */
5378 if (!strcmp(l->name,dest))
5380 /* send, but not to src */
5381 if (strcmp(l->name,src)) {
5382 wf.data = str;
5383 if (l->chan) ast_write(l->chan,&wf);
5385 return;
5387 l = l->next;
5389 l = myrpt->links.next;
5390 /* otherwise, send it to all of em */
5391 while(l != &myrpt->links)
5393 if (l->name[0] == '0')
5395 l = l->next;
5396 continue;
5398 /* dont send back from where it came */
5399 if ((l == mylink) || (!strcmp(l->name,mylink->name)))
5401 l = l->next;
5402 continue;
5404 /* send, but not to src */
5405 if (strcmp(l->name,src)) {
5406 wf.data = str;
5407 if (l->chan) ast_write(l->chan,&wf);
5409 l = l->next;
5411 return;
5413 if (myrpt->p.archivedir)
5415 char str[100];
5417 sprintf(str,"DTMF,%s,%c",mylink->name,c);
5418 donodelog(myrpt,str);
5420 c = func_xlat(myrpt,c,&myrpt->p.outxlat);
5421 if (!c) return;
5422 rpt_mutex_lock(&myrpt->lock);
5423 if (c == myrpt->p.endchar) myrpt->stopgen = 1;
5424 if (myrpt->callmode == 1)
5426 myrpt->exten[myrpt->cidx++] = c;
5427 myrpt->exten[myrpt->cidx] = 0;
5428 /* if this exists */
5429 if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
5431 myrpt->callmode = 2;
5432 if(!myrpt->patchquiet){
5433 rpt_mutex_unlock(&myrpt->lock);
5434 rpt_telemetry(myrpt,PROC,NULL);
5435 rpt_mutex_lock(&myrpt->lock);
5438 /* if can continue, do so */
5439 if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
5441 /* call has failed, inform user */
5442 myrpt->callmode = 4;
5445 if (c == myrpt->p.funcchar)
5447 myrpt->rem_dtmfidx = 0;
5448 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
5449 time(&myrpt->rem_dtmf_time);
5450 rpt_mutex_unlock(&myrpt->lock);
5451 return;
5453 else if (myrpt->rem_dtmfidx < 0)
5455 if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
5457 myrpt->mydtmf = c;
5459 if (myrpt->p.propagate_dtmf) do_dtmf_local(myrpt,c);
5460 if (myrpt->p.propagate_phonedtmf) do_dtmf_phone(myrpt,mylink,c);
5461 rpt_mutex_unlock(&myrpt->lock);
5462 return;
5464 else if ((c != myrpt->p.endchar) && (myrpt->rem_dtmfidx >= 0))
5466 time(&myrpt->rem_dtmf_time);
5467 if (myrpt->rem_dtmfidx < MAXDTMF)
5469 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
5470 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
5472 rpt_mutex_unlock(&myrpt->lock);
5473 strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
5474 res = collect_function_digits(myrpt, cmd, SOURCE_LNK, mylink);
5475 rpt_mutex_lock(&myrpt->lock);
5477 switch(res){
5479 case DC_INDETERMINATE:
5480 break;
5482 case DC_REQ_FLUSH:
5483 myrpt->rem_dtmfidx = 0;
5484 myrpt->rem_dtmfbuf[0] = 0;
5485 break;
5488 case DC_COMPLETE:
5489 case DC_COMPLETEQUIET:
5490 myrpt->totalexecdcommands++;
5491 myrpt->dailyexecdcommands++;
5492 strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
5493 myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
5494 myrpt->rem_dtmfbuf[0] = 0;
5495 myrpt->rem_dtmfidx = -1;
5496 myrpt->rem_dtmf_time = 0;
5497 break;
5499 case DC_ERROR:
5500 default:
5501 myrpt->rem_dtmfbuf[0] = 0;
5502 myrpt->rem_dtmfidx = -1;
5503 myrpt->rem_dtmf_time = 0;
5504 break;
5509 rpt_mutex_unlock(&myrpt->lock);
5510 return;
5513 static void handle_link_phone_dtmf(struct rpt *myrpt, struct rpt_link *mylink,
5514 char c)
5517 char cmd[300];
5518 int res;
5520 if (myrpt->p.archivedir)
5522 char str[100];
5524 sprintf(str,"DTMF(P),%s,%c",mylink->name,c);
5525 donodelog(myrpt,str);
5527 rpt_mutex_lock(&myrpt->lock);
5528 if (c == myrpt->p.endchar)
5530 if (mylink->lastrx)
5532 mylink->lastrx = 0;
5533 rpt_mutex_unlock(&myrpt->lock);
5534 return;
5536 myrpt->stopgen = 1;
5537 if (myrpt->cmdnode[0])
5539 myrpt->cmdnode[0] = 0;
5540 myrpt->dtmfidx = -1;
5541 myrpt->dtmfbuf[0] = 0;
5542 rpt_mutex_unlock(&myrpt->lock);
5543 rpt_telemetry(myrpt,COMPLETE,NULL);
5544 return;
5547 if (myrpt->cmdnode[0])
5549 rpt_mutex_unlock(&myrpt->lock);
5550 send_link_dtmf(myrpt,c);
5551 return;
5553 if (myrpt->callmode == 1)
5555 myrpt->exten[myrpt->cidx++] = c;
5556 myrpt->exten[myrpt->cidx] = 0;
5557 /* if this exists */
5558 if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
5560 myrpt->callmode = 2;
5561 if(!myrpt->patchquiet){
5562 rpt_mutex_unlock(&myrpt->lock);
5563 rpt_telemetry(myrpt,PROC,NULL);
5564 rpt_mutex_lock(&myrpt->lock);
5567 /* if can continue, do so */
5568 if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
5570 /* call has failed, inform user */
5571 myrpt->callmode = 4;
5574 if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
5576 myrpt->mydtmf = c;
5578 if (c == myrpt->p.funcchar)
5580 myrpt->rem_dtmfidx = 0;
5581 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
5582 time(&myrpt->rem_dtmf_time);
5583 rpt_mutex_unlock(&myrpt->lock);
5584 return;
5586 else if ((c != myrpt->p.endchar) && (myrpt->rem_dtmfidx >= 0))
5588 time(&myrpt->rem_dtmf_time);
5589 if (myrpt->rem_dtmfidx < MAXDTMF)
5591 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
5592 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
5594 rpt_mutex_unlock(&myrpt->lock);
5595 strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
5596 switch(mylink->phonemode)
5598 case 1:
5599 res = collect_function_digits(myrpt, cmd,
5600 SOURCE_PHONE, mylink);
5601 break;
5602 case 2:
5603 res = collect_function_digits(myrpt, cmd,
5604 SOURCE_DPHONE,mylink);
5605 break;
5606 default:
5607 res = collect_function_digits(myrpt, cmd,
5608 SOURCE_LNK, mylink);
5609 break;
5612 rpt_mutex_lock(&myrpt->lock);
5614 switch(res){
5616 case DC_INDETERMINATE:
5617 break;
5619 case DC_DOKEY:
5620 mylink->lastrx = 1;
5621 break;
5623 case DC_REQ_FLUSH:
5624 myrpt->rem_dtmfidx = 0;
5625 myrpt->rem_dtmfbuf[0] = 0;
5626 break;
5629 case DC_COMPLETE:
5630 case DC_COMPLETEQUIET:
5631 myrpt->totalexecdcommands++;
5632 myrpt->dailyexecdcommands++;
5633 strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
5634 myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
5635 myrpt->rem_dtmfbuf[0] = 0;
5636 myrpt->rem_dtmfidx = -1;
5637 myrpt->rem_dtmf_time = 0;
5638 break;
5640 case DC_ERROR:
5641 default:
5642 myrpt->rem_dtmfbuf[0] = 0;
5643 myrpt->rem_dtmfidx = -1;
5644 myrpt->rem_dtmf_time = 0;
5645 break;
5650 rpt_mutex_unlock(&myrpt->lock);
5651 return;
5654 /* Doug Hall RBI-1 serial data definitions:
5656 * Byte 0: Expansion external outputs
5657 * Byte 1:
5658 * Bits 0-3 are BAND as follows:
5659 * Bits 4-5 are POWER bits as follows:
5660 * 00 - Low Power
5661 * 01 - Hi Power
5662 * 02 - Med Power
5663 * Bits 6-7 are always set
5664 * Byte 2:
5665 * Bits 0-3 MHZ in BCD format
5666 * Bits 4-5 are offset as follows:
5667 * 00 - minus
5668 * 01 - plus
5669 * 02 - simplex
5670 * 03 - minus minus (whatever that is)
5671 * Bit 6 is the 0/5 KHZ bit
5672 * Bit 7 is always set
5673 * Byte 3:
5674 * Bits 0-3 are 10 KHZ in BCD format
5675 * Bits 4-7 are 100 KHZ in BCD format
5676 * Byte 4: PL Tone code and encode/decode enable bits
5677 * Bits 0-5 are PL tone code (comspec binary codes)
5678 * Bit 6 is encode enable/disable
5679 * Bit 7 is decode enable/disable
5682 /* take the frequency from the 10 mhz digits (and up) and convert it
5683 to a band number */
5685 static int rbi_mhztoband(char *str)
5687 int i;
5689 i = atoi(str) / 10; /* get the 10's of mhz */
5690 switch(i)
5692 case 2:
5693 return 10;
5694 case 5:
5695 return 11;
5696 case 14:
5697 return 2;
5698 case 22:
5699 return 3;
5700 case 44:
5701 return 4;
5702 case 124:
5703 return 0;
5704 case 125:
5705 return 1;
5706 case 126:
5707 return 8;
5708 case 127:
5709 return 5;
5710 case 128:
5711 return 6;
5712 case 129:
5713 return 7;
5714 default:
5715 break;
5717 return -1;
5720 /* take a PL frequency and turn it into a code */
5721 static int rbi_pltocode(char *str)
5723 int i;
5724 char *s;
5726 s = strchr(str,'.');
5727 i = 0;
5728 if (s) i = atoi(s + 1);
5729 i += atoi(str) * 10;
5730 switch(i)
5732 case 670:
5733 return 0;
5734 case 719:
5735 return 1;
5736 case 744:
5737 return 2;
5738 case 770:
5739 return 3;
5740 case 797:
5741 return 4;
5742 case 825:
5743 return 5;
5744 case 854:
5745 return 6;
5746 case 885:
5747 return 7;
5748 case 915:
5749 return 8;
5750 case 948:
5751 return 9;
5752 case 974:
5753 return 10;
5754 case 1000:
5755 return 11;
5756 case 1035:
5757 return 12;
5758 case 1072:
5759 return 13;
5760 case 1109:
5761 return 14;
5762 case 1148:
5763 return 15;
5764 case 1188:
5765 return 16;
5766 case 1230:
5767 return 17;
5768 case 1273:
5769 return 18;
5770 case 1318:
5771 return 19;
5772 case 1365:
5773 return 20;
5774 case 1413:
5775 return 21;
5776 case 1462:
5777 return 22;
5778 case 1514:
5779 return 23;
5780 case 1567:
5781 return 24;
5782 case 1622:
5783 return 25;
5784 case 1679:
5785 return 26;
5786 case 1738:
5787 return 27;
5788 case 1799:
5789 return 28;
5790 case 1862:
5791 return 29;
5792 case 1928:
5793 return 30;
5794 case 2035:
5795 return 31;
5796 case 2107:
5797 return 32;
5798 case 2181:
5799 return 33;
5800 case 2257:
5801 return 34;
5802 case 2336:
5803 return 35;
5804 case 2418:
5805 return 36;
5806 case 2503:
5807 return 37;
5809 return -1;
5813 * Shift out a formatted serial bit stream
5816 static void rbi_out_parallel(struct rpt *myrpt,unsigned char *data)
5818 #ifdef __i386__
5819 int i,j;
5820 unsigned char od,d;
5821 static volatile long long delayvar;
5823 for(i = 0 ; i < 5 ; i++){
5824 od = *data++;
5825 for(j = 0 ; j < 8 ; j++){
5826 d = od & 1;
5827 outb(d,myrpt->p.iobase);
5828 /* >= 15 us */
5829 for(delayvar = 1; delayvar < 15000; delayvar++);
5830 od >>= 1;
5831 outb(d | 2,myrpt->p.iobase);
5832 /* >= 30 us */
5833 for(delayvar = 1; delayvar < 30000; delayvar++);
5834 outb(d,myrpt->p.iobase);
5835 /* >= 10 us */
5836 for(delayvar = 1; delayvar < 10000; delayvar++);
5839 /* >= 50 us */
5840 for(delayvar = 1; delayvar < 50000; delayvar++);
5841 #endif
5844 static void rbi_out(struct rpt *myrpt,unsigned char *data)
5846 struct dahdi_radio_param r;
5848 memset(&r,0,sizeof(struct dahdi_radio_param));
5849 r.radpar = DAHDI_RADPAR_REMMODE;
5850 r.data = DAHDI_RADPAR_REM_RBI1;
5851 /* if setparam ioctl fails, its probably not a pciradio card */
5852 if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_SETPARAM,&r) == -1)
5854 rbi_out_parallel(myrpt,data);
5855 return;
5857 r.radpar = DAHDI_RADPAR_REMCOMMAND;
5858 memcpy(&r.data,data,5);
5859 if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_SETPARAM,&r) == -1)
5861 ast_log(LOG_WARNING,"Cannot send RBI command for channel %s\n",myrpt->zaprxchannel->name);
5862 return;
5866 static int serial_remote_io(struct rpt *myrpt, unsigned char *txbuf, int txbytes,
5867 unsigned char *rxbuf, int rxmaxbytes, int asciiflag)
5869 int i,j,index,oldmode,olddata;
5870 struct dahdi_radio_param prm;
5871 char c;
5873 if(debug){
5874 printf("String output was: ");
5875 for(i = 0; i < txbytes; i++)
5876 printf("%02X ", (unsigned char ) txbuf[i]);
5877 printf("\n");
5879 if (myrpt->iofd > 0) /* if to do out a serial port */
5881 if (rxmaxbytes && rxbuf) tcflush(myrpt->iofd,TCIFLUSH);
5882 if (write(myrpt->iofd,txbuf,txbytes) != txbytes) return -1;
5883 if ((!rxmaxbytes) || (rxbuf == NULL)) return(0);
5884 memset(rxbuf,0,rxmaxbytes);
5885 for(i = 0; i < rxmaxbytes; i++)
5887 j = read(myrpt->iofd,&c,1);
5888 if (j < 1) return(i);
5889 rxbuf[i] = c;
5890 if (asciiflag & 1)
5892 rxbuf[i + 1] = 0;
5893 if (c == '\r') break;
5896 if(debug){
5897 printf("String returned was: ");
5898 for(j = 0; j < i; j++)
5899 printf("%02X ", (unsigned char ) rxbuf[j]);
5900 printf("\n");
5902 return(i);
5905 /* if not a zap channel, cant use pciradio stuff */
5906 if (myrpt->rxchannel != myrpt->zaprxchannel) return -1;
5908 prm.radpar = DAHDI_RADPAR_UIOMODE;
5909 if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_GETPARAM,&prm) == -1) return -1;
5910 oldmode = prm.data;
5911 prm.radpar = DAHDI_RADPAR_UIODATA;
5912 if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_GETPARAM,&prm) == -1) return -1;
5913 olddata = prm.data;
5914 prm.radpar = DAHDI_RADPAR_REMMODE;
5915 if (asciiflag & 1) prm.data = DAHDI_RADPAR_REM_SERIAL_ASCII;
5916 else prm.data = DAHDI_RADPAR_REM_SERIAL;
5917 if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
5918 if (asciiflag & 2)
5920 i = DAHDI_ONHOOK;
5921 if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_HOOK,&i) == -1) return -1;
5922 usleep(100000);
5924 prm.radpar = DAHDI_RADPAR_REMCOMMAND;
5925 prm.data = rxmaxbytes;
5926 memcpy(prm.buf,txbuf,txbytes);
5927 prm.index = txbytes;
5928 if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
5929 if (rxbuf)
5931 *rxbuf = 0;
5932 memcpy(rxbuf,prm.buf,prm.index);
5934 index = prm.index;
5935 prm.radpar = DAHDI_RADPAR_REMMODE;
5936 prm.data = DAHDI_RADPAR_REM_NONE;
5937 if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
5938 if (asciiflag & 2)
5940 i = DAHDI_OFFHOOK;
5941 if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_HOOK,&i) == -1) return -1;
5943 prm.radpar = DAHDI_RADPAR_UIOMODE;
5944 prm.data = oldmode;
5945 if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
5946 prm.radpar = DAHDI_RADPAR_UIODATA;
5947 prm.data = olddata;
5948 if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
5949 return(index);
5952 static int civ_cmd(struct rpt *myrpt,unsigned char *cmd, int cmdlen)
5954 unsigned char rxbuf[100];
5955 int i,rv ;
5957 rv = serial_remote_io(myrpt,cmd,cmdlen,rxbuf,cmdlen + 6,0);
5958 if (rv == -1) return(-1);
5959 if (rv != (cmdlen + 6)) return(1);
5960 for(i = 0; i < 6; i++)
5961 if (rxbuf[i] != cmd[i]) return(1);
5962 if (rxbuf[cmdlen] != 0xfe) return(1);
5963 if (rxbuf[cmdlen + 1] != 0xfe) return(1);
5964 if (rxbuf[cmdlen + 4] != 0xfb) return(1);
5965 if (rxbuf[cmdlen + 5] != 0xfd) return(1);
5966 return(0);
5969 static int sendkenwood(struct rpt *myrpt,char *txstr, char *rxstr)
5971 int i;
5973 if (debug) printf("Send to kenwood: %s\n",txstr);
5974 i = serial_remote_io(myrpt, (unsigned char *)txstr, strlen(txstr),
5975 (unsigned char *)rxstr,RAD_SERIAL_BUFLEN - 1,3);
5976 if (i < 0) return -1;
5977 if ((i > 0) && (rxstr[i - 1] == '\r'))
5978 rxstr[i-- - 1] = 0;
5979 if (debug) printf("Got from kenwood: %s\n",rxstr);
5980 return(i);
5983 /* take a PL frequency and turn it into a code */
5984 static int kenwood_pltocode(char *str)
5986 int i;
5987 char *s;
5989 s = strchr(str,'.');
5990 i = 0;
5991 if (s) i = atoi(s + 1);
5992 i += atoi(str) * 10;
5993 switch(i)
5995 case 670:
5996 return 1;
5997 case 719:
5998 return 3;
5999 case 744:
6000 return 4;
6001 case 770:
6002 return 5;
6003 case 797:
6004 return 6;
6005 case 825:
6006 return 7;
6007 case 854:
6008 return 8;
6009 case 885:
6010 return 9;
6011 case 915:
6012 return 10;
6013 case 948:
6014 return 11;
6015 case 974:
6016 return 12;
6017 case 1000:
6018 return 13;
6019 case 1035:
6020 return 14;
6021 case 1072:
6022 return 15;
6023 case 1109:
6024 return 16;
6025 case 1148:
6026 return 17;
6027 case 1188:
6028 return 18;
6029 case 1230:
6030 return 19;
6031 case 1273:
6032 return 20;
6033 case 1318:
6034 return 21;
6035 case 1365:
6036 return 22;
6037 case 1413:
6038 return 23;
6039 case 1462:
6040 return 24;
6041 case 1514:
6042 return 25;
6043 case 1567:
6044 return 26;
6045 case 1622:
6046 return 27;
6047 case 1679:
6048 return 28;
6049 case 1738:
6050 return 29;
6051 case 1799:
6052 return 30;
6053 case 1862:
6054 return 31;
6055 case 1928:
6056 return 32;
6057 case 2035:
6058 return 33;
6059 case 2107:
6060 return 34;
6061 case 2181:
6062 return 35;
6063 case 2257:
6064 return 36;
6065 case 2336:
6066 return 37;
6067 case 2418:
6068 return 38;
6069 case 2503:
6070 return 39;
6072 return -1;
6075 static int sendrxkenwood(struct rpt *myrpt, char *txstr, char *rxstr,
6076 char *cmpstr)
6078 int i,j;
6080 for(i = 0;i < KENWOOD_RETRIES;i++)
6082 j = sendkenwood(myrpt,txstr,rxstr);
6083 if (j < 0) return(j);
6084 if (j == 0) continue;
6085 if (!strncmp(rxstr,cmpstr,strlen(cmpstr))) return(0);
6087 return(-1);
6090 static int setkenwood(struct rpt *myrpt)
6092 char rxstr[RAD_SERIAL_BUFLEN],txstr[RAD_SERIAL_BUFLEN],freq[20];
6093 char mhz[MAXREMSTR],offset[20],band,decimals[MAXREMSTR],band1,band2;
6095 int offsets[] = {0,2,1};
6096 int powers[] = {2,1,0};
6098 if (sendrxkenwood(myrpt,"VMC 0,0\r",rxstr,"VMC") < 0) return -1;
6099 split_freq(mhz, decimals, myrpt->freq);
6100 if (atoi(mhz) > 400)
6102 band = '6';
6103 band1 = '1';
6104 band2 = '5';
6105 strcpy(offset,"005000000");
6107 else
6109 band = '2';
6110 band1 = '0';
6111 band2 = '2';
6112 strcpy(offset,"000600000");
6114 strcpy(freq,"000000");
6115 strncpy(freq,decimals,strlen(decimals));
6116 sprintf(txstr,"VW %c,%05d%s,0,%d,0,%d,%d,,%02d,,%02d,%s\r",
6117 band,atoi(mhz),freq,offsets[(int)myrpt->offset],
6118 (myrpt->txplon != 0),(myrpt->rxplon != 0),
6119 kenwood_pltocode(myrpt->txpl),kenwood_pltocode(myrpt->rxpl),
6120 offset);
6121 if (sendrxkenwood(myrpt,txstr,rxstr,"VW") < 0) return -1;
6122 sprintf(txstr,"RBN %c\r",band2);
6123 if (sendrxkenwood(myrpt,txstr,rxstr,"RBN") < 0) return -1;
6124 sprintf(txstr,"PC %c,%d\r",band1,powers[(int)myrpt->powerlevel]);
6125 if (sendrxkenwood(myrpt,txstr,rxstr,"PC") < 0) return -1;
6126 return 0;
6129 static int setrbi(struct rpt *myrpt)
6131 char tmp[MAXREMSTR] = "",*s;
6132 unsigned char rbicmd[5];
6133 int band,txoffset = 0,txpower = 0,rxpl;
6135 /* must be a remote system */
6136 if (!myrpt->remote) return(0);
6137 /* must have rbi hardware */
6138 if (strncmp(myrpt->remote,remote_rig_rbi,3)) return(0);
6139 if (setrbi_check(myrpt) == -1) return(-1);
6140 strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
6141 s = strchr(tmp,'.');
6142 /* if no decimal, is invalid */
6144 if (s == NULL){
6145 if(debug)
6146 printf("@@@@ Frequency needs a decimal\n");
6147 return -1;
6150 *s++ = 0;
6151 if (strlen(tmp) < 2){
6152 if(debug)
6153 printf("@@@@ Bad MHz digits: %s\n", tmp);
6154 return -1;
6157 if (strlen(s) < 3){
6158 if(debug)
6159 printf("@@@@ Bad KHz digits: %s\n", s);
6160 return -1;
6163 if ((s[2] != '0') && (s[2] != '5')){
6164 if(debug)
6165 printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
6166 return -1;
6169 band = rbi_mhztoband(tmp);
6170 if (band == -1){
6171 if(debug)
6172 printf("@@@@ Bad Band: %s\n", tmp);
6173 return -1;
6176 rxpl = rbi_pltocode(myrpt->rxpl);
6178 if (rxpl == -1){
6179 if(debug)
6180 printf("@@@@ Bad TX PL: %s\n", myrpt->rxpl);
6181 return -1;
6185 switch(myrpt->offset)
6187 case REM_MINUS:
6188 txoffset = 0;
6189 break;
6190 case REM_PLUS:
6191 txoffset = 0x10;
6192 break;
6193 case REM_SIMPLEX:
6194 txoffset = 0x20;
6195 break;
6197 switch(myrpt->powerlevel)
6199 case REM_LOWPWR:
6200 txpower = 0;
6201 break;
6202 case REM_MEDPWR:
6203 txpower = 0x20;
6204 break;
6205 case REM_HIPWR:
6206 txpower = 0x10;
6207 break;
6209 rbicmd[0] = 0;
6210 rbicmd[1] = band | txpower | 0xc0;
6211 rbicmd[2] = (*(s - 2) - '0') | txoffset | 0x80;
6212 if (s[2] == '5') rbicmd[2] |= 0x40;
6213 rbicmd[3] = ((*s - '0') << 4) + (s[1] - '0');
6214 rbicmd[4] = rxpl;
6215 if (myrpt->txplon) rbicmd[4] |= 0x40;
6216 if (myrpt->rxplon) rbicmd[4] |= 0x80;
6217 rbi_out(myrpt,rbicmd);
6218 return 0;
6221 static int setrbi_check(struct rpt *myrpt)
6223 char tmp[MAXREMSTR] = "",*s;
6224 int band,txpl;
6226 /* must be a remote system */
6227 if (!myrpt->remote) return(0);
6228 /* must have rbi hardware */
6229 if (strncmp(myrpt->remote,remote_rig_rbi,3)) return(0);
6230 strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
6231 s = strchr(tmp,'.');
6232 /* if no decimal, is invalid */
6234 if (s == NULL){
6235 if(debug)
6236 printf("@@@@ Frequency needs a decimal\n");
6237 return -1;
6240 *s++ = 0;
6241 if (strlen(tmp) < 2){
6242 if(debug)
6243 printf("@@@@ Bad MHz digits: %s\n", tmp);
6244 return -1;
6247 if (strlen(s) < 3){
6248 if(debug)
6249 printf("@@@@ Bad KHz digits: %s\n", s);
6250 return -1;
6253 if ((s[2] != '0') && (s[2] != '5')){
6254 if(debug)
6255 printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
6256 return -1;
6259 band = rbi_mhztoband(tmp);
6260 if (band == -1){
6261 if(debug)
6262 printf("@@@@ Bad Band: %s\n", tmp);
6263 return -1;
6266 txpl = rbi_pltocode(myrpt->txpl);
6268 if (txpl == -1){
6269 if(debug)
6270 printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
6271 return -1;
6273 return 0;
6276 static int check_freq_kenwood(int m, int d, int *defmode)
6278 int dflmd = REM_MODE_FM;
6280 if (m == 144){ /* 2 meters */
6281 if(d < 10100)
6282 return -1;
6284 else if((m >= 145) && (m < 148)){
6287 else if((m >= 430) && (m < 450)){ /* 70 centimeters */
6290 else
6291 return -1;
6293 if(defmode)
6294 *defmode = dflmd;
6297 return 0;
6301 /* Check for valid rbi frequency */
6302 /* Hard coded limits now, configurable later, maybe? */
6304 static int check_freq_rbi(int m, int d, int *defmode)
6306 int dflmd = REM_MODE_FM;
6308 if(m == 50){ /* 6 meters */
6309 if(d < 10100)
6310 return -1;
6312 else if((m >= 51) && ( m < 54)){
6315 else if(m == 144){ /* 2 meters */
6316 if(d < 10100)
6317 return -1;
6319 else if((m >= 145) && (m < 148)){
6322 else if((m >= 222) && (m < 225)){ /* 1.25 meters */
6325 else if((m >= 430) && (m < 450)){ /* 70 centimeters */
6328 else if((m >= 1240) && (m < 1300)){ /* 23 centimeters */
6331 else
6332 return -1;
6334 if(defmode)
6335 *defmode = dflmd;
6338 return 0;
6342 * Convert decimals of frequency to int
6345 static int decimals2int(char *fraction)
6347 int i;
6348 char len = strlen(fraction);
6349 int multiplier = 100000;
6350 int res = 0;
6352 if(!len)
6353 return 0;
6354 for( i = 0 ; i < len ; i++, multiplier /= 10)
6355 res += (fraction[i] - '0') * multiplier;
6356 return res;
6361 * Split frequency into mhz and decimals
6364 static int split_freq(char *mhz, char *decimals, char *freq)
6366 char freq_copy[MAXREMSTR];
6367 char *decp;
6369 decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
6370 if(decp){
6371 *decp++ = 0;
6372 strncpy(mhz, freq_copy, MAXREMSTR);
6373 strcpy(decimals, "00000");
6374 strncpy(decimals, decp, strlen(decp));
6375 decimals[5] = 0;
6376 return 0;
6378 else
6379 return -1;
6384 * Split ctcss frequency into hertz and decimal
6387 static int split_ctcss_freq(char *hertz, char *decimal, char *freq)
6389 char freq_copy[MAXREMSTR];
6390 char *decp;
6392 decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
6393 if(decp){
6394 *decp++ = 0;
6395 strncpy(hertz, freq_copy, MAXREMSTR);
6396 strncpy(decimal, decp, strlen(decp));
6397 decimal[strlen(decp)] = '\0';
6398 return 0;
6400 else
6401 return -1;
6407 * FT-897 I/O handlers
6410 /* Check to see that the frequency is valid */
6411 /* Hard coded limits now, configurable later, maybe? */
6414 static int check_freq_ft897(int m, int d, int *defmode)
6416 int dflmd = REM_MODE_FM;
6418 if(m == 1){ /* 160 meters */
6419 dflmd = REM_MODE_LSB;
6420 if(d < 80000)
6421 return -1;
6423 else if(m == 3){ /* 80 meters */
6424 dflmd = REM_MODE_LSB;
6425 if(d < 50000)
6426 return -1;
6428 else if(m == 7){ /* 40 meters */
6429 dflmd = REM_MODE_LSB;
6430 if(d > 30000)
6431 return -1;
6433 else if(m == 14){ /* 20 meters */
6434 dflmd = REM_MODE_USB;
6435 if(d > 35000)
6436 return -1;
6438 else if(m == 18){ /* 17 meters */
6439 dflmd = REM_MODE_USB;
6440 if((d < 6800) || (d > 16800))
6441 return -1;
6443 else if(m == 21){ /* 15 meters */
6444 dflmd = REM_MODE_USB;
6445 if((d < 20000) || (d > 45000))
6446 return -1;
6448 else if(m == 24){ /* 12 meters */
6449 dflmd = REM_MODE_USB;
6450 if((d < 89000) || (d > 99000))
6451 return -1;
6453 else if(m == 28){ /* 10 meters */
6454 dflmd = REM_MODE_USB;
6456 else if(m == 29){
6457 if(d >= 51000)
6458 dflmd = REM_MODE_FM;
6459 else
6460 dflmd = REM_MODE_USB;
6461 if(d > 70000)
6462 return -1;
6464 else if(m == 50){ /* 6 meters */
6465 if(d >= 30000)
6466 dflmd = REM_MODE_FM;
6467 else
6468 dflmd = REM_MODE_USB;
6471 else if((m >= 51) && ( m < 54)){
6472 dflmd = REM_MODE_FM;
6474 else if(m == 144){ /* 2 meters */
6475 if(d >= 30000)
6476 dflmd = REM_MODE_FM;
6477 else
6478 dflmd = REM_MODE_USB;
6480 else if((m >= 145) && (m < 148)){
6481 dflmd = REM_MODE_FM;
6483 else if((m >= 430) && (m < 450)){ /* 70 centimeters */
6484 if(m < 438)
6485 dflmd = REM_MODE_USB;
6486 else
6487 dflmd = REM_MODE_FM;
6490 else
6491 return -1;
6493 if(defmode)
6494 *defmode = dflmd;
6496 return 0;
6500 * Set a new frequency for the FT897
6503 static int set_freq_ft897(struct rpt *myrpt, char *newfreq)
6505 unsigned char cmdstr[5];
6506 int fd,m,d;
6507 char mhz[MAXREMSTR];
6508 char decimals[MAXREMSTR];
6510 fd = 0;
6511 if(debug)
6512 printf("New frequency: %s\n",newfreq);
6514 if(split_freq(mhz, decimals, newfreq))
6515 return -1;
6517 m = atoi(mhz);
6518 d = atoi(decimals);
6520 /* The FT-897 likes packed BCD frequencies */
6522 cmdstr[0] = ((m / 100) << 4) + ((m % 100)/10); /* 100MHz 10Mhz */
6523 cmdstr[1] = ((m % 10) << 4) + (d / 10000); /* 1MHz 100KHz */
6524 cmdstr[2] = (((d % 10000)/1000) << 4) + ((d % 1000)/ 100); /* 10KHz 1KHz */
6525 cmdstr[3] = (((d % 100)/10) << 4) + (d % 10); /* 100Hz 10Hz */
6526 cmdstr[4] = 0x01; /* command */
6528 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
6532 /* ft-897 simple commands */
6534 static int simple_command_ft897(struct rpt *myrpt, char command)
6536 unsigned char cmdstr[5];
6538 memset(cmdstr, 0, 5);
6540 cmdstr[4] = command;
6542 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
6546 /* ft-897 offset */
6548 static int set_offset_ft897(struct rpt *myrpt, char offset)
6550 unsigned char cmdstr[5];
6552 memset(cmdstr, 0, 5);
6554 switch(offset){
6555 case REM_SIMPLEX:
6556 cmdstr[0] = 0x89;
6557 break;
6559 case REM_MINUS:
6560 cmdstr[0] = 0x09;
6561 break;
6563 case REM_PLUS:
6564 cmdstr[0] = 0x49;
6565 break;
6567 default:
6568 return -1;
6571 cmdstr[4] = 0x09;
6573 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
6576 /* ft-897 mode */
6578 static int set_mode_ft897(struct rpt *myrpt, char newmode)
6580 unsigned char cmdstr[5];
6582 memset(cmdstr, 0, 5);
6584 switch(newmode){
6585 case REM_MODE_FM:
6586 cmdstr[0] = 0x08;
6587 break;
6589 case REM_MODE_USB:
6590 cmdstr[0] = 0x01;
6591 break;
6593 case REM_MODE_LSB:
6594 cmdstr[0] = 0x00;
6595 break;
6597 case REM_MODE_AM:
6598 cmdstr[0] = 0x04;
6599 break;
6601 default:
6602 return -1;
6604 cmdstr[4] = 0x07;
6606 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
6609 /* Set tone encode and decode modes */
6611 static int set_ctcss_mode_ft897(struct rpt *myrpt, char txplon, char rxplon)
6613 unsigned char cmdstr[5];
6615 memset(cmdstr, 0, 5);
6617 if(rxplon && txplon)
6618 cmdstr[0] = 0x2A; /* Encode and Decode */
6619 else if (!rxplon && txplon)
6620 cmdstr[0] = 0x4A; /* Encode only */
6621 else if (rxplon && !txplon)
6622 cmdstr[0] = 0x3A; /* Encode only */
6623 else
6624 cmdstr[0] = 0x8A; /* OFF */
6626 cmdstr[4] = 0x0A;
6628 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
6632 /* Set transmit and receive ctcss tone frequencies */
6634 static int set_ctcss_freq_ft897(struct rpt *myrpt, char *txtone, char *rxtone)
6636 unsigned char cmdstr[5];
6637 char hertz[MAXREMSTR],decimal[MAXREMSTR];
6638 int h,d;
6640 memset(cmdstr, 0, 5);
6642 if(split_ctcss_freq(hertz, decimal, txtone))
6643 return -1;
6645 h = atoi(hertz);
6646 d = atoi(decimal);
6648 cmdstr[0] = ((h / 100) << 4) + (h % 100)/ 10;
6649 cmdstr[1] = ((h % 10) << 4) + (d % 10);
6651 if(rxtone){
6653 if(split_ctcss_freq(hertz, decimal, rxtone))
6654 return -1;
6656 h = atoi(hertz);
6657 d = atoi(decimal);
6659 cmdstr[2] = ((h / 100) << 4) + (h % 100)/ 10;
6660 cmdstr[3] = ((h % 10) << 4) + (d % 10);
6662 cmdstr[4] = 0x0B;
6664 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
6669 static int set_ft897(struct rpt *myrpt)
6671 int res;
6673 if(debug)
6674 printf("@@@@ lock on\n");
6676 res = simple_command_ft897(myrpt, 0x00); /* LOCK on */
6678 if(debug)
6679 printf("@@@@ ptt off\n");
6681 if(!res)
6682 res = simple_command_ft897(myrpt, 0x88); /* PTT off */
6684 if(debug)
6685 printf("Modulation mode\n");
6687 if(!res)
6688 res = set_mode_ft897(myrpt, myrpt->remmode); /* Modulation mode */
6690 if(debug)
6691 printf("Split off\n");
6693 if(!res)
6694 simple_command_ft897(myrpt, 0x82); /* Split off */
6696 if(debug)
6697 printf("Frequency\n");
6699 if(!res)
6700 res = set_freq_ft897(myrpt, myrpt->freq); /* Frequency */
6701 if((myrpt->remmode == REM_MODE_FM)){
6702 if(debug)
6703 printf("Offset\n");
6704 if(!res)
6705 res = set_offset_ft897(myrpt, myrpt->offset); /* Offset if FM */
6706 if((!res)&&(myrpt->rxplon || myrpt->txplon)){
6707 if(debug)
6708 printf("CTCSS tone freqs.\n");
6709 res = set_ctcss_freq_ft897(myrpt, myrpt->txpl, myrpt->rxpl); /* CTCSS freqs if CTCSS is enabled */
6711 if(!res){
6712 if(debug)
6713 printf("CTCSS mode\n");
6714 res = set_ctcss_mode_ft897(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */
6717 if((myrpt->remmode == REM_MODE_USB)||(myrpt->remmode == REM_MODE_LSB)){
6718 if(debug)
6719 printf("Clarifier off\n");
6720 simple_command_ft897(myrpt, 0x85); /* Clarifier off if LSB or USB */
6722 return res;
6725 static int closerem_ft897(struct rpt *myrpt)
6727 simple_command_ft897(myrpt, 0x88); /* PTT off */
6728 return 0;
6732 * Bump frequency up or down by a small amount
6733 * Return 0 if the new frequnecy is valid, or -1 if invalid
6734 * Interval is in Hz, resolution is 10Hz
6737 static int multimode_bump_freq_ft897(struct rpt *myrpt, int interval)
6739 int m,d;
6740 char mhz[MAXREMSTR], decimals[MAXREMSTR];
6742 if(debug)
6743 printf("Before bump: %s\n", myrpt->freq);
6745 if(split_freq(mhz, decimals, myrpt->freq))
6746 return -1;
6748 m = atoi(mhz);
6749 d = atoi(decimals);
6751 d += (interval / 10); /* 10Hz resolution */
6752 if(d < 0){
6753 m--;
6754 d += 100000;
6756 else if(d >= 100000){
6757 m++;
6758 d -= 100000;
6761 if(check_freq_ft897(m, d, NULL)){
6762 if(debug)
6763 printf("Bump freq invalid\n");
6764 return -1;
6767 snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d);
6769 if(debug)
6770 printf("After bump: %s\n", myrpt->freq);
6772 return set_freq_ft897(myrpt, myrpt->freq);
6778 * IC-706 I/O handlers
6781 /* Check to see that the frequency is valid */
6782 /* Hard coded limits now, configurable later, maybe? */
6785 static int check_freq_ic706(int m, int d, int *defmode)
6787 int dflmd = REM_MODE_FM;
6789 if(m == 1){ /* 160 meters */
6790 dflmd = REM_MODE_LSB;
6791 if(d < 80000)
6792 return -1;
6794 else if(m == 3){ /* 80 meters */
6795 dflmd = REM_MODE_LSB;
6796 if(d < 50000)
6797 return -1;
6799 else if(m == 7){ /* 40 meters */
6800 dflmd = REM_MODE_LSB;
6801 if(d > 30000)
6802 return -1;
6804 else if(m == 14){ /* 20 meters */
6805 dflmd = REM_MODE_USB;
6806 if(d > 35000)
6807 return -1;
6809 else if(m == 18){ /* 17 meters */
6810 dflmd = REM_MODE_USB;
6811 if((d < 6800) || (d > 16800))
6812 return -1;
6814 else if(m == 21){ /* 15 meters */
6815 dflmd = REM_MODE_USB;
6816 if((d < 20000) || (d > 45000))
6817 return -1;
6819 else if(m == 24){ /* 12 meters */
6820 dflmd = REM_MODE_USB;
6821 if((d < 89000) || (d > 99000))
6822 return -1;
6824 else if(m == 28){ /* 10 meters */
6825 dflmd = REM_MODE_USB;
6827 else if(m == 29){
6828 if(d >= 51000)
6829 dflmd = REM_MODE_FM;
6830 else
6831 dflmd = REM_MODE_USB;
6832 if(d > 70000)
6833 return -1;
6835 else if(m == 50){ /* 6 meters */
6836 if(d >= 30000)
6837 dflmd = REM_MODE_FM;
6838 else
6839 dflmd = REM_MODE_USB;
6842 else if((m >= 51) && ( m < 54)){
6843 dflmd = REM_MODE_FM;
6845 else if(m == 144){ /* 2 meters */
6846 if(d >= 30000)
6847 dflmd = REM_MODE_FM;
6848 else
6849 dflmd = REM_MODE_USB;
6851 else if((m >= 145) && (m < 148)){
6852 dflmd = REM_MODE_FM;
6854 else if((m >= 430) && (m < 450)){ /* 70 centimeters */
6855 if(m < 438)
6856 dflmd = REM_MODE_USB;
6857 else
6858 dflmd = REM_MODE_FM;
6861 else
6862 return -1;
6864 if(defmode)
6865 *defmode = dflmd;
6867 return 0;
6870 /* take a PL frequency and turn it into a code */
6871 static int ic706_pltocode(char *str)
6873 int i;
6874 char *s;
6876 s = strchr(str,'.');
6877 i = 0;
6878 if (s) i = atoi(s + 1);
6879 i += atoi(str) * 10;
6880 switch(i)
6882 case 670:
6883 return 0;
6884 case 693:
6885 return 1;
6886 case 719:
6887 return 2;
6888 case 744:
6889 return 3;
6890 case 770:
6891 return 4;
6892 case 797:
6893 return 5;
6894 case 825:
6895 return 6;
6896 case 854:
6897 return 7;
6898 case 885:
6899 return 8;
6900 case 915:
6901 return 9;
6902 case 948:
6903 return 10;
6904 case 974:
6905 return 11;
6906 case 1000:
6907 return 12;
6908 case 1035:
6909 return 13;
6910 case 1072:
6911 return 14;
6912 case 1109:
6913 return 15;
6914 case 1148:
6915 return 16;
6916 case 1188:
6917 return 17;
6918 case 1230:
6919 return 18;
6920 case 1273:
6921 return 19;
6922 case 1318:
6923 return 20;
6924 case 1365:
6925 return 21;
6926 case 1413:
6927 return 22;
6928 case 1462:
6929 return 23;
6930 case 1514:
6931 return 24;
6932 case 1567:
6933 return 25;
6934 case 1598:
6935 return 26;
6936 case 1622:
6937 return 27;
6938 case 1655:
6939 return 28;
6940 case 1679:
6941 return 29;
6942 case 1713:
6943 return 30;
6944 case 1738:
6945 return 31;
6946 case 1773:
6947 return 32;
6948 case 1799:
6949 return 33;
6950 case 1835:
6951 return 34;
6952 case 1862:
6953 return 35;
6954 case 1899:
6955 return 36;
6956 case 1928:
6957 return 37;
6958 case 1966:
6959 return 38;
6960 case 1995:
6961 return 39;
6962 case 2035:
6963 return 40;
6964 case 2065:
6965 return 41;
6966 case 2107:
6967 return 42;
6968 case 2181:
6969 return 43;
6970 case 2257:
6971 return 44;
6972 case 2291:
6973 return 45;
6974 case 2336:
6975 return 46;
6976 case 2418:
6977 return 47;
6978 case 2503:
6979 return 48;
6980 case 2541:
6981 return 49;
6983 return -1;
6986 /* ic-706 simple commands */
6988 static int simple_command_ic706(struct rpt *myrpt, char command, char subcommand)
6990 unsigned char cmdstr[10];
6992 cmdstr[0] = cmdstr[1] = 0xfe;
6993 cmdstr[2] = myrpt->p.civaddr;
6994 cmdstr[3] = 0xe0;
6995 cmdstr[4] = command;
6996 cmdstr[5] = subcommand;
6997 cmdstr[6] = 0xfd;
6999 return(civ_cmd(myrpt,cmdstr,7));
7003 * Set a new frequency for the ic706
7006 static int set_freq_ic706(struct rpt *myrpt, char *newfreq)
7008 unsigned char cmdstr[20];
7009 char mhz[MAXREMSTR], decimals[MAXREMSTR];
7010 int fd,m,d;
7012 fd = 0;
7013 if(debug)
7014 printf("New frequency: %s\n",newfreq);
7016 if(split_freq(mhz, decimals, newfreq))
7017 return -1;
7019 m = atoi(mhz);
7020 d = atoi(decimals);
7022 /* The ic-706 likes packed BCD frequencies */
7024 cmdstr[0] = cmdstr[1] = 0xfe;
7025 cmdstr[2] = myrpt->p.civaddr;
7026 cmdstr[3] = 0xe0;
7027 cmdstr[4] = 5;
7028 cmdstr[5] = ((d % 10) << 4);
7029 cmdstr[6] = (((d % 1000)/ 100) << 4) + ((d % 100)/10);
7030 cmdstr[7] = ((d / 10000) << 4) + ((d % 10000)/1000);
7031 cmdstr[8] = (((m % 100)/10) << 4) + (m % 10);
7032 cmdstr[9] = (m / 100);
7033 cmdstr[10] = 0xfd;
7035 return(civ_cmd(myrpt,cmdstr,11));
7038 /* ic-706 offset */
7040 static int set_offset_ic706(struct rpt *myrpt, char offset)
7042 unsigned char c;
7044 switch(offset){
7045 case REM_SIMPLEX:
7046 c = 0x10;
7047 break;
7049 case REM_MINUS:
7050 c = 0x11;
7051 break;
7053 case REM_PLUS:
7054 c = 0x12;
7055 break;
7057 default:
7058 return -1;
7061 return simple_command_ic706(myrpt,0x0f,c);
7065 /* ic-706 mode */
7067 static int set_mode_ic706(struct rpt *myrpt, char newmode)
7069 unsigned char c;
7071 switch(newmode){
7072 case REM_MODE_FM:
7073 c = 5;
7074 break;
7076 case REM_MODE_USB:
7077 c = 1;
7078 break;
7080 case REM_MODE_LSB:
7081 c = 0;
7082 break;
7084 case REM_MODE_AM:
7085 c = 2;
7086 break;
7088 default:
7089 return -1;
7091 return simple_command_ic706(myrpt,6,c);
7094 /* Set tone encode and decode modes */
7096 static int set_ctcss_mode_ic706(struct rpt *myrpt, char txplon, char rxplon)
7098 unsigned char cmdstr[10];
7099 int rv;
7101 cmdstr[0] = cmdstr[1] = 0xfe;
7102 cmdstr[2] = myrpt->p.civaddr;
7103 cmdstr[3] = 0xe0;
7104 cmdstr[4] = 0x16;
7105 cmdstr[5] = 0x42;
7106 cmdstr[6] = (txplon != 0);
7107 cmdstr[7] = 0xfd;
7109 rv = civ_cmd(myrpt,cmdstr,8);
7110 if (rv) return(-1);
7112 cmdstr[0] = cmdstr[1] = 0xfe;
7113 cmdstr[2] = myrpt->p.civaddr;
7114 cmdstr[3] = 0xe0;
7115 cmdstr[4] = 0x16;
7116 cmdstr[5] = 0x43;
7117 cmdstr[6] = (rxplon != 0);
7118 cmdstr[7] = 0xfd;
7120 return(civ_cmd(myrpt,cmdstr,8));
7123 #if 0
7124 /* Set transmit and receive ctcss tone frequencies */
7126 static int set_ctcss_freq_ic706(struct rpt *myrpt, char *txtone, char *rxtone)
7128 unsigned char cmdstr[10];
7129 char hertz[MAXREMSTR],decimal[MAXREMSTR];
7130 int h,d,rv;
7132 memset(cmdstr, 0, 5);
7134 if(split_ctcss_freq(hertz, decimal, txtone))
7135 return -1;
7137 h = atoi(hertz);
7138 d = atoi(decimal);
7140 cmdstr[0] = cmdstr[1] = 0xfe;
7141 cmdstr[2] = myrpt->p.civaddr;
7142 cmdstr[3] = 0xe0;
7143 cmdstr[4] = 0x1b;
7144 cmdstr[5] = 0;
7145 cmdstr[6] = ((h / 100) << 4) + (h % 100)/ 10;
7146 cmdstr[7] = ((h % 10) << 4) + (d % 10);
7147 cmdstr[8] = 0xfd;
7149 rv = civ_cmd(myrpt,cmdstr,9);
7150 if (rv) return(-1);
7152 if (!rxtone) return(0);
7154 if(split_ctcss_freq(hertz, decimal, rxtone))
7155 return -1;
7157 h = atoi(hertz);
7158 d = atoi(decimal);
7160 cmdstr[0] = cmdstr[1] = 0xfe;
7161 cmdstr[2] = myrpt->p.civaddr;
7162 cmdstr[3] = 0xe0;
7163 cmdstr[4] = 0x1b;
7164 cmdstr[5] = 1;
7165 cmdstr[6] = ((h / 100) << 4) + (h % 100)/ 10;
7166 cmdstr[7] = ((h % 10) << 4) + (d % 10);
7167 cmdstr[8] = 0xfd;
7168 return(civ_cmd(myrpt,cmdstr,9));
7170 #endif
7172 static int vfo_ic706(struct rpt *myrpt)
7174 unsigned char cmdstr[10];
7176 cmdstr[0] = cmdstr[1] = 0xfe;
7177 cmdstr[2] = myrpt->p.civaddr;
7178 cmdstr[3] = 0xe0;
7179 cmdstr[4] = 7;
7180 cmdstr[5] = 0xfd;
7182 return(civ_cmd(myrpt,cmdstr,6));
7185 static int mem2vfo_ic706(struct rpt *myrpt)
7187 unsigned char cmdstr[10];
7189 cmdstr[0] = cmdstr[1] = 0xfe;
7190 cmdstr[2] = myrpt->p.civaddr;
7191 cmdstr[3] = 0xe0;
7192 cmdstr[4] = 0x0a;
7193 cmdstr[5] = 0xfd;
7195 return(civ_cmd(myrpt,cmdstr,6));
7198 static int select_mem_ic706(struct rpt *myrpt, int slot)
7200 unsigned char cmdstr[10];
7202 cmdstr[0] = cmdstr[1] = 0xfe;
7203 cmdstr[2] = myrpt->p.civaddr;
7204 cmdstr[3] = 0xe0;
7205 cmdstr[4] = 8;
7206 cmdstr[5] = 0;
7207 cmdstr[6] = ((slot / 10) << 4) + (slot % 10);
7208 cmdstr[7] = 0xfd;
7210 return(civ_cmd(myrpt,cmdstr,8));
7213 static int set_ic706(struct rpt *myrpt)
7215 int res = 0,i;
7217 if(debug)
7218 printf("Set to VFO A\n");
7220 if (!res)
7221 res = simple_command_ic706(myrpt,7,0);
7224 if((myrpt->remmode == REM_MODE_FM))
7226 i = ic706_pltocode(myrpt->rxpl);
7227 if (i == -1) return -1;
7228 if(debug)
7229 printf("Select memory number\n");
7230 if (!res)
7231 res = select_mem_ic706(myrpt,i + IC706_PL_MEMORY_OFFSET);
7232 if(debug)
7233 printf("Transfer memory to VFO\n");
7234 if (!res)
7235 res = mem2vfo_ic706(myrpt);
7238 if(debug)
7239 printf("Set to VFO\n");
7241 if (!res)
7242 res = vfo_ic706(myrpt);
7244 if(debug)
7245 printf("Modulation mode\n");
7247 if (!res)
7248 res = set_mode_ic706(myrpt, myrpt->remmode); /* Modulation mode */
7250 if(debug)
7251 printf("Split off\n");
7253 if(!res)
7254 simple_command_ic706(myrpt, 0x82,0); /* Split off */
7256 if(debug)
7257 printf("Frequency\n");
7259 if(!res)
7260 res = set_freq_ic706(myrpt, myrpt->freq); /* Frequency */
7261 if((myrpt->remmode == REM_MODE_FM)){
7262 if(debug)
7263 printf("Offset\n");
7264 if(!res)
7265 res = set_offset_ic706(myrpt, myrpt->offset); /* Offset if FM */
7266 if(!res){
7267 if(debug)
7268 printf("CTCSS mode\n");
7269 res = set_ctcss_mode_ic706(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */
7272 return res;
7276 * Bump frequency up or down by a small amount
7277 * Return 0 if the new frequnecy is valid, or -1 if invalid
7278 * Interval is in Hz, resolution is 10Hz
7281 static int multimode_bump_freq_ic706(struct rpt *myrpt, int interval)
7283 int m,d;
7284 char mhz[MAXREMSTR], decimals[MAXREMSTR];
7285 unsigned char cmdstr[20];
7287 if(debug)
7288 printf("Before bump: %s\n", myrpt->freq);
7290 if(split_freq(mhz, decimals, myrpt->freq))
7291 return -1;
7293 m = atoi(mhz);
7294 d = atoi(decimals);
7296 d += (interval / 10); /* 10Hz resolution */
7297 if(d < 0){
7298 m--;
7299 d += 100000;
7301 else if(d >= 100000){
7302 m++;
7303 d -= 100000;
7306 if(check_freq_ic706(m, d, NULL)){
7307 if(debug)
7308 printf("Bump freq invalid\n");
7309 return -1;
7312 snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d);
7314 if(debug)
7315 printf("After bump: %s\n", myrpt->freq);
7317 /* The ic-706 likes packed BCD frequencies */
7319 cmdstr[0] = cmdstr[1] = 0xfe;
7320 cmdstr[2] = myrpt->p.civaddr;
7321 cmdstr[3] = 0xe0;
7322 cmdstr[4] = 0;
7323 cmdstr[5] = ((d % 10) << 4);
7324 cmdstr[6] = (((d % 1000)/ 100) << 4) + ((d % 100)/10);
7325 cmdstr[7] = ((d / 10000) << 4) + ((d % 10000)/1000);
7326 cmdstr[8] = (((m % 100)/10) << 4) + (m % 10);
7327 cmdstr[9] = (m / 100);
7328 cmdstr[10] = 0xfd;
7330 return(serial_remote_io(myrpt,cmdstr,11,NULL,0,0));
7336 * Dispatch to correct I/O handler
7339 static int setrem(struct rpt *myrpt)
7341 char str[300];
7342 char *offsets[] = {"MINUS","SIMPLEX","PLUS"};
7343 char *powerlevels[] = {"LOW","MEDIUM","HIGH"};
7344 char *modes[] = {"FM","USB","LSB","AM"};
7345 int res = -1;
7347 if (myrpt->p.archivedir)
7349 sprintf(str,"FREQ,%s,%s,%s,%s,%s,%s,%d,%d",myrpt->freq,
7350 modes[(int)myrpt->remmode],
7351 myrpt->txpl,myrpt->rxpl,offsets[(int)myrpt->offset],
7352 powerlevels[(int)myrpt->powerlevel],myrpt->txplon,
7353 myrpt->rxplon);
7354 donodelog(myrpt,str);
7356 if(!strcmp(myrpt->remote, remote_rig_ft897))
7358 rpt_telemetry(myrpt,SETREMOTE,NULL);
7359 res = 0;
7361 if(!strcmp(myrpt->remote, remote_rig_ic706))
7363 rpt_telemetry(myrpt,SETREMOTE,NULL);
7364 res = 0;
7366 else if(!strcmp(myrpt->remote, remote_rig_rbi))
7368 res = setrbi_check(myrpt);
7369 if (!res)
7371 rpt_telemetry(myrpt,SETREMOTE,NULL);
7372 res = 0;
7375 else if(!strcmp(myrpt->remote, remote_rig_kenwood)) {
7376 rpt_telemetry(myrpt,SETREMOTE,NULL);
7377 res = 0;
7379 else
7380 res = 0;
7382 if (res < 0) ast_log(LOG_ERROR,"Unable to send remote command on node %s\n",myrpt->name);
7384 return res;
7387 static int closerem(struct rpt *myrpt)
7389 if(!strcmp(myrpt->remote, remote_rig_ft897))
7390 return closerem_ft897(myrpt);
7391 else
7392 return 0;
7396 * Dispatch to correct RX frequency checker
7399 static int check_freq(struct rpt *myrpt, int m, int d, int *defmode)
7401 if(!strcmp(myrpt->remote, remote_rig_ft897))
7402 return check_freq_ft897(m, d, defmode);
7403 else if(!strcmp(myrpt->remote, remote_rig_ic706))
7404 return check_freq_ic706(m, d, defmode);
7405 else if(!strcmp(myrpt->remote, remote_rig_rbi))
7406 return check_freq_rbi(m, d, defmode);
7407 else if(!strcmp(myrpt->remote, remote_rig_kenwood))
7408 return check_freq_kenwood(m, d, defmode);
7409 else
7410 return -1;
7414 * Check TX frequency before transmitting
7417 static char check_tx_freq(struct rpt *myrpt)
7419 int i;
7420 int radio_mhz, radio_decimals, ulimit_mhz, ulimit_decimals, llimit_mhz, llimit_decimals;
7421 char radio_mhz_char[MAXREMSTR];
7422 char radio_decimals_char[MAXREMSTR];
7423 char limit_mhz_char[MAXREMSTR];
7424 char limit_decimals_char[MAXREMSTR];
7425 char limits[256];
7426 char *limit_ranges[40];
7427 struct ast_variable *limitlist;
7430 /* Must have user logged in and tx_limits defined */
7432 if(!myrpt->p.txlimitsstanzaname || !myrpt->loginuser[0] || !myrpt->loginlevel[0]){
7433 if(debug > 3){
7434 ast_log(LOG_NOTICE, "No tx band table defined, or no user logged in\n");
7436 return 1; /* Assume it's ok otherwise */
7439 /* Retrieve the band table for the loginlevel */
7440 limitlist = ast_variable_browse(myrpt->cfg, myrpt->p.txlimitsstanzaname);
7442 if(!limitlist){
7443 ast_log(LOG_WARNING, "No entries in %s band table stanza\n", myrpt->p.txlimitsstanzaname);
7444 return 0;
7447 split_freq(radio_mhz_char, radio_decimals_char, myrpt->freq);
7448 radio_mhz = atoi(radio_mhz_char);
7449 radio_decimals = decimals2int(radio_decimals_char);
7452 if(debug > 3){
7453 ast_log(LOG_NOTICE, "Login User = %s, login level = %s\n", myrpt->loginuser, myrpt->loginlevel);
7456 /* Find our entry */
7458 for(;limitlist; limitlist=limitlist->next){
7459 if(!strcmp(limitlist->name, myrpt->loginlevel))
7460 break;
7463 if(!limitlist){
7464 ast_log(LOG_WARNING, "Can't find %s entry in band table stanza %s\n", myrpt->loginlevel, myrpt->p.txlimitsstanzaname);
7465 return 0;
7468 if(debug > 3){
7469 ast_log(LOG_NOTICE, "Auth %s = %s\n", limitlist->name, limitlist->value);
7472 /* Parse the limits */
7474 strncpy(limits, limitlist->value, 256);
7475 limits[255] = 0;
7476 finddelim(limits, limit_ranges, 40);
7477 for(i = 0; i < 40 && limit_ranges[i] ; i++){
7478 char range[40];
7479 char *r,*s;
7480 strncpy(range, limit_ranges[i], 40);
7481 range[39] = 0;
7482 if(debug > 3){
7483 ast_log(LOG_NOTICE, "Checking to see if %s is within limits of %s\n", myrpt->freq, range);
7486 r = strchr(range, '-');
7487 if(!r){
7488 ast_log(LOG_WARNING, "Malformed range in %s tx band table entry\n", limitlist->name);
7489 return 0;
7491 *r++ = 0;
7492 s = eatwhite(range);
7493 r = eatwhite(r);
7494 split_freq(limit_mhz_char, limit_decimals_char, s);
7495 llimit_mhz = atoi(limit_mhz_char);
7496 llimit_decimals = decimals2int(limit_decimals_char);
7497 split_freq(limit_mhz_char, limit_decimals_char, r);
7498 ulimit_mhz = atoi(limit_mhz_char);
7499 ulimit_decimals = decimals2int(limit_decimals_char);
7501 if((radio_mhz >= llimit_mhz) && (radio_mhz <= ulimit_mhz)){
7502 if(radio_mhz == llimit_mhz){ /* CASE 1: TX freq is in llimit mhz portion of band */
7503 if(radio_decimals >= llimit_decimals){ /* Cannot be below llimit decimals */
7504 if(llimit_mhz == ulimit_mhz){ /* If bandwidth < 1Mhz, check ulimit decimals */
7505 if(radio_decimals <= ulimit_decimals){
7506 return 1;
7508 else{
7509 if(debug > 3)
7510 ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 1\n");
7511 return 0;
7514 else{
7515 return 1;
7518 else{ /* Is below llimit decimals */
7519 if(debug > 3)
7520 ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 2\n");
7521 return 0;
7524 else if(radio_mhz == ulimit_mhz){ /* CASE 2: TX freq not in llimit mhz portion of band */
7525 if(radio_decimals <= ulimit_decimals){
7526 return 1;
7528 else{ /* Is above ulimit decimals */
7529 if(debug > 3)
7530 ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 3\n");
7531 return 0;
7534 else /* CASE 3: TX freq within a multi-Mhz band and ok */
7535 return 1;
7538 if(debug > 3) /* No match found in TX band table */
7539 ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 4\n");
7540 return 0;
7545 * Dispatch to correct frequency bumping function
7548 static int multimode_bump_freq(struct rpt *myrpt, int interval)
7550 if(!strcmp(myrpt->remote, remote_rig_ft897))
7551 return multimode_bump_freq_ft897(myrpt, interval);
7552 else if(!strcmp(myrpt->remote, remote_rig_ic706))
7553 return multimode_bump_freq_ic706(myrpt, interval);
7554 else
7555 return -1;
7560 * Queue announcment that scan has been stopped
7563 static void stop_scan(struct rpt *myrpt)
7565 myrpt->hfscanstop = 1;
7566 rpt_telemetry(myrpt,SCAN,0);
7570 * This is called periodically when in scan mode
7574 static int service_scan(struct rpt *myrpt)
7576 int res, interval;
7577 char mhz[MAXREMSTR], decimals[MAXREMSTR], k10=0i, k100=0;
7579 switch(myrpt->hfscanmode){
7581 case HF_SCAN_DOWN_SLOW:
7582 interval = -10; /* 100Hz /sec */
7583 break;
7585 case HF_SCAN_DOWN_QUICK:
7586 interval = -50; /* 500Hz /sec */
7587 break;
7589 case HF_SCAN_DOWN_FAST:
7590 interval = -200; /* 2KHz /sec */
7591 break;
7593 case HF_SCAN_UP_SLOW:
7594 interval = 10; /* 100Hz /sec */
7595 break;
7597 case HF_SCAN_UP_QUICK:
7598 interval = 50; /* 500 Hz/sec */
7599 break;
7601 case HF_SCAN_UP_FAST:
7602 interval = 200; /* 2KHz /sec */
7603 break;
7605 default:
7606 myrpt->hfscanmode = 0; /* Huh? */
7607 return -1;
7610 res = split_freq(mhz, decimals, myrpt->freq);
7612 if(!res){
7613 k100 =decimals[0];
7614 k10 = decimals[1];
7615 res = multimode_bump_freq(myrpt, interval);
7618 if(!res)
7619 res = split_freq(mhz, decimals, myrpt->freq);
7622 if(res){
7623 myrpt->hfscanmode = 0;
7624 myrpt->hfscanstatus = -2;
7625 return -1;
7628 /* Announce 10KHz boundaries */
7629 if(k10 != decimals[1]){
7630 int myhund = (interval < 0) ? k100 : decimals[0];
7631 int myten = (interval < 0) ? k10 : decimals[1];
7632 myrpt->hfscanstatus = (myten == '0') ? (myhund - '0') * 100 : (myten - '0') * 10;
7633 } else myrpt->hfscanstatus = 0;
7634 return res;
7639 * Retrieve a memory channel
7640 * Return 0 if sucessful,
7641 * -1 if channel not found,
7642 * 1 if parse error
7645 static int retreive_memory(struct rpt *myrpt, char *memory)
7647 char tmp[30], *s, *s1, *val;
7649 val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.memory, memory);
7650 if (!val){
7651 return -1;
7653 strncpy(tmp,val,sizeof(tmp) - 1);
7654 tmp[sizeof(tmp)-1] = 0;
7656 s = strchr(tmp,',');
7657 if (!s)
7658 return 1;
7659 *s++ = 0;
7660 s1 = strchr(s,',');
7661 if (!s1)
7662 return 1;
7663 *s1++ = 0;
7664 strncpy(myrpt->freq, tmp, sizeof(myrpt->freq) - 1);
7665 strncpy(myrpt->rxpl, s, sizeof(myrpt->rxpl) - 1);
7666 strncpy(myrpt->txpl, s, sizeof(myrpt->rxpl) - 1);
7667 myrpt->remmode = REM_MODE_FM;
7668 myrpt->offset = REM_SIMPLEX;
7669 myrpt->powerlevel = REM_MEDPWR;
7670 myrpt->txplon = myrpt->rxplon = 0;
7671 while(*s1){
7672 switch(*s1++){
7673 case 'A':
7674 case 'a':
7675 strcpy(myrpt->rxpl, "100.0");
7676 strcpy(myrpt->txpl, "100.0");
7677 myrpt->remmode = REM_MODE_AM;
7678 break;
7679 case 'B':
7680 case 'b':
7681 strcpy(myrpt->rxpl, "100.0");
7682 strcpy(myrpt->txpl, "100.0");
7683 myrpt->remmode = REM_MODE_LSB;
7684 break;
7685 case 'F':
7686 myrpt->remmode = REM_MODE_FM;
7687 break;
7688 case 'L':
7689 case 'l':
7690 myrpt->powerlevel = REM_LOWPWR;
7691 break;
7692 case 'H':
7693 case 'h':
7694 myrpt->powerlevel = REM_HIPWR;
7695 break;
7697 case 'M':
7698 case 'm':
7699 myrpt->powerlevel = REM_MEDPWR;
7700 break;
7702 case '-':
7703 myrpt->offset = REM_MINUS;
7704 break;
7706 case '+':
7707 myrpt->offset = REM_PLUS;
7708 break;
7710 case 'S':
7711 case 's':
7712 myrpt->offset = REM_SIMPLEX;
7713 break;
7715 case 'T':
7716 case 't':
7717 myrpt->txplon = 1;
7718 break;
7720 case 'R':
7721 case 'r':
7722 myrpt->rxplon = 1;
7723 break;
7725 case 'U':
7726 case 'u':
7727 strcpy(myrpt->rxpl, "100.0");
7728 strcpy(myrpt->txpl, "100.0");
7729 myrpt->remmode = REM_MODE_USB;
7730 break;
7731 default:
7732 return 1;
7735 return 0;
7741 * Remote base function
7744 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
7746 char *s,*s1,*s2;
7747 int i,j,p,r,ht,k,l,ls2,m,d,offset,offsave, modesave, defmode;
7748 char multimode = 0;
7749 char oc,*cp,*cp1,*cp2;
7750 char tmp[20], freq[20] = "", savestr[20] = "";
7751 char mhz[MAXREMSTR], decimals[MAXREMSTR];
7753 if((!param) || (command_source == SOURCE_RPT) || (command_source == SOURCE_LNK))
7754 return DC_ERROR;
7756 p = myatoi(param);
7758 if ((p != 99) && (p != 5) && (p != 140) && myrpt->p.authlevel &&
7759 (!myrpt->loginlevel[0])) return DC_ERROR;
7760 multimode = multimode_capable(myrpt);
7762 switch(p){
7764 case 1: /* retrieve memory */
7765 if(strlen(digitbuf) < 2) /* needs 2 digits */
7766 break;
7768 for(i = 0 ; i < 2 ; i++){
7769 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
7770 return DC_ERROR;
7773 r = retreive_memory(myrpt, digitbuf);
7774 if (r < 0){
7775 rpt_telemetry(myrpt,MEMNOTFOUND,NULL);
7776 return DC_COMPLETE;
7778 if (r > 0){
7779 return DC_ERROR;
7781 if (setrem(myrpt) == -1) return DC_ERROR;
7782 return DC_COMPLETE;
7784 case 2: /* set freq and offset */
7787 for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for M+*K+*O or M+*H+* depending on mode */
7788 if(digitbuf[i] == '*'){
7789 j++;
7790 continue;
7792 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
7793 goto invalid_freq;
7794 else{
7795 if(j == 0)
7796 l++; /* # of digits before first * */
7797 if(j == 1)
7798 k++; /* # of digits after first * */
7802 i = strlen(digitbuf) - 1;
7803 if(multimode){
7804 if((j > 2) || (l > 3) || (k > 6))
7805 goto invalid_freq; /* &^@#! */
7807 else{
7808 if((j > 2) || (l > 4) || (k > 3))
7809 goto invalid_freq; /* &^@#! */
7812 /* Wait for M+*K+* */
7814 if(j < 2)
7815 break; /* Not yet */
7817 /* We have a frequency */
7819 strncpy(tmp, digitbuf ,sizeof(tmp) - 1);
7821 s = tmp;
7822 s1 = strsep(&s, "*"); /* Pick off MHz */
7823 s2 = strsep(&s,"*"); /* Pick off KHz and Hz */
7824 ls2 = strlen(s2);
7826 switch(ls2){ /* Allow partial entry of khz and hz digits for laziness support */
7827 case 1:
7828 ht = 0;
7829 k = 100 * atoi(s2);
7830 break;
7832 case 2:
7833 ht = 0;
7834 k = 10 * atoi(s2);
7835 break;
7837 case 3:
7838 if(!multimode){
7839 if((s2[2] != '0')&&(s2[2] != '5'))
7840 goto invalid_freq;
7842 ht = 0;
7843 k = atoi(s2);
7844 break;
7845 case 4:
7846 k = atoi(s2)/10;
7847 ht = 10 * (atoi(s2+(ls2-1)));
7848 break;
7850 case 5:
7851 k = atoi(s2)/100;
7852 ht = (atoi(s2+(ls2-2)));
7853 break;
7855 default:
7856 goto invalid_freq;
7859 /* Check frequency for validity and establish a default mode */
7861 snprintf(freq, sizeof(freq), "%s.%03d%02d",s1, k, ht);
7863 if(debug)
7864 printf("New frequency: %s\n", freq);
7866 split_freq(mhz, decimals, freq);
7867 m = atoi(mhz);
7868 d = atoi(decimals);
7870 if(check_freq(myrpt, m, d, &defmode)) /* Check to see if frequency entered is legit */
7871 goto invalid_freq;
7874 if((defmode == REM_MODE_FM) && (digitbuf[i] == '*')) /* If FM, user must enter and additional offset digit */
7875 break; /* Not yet */
7878 offset = REM_SIMPLEX; /* Assume simplex */
7880 if(defmode == REM_MODE_FM){
7881 oc = *s; /* Pick off offset */
7883 if (oc){
7884 switch(oc){
7885 case '1':
7886 offset = REM_MINUS;
7887 break;
7889 case '2':
7890 offset = REM_SIMPLEX;
7891 break;
7893 case '3':
7894 offset = REM_PLUS;
7895 break;
7897 default:
7898 goto invalid_freq;
7902 offsave = myrpt->offset;
7903 modesave = myrpt->remmode;
7904 strncpy(savestr, myrpt->freq, sizeof(savestr) - 1);
7905 strncpy(myrpt->freq, freq, sizeof(myrpt->freq) - 1);
7906 myrpt->offset = offset;
7907 myrpt->remmode = defmode;
7909 if (setrem(myrpt) == -1){
7910 myrpt->offset = offsave;
7911 myrpt->remmode = modesave;
7912 strncpy(myrpt->freq, savestr, sizeof(myrpt->freq) - 1);
7913 goto invalid_freq;
7916 return DC_COMPLETE;
7918 invalid_freq:
7919 rpt_telemetry(myrpt,INVFREQ,NULL);
7920 return DC_ERROR;
7922 case 3: /* set rx PL tone */
7923 for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
7924 if(digitbuf[i] == '*'){
7925 j++;
7926 continue;
7928 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
7929 return DC_ERROR;
7930 else{
7931 if(j)
7932 l++;
7933 else
7934 k++;
7937 if((j > 1) || (k > 3) || (l > 1))
7938 return DC_ERROR; /* &$@^! */
7939 i = strlen(digitbuf) - 1;
7940 if((j != 1) || (k < 2)|| (l != 1))
7941 break; /* Not yet */
7942 if(debug)
7943 printf("PL digits entered %s\n", digitbuf);
7945 strncpy(tmp, digitbuf, sizeof(tmp) - 1);
7946 /* see if we have at least 1 */
7947 s = strchr(tmp,'*');
7948 if(s)
7949 *s = '.';
7950 strncpy(savestr, myrpt->rxpl, sizeof(savestr) - 1);
7951 strncpy(myrpt->rxpl, tmp, sizeof(myrpt->rxpl) - 1);
7952 if(!strcmp(myrpt->remote, remote_rig_rbi))
7954 strncpy(myrpt->txpl, tmp, sizeof(myrpt->txpl) - 1);
7956 if (setrem(myrpt) == -1){
7957 strncpy(myrpt->rxpl, savestr, sizeof(myrpt->rxpl) - 1);
7958 return DC_ERROR;
7962 return DC_COMPLETE;
7964 case 4: /* set tx PL tone */
7965 /* cant set tx tone on RBI (rx tone does both) */
7966 if(!strcmp(myrpt->remote, remote_rig_rbi))
7967 return DC_ERROR;
7968 if(!strcmp(myrpt->remote, remote_rig_ic706))
7969 return DC_ERROR;
7970 for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
7971 if(digitbuf[i] == '*'){
7972 j++;
7973 continue;
7975 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
7976 return DC_ERROR;
7977 else{
7978 if(j)
7979 l++;
7980 else
7981 k++;
7984 if((j > 1) || (k > 3) || (l > 1))
7985 return DC_ERROR; /* &$@^! */
7986 i = strlen(digitbuf) - 1;
7987 if((j != 1) || (k < 2)|| (l != 1))
7988 break; /* Not yet */
7989 if(debug)
7990 printf("PL digits entered %s\n", digitbuf);
7992 strncpy(tmp, digitbuf, sizeof(tmp) - 1);
7993 /* see if we have at least 1 */
7994 s = strchr(tmp,'*');
7995 if(s)
7996 *s = '.';
7997 strncpy(savestr, myrpt->txpl, sizeof(savestr) - 1);
7998 strncpy(myrpt->txpl, tmp, sizeof(myrpt->txpl) - 1);
8000 if (setrem(myrpt) == -1){
8001 strncpy(myrpt->txpl, savestr, sizeof(myrpt->txpl) - 1);
8002 return DC_ERROR;
8006 return DC_COMPLETE;
8009 case 6: /* MODE (FM,USB,LSB,AM) */
8010 if(strlen(digitbuf) < 1)
8011 break;
8013 if(!multimode)
8014 return DC_ERROR; /* Multimode radios only */
8016 switch(*digitbuf){
8017 case '1':
8018 split_freq(mhz, decimals, myrpt->freq);
8019 m=atoi(mhz);
8020 if(m < 29) /* No FM allowed below 29MHz! */
8021 return DC_ERROR;
8022 myrpt->remmode = REM_MODE_FM;
8024 rpt_telemetry(myrpt,REMMODE,NULL);
8025 break;
8027 case '2':
8028 myrpt->remmode = REM_MODE_USB;
8029 rpt_telemetry(myrpt,REMMODE,NULL);
8030 break;
8032 case '3':
8033 myrpt->remmode = REM_MODE_LSB;
8034 rpt_telemetry(myrpt,REMMODE,NULL);
8035 break;
8037 case '4':
8038 myrpt->remmode = REM_MODE_AM;
8039 rpt_telemetry(myrpt,REMMODE,NULL);
8040 break;
8042 default:
8043 return DC_ERROR;
8046 if(setrem(myrpt))
8047 return DC_ERROR;
8048 return DC_COMPLETEQUIET;
8049 case 99:
8050 /* cant log in when logged in */
8051 if (myrpt->loginlevel[0])
8052 return DC_ERROR;
8053 *myrpt->loginuser = 0;
8054 myrpt->loginlevel[0] = 0;
8055 cp = strdup(param);
8056 cp1 = strchr(cp,',');
8057 ast_mutex_lock(&myrpt->lock);
8058 if (cp1)
8060 *cp1 = 0;
8061 cp2 = strchr(cp1 + 1,',');
8062 if (cp2)
8064 *cp2 = 0;
8065 strncpy(myrpt->loginlevel,cp2 + 1,
8066 sizeof(myrpt->loginlevel) - 1);
8068 strncpy(myrpt->loginuser,cp1 + 1,sizeof(myrpt->loginuser));
8069 ast_mutex_unlock(&myrpt->lock);
8070 if (myrpt->p.archivedir)
8072 char str[100];
8074 sprintf(str,"LOGIN,%s,%s",
8075 myrpt->loginuser,myrpt->loginlevel);
8076 donodelog(myrpt,str);
8078 if (debug)
8079 printf("loginuser %s level %s\n",myrpt->loginuser,myrpt->loginlevel);
8080 rpt_telemetry(myrpt,REMLOGIN,NULL);
8082 free(cp);
8083 return DC_COMPLETEQUIET;
8084 case 100: /* RX PL Off */
8085 myrpt->rxplon = 0;
8086 setrem(myrpt);
8087 rpt_telemetry(myrpt,REMXXX,(void *)p);
8088 return DC_COMPLETEQUIET;
8089 case 101: /* RX PL On */
8090 myrpt->rxplon = 1;
8091 setrem(myrpt);
8092 rpt_telemetry(myrpt,REMXXX,(void *)p);
8093 return DC_COMPLETEQUIET;
8094 case 102: /* TX PL Off */
8095 myrpt->txplon = 0;
8096 setrem(myrpt);
8097 rpt_telemetry(myrpt,REMXXX,(void *)p);
8098 return DC_COMPLETEQUIET;
8099 case 103: /* TX PL On */
8100 myrpt->txplon = 1;
8101 setrem(myrpt);
8102 rpt_telemetry(myrpt,REMXXX,(void *)p);
8103 return DC_COMPLETEQUIET;
8104 case 104: /* Low Power */
8105 if(!strcmp(myrpt->remote, remote_rig_ic706))
8106 return DC_ERROR;
8107 myrpt->powerlevel = REM_LOWPWR;
8108 setrem(myrpt);
8109 rpt_telemetry(myrpt,REMXXX,(void *)p);
8110 return DC_COMPLETEQUIET;
8111 case 105: /* Medium Power */
8112 if(!strcmp(myrpt->remote, remote_rig_ic706))
8113 return DC_ERROR;
8114 myrpt->powerlevel = REM_MEDPWR;
8115 setrem(myrpt);
8116 rpt_telemetry(myrpt,REMXXX,(void *)p);
8117 return DC_COMPLETEQUIET;
8118 case 106: /* Hi Power */
8119 if(!strcmp(myrpt->remote, remote_rig_ic706))
8120 return DC_ERROR;
8121 myrpt->powerlevel = REM_HIPWR;
8122 setrem(myrpt);
8123 rpt_telemetry(myrpt,REMXXX,(void *)p);
8124 return DC_COMPLETEQUIET;
8125 case 107: /* Bump down 20Hz */
8126 multimode_bump_freq(myrpt, -20);
8127 return DC_COMPLETE;
8128 case 108: /* Bump down 100Hz */
8129 multimode_bump_freq(myrpt, -100);
8130 return DC_COMPLETE;
8131 case 109: /* Bump down 500Hz */
8132 multimode_bump_freq(myrpt, -500);
8133 return DC_COMPLETE;
8134 case 110: /* Bump up 20Hz */
8135 multimode_bump_freq(myrpt, 20);
8136 return DC_COMPLETE;
8137 case 111: /* Bump up 100Hz */
8138 multimode_bump_freq(myrpt, 100);
8139 return DC_COMPLETE;
8140 case 112: /* Bump up 500Hz */
8141 multimode_bump_freq(myrpt, 500);
8142 return DC_COMPLETE;
8143 case 113: /* Scan down slow */
8144 myrpt->scantimer = REM_SCANTIME;
8145 myrpt->hfscanmode = HF_SCAN_DOWN_SLOW;
8146 rpt_telemetry(myrpt,REMXXX,(void *)p);
8147 return DC_COMPLETEQUIET;
8148 case 114: /* Scan down quick */
8149 myrpt->scantimer = REM_SCANTIME;
8150 myrpt->hfscanmode = HF_SCAN_DOWN_QUICK;
8151 rpt_telemetry(myrpt,REMXXX,(void *)p);
8152 return DC_COMPLETEQUIET;
8153 case 115: /* Scan down fast */
8154 myrpt->scantimer = REM_SCANTIME;
8155 myrpt->hfscanmode = HF_SCAN_DOWN_FAST;
8156 rpt_telemetry(myrpt,REMXXX,(void *)p);
8157 return DC_COMPLETEQUIET;
8158 case 116: /* Scan up slow */
8159 myrpt->scantimer = REM_SCANTIME;
8160 myrpt->hfscanmode = HF_SCAN_UP_SLOW;
8161 rpt_telemetry(myrpt,REMXXX,(void *)p);
8162 return DC_COMPLETEQUIET;
8163 case 117: /* Scan up quick */
8164 myrpt->scantimer = REM_SCANTIME;
8165 myrpt->hfscanmode = HF_SCAN_UP_QUICK;
8166 rpt_telemetry(myrpt,REMXXX,(void *)p);
8167 return DC_COMPLETEQUIET;
8168 case 118: /* Scan up fast */
8169 myrpt->scantimer = REM_SCANTIME;
8170 myrpt->hfscanmode = HF_SCAN_UP_FAST;
8171 rpt_telemetry(myrpt,REMXXX,(void *)p);
8172 return DC_COMPLETEQUIET;
8173 case 119: /* Tune Request */
8174 /* if not currently going, and valid to do */
8175 if((!myrpt->tunerequest) &&
8176 ((!strcmp(myrpt->remote, remote_rig_ft897) ||
8177 !strcmp(myrpt->remote, remote_rig_ic706)) )) {
8178 myrpt->remotetx = 0;
8179 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
8180 myrpt->tunerequest = 1;
8181 rpt_telemetry(myrpt,TUNE,NULL);
8182 return DC_COMPLETEQUIET;
8184 return DC_ERROR;
8185 case 5: /* Long Status */
8186 rpt_telemetry(myrpt,REMLONGSTATUS,NULL);
8187 return DC_COMPLETEQUIET;
8188 case 140: /* Short Status */
8189 rpt_telemetry(myrpt,REMSHORTSTATUS,NULL);
8190 return DC_COMPLETEQUIET;
8191 case 200:
8192 case 201:
8193 case 202:
8194 case 203:
8195 case 204:
8196 case 205:
8197 case 206:
8198 case 207:
8199 case 208:
8200 case 209:
8201 case 210:
8202 case 211:
8203 case 212:
8204 case 213:
8205 case 214:
8206 case 215:
8207 do_dtmf_local(myrpt,remdtmfstr[p - 200]);
8208 return DC_COMPLETEQUIET;
8209 default:
8210 break;
8212 return DC_INDETERMINATE;
8216 static int handle_remote_dtmf_digit(struct rpt *myrpt,char c, char *keyed, int phonemode)
8218 time_t now;
8219 int ret,res = 0,src;
8221 time(&myrpt->last_activity_time);
8222 /* Stop scan mode if in scan mode */
8223 if(myrpt->hfscanmode){
8224 stop_scan(myrpt);
8225 return 0;
8228 time(&now);
8229 /* if timed-out */
8230 if ((myrpt->dtmf_time_rem + DTMF_TIMEOUT) < now)
8232 myrpt->dtmfidx = -1;
8233 myrpt->dtmfbuf[0] = 0;
8234 myrpt->dtmf_time_rem = 0;
8236 /* if decode not active */
8237 if (myrpt->dtmfidx == -1)
8239 /* if not lead-in digit, dont worry */
8240 if (c != myrpt->p.funcchar)
8242 if (!myrpt->p.propagate_dtmf)
8244 rpt_mutex_lock(&myrpt->lock);
8245 do_dtmf_local(myrpt,c);
8246 rpt_mutex_unlock(&myrpt->lock);
8248 return 0;
8250 myrpt->dtmfidx = 0;
8251 myrpt->dtmfbuf[0] = 0;
8252 myrpt->dtmf_time_rem = now;
8253 return 0;
8255 /* if too many in buffer, start over */
8256 if (myrpt->dtmfidx >= MAXDTMF)
8258 myrpt->dtmfidx = 0;
8259 myrpt->dtmfbuf[0] = 0;
8260 myrpt->dtmf_time_rem = now;
8262 if (c == myrpt->p.funcchar)
8264 /* if star at beginning, or 2 together, erase buffer */
8265 if ((myrpt->dtmfidx < 1) ||
8266 (myrpt->dtmfbuf[myrpt->dtmfidx - 1] == myrpt->p.funcchar))
8268 myrpt->dtmfidx = 0;
8269 myrpt->dtmfbuf[0] = 0;
8270 myrpt->dtmf_time_rem = now;
8271 return 0;
8274 myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
8275 myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
8276 myrpt->dtmf_time_rem = now;
8279 src = SOURCE_RMT;
8280 if (phonemode > 1) src = SOURCE_DPHONE;
8281 else if (phonemode) src = SOURCE_PHONE;
8282 ret = collect_function_digits(myrpt, myrpt->dtmfbuf, src, NULL);
8284 switch(ret){
8286 case DC_INDETERMINATE:
8287 res = 0;
8288 break;
8290 case DC_DOKEY:
8291 if (keyed) *keyed = 1;
8292 res = 0;
8293 break;
8295 case DC_REQ_FLUSH:
8296 myrpt->dtmfidx = 0;
8297 myrpt->dtmfbuf[0] = 0;
8298 res = 0;
8299 break;
8302 case DC_COMPLETE:
8303 res = 1;
8304 case DC_COMPLETEQUIET:
8305 myrpt->totalexecdcommands++;
8306 myrpt->dailyexecdcommands++;
8307 strncpy(myrpt->lastdtmfcommand, myrpt->dtmfbuf, MAXDTMF-1);
8308 myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
8309 myrpt->dtmfbuf[0] = 0;
8310 myrpt->dtmfidx = -1;
8311 myrpt->dtmf_time_rem = 0;
8312 break;
8314 case DC_ERROR:
8315 default:
8316 myrpt->dtmfbuf[0] = 0;
8317 myrpt->dtmfidx = -1;
8318 myrpt->dtmf_time_rem = 0;
8319 res = 0;
8320 break;
8323 return res;
8326 static int handle_remote_data(struct rpt *myrpt, char *str)
8328 char tmp[300],cmd[300],dest[300],src[300],c;
8329 int seq,res;
8331 /* put string in our buffer */
8332 strncpy(tmp,str,sizeof(tmp) - 1);
8333 if (!strcmp(tmp,discstr)) return 0;
8335 #ifndef DO_NOT_NOTIFY_MDC1200_ON_REMOTE_BASES
8336 if (tmp[0] == 'I')
8338 if (sscanf(tmp,"%s %s %x",cmd,src,&seq) != 3)
8340 ast_log(LOG_WARNING, "Unable to parse ident string %s\n",str);
8341 return 0;
8343 mdc1200_notify(myrpt,src,seq);
8344 return 0;
8346 #endif
8347 if (sscanf(tmp,"%s %s %s %d %c",cmd,dest,src,&seq,&c) != 5)
8349 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
8350 return 0;
8352 if (strcmp(cmd,"D"))
8354 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
8355 return 0;
8357 /* if not for me, ignore */
8358 if (strcmp(dest,myrpt->name)) return 0;
8359 if (myrpt->p.archivedir)
8361 char str[100];
8363 sprintf(str,"DTMF,%c",c);
8364 donodelog(myrpt,str);
8366 c = func_xlat(myrpt,c,&myrpt->p.outxlat);
8367 if (!c) return(0);
8368 res = handle_remote_dtmf_digit(myrpt,c, NULL, 0);
8369 if (res != 1)
8370 return res;
8371 rpt_telemetry(myrpt,COMPLETE,NULL);
8372 return 0;
8375 static int handle_remote_phone_dtmf(struct rpt *myrpt, char c, char *keyed, int phonemode)
8377 int res;
8380 if (keyed && *keyed && (c == myrpt->p.endchar))
8382 *keyed = 0;
8383 return DC_INDETERMINATE;
8386 if (myrpt->p.archivedir)
8388 char str[100];
8390 sprintf(str,"DTMF(P),%c",c);
8391 donodelog(myrpt,str);
8393 res = handle_remote_dtmf_digit(myrpt,c,keyed, phonemode);
8394 if (res != 1)
8395 return res;
8396 rpt_telemetry(myrpt,COMPLETE,NULL);
8397 return 0;
8400 static int attempt_reconnect(struct rpt *myrpt, struct rpt_link *l)
8402 char *val, *s, *s1, *s2, *tele;
8403 char tmp[300], deststr[300] = "";
8405 val = node_lookup(myrpt,l->name);
8406 if (!val)
8408 fprintf(stderr,"attempt_reconnect: cannot find node %s\n",l->name);
8409 return -1;
8412 rpt_mutex_lock(&myrpt->lock);
8413 /* remove from queue */
8414 remque((struct qelem *) l);
8415 rpt_mutex_unlock(&myrpt->lock);
8416 strncpy(tmp,val,sizeof(tmp) - 1);
8417 s = tmp;
8418 s1 = strsep(&s,",");
8419 s2 = strsep(&s,",");
8420 snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
8421 tele = strchr(deststr, '/');
8422 if (!tele) {
8423 fprintf(stderr,"attempt_reconnect:Dial number (%s) must be in format tech/number\n",deststr);
8424 return -1;
8426 *tele++ = 0;
8427 l->elaptime = 0;
8428 l->connecttime = 0;
8429 l->thisconnected = 0;
8430 l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL);
8431 if (l->chan){
8432 ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
8433 ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
8434 l->chan->whentohangup = 0;
8435 l->chan->appl = "Apprpt";
8436 l->chan->data = "(Remote Rx)";
8437 if (option_verbose > 2)
8438 ast_verbose(VERBOSE_PREFIX_3 "rpt (attempt_reconnect) initiating call to %s/%s on %s\n",
8439 deststr, tele, l->chan->name);
8440 if(l->chan->cid.cid_num)
8441 free(l->chan->cid.cid_num);
8442 l->chan->cid.cid_num = strdup(myrpt->name);
8443 ast_call(l->chan,tele,999);
8446 else
8448 if (option_verbose > 2)
8449 ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
8450 deststr,tele,l->chan->name);
8451 return -1;
8453 rpt_mutex_lock(&myrpt->lock);
8454 /* put back in queue */
8455 insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
8456 rpt_mutex_unlock(&myrpt->lock);
8457 ast_log(LOG_NOTICE,"Reconnect Attempt to %s in process\n",l->name);
8458 return 0;
8461 /* 0 return=continue, 1 return = break, -1 return = error */
8462 static void local_dtmf_helper(struct rpt *myrpt,char c)
8464 int res;
8465 pthread_attr_t attr;
8466 char cmd[MAXDTMF+1] = "";
8468 if (myrpt->p.archivedir)
8470 char str[100];
8472 sprintf(str,"DTMF,MAIN,%c",c);
8473 donodelog(myrpt,str);
8475 if (c == myrpt->p.endchar)
8477 /* if in simple mode, kill autopatch */
8478 if (myrpt->p.simple && myrpt->callmode)
8480 rpt_mutex_lock(&myrpt->lock);
8481 myrpt->callmode = 0;
8482 rpt_mutex_unlock(&myrpt->lock);
8483 rpt_telemetry(myrpt,TERM,NULL);
8484 return;
8486 rpt_mutex_lock(&myrpt->lock);
8487 myrpt->stopgen = 1;
8488 if (myrpt->cmdnode[0])
8490 myrpt->cmdnode[0] = 0;
8491 myrpt->dtmfidx = -1;
8492 myrpt->dtmfbuf[0] = 0;
8493 rpt_mutex_unlock(&myrpt->lock);
8494 rpt_telemetry(myrpt,COMPLETE,NULL);
8496 else
8498 rpt_mutex_unlock(&myrpt->lock);
8499 if (myrpt->p.propagate_phonedtmf)
8500 do_dtmf_phone(myrpt,NULL,c);
8502 return;
8504 rpt_mutex_lock(&myrpt->lock);
8505 if (myrpt->cmdnode[0])
8507 rpt_mutex_unlock(&myrpt->lock);
8508 send_link_dtmf(myrpt,c);
8509 return;
8511 if (!myrpt->p.simple)
8513 if (c == myrpt->p.funcchar)
8515 myrpt->dtmfidx = 0;
8516 myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
8517 rpt_mutex_unlock(&myrpt->lock);
8518 time(&myrpt->dtmf_time);
8519 return;
8521 else if ((c != myrpt->p.endchar) && (myrpt->dtmfidx >= 0))
8523 time(&myrpt->dtmf_time);
8525 if (myrpt->dtmfidx < MAXDTMF)
8527 myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
8528 myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
8530 strncpy(cmd, myrpt->dtmfbuf, sizeof(cmd) - 1);
8532 rpt_mutex_unlock(&myrpt->lock);
8533 res = collect_function_digits(myrpt, cmd, SOURCE_RPT, NULL);
8534 rpt_mutex_lock(&myrpt->lock);
8535 switch(res){
8536 case DC_INDETERMINATE:
8537 break;
8538 case DC_REQ_FLUSH:
8539 myrpt->dtmfidx = 0;
8540 myrpt->dtmfbuf[0] = 0;
8541 break;
8542 case DC_COMPLETE:
8543 case DC_COMPLETEQUIET:
8544 myrpt->totalexecdcommands++;
8545 myrpt->dailyexecdcommands++;
8546 strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
8547 myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
8548 myrpt->dtmfbuf[0] = 0;
8549 myrpt->dtmfidx = -1;
8550 myrpt->dtmf_time = 0;
8551 break;
8553 case DC_ERROR:
8554 default:
8555 myrpt->dtmfbuf[0] = 0;
8556 myrpt->dtmfidx = -1;
8557 myrpt->dtmf_time = 0;
8558 break;
8560 if(res != DC_INDETERMINATE) {
8561 rpt_mutex_unlock(&myrpt->lock);
8562 return;
8567 else /* if simple */
8569 if ((!myrpt->callmode) && (c == myrpt->p.funcchar))
8571 myrpt->callmode = 1;
8572 myrpt->patchnoct = 0;
8573 myrpt->patchquiet = 0;
8574 myrpt->patchfarenddisconnect = 0;
8575 myrpt->patchdialtime = 0;
8576 strncpy(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
8577 myrpt->cidx = 0;
8578 myrpt->exten[myrpt->cidx] = 0;
8579 rpt_mutex_unlock(&myrpt->lock);
8580 pthread_attr_init(&attr);
8581 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
8582 ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *)myrpt);
8583 return;
8586 if (myrpt->callmode == 1)
8588 myrpt->exten[myrpt->cidx++] = c;
8589 myrpt->exten[myrpt->cidx] = 0;
8590 /* if this exists */
8591 if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
8593 myrpt->callmode = 2;
8594 rpt_mutex_unlock(&myrpt->lock);
8595 if(!myrpt->patchquiet)
8596 rpt_telemetry(myrpt,PROC,NULL);
8597 return;
8599 /* if can continue, do so */
8600 if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
8602 /* call has failed, inform user */
8603 myrpt->callmode = 4;
8605 rpt_mutex_unlock(&myrpt->lock);
8606 return;
8608 if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
8610 myrpt->mydtmf = c;
8612 rpt_mutex_unlock(&myrpt->lock);
8613 if ((myrpt->dtmfidx < 0) && myrpt->p.propagate_phonedtmf)
8614 do_dtmf_phone(myrpt,NULL,c);
8615 return;
8619 /* place an ID event in the telemetry queue */
8621 static void queue_id(struct rpt *myrpt)
8623 if(myrpt->p.idtime){ /* ID time must be non-zero */
8624 myrpt->mustid = myrpt->tailid = 0;
8625 myrpt->idtimer = myrpt->p.idtime; /* Reset our ID timer */
8626 rpt_mutex_unlock(&myrpt->lock);
8627 rpt_telemetry(myrpt,ID,NULL);
8628 rpt_mutex_lock(&myrpt->lock);
8632 /* Scheduler */
8633 /* must be called locked */
8635 static void do_scheduler(struct rpt *myrpt)
8637 int i,res;
8638 struct tm tmnow;
8639 struct ast_variable *skedlist;
8640 char *strs[5],*vp,*val,value[100];
8642 memcpy(&myrpt->lasttv, &myrpt->curtv, sizeof(struct timeval));
8644 if( (res = gettimeofday(&myrpt->curtv, NULL)) < 0)
8645 ast_log(LOG_NOTICE, "Scheduler gettime of day returned: %s\n", strerror(res));
8647 /* Try to get close to a 1 second resolution */
8649 if(myrpt->lasttv.tv_sec == myrpt->curtv.tv_sec)
8650 return;
8652 rpt_localtime(&myrpt->curtv.tv_sec, &tmnow);
8654 /* If midnight, then reset all daily statistics */
8656 if((tmnow.tm_hour == 0)&&(tmnow.tm_min == 0)&&(tmnow.tm_sec == 0)){
8657 myrpt->dailykeyups = 0;
8658 myrpt->dailytxtime = 0;
8659 myrpt->dailykerchunks = 0;
8660 myrpt->dailyexecdcommands = 0;
8663 if(tmnow.tm_sec != 0)
8664 return;
8666 /* Code below only executes once per minute */
8669 /* Don't schedule if remote */
8671 if (myrpt->remote)
8672 return;
8674 /* Don't schedule if disabled */
8676 if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable){
8677 if(debug > 6)
8678 ast_log(LOG_NOTICE, "Scheduler disabled\n");
8679 return;
8682 if(!myrpt->p.skedstanzaname){ /* No stanza means we do nothing */
8683 if(debug > 6)
8684 ast_log(LOG_NOTICE,"No stanza for scheduler in rpt.conf\n");
8685 return;
8688 /* get pointer to linked list of scheduler entries */
8689 skedlist = ast_variable_browse(myrpt->cfg, myrpt->p.skedstanzaname);
8691 if(debug > 6){
8692 ast_log(LOG_NOTICE, "Time now: %02d:%02d %02d %02d %02d\n",
8693 tmnow.tm_hour,tmnow.tm_min,tmnow.tm_mday,tmnow.tm_mon + 1, tmnow.tm_wday);
8695 /* walk the list */
8696 for(; skedlist; skedlist = skedlist->next){
8697 if(debug > 6)
8698 ast_log(LOG_NOTICE, "Scheduler entry %s = %s being considered\n",skedlist->name, skedlist->value);
8699 strncpy(value,skedlist->value,99);
8700 value[99] = 0;
8701 /* point to the substrings for minute, hour, dom, month, and dow */
8702 for( i = 0, vp = value ; i < 5; i++){
8703 if(!*vp)
8704 break;
8705 while((*vp == ' ') || (*vp == 0x09)) /* get rid of any leading white space */
8706 vp++;
8707 strs[i] = vp; /* save pointer to beginning of substring */
8708 while((*vp != ' ') && (*vp != 0x09) && (*vp != 0)) /* skip over substring */
8709 vp++;
8710 if(*vp)
8711 *vp++ = 0; /* mark end of substring */
8713 if(debug > 6)
8714 ast_log(LOG_NOTICE, "i = %d, min = %s, hour = %s, mday=%s, mon=%s, wday=%s\n",i,
8715 strs[0], strs[1], strs[2], strs[3], strs[4]);
8716 if(i == 5){
8717 if((*strs[0] != '*')&&(atoi(strs[0]) != tmnow.tm_min))
8718 continue;
8719 if((*strs[1] != '*')&&(atoi(strs[1]) != tmnow.tm_hour))
8720 continue;
8721 if((*strs[2] != '*')&&(atoi(strs[2]) != tmnow.tm_mday))
8722 continue;
8723 if((*strs[3] != '*')&&(atoi(strs[3]) != tmnow.tm_mon + 1))
8724 continue;
8725 if(atoi(strs[4]) == 7)
8726 strs[4] = "0";
8727 if((*strs[4] != '*')&&(atoi(strs[4]) != tmnow.tm_wday))
8728 continue;
8729 if(debug)
8730 ast_log(LOG_NOTICE, "Executing scheduler entry %s = %s\n", skedlist->name, skedlist->value);
8731 if(atoi(skedlist->name) == 0)
8732 return; /* Zero is reserved for the startup macro */
8733 val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, skedlist->name);
8734 if (!val){
8735 ast_log(LOG_WARNING,"Scheduler could not find macro %s\n",skedlist->name);
8736 return; /* Macro not found */
8738 if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val)){
8739 ast_log(LOG_WARNING, "Scheduler could not execute macro %s: Macro buffer full\n",
8740 skedlist->name);
8741 return; /* Macro buffer full */
8743 myrpt->macrotimer = MACROTIME;
8744 strncat(myrpt->macrobuf,val,MAXMACRO - strlen(myrpt->macrobuf) - 1);
8746 else{
8747 ast_log(LOG_WARNING,"Malformed scheduler entry in rpt.conf: %s = %s\n",
8748 skedlist->name, skedlist->value);
8754 /* single thread with one file (request) to dial */
8755 static void *rpt(void *this)
8757 struct rpt *myrpt = (struct rpt *)this;
8758 char *tele,*idtalkover,c;
8759 int ms = MSWAIT,i,lasttx=0,val,remrx=0,identqueued,othertelemqueued;
8760 int tailmessagequeued,ctqueued,dtmfed;
8761 struct ast_channel *who;
8762 struct dahdi_confinfo ci; /* conference info */
8763 time_t t;
8764 struct rpt_link *l,*m;
8765 struct rpt_tele *telem;
8766 char tmpstr[300],lstr[MAXLINKLIST];
8769 if (myrpt->p.archivedir) mkdir(myrpt->p.archivedir,0600);
8770 sprintf(tmpstr,"%s/%s",myrpt->p.archivedir,myrpt->name);
8771 mkdir(tmpstr,0600);
8772 rpt_mutex_lock(&myrpt->lock);
8774 telem = myrpt->tele.next;
8775 while(telem != &myrpt->tele)
8777 ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
8778 telem = telem->next;
8780 rpt_mutex_unlock(&myrpt->lock);
8781 /* find our index, and load the vars initially */
8782 for(i = 0; i < nrpts; i++)
8784 if (&rpt_vars[i] == myrpt)
8786 load_rpt_vars(i,0);
8787 break;
8790 rpt_mutex_lock(&myrpt->lock);
8791 strncpy(tmpstr,myrpt->rxchanname,sizeof(tmpstr) - 1);
8792 tele = strchr(tmpstr,'/');
8793 if (!tele)
8795 fprintf(stderr,"rpt:Rxchannel Dial number (%s) must be in format tech/number\n",myrpt->rxchanname);
8796 rpt_mutex_unlock(&myrpt->lock);
8797 myrpt->rpt_thread = AST_PTHREADT_STOP;
8798 pthread_exit(NULL);
8800 *tele++ = 0;
8801 myrpt->rxchannel = ast_request(tmpstr,AST_FORMAT_SLINEAR,tele,NULL);
8802 myrpt->zaprxchannel = NULL;
8803 if (!strcasecmp(tmpstr,"Zap"))
8804 myrpt->zaprxchannel = myrpt->rxchannel;
8805 if (myrpt->rxchannel)
8807 if (myrpt->rxchannel->_state == AST_STATE_BUSY)
8809 fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
8810 rpt_mutex_unlock(&myrpt->lock);
8811 ast_hangup(myrpt->rxchannel);
8812 myrpt->rpt_thread = AST_PTHREADT_STOP;
8813 pthread_exit(NULL);
8815 ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
8816 ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
8817 #ifdef AST_CDR_FLAG_POST_DISABLED
8818 ast_set_flag(myrpt->rxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
8819 #endif
8820 myrpt->rxchannel->whentohangup = 0;
8821 myrpt->rxchannel->appl = "Apprpt";
8822 myrpt->rxchannel->data = "(Repeater Rx)";
8823 if (option_verbose > 2)
8824 ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
8825 tmpstr,tele,myrpt->rxchannel->name);
8826 ast_call(myrpt->rxchannel,tele,999);
8827 if (myrpt->rxchannel->_state != AST_STATE_UP)
8829 rpt_mutex_unlock(&myrpt->lock);
8830 ast_hangup(myrpt->rxchannel);
8831 myrpt->rpt_thread = AST_PTHREADT_STOP;
8832 pthread_exit(NULL);
8835 else
8837 fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
8838 rpt_mutex_unlock(&myrpt->lock);
8839 myrpt->rpt_thread = AST_PTHREADT_STOP;
8840 pthread_exit(NULL);
8842 myrpt->zaptxchannel = NULL;
8843 if (myrpt->txchanname)
8845 strncpy(tmpstr,myrpt->txchanname,sizeof(tmpstr) - 1);
8846 tele = strchr(tmpstr,'/');
8847 if (!tele)
8849 fprintf(stderr,"rpt:Txchannel Dial number (%s) must be in format tech/number\n",myrpt->txchanname);
8850 rpt_mutex_unlock(&myrpt->lock);
8851 ast_hangup(myrpt->rxchannel);
8852 myrpt->rpt_thread = AST_PTHREADT_STOP;
8853 pthread_exit(NULL);
8855 *tele++ = 0;
8856 myrpt->txchannel = ast_request(tmpstr,AST_FORMAT_SLINEAR,tele,NULL);
8857 if (!strcasecmp(tmpstr,"Zap"))
8858 myrpt->zaptxchannel = myrpt->txchannel;
8859 if (myrpt->txchannel)
8861 if (myrpt->txchannel->_state == AST_STATE_BUSY)
8863 fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
8864 rpt_mutex_unlock(&myrpt->lock);
8865 ast_hangup(myrpt->txchannel);
8866 ast_hangup(myrpt->rxchannel);
8867 myrpt->rpt_thread = AST_PTHREADT_STOP;
8868 pthread_exit(NULL);
8870 ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
8871 ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
8872 #ifdef AST_CDR_FLAG_POST_DISABLED
8873 ast_set_flag(myrpt->txchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
8874 #endif
8875 myrpt->txchannel->whentohangup = 0;
8876 myrpt->txchannel->appl = "Apprpt";
8877 myrpt->txchannel->data = "(Repeater Tx)";
8878 if (option_verbose > 2)
8879 ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
8880 tmpstr,tele,myrpt->txchannel->name);
8881 ast_call(myrpt->txchannel,tele,999);
8882 if (myrpt->rxchannel->_state != AST_STATE_UP)
8884 rpt_mutex_unlock(&myrpt->lock);
8885 ast_hangup(myrpt->rxchannel);
8886 ast_hangup(myrpt->txchannel);
8887 myrpt->rpt_thread = AST_PTHREADT_STOP;
8888 pthread_exit(NULL);
8891 else
8893 fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
8894 rpt_mutex_unlock(&myrpt->lock);
8895 ast_hangup(myrpt->rxchannel);
8896 myrpt->rpt_thread = AST_PTHREADT_STOP;
8897 pthread_exit(NULL);
8900 else
8902 myrpt->txchannel = myrpt->rxchannel;
8904 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
8905 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
8906 /* allocate a pseudo-channel thru asterisk */
8907 myrpt->pchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
8908 if (!myrpt->pchannel)
8910 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
8911 rpt_mutex_unlock(&myrpt->lock);
8912 if (myrpt->txchannel != myrpt->rxchannel)
8913 ast_hangup(myrpt->txchannel);
8914 ast_hangup(myrpt->rxchannel);
8915 myrpt->rpt_thread = AST_PTHREADT_STOP;
8916 pthread_exit(NULL);
8918 #ifdef AST_CDR_FLAG_POST_DISABLED
8919 ast_set_flag(myrpt->pchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
8920 #endif
8921 if (!myrpt->zaprxchannel) myrpt->zaprxchannel = myrpt->pchannel;
8922 if (!myrpt->zaptxchannel)
8924 /* allocate a pseudo-channel thru asterisk */
8925 myrpt->zaptxchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
8926 if (!myrpt->zaptxchannel)
8928 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
8929 rpt_mutex_unlock(&myrpt->lock);
8930 if (myrpt->txchannel != myrpt->rxchannel)
8931 ast_hangup(myrpt->txchannel);
8932 ast_hangup(myrpt->rxchannel);
8933 myrpt->rpt_thread = AST_PTHREADT_STOP;
8934 pthread_exit(NULL);
8936 ast_set_read_format(myrpt->zaptxchannel,AST_FORMAT_SLINEAR);
8937 ast_set_write_format(myrpt->zaptxchannel,AST_FORMAT_SLINEAR);
8938 #ifdef AST_CDR_FLAG_POST_DISABLED
8939 ast_set_flag(myrpt->zaptxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
8940 #endif
8942 /* allocate a pseudo-channel thru asterisk */
8943 myrpt->monchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
8944 if (!myrpt->monchannel)
8946 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
8947 rpt_mutex_unlock(&myrpt->lock);
8948 if (myrpt->txchannel != myrpt->rxchannel)
8949 ast_hangup(myrpt->txchannel);
8950 ast_hangup(myrpt->rxchannel);
8951 myrpt->rpt_thread = AST_PTHREADT_STOP;
8952 pthread_exit(NULL);
8954 ast_set_read_format(myrpt->monchannel,AST_FORMAT_SLINEAR);
8955 ast_set_write_format(myrpt->monchannel,AST_FORMAT_SLINEAR);
8956 #ifdef AST_CDR_FLAG_POST_DISABLED
8957 ast_set_flag(myrpt->monchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
8958 #endif
8959 /* make a conference for the tx */
8960 ci.chan = 0;
8961 ci.confno = -1; /* make a new conf */
8962 ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER;
8963 /* first put the channel on the conference in proper mode */
8964 if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
8966 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
8967 rpt_mutex_unlock(&myrpt->lock);
8968 ast_hangup(myrpt->pchannel);
8969 ast_hangup(myrpt->monchannel);
8970 if (myrpt->txchannel != myrpt->rxchannel)
8971 ast_hangup(myrpt->txchannel);
8972 ast_hangup(myrpt->rxchannel);
8973 myrpt->rpt_thread = AST_PTHREADT_STOP;
8974 pthread_exit(NULL);
8976 /* save tx conference number */
8977 myrpt->txconf = ci.confno;
8978 /* make a conference for the pseudo */
8979 ci.chan = 0;
8980 ci.confno = -1; /* make a new conf */
8981 ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? DAHDI_CONF_CONFANNMON :
8982 (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
8983 /* first put the channel on the conference in announce mode */
8984 if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
8986 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
8987 rpt_mutex_unlock(&myrpt->lock);
8988 ast_hangup(myrpt->pchannel);
8989 ast_hangup(myrpt->monchannel);
8990 if (myrpt->txchannel != myrpt->rxchannel)
8991 ast_hangup(myrpt->txchannel);
8992 ast_hangup(myrpt->rxchannel);
8993 myrpt->rpt_thread = AST_PTHREADT_STOP;
8994 pthread_exit(NULL);
8996 /* save pseudo channel conference number */
8997 myrpt->conf = ci.confno;
8998 /* make a conference for the pseudo */
8999 ci.chan = 0;
9000 if ((strstr(myrpt->txchannel->name,"pseudo") == NULL) &&
9001 (myrpt->zaptxchannel == myrpt->txchannel))
9003 /* get tx channel's port number */
9004 if (ioctl(myrpt->txchannel->fds[0],DAHDI_CHANNO,&ci.confno) == -1)
9006 ast_log(LOG_WARNING, "Unable to set tx channel's chan number\n");
9007 rpt_mutex_unlock(&myrpt->lock);
9008 ast_hangup(myrpt->pchannel);
9009 ast_hangup(myrpt->monchannel);
9010 if (myrpt->txchannel != myrpt->rxchannel)
9011 ast_hangup(myrpt->txchannel);
9012 ast_hangup(myrpt->rxchannel);
9013 myrpt->rpt_thread = AST_PTHREADT_STOP;
9014 pthread_exit(NULL);
9016 ci.confmode = DAHDI_CONF_MONITORTX;
9018 else
9020 ci.confno = myrpt->txconf;
9021 ci.confmode = DAHDI_CONF_CONFANNMON;
9023 /* first put the channel on the conference in announce mode */
9024 if (ioctl(myrpt->monchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
9026 ast_log(LOG_WARNING, "Unable to set conference mode for monitor\n");
9027 rpt_mutex_unlock(&myrpt->lock);
9028 ast_hangup(myrpt->pchannel);
9029 ast_hangup(myrpt->monchannel);
9030 if (myrpt->txchannel != myrpt->rxchannel)
9031 ast_hangup(myrpt->txchannel);
9032 ast_hangup(myrpt->rxchannel);
9033 myrpt->rpt_thread = AST_PTHREADT_STOP;
9034 pthread_exit(NULL);
9036 /* allocate a pseudo-channel thru asterisk */
9037 myrpt->txpchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
9038 if (!myrpt->txpchannel)
9040 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
9041 rpt_mutex_unlock(&myrpt->lock);
9042 ast_hangup(myrpt->pchannel);
9043 ast_hangup(myrpt->monchannel);
9044 if (myrpt->txchannel != myrpt->rxchannel)
9045 ast_hangup(myrpt->txchannel);
9046 ast_hangup(myrpt->rxchannel);
9047 myrpt->rpt_thread = AST_PTHREADT_STOP;
9048 pthread_exit(NULL);
9050 #ifdef AST_CDR_FLAG_POST_DISABLED
9051 ast_set_flag(myrpt->txpchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
9052 #endif
9053 /* make a conference for the tx */
9054 ci.chan = 0;
9055 ci.confno = myrpt->txconf;
9056 ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER ;
9057 /* first put the channel on the conference in proper mode */
9058 if (ioctl(myrpt->txpchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
9060 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
9061 rpt_mutex_unlock(&myrpt->lock);
9062 ast_hangup(myrpt->txpchannel);
9063 ast_hangup(myrpt->monchannel);
9064 if (myrpt->txchannel != myrpt->rxchannel)
9065 ast_hangup(myrpt->txchannel);
9066 ast_hangup(myrpt->rxchannel);
9067 myrpt->rpt_thread = AST_PTHREADT_STOP;
9068 pthread_exit(NULL);
9070 /* Now, the idea here is to copy from the physical rx channel buffer
9071 into the pseudo tx buffer, and from the pseudo rx buffer into the
9072 tx channel buffer */
9073 myrpt->links.next = &myrpt->links;
9074 myrpt->links.prev = &myrpt->links;
9075 myrpt->tailtimer = 0;
9076 myrpt->totimer = 0;
9077 myrpt->tmsgtimer = myrpt->p.tailmessagetime;
9078 myrpt->idtimer = myrpt->p.politeid;
9079 myrpt->mustid = myrpt->tailid = 0;
9080 myrpt->callmode = 0;
9081 myrpt->tounkeyed = 0;
9082 myrpt->tonotify = 0;
9083 myrpt->retxtimer = 0;
9084 myrpt->rerxtimer = 0;
9085 myrpt->skedtimer = 0;
9086 myrpt->tailevent = 0;
9087 lasttx = 0;
9088 myrpt->keyed = 0;
9089 idtalkover = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "idtalkover");
9090 myrpt->dtmfidx = -1;
9091 myrpt->dtmfbuf[0] = 0;
9092 myrpt->rem_dtmfidx = -1;
9093 myrpt->rem_dtmfbuf[0] = 0;
9094 myrpt->dtmf_time = 0;
9095 myrpt->rem_dtmf_time = 0;
9096 myrpt->disgorgetime = 0;
9097 myrpt->lastnodewhichkeyedusup[0] = '\0';
9098 myrpt->dailytxtime = 0;
9099 myrpt->totaltxtime = 0;
9100 myrpt->dailykeyups = 0;
9101 myrpt->totalkeyups = 0;
9102 myrpt->dailykerchunks = 0;
9103 myrpt->totalkerchunks = 0;
9104 myrpt->dailyexecdcommands = 0;
9105 myrpt->totalexecdcommands = 0;
9106 myrpt->timeouts = 0;
9107 myrpt->exten[0] = '\0';
9108 myrpt->lastdtmfcommand[0] = '\0';
9109 if (myrpt->p.startupmacro)
9111 snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
9113 rpt_mutex_unlock(&myrpt->lock);
9114 val = 1;
9115 ast_channel_setoption(myrpt->rxchannel,AST_OPTION_RELAXDTMF,&val,sizeof(char),0);
9116 val = 1;
9117 ast_channel_setoption(myrpt->rxchannel,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0);
9118 if (myrpt->p.archivedir) donodelog(myrpt,"STARTUP");
9119 dtmfed = 0;
9120 while (ms >= 0)
9122 struct ast_frame *f,*f1,*f2;
9123 struct ast_channel *cs[300],*cs1[300];
9124 int totx=0,elap=0,n,x,toexit=0;
9126 /* DEBUG Dump */
9127 if((myrpt->disgorgetime) && (time(NULL) >= myrpt->disgorgetime)){
9128 struct rpt_link *zl;
9129 struct rpt_tele *zt;
9131 myrpt->disgorgetime = 0;
9132 ast_log(LOG_NOTICE,"********** Variable Dump Start (app_rpt) **********\n");
9133 ast_log(LOG_NOTICE,"totx = %d\n",totx);
9134 ast_log(LOG_NOTICE,"remrx = %d\n",remrx);
9135 ast_log(LOG_NOTICE,"lasttx = %d\n",lasttx);
9136 ast_log(LOG_NOTICE,"elap = %d\n",elap);
9137 ast_log(LOG_NOTICE,"toexit = %d\n",toexit);
9139 ast_log(LOG_NOTICE,"myrpt->keyed = %d\n",myrpt->keyed);
9140 ast_log(LOG_NOTICE,"myrpt->localtx = %d\n",myrpt->localtx);
9141 ast_log(LOG_NOTICE,"myrpt->callmode = %d\n",myrpt->callmode);
9142 ast_log(LOG_NOTICE,"myrpt->mustid = %d\n",myrpt->mustid);
9143 ast_log(LOG_NOTICE,"myrpt->tounkeyed = %d\n",myrpt->tounkeyed);
9144 ast_log(LOG_NOTICE,"myrpt->tonotify = %d\n",myrpt->tonotify);
9145 ast_log(LOG_NOTICE,"myrpt->retxtimer = %ld\n",myrpt->retxtimer);
9146 ast_log(LOG_NOTICE,"myrpt->totimer = %d\n",myrpt->totimer);
9147 ast_log(LOG_NOTICE,"myrpt->tailtimer = %d\n",myrpt->tailtimer);
9148 ast_log(LOG_NOTICE,"myrpt->tailevent = %d\n",myrpt->tailevent);
9150 zl = myrpt->links.next;
9151 while(zl != &myrpt->links){
9152 ast_log(LOG_NOTICE,"*** Link Name: %s ***\n",zl->name);
9153 ast_log(LOG_NOTICE," link->lasttx %d\n",zl->lasttx);
9154 ast_log(LOG_NOTICE," link->lastrx %d\n",zl->lastrx);
9155 ast_log(LOG_NOTICE," link->connected %d\n",zl->connected);
9156 ast_log(LOG_NOTICE," link->hasconnected %d\n",zl->hasconnected);
9157 ast_log(LOG_NOTICE," link->outbound %d\n",zl->outbound);
9158 ast_log(LOG_NOTICE," link->disced %d\n",zl->disced);
9159 ast_log(LOG_NOTICE," link->killme %d\n",zl->killme);
9160 ast_log(LOG_NOTICE," link->disctime %ld\n",zl->disctime);
9161 ast_log(LOG_NOTICE," link->retrytimer %ld\n",zl->retrytimer);
9162 ast_log(LOG_NOTICE," link->retries = %d\n",zl->retries);
9163 ast_log(LOG_NOTICE," link->reconnects = %d\n",zl->reconnects);
9164 zl = zl->next;
9167 zt = myrpt->tele.next;
9168 if(zt != &myrpt->tele)
9169 ast_log(LOG_NOTICE,"*** Telemetry Queue ***\n");
9170 while(zt != &myrpt->tele){
9171 ast_log(LOG_NOTICE," Telemetry mode: %d\n",zt->mode);
9172 zt = zt->next;
9174 ast_log(LOG_NOTICE,"******* Variable Dump End (app_rpt) *******\n");
9179 if (myrpt->reload)
9181 struct rpt_tele *telem;
9183 rpt_mutex_lock(&myrpt->lock);
9184 telem = myrpt->tele.next;
9185 while(telem != &myrpt->tele)
9187 ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
9188 telem = telem->next;
9190 myrpt->reload = 0;
9191 rpt_mutex_unlock(&myrpt->lock);
9192 usleep(10000);
9193 /* find our index, and load the vars */
9194 for(i = 0; i < nrpts; i++)
9196 if (&rpt_vars[i] == myrpt)
9198 load_rpt_vars(i,0);
9199 break;
9204 rpt_mutex_lock(&myrpt->lock);
9205 if (ast_check_hangup(myrpt->rxchannel)) break;
9206 if (ast_check_hangup(myrpt->txchannel)) break;
9207 if (ast_check_hangup(myrpt->pchannel)) break;
9208 if (ast_check_hangup(myrpt->monchannel)) break;
9209 if (ast_check_hangup(myrpt->txpchannel)) break;
9210 if (myrpt->zaptxchannel && ast_check_hangup(myrpt->zaptxchannel)) break;
9212 /* Set local tx with keyed */
9213 myrpt->localtx = myrpt->keyed;
9214 /* If someone's connected, and they're transmitting from their end to us, set remrx true */
9215 l = myrpt->links.next;
9216 remrx = 0;
9217 while(l != &myrpt->links)
9219 if (l->lastrx){
9220 remrx = 1;
9221 if(l->name[0] != '0') /* Ignore '0' nodes */
9222 strcpy(myrpt->lastnodewhichkeyedusup, l->name); /* Note the node which is doing the key up */
9224 l = l->next;
9226 /* Create a "must_id" flag for the cleanup ID */
9227 if(myrpt->p.idtime) /* ID time must be non-zero */
9228 myrpt->mustid |= (myrpt->idtimer) && (myrpt->keyed || remrx) ;
9229 /* Build a fresh totx from myrpt->keyed and autopatch activated */
9230 totx = myrpt->callmode;
9231 /* If full duplex, add local tx to totx */
9232 if (myrpt->p.duplex > 1)
9234 totx = totx || myrpt->localtx;
9236 /* Traverse the telemetry list to see what's queued */
9237 identqueued = 0;
9238 othertelemqueued = 0;
9239 tailmessagequeued = 0;
9240 ctqueued = 0;
9241 telem = myrpt->tele.next;
9242 while(telem != &myrpt->tele)
9244 if((telem->mode == ID) || (telem->mode == IDTALKOVER)){
9245 identqueued = 1; /* Identification telemetry */
9247 else if(telem->mode == TAILMSG)
9249 tailmessagequeued = 1; /* Tail message telemetry */
9251 else
9253 if ((telem->mode != UNKEY) && (telem->mode != LINKUNKEY))
9254 othertelemqueued = 1; /* Other telemetry */
9255 else
9256 ctqueued = 1; /* Courtesy tone telemetry */
9258 telem = telem->next;
9261 /* Add in any "other" telemetry, unless specified otherwise */
9262 if (!myrpt->p.notelemtx) totx = totx || othertelemqueued;
9263 /* Update external (to links) transmitter PTT state with everything but ID, CT, and tailmessage telemetry */
9264 myrpt->exttx = totx;
9265 totx = totx || myrpt->dtmf_local_timer;
9266 /* If half or 3/4 duplex, add localtx to external link tx */
9267 if (myrpt->p.duplex < 2) myrpt->exttx = myrpt->exttx || myrpt->localtx;
9268 /* Add in ID telemetry to local transmitter */
9269 totx = totx || remrx;
9270 /* If 3/4 or full duplex, add in ident and CT telemetry */
9271 if (myrpt->p.duplex > 0)
9272 totx = totx || identqueued || ctqueued;
9273 /* If full duplex, add local dtmf stuff active */
9274 if (myrpt->p.duplex > 1)
9276 totx = totx || (myrpt->dtmfidx > -1) ||
9277 myrpt->cmdnode[0];
9279 /* Reset time out timer variables if there is no activity */
9280 if (!totx)
9282 myrpt->totimer = myrpt->p.totime;
9283 myrpt->tounkeyed = 0;
9284 myrpt->tonotify = 0;
9286 else{
9287 myrpt->tailtimer = myrpt->p.s[myrpt->p.sysstate_cur].alternatetail ?
9288 myrpt->p.althangtime : /* Initialize tail timer */
9289 myrpt->p.hangtime;
9291 /* Disable the local transmitter if we are timed out */
9292 totx = totx && myrpt->totimer;
9293 /* if timed-out and not said already, say it */
9294 if ((!myrpt->totimer) && (!myrpt->tonotify))
9296 myrpt->tonotify = 1;
9297 myrpt->timeouts++;
9298 rpt_mutex_unlock(&myrpt->lock);
9299 rpt_telemetry(myrpt,TIMEOUT,NULL);
9300 rpt_mutex_lock(&myrpt->lock);
9303 /* If unkey and re-key, reset time out timer */
9304 if ((!totx) && (!myrpt->totimer) && (!myrpt->tounkeyed) && (!myrpt->keyed))
9306 myrpt->tounkeyed = 1;
9308 if ((!totx) && (!myrpt->totimer) && myrpt->tounkeyed && myrpt->keyed)
9310 myrpt->totimer = myrpt->p.totime;
9311 myrpt->tounkeyed = 0;
9312 myrpt->tonotify = 0;
9313 rpt_mutex_unlock(&myrpt->lock);
9314 continue;
9316 /* if timed-out and in circuit busy after call */
9317 if ((!totx) && (!myrpt->totimer) && (myrpt->callmode == 4))
9319 myrpt->callmode = 0;
9321 /* get rid of tail if timed out */
9322 if (!myrpt->totimer) myrpt->tailtimer = 0;
9323 /* if not timed-out, add in tail */
9324 if (myrpt->totimer) totx = totx || myrpt->tailtimer;
9325 /* If user or links key up or are keyed up over standard ID, switch to talkover ID, if one is defined */
9326 /* If tail message, kill the message if someone keys up over it */
9327 if ((myrpt->keyed || remrx) && ((identqueued && idtalkover) || (tailmessagequeued))) {
9328 int hasid = 0,hastalkover = 0;
9330 telem = myrpt->tele.next;
9331 while(telem != &myrpt->tele){
9332 if(telem->mode == ID){
9333 if (telem->chan) ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
9334 hasid = 1;
9336 if(telem->mode == TAILMSG){
9337 if (telem->chan) ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
9339 if (telem->mode == IDTALKOVER) hastalkover = 1;
9340 telem = telem->next;
9342 rpt_mutex_unlock(&myrpt->lock);
9343 if (hasid && (!hastalkover)) rpt_telemetry(myrpt, IDTALKOVER, NULL); /* Start Talkover ID */
9344 rpt_mutex_lock(&myrpt->lock);
9346 /* Try to be polite */
9347 /* If the repeater has been inactive for longer than the ID time, do an initial ID in the tail*/
9348 /* If within 30 seconds of the time to ID, try do it in the tail */
9349 /* else if at ID time limit, do it right over the top of them */
9350 /* Lastly, if the repeater has been keyed, and the ID timer is expired, do a clean up ID */
9351 if(myrpt->mustid && (!myrpt->idtimer))
9352 queue_id(myrpt);
9354 if ((myrpt->p.idtime && totx && (!myrpt->exttx) &&
9355 (myrpt->idtimer <= myrpt->p.politeid) && myrpt->tailtimer)) /* ID time must be non-zero */
9357 myrpt->tailid = 1;
9360 /* If tail timer expires, then check for tail messages */
9362 if(myrpt->tailevent){
9363 myrpt->tailevent = 0;
9364 if(myrpt->tailid){
9365 totx = 1;
9366 queue_id(myrpt);
9368 else if ((myrpt->p.tailmessages[0]) &&
9369 (myrpt->p.tailmessagetime) && (myrpt->tmsgtimer == 0)){
9370 totx = 1;
9371 myrpt->tmsgtimer = myrpt->p.tailmessagetime;
9372 rpt_mutex_unlock(&myrpt->lock);
9373 rpt_telemetry(myrpt, TAILMSG, NULL);
9374 rpt_mutex_lock(&myrpt->lock);
9378 /* Main TX control */
9380 /* let telemetry transmit anyway (regardless of timeout) */
9381 if (myrpt->p.duplex > 0) totx = totx || (myrpt->tele.next != &myrpt->tele);
9382 if (totx && (!lasttx))
9384 char mydate[100],myfname[100];
9385 time_t myt;
9387 if (myrpt->monstream) ast_closestream(myrpt->monstream);
9388 if (myrpt->p.archivedir)
9390 long blocksleft;
9392 time(&myt);
9393 strftime(mydate,sizeof(mydate) - 1,"%Y%m%d%H%M%S",
9394 localtime(&myt));
9395 sprintf(myfname,"%s/%s/%s",myrpt->p.archivedir,
9396 myrpt->name,mydate);
9397 myrpt->monstream = ast_writefile(myfname,"wav49",
9398 "app_rpt Air Archive",O_CREAT | O_APPEND,0,0600);
9399 if (myrpt->p.monminblocks)
9401 blocksleft = diskavail(myrpt);
9402 if (blocksleft >= myrpt->p.monminblocks)
9403 donodelog(myrpt,"TXKEY,MAIN");
9404 } else donodelog(myrpt,"TXKEY,MAIN");
9406 lasttx = 1;
9407 myrpt->dailykeyups++;
9408 myrpt->totalkeyups++;
9409 rpt_mutex_unlock(&myrpt->lock);
9410 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
9411 rpt_mutex_lock(&myrpt->lock);
9413 totx = totx && !myrpt->p.s[myrpt->p.sysstate_cur].txdisable;
9414 if ((!totx) && lasttx)
9416 if (myrpt->monstream) ast_closestream(myrpt->monstream);
9417 myrpt->monstream = NULL;
9419 lasttx = 0;
9420 rpt_mutex_unlock(&myrpt->lock);
9421 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
9422 rpt_mutex_lock(&myrpt->lock);
9423 donodelog(myrpt,"TXUNKEY,MAIN");
9425 time(&t);
9426 /* if DTMF timeout */
9427 if ((!myrpt->cmdnode[0]) && (myrpt->dtmfidx >= 0) && ((myrpt->dtmf_time + DTMF_TIMEOUT) < t))
9429 myrpt->dtmfidx = -1;
9430 myrpt->dtmfbuf[0] = 0;
9432 /* if remote DTMF timeout */
9433 if ((myrpt->rem_dtmfidx >= 0) && ((myrpt->rem_dtmf_time + DTMF_TIMEOUT) < t))
9435 myrpt->rem_dtmfidx = -1;
9436 myrpt->rem_dtmfbuf[0] = 0;
9439 /* Reconnect */
9441 l = myrpt->links.next;
9442 while(l != &myrpt->links)
9444 if (l->killme)
9446 /* remove from queue */
9447 remque((struct qelem *) l);
9448 if (!strcmp(myrpt->cmdnode,l->name))
9449 myrpt->cmdnode[0] = 0;
9450 rpt_mutex_unlock(&myrpt->lock);
9451 /* hang-up on call to device */
9452 if (l->chan) ast_hangup(l->chan);
9453 ast_hangup(l->pchan);
9454 free(l);
9455 rpt_mutex_lock(&myrpt->lock);
9456 /* re-start link traversal */
9457 l = myrpt->links.next;
9458 continue;
9460 l = l->next;
9462 n = 0;
9463 cs[n++] = myrpt->rxchannel;
9464 cs[n++] = myrpt->pchannel;
9465 cs[n++] = myrpt->monchannel;
9466 cs[n++] = myrpt->txpchannel;
9467 if (myrpt->txchannel != myrpt->rxchannel) cs[n++] = myrpt->txchannel;
9468 if (myrpt->zaptxchannel != myrpt->txchannel)
9469 cs[n++] = myrpt->zaptxchannel;
9470 l = myrpt->links.next;
9471 while(l != &myrpt->links)
9473 if ((!l->killme) && (!l->disctime) && l->chan)
9475 cs[n++] = l->chan;
9476 cs[n++] = l->pchan;
9478 l = l->next;
9480 rpt_mutex_unlock(&myrpt->lock);
9481 ms = MSWAIT;
9482 for(x = 0; x < n; x++)
9484 int s = -(-x - myrpt->scram - 1) % n;
9485 cs1[x] = cs[s];
9487 myrpt->scram++;
9488 who = ast_waitfor_n(cs1,n,&ms);
9489 if (who == NULL) ms = 0;
9490 elap = MSWAIT - ms;
9491 rpt_mutex_lock(&myrpt->lock);
9492 l = myrpt->links.next;
9493 while(l != &myrpt->links)
9495 if (l->linklisttimer)
9497 l->linklisttimer -= elap;
9498 if (l->linklisttimer < 0) l->linklisttimer = 0;
9500 if ((!l->linklisttimer) && (l->name[0] != '0') && (!l->isremote))
9502 struct ast_frame lf;
9504 memset(&lf,0,sizeof(lf));
9505 lf.frametype = AST_FRAME_TEXT;
9506 lf.subclass = 0;
9507 lf.offset = 0;
9508 lf.mallocd = 0;
9509 lf.samples = 0;
9510 l->linklisttimer = LINKLISTTIME;
9511 strcpy(lstr,"L ");
9512 __mklinklist(myrpt,l,lstr + 2);
9513 if (l->chan)
9515 lf.datalen = strlen(lstr) + 1;
9516 lf.data = lstr;
9517 ast_write(l->chan,&lf);
9518 if (debug > 6) ast_log(LOG_NOTICE,
9519 "@@@@ node %s sent node string %s to node %s\n",
9520 myrpt->name,lstr,l->name);
9523 #ifndef OLDKEY
9524 if ((l->retxtimer += elap) >= REDUNDANT_TX_TIME)
9526 l->retxtimer = 0;
9527 if (l->chan && l->phonemode == 0)
9529 if (l->lasttx)
9530 ast_indicate(l->chan,AST_CONTROL_RADIO_KEY);
9531 else
9532 ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
9535 if ((l->rerxtimer += elap) >= (REDUNDANT_TX_TIME * 5))
9537 if (debug == 7) printf("@@@@ rx un-key\n");
9538 l->lastrx = 0;
9539 l->rerxtimer = 0;
9540 if(myrpt->p.duplex)
9541 rpt_telemetry(myrpt,LINKUNKEY,l);
9542 if (myrpt->p.archivedir)
9544 char str[100];
9546 l->lastrx1 = 0;
9547 sprintf(str,"RXUNKEY(T),%s",l->name);
9548 donodelog(myrpt,str);
9551 #endif
9552 if (l->disctime) /* Disconnect timer active on a channel ? */
9554 l->disctime -= elap;
9555 if (l->disctime <= 0) /* Disconnect timer expired on inbound channel ? */
9556 l->disctime = 0; /* Yep */
9559 if (l->retrytimer)
9561 l->retrytimer -= elap;
9562 if (l->retrytimer < 0) l->retrytimer = 0;
9565 /* Tally connect time */
9566 l->connecttime += elap;
9568 /* ignore non-timing channels */
9569 if (l->elaptime < 0)
9571 l = l->next;
9572 continue;
9574 l->elaptime += elap;
9575 /* if connection has taken too long */
9576 if ((l->elaptime > MAXCONNECTTIME) &&
9577 ((!l->chan) || (l->chan->_state != AST_STATE_UP)))
9579 l->elaptime = 0;
9580 rpt_mutex_unlock(&myrpt->lock);
9581 if (l->chan) ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
9582 rpt_mutex_lock(&myrpt->lock);
9583 break;
9585 if ((!l->chan) && (!l->retrytimer) && l->outbound &&
9586 (l->retries++ < l->max_retries) && (l->hasconnected))
9588 if (l->chan) ast_hangup(l->chan);
9589 l->chan = 0;
9590 rpt_mutex_unlock(&myrpt->lock);
9591 if ((l->name[0] != '0') && (!l->isremote))
9593 if (attempt_reconnect(myrpt,l) == -1)
9595 l->retrytimer = RETRY_TIMER_MS;
9598 else
9600 l->retrytimer = l->max_retries + 1;
9603 rpt_mutex_lock(&myrpt->lock);
9604 break;
9606 if ((!l->chan) && (!l->retrytimer) && l->outbound &&
9607 (l->retries >= l->max_retries))
9609 /* remove from queue */
9610 remque((struct qelem *) l);
9611 if (!strcmp(myrpt->cmdnode,l->name))
9612 myrpt->cmdnode[0] = 0;
9613 rpt_mutex_unlock(&myrpt->lock);
9614 if (l->name[0] != '0')
9616 if (!l->hasconnected)
9617 rpt_telemetry(myrpt,CONNFAIL,l);
9618 else rpt_telemetry(myrpt,REMDISC,l);
9620 if (myrpt->p.archivedir)
9622 char str[100];
9624 if (!l->hasconnected)
9625 sprintf(str,"LINKFAIL,%s",l->name);
9626 else
9627 sprintf(str,"LINKDISC,%s",l->name);
9628 donodelog(myrpt,str);
9630 /* hang-up on call to device */
9631 ast_hangup(l->pchan);
9632 free(l);
9633 rpt_mutex_lock(&myrpt->lock);
9634 break;
9636 if ((!l->chan) && (!l->disctime) && (!l->outbound))
9638 /* remove from queue */
9639 remque((struct qelem *) l);
9640 if (!strcmp(myrpt->cmdnode,l->name))
9641 myrpt->cmdnode[0] = 0;
9642 rpt_mutex_unlock(&myrpt->lock);
9643 if (l->name[0] != '0')
9645 rpt_telemetry(myrpt,REMDISC,l);
9647 if (myrpt->p.archivedir)
9649 char str[100];
9651 sprintf(str,"LINKDISC,%s",l->name);
9652 donodelog(myrpt,str);
9654 /* hang-up on call to device */
9655 ast_hangup(l->pchan);
9656 free(l);
9657 rpt_mutex_lock(&myrpt->lock);
9658 break;
9660 l = l->next;
9662 if(totx){
9663 myrpt->dailytxtime += elap;
9664 myrpt->totaltxtime += elap;
9666 i = myrpt->tailtimer;
9667 if (myrpt->tailtimer) myrpt->tailtimer -= elap;
9668 if (myrpt->tailtimer < 0) myrpt->tailtimer = 0;
9669 if((i) && (myrpt->tailtimer == 0))
9670 myrpt->tailevent = 1;
9671 if ((!myrpt->p.s[myrpt->p.sysstate_cur].totdisable) && myrpt->totimer) myrpt->totimer -= elap;
9672 if (myrpt->totimer < 0) myrpt->totimer = 0;
9673 if (myrpt->idtimer) myrpt->idtimer -= elap;
9674 if (myrpt->idtimer < 0) myrpt->idtimer = 0;
9675 if (myrpt->tmsgtimer) myrpt->tmsgtimer -= elap;
9676 if (myrpt->tmsgtimer < 0) myrpt->tmsgtimer = 0;
9677 /* do macro timers */
9678 if (myrpt->macrotimer) myrpt->macrotimer -= elap;
9679 if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
9680 /* do local dtmf timer */
9681 if (myrpt->dtmf_local_timer)
9683 if (myrpt->dtmf_local_timer > 1) myrpt->dtmf_local_timer -= elap;
9684 if (myrpt->dtmf_local_timer < 1) myrpt->dtmf_local_timer = 1;
9686 do_dtmf_local(myrpt,0);
9687 /* Execute scheduler appx. every 2 tenths of a second */
9688 if (myrpt->skedtimer <= 0){
9689 myrpt->skedtimer = 200;
9690 do_scheduler(myrpt);
9692 else
9693 myrpt->skedtimer -=elap;
9694 if (!ms)
9696 rpt_mutex_unlock(&myrpt->lock);
9697 continue;
9699 c = myrpt->macrobuf[0];
9700 time(&t);
9701 if (c && (!myrpt->macrotimer) &&
9702 starttime && (t > (starttime + START_DELAY)))
9704 myrpt->macrotimer = MACROTIME;
9705 memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1);
9706 if ((c == 'p') || (c == 'P'))
9707 myrpt->macrotimer = MACROPTIME;
9708 rpt_mutex_unlock(&myrpt->lock);
9709 if (myrpt->p.archivedir)
9711 char str[100];
9713 sprintf(str,"DTMF(M),MAIN,%c",c);
9714 donodelog(myrpt,str);
9716 local_dtmf_helper(myrpt,c);
9717 } else rpt_mutex_unlock(&myrpt->lock);
9718 if (who == myrpt->rxchannel) /* if it was a read from rx */
9720 int ismuted;
9722 f = ast_read(myrpt->rxchannel);
9723 if (!f)
9725 if (debug) printf("@@@@ rpt:Hung Up\n");
9726 break;
9728 if (f->frametype == AST_FRAME_VOICE)
9730 #ifdef _MDC_DECODE_H_
9731 unsigned char ubuf[2560];
9732 short *sp;
9733 int n;
9734 #endif
9736 if ((!myrpt->localtx) && (!myrpt->p.linktolink)) {
9737 memset(f->data,0,f->datalen);
9740 #ifdef _MDC_DECODE_H_
9741 sp = (short *) f->data;
9742 /* convert block to unsigned char */
9743 for(n = 0; n < f->datalen / 2; n++)
9745 ubuf[n] = (*sp++ >> 8) + 128;
9747 n = mdc_decoder_process_samples(myrpt->mdc,ubuf,f->datalen / 2);
9748 if (n == 1)
9750 unsigned char op,arg;
9751 unsigned short unitID;
9753 mdc_decoder_get_packet(myrpt->mdc,&op,&arg,&unitID);
9754 if (debug > 2)
9756 ast_log(LOG_NOTICE,"Got (single-length) packet:\n");
9757 ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
9758 op & 255,arg & 255,unitID);
9760 if ((op == 1) && (arg == 0))
9762 myrpt->lastunit = unitID;
9763 mdc1200_notify(myrpt,NULL,myrpt->lastunit);
9764 mdc1200_send(myrpt,myrpt->lastunit);
9767 if ((debug > 2) && (i == 2))
9769 unsigned char op,arg,ex1,ex2,ex3,ex4;
9770 unsigned short unitID;
9772 mdc_decoder_get_double_packet(myrpt->mdc,&op,&arg,&unitID,
9773 &ex1,&ex2,&ex3,&ex4);
9774 ast_log(LOG_NOTICE,"Got (double-length) packet:\n");
9775 ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
9776 op & 255,arg & 255,unitID);
9777 ast_log(LOG_NOTICE,"ex1: %02x, ex2: %02x, ex3: %02x, ex4: %02x\n",
9778 ex1 & 255, ex2 & 255, ex3 & 255, ex4 & 255);
9780 #endif
9781 #ifdef __RPT_NOTCH
9782 /* apply inbound filters, if any */
9783 rpt_filter(myrpt,f->data,f->datalen / 2);
9784 #endif
9785 if (ioctl(myrpt->zaprxchannel->fds[0], DAHDI_GETCONFMUTE, &ismuted) == -1)
9787 ismuted = 0;
9789 if (dtmfed) ismuted = 1;
9790 dtmfed = 0;
9791 if (ismuted)
9793 memset(f->data,0,f->datalen);
9794 if (myrpt->lastf1)
9795 memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
9796 if (myrpt->lastf2)
9797 memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
9799 if (f) f2 = ast_frdup(f);
9800 else f2 = NULL;
9801 f1 = myrpt->lastf2;
9802 myrpt->lastf2 = myrpt->lastf1;
9803 myrpt->lastf1 = f2;
9804 if (ismuted)
9806 if (myrpt->lastf1)
9807 memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
9808 if (myrpt->lastf2)
9809 memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
9811 if (f1)
9813 ast_write(myrpt->pchannel,f1);
9814 ast_frfree(f1);
9817 #ifndef OLD_ASTERISK
9818 else if (f->frametype == AST_FRAME_DTMF_BEGIN)
9820 if (myrpt->lastf1)
9821 memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
9822 if (myrpt->lastf2)
9823 memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
9824 dtmfed = 1;
9826 #endif
9827 else if (f->frametype == AST_FRAME_DTMF)
9829 c = (char) f->subclass; /* get DTMF char */
9830 ast_frfree(f);
9831 if (myrpt->lastf1)
9832 memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
9833 if (myrpt->lastf2)
9834 memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
9835 dtmfed = 1;
9836 if (!myrpt->keyed) continue;
9837 c = func_xlat(myrpt,c,&myrpt->p.inxlat);
9838 if (c) local_dtmf_helper(myrpt,c);
9839 continue;
9841 else if (f->frametype == AST_FRAME_CONTROL)
9843 if (f->subclass == AST_CONTROL_HANGUP)
9845 if (debug) printf("@@@@ rpt:Hung Up\n");
9846 ast_frfree(f);
9847 break;
9849 /* if RX key */
9850 if (f->subclass == AST_CONTROL_RADIO_KEY)
9852 if ((!lasttx) || (myrpt->p.duplex > 1) || (myrpt->p.linktolink))
9854 if (debug == 7) printf("@@@@ rx key\n");
9855 myrpt->keyed = 1;
9857 if (myrpt->p.archivedir)
9859 donodelog(myrpt,"RXKEY,MAIN");
9862 /* if RX un-key */
9863 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
9865 if ((!lasttx) || (myrpt->p.duplex > 1) || (myrpt->p.linktolink))
9867 if (debug == 7) printf("@@@@ rx un-key\n");
9868 if(myrpt->p.duplex && myrpt->keyed) {
9869 rpt_telemetry(myrpt,UNKEY,NULL);
9872 myrpt->keyed = 0;
9873 if (myrpt->p.archivedir)
9875 donodelog(myrpt,"RXUNKEY,MAIN");
9879 ast_frfree(f);
9880 continue;
9882 if (who == myrpt->pchannel) /* if it was a read from pseudo */
9884 f = ast_read(myrpt->pchannel);
9885 if (!f)
9887 if (debug) printf("@@@@ rpt:Hung Up\n");
9888 break;
9890 if (f->frametype == AST_FRAME_VOICE)
9892 ast_write(myrpt->txpchannel,f);
9894 if (f->frametype == AST_FRAME_CONTROL)
9896 if (f->subclass == AST_CONTROL_HANGUP)
9898 if (debug) printf("@@@@ rpt:Hung Up\n");
9899 ast_frfree(f);
9900 break;
9903 ast_frfree(f);
9904 continue;
9906 if (who == myrpt->txchannel) /* if it was a read from tx */
9908 f = ast_read(myrpt->txchannel);
9909 if (!f)
9911 if (debug) printf("@@@@ rpt:Hung Up\n");
9912 break;
9914 if (f->frametype == AST_FRAME_CONTROL)
9916 if (f->subclass == AST_CONTROL_HANGUP)
9918 if (debug) printf("@@@@ rpt:Hung Up\n");
9919 ast_frfree(f);
9920 break;
9923 ast_frfree(f);
9924 continue;
9926 if (who == myrpt->zaptxchannel) /* if it was a read from pseudo-tx */
9928 f = ast_read(myrpt->zaptxchannel);
9929 if (!f)
9931 if (debug) printf("@@@@ rpt:Hung Up\n");
9932 break;
9934 if (f->frametype == AST_FRAME_VOICE)
9936 ast_write(myrpt->txchannel,f);
9938 if (f->frametype == AST_FRAME_CONTROL)
9940 if (f->subclass == AST_CONTROL_HANGUP)
9942 if (debug) printf("@@@@ rpt:Hung Up\n");
9943 ast_frfree(f);
9944 break;
9947 ast_frfree(f);
9948 continue;
9950 toexit = 0;
9951 rpt_mutex_lock(&myrpt->lock);
9952 l = myrpt->links.next;
9953 while(l != &myrpt->links)
9955 if (l->disctime)
9957 l = l->next;
9958 continue;
9960 if (who == l->chan) /* if it was a read from rx */
9962 int remnomute;
9964 remrx = 0;
9965 /* see if any other links are receiving */
9966 m = myrpt->links.next;
9967 while(m != &myrpt->links)
9969 /* if not us, count it */
9970 if ((m != l) && (m->lastrx)) remrx = 1;
9971 m = m->next;
9973 rpt_mutex_unlock(&myrpt->lock);
9974 remnomute = myrpt->localtx &&
9975 (!(myrpt->cmdnode[0] ||
9976 (myrpt->dtmfidx > -1)));
9977 totx = (((l->isremote) ? (remnomute) :
9978 myrpt->exttx) || remrx) && l->mode;
9979 if (l->phonemode == 0 && l->chan && (l->lasttx != totx))
9981 if (totx)
9983 ast_indicate(l->chan,AST_CONTROL_RADIO_KEY);
9985 else
9987 ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
9989 if (myrpt->p.archivedir)
9991 char str[100];
9993 if (totx)
9994 sprintf(str,"TXKEY,%s",l->name);
9995 else
9996 sprintf(str,"TXUNKEY,%s",l->name);
9997 donodelog(myrpt,str);
10000 l->lasttx = totx;
10001 f = ast_read(l->chan);
10002 if (!f)
10004 rpt_mutex_lock(&myrpt->lock);
10005 __kickshort(myrpt);
10006 rpt_mutex_unlock(&myrpt->lock);
10007 if ((!l->disced) && (!l->outbound))
10009 if ((l->name[0] == '0') || l->isremote)
10010 l->disctime = 1;
10011 else
10012 l->disctime = DISC_TIME;
10013 rpt_mutex_lock(&myrpt->lock);
10014 ast_hangup(l->chan);
10015 l->chan = 0;
10016 break;
10019 if (l->retrytimer)
10021 ast_hangup(l->chan);
10022 l->chan = 0;
10023 rpt_mutex_lock(&myrpt->lock);
10024 break;
10026 if (l->outbound && (l->retries++ < l->max_retries) && (l->hasconnected))
10028 rpt_mutex_lock(&myrpt->lock);
10029 if (l->chan) ast_hangup(l->chan);
10030 l->chan = 0;
10031 l->hasconnected = 1;
10032 l->retrytimer = RETRY_TIMER_MS;
10033 l->elaptime = 0;
10034 l->connecttime = 0;
10035 l->thisconnected = 0;
10036 break;
10038 rpt_mutex_lock(&myrpt->lock);
10039 /* remove from queue */
10040 remque((struct qelem *) l);
10041 if (!strcmp(myrpt->cmdnode,l->name))
10042 myrpt->cmdnode[0] = 0;
10043 __kickshort(myrpt);
10044 rpt_mutex_unlock(&myrpt->lock);
10045 if (!l->hasconnected)
10046 rpt_telemetry(myrpt,CONNFAIL,l);
10047 else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
10048 if (myrpt->p.archivedir)
10050 char str[100];
10052 if (!l->hasconnected)
10053 sprintf(str,"LINKFAIL,%s",l->name);
10054 else
10055 sprintf(str,"LINKDISC,%s",l->name);
10056 donodelog(myrpt,str);
10058 if (l->lastf1) ast_frfree(l->lastf1);
10059 l->lastf1 = NULL;
10060 if (l->lastf2) ast_frfree(l->lastf2);
10061 l->lastf2 = NULL;
10062 /* hang-up on call to device */
10063 ast_hangup(l->chan);
10064 ast_hangup(l->pchan);
10065 free(l);
10066 rpt_mutex_lock(&myrpt->lock);
10067 break;
10069 if (f->frametype == AST_FRAME_VOICE)
10071 int ismuted;
10073 if (l->phonemode)
10075 if (ioctl(l->chan->fds[0], DAHDI_GETCONFMUTE, &ismuted) == -1)
10077 ismuted = 0;
10079 /* if not receiving, zero-out audio */
10080 ismuted |= (!l->lastrx);
10081 if (l->dtmfed && l->phonemode) ismuted = 1;
10082 l->dtmfed = 0;
10083 if (ismuted)
10085 memset(f->data,0,f->datalen);
10086 if (l->lastf1)
10087 memset(l->lastf1->data,0,l->lastf1->datalen);
10088 if (l->lastf2)
10089 memset(l->lastf2->data,0,l->lastf2->datalen);
10091 if (f) f2 = ast_frdup(f);
10092 else f2 = NULL;
10093 f1 = l->lastf2;
10094 l->lastf2 = l->lastf1;
10095 l->lastf1 = f2;
10096 if (ismuted)
10098 if (l->lastf1)
10099 memset(l->lastf1->data,0,l->lastf1->datalen);
10100 if (l->lastf2)
10101 memset(l->lastf2->data,0,l->lastf2->datalen);
10103 if (f1)
10105 ast_write(l->pchan,f1);
10106 ast_frfree(f1);
10109 else
10111 if (!l->lastrx)
10112 memset(f->data,0,f->datalen);
10113 ast_write(l->pchan,f);
10116 #ifndef OLD_ASTERISK
10117 else if (f->frametype == AST_FRAME_DTMF_BEGIN)
10119 if (l->lastf1)
10120 memset(l->lastf1->data,0,l->lastf1->datalen);
10121 if (l->lastf2)
10122 memset(l->lastf2->data,0,l->lastf2->datalen);
10123 l->dtmfed = 1;
10125 #endif
10127 if (f->frametype == AST_FRAME_TEXT)
10129 handle_link_data(myrpt,l,f->data);
10131 if (f->frametype == AST_FRAME_DTMF)
10133 if (l->lastf1)
10134 memset(l->lastf1->data,0,l->lastf1->datalen);
10135 if (l->lastf2)
10136 memset(l->lastf2->data,0,l->lastf2->datalen);
10137 l->dtmfed = 1;
10138 handle_link_phone_dtmf(myrpt,l,f->subclass);
10140 if (f->frametype == AST_FRAME_CONTROL)
10142 if (f->subclass == AST_CONTROL_ANSWER)
10144 char lconnected = l->connected;
10146 __kickshort(myrpt);
10147 l->connected = 1;
10148 l->hasconnected = 1;
10149 l->thisconnected = 1;
10150 l->elaptime = -1;
10151 if (!l->isremote) l->retries = 0;
10152 if (!lconnected)
10154 rpt_telemetry(myrpt,CONNECTED,l);
10155 if (myrpt->p.archivedir)
10157 char str[100];
10159 if (l->mode)
10160 sprintf(str,"LINKTRX,%s",l->name);
10161 else
10162 sprintf(str,"LINKMONITOR,%s",l->name);
10163 donodelog(myrpt,str);
10166 else
10167 l->reconnects++;
10169 /* if RX key */
10170 if (f->subclass == AST_CONTROL_RADIO_KEY)
10172 if (debug == 7 ) printf("@@@@ rx key\n");
10173 l->lastrx = 1;
10174 l->rerxtimer = 0;
10175 if (myrpt->p.archivedir && (!l->lastrx1))
10177 char str[100];
10179 l->lastrx1 = 1;
10180 sprintf(str,"RXKEY,%s",l->name);
10181 donodelog(myrpt,str);
10184 /* if RX un-key */
10185 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
10187 if (debug == 7) printf("@@@@ rx un-key\n");
10188 l->lastrx = 0;
10189 l->rerxtimer = 0;
10190 if(myrpt->p.duplex)
10191 rpt_telemetry(myrpt,LINKUNKEY,l);
10192 if (myrpt->p.archivedir && (l->lastrx1))
10194 char str[100];
10196 l->lastrx1 = 0;
10197 sprintf(str,"RXUNKEY,%s",l->name);
10198 donodelog(myrpt,str);
10201 if (f->subclass == AST_CONTROL_HANGUP)
10203 ast_frfree(f);
10204 rpt_mutex_lock(&myrpt->lock);
10205 __kickshort(myrpt);
10206 rpt_mutex_unlock(&myrpt->lock);
10207 if ((!l->outbound) && (!l->disced))
10209 if ((l->name[0] == '0') || l->isremote)
10210 l->disctime = 1;
10211 else
10212 l->disctime = DISC_TIME;
10213 rpt_mutex_lock(&myrpt->lock);
10214 ast_hangup(l->chan);
10215 l->chan = 0;
10216 break;
10218 if (l->retrytimer)
10220 if (l->chan) ast_hangup(l->chan);
10221 l->chan = 0;
10222 rpt_mutex_lock(&myrpt->lock);
10223 break;
10225 if (l->outbound && (l->retries++ < l->max_retries) && (l->hasconnected))
10227 rpt_mutex_lock(&myrpt->lock);
10228 if (l->chan) ast_hangup(l->chan);
10229 l->chan = 0;
10230 l->hasconnected = 1;
10231 l->elaptime = 0;
10232 l->retrytimer = RETRY_TIMER_MS;
10233 l->connecttime = 0;
10234 l->thisconnected = 0;
10235 break;
10237 rpt_mutex_lock(&myrpt->lock);
10238 /* remove from queue */
10239 remque((struct qelem *) l);
10240 if (!strcmp(myrpt->cmdnode,l->name))
10241 myrpt->cmdnode[0] = 0;
10242 __kickshort(myrpt);
10243 rpt_mutex_unlock(&myrpt->lock);
10244 if (!l->hasconnected)
10245 rpt_telemetry(myrpt,CONNFAIL,l);
10246 else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
10247 if (myrpt->p.archivedir)
10249 char str[100];
10251 if (!l->hasconnected)
10252 sprintf(str,"LINKFAIL,%s",l->name);
10253 else
10254 sprintf(str,"LINKDISC,%s",l->name);
10255 donodelog(myrpt,str);
10257 if (l->lastf1) ast_frfree(l->lastf1);
10258 l->lastf1 = NULL;
10259 if (l->lastf2) ast_frfree(l->lastf2);
10260 l->lastf2 = NULL;
10261 /* hang-up on call to device */
10262 ast_hangup(l->chan);
10263 ast_hangup(l->pchan);
10264 free(l);
10265 rpt_mutex_lock(&myrpt->lock);
10266 break;
10269 ast_frfree(f);
10270 rpt_mutex_lock(&myrpt->lock);
10271 break;
10273 if (who == l->pchan)
10275 rpt_mutex_unlock(&myrpt->lock);
10276 f = ast_read(l->pchan);
10277 if (!f)
10279 if (debug) printf("@@@@ rpt:Hung Up\n");
10280 toexit = 1;
10281 rpt_mutex_lock(&myrpt->lock);
10282 break;
10284 if (f->frametype == AST_FRAME_VOICE)
10286 if (l->chan) ast_write(l->chan,f);
10288 if (f->frametype == AST_FRAME_CONTROL)
10290 if (f->subclass == AST_CONTROL_HANGUP)
10292 if (debug) printf("@@@@ rpt:Hung Up\n");
10293 ast_frfree(f);
10294 toexit = 1;
10295 rpt_mutex_lock(&myrpt->lock);
10296 break;
10299 ast_frfree(f);
10300 rpt_mutex_lock(&myrpt->lock);
10301 break;
10303 l = l->next;
10305 rpt_mutex_unlock(&myrpt->lock);
10306 if (toexit) break;
10307 if (who == myrpt->monchannel)
10309 f = ast_read(myrpt->monchannel);
10310 if (!f)
10312 if (debug) printf("@@@@ rpt:Hung Up\n");
10313 break;
10315 if (f->frametype == AST_FRAME_VOICE)
10317 if (myrpt->monstream)
10318 ast_writestream(myrpt->monstream,f);
10320 if (f->frametype == AST_FRAME_CONTROL)
10322 if (f->subclass == AST_CONTROL_HANGUP)
10324 if (debug) printf("@@@@ rpt:Hung Up\n");
10325 ast_frfree(f);
10326 break;
10329 ast_frfree(f);
10330 continue;
10332 if (who == myrpt->txpchannel) /* if it was a read from remote tx */
10334 f = ast_read(myrpt->txpchannel);
10335 if (!f)
10337 if (debug) printf("@@@@ rpt:Hung Up\n");
10338 break;
10340 if (f->frametype == AST_FRAME_CONTROL)
10342 if (f->subclass == AST_CONTROL_HANGUP)
10344 if (debug) printf("@@@@ rpt:Hung Up\n");
10345 ast_frfree(f);
10346 break;
10349 ast_frfree(f);
10350 continue;
10353 usleep(100000);
10354 ast_hangup(myrpt->pchannel);
10355 ast_hangup(myrpt->monchannel);
10356 ast_hangup(myrpt->txpchannel);
10357 if (myrpt->txchannel != myrpt->rxchannel) ast_hangup(myrpt->txchannel);
10358 if (myrpt->zaptxchannel != myrpt->txchannel) ast_hangup(myrpt->zaptxchannel);
10359 if (myrpt->lastf1) ast_frfree(myrpt->lastf1);
10360 myrpt->lastf1 = NULL;
10361 if (myrpt->lastf2) ast_frfree(myrpt->lastf2);
10362 myrpt->lastf2 = NULL;
10363 ast_hangup(myrpt->rxchannel);
10364 rpt_mutex_lock(&myrpt->lock);
10365 l = myrpt->links.next;
10366 while(l != &myrpt->links)
10368 struct rpt_link *ll = l;
10369 /* remove from queue */
10370 remque((struct qelem *) l);
10371 /* hang-up on call to device */
10372 if (l->chan) ast_hangup(l->chan);
10373 ast_hangup(l->pchan);
10374 l = l->next;
10375 free(ll);
10377 rpt_mutex_unlock(&myrpt->lock);
10378 if (debug) printf("@@@@ rpt:Hung up channel\n");
10379 myrpt->rpt_thread = AST_PTHREADT_STOP;
10380 pthread_exit(NULL);
10381 return NULL;
10385 static void *rpt_master(void *ignore)
10387 int i,n;
10388 pthread_attr_t attr;
10389 struct ast_config *cfg;
10390 char *this,*val;
10392 /* init nodelog queue */
10393 nodelog.next = nodelog.prev = &nodelog;
10394 /* go thru all the specified repeaters */
10395 this = NULL;
10396 n = 0;
10397 /* wait until asterisk starts */
10398 while(!ast_test_flag(&ast_options,AST_OPT_FLAG_FULLY_BOOTED))
10399 usleep(250000);
10400 rpt_vars[n].cfg = ast_config_load("rpt.conf");
10401 cfg = rpt_vars[n].cfg;
10402 if (!cfg) {
10403 ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf. Radio Repeater disabled.\n");
10404 pthread_exit(NULL);
10406 while((this = ast_category_browse(cfg,this)) != NULL)
10408 for(i = 0 ; i < strlen(this) ; i++){
10409 if((this[i] < '0') || (this[i] > '9'))
10410 break;
10412 if(i != strlen(this)) continue; /* Not a node defn */
10413 memset(&rpt_vars[n],0,sizeof(rpt_vars[n]));
10414 rpt_vars[n].name = strdup(this);
10415 val = (char *) ast_variable_retrieve(cfg,this,"rxchannel");
10416 if (val) rpt_vars[n].rxchanname = strdup(val);
10417 val = (char *) ast_variable_retrieve(cfg,this,"txchannel");
10418 if (val) rpt_vars[n].txchanname = strdup(val);
10419 val = (char *) ast_variable_retrieve(cfg,this,"remote");
10420 if (val) rpt_vars[n].remote = strdup(val);
10421 ast_mutex_init(&rpt_vars[n].lock);
10422 ast_mutex_init(&rpt_vars[n].remlock);
10423 rpt_vars[n].tele.next = &rpt_vars[n].tele;
10424 rpt_vars[n].tele.prev = &rpt_vars[n].tele;
10425 rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
10426 rpt_vars[n].tailmessagen = 0;
10427 #ifdef _MDC_DECODE_H_
10428 rpt_vars[n].mdc = mdc_decoder_new(8000);
10429 #endif
10430 n++;
10432 nrpts = n;
10433 ast_config_destroy(cfg);
10435 /* start em all */
10436 for(i = 0; i < n; i++)
10438 load_rpt_vars(i,1);
10440 /* if is a remote, dont start one for it */
10441 if (rpt_vars[i].remote)
10443 if(retreive_memory(&rpt_vars[i],"init")){ /* Try to retreive initial memory channel */
10444 strncpy(rpt_vars[i].freq, "146.580", sizeof(rpt_vars[i].freq) - 1);
10445 strncpy(rpt_vars[i].rxpl, "100.0", sizeof(rpt_vars[i].rxpl) - 1);
10447 strncpy(rpt_vars[i].txpl, "100.0", sizeof(rpt_vars[i].txpl) - 1);
10448 rpt_vars[i].remmode = REM_MODE_FM;
10449 rpt_vars[i].offset = REM_SIMPLEX;
10450 rpt_vars[i].powerlevel = REM_MEDPWR;
10452 continue;
10454 if (!rpt_vars[i].p.ident)
10456 ast_log(LOG_WARNING,"Did not specify ident for node %s\n",rpt_vars[i].name);
10457 ast_config_destroy(cfg);
10458 pthread_exit(NULL);
10460 pthread_attr_init(&attr);
10461 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
10462 ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]);
10464 usleep(500000);
10465 time(&starttime);
10466 for(;;)
10468 /* Now monitor each thread, and restart it if necessary */
10469 for(i = 0; i < n; i++)
10471 int rv;
10472 if (rpt_vars[i].remote) continue;
10473 if (rpt_vars[i].rpt_thread == AST_PTHREADT_STOP)
10474 rv = -1;
10475 else
10476 rv = pthread_kill(rpt_vars[i].rpt_thread,0);
10477 if (rv)
10479 if(time(NULL) - rpt_vars[i].lastthreadrestarttime <= 15)
10481 if(rpt_vars[i].threadrestarts >= 5)
10483 ast_log(LOG_ERROR,"Continual RPT thread restarts, killing Asterisk\n");
10484 exit(1); /* Stuck in a restart loop, kill Asterisk and start over */
10486 else
10488 ast_log(LOG_NOTICE,"RPT thread restarted on %s\n",rpt_vars[i].name);
10489 rpt_vars[i].threadrestarts++;
10492 else
10493 rpt_vars[i].threadrestarts = 0;
10495 rpt_vars[i].lastthreadrestarttime = time(NULL);
10496 pthread_attr_init(&attr);
10497 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
10498 ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]);
10499 ast_log(LOG_WARNING, "rpt_thread restarted on node %s\n", rpt_vars[i].name);
10503 for(;;)
10505 struct nodelog *nodep;
10506 char *space,datestr[100],fname[300];
10507 int fd;
10509 ast_mutex_lock(&nodeloglock);
10510 nodep = nodelog.next;
10511 if(nodep == &nodelog) /* if nothing in queue */
10513 ast_mutex_unlock(&nodeloglock);
10514 break;
10516 remque((struct qelem *)nodep);
10517 ast_mutex_unlock(&nodeloglock);
10518 space = strchr(nodep->str,' ');
10519 if (!space)
10521 free(nodep);
10522 continue;
10524 *space = 0;
10525 strftime(datestr,sizeof(datestr) - 1,"%Y%m%d",
10526 localtime(&nodep->timestamp));
10527 sprintf(fname,"%s/%s/%s.txt",nodep->archivedir,
10528 nodep->str,datestr);
10529 fd = open(fname,O_WRONLY | O_CREAT | O_APPEND,0600);
10530 if (fd == -1)
10532 ast_log(LOG_ERROR,"Cannot open node log file %s for write",space + 1);
10533 free(nodep);
10534 continue;
10536 if (write(fd,space + 1,strlen(space + 1)) !=
10537 strlen(space + 1))
10539 ast_log(LOG_ERROR,"Cannot write node log file %s for write",space + 1);
10540 free(nodep);
10541 continue;
10543 close(fd);
10544 free(nodep);
10546 sleep(2);
10548 ast_config_destroy(cfg);
10549 pthread_exit(NULL);
10552 static int rpt_exec(struct ast_channel *chan, void *data)
10554 int res=-1,i,rem_totx,rem_rx,remkeyed,n,phone_mode = 0;
10555 int iskenwood_pci4,authtold,authreq,setting,notremming,reming;
10556 int ismuted,dtmfed;
10557 #ifdef OLD_ASTERISK
10558 struct localuser *u;
10559 #endif
10560 char tmp[256], keyed = 0,keyed1 = 0;
10561 char *options,*stringp,*tele,c;
10562 struct rpt *myrpt;
10563 struct ast_frame *f,*f1,*f2;
10564 struct ast_channel *who;
10565 struct ast_channel *cs[20];
10566 struct rpt_link *l;
10567 struct dahdi_confinfo ci; /* conference info */
10568 struct dahdi_params par;
10569 int ms,elap,nullfd;
10570 time_t t,last_timeout_warning;
10571 struct dahdi_radio_param z;
10572 struct rpt_tele *telem;
10574 nullfd = open("/dev/null",O_RDWR);
10575 if (ast_strlen_zero(data)) {
10576 ast_log(LOG_WARNING, "Rpt requires an argument (system node)\n");
10577 return -1;
10580 strncpy(tmp, (char *)data, sizeof(tmp)-1);
10581 time(&t);
10582 /* if time has externally shifted negative, screw it */
10583 if (t < starttime) t = starttime + START_DELAY;
10584 if ((!starttime) || (t < (starttime + START_DELAY)))
10586 ast_log(LOG_NOTICE,"Node %s rejecting call: too soon!\n",tmp);
10587 ast_safe_sleep(chan,3000);
10588 return -1;
10590 stringp=tmp;
10591 strsep(&stringp, "|");
10592 options = stringp;
10593 myrpt = NULL;
10594 /* see if we can find our specified one */
10595 for(i = 0; i < nrpts; i++)
10597 /* if name matches, assign it and exit loop */
10598 if (!strcmp(tmp,rpt_vars[i].name))
10600 myrpt = &rpt_vars[i];
10601 break;
10604 if (myrpt == NULL)
10606 ast_log(LOG_WARNING, "Cannot find specified system node %s\n",tmp);
10607 return -1;
10610 if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable){ /* Do not allow incoming connections if disabled */
10611 ast_log(LOG_NOTICE, "Connect attempt to node %s with tx disabled", myrpt->name);
10612 return -1;
10615 /* if not phone access, must be an IAX connection */
10616 if (options && ((*options == 'P') || (*options == 'D') || (*options == 'R')))
10618 int val;
10620 phone_mode = 1;
10621 if (*options == 'D') phone_mode = 2;
10622 ast_set_callerid(chan,"0","app_rpt user","0");
10623 val = 1;
10624 ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0);
10626 else
10628 #ifdef ALLOW_LOCAL_CHANNELS
10629 /* Check to insure the connection is IAX2 or Local*/
10630 if ( (strncmp(chan->name,"IAX2",4)) && (strncmp(chan->name,"Local",5)) ) {
10631 ast_log(LOG_WARNING, "We only accept links via IAX2 or Local!!\n");
10632 return -1;
10634 #else
10635 if (strncmp(chan->name,"IAX2",4))
10637 ast_log(LOG_WARNING, "We only accept links via IAX2!!\n");
10638 return -1;
10640 #endif
10642 if (options && (*options == 'R'))
10645 /* Parts of this section taken from app_parkandannounce */
10646 char *return_context;
10647 int l, m, lot, timeout = 0;
10648 char tmp[256],*template;
10649 char *working, *context, *exten, *priority;
10650 char *s,*orig_s;
10653 rpt_mutex_lock(&myrpt->lock);
10654 m = myrpt->callmode;
10655 rpt_mutex_unlock(&myrpt->lock);
10657 if ((!myrpt->p.nobusyout) && m)
10659 if (chan->_state != AST_STATE_UP)
10661 ast_indicate(chan,AST_CONTROL_BUSY);
10663 while(ast_safe_sleep(chan,10000) != -1);
10664 return -1;
10667 if (chan->_state != AST_STATE_UP)
10669 ast_answer(chan);
10672 l=strlen(options)+2;
10673 orig_s=malloc(l);
10674 if(!orig_s) {
10675 ast_log(LOG_WARNING, "Out of memory\n");
10676 return -1;
10678 s=orig_s;
10679 strncpy(s,options,l);
10681 template=strsep(&s,"|");
10682 if(!template) {
10683 ast_log(LOG_WARNING, "An announce template must be defined\n");
10684 free(orig_s);
10685 return -1;
10688 if(s) {
10689 timeout = atoi(strsep(&s, "|"));
10690 timeout *= 1000;
10693 return_context = s;
10695 if(return_context != NULL) {
10696 /* set the return context. Code borrowed from the Goto builtin */
10698 working = return_context;
10699 context = strsep(&working, "|");
10700 exten = strsep(&working, "|");
10701 if(!exten) {
10702 /* Only a priority in this one */
10703 priority = context;
10704 exten = NULL;
10705 context = NULL;
10706 } else {
10707 priority = strsep(&working, "|");
10708 if(!priority) {
10709 /* Only an extension and priority in this one */
10710 priority = exten;
10711 exten = context;
10712 context = NULL;
10715 if(atoi(priority) < 0) {
10716 ast_log(LOG_WARNING, "Priority '%s' must be a number > 0\n", priority);
10717 free(orig_s);
10718 return -1;
10720 /* At this point we have a priority and maybe an extension and a context */
10721 chan->priority = atoi(priority);
10722 #ifdef OLD_ASTERISK
10723 if(exten && strcasecmp(exten, "BYEXTENSION"))
10724 #else
10725 if(exten)
10726 #endif
10727 strncpy(chan->exten, exten, sizeof(chan->exten)-1);
10728 if(context)
10729 strncpy(chan->context, context, sizeof(chan->context)-1);
10730 } else { /* increment the priority by default*/
10731 chan->priority++;
10734 if(option_verbose > 2) {
10735 ast_verbose( VERBOSE_PREFIX_3 "Return Context: (%s,%s,%d) ID: %s\n", chan->context,chan->exten, chan->priority, chan->cid.cid_num);
10736 if(!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) {
10737 ast_verbose( VERBOSE_PREFIX_3 "Warning: Return Context Invalid, call will return to default|s\n");
10741 /* we are using masq_park here to protect * from touching the channel once we park it. If the channel comes out of timeout
10742 before we are done announcing and the channel is messed with, Kablooeee. So we use Masq to prevent this. */
10744 ast_masq_park_call(chan, NULL, timeout, &lot);
10746 if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "Call Parking Called, lot: %d, timeout: %d, context: %s\n", lot, timeout, return_context);
10748 snprintf(tmp,sizeof(tmp) - 1,"%d,%s",lot,template + 1);
10750 rpt_telemetry(myrpt,REV_PATCH,tmp);
10752 free(orig_s);
10754 return 0;
10758 if (!options)
10760 struct ast_hostent ahp;
10761 struct hostent *hp;
10762 struct in_addr ia;
10763 char hisip[100],nodeip[100],*val, *s, *s1, *s2, *b,*b1;
10765 /* look at callerid to see what node this comes from */
10766 if (!chan->cid.cid_num) /* if doesn't have caller id */
10768 ast_log(LOG_WARNING, "Doesnt have callerid on %s\n",tmp);
10769 return -1;
10772 /* get his IP from IAX2 module */
10773 memset(hisip,0,sizeof(hisip));
10774 #ifdef ALLOW_LOCAL_CHANNELS
10775 /* set IP address if this is a local connection*/
10776 if (strncmp(chan->name,"Local",5)==0) {
10777 strcpy(hisip,"127.0.0.1");
10778 } else {
10779 pbx_substitute_variables_helper(chan,"${IAXPEER(CURRENTCHANNEL)}",hisip,sizeof(hisip) - 1);
10781 #else
10782 pbx_substitute_variables_helper(chan,"${IAXPEER(CURRENTCHANNEL)}",hisip,sizeof(hisip) - 1);
10783 #endif
10785 if (!hisip[0])
10787 ast_log(LOG_WARNING, "Link IP address cannot be determined!!\n");
10788 return -1;
10791 ast_callerid_parse(chan->cid.cid_num,&b,&b1);
10792 ast_shrink_phone_number(b1);
10793 if (!strcmp(myrpt->name,b1))
10795 ast_log(LOG_WARNING, "Trying to link to self!!\n");
10796 return -1;
10799 if (*b1 < '1')
10801 ast_log(LOG_WARNING, "Node %s Invalid for connection here!!\n",b1);
10802 return -1;
10806 /* look for his reported node string */
10807 val = node_lookup(myrpt,b1);
10808 if (!val)
10810 ast_log(LOG_WARNING, "Reported node %s cannot be found!!\n",b1);
10811 return -1;
10813 strncpy(tmp,val,sizeof(tmp) - 1);
10814 s = tmp;
10815 s1 = strsep(&s,",");
10816 s2 = strsep(&s,",");
10817 if (!s2)
10819 ast_log(LOG_WARNING, "Reported node %s not in correct format!!\n",b1);
10820 return -1;
10822 if (strcmp(s2,"NONE")) {
10823 hp = ast_gethostbyname(s2, &ahp);
10824 if (!hp)
10826 ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n",b1,s2);
10827 return -1;
10829 memcpy(&ia,hp->h_addr,sizeof(in_addr_t));
10830 #ifdef OLD_ASTERISK
10831 ast_inet_ntoa(nodeip,sizeof(nodeip) - 1,ia);
10832 #else
10833 strncpy(nodeip,ast_inet_ntoa(ia),sizeof(nodeip) - 1);
10834 #endif
10835 if (strcmp(hisip,nodeip))
10837 char *s3 = strchr(s1,'@');
10838 if (s3) s1 = s3 + 1;
10839 s3 = strchr(s1,'/');
10840 if (s3) *s3 = 0;
10841 hp = ast_gethostbyname(s1, &ahp);
10842 if (!hp)
10844 ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n",b1,s1);
10845 return -1;
10847 memcpy(&ia,hp->h_addr,sizeof(in_addr_t));
10848 #ifdef OLD_ASTERISK
10849 ast_inet_ntoa(nodeip,sizeof(nodeip) - 1,ia);
10850 #else
10851 strncpy(nodeip,ast_inet_ntoa(ia),sizeof(nodeip) - 1);
10852 #endif
10853 if (strcmp(hisip,nodeip))
10855 ast_log(LOG_WARNING, "Node %s IP %s does not match link IP %s!!\n",b1,nodeip,hisip);
10856 return -1;
10862 /* if is not a remote */
10863 if (!myrpt->remote)
10866 char *b,*b1;
10867 int reconnects = 0;
10869 /* look at callerid to see what node this comes from */
10870 if (!chan->cid.cid_num) /* if doesn't have caller id */
10872 ast_log(LOG_WARNING, "Doesnt have callerid on %s\n",tmp);
10873 return -1;
10876 ast_callerid_parse(chan->cid.cid_num,&b,&b1);
10877 ast_shrink_phone_number(b1);
10878 if (!strcmp(myrpt->name,b1))
10880 ast_log(LOG_WARNING, "Trying to link to self!!\n");
10881 return -1;
10883 rpt_mutex_lock(&myrpt->lock);
10884 l = myrpt->links.next;
10885 /* try to find this one in queue */
10886 while(l != &myrpt->links)
10888 if (l->name[0] == '0')
10890 l = l->next;
10891 continue;
10893 /* if found matching string */
10894 if (!strcmp(l->name,b1)) break;
10895 l = l->next;
10897 /* if found */
10898 if (l != &myrpt->links)
10900 l->killme = 1;
10901 l->retries = l->max_retries + 1;
10902 l->disced = 2;
10903 reconnects = l->reconnects;
10904 reconnects++;
10905 rpt_mutex_unlock(&myrpt->lock);
10906 usleep(500000);
10907 } else
10908 rpt_mutex_unlock(&myrpt->lock);
10909 /* establish call in tranceive mode */
10910 l = malloc(sizeof(struct rpt_link));
10911 if (!l)
10913 ast_log(LOG_WARNING, "Unable to malloc\n");
10914 pthread_exit(NULL);
10916 /* zero the silly thing */
10917 memset((char *)l,0,sizeof(struct rpt_link));
10918 l->mode = 1;
10919 strncpy(l->name,b1,MAXNODESTR - 1);
10920 l->isremote = 0;
10921 l->chan = chan;
10922 l->connected = 1;
10923 l->thisconnected = 1;
10924 l->hasconnected = 1;
10925 l->reconnects = reconnects;
10926 l->phonemode = phone_mode;
10927 l->lastf1 = NULL;
10928 l->lastf2 = NULL;
10929 l->dtmfed = 0;
10930 ast_set_read_format(l->chan,AST_FORMAT_SLINEAR);
10931 ast_set_write_format(l->chan,AST_FORMAT_SLINEAR);
10932 /* allocate a pseudo-channel thru asterisk */
10933 l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
10934 if (!l->pchan)
10936 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
10937 pthread_exit(NULL);
10939 ast_set_read_format(l->pchan,AST_FORMAT_SLINEAR);
10940 ast_set_write_format(l->pchan,AST_FORMAT_SLINEAR);
10941 #ifdef AST_CDR_FLAG_POST_DISABLED
10942 ast_set_flag(l->pchan->cdr,AST_CDR_FLAG_POST_DISABLED);
10943 #endif
10944 /* make a conference for the tx */
10945 ci.chan = 0;
10946 ci.confno = myrpt->conf;
10947 ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER;
10948 /* first put the channel on the conference in proper mode */
10949 if (ioctl(l->pchan->fds[0],DAHDI_SETCONF,&ci) == -1)
10951 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
10952 pthread_exit(NULL);
10954 rpt_mutex_lock(&myrpt->lock);
10955 if (phone_mode > 1) l->lastrx = 1;
10956 l->max_retries = MAX_RETRIES;
10957 /* insert at end of queue */
10958 insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
10959 __kickshort(myrpt);
10960 rpt_mutex_unlock(&myrpt->lock);
10961 if (chan->_state != AST_STATE_UP) {
10962 ast_answer(chan);
10964 if (myrpt->p.archivedir)
10966 char str[100];
10968 if (l->phonemode)
10969 sprintf(str,"LINK(P),%s",l->name);
10970 else
10971 sprintf(str,"LINK,%s",l->name);
10972 donodelog(myrpt,str);
10974 return AST_PBX_KEEPALIVE;
10976 /* well, then it is a remote */
10977 rpt_mutex_lock(&myrpt->lock);
10978 /* if remote, error if anyone else already linked */
10979 if (myrpt->remoteon)
10981 rpt_mutex_unlock(&myrpt->lock);
10982 usleep(500000);
10983 if (myrpt->remoteon)
10985 ast_log(LOG_WARNING, "Trying to use busy link on %s\n",tmp);
10986 return -1;
10988 rpt_mutex_lock(&myrpt->lock);
10990 if ((!strcmp(myrpt->remote, remote_rig_rbi)) &&
10991 (ioperm(myrpt->p.iobase,1,1) == -1))
10993 rpt_mutex_unlock(&myrpt->lock);
10994 ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase);
10995 return -1;
10997 myrpt->remoteon = 1;
10998 #ifdef OLD_ASTERISK
10999 LOCAL_USER_ADD(u);
11000 #endif
11001 rpt_mutex_unlock(&myrpt->lock);
11002 /* find our index, and load the vars initially */
11003 for(i = 0; i < nrpts; i++)
11005 if (&rpt_vars[i] == myrpt)
11007 load_rpt_vars(i,0);
11008 break;
11011 rpt_mutex_lock(&myrpt->lock);
11012 tele = strchr(myrpt->rxchanname,'/');
11013 if (!tele)
11015 fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
11016 rpt_mutex_unlock(&myrpt->lock);
11017 pthread_exit(NULL);
11019 *tele++ = 0;
11020 myrpt->rxchannel = ast_request(myrpt->rxchanname,AST_FORMAT_SLINEAR,tele,NULL);
11021 myrpt->zaprxchannel = NULL;
11022 if (!strcasecmp(myrpt->rxchanname,"Zap"))
11023 myrpt->zaprxchannel = myrpt->rxchannel;
11024 if (myrpt->rxchannel)
11026 ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
11027 ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
11028 #ifdef AST_CDR_FLAG_POST_DISABLED
11029 ast_set_flag(myrpt->rxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11030 #endif
11031 myrpt->rxchannel->whentohangup = 0;
11032 myrpt->rxchannel->appl = "Apprpt";
11033 myrpt->rxchannel->data = "(Link Rx)";
11034 if (option_verbose > 2)
11035 ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
11036 myrpt->rxchanname,tele,myrpt->rxchannel->name);
11037 rpt_mutex_unlock(&myrpt->lock);
11038 ast_call(myrpt->rxchannel,tele,999);
11039 rpt_mutex_lock(&myrpt->lock);
11041 else
11043 fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
11044 rpt_mutex_unlock(&myrpt->lock);
11045 pthread_exit(NULL);
11047 *--tele = '/';
11048 myrpt->zaptxchannel = NULL;
11049 if (myrpt->txchanname)
11051 tele = strchr(myrpt->txchanname,'/');
11052 if (!tele)
11054 fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
11055 rpt_mutex_unlock(&myrpt->lock);
11056 ast_hangup(myrpt->rxchannel);
11057 pthread_exit(NULL);
11059 *tele++ = 0;
11060 myrpt->txchannel = ast_request(myrpt->txchanname,AST_FORMAT_SLINEAR,tele,NULL);
11061 if (!strcasecmp(myrpt->txchanname,"Zap"))
11062 myrpt->zaptxchannel = myrpt->txchannel;
11063 if (myrpt->txchannel)
11065 ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
11066 ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
11067 #ifdef AST_CDR_FLAG_POST_DISABLED
11068 ast_set_flag(myrpt->txchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11069 #endif
11070 myrpt->txchannel->whentohangup = 0;
11071 myrpt->txchannel->appl = "Apprpt";
11072 myrpt->txchannel->data = "(Link Tx)";
11073 if (option_verbose > 2)
11074 ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
11075 myrpt->txchanname,tele,myrpt->txchannel->name);
11076 rpt_mutex_unlock(&myrpt->lock);
11077 ast_call(myrpt->txchannel,tele,999);
11078 rpt_mutex_lock(&myrpt->lock);
11080 else
11082 fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
11083 rpt_mutex_unlock(&myrpt->lock);
11084 ast_hangup(myrpt->rxchannel);
11085 pthread_exit(NULL);
11087 *--tele = '/';
11089 else
11091 myrpt->txchannel = myrpt->rxchannel;
11093 /* allocate a pseudo-channel thru asterisk */
11094 myrpt->pchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
11095 if (!myrpt->pchannel)
11097 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
11098 rpt_mutex_unlock(&myrpt->lock);
11099 if (myrpt->txchannel != myrpt->rxchannel)
11100 ast_hangup(myrpt->txchannel);
11101 ast_hangup(myrpt->rxchannel);
11102 pthread_exit(NULL);
11104 ast_set_read_format(myrpt->pchannel,AST_FORMAT_SLINEAR);
11105 ast_set_write_format(myrpt->pchannel,AST_FORMAT_SLINEAR);
11106 #ifdef AST_CDR_FLAG_POST_DISABLED
11107 ast_set_flag(myrpt->pchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11108 #endif
11109 if (!myrpt->zaprxchannel) myrpt->zaprxchannel = myrpt->pchannel;
11110 if (!myrpt->zaptxchannel) myrpt->zaptxchannel = myrpt->pchannel;
11111 /* make a conference for the pseudo */
11112 ci.chan = 0;
11113 ci.confno = -1; /* make a new conf */
11114 ci.confmode = DAHDI_CONF_CONFANNMON ;
11115 /* first put the channel on the conference in announce/monitor mode */
11116 if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11118 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
11119 rpt_mutex_unlock(&myrpt->lock);
11120 ast_hangup(myrpt->pchannel);
11121 if (myrpt->txchannel != myrpt->rxchannel)
11122 ast_hangup(myrpt->txchannel);
11123 ast_hangup(myrpt->rxchannel);
11124 pthread_exit(NULL);
11126 /* save pseudo channel conference number */
11127 myrpt->conf = myrpt->txconf = ci.confno;
11128 /* if serial io port, open it */
11129 myrpt->iofd = -1;
11130 if (myrpt->p.ioport && ((myrpt->iofd = openserial(myrpt->p.ioport)) == -1))
11132 rpt_mutex_unlock(&myrpt->lock);
11133 ast_hangup(myrpt->pchannel);
11134 if (myrpt->txchannel != myrpt->rxchannel)
11135 ast_hangup(myrpt->txchannel);
11136 ast_hangup(myrpt->rxchannel);
11137 pthread_exit(NULL);
11139 iskenwood_pci4 = 0;
11140 memset(&z,0,sizeof(z));
11141 if ((myrpt->iofd < 1) && (myrpt->txchannel == myrpt->zaptxchannel))
11143 z.radpar = DAHDI_RADPAR_REMMODE;
11144 z.data = DAHDI_RADPAR_REM_NONE;
11145 res = ioctl(myrpt->zaptxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z);
11146 /* if PCIRADIO and kenwood selected */
11147 if ((!res) && (!strcmp(myrpt->remote,remote_rig_kenwood)))
11149 z.radpar = DAHDI_RADPAR_UIOMODE;
11150 z.data = 1;
11151 if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
11153 ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
11154 return -1;
11156 z.radpar = DAHDI_RADPAR_UIODATA;
11157 z.data = 3;
11158 if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
11160 ast_log(LOG_ERROR,"Cannot set UIODATA\n");
11161 return -1;
11163 i = DAHDI_OFFHOOK;
11164 if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_HOOK,&i) == -1)
11166 ast_log(LOG_ERROR,"Cannot set hook\n");
11167 return -1;
11169 iskenwood_pci4 = 1;
11172 if (myrpt->txchannel == myrpt->zaptxchannel)
11174 i = DAHDI_ONHOOK;
11175 ioctl(myrpt->zaptxchannel->fds[0],DAHDI_HOOK,&i);
11176 /* if PCIRADIO and Yaesu ft897/ICOM IC-706 selected */
11177 if ((myrpt->iofd < 1) && (!res) &&
11178 (!strcmp(myrpt->remote,remote_rig_ft897) ||
11179 (!strcmp(myrpt->remote,remote_rig_ic706))))
11181 z.radpar = DAHDI_RADPAR_UIOMODE;
11182 z.data = 1;
11183 if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
11185 ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
11186 return -1;
11188 z.radpar = DAHDI_RADPAR_UIODATA;
11189 z.data = 3;
11190 if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
11192 ast_log(LOG_ERROR,"Cannot set UIODATA\n");
11193 return -1;
11197 myrpt->remoterx = 0;
11198 myrpt->remotetx = 0;
11199 myrpt->retxtimer = 0;
11200 myrpt->rerxtimer = 0;
11201 myrpt->remoteon = 1;
11202 myrpt->dtmfidx = -1;
11203 myrpt->dtmfbuf[0] = 0;
11204 myrpt->dtmf_time_rem = 0;
11205 myrpt->hfscanmode = 0;
11206 myrpt->hfscanstatus = 0;
11207 if (myrpt->p.startupmacro)
11209 snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
11211 time(&myrpt->start_time);
11212 myrpt->last_activity_time = myrpt->start_time;
11213 last_timeout_warning = 0;
11214 myrpt->reload = 0;
11215 myrpt->tele.next = &myrpt->tele;
11216 myrpt->tele.prev = &myrpt->tele;
11217 rpt_mutex_unlock(&myrpt->lock);
11218 ast_set_write_format(chan, AST_FORMAT_SLINEAR);
11219 ast_set_read_format(chan, AST_FORMAT_SLINEAR);
11220 rem_rx = 0;
11221 remkeyed = 0;
11222 /* if we are on 2w loop and are a remote, turn EC on */
11223 if (myrpt->remote && (myrpt->rxchannel == myrpt->txchannel))
11225 i = 128;
11226 ioctl(myrpt->zaprxchannel->fds[0],DAHDI_ECHOCANCEL,&i);
11228 if (chan->_state != AST_STATE_UP) {
11229 ast_answer(chan);
11232 if (myrpt->rxchannel == myrpt->zaprxchannel)
11234 if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_GET_PARAMS,&par) != -1)
11236 if (par.rxisoffhook)
11238 ast_indicate(chan,AST_CONTROL_RADIO_KEY);
11239 myrpt->remoterx = 1;
11240 remkeyed = 1;
11244 if (myrpt->p.archivedir)
11246 char mycmd[100],mydate[100],*b,*b1;
11247 time_t myt;
11248 long blocksleft;
11251 mkdir(myrpt->p.archivedir,0600);
11252 sprintf(mycmd,"%s/%s",myrpt->p.archivedir,myrpt->name);
11253 mkdir(mycmd,0600);
11254 time(&myt);
11255 strftime(mydate,sizeof(mydate) - 1,"%Y%m%d%H%M%S",
11256 localtime(&myt));
11257 sprintf(mycmd,"mixmonitor start %s %s/%s/%s.wav49 a",chan->name,
11258 myrpt->p.archivedir,myrpt->name,mydate);
11259 if (myrpt->p.monminblocks)
11261 blocksleft = diskavail(myrpt);
11262 if (myrpt->p.remotetimeout)
11264 blocksleft -= (myrpt->p.remotetimeout *
11265 MONITOR_DISK_BLOCKS_PER_MINUTE) / 60;
11267 if (blocksleft >= myrpt->p.monminblocks)
11268 ast_cli_command(nullfd,mycmd);
11269 } else ast_cli_command(nullfd,mycmd);
11270 /* look at callerid to see what node this comes from */
11271 if (!chan->cid.cid_num) /* if doesn't have caller id */
11273 b1 = "0";
11274 } else {
11275 ast_callerid_parse(chan->cid.cid_num,&b,&b1);
11276 ast_shrink_phone_number(b1);
11278 sprintf(mycmd,"CONNECT,%s",b1);
11279 donodelog(myrpt,mycmd);
11281 myrpt->loginuser[0] = 0;
11282 myrpt->loginlevel[0] = 0;
11283 myrpt->authtelltimer = 0;
11284 myrpt->authtimer = 0;
11285 authtold = 0;
11286 authreq = 0;
11287 if (myrpt->p.authlevel > 1) authreq = 1;
11288 setrem(myrpt);
11289 n = 0;
11290 dtmfed = 0;
11291 cs[n++] = chan;
11292 cs[n++] = myrpt->rxchannel;
11293 cs[n++] = myrpt->pchannel;
11294 if (myrpt->rxchannel != myrpt->txchannel)
11295 cs[n++] = myrpt->txchannel;
11296 /* start un-locked */
11297 for(;;)
11299 if (ast_check_hangup(chan)) break;
11300 if (ast_check_hangup(myrpt->rxchannel)) break;
11301 notremming = 0;
11302 setting = 0;
11303 reming = 0;
11304 telem = myrpt->tele.next;
11305 while(telem != &myrpt->tele)
11307 if (telem->mode == SETREMOTE) setting = 1;
11308 if ((telem->mode == SETREMOTE) ||
11309 (telem->mode == SCAN) ||
11310 (telem->mode == TUNE)) reming = 1;
11311 else notremming = 1;
11312 telem = telem->next;
11314 if (myrpt->reload)
11316 myrpt->reload = 0;
11317 /* find our index, and load the vars */
11318 for(i = 0; i < nrpts; i++)
11320 if (&rpt_vars[i] == myrpt)
11322 load_rpt_vars(i,0);
11323 break;
11327 time(&t);
11328 if (myrpt->p.remotetimeout)
11330 time_t r;
11332 r = (t - myrpt->start_time);
11333 if (r >= myrpt->p.remotetimeout)
11335 sayfile(chan,"rpt/node");
11336 ast_say_character_str(chan,myrpt->name,NULL,chan->language);
11337 sayfile(chan,"rpt/timeout");
11338 ast_safe_sleep(chan,1000);
11339 break;
11341 if ((myrpt->p.remotetimeoutwarning) &&
11342 (r >= (myrpt->p.remotetimeout -
11343 myrpt->p.remotetimeoutwarning)) &&
11344 (r <= (myrpt->p.remotetimeout -
11345 myrpt->p.remotetimeoutwarningfreq)))
11347 if (myrpt->p.remotetimeoutwarningfreq)
11349 if ((t - last_timeout_warning) >=
11350 myrpt->p.remotetimeoutwarningfreq)
11352 time(&last_timeout_warning);
11353 rpt_telemetry(myrpt,TIMEOUT_WARNING,0);
11356 else
11358 if (!last_timeout_warning)
11360 time(&last_timeout_warning);
11361 rpt_telemetry(myrpt,TIMEOUT_WARNING,0);
11366 if (myrpt->p.remoteinacttimeout && myrpt->last_activity_time)
11368 time_t r;
11370 r = (t - myrpt->last_activity_time);
11371 if (r >= myrpt->p.remoteinacttimeout)
11373 sayfile(chan,"rpt/node");
11374 ast_say_character_str(chan,myrpt->name,NULL,chan->language);
11375 sayfile(chan,"rpt/timeout");
11376 ast_safe_sleep(chan,1000);
11377 break;
11379 if ((myrpt->p.remotetimeoutwarning) &&
11380 (r >= (myrpt->p.remoteinacttimeout -
11381 myrpt->p.remotetimeoutwarning)) &&
11382 (r <= (myrpt->p.remoteinacttimeout -
11383 myrpt->p.remotetimeoutwarningfreq)))
11385 if (myrpt->p.remotetimeoutwarningfreq)
11387 if ((t - last_timeout_warning) >=
11388 myrpt->p.remotetimeoutwarningfreq)
11390 time(&last_timeout_warning);
11391 rpt_telemetry(myrpt,ACT_TIMEOUT_WARNING,0);
11394 else
11396 if (!last_timeout_warning)
11398 time(&last_timeout_warning);
11399 rpt_telemetry(myrpt,ACT_TIMEOUT_WARNING,0);
11404 ms = MSWAIT;
11405 who = ast_waitfor_n(cs,n,&ms);
11406 if (who == NULL) ms = 0;
11407 elap = MSWAIT - ms;
11408 if (myrpt->macrotimer) myrpt->macrotimer -= elap;
11409 if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
11410 if (!ms) continue;
11411 /* do local dtmf timer */
11412 if (myrpt->dtmf_local_timer)
11414 if (myrpt->dtmf_local_timer > 1) myrpt->dtmf_local_timer -= elap;
11415 if (myrpt->dtmf_local_timer < 1) myrpt->dtmf_local_timer = 1;
11417 rpt_mutex_lock(&myrpt->lock);
11418 do_dtmf_local(myrpt,0);
11419 rpt_mutex_unlock(&myrpt->lock);
11420 rem_totx = myrpt->dtmf_local_timer && (!phone_mode);
11421 rem_totx |= keyed && (!myrpt->tunerequest);
11422 rem_rx = (remkeyed && (!setting)) || (myrpt->tele.next != &myrpt->tele);
11423 if(!strcmp(myrpt->remote, remote_rig_ic706))
11424 rem_totx |= myrpt->tunerequest;
11425 if (keyed && (!keyed1))
11427 keyed1 = 1;
11430 if (!keyed && (keyed1))
11432 time_t myt;
11434 keyed1 = 0;
11435 time(&myt);
11436 /* if login necessary, and not too soon */
11437 if ((myrpt->p.authlevel) &&
11438 (!myrpt->loginlevel[0]) &&
11439 (myt > (t + 3)))
11441 authreq = 1;
11442 authtold = 0;
11443 myrpt->authtelltimer = AUTHTELLTIME - AUTHTXTIME;
11448 if (rem_rx && (!myrpt->remoterx))
11450 myrpt->remoterx = 1;
11451 ast_indicate(chan,AST_CONTROL_RADIO_KEY);
11453 if ((!rem_rx) && (myrpt->remoterx))
11455 myrpt->remoterx = 0;
11456 ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
11458 /* if auth requested, and not authed yet */
11459 if (authreq && (!myrpt->loginlevel[0]))
11461 if ((!authtold) && ((myrpt->authtelltimer += elap)
11462 >= AUTHTELLTIME))
11464 authtold = 1;
11465 rpt_telemetry(myrpt,LOGINREQ,NULL);
11467 if ((myrpt->authtimer += elap) >= AUTHLOGOUTTIME)
11469 break; /* if not logged in, hang up after a time */
11472 #ifndef OLDKEY
11473 if ((myrpt->retxtimer += elap) >= REDUNDANT_TX_TIME)
11475 myrpt->retxtimer = 0;
11476 if ((myrpt->remoterx) && (!myrpt->remotetx))
11477 ast_indicate(chan,AST_CONTROL_RADIO_KEY);
11478 else
11479 ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
11482 if ((myrpt->rerxtimer += elap) >= (REDUNDANT_TX_TIME * 2))
11484 keyed = 0;
11485 myrpt->rerxtimer = 0;
11487 #endif
11488 if (rem_totx && (!myrpt->remotetx))
11490 /* if not authed, and needed, dont transmit */
11491 if ((!myrpt->p.authlevel) || myrpt->loginlevel[0])
11493 myrpt->remotetx = 1;
11494 if((myrpt->remtxfreqok = check_tx_freq(myrpt)))
11496 time(&myrpt->last_activity_time);
11497 if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->zaptxchannel))
11499 z.radpar = DAHDI_RADPAR_UIODATA;
11500 z.data = 1;
11501 if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
11503 ast_log(LOG_ERROR,"Cannot set UIODATA\n");
11504 return -1;
11507 else
11509 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
11511 if (myrpt->p.archivedir) donodelog(myrpt,"TXKEY");
11515 if ((!rem_totx) && myrpt->remotetx) /* Remote base radio TX unkey */
11517 myrpt->remotetx = 0;
11518 if(!myrpt->remtxfreqok){
11519 rpt_telemetry(myrpt,UNAUTHTX,NULL);
11521 if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->zaptxchannel))
11523 z.radpar = DAHDI_RADPAR_UIODATA;
11524 z.data = 3;
11525 if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
11527 ast_log(LOG_ERROR,"Cannot set UIODATA\n");
11528 return -1;
11531 else
11533 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
11535 if (myrpt->p.archivedir) donodelog(myrpt,"TXUNKEY");
11537 if (myrpt->hfscanmode){
11538 myrpt->scantimer -= elap;
11539 if(myrpt->scantimer <= 0){
11540 if (!reming)
11542 myrpt->scantimer = REM_SCANTIME;
11543 rpt_telemetry(myrpt,SCAN,0);
11544 } else myrpt->scantimer = 1;
11547 rpt_mutex_lock(&myrpt->lock);
11548 c = myrpt->macrobuf[0];
11549 if (c && (!myrpt->macrotimer))
11551 myrpt->macrotimer = MACROTIME;
11552 memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1);
11553 if ((c == 'p') || (c == 'P'))
11554 myrpt->macrotimer = MACROPTIME;
11555 rpt_mutex_unlock(&myrpt->lock);
11556 if (myrpt->p.archivedir)
11558 char str[100];
11559 sprintf(str,"DTMF(M),%c",c);
11560 donodelog(myrpt,str);
11562 if (handle_remote_dtmf_digit(myrpt,c,&keyed,0) == -1) break;
11563 continue;
11564 } else rpt_mutex_unlock(&myrpt->lock);
11565 if (who == chan) /* if it was a read from incomming */
11567 f = ast_read(chan);
11568 if (!f)
11570 if (debug) printf("@@@@ link:Hung Up\n");
11571 break;
11573 if (f->frametype == AST_FRAME_VOICE)
11575 if (ioctl(chan->fds[0], DAHDI_GETCONFMUTE, &ismuted) == -1)
11577 ismuted = 0;
11579 /* if not transmitting, zero-out audio */
11580 ismuted |= (!myrpt->remotetx);
11581 if (dtmfed && phone_mode) ismuted = 1;
11582 dtmfed = 0;
11583 if (ismuted)
11585 memset(f->data,0,f->datalen);
11586 if (myrpt->lastf1)
11587 memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
11588 if (myrpt->lastf2)
11589 memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
11591 if (f) f2 = ast_frdup(f);
11592 else f2 = NULL;
11593 f1 = myrpt->lastf2;
11594 myrpt->lastf2 = myrpt->lastf1;
11595 myrpt->lastf1 = f2;
11596 if (ismuted)
11598 if (myrpt->lastf1)
11599 memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
11600 if (myrpt->lastf2)
11601 memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
11603 if (f1)
11605 if (phone_mode)
11606 ast_write(myrpt->txchannel,f1);
11607 else
11608 ast_write(myrpt->txchannel,f);
11609 ast_frfree(f1);
11612 #ifndef OLD_ASTERISK
11613 else if (f->frametype == AST_FRAME_DTMF_BEGIN)
11615 if (myrpt->lastf1)
11616 memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
11617 if (myrpt->lastf2)
11618 memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
11619 dtmfed = 1;
11621 #endif
11622 if (f->frametype == AST_FRAME_DTMF)
11624 if (myrpt->lastf1)
11625 memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
11626 if (myrpt->lastf2)
11627 memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
11628 dtmfed = 1;
11629 if (handle_remote_phone_dtmf(myrpt,f->subclass,&keyed,phone_mode) == -1)
11631 if (debug) printf("@@@@ rpt:Hung Up\n");
11632 ast_frfree(f);
11633 break;
11636 if (f->frametype == AST_FRAME_TEXT)
11638 if (handle_remote_data(myrpt,f->data) == -1)
11640 if (debug) printf("@@@@ rpt:Hung Up\n");
11641 ast_frfree(f);
11642 break;
11645 if (f->frametype == AST_FRAME_CONTROL)
11647 if (f->subclass == AST_CONTROL_HANGUP)
11649 if (debug) printf("@@@@ rpt:Hung Up\n");
11650 ast_frfree(f);
11651 break;
11653 /* if RX key */
11654 if (f->subclass == AST_CONTROL_RADIO_KEY)
11656 if (debug == 7) printf("@@@@ rx key\n");
11657 keyed = 1;
11658 myrpt->rerxtimer = 0;
11660 /* if RX un-key */
11661 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
11663 myrpt->rerxtimer = 0;
11664 if (debug == 7) printf("@@@@ rx un-key\n");
11665 keyed = 0;
11668 ast_frfree(f);
11669 continue;
11671 if (who == myrpt->rxchannel) /* if it was a read from radio */
11673 f = ast_read(myrpt->rxchannel);
11674 if (!f)
11676 if (debug) printf("@@@@ link:Hung Up\n");
11677 break;
11679 if (f->frametype == AST_FRAME_VOICE)
11681 int myreming = 0;
11683 if(!strcmp(myrpt->remote, remote_rig_kenwood))
11684 myreming = reming;
11686 if (myreming || (!remkeyed) ||
11687 ((myrpt->remote) && (myrpt->remotetx)) ||
11688 ((myrpt->remmode != REM_MODE_FM) &&
11689 notremming))
11690 memset(f->data,0,f->datalen);
11691 ast_write(myrpt->pchannel,f);
11693 else if (f->frametype == AST_FRAME_CONTROL)
11695 if (f->subclass == AST_CONTROL_HANGUP)
11697 if (debug) printf("@@@@ rpt:Hung Up\n");
11698 ast_frfree(f);
11699 break;
11701 /* if RX key */
11702 if (f->subclass == AST_CONTROL_RADIO_KEY)
11704 if (debug == 7) printf("@@@@ remote rx key\n");
11705 if (!myrpt->remotetx)
11707 remkeyed = 1;
11710 /* if RX un-key */
11711 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
11713 if (debug == 7) printf("@@@@ remote rx un-key\n");
11714 if (!myrpt->remotetx)
11716 remkeyed = 0;
11720 ast_frfree(f);
11721 continue;
11723 if (who == myrpt->pchannel) /* if is remote mix output */
11725 f = ast_read(myrpt->pchannel);
11726 if (!f)
11728 if (debug) printf("@@@@ link:Hung Up\n");
11729 break;
11731 if (f->frametype == AST_FRAME_VOICE)
11733 ast_write(chan,f);
11735 if (f->frametype == AST_FRAME_CONTROL)
11737 if (f->subclass == AST_CONTROL_HANGUP)
11739 if (debug) printf("@@@@ rpt:Hung Up\n");
11740 ast_frfree(f);
11741 break;
11744 ast_frfree(f);
11745 continue;
11747 if ((myrpt->rxchannel != myrpt->txchannel) &&
11748 (who == myrpt->txchannel)) /* do this cuz you have to */
11750 f = ast_read(myrpt->txchannel);
11751 if (!f)
11753 if (debug) printf("@@@@ link:Hung Up\n");
11754 break;
11756 if (f->frametype == AST_FRAME_CONTROL)
11758 if (f->subclass == AST_CONTROL_HANGUP)
11760 if (debug) printf("@@@@ rpt:Hung Up\n");
11761 ast_frfree(f);
11762 break;
11765 ast_frfree(f);
11766 continue;
11769 if (myrpt->p.archivedir)
11771 char mycmd[100],*b,*b1;
11773 /* look at callerid to see what node this comes from */
11774 if (!chan->cid.cid_num) /* if doesn't have caller id */
11776 b1 = "0";
11777 } else {
11778 ast_callerid_parse(chan->cid.cid_num,&b,&b1);
11779 ast_shrink_phone_number(b1);
11781 sprintf(mycmd,"DISCONNECT,%s",b1);
11782 donodelog(myrpt,mycmd);
11784 /* wait for telem to be done */
11785 while(myrpt->tele.next != &myrpt->tele) usleep(100000);
11786 sprintf(tmp,"mixmonitor stop %s",chan->name);
11787 ast_cli_command(nullfd,tmp);
11788 close(nullfd);
11789 rpt_mutex_lock(&myrpt->lock);
11790 myrpt->hfscanmode = 0;
11791 myrpt->hfscanstatus = 0;
11792 myrpt->remoteon = 0;
11793 rpt_mutex_unlock(&myrpt->lock);
11794 if (myrpt->lastf1) ast_frfree(myrpt->lastf1);
11795 myrpt->lastf1 = NULL;
11796 if (myrpt->lastf2) ast_frfree(myrpt->lastf2);
11797 myrpt->lastf2 = NULL;
11798 if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->zaptxchannel))
11800 z.radpar = DAHDI_RADPAR_UIOMODE;
11801 z.data = 3;
11802 if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
11804 ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
11805 return -1;
11807 z.radpar = DAHDI_RADPAR_UIODATA;
11808 z.data = 3;
11809 if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
11811 ast_log(LOG_ERROR,"Cannot set UIODATA\n");
11812 return -1;
11814 i = DAHDI_OFFHOOK;
11815 if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_HOOK,&i) == -1)
11817 ast_log(LOG_ERROR,"Cannot set hook\n");
11818 return -1;
11821 if (myrpt->iofd) close(myrpt->iofd);
11822 myrpt->iofd = -1;
11823 ast_hangup(myrpt->pchannel);
11824 if (myrpt->rxchannel != myrpt->txchannel) ast_hangup(myrpt->txchannel);
11825 ast_hangup(myrpt->rxchannel);
11826 closerem(myrpt);
11827 #ifdef OLD_ASTERISK
11828 LOCAL_USER_REMOVE(u);
11829 #endif
11830 return res;
11833 #ifdef OLD_ASTERISK
11834 int unload_module()
11835 #else
11836 static int unload_module(void)
11837 #endif
11839 int i;
11841 #ifdef OLD_ASTERISK
11842 STANDARD_HANGUP_LOCALUSERS;
11843 #endif
11844 for(i = 0; i < nrpts; i++) {
11845 if (!strcmp(rpt_vars[i].name,rpt_vars[i].p.nodes)) continue;
11846 ast_mutex_destroy(&rpt_vars[i].lock);
11847 ast_mutex_destroy(&rpt_vars[i].remlock);
11849 i = ast_unregister_application(app);
11851 /* Unregister cli extensions */
11852 ast_cli_unregister(&cli_debug);
11853 ast_cli_unregister(&cli_dump);
11854 ast_cli_unregister(&cli_stats);
11855 ast_cli_unregister(&cli_lstats);
11856 ast_cli_unregister(&cli_nodes);
11857 ast_cli_unregister(&cli_reload);
11858 ast_cli_unregister(&cli_restart);
11859 ast_cli_unregister(&cli_fun);
11861 return i;
11864 #ifdef OLD_ASTERISK
11865 int load_module()
11866 #else
11867 static int load_module(void)
11868 #endif
11870 ast_pthread_create(&rpt_master_thread,NULL,rpt_master,NULL);
11872 /* Register cli extensions */
11873 ast_cli_register(&cli_debug);
11874 ast_cli_register(&cli_dump);
11875 ast_cli_register(&cli_stats);
11876 ast_cli_register(&cli_lstats);
11877 ast_cli_register(&cli_nodes);
11878 ast_cli_register(&cli_reload);
11879 ast_cli_register(&cli_restart);
11880 ast_cli_register(&cli_fun);
11882 return ast_register_application(app, rpt_exec, synopsis, descrip);
11885 #ifdef OLD_ASTERISK
11886 char *description()
11888 return tdesc;
11890 int usecount(void)
11892 int res;
11893 STANDARD_USECOUNT(res);
11894 return res;
11897 char *key()
11899 return ASTERISK_GPL_KEY;
11901 #endif
11903 #ifdef OLD_ASTERISK
11904 int reload()
11905 #else
11906 static int reload(void)
11907 #endif
11909 int n;
11911 for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
11912 return(0);
11915 #ifndef OLD_ASTERISK
11916 /* STD_MOD(MOD_1, reload, NULL, NULL); */
11917 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Radio Repeater/Remote Base Application",
11918 .load = load_module,
11919 .unload = unload_module,
11920 .reload = reload,
11923 #endif