Adds DAHDI support alongside Zaptel. DAHDI usage favored, but all Zap stuff should...
[asterisk-bristuff.git] / apps / app_rpt.c
blob8465a262776eb411b5121543b350ed51e83908ba
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>zaptel</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 #ifdef OLD_ASTERISK
280 #include <linux/zaptel.h>
281 #include <tonezone.h>
282 #else
283 #include <zaptel/zaptel.h>
284 #include <zaptel/tonezone.h>
285 #endif
286 #include <netinet/in.h>
287 #include <arpa/inet.h>
289 #include "asterisk/utils.h"
290 #include "asterisk/lock.h"
291 #include "asterisk/file.h"
292 #include "asterisk/logger.h"
293 #include "asterisk/channel.h"
294 #include "asterisk/callerid.h"
295 #include "asterisk/pbx.h"
296 #include "asterisk/module.h"
297 #include "asterisk/translate.h"
298 #include "asterisk/features.h"
299 #include "asterisk/options.h"
300 #include "asterisk/cli.h"
301 #include "asterisk/config.h"
302 #include "asterisk/say.h"
303 #include "asterisk/localtime.h"
304 #include "asterisk/cdr.h"
305 #include "asterisk/options.h"
306 #include <termios.h>
308 /* Start a tone-list going */
309 int ast_playtones_start(struct ast_channel *chan, int vol, const char* tonelist, int interruptible);
310 /*! Stop the tones from playing */
311 void ast_playtones_stop(struct ast_channel *chan);
313 static char *tdesc = "Radio Repeater / Remote Base version 0.73 09/04/2007";
315 static char *app = "Rpt";
317 static char *synopsis = "Radio Repeater/Remote Base Control System";
319 static char *descrip =
320 " Rpt(nodename[|options]): Radio Remote Link or Remote Base Link Endpoint Process.\n"
321 "\n"
322 " Not specifying an option puts it in normal endpoint mode (where source\n"
323 " IP and nodename are verified).\n"
324 "\n"
325 " Options are as follows:\n"
326 "\n"
327 " X - Normal endpoint mode WITHOUT security check. Only specify\n"
328 " this if you have checked security already (like with an IAX2\n"
329 " user/password or something).\n"
330 "\n"
331 " Rannounce-string[|timeout[|timeout-destination]] - Amateur Radio\n"
332 " Reverse Autopatch. Caller is put on hold, and announcement (as\n"
333 " specified by the 'announce-string') is played on radio system.\n"
334 " Users of radio system can access autopatch, dial specified\n"
335 " code, and pick up call. Announce-string is list of names of\n"
336 " recordings, or \"PARKED\" to substitute code for un-parking,\n"
337 " or \"NODE\" to substitute node number.\n"
338 "\n"
339 " P - Phone Control mode. This allows a regular phone user to have\n"
340 " full control and audio access to the radio system. For the\n"
341 " user to have DTMF control, the 'phone_functions' parameter\n"
342 " must be specified for the node in 'rpt.conf'. An additional\n"
343 " function (cop,6) must be listed so that PTT control is available.\n"
344 "\n"
345 " D - Dumb Phone Control mode. This allows a regular phone user to\n"
346 " have full control and audio access to the radio system. In this\n"
347 " mode, the PTT is activated for the entire length of the call.\n"
348 " For the user to have DTMF control (not generally recomended in\n"
349 " this mode), the 'dphone_functions' parameter must be specified\n"
350 " for the node in 'rpt.conf'. Otherwise no DTMF control will be\n"
351 " available to the phone user.\n"
352 "\n";
354 static int debug = 0; /* Set this >0 for extra debug output */
355 static int nrpts = 0;
357 static char remdtmfstr[] = "0123456789*#ABCD";
359 enum {TOP_TOP,TOP_WON,WON_BEFREAD,BEFREAD_AFTERREAD};
361 int max_chan_stat [] = {22000,1000,22000,100,22000,2000,22000};
363 #define NRPTSTAT 7
365 struct rpt_chan_stat
367 struct timeval last;
368 long long total;
369 unsigned long count;
370 unsigned long largest;
371 struct timeval largest_time;
374 char *discstr = "!!DISCONNECT!!";
375 static char *remote_rig_ft897="ft897";
376 static char *remote_rig_rbi="rbi";
377 static char *remote_rig_kenwood="kenwood";
378 static char *remote_rig_ic706="ic706";
380 #ifdef OLD_ASTERISK
381 STANDARD_LOCAL_USER;
382 LOCAL_USER_DECL;
383 #endif
385 #define MSWAIT 200
386 #define HANGTIME 5000
387 #define TOTIME 180000
388 #define IDTIME 300000
389 #define MAXRPTS 20
390 #define MAX_STAT_LINKS 32
391 #define POLITEID 30000
392 #define FUNCTDELAY 1500
394 #define MAXXLAT 20
395 #define MAXXLATTIME 3
397 #define MAX_SYSSTATES 10
399 struct rpt_xlat
401 char funccharseq[MAXXLAT];
402 char endcharseq[MAXXLAT];
403 char passchars[MAXXLAT];
404 int funcindex;
405 int endindex;
406 time_t lastone;
409 static time_t starttime = 0;
411 static pthread_t rpt_master_thread;
413 struct rpt;
415 struct rpt_link
417 struct rpt_link *next;
418 struct rpt_link *prev;
419 char mode; /* 1 if in tx mode */
420 char isremote;
421 char phonemode;
422 char name[MAXNODESTR]; /* identifier (routing) string */
423 char lasttx;
424 char lastrx;
425 char lastrx1;
426 char connected;
427 char hasconnected;
428 char perma;
429 char thisconnected;
430 char outbound;
431 char disced;
432 char killme;
433 long elaptime;
434 long disctime;
435 long retrytimer;
436 long retxtimer;
437 long rerxtimer;
438 int retries;
439 int max_retries;
440 int reconnects;
441 long long connecttime;
442 struct ast_channel *chan;
443 struct ast_channel *pchan;
444 char linklist[MAXLINKLIST];
445 time_t linklistreceived;
446 long linklisttimer;
447 int dtmfed;
448 int linkunkeytocttimer;
449 struct ast_frame *lastf1,*lastf2;
450 struct rpt_chan_stat chan_stat[NRPTSTAT];
453 struct rpt_lstat
455 struct rpt_lstat *next;
456 struct rpt_lstat *prev;
457 char peer[MAXPEERSTR];
458 char name[MAXNODESTR];
459 char mode;
460 char outbound;
461 char reconnects;
462 char thisconnected;
463 long long connecttime;
464 struct rpt_chan_stat chan_stat[NRPTSTAT];
467 struct rpt_tele
469 struct rpt_tele *next;
470 struct rpt_tele *prev;
471 struct rpt *rpt;
472 struct ast_channel *chan;
473 int mode;
474 struct rpt_link mylink;
475 char param[TELEPARAMSIZE];
476 int submode;
477 pthread_t threadid;
480 struct function_table_tag
482 char action[ACTIONSIZE];
483 int (*function)(struct rpt *myrpt, char *param, char *digitbuf,
484 int command_source, struct rpt_link *mylink);
487 /* Used to store the morse code patterns */
489 struct morse_bits
491 int len;
492 int ddcomb;
495 struct telem_defaults
497 char name[20];
498 char value[80];
502 struct sysstate
504 char txdisable;
505 char totdisable;
506 char linkfundisable;
507 char autopatchdisable;
508 char schedulerdisable;
509 char userfundisable;
510 char alternatetail;
513 static struct rpt
515 ast_mutex_t lock;
516 ast_mutex_t remlock;
517 struct ast_config *cfg;
518 char reload;
520 char *name;
521 char *rxchanname;
522 char *txchanname;
523 char *remote;
524 struct rpt_chan_stat chan_stat[NRPTSTAT];
525 unsigned int scram;
527 struct {
528 char *ourcontext;
529 char *ourcallerid;
530 char *acctcode;
531 char *ident;
532 char *tonezone;
533 char simple;
534 char *functions;
535 char *link_functions;
536 char *phone_functions;
537 char *dphone_functions;
538 char *nodes;
539 char *extnodes;
540 char *extnodefile;
541 int hangtime;
542 int althangtime;
543 int totime;
544 int idtime;
545 int tailmessagetime;
546 int tailsquashedtime;
547 int duplex;
548 int politeid;
549 char *tailmessages[500];
550 int tailmessagemax;
551 char *memory;
552 char *macro;
553 char *startupmacro;
554 int iobase;
555 char *ioport;
556 char funcchar;
557 char endchar;
558 char nobusyout;
559 char notelemtx;
560 char propagate_dtmf;
561 char propagate_phonedtmf;
562 char linktolink;
563 unsigned char civaddr;
564 struct rpt_xlat inxlat;
565 struct rpt_xlat outxlat;
566 char *archivedir;
567 int authlevel;
568 char *csstanzaname;
569 char *skedstanzaname;
570 char *txlimitsstanzaname;
571 long monminblocks;
572 int remoteinacttimeout;
573 int remotetimeout;
574 int remotetimeoutwarning;
575 int remotetimeoutwarningfreq;
576 int sysstate_cur;
577 struct sysstate s[MAX_SYSSTATES];
578 } p;
579 struct rpt_link links;
580 int unkeytocttimer;
581 char keyed;
582 char exttx;
583 char localtx;
584 char remoterx;
585 char remotetx;
586 char remoteon;
587 char remtxfreqok;
588 char tounkeyed;
589 char tonotify;
590 char dtmfbuf[MAXDTMF];
591 char macrobuf[MAXMACRO];
592 char rem_dtmfbuf[MAXDTMF];
593 char lastdtmfcommand[MAXDTMF];
594 char cmdnode[50];
595 struct ast_channel *rxchannel,*txchannel, *monchannel;
596 struct ast_channel *pchannel,*txpchannel, *zaprxchannel, *zaptxchannel;
597 struct ast_frame *lastf1,*lastf2;
598 struct rpt_tele tele;
599 struct timeval lasttv,curtv;
600 pthread_t rpt_call_thread,rpt_thread;
601 time_t dtmf_time,rem_dtmf_time,dtmf_time_rem;
602 int tailtimer,totimer,idtimer,txconf,conf,callmode,cidx,scantimer,tmsgtimer,skedtimer;
603 int mustid,tailid;
604 int tailevent;
605 int telemrefcount;
606 int dtmfidx,rem_dtmfidx;
607 int dailytxtime,dailykerchunks,totalkerchunks,dailykeyups,totalkeyups,timeouts;
608 int totalexecdcommands, dailyexecdcommands;
609 long retxtimer;
610 long rerxtimer;
611 long long totaltxtime;
612 char mydtmf;
613 char exten[AST_MAX_EXTENSION];
614 char freq[MAXREMSTR],rxpl[MAXREMSTR],txpl[MAXREMSTR];
615 char offset;
616 char powerlevel;
617 char txplon;
618 char rxplon;
619 char remmode;
620 char tunerequest;
621 char hfscanmode;
622 int hfscanstatus;
623 char hfscanstop;
624 char lastlinknode[MAXNODESTR];
625 char savednodes[MAXNODESTR];
626 int stopgen;
627 char patchfarenddisconnect;
628 char patchnoct;
629 char patchquiet;
630 char patchcontext[MAXPATCHCONTEXT];
631 int patchdialtime;
632 int macro_longest;
633 int phone_longestfunc;
634 int dphone_longestfunc;
635 int link_longestfunc;
636 int longestfunc;
637 int longestnode;
638 int threadrestarts;
639 int tailmessagen;
640 time_t disgorgetime;
641 time_t lastthreadrestarttime;
642 long macrotimer;
643 char lastnodewhichkeyedusup[MAXNODESTR];
644 int dtmf_local_timer;
645 char dtmf_local_str[100];
646 struct ast_filestream *monstream;
647 char loginuser[50];
648 char loginlevel[10];
649 long authtelltimer;
650 long authtimer;
651 int iofd;
652 time_t start_time,last_activity_time;
653 #ifdef __RPT_NOTCH
654 struct rptfilter
656 char desc[100];
657 float x0;
658 float x1;
659 float x2;
660 float y0;
661 float y1;
662 float y2;
663 float gain;
664 float const0;
665 float const1;
666 float const2;
667 } filters[MAXFILTERS];
668 #endif
669 #ifdef _MDC_DECODE_H_
670 mdc_decoder_t *mdc;
671 unsigned short lastunit;
672 #endif
673 } rpt_vars[MAXRPTS];
675 struct nodelog {
676 struct nodelog *next;
677 struct nodelog *prev;
678 time_t timestamp;
679 char archivedir[MAXNODESTR];
680 char str[MAXNODESTR * 2];
681 } nodelog;
683 static int service_scan(struct rpt *myrpt);
684 static int set_mode_ft897(struct rpt *myrpt, char newmode);
685 static int set_mode_ic706(struct rpt *myrpt, char newmode);
686 static int simple_command_ft897(struct rpt *myrpt, char command);
687 static int setrem(struct rpt *myrpt);
689 AST_MUTEX_DEFINE_STATIC(nodeloglock);
691 AST_MUTEX_DEFINE_STATIC(nodelookuplock);
693 #ifdef APP_RPT_LOCK_DEBUG
695 #warning COMPILING WITH LOCK-DEBUGGING ENABLED!!
697 #define MAXLOCKTHREAD 100
699 #define rpt_mutex_lock(x) _rpt_mutex_lock(x,myrpt,__LINE__)
700 #define rpt_mutex_unlock(x) _rpt_mutex_unlock(x,myrpt,__LINE__)
702 struct lockthread
704 pthread_t id;
705 int lockcount;
706 int lastlock;
707 int lastunlock;
708 } lockthreads[MAXLOCKTHREAD];
711 struct by_lightning
713 int line;
714 struct timeval tv;
715 struct rpt *rpt;
716 struct lockthread lockthread;
717 } lock_ring[32];
719 int lock_ring_index = 0;
721 AST_MUTEX_DEFINE_STATIC(locklock);
723 static struct lockthread *get_lockthread(pthread_t id)
725 int i;
727 for(i = 0; i < MAXLOCKTHREAD; i++)
729 if (lockthreads[i].id == id) return(&lockthreads[i]);
731 return(NULL);
734 static struct lockthread *put_lockthread(pthread_t id)
736 int i;
738 for(i = 0; i < MAXLOCKTHREAD; i++)
740 if (lockthreads[i].id == id)
741 return(&lockthreads[i]);
743 for(i = 0; i < MAXLOCKTHREAD; i++)
745 if (!lockthreads[i].id)
747 lockthreads[i].lockcount = 0;
748 lockthreads[i].lastlock = 0;
749 lockthreads[i].lastunlock = 0;
750 lockthreads[i].id = id;
751 return(&lockthreads[i]);
754 return(NULL);
758 static void rpt_mutex_spew(void)
760 struct by_lightning lock_ring_copy[32];
761 int lock_ring_index_copy;
762 int i,j;
763 long long diff;
764 char a[100];
765 struct timeval lasttv;
767 ast_mutex_lock(&locklock);
768 memcpy(&lock_ring_copy, &lock_ring, sizeof(lock_ring_copy));
769 lock_ring_index_copy = lock_ring_index;
770 ast_mutex_unlock(&locklock);
772 lasttv.tv_sec = lasttv.tv_usec = 0;
773 for(i = 0 ; i < 32 ; i++)
775 j = (i + lock_ring_index_copy) % 32;
776 strftime(a,sizeof(a) - 1,"%m/%d/%Y %H:%M:%S",
777 localtime(&lock_ring_copy[j].tv.tv_sec));
778 diff = 0;
779 if(lasttv.tv_sec)
781 diff = (lock_ring_copy[j].tv.tv_sec - lasttv.tv_sec)
782 * 1000000;
783 diff += (lock_ring_copy[j].tv.tv_usec - lasttv.tv_usec);
785 lasttv.tv_sec = lock_ring_copy[j].tv.tv_sec;
786 lasttv.tv_usec = lock_ring_copy[j].tv.tv_usec;
787 if (!lock_ring_copy[j].tv.tv_sec) continue;
788 if (lock_ring_copy[j].line < 0)
790 ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] UNLOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
791 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);
793 else
795 ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] LOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
796 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);
802 static void _rpt_mutex_lock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
804 struct lockthread *t;
805 pthread_t id;
807 id = pthread_self();
808 ast_mutex_lock(&locklock);
809 t = put_lockthread(id);
810 if (!t)
812 ast_mutex_unlock(&locklock);
813 return;
815 if (t->lockcount)
817 int lastline = t->lastlock;
818 ast_mutex_unlock(&locklock);
819 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);
820 rpt_mutex_spew();
821 return;
823 t->lastlock = line;
824 t->lockcount = 1;
825 gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
826 lock_ring[lock_ring_index].rpt = myrpt;
827 memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
828 lock_ring[lock_ring_index++].line = line;
829 if(lock_ring_index == 32)
830 lock_ring_index = 0;
831 ast_mutex_unlock(&locklock);
832 ast_mutex_lock(lockp);
836 static void _rpt_mutex_unlock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
838 struct lockthread *t;
839 pthread_t id;
841 id = pthread_self();
842 ast_mutex_lock(&locklock);
843 t = put_lockthread(id);
844 if (!t)
846 ast_mutex_unlock(&locklock);
847 return;
849 if (!t->lockcount)
851 int lastline = t->lastunlock;
852 ast_mutex_unlock(&locklock);
853 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);
854 rpt_mutex_spew();
855 return;
857 t->lastunlock = line;
858 t->lockcount = 0;
859 gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
860 lock_ring[lock_ring_index].rpt = myrpt;
861 memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
862 lock_ring[lock_ring_index++].line = -line;
863 if(lock_ring_index == 32)
864 lock_ring_index = 0;
865 ast_mutex_unlock(&locklock);
866 ast_mutex_unlock(lockp);
869 #else /* APP_RPT_LOCK_DEBUG */
871 #define rpt_mutex_lock(x) ast_mutex_lock(x)
872 #define rpt_mutex_unlock(x) ast_mutex_unlock(x)
874 #endif /* APP_RPT_LOCK_DEBUG */
877 * Return 1 if rig is multimode capable
880 static int multimode_capable(struct rpt *myrpt)
882 if(!strcmp(myrpt->remote, remote_rig_ft897))
883 return 1;
884 if(!strcmp(myrpt->remote, remote_rig_ic706))
885 return 1;
886 return 0;
890 * CLI extensions
893 /* Debug mode */
894 static int rpt_do_debug(int fd, int argc, char *argv[]);
895 static int rpt_do_dump(int fd, int argc, char *argv[]);
896 static int rpt_do_stats(int fd, int argc, char *argv[]);
897 static int rpt_do_lstats(int fd, int argc, char *argv[]);
898 static int rpt_do_nodes(int fd, int argc, char *argv[]);
899 static int rpt_do_reload(int fd, int argc, char *argv[]);
900 static int rpt_do_restart(int fd, int argc, char *argv[]);
901 static int rpt_do_fun(int fd, int argc, char *argv[]);
903 static char debug_usage[] =
904 "Usage: rpt debug level {0-7}\n"
905 " Enables debug messages in app_rpt\n";
907 static char dump_usage[] =
908 "Usage: rpt dump <nodename>\n"
909 " Dumps struct debug info to log\n";
911 static char dump_stats[] =
912 "Usage: rpt stats <nodename>\n"
913 " Dumps node statistics to console\n";
915 static char dump_lstats[] =
916 "Usage: rpt lstats <nodename>\n"
917 " Dumps link statistics to console\n";
919 static char dump_nodes[] =
920 "Usage: rpt nodes <nodename>\n"
921 " Dumps a list of directly and indirectly connected nodes to the console\n";
923 static char reload_usage[] =
924 "Usage: rpt reload\n"
925 " Reloads app_rpt running config parameters\n";
927 static char restart_usage[] =
928 "Usage: rpt restart\n"
929 " Restarts app_rpt\n";
931 static char fun_usage[] =
932 "Usage: rpt fun <nodename> <command>\n"
933 " Send a DTMF function to a node\n";
936 static struct ast_cli_entry cli_debug =
937 { { "rpt", "debug", "level" }, rpt_do_debug,
938 "Enable app_rpt debugging", debug_usage };
940 static struct ast_cli_entry cli_dump =
941 { { "rpt", "dump" }, rpt_do_dump,
942 "Dump app_rpt structs for debugging", dump_usage };
944 static struct ast_cli_entry cli_stats =
945 { { "rpt", "stats" }, rpt_do_stats,
946 "Dump node statistics", dump_stats };
948 static struct ast_cli_entry cli_nodes =
949 { { "rpt", "nodes" }, rpt_do_nodes,
950 "Dump node list", dump_nodes };
952 static struct ast_cli_entry cli_lstats =
953 { { "rpt", "lstats" }, rpt_do_lstats,
954 "Dump link statistics", dump_lstats };
956 static struct ast_cli_entry cli_reload =
957 { { "rpt", "reload" }, rpt_do_reload,
958 "Reload app_rpt config", reload_usage };
960 static struct ast_cli_entry cli_restart =
961 { { "rpt", "restart" }, rpt_do_restart,
962 "Restart app_rpt", restart_usage };
964 static struct ast_cli_entry cli_fun =
965 { { "rpt", "fun" }, rpt_do_fun,
966 "Execute a DTMF function", fun_usage };
969 * Telemetry defaults
973 static struct telem_defaults tele_defs[] = {
974 {"ct1","|t(350,0,100,3072)(500,0,100,3072)(660,0,100,3072)"},
975 {"ct2","|t(660,880,150,3072)"},
976 {"ct3","|t(440,0,150,3072)"},
977 {"ct4","|t(550,0,150,3072)"},
978 {"ct5","|t(660,0,150,3072)"},
979 {"ct6","|t(880,0,150,3072)"},
980 {"ct7","|t(660,440,150,3072)"},
981 {"ct8","|t(700,1100,150,3072)"},
982 {"remotemon","|t(1600,0,75,2048)"},
983 {"remotetx","|t(2000,0,75,2048)(0,0,75,0)(1600,0,75,2048)"},
984 {"cmdmode","|t(900,904,200,2048)"},
985 {"functcomplete","|t(1000,0,100,2048)(0,0,100,0)(1000,0,100,2048)"}
989 * Forward decl's - these suppress compiler warnings when funcs coded further down the file than thier invokation
992 static int setrbi(struct rpt *myrpt);
993 static int set_ft897(struct rpt *myrpt);
994 static int set_ic706(struct rpt *myrpt);
995 static int setkenwood(struct rpt *myrpt);
996 static int setrbi_check(struct rpt *myrpt);
1001 * Define function protos for function table here
1004 static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1005 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1006 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1007 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1008 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1009 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1010 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1012 * Function table
1015 static struct function_table_tag function_table[] = {
1016 {"cop", function_cop},
1017 {"autopatchup", function_autopatchup},
1018 {"autopatchdn", function_autopatchdn},
1019 {"ilink", function_ilink},
1020 {"status", function_status},
1021 {"remote", function_remote},
1022 {"macro", function_macro}
1025 static long diskavail(struct rpt *myrpt)
1027 struct statfs statfsbuf;
1029 if (!myrpt->p.archivedir) return(0);
1030 if (statfs(myrpt->p.archivedir,&statfsbuf) == -1)
1032 ast_log(LOG_WARNING,"Cannot get filesystem size for %s node %s\n",
1033 myrpt->p.archivedir,myrpt->name);
1034 return(-1);
1036 return(statfsbuf.f_bavail);
1039 static void do_dtmf_phone(struct rpt *myrpt, struct rpt_link *mylink, char c)
1041 struct rpt_link *l;
1043 l = myrpt->links.next;
1044 /* go thru all the links */
1045 while(l != &myrpt->links)
1047 if (!l->phonemode)
1049 l = l->next;
1050 continue;
1052 /* dont send to self */
1053 if (mylink && (l == mylink))
1055 l = l->next;
1056 continue;
1058 if (l->chan) ast_senddigit(l->chan,c);
1059 l = l->next;
1061 return;
1064 /* node logging function */
1065 static void donodelog(struct rpt *myrpt,char *str)
1067 struct nodelog *nodep;
1068 char datestr[100];
1070 if (!myrpt->p.archivedir) return;
1071 nodep = (struct nodelog *)malloc(sizeof(struct nodelog));
1072 if (nodep == NULL)
1074 ast_log(LOG_ERROR,"Cannot get memory for node log");
1075 return;
1077 time(&nodep->timestamp);
1078 strncpy(nodep->archivedir,myrpt->p.archivedir,
1079 sizeof(nodep->archivedir) - 1);
1080 strftime(datestr,sizeof(datestr) - 1,"%Y%m%d%H%M%S",
1081 localtime(&nodep->timestamp));
1082 snprintf(nodep->str,sizeof(nodep->str) - 1,"%s %s,%s\n",
1083 myrpt->name,datestr,str);
1084 ast_mutex_lock(&nodeloglock);
1085 insque((struct qelem *) nodep, (struct qelem *) nodelog.prev);
1086 ast_mutex_unlock(&nodeloglock);
1089 /* must be called locked */
1090 static void do_dtmf_local(struct rpt *myrpt, char c)
1092 int i;
1093 char digit;
1094 static const char* dtmf_tones[] = {
1095 "!941+1336/200,!0/200", /* 0 */
1096 "!697+1209/200,!0/200", /* 1 */
1097 "!697+1336/200,!0/200", /* 2 */
1098 "!697+1477/200,!0/200", /* 3 */
1099 "!770+1209/200,!0/200", /* 4 */
1100 "!770+1336/200,!0/200", /* 5 */
1101 "!770+1477/200,!0/200", /* 6 */
1102 "!852+1209/200,!0/200", /* 7 */
1103 "!852+1336/200,!0/200", /* 8 */
1104 "!852+1477/200,!0/200", /* 9 */
1105 "!697+1633/200,!0/200", /* A */
1106 "!770+1633/200,!0/200", /* B */
1107 "!852+1633/200,!0/200", /* C */
1108 "!941+1633/200,!0/200", /* D */
1109 "!941+1209/200,!0/200", /* * */
1110 "!941+1477/200,!0/200" }; /* # */
1113 if (c)
1115 snprintf(myrpt->dtmf_local_str + strlen(myrpt->dtmf_local_str),sizeof(myrpt->dtmf_local_str) - 1,"%c",c);
1116 if (!myrpt->dtmf_local_timer)
1117 myrpt->dtmf_local_timer = DTMF_LOCAL_STARTTIME;
1119 /* if at timeout */
1120 if (myrpt->dtmf_local_timer == 1)
1122 /* if anything in the string */
1123 if (myrpt->dtmf_local_str[0])
1125 digit = myrpt->dtmf_local_str[0];
1126 myrpt->dtmf_local_str[0] = 0;
1127 for(i = 1; myrpt->dtmf_local_str[i]; i++)
1129 myrpt->dtmf_local_str[i - 1] =
1130 myrpt->dtmf_local_str[i];
1132 myrpt->dtmf_local_str[i - 1] = 0;
1133 myrpt->dtmf_local_timer = DTMF_LOCAL_TIME;
1134 rpt_mutex_unlock(&myrpt->lock);
1135 if (digit >= '0' && digit <='9')
1136 ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'0'], 0);
1137 else if (digit >= 'A' && digit <= 'D')
1138 ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'A'+10], 0);
1139 else if (digit == '*')
1140 ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[14], 0);
1141 else if (digit == '#')
1142 ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[15], 0);
1143 else {
1144 /* not handled */
1145 ast_log(LOG_DEBUG, "Unable to generate DTMF tone '%c' for '%s'\n", digit, myrpt->txchannel->name);
1147 rpt_mutex_lock(&myrpt->lock);
1149 else
1151 myrpt->dtmf_local_timer = 0;
1156 static int openserial(char *fname)
1158 struct termios mode;
1159 int fd;
1161 fd = open(fname,O_RDWR);
1162 if (fd == -1)
1164 ast_log(LOG_WARNING,"Cannot open serial port %s\n",fname);
1165 return -1;
1167 memset(&mode, 0, sizeof(mode));
1168 if (tcgetattr(fd, &mode)) {
1169 ast_log(LOG_WARNING, "Unable to get serial parameters on %s: %s\n", fname, strerror(errno));
1170 return -1;
1172 #ifndef SOLARIS
1173 cfmakeraw(&mode);
1174 #else
1175 mode.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
1176 |INLCR|IGNCR|ICRNL|IXON);
1177 mode.c_oflag &= ~OPOST;
1178 mode.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
1179 mode.c_cflag &= ~(CSIZE|PARENB|CRTSCTS);
1180 mode.c_cflag |= CS8;
1181 mode.c_cc[TIME] = 3;
1182 mode.c_cc[MAX] = 1;
1183 #endif
1185 cfsetispeed(&mode, B9600);
1186 cfsetospeed(&mode, B9600);
1187 if (tcsetattr(fd, TCSANOW, &mode))
1188 ast_log(LOG_WARNING, "Unable to set serial parameters on %s: %s\n", fname, strerror(errno));
1189 return(fd);
1192 static void mdc1200_notify(struct rpt *myrpt,char *fromnode, unsigned int unit)
1194 if (!fromnode)
1196 ast_verbose("Got MDC-1200 ID %04X from local system (%s)\n",
1197 unit,myrpt->name);
1199 else
1201 ast_verbose("Got MDC-1200 ID %04X from node %s (%s)\n",
1202 unit,fromnode,myrpt->name);
1206 #ifdef _MDC_DECODE_H_
1208 static void mdc1200_send(struct rpt *myrpt, unsigned int unit)
1210 struct rpt_link *l;
1211 struct ast_frame wf;
1212 char str[200];
1215 sprintf(str,"I %s %04X",myrpt->name,unit);
1217 wf.frametype = AST_FRAME_TEXT;
1218 wf.subclass = 0;
1219 wf.offset = 0;
1220 wf.mallocd = 0;
1221 wf.datalen = strlen(str) + 1;
1222 wf.samples = 0;
1225 l = myrpt->links.next;
1226 /* otherwise, send it to all of em */
1227 while(l != &myrpt->links)
1229 if (l->name[0] == '0')
1231 l = l->next;
1232 continue;
1234 wf.data = str;
1235 if (l->chan) ast_write(l->chan,&wf);
1236 l = l->next;
1238 return;
1241 #endif
1243 static char func_xlat(struct rpt *myrpt,char c,struct rpt_xlat *xlat)
1245 time_t now;
1246 int gotone;
1248 time(&now);
1249 gotone = 0;
1250 /* if too much time, reset the skate machine */
1251 if ((now - xlat->lastone) > MAXXLATTIME)
1253 xlat->funcindex = xlat->endindex = 0;
1255 if (xlat->funccharseq[0] && (c == xlat->funccharseq[xlat->funcindex++]))
1257 time(&xlat->lastone);
1258 gotone = 1;
1259 if (!xlat->funccharseq[xlat->funcindex])
1261 xlat->funcindex = xlat->endindex = 0;
1262 return(myrpt->p.funcchar);
1264 } else xlat->funcindex = 0;
1265 if (xlat->endcharseq[0] && (c == xlat->endcharseq[xlat->endindex++]))
1267 time(&xlat->lastone);
1268 gotone = 1;
1269 if (!xlat->endcharseq[xlat->endindex])
1271 xlat->funcindex = xlat->endindex = 0;
1272 return(myrpt->p.endchar);
1274 } else xlat->endindex = 0;
1275 /* if in middle of decode seq, send nothing back */
1276 if (gotone) return(0);
1277 /* if no pass chars specified, return em all */
1278 if (!xlat->passchars[0]) return(c);
1279 /* if a "pass char", pass it */
1280 if (strchr(xlat->passchars,c)) return(c);
1281 return(0);
1285 * Return a pointer to the first non-whitespace character
1288 static char *eatwhite(char *s)
1290 while((*s == ' ') || (*s == 0x09)){ /* get rid of any leading white space */
1291 if(!*s)
1292 break;
1293 s++;
1295 return s;
1299 * Break up a delimited string into a table of substrings
1301 * str - delimited string ( will be modified )
1302 * strp- list of pointers to substrings (this is built by this function), NULL will be placed at end of list
1303 * limit- maximum number of substrings to process
1308 static int finddelim(char *str, char *strp[], int limit)
1310 int i,l,inquo;
1312 inquo = 0;
1313 i = 0;
1314 strp[i++] = str;
1315 if (!*str)
1317 strp[0] = 0;
1318 return(0);
1320 for(l = 0; *str && (l < limit) ; str++)
1322 if (*str == QUOTECHR)
1324 if (inquo)
1326 *str = 0;
1327 inquo = 0;
1329 else
1331 strp[i - 1] = str + 1;
1332 inquo = 1;
1335 if ((*str == DELIMCHR) && (!inquo))
1337 *str = 0;
1338 l++;
1339 strp[i++] = str + 1;
1342 strp[i] = 0;
1343 return(i);
1347 /* must be called locked */
1348 static void __mklinklist(struct rpt *myrpt, struct rpt_link *mylink, char *buf)
1350 struct rpt_link *l;
1351 char mode;
1352 int i,spos;
1354 buf[0] = 0; /* clear output buffer */
1355 /* go thru all links */
1356 for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
1358 /* if is not a real link, ignore it */
1359 if (l->name[0] == '0') continue;
1360 /* dont count our stuff */
1361 if (l == mylink) continue;
1362 if (mylink && (!strcmp(l->name,mylink->name))) continue;
1363 /* figure out mode to report */
1364 mode = 'T'; /* use Tranceive by default */
1365 if (!l->mode) mode = 'R'; /* indicate RX for our mode */
1366 if (!l->thisconnected) mode = 'C'; /* indicate connecting */
1367 spos = strlen(buf); /* current buf size (b4 we add our stuff) */
1368 if (spos)
1370 strcat(buf,",");
1371 spos++;
1373 /* add nodes into buffer */
1374 if (l->linklist[0])
1376 snprintf(buf + spos,MAXLINKLIST - spos,
1377 "%c%s,%s",mode,l->name,l->linklist);
1379 else /* if no nodes, add this node into buffer */
1381 snprintf(buf + spos,MAXLINKLIST - spos,
1382 "%c%s",mode,l->name);
1384 /* if we are in tranceive mode, let all modes stand */
1385 if (mode == 'T') continue;
1386 /* downgrade everyone on this node if appropriate */
1387 for(i = spos; buf[i]; i++)
1389 if (buf[i] == 'T') buf[i] = mode;
1390 if ((buf[i] == 'R') && (mode == 'C')) buf[i] = mode;
1393 return;
1396 /* must be called locked */
1397 static void __kickshort(struct rpt *myrpt)
1399 struct rpt_link *l;
1401 for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
1403 /* if is not a real link, ignore it */
1404 if (l->name[0] == '0') continue;
1405 l->linklisttimer = LINKLISTSHORTTIME;
1407 return;
1410 static char *node_lookup(struct rpt *myrpt,char *digitbuf)
1413 char *val;
1414 int longestnode,j;
1415 struct stat mystat;
1416 static time_t last = 0;
1417 static struct ast_config *ourcfg = NULL;
1418 struct ast_variable *vp;
1420 /* try to look it up locally first */
1421 val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
1422 if (val) return(val);
1423 ast_mutex_lock(&nodelookuplock);
1424 /* if file does not exist */
1425 if (stat(myrpt->p.extnodefile,&mystat) == -1)
1427 if (ourcfg) ast_config_destroy(ourcfg);
1428 ourcfg = NULL;
1429 ast_mutex_unlock(&nodelookuplock);
1430 return(NULL);
1432 /* if we need to reload */
1433 if (mystat.st_mtime > last)
1435 if (ourcfg) ast_config_destroy(ourcfg);
1436 ourcfg = ast_config_load(myrpt->p.extnodefile);
1437 /* if file not there, just bail */
1438 if (!ourcfg)
1440 ast_mutex_unlock(&nodelookuplock);
1441 return(NULL);
1443 /* reset "last" time */
1444 last = mystat.st_mtime;
1446 /* determine longest node length again */
1447 longestnode = 0;
1448 vp = ast_variable_browse(myrpt->cfg, myrpt->p.nodes);
1449 while(vp){
1450 j = strlen(vp->name);
1451 if (j > longestnode)
1452 longestnode = j;
1453 vp = vp->next;
1456 vp = ast_variable_browse(ourcfg, myrpt->p.extnodes);
1457 while(vp){
1458 j = strlen(vp->name);
1459 if (j > longestnode)
1460 longestnode = j;
1461 vp = vp->next;
1464 myrpt->longestnode = longestnode;
1466 val = NULL;
1467 if (ourcfg)
1468 val = (char *) ast_variable_retrieve(ourcfg, myrpt->p.extnodes, digitbuf);
1469 ast_mutex_unlock(&nodelookuplock);
1470 return(val);
1474 * Match a keyword in a list, and return index of string plus 1 if there was a match,* else return 0.
1475 * If param is passed in non-null, then it will be set to the first character past the match
1478 static int matchkeyword(char *string, char **param, char *keywords[])
1480 int i,ls;
1481 for( i = 0 ; keywords[i] ; i++){
1482 ls = strlen(keywords[i]);
1483 if(!ls){
1484 *param = NULL;
1485 return 0;
1487 if(!strncmp(string, keywords[i], ls)){
1488 if(param)
1489 *param = string + ls;
1490 return i + 1;
1493 param = NULL;
1494 return 0;
1498 * Skip characters in string which are in charlist, and return a pointer to the
1499 * first non-matching character
1502 static char *skipchars(char *string, char *charlist)
1504 int i;
1505 while(*string){
1506 for(i = 0; charlist[i] ; i++){
1507 if(*string == charlist[i]){
1508 string++;
1509 break;
1512 if(!charlist[i])
1513 return string;
1515 return string;
1520 static int myatoi(char *str)
1522 int ret;
1524 if (str == NULL) return -1;
1525 /* leave this %i alone, non-base-10 input is useful here */
1526 if (sscanf(str,"%i",&ret) != 1) return -1;
1527 return ret;
1530 static int mycompar(const void *a, const void *b)
1532 char **x = (char **) a;
1533 char **y = (char **) b;
1534 int xoff,yoff;
1536 if ((**x < '0') || (**x > '9')) xoff = 1; else xoff = 0;
1537 if ((**y < '0') || (**y > '9')) yoff = 1; else yoff = 0;
1538 return(strcmp((*x) + xoff,(*y) + yoff));
1541 #ifdef __RPT_NOTCH
1543 /* rpt filter routine */
1544 static void rpt_filter(struct rpt *myrpt, volatile short *buf, int len)
1546 int i,j;
1547 struct rptfilter *f;
1549 for(i = 0; i < len; i++)
1551 for(j = 0; j < MAXFILTERS; j++)
1553 f = &myrpt->filters[j];
1554 if (!*f->desc) continue;
1555 f->x0 = f->x1; f->x1 = f->x2;
1556 f->x2 = ((float)buf[i]) / f->gain;
1557 f->y0 = f->y1; f->y1 = f->y2;
1558 f->y2 = (f->x0 + f->x2) + f->const0 * f->x1
1559 + (f->const1 * f->y0) + (f->const2 * f->y1);
1560 buf[i] = (short)f->y2;
1565 #endif
1569 Get the time for the machine's time zone
1570 Note: Asterisk requires a copy of localtime
1571 in the /etc directory for this to work properly.
1572 If /etc/localtime is not present, you will get
1573 GMT time! This is especially important on systems
1574 running embedded linux distributions as they don't usually
1575 have support for locales.
1577 If OLD_ASTERISK is defined, then the older localtime_r
1578 function will be used. The /etc/localtime file is not
1579 required in this case. This provides backward compatibility
1580 with Asterisk 1.2 systems.
1584 static void rpt_localtime( time_t * t, struct tm *lt)
1586 #ifdef OLD_ASTERISK
1587 localtime_r(t, lt);
1588 #else
1589 ast_localtime(t, lt, NULL);
1590 #endif
1593 /* Retrieve an int from a config file */
1595 static int retrieve_astcfgint(struct rpt *myrpt,char *category, char *name, int min, int max, int defl)
1597 char *var;
1598 int ret;
1599 char include_zero = 0;
1601 if(min < 0){ /* If min is negative, this means include 0 as a valid entry */
1602 min = -min;
1603 include_zero = 1;
1606 var = (char *) ast_variable_retrieve(myrpt->cfg, category, name);
1607 if(var){
1608 ret = myatoi(var);
1609 if(include_zero && !ret)
1610 return 0;
1611 if(ret < min)
1612 ret = min;
1613 if(ret > max)
1614 ret = max;
1616 else
1617 ret = defl;
1618 return ret;
1622 static void load_rpt_vars(int n,int init)
1624 char *this,*val;
1625 int i,j,longestnode;
1626 struct ast_variable *vp;
1627 struct ast_config *cfg;
1628 char *strs[100];
1629 char s1[256];
1630 static char *cs_keywords[] = {"rptena","rptdis","apena","apdis","lnkena","lnkdis","totena","totdis","skena","skdis",
1631 "ufena","ufdis","atena","atdis",NULL};
1633 if (option_verbose > 2)
1634 ast_verbose(VERBOSE_PREFIX_3 "%s config for repeater %s\n",
1635 (init) ? "Loading initial" : "Re-Loading",rpt_vars[n].name);
1636 ast_mutex_lock(&rpt_vars[n].lock);
1637 if (rpt_vars[n].cfg) ast_config_destroy(rpt_vars[n].cfg);
1638 cfg = ast_config_load("rpt.conf");
1639 if (!cfg) {
1640 ast_mutex_unlock(&rpt_vars[n].lock);
1641 ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf. Radio Repeater disabled.\n");
1642 pthread_exit(NULL);
1644 rpt_vars[n].cfg = cfg;
1645 this = rpt_vars[n].name;
1646 memset(&rpt_vars[n].p,0,sizeof(rpt_vars[n].p));
1647 if (init)
1649 /* clear all the fields in the structure after 'p' */
1650 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));
1651 rpt_vars[n].tele.next = &rpt_vars[n].tele;
1652 rpt_vars[n].tele.prev = &rpt_vars[n].tele;
1653 rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
1654 rpt_vars[n].tailmessagen = 0;
1656 #ifdef __RPT_NOTCH
1657 /* zot out filters stuff */
1658 memset(&rpt_vars[n].filters,0,sizeof(rpt_vars[n].filters));
1659 #endif
1660 val = (char *) ast_variable_retrieve(cfg,this,"context");
1661 if (val) rpt_vars[n].p.ourcontext = val;
1662 else rpt_vars[n].p.ourcontext = this;
1663 val = (char *) ast_variable_retrieve(cfg,this,"callerid");
1664 if (val) rpt_vars[n].p.ourcallerid = val;
1665 val = (char *) ast_variable_retrieve(cfg,this,"accountcode");
1666 if (val) rpt_vars[n].p.acctcode = val;
1667 val = (char *) ast_variable_retrieve(cfg,this,"idrecording");
1668 if (val) rpt_vars[n].p.ident = val;
1669 val = (char *) ast_variable_retrieve(cfg,this,"hangtime");
1670 if (val) rpt_vars[n].p.hangtime = atoi(val);
1671 else rpt_vars[n].p.hangtime = HANGTIME;
1672 val = (char *) ast_variable_retrieve(cfg,this,"althangtime");
1673 if (val) rpt_vars[n].p.althangtime = atoi(val);
1674 else rpt_vars[n].p.althangtime = HANGTIME;
1675 val = (char *) ast_variable_retrieve(cfg,this,"totime");
1676 if (val) rpt_vars[n].p.totime = atoi(val);
1677 else rpt_vars[n].p.totime = TOTIME;
1678 rpt_vars[n].p.tailmessagetime = retrieve_astcfgint(&rpt_vars[n],this, "tailmessagetime", 0, 2400000, 0);
1679 rpt_vars[n].p.tailsquashedtime = retrieve_astcfgint(&rpt_vars[n],this, "tailsquashedtime", 0, 2400000, 0);
1680 rpt_vars[n].p.duplex = retrieve_astcfgint(&rpt_vars[n],this,"duplex",0,4,2);
1681 rpt_vars[n].p.idtime = retrieve_astcfgint(&rpt_vars[n],this, "idtime", -60000, 2400000, IDTIME); /* Enforce a min max including zero */
1682 rpt_vars[n].p.politeid = retrieve_astcfgint(&rpt_vars[n],this, "politeid", 30000, 300000, POLITEID); /* Enforce a min max */
1683 val = (char *) ast_variable_retrieve(cfg,this,"tonezone");
1684 if (val) rpt_vars[n].p.tonezone = val;
1685 rpt_vars[n].p.tailmessages[0] = 0;
1686 rpt_vars[n].p.tailmessagemax = 0;
1687 val = (char *) ast_variable_retrieve(cfg,this,"tailmessagelist");
1688 if (val) rpt_vars[n].p.tailmessagemax = finddelim(val, rpt_vars[n].p.tailmessages, 500);
1689 val = (char *) ast_variable_retrieve(cfg,this,"memory");
1690 if (!val) val = MEMORY;
1691 rpt_vars[n].p.memory = val;
1692 val = (char *) ast_variable_retrieve(cfg,this,"macro");
1693 if (!val) val = MACRO;
1694 rpt_vars[n].p.macro = val;
1695 val = (char *) ast_variable_retrieve(cfg,this,"startup_macro");
1696 if (val) rpt_vars[n].p.startupmacro = val;
1697 val = (char *) ast_variable_retrieve(cfg,this,"iobase");
1698 /* do not use atoi() here, we need to be able to have
1699 the input specified in hex or decimal so we use
1700 sscanf with a %i */
1701 if ((!val) || (sscanf(val,"%i",&rpt_vars[n].p.iobase) != 1))
1702 rpt_vars[n].p.iobase = DEFAULT_IOBASE;
1703 val = (char *) ast_variable_retrieve(cfg,this,"ioport");
1704 rpt_vars[n].p.ioport = val;
1705 val = (char *) ast_variable_retrieve(cfg,this,"functions");
1706 if (!val)
1708 val = FUNCTIONS;
1709 rpt_vars[n].p.simple = 1;
1711 rpt_vars[n].p.functions = val;
1712 val = (char *) ast_variable_retrieve(cfg,this,"link_functions");
1713 if (val) rpt_vars[n].p.link_functions = val;
1714 else
1715 rpt_vars[n].p.link_functions = rpt_vars[n].p.functions;
1716 val = (char *) ast_variable_retrieve(cfg,this,"phone_functions");
1717 if (val) rpt_vars[n].p.phone_functions = val;
1718 val = (char *) ast_variable_retrieve(cfg,this,"dphone_functions");
1719 if (val) rpt_vars[n].p.dphone_functions = val;
1720 val = (char *) ast_variable_retrieve(cfg,this,"funcchar");
1721 if (!val) rpt_vars[n].p.funcchar = FUNCCHAR; else
1722 rpt_vars[n].p.funcchar = *val;
1723 val = (char *) ast_variable_retrieve(cfg,this,"endchar");
1724 if (!val) rpt_vars[n].p.endchar = ENDCHAR; else
1725 rpt_vars[n].p.endchar = *val;
1726 val = (char *) ast_variable_retrieve(cfg,this,"nobusyout");
1727 if (val) rpt_vars[n].p.nobusyout = ast_true(val);
1728 val = (char *) ast_variable_retrieve(cfg,this,"notelemtx");
1729 if (val) rpt_vars[n].p.notelemtx = ast_true(val);
1730 val = (char *) ast_variable_retrieve(cfg,this,"propagate_dtmf");
1731 if (val) rpt_vars[n].p.propagate_dtmf = ast_true(val);
1732 val = (char *) ast_variable_retrieve(cfg,this,"propagate_phonedtmf");
1733 if (val) rpt_vars[n].p.propagate_phonedtmf = ast_true(val);
1734 val = (char *) ast_variable_retrieve(cfg,this,"linktolink");
1735 if (val) rpt_vars[n].p.linktolink = ast_true(val);
1736 val = (char *) ast_variable_retrieve(cfg,this,"nodes");
1737 if (!val) val = NODES;
1738 rpt_vars[n].p.nodes = val;
1739 val = (char *) ast_variable_retrieve(cfg,this,"extnodes");
1740 if (!val) val = EXTNODES;
1741 rpt_vars[n].p.extnodes = val;
1742 val = (char *) ast_variable_retrieve(cfg,this,"extnodefile");
1743 if (!val) val = EXTNODEFILE;
1744 rpt_vars[n].p.extnodefile = val;
1745 val = (char *) ast_variable_retrieve(cfg,this,"archivedir");
1746 if (val) rpt_vars[n].p.archivedir = val;
1747 val = (char *) ast_variable_retrieve(cfg,this,"authlevel");
1748 if (val) rpt_vars[n].p.authlevel = atoi(val);
1749 else rpt_vars[n].p.authlevel = 0;
1750 val = (char *) ast_variable_retrieve(cfg,this,"monminblocks");
1751 if (val) rpt_vars[n].p.monminblocks = atol(val);
1752 else rpt_vars[n].p.monminblocks = DEFAULT_MONITOR_MIN_DISK_BLOCKS;
1753 val = (char *) ast_variable_retrieve(cfg,this,"remote_inact_timeout");
1754 if (val) rpt_vars[n].p.remoteinacttimeout = atoi(val);
1755 else rpt_vars[n].p.remoteinacttimeout = DEFAULT_REMOTE_INACT_TIMEOUT;
1756 val = (char *) ast_variable_retrieve(cfg,this,"civaddr");
1757 if (val) rpt_vars[n].p.civaddr = atoi(val);
1758 else rpt_vars[n].p.civaddr = DEFAULT_CIV_ADDR;
1759 val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout");
1760 if (val) rpt_vars[n].p.remotetimeout = atoi(val);
1761 else rpt_vars[n].p.remotetimeout = DEFAULT_REMOTE_TIMEOUT;
1762 val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning");
1763 if (val) rpt_vars[n].p.remotetimeoutwarning = atoi(val);
1764 else rpt_vars[n].p.remotetimeoutwarning = DEFAULT_REMOTE_TIMEOUT_WARNING;
1765 val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning_freq");
1766 if (val) rpt_vars[n].p.remotetimeoutwarningfreq = atoi(val);
1767 else rpt_vars[n].p.remotetimeoutwarningfreq = DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ;
1768 #ifdef __RPT_NOTCH
1769 val = (char *) ast_variable_retrieve(cfg,this,"rxnotch");
1770 if (val) {
1771 i = finddelim(val,strs,MAXFILTERS * 2);
1772 i &= ~1; /* force an even number, rounded down */
1773 if (i >= 2) for(j = 0; j < i; j += 2)
1775 rpt_mknotch(atof(strs[j]),atof(strs[j + 1]),
1776 &rpt_vars[n].filters[j >> 1].gain,
1777 &rpt_vars[n].filters[j >> 1].const0,
1778 &rpt_vars[n].filters[j >> 1].const1,
1779 &rpt_vars[n].filters[j >> 1].const2);
1780 sprintf(rpt_vars[n].filters[j >> 1].desc,"%s Hz, BW = %s",
1781 strs[j],strs[j + 1]);
1785 #endif
1786 val = (char *) ast_variable_retrieve(cfg,this,"inxlat");
1787 if (val) {
1788 memset(&rpt_vars[n].p.inxlat,0,sizeof(struct rpt_xlat));
1789 i = finddelim(val,strs,3);
1790 if (i) strncpy(rpt_vars[n].p.inxlat.funccharseq,strs[0],MAXXLAT - 1);
1791 if (i > 1) strncpy(rpt_vars[n].p.inxlat.endcharseq,strs[1],MAXXLAT - 1);
1792 if (i > 2) strncpy(rpt_vars[n].p.inxlat.passchars,strs[2],MAXXLAT - 1);
1794 val = (char *) ast_variable_retrieve(cfg,this,"outxlat");
1795 if (val) {
1796 memset(&rpt_vars[n].p.outxlat,0,sizeof(struct rpt_xlat));
1797 i = finddelim(val,strs,3);
1798 if (i) strncpy(rpt_vars[n].p.outxlat.funccharseq,strs[0],MAXXLAT - 1);
1799 if (i > 1) strncpy(rpt_vars[n].p.outxlat.endcharseq,strs[1],MAXXLAT - 1);
1800 if (i > 2) strncpy(rpt_vars[n].p.outxlat.passchars,strs[2],MAXXLAT - 1);
1802 /* retreive the stanza name for the control states if there is one */
1803 val = (char *) ast_variable_retrieve(cfg,this,"controlstates");
1804 rpt_vars[n].p.csstanzaname = val;
1806 /* retreive the stanza name for the scheduler if there is one */
1807 val = (char *) ast_variable_retrieve(cfg,this,"scheduler");
1808 rpt_vars[n].p.skedstanzaname = val;
1810 /* retreive the stanza name for the txlimits */
1811 val = (char *) ast_variable_retrieve(cfg,this,"txlimits");
1812 rpt_vars[n].p.txlimitsstanzaname = val;
1814 longestnode = 0;
1816 vp = ast_variable_browse(cfg, rpt_vars[n].p.nodes);
1818 while(vp){
1819 j = strlen(vp->name);
1820 if (j > longestnode)
1821 longestnode = j;
1822 vp = vp->next;
1825 rpt_vars[n].longestnode = longestnode;
1828 * For this repeater, Determine the length of the longest function
1830 rpt_vars[n].longestfunc = 0;
1831 vp = ast_variable_browse(cfg, rpt_vars[n].p.functions);
1832 while(vp){
1833 j = strlen(vp->name);
1834 if (j > rpt_vars[n].longestfunc)
1835 rpt_vars[n].longestfunc = j;
1836 vp = vp->next;
1839 * For this repeater, Determine the length of the longest function
1841 rpt_vars[n].link_longestfunc = 0;
1842 vp = ast_variable_browse(cfg, rpt_vars[n].p.link_functions);
1843 while(vp){
1844 j = strlen(vp->name);
1845 if (j > rpt_vars[n].link_longestfunc)
1846 rpt_vars[n].link_longestfunc = j;
1847 vp = vp->next;
1849 rpt_vars[n].phone_longestfunc = 0;
1850 if (rpt_vars[n].p.phone_functions)
1852 vp = ast_variable_browse(cfg, rpt_vars[n].p.phone_functions);
1853 while(vp){
1854 j = strlen(vp->name);
1855 if (j > rpt_vars[n].phone_longestfunc)
1856 rpt_vars[n].phone_longestfunc = j;
1857 vp = vp->next;
1860 rpt_vars[n].dphone_longestfunc = 0;
1861 if (rpt_vars[n].p.dphone_functions)
1863 vp = ast_variable_browse(cfg, rpt_vars[n].p.dphone_functions);
1864 while(vp){
1865 j = strlen(vp->name);
1866 if (j > rpt_vars[n].dphone_longestfunc)
1867 rpt_vars[n].dphone_longestfunc = j;
1868 vp = vp->next;
1871 rpt_vars[n].macro_longest = 1;
1872 vp = ast_variable_browse(cfg, rpt_vars[n].p.macro);
1873 while(vp){
1874 j = strlen(vp->name);
1875 if (j > rpt_vars[n].macro_longest)
1876 rpt_vars[n].macro_longest = j;
1877 vp = vp->next;
1880 /* Browse for control states */
1881 if(rpt_vars[n].p.csstanzaname)
1882 vp = ast_variable_browse(cfg, rpt_vars[n].p.csstanzaname);
1883 else
1884 vp = NULL;
1885 for( i = 0 ; vp && (i < MAX_SYSSTATES) ; i++){ /* Iterate over the number of control state lines in the stanza */
1886 int k,nukw,statenum;
1887 statenum=atoi(vp->name);
1888 strncpy(s1, vp->value, 255);
1889 s1[255] = 0;
1890 nukw = finddelim(s1,strs,32);
1892 for (k = 0 ; k < nukw ; k++){ /* for each user specified keyword */
1893 for(j = 0 ; cs_keywords[j] != NULL ; j++){ /* try to match to one in our internal table */
1894 if(!strcmp(strs[k],cs_keywords[j])){
1895 switch(j){
1896 case 0: /* rptena */
1897 rpt_vars[n].p.s[statenum].txdisable = 0;
1898 break;
1899 case 1: /* rptdis */
1900 rpt_vars[n].p.s[statenum].txdisable = 1;
1901 break;
1903 case 2: /* apena */
1904 rpt_vars[n].p.s[statenum].autopatchdisable = 0;
1905 break;
1907 case 3: /* apdis */
1908 rpt_vars[n].p.s[statenum].autopatchdisable = 1;
1909 break;
1911 case 4: /* lnkena */
1912 rpt_vars[n].p.s[statenum].linkfundisable = 0;
1913 break;
1915 case 5: /* lnkdis */
1916 rpt_vars[n].p.s[statenum].linkfundisable = 1;
1917 break;
1919 case 6: /* totena */
1920 rpt_vars[n].p.s[statenum].totdisable = 0;
1921 break;
1923 case 7: /* totdis */
1924 rpt_vars[n].p.s[statenum].totdisable = 1;
1925 break;
1927 case 8: /* skena */
1928 rpt_vars[n].p.s[statenum].schedulerdisable = 0;
1929 break;
1931 case 9: /* skdis */
1932 rpt_vars[n].p.s[statenum].schedulerdisable = 1;
1933 break;
1935 case 10: /* ufena */
1936 rpt_vars[n].p.s[statenum].userfundisable = 0;
1937 break;
1939 case 11: /* ufdis */
1940 rpt_vars[n].p.s[statenum].userfundisable = 1;
1941 break;
1943 case 12: /* atena */
1944 rpt_vars[n].p.s[statenum].alternatetail = 1;
1945 break;
1947 case 13: /* atdis */
1948 rpt_vars[n].p.s[statenum].alternatetail = 0;
1949 break;
1951 default:
1952 ast_log(LOG_WARNING,
1953 "Unhandled control state keyword %s", cs_keywords[i]);
1954 break;
1959 vp = vp->next;
1961 ast_mutex_unlock(&rpt_vars[n].lock);
1965 * Enable or disable debug output at a given level at the console
1968 static int rpt_do_debug(int fd, int argc, char *argv[])
1970 int newlevel;
1972 if (argc != 4)
1973 return RESULT_SHOWUSAGE;
1974 newlevel = myatoi(argv[3]);
1975 if((newlevel < 0) || (newlevel > 7))
1976 return RESULT_SHOWUSAGE;
1977 if(newlevel)
1978 ast_cli(fd, "app_rpt Debugging enabled, previous level: %d, new level: %d\n", debug, newlevel);
1979 else
1980 ast_cli(fd, "app_rpt Debugging disabled\n");
1982 debug = newlevel;
1983 return RESULT_SUCCESS;
1987 * Dump rpt struct debugging onto console
1990 static int rpt_do_dump(int fd, int argc, char *argv[])
1992 int i;
1994 if (argc != 3)
1995 return RESULT_SHOWUSAGE;
1997 for(i = 0; i < nrpts; i++)
1999 if (!strcmp(argv[2],rpt_vars[i].name))
2001 rpt_vars[i].disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
2002 ast_cli(fd, "app_rpt struct dump requested for node %s\n",argv[2]);
2003 return RESULT_SUCCESS;
2006 return RESULT_FAILURE;
2010 * Dump statistics onto console
2013 static int rpt_do_stats(int fd, int argc, char *argv[])
2015 int i,j;
2016 int dailytxtime, dailykerchunks;
2017 int totalkerchunks, dailykeyups, totalkeyups, timeouts;
2018 int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
2019 long long totaltxtime;
2020 struct rpt_link *l;
2021 char *listoflinks[MAX_STAT_LINKS];
2022 char *lastnodewhichkeyedusup, *lastdtmfcommand;
2023 char *tot_state, *ider_state, *patch_state;
2024 char *reverse_patch_state, *sys_ena, *tot_ena, *link_ena, *patch_ena;
2025 char *sch_ena, *input_signal, *called_number, *user_funs, *tail_type;
2026 struct rpt *myrpt;
2028 static char *not_applicable = "N/A";
2030 if(argc != 3)
2031 return RESULT_SHOWUSAGE;
2033 for(i = 0 ; i < MAX_STAT_LINKS; i++)
2034 listoflinks[i] = NULL;
2036 tot_state = ider_state =
2037 patch_state = reverse_patch_state =
2038 input_signal = called_number =
2039 lastdtmfcommand = not_applicable;
2041 for(i = 0; i < nrpts; i++)
2043 if (!strcmp(argv[2],rpt_vars[i].name)){
2044 /* Make a copy of all stat variables while locked */
2045 myrpt = &rpt_vars[i];
2046 rpt_mutex_lock(&myrpt->lock); /* LOCK */
2048 dailytxtime = myrpt->dailytxtime;
2049 totaltxtime = myrpt->totaltxtime;
2050 dailykeyups = myrpt->dailykeyups;
2051 totalkeyups = myrpt->totalkeyups;
2052 dailykerchunks = myrpt->dailykerchunks;
2053 totalkerchunks = myrpt->totalkerchunks;
2054 dailyexecdcommands = myrpt->dailyexecdcommands;
2055 totalexecdcommands = myrpt->totalexecdcommands;
2056 timeouts = myrpt->timeouts;
2058 /* Traverse the list of connected nodes */
2059 reverse_patch_state = "DOWN";
2060 j = 0;
2061 l = myrpt->links.next;
2062 while(l && (l != &myrpt->links)){
2063 if (l->name[0] == '0'){ /* Skip '0' nodes */
2064 reverse_patch_state = "UP";
2065 l = l->next;
2066 continue;
2068 listoflinks[j] = ast_strdupa(l->name);
2069 if(listoflinks[j])
2070 j++;
2071 l = l->next;
2074 lastnodewhichkeyedusup = ast_strdupa(myrpt->lastnodewhichkeyedusup);
2075 if((!lastnodewhichkeyedusup) || (!strlen(lastnodewhichkeyedusup)))
2076 lastnodewhichkeyedusup = not_applicable;
2078 if(myrpt->keyed)
2079 input_signal = "YES";
2080 else
2081 input_signal = "NO";
2083 if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable)
2084 sys_ena = "DISABLED";
2085 else
2086 sys_ena = "ENABLED";
2088 if(myrpt->p.s[myrpt->p.sysstate_cur].totdisable)
2089 tot_ena = "DISABLED";
2090 else
2091 tot_ena = "ENABLED";
2093 if(myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable)
2094 link_ena = "DISABLED";
2095 else
2096 link_ena = "ENABLED";
2098 if(myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
2099 patch_ena = "DISABLED";
2100 else
2101 patch_ena = "ENABLED";
2103 if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable)
2104 sch_ena = "DISABLED";
2105 else
2106 sch_ena = "ENABLED";
2108 if(myrpt->p.s[myrpt->p.sysstate_cur].userfundisable)
2109 user_funs = "DISABLED";
2110 else
2111 user_funs = "ENABLED";
2113 if(myrpt->p.s[myrpt->p.sysstate_cur].alternatetail)
2114 tail_type = "ALTERNATE";
2115 else
2116 tail_type = "STANDARD";
2118 if(!myrpt->totimer)
2119 tot_state = "TIMED OUT!";
2120 else if(myrpt->totimer != myrpt->p.totime)
2121 tot_state = "ARMED";
2122 else
2123 tot_state = "RESET";
2125 if(myrpt->tailid)
2126 ider_state = "QUEUED IN TAIL";
2127 else if(myrpt->mustid)
2128 ider_state = "QUEUED FOR CLEANUP";
2129 else
2130 ider_state = "CLEAN";
2132 switch(myrpt->callmode){
2133 case 1:
2134 patch_state = "DIALING";
2135 break;
2136 case 2:
2137 patch_state = "CONNECTING";
2138 break;
2139 case 3:
2140 patch_state = "UP";
2141 break;
2143 case 4:
2144 patch_state = "CALL FAILED";
2145 break;
2147 default:
2148 patch_state = "DOWN";
2151 if(strlen(myrpt->exten)){
2152 called_number = ast_strdupa(myrpt->exten);
2153 if(!called_number)
2154 called_number = not_applicable;
2157 if(strlen(myrpt->lastdtmfcommand)){
2158 lastdtmfcommand = ast_strdupa(myrpt->lastdtmfcommand);
2159 if(!lastdtmfcommand)
2160 lastdtmfcommand = not_applicable;
2163 rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
2165 ast_cli(fd, "************************ NODE %s STATISTICS *************************\n\n", myrpt->name);
2166 ast_cli(fd, "Selected system state............................: %d\n", myrpt->p.sysstate_cur);
2167 ast_cli(fd, "Signal on input..................................: %s\n", input_signal);
2168 ast_cli(fd, "System...........................................: %s\n", sys_ena);
2169 ast_cli(fd, "Scheduler........................................: %s\n", sch_ena);
2170 ast_cli(fd, "Tail Time........................................: %s\n", tail_type);
2171 ast_cli(fd, "Time out timer...................................: %s\n", tot_ena);
2172 ast_cli(fd, "Time out timer state.............................: %s\n", tot_state);
2173 ast_cli(fd, "Time outs since system initialization............: %d\n", timeouts);
2174 ast_cli(fd, "Identifier state.................................: %s\n", ider_state);
2175 ast_cli(fd, "Kerchunks today..................................: %d\n", dailykerchunks);
2176 ast_cli(fd, "Kerchunks since system initialization............: %d\n", totalkerchunks);
2177 ast_cli(fd, "Keyups today.....................................: %d\n", dailykeyups);
2178 ast_cli(fd, "Keyups since system initialization...............: %d\n", totalkeyups);
2179 ast_cli(fd, "DTMF commands today..............................: %d\n", dailyexecdcommands);
2180 ast_cli(fd, "DTMF commands since system initialization........: %d\n", totalexecdcommands);
2181 ast_cli(fd, "Last DTMF command executed.......................: %s\n", lastdtmfcommand);
2182 hours = dailytxtime/3600000;
2183 dailytxtime %= 3600000;
2184 minutes = dailytxtime/60000;
2185 dailytxtime %= 60000;
2186 seconds = dailytxtime/1000;
2187 dailytxtime %= 1000;
2189 ast_cli(fd, "TX time today ...................................: %02d:%02d:%02d.%d\n",
2190 hours, minutes, seconds, dailytxtime);
2192 hours = (int) totaltxtime/3600000;
2193 totaltxtime %= 3600000;
2194 minutes = (int) totaltxtime/60000;
2195 totaltxtime %= 60000;
2196 seconds = (int) totaltxtime/1000;
2197 totaltxtime %= 1000;
2199 ast_cli(fd, "TX time since system initialization..............: %02d:%02d:%02d.%d\n",
2200 hours, minutes, seconds, (int) totaltxtime);
2201 ast_cli(fd, "Nodes currently connected to us..................: ");
2202 for(j = 0 ;; j++){
2203 if(!listoflinks[j]){
2204 if(!j){
2205 ast_cli(fd,"<NONE>");
2207 break;
2209 ast_cli(fd, "%s", listoflinks[j]);
2210 if(j % 4 == 3){
2211 ast_cli(fd, "\n");
2212 ast_cli(fd, " : ");
2214 else{
2215 if(listoflinks[j + 1])
2216 ast_cli(fd, ", ");
2219 ast_cli(fd,"\n");
2221 ast_cli(fd, "Last node which transmitted to us................: %s\n", lastnodewhichkeyedusup);
2222 ast_cli(fd, "Autopatch........................................: %s\n", patch_ena);
2223 ast_cli(fd, "Autopatch state..................................: %s\n", patch_state);
2224 ast_cli(fd, "Autopatch called number..........................: %s\n", called_number);
2225 ast_cli(fd, "Reverse patch/IAXRPT connected...................: %s\n", reverse_patch_state);
2226 ast_cli(fd, "User linking commands............................: %s\n", link_ena);
2227 ast_cli(fd, "User functions...................................: %s\n\n", user_funs);
2228 return RESULT_SUCCESS;
2231 return RESULT_FAILURE;
2235 * Link stats function
2238 static int rpt_do_lstats(int fd, int argc, char *argv[])
2240 int i,j;
2241 char *connstate;
2242 struct rpt *myrpt;
2243 struct rpt_link *l;
2244 struct rpt_lstat *s,*t;
2245 struct rpt_lstat s_head;
2246 if(argc != 3)
2247 return RESULT_SHOWUSAGE;
2249 s = NULL;
2250 s_head.next = &s_head;
2251 s_head.prev = &s_head;
2253 for(i = 0; i < nrpts; i++)
2255 if (!strcmp(argv[2],rpt_vars[i].name)){
2256 /* Make a copy of all stat variables while locked */
2257 myrpt = &rpt_vars[i];
2258 rpt_mutex_lock(&myrpt->lock); /* LOCK */
2259 /* Traverse the list of connected nodes */
2260 j = 0;
2261 l = myrpt->links.next;
2262 while(l && (l != &myrpt->links)){
2263 if (l->name[0] == '0'){ /* Skip '0' nodes */
2264 l = l->next;
2265 continue;
2267 if((s = (struct rpt_lstat *) malloc(sizeof(struct rpt_lstat))) == NULL){
2268 ast_log(LOG_ERROR, "Malloc failed in rpt_do_lstats\n");
2269 rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
2270 return RESULT_FAILURE;
2272 memset(s, 0, sizeof(struct rpt_lstat));
2273 strncpy(s->name, l->name, MAXREMSTR - 1);
2274 if (l->chan) pbx_substitute_variables_helper(l->chan, "${IAXPEER(CURRENTCHANNEL)}", s->peer, MAXPEERSTR - 1);
2275 else strcpy(s->peer,"(none)");
2276 s->mode = l->mode;
2277 s->outbound = l->outbound;
2278 s->reconnects = l->reconnects;
2279 s->connecttime = l->connecttime;
2280 s->thisconnected = l->thisconnected;
2281 memcpy(s->chan_stat,l->chan_stat,NRPTSTAT * sizeof(struct rpt_chan_stat));
2282 insque((struct qelem *) s, (struct qelem *) s_head.next);
2283 memset(l->chan_stat,0,NRPTSTAT * sizeof(struct rpt_chan_stat));
2284 l = l->next;
2286 rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
2287 ast_cli(fd, "NODE PEER RECONNECTS DIRECTION CONNECT TIME CONNECT STATE\n");
2288 ast_cli(fd, "---- ---- ---------- --------- ------------ -------------\n");
2290 for(s = s_head.next; s != &s_head; s = s->next){
2291 int hours, minutes, seconds;
2292 long long connecttime = s->connecttime;
2293 char conntime[21];
2294 hours = (int) connecttime/3600000;
2295 connecttime %= 3600000;
2296 minutes = (int) connecttime/60000;
2297 connecttime %= 60000;
2298 seconds = (int) connecttime/1000;
2299 connecttime %= 1000;
2300 snprintf(conntime, 20, "%02d:%02d:%02d.%d",
2301 hours, minutes, seconds, (int) connecttime);
2302 conntime[20] = 0;
2303 if(s->thisconnected)
2304 connstate = "ESTABLISHED";
2305 else
2306 connstate = "CONNECTING";
2307 ast_cli(fd, "%-10s%-20s%-12d%-11s%-20s%-20s\n",
2308 s->name, s->peer, s->reconnects, (s->outbound)? "OUT":"IN", conntime, connstate);
2310 /* destroy our local link queue */
2311 s = s_head.next;
2312 while(s != &s_head){
2313 t = s;
2314 s = s->next;
2315 remque((struct qelem *)t);
2316 free(t);
2318 return RESULT_SUCCESS;
2321 return RESULT_FAILURE;
2325 * List all nodes connected, directly or indirectly
2328 static int rpt_do_nodes(int fd, int argc, char *argv[])
2330 int i,j;
2331 char ns;
2332 char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
2333 struct rpt *myrpt;
2334 if(argc != 3)
2335 return RESULT_SHOWUSAGE;
2337 for(i = 0; i < nrpts; i++)
2339 if (!strcmp(argv[2],rpt_vars[i].name)){
2340 /* Make a copy of all stat variables while locked */
2341 myrpt = &rpt_vars[i];
2342 rpt_mutex_lock(&myrpt->lock); /* LOCK */
2343 __mklinklist(myrpt,NULL,lbuf);
2344 rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
2345 /* parse em */
2346 ns = finddelim(lbuf,strs,MAXLINKLIST);
2347 /* sort em */
2348 if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar);
2349 ast_cli(fd,"\n");
2350 ast_cli(fd, "************************* CONNECTED NODES *************************\n\n");
2351 for(j = 0 ;; j++){
2352 if(!strs[j]){
2353 if(!j){
2354 ast_cli(fd,"<NONE>");
2356 break;
2358 ast_cli(fd, "%s", strs[j]);
2359 if(j % 8 == 7){
2360 ast_cli(fd, "\n");
2362 else{
2363 if(strs[j + 1])
2364 ast_cli(fd, ", ");
2367 ast_cli(fd,"\n\n");
2368 return RESULT_SUCCESS;
2371 return RESULT_FAILURE;
2375 * reload vars
2378 static int rpt_do_reload(int fd, int argc, char *argv[])
2380 int n;
2382 if (argc > 2) return RESULT_SHOWUSAGE;
2384 for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
2386 return RESULT_FAILURE;
2390 * restart app_rpt
2393 static int rpt_do_restart(int fd, int argc, char *argv[])
2395 int i;
2397 if (argc > 2) return RESULT_SHOWUSAGE;
2398 for(i = 0; i < nrpts; i++)
2400 if (rpt_vars[i].rxchannel) ast_softhangup(rpt_vars[i].rxchannel,AST_SOFTHANGUP_DEV);
2402 return RESULT_FAILURE;
2407 * send an app_rpt DTMF function from the CLI
2410 static int rpt_do_fun(int fd, int argc, char *argv[])
2412 int i,busy=0;
2414 if (argc != 4) return RESULT_SHOWUSAGE;
2416 for(i = 0; i < nrpts; i++){
2417 if(!strcmp(argv[2], rpt_vars[i].name)){
2418 struct rpt *myrpt = &rpt_vars[i];
2419 rpt_mutex_lock(&myrpt->lock);
2420 if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(argv[3])){
2421 rpt_mutex_unlock(&myrpt->lock);
2422 busy=1;
2424 if(!busy){
2425 myrpt->macrotimer = MACROTIME;
2426 strncat(myrpt->macrobuf, argv[3], MAXMACRO - strlen(myrpt->macrobuf) - 1);
2428 rpt_mutex_unlock(&myrpt->lock);
2431 if(busy){
2432 ast_cli(fd, "Function decoder busy");
2434 return RESULT_FAILURE;
2439 static int play_tone_pair(struct ast_channel *chan, int f1, int f2, int duration, int amplitude)
2441 int res;
2443 if ((res = ast_tonepair_start(chan, f1, f2, duration, amplitude)))
2444 return res;
2446 while(chan->generatordata) {
2447 if (ast_safe_sleep(chan,1)) return -1;
2450 return 0;
2453 static int play_tone(struct ast_channel *chan, int freq, int duration, int amplitude)
2455 return play_tone_pair(chan, freq, 0, duration, amplitude);
2458 static int play_silence(struct ast_channel *chan, int duration)
2460 return play_tone_pair(chan, 0, 0, duration, 0);
2464 static int send_morse(struct ast_channel *chan, char *string, int speed, int freq, int amplitude)
2467 static struct morse_bits mbits[] = {
2468 {0, 0}, /* SPACE */
2469 {0, 0},
2470 {6, 18},/* " */
2471 {0, 0},
2472 {7, 72},/* $ */
2473 {0, 0},
2474 {0, 0},
2475 {6, 30},/* ' */
2476 {5, 13},/* ( */
2477 {6, 29},/* ) */
2478 {0, 0},
2479 {5, 10},/* + */
2480 {6, 51},/* , */
2481 {6, 33},/* - */
2482 {6, 42},/* . */
2483 {5, 9}, /* / */
2484 {5, 31},/* 0 */
2485 {5, 30},/* 1 */
2486 {5, 28},/* 2 */
2487 {5, 24},/* 3 */
2488 {5, 16},/* 4 */
2489 {5, 0}, /* 5 */
2490 {5, 1}, /* 6 */
2491 {5, 3}, /* 7 */
2492 {5, 7}, /* 8 */
2493 {5, 15},/* 9 */
2494 {6, 7}, /* : */
2495 {6, 21},/* ; */
2496 {0, 0},
2497 {5, 33},/* = */
2498 {0, 0},
2499 {6, 12},/* ? */
2500 {0, 0},
2501 {2, 2}, /* A */
2502 {4, 1}, /* B */
2503 {4, 5}, /* C */
2504 {3, 1}, /* D */
2505 {1, 0}, /* E */
2506 {4, 4}, /* F */
2507 {3, 3}, /* G */
2508 {4, 0}, /* H */
2509 {2, 0}, /* I */
2510 {4, 14},/* J */
2511 {3, 5}, /* K */
2512 {4, 2}, /* L */
2513 {2, 3}, /* M */
2514 {2, 1}, /* N */
2515 {3, 7}, /* O */
2516 {4, 6}, /* P */
2517 {4, 11},/* Q */
2518 {3, 2}, /* R */
2519 {3, 0}, /* S */
2520 {1, 1}, /* T */
2521 {3, 4}, /* U */
2522 {4, 8}, /* V */
2523 {3, 6}, /* W */
2524 {4, 9}, /* X */
2525 {4, 13},/* Y */
2526 {4, 3} /* Z */
2530 int dottime;
2531 int dashtime;
2532 int intralettertime;
2533 int interlettertime;
2534 int interwordtime;
2535 int len, ddcomb;
2536 int res;
2537 int c;
2538 int i;
2539 int flags;
2541 res = 0;
2543 /* Approximate the dot time from the speed arg. */
2545 dottime = 900/speed;
2547 /* Establish timing releationships */
2549 dashtime = 3 * dottime;
2550 intralettertime = dottime;
2551 interlettertime = dottime * 4 ;
2552 interwordtime = dottime * 7;
2554 for(;(*string) && (!res); string++){
2556 c = *string;
2558 /* Convert lower case to upper case */
2560 if((c >= 'a') && (c <= 'z'))
2561 c -= 0x20;
2563 /* Can't deal with any char code greater than Z, skip it */
2565 if(c > 'Z')
2566 continue;
2568 /* If space char, wait the inter word time */
2570 if(c == ' '){
2571 if(!res)
2572 res = play_silence(chan, interwordtime);
2573 continue;
2576 /* Subtract out control char offset to match our table */
2578 c -= 0x20;
2580 /* Get the character data */
2582 len = mbits[c].len;
2583 ddcomb = mbits[c].ddcomb;
2585 /* Send the character */
2587 for(; len ; len--){
2588 if(!res)
2589 res = play_tone(chan, freq, (ddcomb & 1) ? dashtime : dottime, amplitude);
2590 if(!res)
2591 res = play_silence(chan, intralettertime);
2592 ddcomb >>= 1;
2595 /* Wait the interletter time */
2597 if(!res)
2598 res = play_silence(chan, interlettertime - intralettertime);
2601 /* Wait for all the frames to be sent */
2603 if (!res)
2604 res = ast_waitstream(chan, "");
2605 ast_stopstream(chan);
2608 * Wait for the zaptel driver to physically write the tone blocks to the hardware
2611 for(i = 0; i < 20 ; i++){
2612 flags = DAHDI_IOMUX_WRITEEMPTY | ZT_IOMUX_NOWAIT;
2613 res = ioctl(chan->fds[0], DAHDI_IOMUX, &flags);
2614 if(flags & DAHDI_IOMUX_WRITEEMPTY)
2615 break;
2616 if( ast_safe_sleep(chan, 50)){
2617 res = -1;
2618 break;
2623 return res;
2626 static int send_tone_telemetry(struct ast_channel *chan, char *tonestring)
2628 char *stringp;
2629 char *tonesubset;
2630 int f1,f2;
2631 int duration;
2632 int amplitude;
2633 int res;
2634 int i;
2635 int flags;
2637 res = 0;
2639 stringp = ast_strdupa(tonestring);
2641 for(;tonestring;){
2642 tonesubset = strsep(&stringp,")");
2643 if(!tonesubset)
2644 break;
2645 if(sscanf(tonesubset,"(%d,%d,%d,%d", &f1, &f2, &duration, &amplitude) != 4)
2646 break;
2647 res = play_tone_pair(chan, f1, f2, duration, amplitude);
2648 if(res)
2649 break;
2651 if(!res)
2652 res = play_tone_pair(chan, 0, 0, 100, 0); /* This is needed to ensure the last tone segment is timed correctly */
2654 if (!res)
2655 res = ast_waitstream(chan, "");
2656 ast_stopstream(chan);
2659 * Wait for the zaptel driver to physically write the tone blocks to the hardware
2662 for(i = 0; i < 20 ; i++){
2663 flags = DAHDI_IOMUX_WRITEEMPTY | ZT_IOMUX_NOWAIT;
2664 res = ioctl(chan->fds[0], DAHDI_IOMUX, &flags);
2665 if(flags & DAHDI_IOMUX_WRITEEMPTY)
2666 break;
2667 if( ast_safe_sleep(chan, 50)){
2668 res = -1;
2669 break;
2673 return res;
2677 static int sayfile(struct ast_channel *mychannel,char *fname)
2679 int res;
2681 res = ast_streamfile(mychannel, fname, mychannel->language);
2682 if (!res)
2683 res = ast_waitstream(mychannel, "");
2684 else
2685 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2686 ast_stopstream(mychannel);
2687 return res;
2690 static int saycharstr(struct ast_channel *mychannel,char *str)
2692 int res;
2694 res = ast_say_character_str(mychannel,str,NULL,mychannel->language);
2695 if (!res)
2696 res = ast_waitstream(mychannel, "");
2697 else
2698 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2699 ast_stopstream(mychannel);
2700 return res;
2703 static int saynum(struct ast_channel *mychannel, int num)
2705 int res;
2706 res = ast_say_number(mychannel, num, NULL, mychannel->language, NULL);
2707 if(!res)
2708 res = ast_waitstream(mychannel, "");
2709 else
2710 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2711 ast_stopstream(mychannel);
2712 return res;
2716 static int telem_any(struct rpt *myrpt,struct ast_channel *chan, char *entry)
2718 int res;
2719 char c;
2721 static int morsespeed;
2722 static int morsefreq;
2723 static int morseampl;
2724 static int morseidfreq = 0;
2725 static int morseidampl;
2726 static char mcat[] = MORSE;
2728 res = 0;
2730 if(!morseidfreq){ /* Get the morse parameters if not already loaded */
2731 morsespeed = retrieve_astcfgint(myrpt, mcat, "speed", 5, 20, 20);
2732 morsefreq = retrieve_astcfgint(myrpt, mcat, "frequency", 300, 3000, 800);
2733 morseampl = retrieve_astcfgint(myrpt, mcat, "amplitude", 200, 8192, 4096);
2734 morseidampl = retrieve_astcfgint(myrpt, mcat, "idamplitude", 200, 8192, 2048);
2735 morseidfreq = retrieve_astcfgint(myrpt, mcat, "idfrequency", 300, 3000, 330);
2738 /* Is it a file, or a tone sequence? */
2740 if(entry[0] == '|'){
2741 c = entry[1];
2742 if((c >= 'a')&&(c <= 'z'))
2743 c -= 0x20;
2745 switch(c){
2746 case 'I': /* Morse ID */
2747 res = send_morse(chan, entry + 2, morsespeed, morseidfreq, morseidampl);
2748 break;
2750 case 'M': /* Morse Message */
2751 res = send_morse(chan, entry + 2, morsespeed, morsefreq, morseampl);
2752 break;
2754 case 'T': /* Tone sequence */
2755 res = send_tone_telemetry(chan, entry + 2);
2756 break;
2757 default:
2758 res = -1;
2761 else
2762 res = sayfile(chan, entry); /* File */
2763 return res;
2767 * This function looks up a telemetry name in the config file, and does a telemetry response as configured.
2769 * 4 types of telemtry are handled: Morse ID, Morse Message, Tone Sequence, and a File containing a recording.
2772 static int telem_lookup(struct rpt *myrpt,struct ast_channel *chan, char *node, char *name)
2775 int res;
2776 int i;
2777 char *entry;
2778 char *telemetry;
2779 char *telemetry_save;
2781 res = 0;
2782 telemetry_save = NULL;
2783 entry = NULL;
2785 /* Retrieve the section name for telemetry from the node section */
2786 telemetry = (char *) ast_variable_retrieve(myrpt->cfg, node, TELEMETRY);
2787 if(telemetry ){
2788 telemetry_save = ast_strdupa(telemetry);
2789 if(!telemetry_save){
2790 ast_log(LOG_WARNING,"ast_strdupa() failed in telem_lookup()\n");
2791 return res;
2793 entry = (char *) ast_variable_retrieve(myrpt->cfg, telemetry_save, name);
2796 /* Try to look up the telemetry name */
2798 if(!entry){
2799 /* Telemetry name wasn't found in the config file, use the default */
2800 for(i = 0; i < sizeof(tele_defs)/sizeof(struct telem_defaults) ; i++){
2801 if(!strcasecmp(tele_defs[i].name, name))
2802 entry = tele_defs[i].value;
2805 if(entry){
2806 if(strlen(entry))
2807 telem_any(myrpt,chan, entry);
2809 else{
2810 res = -1;
2812 return res;
2816 * Retrieve a wait interval
2819 static int get_wait_interval(struct rpt *myrpt, int type)
2821 int interval;
2822 char *wait_times;
2823 char *wait_times_save;
2825 wait_times_save = NULL;
2826 wait_times = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "wait_times");
2828 if(wait_times){
2829 wait_times_save = ast_strdupa(wait_times);
2830 if(!wait_times_save){
2831 ast_log(LOG_WARNING, "Out of memory in wait_interval()\n");
2832 wait_times = NULL;
2836 switch(type){
2837 case DLY_TELEM:
2838 if(wait_times)
2839 interval = retrieve_astcfgint(myrpt,wait_times_save, "telemwait", 500, 5000, 1000);
2840 else
2841 interval = 1000;
2842 break;
2844 case DLY_ID:
2845 if(wait_times)
2846 interval = retrieve_astcfgint(myrpt,wait_times_save, "idwait",250,5000,500);
2847 else
2848 interval = 500;
2849 break;
2851 case DLY_UNKEY:
2852 if(wait_times)
2853 interval = retrieve_astcfgint(myrpt,wait_times_save, "unkeywait",500,5000,1000);
2854 else
2855 interval = 1000;
2856 break;
2858 case DLY_LINKUNKEY:
2859 if(wait_times)
2860 interval = retrieve_astcfgint(myrpt,wait_times_save, "linkunkeywait",500,5000,1000);
2861 else
2862 interval = 1000;
2863 break;
2865 case DLY_CALLTERM:
2866 if(wait_times)
2867 interval = retrieve_astcfgint(myrpt,wait_times_save, "calltermwait",500,5000,1500);
2868 else
2869 interval = 1500;
2870 break;
2872 case DLY_COMP:
2873 if(wait_times)
2874 interval = retrieve_astcfgint(myrpt,wait_times_save, "compwait",500,5000,200);
2875 else
2876 interval = 200;
2877 break;
2879 default:
2880 return 0;
2882 return interval;
2887 * Wait a configurable interval of time
2891 static void wait_interval(struct rpt *myrpt, int type, struct ast_channel *chan)
2893 int interval;
2894 interval = get_wait_interval(myrpt, type);
2895 if(debug)
2896 ast_log(LOG_NOTICE," Delay interval = %d\n", interval);
2897 if(interval)
2898 ast_safe_sleep(chan,interval);
2899 if(debug)
2900 ast_log(LOG_NOTICE,"Delay complete\n");
2901 return;
2904 static int split_freq(char *mhz, char *decimals, char *freq);
2906 static void *rpt_tele_thread(void *this)
2908 DAHDI_CONFINFO ci; /* conference info */
2909 int res = 0,haslink,hastx,hasremote,imdone = 0, unkeys_queued, x;
2910 struct rpt_tele *mytele = (struct rpt_tele *)this;
2911 struct rpt_tele *tlist;
2912 struct rpt *myrpt;
2913 struct rpt_link *l,*l1,linkbase;
2914 struct ast_channel *mychannel;
2915 int vmajor, vminor, m;
2916 char *p,*ct,*ct_copy,*ident, *nodename,*cp;
2917 time_t t;
2918 struct tm localtm;
2919 char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
2920 int i,ns,rbimode;
2921 char mhz[MAXREMSTR];
2922 char decimals[MAXREMSTR];
2923 struct zt_params par;
2926 /* get a pointer to myrpt */
2927 myrpt = mytele->rpt;
2929 /* Snag copies of a few key myrpt variables */
2930 rpt_mutex_lock(&myrpt->lock);
2931 nodename = ast_strdupa(myrpt->name);
2932 if (myrpt->p.ident) ident = ast_strdupa(myrpt->p.ident);
2933 else ident = "";
2934 rpt_mutex_unlock(&myrpt->lock);
2936 /* allocate a pseudo-channel thru asterisk */
2937 mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
2938 if (!mychannel)
2940 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
2941 rpt_mutex_lock(&myrpt->lock);
2942 remque((struct qelem *)mytele);
2943 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
2944 rpt_mutex_unlock(&myrpt->lock);
2945 free(mytele);
2946 pthread_exit(NULL);
2948 #ifdef AST_CDR_FLAG_POST_DISABLED
2949 ast_set_flag(mychannel->cdr,AST_CDR_FLAG_POST_DISABLED);
2950 #endif
2951 rpt_mutex_lock(&myrpt->lock);
2952 mytele->chan = mychannel;
2953 rpt_mutex_unlock(&myrpt->lock);
2954 /* make a conference for the tx */
2955 ci.chan = 0;
2956 /* If there's an ID queued, or tail message queued, */
2957 /* only connect the ID audio to the local tx conference so */
2958 /* linked systems can't hear it */
2959 ci.confno = (((mytele->mode == ID) || (mytele->mode == IDTALKOVER) || (mytele->mode == UNKEY) ||
2960 (mytele->mode == TAILMSG) || (mytele->mode == LINKUNKEY)) || (mytele->mode == TIMEOUT) ?
2961 myrpt->txconf : myrpt->conf);
2962 ci.confmode = DAHDI_CONF_CONFANN;
2963 /* first put the channel on the conference in announce mode */
2964 if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
2966 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2967 rpt_mutex_lock(&myrpt->lock);
2968 remque((struct qelem *)mytele);
2969 rpt_mutex_unlock(&myrpt->lock);
2970 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
2971 free(mytele);
2972 ast_hangup(mychannel);
2973 pthread_exit(NULL);
2975 ast_stopstream(mychannel);
2976 switch(mytele->mode)
2978 case ID:
2979 case ID1:
2980 /* wait a bit */
2981 wait_interval(myrpt, (mytele->mode == ID) ? DLY_ID : DLY_TELEM,mychannel);
2982 res = telem_any(myrpt,mychannel, ident);
2983 imdone=1;
2984 break;
2986 case TAILMSG:
2987 res = ast_streamfile(mychannel, myrpt->p.tailmessages[myrpt->tailmessagen], mychannel->language);
2988 break;
2990 case IDTALKOVER:
2991 p = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "idtalkover");
2992 if(p)
2993 res = telem_any(myrpt,mychannel, p);
2994 imdone=1;
2995 break;
2997 case PROC:
2998 /* wait a little bit longer */
2999 wait_interval(myrpt, DLY_TELEM, mychannel);
3000 res = telem_lookup(myrpt, mychannel, myrpt->name, "patchup");
3001 if(res < 0){ /* Then default message */
3002 res = ast_streamfile(mychannel, "rpt/callproceeding", mychannel->language);
3004 break;
3005 case TERM:
3006 /* wait a little bit longer */
3007 wait_interval(myrpt, DLY_CALLTERM, mychannel);
3008 res = telem_lookup(myrpt, mychannel, myrpt->name, "patchdown");
3009 if(res < 0){ /* Then default message */
3010 res = ast_streamfile(mychannel, "rpt/callterminated", mychannel->language);
3012 break;
3013 case COMPLETE:
3014 /* wait a little bit */
3015 wait_interval(myrpt, DLY_TELEM, mychannel);
3016 res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
3017 break;
3018 case MACRO_NOTFOUND:
3019 /* wait a little bit */
3020 wait_interval(myrpt, DLY_TELEM, mychannel);
3021 res = ast_streamfile(mychannel, "rpt/macro_notfound", mychannel->language);
3022 break;
3023 case MACRO_BUSY:
3024 /* wait a little bit */
3025 wait_interval(myrpt, DLY_TELEM, mychannel);
3026 res = ast_streamfile(mychannel, "rpt/macro_busy", mychannel->language);
3027 break;
3028 case UNKEY:
3029 if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
3030 imdone = 1;
3031 break;
3035 * Reset the Unkey to CT timer
3038 x = get_wait_interval(myrpt, DLY_UNKEY);
3039 rpt_mutex_lock(&myrpt->lock);
3040 myrpt->unkeytocttimer = x; /* Must be protected as it is changed below */
3041 rpt_mutex_unlock(&myrpt->lock);
3044 * If there's one already queued, don't do another
3047 tlist = myrpt->tele.next;
3048 unkeys_queued = 0;
3049 if (tlist != &myrpt->tele)
3051 rpt_mutex_lock(&myrpt->lock);
3052 while(tlist != &myrpt->tele){
3053 if (tlist->mode == UNKEY) unkeys_queued++;
3054 tlist = tlist->next;
3056 rpt_mutex_unlock(&myrpt->lock);
3058 if( unkeys_queued > 1){
3059 imdone = 1;
3060 break;
3063 /* Wait for the telemetry timer to expire */
3064 /* Periodically check the timer since it can be re-initialized above */
3065 while(myrpt->unkeytocttimer)
3067 int ctint;
3068 if(myrpt->unkeytocttimer > 100)
3069 ctint = 100;
3070 else
3071 ctint = myrpt->unkeytocttimer;
3072 ast_safe_sleep(mychannel, ctint);
3073 rpt_mutex_lock(&myrpt->lock);
3074 if(myrpt->unkeytocttimer < ctint)
3075 myrpt->unkeytocttimer = 0;
3076 else
3077 myrpt->unkeytocttimer -= ctint;
3078 rpt_mutex_unlock(&myrpt->lock);
3082 * Now, the carrier on the rptr rx should be gone.
3083 * If it re-appeared, then forget about sending the CT
3085 if(myrpt->keyed){
3086 imdone = 1;
3087 break;
3090 rpt_mutex_lock(&myrpt->lock); /* Update the kerchunk counters */
3091 myrpt->dailykerchunks++;
3092 myrpt->totalkerchunks++;
3093 rpt_mutex_unlock(&myrpt->lock);
3095 haslink = 0;
3096 hastx = 0;
3097 hasremote = 0;
3098 l = myrpt->links.next;
3099 if (l != &myrpt->links)
3101 rpt_mutex_lock(&myrpt->lock);
3102 while(l != &myrpt->links)
3104 if (l->name[0] == '0')
3106 l = l->next;
3107 continue;
3109 haslink = 1;
3110 if (l->mode) {
3111 hastx++;
3112 if (l->isremote) hasremote++;
3114 l = l->next;
3116 rpt_mutex_unlock(&myrpt->lock);
3118 if (haslink)
3121 res = telem_lookup(myrpt,mychannel, myrpt->name, (!hastx) ? "remotemon" : "remotetx");
3122 if(res)
3123 ast_log(LOG_WARNING, "telem_lookup:remotexx failed on %s\n", mychannel->name);
3126 /* if in remote cmd mode, indicate it */
3127 if (myrpt->cmdnode[0])
3129 ast_safe_sleep(mychannel,200);
3130 res = telem_lookup(myrpt,mychannel, myrpt->name, "cmdmode");
3131 if(res)
3132 ast_log(LOG_WARNING, "telem_lookup:cmdmode failed on %s\n", mychannel->name);
3133 ast_stopstream(mychannel);
3136 else if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "unlinkedct"))){ /* Unlinked Courtesy Tone */
3137 ct_copy = ast_strdupa(ct);
3138 res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
3139 if(res)
3140 ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);
3142 if (hasremote && (!myrpt->cmdnode[0]))
3144 /* set for all to hear */
3145 ci.chan = 0;
3146 ci.confno = myrpt->conf;
3147 ci.confmode = DAHDI_CONF_CONFANN;
3148 /* first put the channel on the conference in announce mode */
3149 if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
3151 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
3152 rpt_mutex_lock(&myrpt->lock);
3153 remque((struct qelem *)mytele);
3154 rpt_mutex_unlock(&myrpt->lock);
3155 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
3156 free(mytele);
3157 ast_hangup(mychannel);
3158 pthread_exit(NULL);
3160 if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "remotect"))){ /* Unlinked Courtesy Tone */
3161 ast_safe_sleep(mychannel,200);
3162 ct_copy = ast_strdupa(ct);
3163 res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
3164 if(res)
3165 ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);
3168 #if defined(_MDC_DECODE_H_) && defined(MDC_SAY_WHEN_DOING_CT)
3169 if (myrpt->lastunit)
3171 char mystr[10];
3173 ast_safe_sleep(mychannel,200);
3174 /* set for all to hear */
3175 ci.chan = 0;
3176 ci.confno = myrpt->txconf;
3177 ci.confmode = DAHDI_CONF_CONFANN;
3178 /* first put the channel on the conference in announce mode */
3179 if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
3181 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
3182 rpt_mutex_lock(&myrpt->lock);
3183 remque((struct qelem *)mytele);
3184 rpt_mutex_unlock(&myrpt->lock);
3185 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
3186 free(mytele);
3187 ast_hangup(mychannel);
3188 pthread_exit(NULL);
3190 sprintf(mystr,"%04x",myrpt->lastunit);
3191 myrpt->lastunit = 0;
3192 ast_say_character_str(mychannel,mystr,NULL,mychannel->language);
3193 break;
3195 #endif
3196 imdone = 1;
3197 break;
3198 case LINKUNKEY:
3199 if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
3200 imdone = 1;
3201 break;
3205 * Reset the Unkey to CT timer
3208 x = get_wait_interval(myrpt, DLY_LINKUNKEY);
3209 mytele->mylink.linkunkeytocttimer = x; /* Must be protected as it is changed below */
3212 * If there's one already queued, don't do another
3215 tlist = myrpt->tele.next;
3216 unkeys_queued = 0;
3217 if (tlist != &myrpt->tele)
3219 rpt_mutex_lock(&myrpt->lock);
3220 while(tlist != &myrpt->tele){
3221 if (tlist->mode == LINKUNKEY) unkeys_queued++;
3222 tlist = tlist->next;
3224 rpt_mutex_unlock(&myrpt->lock);
3226 if( unkeys_queued > 1){
3227 imdone = 1;
3228 break;
3231 /* Wait for the telemetry timer to expire */
3232 /* Periodically check the timer since it can be re-initialized above */
3233 while(mytele->mylink.linkunkeytocttimer)
3235 int ctint;
3236 if(mytele->mylink.linkunkeytocttimer > 100)
3237 ctint = 100;
3238 else
3239 ctint = mytele->mylink.linkunkeytocttimer;
3240 ast_safe_sleep(mychannel, ctint);
3241 rpt_mutex_lock(&myrpt->lock);
3242 if(mytele->mylink.linkunkeytocttimer < ctint)
3243 mytele->mylink.linkunkeytocttimer = 0;
3244 else
3245 mytele->mylink.linkunkeytocttimer -= ctint;
3246 rpt_mutex_unlock(&myrpt->lock);
3249 if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "linkunkeyct"))){ /* Unlinked Courtesy Tone */
3250 ct_copy = ast_strdupa(ct);
3251 res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
3252 if(res)
3253 ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);
3255 imdone = 1;
3256 break;
3257 case REMDISC:
3258 /* wait a little bit */
3259 wait_interval(myrpt, DLY_TELEM, mychannel);
3260 l = myrpt->links.next;
3261 haslink = 0;
3262 /* dont report if a link for this one still on system */
3263 if (l != &myrpt->links)
3265 rpt_mutex_lock(&myrpt->lock);
3266 while(l != &myrpt->links)
3268 if (l->name[0] == '0')
3270 l = l->next;
3271 continue;
3273 if (!strcmp(l->name,mytele->mylink.name))
3275 haslink = 1;
3276 break;
3278 l = l->next;
3280 rpt_mutex_unlock(&myrpt->lock);
3282 if (haslink)
3284 imdone = 1;
3285 break;
3287 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3288 if (!res)
3289 res = ast_waitstream(mychannel, "");
3290 else
3291 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3292 ast_stopstream(mychannel);
3293 ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
3294 res = ast_streamfile(mychannel, ((mytele->mylink.hasconnected) ?
3295 "rpt/remote_disc" : "rpt/remote_busy"), mychannel->language);
3296 break;
3297 case REMALREADY:
3298 /* wait a little bit */
3299 wait_interval(myrpt, DLY_TELEM, mychannel);
3300 res = ast_streamfile(mychannel, "rpt/remote_already", mychannel->language);
3301 break;
3302 case REMNOTFOUND:
3303 /* wait a little bit */
3304 wait_interval(myrpt, DLY_TELEM, mychannel);
3305 res = ast_streamfile(mychannel, "rpt/remote_notfound", mychannel->language);
3306 break;
3307 case REMGO:
3308 /* wait a little bit */
3309 wait_interval(myrpt, DLY_TELEM, mychannel);
3310 res = ast_streamfile(mychannel, "rpt/remote_go", mychannel->language);
3311 break;
3312 case CONNECTED:
3313 /* wait a little bit */
3314 wait_interval(myrpt, DLY_TELEM, mychannel);
3315 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3316 if (!res)
3317 res = ast_waitstream(mychannel, "");
3318 else
3319 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3320 ast_stopstream(mychannel);
3321 ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
3322 res = ast_streamfile(mychannel, "rpt/connected", mychannel->language);
3323 if (!res)
3324 res = ast_waitstream(mychannel, "");
3325 else
3326 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3327 ast_stopstream(mychannel);
3328 res = ast_streamfile(mychannel, "digits/2", mychannel->language);
3329 if (!res)
3330 res = ast_waitstream(mychannel, "");
3331 else
3332 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3333 ast_stopstream(mychannel);
3334 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3335 if (!res)
3336 res = ast_waitstream(mychannel, "");
3337 else
3338 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3339 ast_stopstream(mychannel);
3340 ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
3341 imdone = 1;
3342 break;
3343 case CONNFAIL:
3344 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3345 if (!res)
3346 res = ast_waitstream(mychannel, "");
3347 else
3348 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3349 ast_stopstream(mychannel);
3350 ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
3351 res = ast_streamfile(mychannel, "rpt/connection_failed", mychannel->language);
3352 break;
3353 case MEMNOTFOUND:
3354 /* wait a little bit */
3355 wait_interval(myrpt, DLY_TELEM, mychannel);
3356 res = ast_streamfile(mychannel, "rpt/memory_notfound", mychannel->language);
3357 break;
3358 case SETREMOTE:
3359 ast_mutex_lock(&myrpt->remlock);
3360 res = 0;
3361 if(!strcmp(myrpt->remote, remote_rig_ft897))
3363 res = set_ft897(myrpt);
3365 if(!strcmp(myrpt->remote, remote_rig_ic706))
3367 res = set_ic706(myrpt);
3369 else if(!strcmp(myrpt->remote, remote_rig_rbi))
3371 if (ioperm(myrpt->p.iobase,1,1) == -1)
3373 rpt_mutex_unlock(&myrpt->lock);
3374 ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase);
3375 res = -1;
3377 else res = setrbi(myrpt);
3379 else if(!strcmp(myrpt->remote, remote_rig_kenwood))
3381 res = setkenwood(myrpt);
3382 if (ast_safe_sleep(mychannel,200) == -1)
3384 ast_mutex_unlock(&myrpt->remlock);
3385 res = -1;
3386 break;
3388 i = DAHDI_FLUSH_EVENT;
3389 if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_FLUSH,&i) == -1)
3391 ast_mutex_unlock(&myrpt->remlock);
3392 ast_log(LOG_ERROR,"Cant flush events");
3393 res = -1;
3394 break;
3396 if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_GET_PARAMS,&par) == -1)
3398 ast_mutex_unlock(&myrpt->remlock);
3399 ast_log(LOG_ERROR,"Cant get params");
3400 res = -1;
3401 break;
3403 myrpt->remoterx =
3404 (par.rxisoffhook || (myrpt->tele.next != &myrpt->tele));
3406 ast_mutex_unlock(&myrpt->remlock);
3407 if (!res)
3409 imdone = 1;
3410 break;
3412 /* fall thru to invalid freq */
3413 case INVFREQ:
3414 /* wait a little bit */
3415 wait_interval(myrpt, DLY_TELEM, mychannel);
3416 res = ast_streamfile(mychannel, "rpt/invalid-freq", mychannel->language);
3417 break;
3418 case REMMODE:
3419 cp = 0;
3420 wait_interval(myrpt, DLY_TELEM, mychannel);
3421 switch(myrpt->remmode)
3423 case REM_MODE_FM:
3424 saycharstr(mychannel,"FM");
3425 break;
3426 case REM_MODE_USB:
3427 saycharstr(mychannel,"USB");
3428 break;
3429 case REM_MODE_LSB:
3430 saycharstr(mychannel,"LSB");
3431 break;
3432 case REM_MODE_AM:
3433 saycharstr(mychannel,"AM");
3434 break;
3436 wait_interval(myrpt, DLY_COMP, mychannel);
3437 if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
3438 break;
3439 case LOGINREQ:
3440 wait_interval(myrpt, DLY_TELEM, mychannel);
3441 sayfile(mychannel,"rpt/login");
3442 saycharstr(mychannel,myrpt->name);
3443 break;
3444 case REMLOGIN:
3445 wait_interval(myrpt, DLY_TELEM, mychannel);
3446 saycharstr(mychannel,myrpt->loginuser);
3447 sayfile(mychannel,"rpt/node");
3448 saycharstr(mychannel,myrpt->name);
3449 wait_interval(myrpt, DLY_COMP, mychannel);
3450 if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
3451 break;
3452 case REMXXX:
3453 wait_interval(myrpt, DLY_TELEM, mychannel);
3454 res = 0;
3455 switch(mytele->submode)
3457 case 100: /* RX PL Off */
3458 sayfile(mychannel, "rpt/rxpl");
3459 sayfile(mychannel, "rpt/off");
3460 break;
3461 case 101: /* RX PL On */
3462 sayfile(mychannel, "rpt/rxpl");
3463 sayfile(mychannel, "rpt/on");
3464 break;
3465 case 102: /* TX PL Off */
3466 sayfile(mychannel, "rpt/txpl");
3467 sayfile(mychannel, "rpt/off");
3468 break;
3469 case 103: /* TX PL On */
3470 sayfile(mychannel, "rpt/txpl");
3471 sayfile(mychannel, "rpt/on");
3472 break;
3473 case 104: /* Low Power */
3474 sayfile(mychannel, "rpt/lopwr");
3475 break;
3476 case 105: /* Medium Power */
3477 sayfile(mychannel, "rpt/medpwr");
3478 break;
3479 case 106: /* Hi Power */
3480 sayfile(mychannel, "rpt/hipwr");
3481 break;
3482 case 113: /* Scan down slow */
3483 sayfile(mychannel,"rpt/down");
3484 sayfile(mychannel, "rpt/slow");
3485 break;
3486 case 114: /* Scan down quick */
3487 sayfile(mychannel,"rpt/down");
3488 sayfile(mychannel, "rpt/quick");
3489 break;
3490 case 115: /* Scan down fast */
3491 sayfile(mychannel,"rpt/down");
3492 sayfile(mychannel, "rpt/fast");
3493 break;
3494 case 116: /* Scan up slow */
3495 sayfile(mychannel,"rpt/up");
3496 sayfile(mychannel, "rpt/slow");
3497 break;
3498 case 117: /* Scan up quick */
3499 sayfile(mychannel,"rpt/up");
3500 sayfile(mychannel, "rpt/quick");
3501 break;
3502 case 118: /* Scan up fast */
3503 sayfile(mychannel,"rpt/up");
3504 sayfile(mychannel, "rpt/fast");
3505 break;
3506 default:
3507 res = -1;
3509 wait_interval(myrpt, DLY_COMP, mychannel);
3510 if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
3511 break;
3512 case SCAN:
3513 ast_mutex_lock(&myrpt->remlock);
3514 if (myrpt->hfscanstop)
3516 myrpt->hfscanstatus = 0;
3517 myrpt->hfscanmode = 0;
3518 myrpt->hfscanstop = 0;
3519 mytele->mode = SCANSTAT;
3520 ast_mutex_unlock(&myrpt->remlock);
3521 if (ast_safe_sleep(mychannel,1000) == -1) break;
3522 sayfile(mychannel, "rpt/stop");
3523 imdone = 1;
3524 break;
3526 if (myrpt->hfscanstatus > -2) service_scan(myrpt);
3527 i = myrpt->hfscanstatus;
3528 myrpt->hfscanstatus = 0;
3529 if (i) mytele->mode = SCANSTAT;
3530 ast_mutex_unlock(&myrpt->remlock);
3531 if (i < 0) sayfile(mychannel, "rpt/stop");
3532 else if (i > 0) saynum(mychannel,i);
3533 imdone = 1;
3534 break;
3535 case TUNE:
3536 ast_mutex_lock(&myrpt->remlock);
3537 if (!strcmp(myrpt->remote,remote_rig_ic706))
3539 set_mode_ic706(myrpt, REM_MODE_AM);
3540 if(play_tone(mychannel, 800, 6000, 8192) == -1) break;
3541 ast_safe_sleep(mychannel,500);
3542 set_mode_ic706(myrpt, myrpt->remmode);
3543 myrpt->tunerequest = 0;
3544 ast_mutex_unlock(&myrpt->remlock);
3545 imdone = 1;
3546 break;
3548 set_mode_ft897(myrpt, REM_MODE_AM);
3549 simple_command_ft897(myrpt, 8);
3550 if(play_tone(mychannel, 800, 6000, 8192) == -1) break;
3551 simple_command_ft897(myrpt, 0x88);
3552 ast_safe_sleep(mychannel,500);
3553 set_mode_ft897(myrpt, myrpt->remmode);
3554 myrpt->tunerequest = 0;
3555 ast_mutex_unlock(&myrpt->remlock);
3556 imdone = 1;
3557 break;
3558 case REMSHORTSTATUS:
3559 case REMLONGSTATUS:
3560 wait_interval(myrpt, DLY_TELEM, mychannel);
3561 res = sayfile(mychannel,"rpt/node");
3562 if(!res)
3563 res = saycharstr(mychannel, myrpt->name);
3564 if(!res)
3565 res = sayfile(mychannel,"rpt/frequency");
3566 if(!res)
3567 res = split_freq(mhz, decimals, myrpt->freq);
3568 if (!multimode_capable(myrpt)) decimals[3] = 0;
3569 if(!res){
3570 m = atoi(mhz);
3571 if(m < 100)
3572 res = saynum(mychannel, m);
3573 else
3574 res = saycharstr(mychannel, mhz);
3576 if(!res)
3577 res = sayfile(mychannel, "letters/dot");
3578 if(!res)
3579 res = saycharstr(mychannel, decimals);
3581 if(res) break;
3582 if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */
3583 switch(myrpt->offset){
3585 case REM_MINUS:
3586 res = sayfile(mychannel,"rpt/minus");
3587 break;
3589 case REM_SIMPLEX:
3590 res = sayfile(mychannel,"rpt/simplex");
3591 break;
3593 case REM_PLUS:
3594 res = sayfile(mychannel,"rpt/plus");
3595 break;
3597 default:
3598 break;
3601 else{ /* Must be USB, LSB, or AM */
3602 switch(myrpt->remmode){
3604 case REM_MODE_USB:
3605 res = saycharstr(mychannel, "USB");
3606 break;
3608 case REM_MODE_LSB:
3609 res = saycharstr(mychannel, "LSB");
3610 break;
3612 case REM_MODE_AM:
3613 res = saycharstr(mychannel, "AM");
3614 break;
3617 default:
3618 break;
3622 if (res == -1) break;
3624 if(mytele->mode == REMSHORTSTATUS){ /* Short status? */
3625 wait_interval(myrpt, DLY_COMP, mychannel);
3626 if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
3627 break;
3630 if (strcmp(myrpt->remote,remote_rig_ic706))
3632 switch(myrpt->powerlevel){
3634 case REM_LOWPWR:
3635 res = sayfile(mychannel,"rpt/lopwr") ;
3636 break;
3637 case REM_MEDPWR:
3638 res = sayfile(mychannel,"rpt/medpwr");
3639 break;
3640 case REM_HIPWR:
3641 res = sayfile(mychannel,"rpt/hipwr");
3642 break;
3646 rbimode = ((!strncmp(myrpt->remote,remote_rig_rbi,3))
3647 || (!strncmp(myrpt->remote,remote_rig_ic706,3)));
3648 if (res || (sayfile(mychannel,"rpt/rxpl") == -1)) break;
3649 if (rbimode && (sayfile(mychannel,"rpt/txpl") == -1)) break;
3650 if ((sayfile(mychannel,"rpt/frequency") == -1) ||
3651 (saycharstr(mychannel,myrpt->rxpl) == -1)) break;
3652 if ((!rbimode) && ((sayfile(mychannel,"rpt/txpl") == -1) ||
3653 (sayfile(mychannel,"rpt/frequency") == -1) ||
3654 (saycharstr(mychannel,myrpt->txpl) == -1))) break;
3655 if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */
3656 if ((sayfile(mychannel,"rpt/rxpl") == -1) ||
3657 (sayfile(mychannel,((myrpt->rxplon) ? "rpt/on" : "rpt/off")) == -1) ||
3658 (sayfile(mychannel,"rpt/txpl") == -1) ||
3659 (sayfile(mychannel,((myrpt->txplon) ? "rpt/on" : "rpt/off")) == -1))
3661 break;
3664 wait_interval(myrpt, DLY_COMP, mychannel);
3665 if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
3666 break;
3667 case STATUS:
3668 /* wait a little bit */
3669 wait_interval(myrpt, DLY_TELEM, mychannel);
3670 hastx = 0;
3671 linkbase.next = &linkbase;
3672 linkbase.prev = &linkbase;
3673 rpt_mutex_lock(&myrpt->lock);
3674 /* make our own list of links */
3675 l = myrpt->links.next;
3676 while(l != &myrpt->links)
3678 if (l->name[0] == '0')
3680 l = l->next;
3681 continue;
3683 l1 = malloc(sizeof(struct rpt_link));
3684 if (!l1)
3686 ast_log(LOG_WARNING, "Cannot alloc memory on %s\n", mychannel->name);
3687 remque((struct qelem *)mytele);
3688 rpt_mutex_unlock(&myrpt->lock);
3689 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
3690 free(mytele);
3691 ast_hangup(mychannel);
3692 pthread_exit(NULL);
3694 memcpy(l1,l,sizeof(struct rpt_link));
3695 l1->next = l1->prev = NULL;
3696 insque((struct qelem *)l1,(struct qelem *)linkbase.next);
3697 l = l->next;
3699 rpt_mutex_unlock(&myrpt->lock);
3700 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3701 if (!res)
3702 res = ast_waitstream(mychannel, "");
3703 else
3704 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3705 ast_stopstream(mychannel);
3706 ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
3707 if (!res)
3708 res = ast_waitstream(mychannel, "");
3709 else
3710 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3711 ast_stopstream(mychannel);
3712 if (myrpt->callmode)
3714 hastx = 1;
3715 res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
3716 if (!res)
3717 res = ast_waitstream(mychannel, "");
3718 else
3719 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3720 ast_stopstream(mychannel);
3722 l = linkbase.next;
3723 while(l != &linkbase)
3725 char *s;
3727 hastx = 1;
3728 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3729 if (!res)
3730 res = ast_waitstream(mychannel, "");
3731 else
3732 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3733 ast_stopstream(mychannel);
3734 ast_say_character_str(mychannel,l->name,NULL,mychannel->language);
3735 if (!res)
3736 res = ast_waitstream(mychannel, "");
3737 else
3738 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3739 ast_stopstream(mychannel);
3740 s = "rpt/tranceive";
3741 if (!l->mode) s = "rpt/monitor";
3742 if (!l->thisconnected) s = "rpt/connecting";
3743 res = ast_streamfile(mychannel, s, mychannel->language);
3744 if (!res)
3745 res = ast_waitstream(mychannel, "");
3746 else
3747 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3748 ast_stopstream(mychannel);
3749 l = l->next;
3751 if (!hastx)
3753 res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
3754 if (!res)
3755 res = ast_waitstream(mychannel, "");
3756 else
3757 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3758 ast_stopstream(mychannel);
3760 /* destroy our local link queue */
3761 l = linkbase.next;
3762 while(l != &linkbase)
3764 l1 = l;
3765 l = l->next;
3766 remque((struct qelem *)l1);
3767 free(l1);
3769 imdone = 1;
3770 break;
3771 case FULLSTATUS:
3772 rpt_mutex_lock(&myrpt->lock);
3773 /* get all the nodes */
3774 __mklinklist(myrpt,NULL,lbuf);
3775 rpt_mutex_unlock(&myrpt->lock);
3776 /* parse em */
3777 ns = finddelim(lbuf,strs,MAXLINKLIST);
3778 /* sort em */
3779 if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar);
3780 /* wait a little bit */
3781 wait_interval(myrpt, DLY_TELEM, mychannel);
3782 hastx = 0;
3783 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3784 if (!res)
3785 res = ast_waitstream(mychannel, "");
3786 else
3787 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3788 ast_stopstream(mychannel);
3789 ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
3790 if (!res)
3791 res = ast_waitstream(mychannel, "");
3792 else
3793 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3794 ast_stopstream(mychannel);
3795 if (myrpt->callmode)
3797 hastx = 1;
3798 res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
3799 if (!res)
3800 res = ast_waitstream(mychannel, "");
3801 else
3802 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3803 ast_stopstream(mychannel);
3805 /* go thru all the nodes in list */
3806 for(i = 0; i < ns; i++)
3808 char *s,mode = 'T';
3810 /* if a mode spec at first, handle it */
3811 if ((*strs[i] < '0') || (*strs[i] > '9'))
3813 mode = *strs[i];
3814 strs[i]++;
3817 hastx = 1;
3818 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3819 if (!res)
3820 res = ast_waitstream(mychannel, "");
3821 else
3822 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3823 ast_stopstream(mychannel);
3824 ast_say_character_str(mychannel,strs[i],NULL,mychannel->language);
3825 if (!res)
3826 res = ast_waitstream(mychannel, "");
3827 else
3828 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3829 ast_stopstream(mychannel);
3830 s = "rpt/tranceive";
3831 if (mode == 'R') s = "rpt/monitor";
3832 if (mode == 'C') s = "rpt/connecting";
3833 res = ast_streamfile(mychannel, s, mychannel->language);
3834 if (!res)
3835 res = ast_waitstream(mychannel, "");
3836 else
3837 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3838 ast_stopstream(mychannel);
3840 if (!hastx)
3842 res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
3843 if (!res)
3844 res = ast_waitstream(mychannel, "");
3845 else
3846 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3847 ast_stopstream(mychannel);
3849 imdone = 1;
3850 break;
3852 case LASTNODEKEY: /* Identify last node which keyed us up */
3853 rpt_mutex_lock(&myrpt->lock);
3854 if(myrpt->lastnodewhichkeyedusup)
3855 p = ast_strdupa(myrpt->lastnodewhichkeyedusup); /* Make a local copy of the node name */
3856 else
3857 p = NULL;
3858 rpt_mutex_unlock(&myrpt->lock);
3859 if(!p){
3860 imdone = 1; /* no node previously keyed us up, or the node which did has been disconnected */
3861 break;
3863 wait_interval(myrpt, DLY_TELEM, mychannel);
3864 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3865 if (!res)
3866 res = ast_waitstream(mychannel, "");
3867 else
3868 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3869 ast_stopstream(mychannel);
3870 ast_say_character_str(mychannel, p, NULL, mychannel->language);
3871 if (!res)
3872 res = ast_waitstream(mychannel, "");
3873 else
3874 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3875 ast_stopstream(mychannel);
3876 imdone = 1;
3877 break;
3879 case UNAUTHTX: /* Say unauthorized transmit frequency */
3880 wait_interval(myrpt, DLY_TELEM, mychannel);
3881 res = ast_streamfile(mychannel, "rpt/unauthtx", mychannel->language);
3882 if (!res)
3883 res = ast_waitstream(mychannel, "");
3884 else
3885 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3886 ast_stopstream(mychannel);
3887 imdone = 1;
3888 break;
3891 case TIMEOUT:
3892 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3893 if (!res)
3894 res = ast_waitstream(mychannel, "");
3895 else
3896 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3897 ast_stopstream(mychannel);
3898 ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
3899 res = ast_streamfile(mychannel, "rpt/timeout", mychannel->language);
3900 break;
3902 case TIMEOUT_WARNING:
3903 time(&t);
3904 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3905 if (!res)
3906 res = ast_waitstream(mychannel, "");
3907 else
3908 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3909 ast_stopstream(mychannel);
3910 ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
3911 res = ast_streamfile(mychannel, "rpt/timeout-warning", mychannel->language);
3912 if (!res)
3913 res = ast_waitstream(mychannel, "");
3914 else
3915 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3916 ast_stopstream(mychannel);
3917 if(!res) /* Say number of seconds */
3918 ast_say_number(mychannel, myrpt->p.remotetimeout -
3919 (t - myrpt->last_activity_time),
3920 "", mychannel->language, (char *) NULL);
3921 if (!res)
3922 res = ast_waitstream(mychannel, "");
3923 ast_stopstream(mychannel);
3924 res = ast_streamfile(mychannel, "queue-seconds", mychannel->language);
3925 break;
3927 case ACT_TIMEOUT_WARNING:
3928 time(&t);
3929 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3930 if (!res)
3931 res = ast_waitstream(mychannel, "");
3932 else
3933 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3934 ast_stopstream(mychannel);
3935 ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
3936 res = ast_streamfile(mychannel, "rpt/act-timeout-warning", mychannel->language);
3937 if (!res)
3938 res = ast_waitstream(mychannel, "");
3939 else
3940 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3941 ast_stopstream(mychannel);
3942 if(!res) /* Say number of seconds */
3943 ast_say_number(mychannel, myrpt->p.remoteinacttimeout -
3944 (t - myrpt->last_activity_time),
3945 "", mychannel->language, (char *) NULL);
3946 if (!res)
3947 res = ast_waitstream(mychannel, "");
3948 ast_stopstream(mychannel);
3949 res = ast_streamfile(mychannel, "queue-seconds", mychannel->language);
3950 break;
3952 case STATS_TIME:
3953 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
3954 t = time(NULL);
3955 rpt_localtime(&t, &localtm);
3956 /* Say the phase of the day is before the time */
3957 if((localtm.tm_hour >= 0) && (localtm.tm_hour < 12))
3958 p = "rpt/goodmorning";
3959 else if((localtm.tm_hour >= 12) && (localtm.tm_hour < 18))
3960 p = "rpt/goodafternoon";
3961 else
3962 p = "rpt/goodevening";
3963 if (sayfile(mychannel,p) == -1)
3965 imdone = 1;
3966 break;
3968 /* Say the time is ... */
3969 if (sayfile(mychannel,"rpt/thetimeis") == -1)
3971 imdone = 1;
3972 break;
3974 /* Say the time */
3975 res = ast_say_time(mychannel, t, "", mychannel->language);
3976 if (!res)
3977 res = ast_waitstream(mychannel, "");
3978 ast_stopstream(mychannel);
3979 imdone = 1;
3980 break;
3981 case STATS_VERSION:
3982 p = strstr(tdesc, "version");
3983 if(!p)
3984 break;
3985 if(sscanf(p, "version %d.%d", &vmajor, &vminor) != 2)
3986 break;
3987 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
3988 /* Say "version" */
3989 if (sayfile(mychannel,"rpt/version") == -1)
3991 imdone = 1;
3992 break;
3994 if(!res) /* Say "X" */
3995 ast_say_number(mychannel, vmajor, "", mychannel->language, (char *) NULL);
3996 if (!res)
3997 res = ast_waitstream(mychannel, "");
3998 ast_stopstream(mychannel);
3999 if (saycharstr(mychannel,".") == -1)
4001 imdone = 1;
4002 break;
4004 if(!res) /* Say "Y" */
4005 ast_say_number(mychannel, vminor, "", mychannel->language, (char *) NULL);
4006 if (!res){
4007 res = ast_waitstream(mychannel, "");
4008 ast_stopstream(mychannel);
4010 else
4011 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
4012 imdone = 1;
4013 break;
4014 case ARB_ALPHA:
4015 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
4016 if(mytele->param)
4017 saycharstr(mychannel, mytele->param);
4018 imdone = 1;
4019 break;
4020 case REV_PATCH:
4021 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
4022 if(mytele->param) {
4024 /* Parts of this section taken from app_parkandannounce */
4025 char *tpl_working, *tpl_current;
4026 char *tmp[100], *myparm;
4027 int looptemp=0,i=0, dres = 0;
4030 tpl_working = strdupa(mytele->param);
4031 myparm = strsep(&tpl_working,",");
4032 tpl_current=strsep(&tpl_working, ":");
4034 while(tpl_current && looptemp < sizeof(tmp)) {
4035 tmp[looptemp]=tpl_current;
4036 looptemp++;
4037 tpl_current=strsep(&tpl_working,":");
4040 for(i=0; i<looptemp; i++) {
4041 if(!strcmp(tmp[i], "PARKED")) {
4042 ast_say_digits(mychannel, atoi(myparm), "", mychannel->language);
4043 } else if(!strcmp(tmp[i], "NODE")) {
4044 ast_say_digits(mychannel, atoi(myrpt->name), "", mychannel->language);
4045 } else {
4046 dres = ast_streamfile(mychannel, tmp[i], mychannel->language);
4047 if(!dres) {
4048 dres = ast_waitstream(mychannel, "");
4049 } else {
4050 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[i], mychannel->name);
4051 dres = 0;
4056 imdone = 1;
4057 break;
4058 case TEST_TONE:
4059 imdone = 1;
4060 if (myrpt->stopgen) break;
4061 myrpt->stopgen = -1;
4062 if ((res = ast_tonepair_start(mychannel, 1004.0, 0, 99999999, 7200.0)))
4064 myrpt->stopgen = 0;
4065 break;
4067 while(mychannel->generatordata && (myrpt->stopgen <= 0)) {
4068 if (ast_safe_sleep(mychannel,1)) break;
4069 imdone = 1;
4071 myrpt->stopgen = 0;
4072 break;
4073 default:
4074 break;
4076 if (!imdone)
4078 if (!res)
4079 res = ast_waitstream(mychannel, "");
4080 else {
4081 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
4082 res = 0;
4085 ast_stopstream(mychannel);
4086 rpt_mutex_lock(&myrpt->lock);
4087 if (mytele->mode == TAILMSG)
4089 if (!res)
4091 myrpt->tailmessagen++;
4092 if(myrpt->tailmessagen >= myrpt->p.tailmessagemax) myrpt->tailmessagen = 0;
4094 else
4096 myrpt->tmsgtimer = myrpt->p.tailsquashedtime;
4099 remque((struct qelem *)mytele);
4100 rpt_mutex_unlock(&myrpt->lock);
4101 free(mytele);
4102 ast_hangup(mychannel);
4103 #ifdef APP_RPT_LOCK_DEBUG
4105 struct lockthread *t;
4107 sleep(5);
4108 ast_mutex_lock(&locklock);
4109 t = get_lockthread(pthread_self());
4110 if (t) memset(t,0,sizeof(struct lockthread));
4111 ast_mutex_unlock(&locklock);
4113 #endif
4114 pthread_exit(NULL);
4117 static void rpt_telemetry(struct rpt *myrpt,int mode, void *data)
4119 struct rpt_tele *tele;
4120 struct rpt_link *mylink = (struct rpt_link *) data;
4121 int res;
4122 pthread_attr_t attr;
4124 tele = malloc(sizeof(struct rpt_tele));
4125 if (!tele)
4127 ast_log(LOG_WARNING, "Unable to allocate memory\n");
4128 pthread_exit(NULL);
4129 return;
4131 /* zero it out */
4132 memset((char *)tele,0,sizeof(struct rpt_tele));
4133 tele->rpt = myrpt;
4134 tele->mode = mode;
4135 rpt_mutex_lock(&myrpt->lock);
4136 if((mode == CONNFAIL) || (mode == REMDISC) || (mode == CONNECTED) ||
4137 (mode == LINKUNKEY)){
4138 memset(&tele->mylink,0,sizeof(struct rpt_link));
4139 if (mylink){
4140 memcpy(&tele->mylink,mylink,sizeof(struct rpt_link));
4143 else if ((mode == ARB_ALPHA) || (mode == REV_PATCH)) {
4144 strncpy(tele->param, (char *) data, TELEPARAMSIZE - 1);
4145 tele->param[TELEPARAMSIZE - 1] = 0;
4147 if (mode == REMXXX) tele->submode = (int) data;
4148 insque((struct qelem *)tele, (struct qelem *)myrpt->tele.next);
4149 rpt_mutex_unlock(&myrpt->lock);
4150 pthread_attr_init(&attr);
4151 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
4152 res = ast_pthread_create(&tele->threadid,&attr,rpt_tele_thread,(void *) tele);
4153 if(res < 0){
4154 rpt_mutex_lock(&myrpt->lock);
4155 remque((struct qlem *) tele); /* We don't like stuck transmitters, remove it from the queue */
4156 rpt_mutex_unlock(&myrpt->lock);
4157 ast_log(LOG_WARNING, "Could not create telemetry thread: %s",strerror(res));
4159 return;
4162 static void *rpt_call(void *this)
4164 DAHDI_CONFINFO ci; /* conference info */
4165 struct rpt *myrpt = (struct rpt *)this;
4166 int res;
4167 int stopped,congstarted,dialtimer,lastcidx,aborted;
4168 struct ast_channel *mychannel,*genchannel;
4171 myrpt->mydtmf = 0;
4172 /* allocate a pseudo-channel thru asterisk */
4173 mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
4174 if (!mychannel)
4176 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
4177 pthread_exit(NULL);
4179 #ifdef AST_CDR_FLAG_POST_DISABLED
4180 ast_set_flag(mychannel->cdr,AST_CDR_FLAG_POST_DISABLED);
4181 #endif
4182 ci.chan = 0;
4183 ci.confno = myrpt->conf; /* use the pseudo conference */
4184 ci.confmode = DAHDI_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER
4185 | DAHDI_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER;
4186 /* first put the channel on the conference */
4187 if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
4189 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
4190 ast_hangup(mychannel);
4191 myrpt->callmode = 0;
4192 pthread_exit(NULL);
4194 /* allocate a pseudo-channel thru asterisk */
4195 genchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
4196 if (!genchannel)
4198 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
4199 ast_hangup(mychannel);
4200 pthread_exit(NULL);
4202 #ifdef AST_CDR_FLAG_POST_DISABLED
4203 ast_set_flag(genchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
4204 #endif
4205 ci.chan = 0;
4206 ci.confno = myrpt->conf;
4207 ci.confmode = DAHDI_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER
4208 | DAHDI_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER;
4209 /* first put the channel on the conference */
4210 if (ioctl(genchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
4212 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
4213 ast_hangup(mychannel);
4214 ast_hangup(genchannel);
4215 myrpt->callmode = 0;
4216 pthread_exit(NULL);
4218 if (myrpt->p.tonezone && (tone_zone_set_zone(mychannel->fds[0],myrpt->p.tonezone) == -1))
4220 ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
4221 ast_hangup(mychannel);
4222 ast_hangup(genchannel);
4223 myrpt->callmode = 0;
4224 pthread_exit(NULL);
4226 if (myrpt->p.tonezone && (tone_zone_set_zone(genchannel->fds[0],myrpt->p.tonezone) == -1))
4228 ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
4229 ast_hangup(mychannel);
4230 ast_hangup(genchannel);
4231 myrpt->callmode = 0;
4232 pthread_exit(NULL);
4234 /* start dialtone if patchquiet is 0. Special patch modes don't send dial tone */
4235 if ((!myrpt->patchquiet) && (tone_zone_play_tone(mychannel->fds[0],DAHDI_TONE_DIALTONE) < 0))
4237 ast_log(LOG_WARNING, "Cannot start dialtone\n");
4238 ast_hangup(mychannel);
4239 ast_hangup(genchannel);
4240 myrpt->callmode = 0;
4241 pthread_exit(NULL);
4243 stopped = 0;
4244 congstarted = 0;
4245 dialtimer = 0;
4246 lastcidx = 0;
4247 aborted = 0;
4250 while ((myrpt->callmode == 1) || (myrpt->callmode == 4))
4253 if((myrpt->patchdialtime)&&(myrpt->callmode == 1)&&(myrpt->cidx != lastcidx)){
4254 dialtimer = 0;
4255 lastcidx = myrpt->cidx;
4258 if((myrpt->patchdialtime)&&(dialtimer >= myrpt->patchdialtime)){
4259 rpt_mutex_lock(&myrpt->lock);
4260 aborted = 1;
4261 myrpt->callmode = 0;
4262 rpt_mutex_unlock(&myrpt->lock);
4263 break;
4266 if ((!myrpt->patchquiet) && (!stopped) && (myrpt->callmode == 1) && (myrpt->cidx > 0))
4268 stopped = 1;
4269 /* stop dial tone */
4270 tone_zone_play_tone(mychannel->fds[0],-1);
4272 if (myrpt->callmode == 4)
4274 if(!congstarted){
4275 congstarted = 1;
4276 /* start congestion tone */
4277 tone_zone_play_tone(mychannel->fds[0],DAHDI_TONE_CONGESTION);
4280 res = ast_safe_sleep(mychannel, MSWAIT);
4281 if (res < 0)
4283 ast_hangup(mychannel);
4284 ast_hangup(genchannel);
4285 rpt_mutex_lock(&myrpt->lock);
4286 myrpt->callmode = 0;
4287 rpt_mutex_unlock(&myrpt->lock);
4288 pthread_exit(NULL);
4290 dialtimer += MSWAIT;
4292 /* stop any tone generation */
4293 tone_zone_play_tone(mychannel->fds[0],-1);
4294 /* end if done */
4295 if (!myrpt->callmode)
4297 ast_hangup(mychannel);
4298 ast_hangup(genchannel);
4299 rpt_mutex_lock(&myrpt->lock);
4300 myrpt->callmode = 0;
4301 rpt_mutex_unlock(&myrpt->lock);
4302 if((!myrpt->patchquiet) && aborted)
4303 rpt_telemetry(myrpt, TERM, NULL);
4304 pthread_exit(NULL);
4307 if (myrpt->p.ourcallerid && *myrpt->p.ourcallerid){
4308 char *name, *loc, *instr;
4309 instr = strdup(myrpt->p.ourcallerid);
4310 if(instr){
4311 ast_callerid_parse(instr, &name, &loc);
4312 if(loc){
4313 if(mychannel->cid.cid_num)
4314 free(mychannel->cid.cid_num);
4315 mychannel->cid.cid_num = strdup(loc);
4317 if(name){
4318 if(mychannel->cid.cid_name)
4319 free(mychannel->cid.cid_name);
4320 mychannel->cid.cid_name = strdup(name);
4322 free(instr);
4326 ast_copy_string(mychannel->exten, myrpt->exten, sizeof(mychannel->exten) - 1);
4327 ast_copy_string(mychannel->context, myrpt->patchcontext, sizeof(mychannel->context) - 1);
4329 if (myrpt->p.acctcode)
4330 ast_cdr_setaccount(mychannel,myrpt->p.acctcode);
4331 mychannel->priority = 1;
4332 ast_channel_undefer_dtmf(mychannel);
4333 if (ast_pbx_start(mychannel) < 0)
4335 ast_log(LOG_WARNING, "Unable to start PBX!!\n");
4336 ast_hangup(mychannel);
4337 ast_hangup(genchannel);
4338 rpt_mutex_lock(&myrpt->lock);
4339 myrpt->callmode = 0;
4340 rpt_mutex_unlock(&myrpt->lock);
4341 pthread_exit(NULL);
4343 usleep(10000);
4344 rpt_mutex_lock(&myrpt->lock);
4345 myrpt->callmode = 3;
4346 /* set appropriate conference for the pseudo */
4347 ci.chan = 0;
4348 ci.confno = myrpt->conf;
4349 ci.confmode = (myrpt->p.duplex == 2) ? DAHDI_CONF_CONFANNMON :
4350 (DAHDI_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER);
4351 /* first put the channel on the conference in announce mode */
4352 if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
4354 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
4355 ast_hangup(mychannel);
4356 ast_hangup(genchannel);
4357 myrpt->callmode = 0;
4358 pthread_exit(NULL);
4360 while(myrpt->callmode)
4362 if ((!mychannel->pbx) && (myrpt->callmode != 4))
4364 if(myrpt->patchfarenddisconnect){ /* If patch is setup for far end disconnect */
4365 myrpt->callmode = 0;
4366 if(!myrpt->patchquiet){
4367 rpt_mutex_unlock(&myrpt->lock);
4368 rpt_telemetry(myrpt, TERM, NULL);
4369 rpt_mutex_lock(&myrpt->lock);
4372 else{ /* Send congestion until patch is downed by command */
4373 myrpt->callmode = 4;
4374 rpt_mutex_unlock(&myrpt->lock);
4375 /* start congestion tone */
4376 tone_zone_play_tone(genchannel->fds[0],DAHDI_TONE_CONGESTION);
4377 rpt_mutex_lock(&myrpt->lock);
4380 if (myrpt->mydtmf)
4382 struct ast_frame wf = {AST_FRAME_DTMF, } ;
4383 wf.subclass = myrpt->mydtmf;
4384 rpt_mutex_unlock(&myrpt->lock);
4385 ast_queue_frame(mychannel,&wf);
4386 ast_senddigit(genchannel,myrpt->mydtmf);
4387 rpt_mutex_lock(&myrpt->lock);
4388 myrpt->mydtmf = 0;
4390 rpt_mutex_unlock(&myrpt->lock);
4391 usleep(MSWAIT * 1000);
4392 rpt_mutex_lock(&myrpt->lock);
4394 rpt_mutex_unlock(&myrpt->lock);
4395 tone_zone_play_tone(genchannel->fds[0],-1);
4396 if (mychannel->pbx) ast_softhangup(mychannel,AST_SOFTHANGUP_DEV);
4397 ast_hangup(genchannel);
4398 rpt_mutex_lock(&myrpt->lock);
4399 myrpt->callmode = 0;
4400 rpt_mutex_unlock(&myrpt->lock);
4401 /* set appropriate conference for the pseudo */
4402 ci.chan = 0;
4403 ci.confno = myrpt->conf;
4404 ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? DAHDI_CONF_CONFANNMON :
4405 (DAHDI_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER);
4406 /* first put the channel on the conference in announce mode */
4407 if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
4409 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
4411 pthread_exit(NULL);
4414 static void send_link_dtmf(struct rpt *myrpt,char c)
4416 char str[300];
4417 struct ast_frame wf;
4418 struct rpt_link *l;
4420 snprintf(str, sizeof(str), "D %s %s %d %c", myrpt->cmdnode, myrpt->name, ++(myrpt->dtmfidx), c);
4421 wf.frametype = AST_FRAME_TEXT;
4422 wf.subclass = 0;
4423 wf.offset = 0;
4424 wf.mallocd = 0;
4425 wf.datalen = strlen(str) + 1;
4426 wf.samples = 0;
4427 l = myrpt->links.next;
4428 /* first, see if our dude is there */
4429 while(l != &myrpt->links)
4431 if (l->name[0] == '0')
4433 l = l->next;
4434 continue;
4436 /* if we found it, write it and were done */
4437 if (!strcmp(l->name,myrpt->cmdnode))
4439 wf.data = str;
4440 if (l->chan) ast_write(l->chan,&wf);
4441 return;
4443 l = l->next;
4445 l = myrpt->links.next;
4446 /* if not, give it to everyone */
4447 while(l != &myrpt->links)
4449 wf.data = str;
4450 if (l->chan) ast_write(l->chan,&wf);
4451 l = l->next;
4453 return;
4457 * Connect a link
4459 * Return values:
4460 * -1: Error
4461 * 0: Success
4462 * 1: No match yet
4463 * 2: Already connected to this node
4466 static int connect_link(struct rpt *myrpt, char* node, int mode, int perma)
4468 char *val, *s, *s1, *s2, *tele;
4469 char lstr[MAXLINKLIST],*strs[MAXLINKLIST];
4470 char tmp[300], deststr[300] = "",modechange = 0;
4471 struct rpt_link *l;
4472 int reconnects = 0;
4473 int i,n;
4474 DAHDI_CONFINFO ci; /* conference info */
4476 val = node_lookup(myrpt,node);
4477 if (!val){
4478 if(strlen(node) >= myrpt->longestnode)
4479 return -1; /* No such node */
4480 return 1; /* No match yet */
4482 if(debug > 3){
4483 ast_log(LOG_NOTICE,"Connect attempt to node %s\n", node);
4484 ast_log(LOG_NOTICE,"Mode: %s\n",(mode)?"Transceive":"Monitor");
4485 ast_log(LOG_NOTICE,"Connection type: %s\n",(perma)?"Permalink":"Normal");
4488 strncpy(tmp,val,sizeof(tmp) - 1);
4489 s = tmp;
4490 s1 = strsep(&s,",");
4491 s2 = strsep(&s,",");
4492 rpt_mutex_lock(&myrpt->lock);
4493 l = myrpt->links.next;
4494 /* try to find this one in queue */
4495 while(l != &myrpt->links){
4496 if (l->name[0] == '0')
4498 l = l->next;
4499 continue;
4501 /* if found matching string */
4502 if (!strcmp(l->name, node))
4503 break;
4504 l = l->next;
4506 /* if found */
4507 if (l != &myrpt->links){
4508 /* if already in this mode, just ignore */
4509 if ((l->mode) || (!l->chan)) {
4510 rpt_mutex_unlock(&myrpt->lock);
4511 return 2; /* Already linked */
4513 reconnects = l->reconnects;
4514 rpt_mutex_unlock(&myrpt->lock);
4515 if (l->chan) ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
4516 l->retries = l->max_retries + 1;
4517 l->disced = 2;
4518 modechange = 1;
4519 } else
4521 __mklinklist(myrpt,NULL,lstr);
4522 rpt_mutex_unlock(&myrpt->lock);
4523 n = finddelim(lstr,strs,MAXLINKLIST);
4524 for(i = 0; i < n; i++)
4526 if ((*strs[i] < '0') ||
4527 (*strs[i] > '9')) strs[i]++;
4528 if (!strcmp(strs[i],node))
4530 return 2; /* Already linked */
4534 strncpy(myrpt->lastlinknode,node,MAXNODESTR - 1);
4535 /* establish call */
4536 l = malloc(sizeof(struct rpt_link));
4537 if (!l)
4539 ast_log(LOG_WARNING, "Unable to malloc\n");
4540 return -1;
4542 /* zero the silly thing */
4543 memset((char *)l,0,sizeof(struct rpt_link));
4544 l->mode = mode;
4545 l->outbound = 1;
4546 l->thisconnected = 0;
4547 strncpy(l->name, node, MAXNODESTR - 1);
4548 l->isremote = (s && ast_true(s));
4549 if (modechange) l->connected = 1;
4550 l->hasconnected = l->perma = perma;
4551 #ifdef ALLOW_LOCAL_CHANNELS
4552 if ((strncasecmp(s1,"iax2/", 5) == 0) || (strncasecmp(s1, "local/", 6) == 0))
4553 strncpy(deststr, s1, sizeof(deststr));
4554 else
4555 snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
4556 #else
4557 snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
4558 #endif
4559 tele = strchr(deststr, '/');
4560 if (!tele){
4561 ast_log(LOG_WARNING,"link3:Dial number (%s) must be in format tech/number\n",deststr);
4562 free(l);
4563 return -1;
4565 *tele++ = 0;
4566 l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL);
4567 if (l->chan){
4568 ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
4569 ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
4570 #ifdef AST_CDR_FLAG_POST_DISABLED
4571 ast_set_flag(l->chan->cdr,AST_CDR_FLAG_POST_DISABLED);
4572 #endif
4573 l->chan->whentohangup = 0;
4574 l->chan->appl = "Apprpt";
4575 l->chan->data = "(Remote Rx)";
4576 if (debug > 3)
4577 ast_log(LOG_NOTICE, "rpt (remote) initiating call to %s/%s on %s\n",
4578 deststr, tele, l->chan->name);
4579 if(l->chan->cid.cid_num)
4580 free(l->chan->cid.cid_num);
4581 l->chan->cid.cid_num = strdup(myrpt->name);
4582 ast_call(l->chan,tele,999);
4584 else {
4585 if(debug > 3)
4586 ast_log(LOG_NOTICE, "Unable to place call to %s/%s on %s\n",
4587 deststr,tele,l->chan->name);
4588 if (myrpt->p.archivedir)
4590 char str[100];
4591 sprintf(str,"LINKFAIL,%s",l->name);
4592 donodelog(myrpt,str);
4594 free(l);
4595 return -1;
4597 /* allocate a pseudo-channel thru asterisk */
4598 l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
4599 if (!l->pchan){
4600 ast_log(LOG_WARNING,"rpt connect: Sorry unable to obtain pseudo channel\n");
4601 ast_hangup(l->chan);
4602 free(l);
4603 return -1;
4605 ast_set_read_format(l->pchan, AST_FORMAT_SLINEAR);
4606 ast_set_write_format(l->pchan, AST_FORMAT_SLINEAR);
4607 #ifdef AST_CDR_FLAG_POST_DISABLED
4608 ast_set_flag(l->pchan->cdr,AST_CDR_FLAG_POST_DISABLED);
4609 #endif
4610 /* make a conference for the tx */
4611 ci.chan = 0;
4612 ci.confno = myrpt->conf;
4613 ci.confmode = DAHDI_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER;
4614 /* first put the channel on the conference in proper mode */
4615 if (ioctl(l->pchan->fds[0], DAHDI_SETCONF, &ci) == -1)
4617 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
4618 ast_hangup(l->chan);
4619 ast_hangup(l->pchan);
4620 free(l);
4621 return -1;
4623 rpt_mutex_lock(&myrpt->lock);
4624 l->reconnects = reconnects;
4625 /* insert at end of queue */
4626 l->max_retries = MAX_RETRIES;
4627 if (perma)
4628 l->max_retries = MAX_RETRIES_PERM;
4629 if (l->isremote) l->retries = l->max_retries + 1;
4630 insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
4631 __kickshort(myrpt);
4632 rpt_mutex_unlock(&myrpt->lock);
4633 return 0;
4639 * Internet linking function
4642 static int function_ilink(struct rpt *myrpt, char *param, char *digits, int command_source, struct rpt_link *mylink)
4645 char *val, *s, *s1, *s2;
4646 char tmp[300];
4647 char digitbuf[MAXNODESTR],*strs[MAXLINKLIST];
4648 char mode,perma;
4649 struct rpt_link *l;
4650 int i,r;
4652 if(!param)
4653 return DC_ERROR;
4656 if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable )
4657 return DC_ERROR;
4659 strncpy(digitbuf,digits,MAXNODESTR - 1);
4661 if(debug > 6)
4662 printf("@@@@ ilink param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
4664 switch(myatoi(param)){
4665 case 11: /* Perm Link off */
4666 case 1: /* Link off */
4667 if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
4668 strcpy(digitbuf,myrpt->lastlinknode);
4669 val = node_lookup(myrpt,digitbuf);
4670 if (!val){
4671 if(strlen(digitbuf) >= myrpt->longestnode)
4672 return DC_ERROR;
4673 break;
4675 strncpy(tmp,val,sizeof(tmp) - 1);
4676 s = tmp;
4677 s1 = strsep(&s,",");
4678 s2 = strsep(&s,",");
4679 rpt_mutex_lock(&myrpt->lock);
4680 l = myrpt->links.next;
4681 /* try to find this one in queue */
4682 while(l != &myrpt->links){
4683 if (l->name[0] == '0')
4685 l = l->next;
4686 continue;
4688 /* if found matching string */
4689 if (!strcmp(l->name, digitbuf))
4690 break;
4691 l = l->next;
4693 if (l != &myrpt->links){ /* if found */
4694 struct ast_frame wf;
4696 /* must use perm command on perm link */
4697 if ((myatoi(param) < 10) &&
4698 (l->max_retries > MAX_RETRIES))
4700 rpt_mutex_unlock(&myrpt->lock);
4701 return DC_COMPLETE;
4703 strncpy(myrpt->lastlinknode,digitbuf,MAXNODESTR - 1);
4704 l->retries = l->max_retries + 1;
4705 l->disced = 1;
4706 rpt_mutex_unlock(&myrpt->lock);
4707 wf.frametype = AST_FRAME_TEXT;
4708 wf.subclass = 0;
4709 wf.offset = 0;
4710 wf.mallocd = 0;
4711 wf.datalen = strlen(discstr) + 1;
4712 wf.samples = 0;
4713 wf.data = discstr;
4714 if (l->chan)
4716 ast_write(l->chan,&wf);
4717 if (ast_safe_sleep(l->chan,250) == -1) return DC_ERROR;
4718 ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
4720 rpt_telemetry(myrpt, COMPLETE, NULL);
4721 return DC_COMPLETE;
4723 rpt_mutex_unlock(&myrpt->lock);
4724 return DC_COMPLETE;
4725 case 2: /* Link Monitor */
4726 case 3: /* Link transceive */
4727 case 12: /* Link Monitor permanent */
4728 case 13: /* Link transceive permanent */
4729 if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
4730 strcpy(digitbuf,myrpt->lastlinknode);
4731 /* Attempt connection */
4732 perma = (atoi(param) > 10) ? 1 : 0;
4733 mode = (atoi(param) & 1) ? 1 : 0;
4734 r = connect_link(myrpt, digitbuf, mode, perma);
4735 switch(r){
4736 case 0:
4737 rpt_telemetry(myrpt, COMPLETE, NULL);
4738 return DC_COMPLETE;
4740 case 1:
4741 break;
4743 case 2:
4744 rpt_telemetry(myrpt, REMALREADY, NULL);
4745 return DC_COMPLETE;
4747 default:
4748 rpt_telemetry(myrpt, CONNFAIL, NULL);
4749 return DC_COMPLETE;
4751 break;
4753 case 4: /* Enter Command Mode */
4755 /* if doesnt allow link cmd, or no links active, return */
4756 if (((command_source != SOURCE_RPT) &&
4757 (command_source != SOURCE_PHONE) &&
4758 (command_source != SOURCE_DPHONE)) ||
4759 (myrpt->links.next == &myrpt->links))
4760 return DC_COMPLETE;
4762 /* if already in cmd mode, or selected self, fughetabahtit */
4763 if ((myrpt->cmdnode[0]) || (!strcmp(myrpt->name, digitbuf))){
4765 rpt_telemetry(myrpt, REMALREADY, NULL);
4766 return DC_COMPLETE;
4768 if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
4769 strcpy(digitbuf,myrpt->lastlinknode);
4770 /* node must at least exist in list */
4771 val = node_lookup(myrpt,digitbuf);
4772 if (!val){
4773 if(strlen(digitbuf) >= myrpt->longestnode)
4774 return DC_ERROR;
4775 break;
4778 rpt_mutex_lock(&myrpt->lock);
4779 strcpy(myrpt->lastlinknode,digitbuf);
4780 strncpy(myrpt->cmdnode, digitbuf, sizeof(myrpt->cmdnode) - 1);
4781 rpt_mutex_unlock(&myrpt->lock);
4782 rpt_telemetry(myrpt, REMGO, NULL);
4783 return DC_COMPLETE;
4785 case 5: /* Status */
4786 rpt_telemetry(myrpt, STATUS, NULL);
4787 return DC_COMPLETE;
4789 case 15: /* Full Status */
4790 rpt_telemetry(myrpt, FULLSTATUS, NULL);
4791 return DC_COMPLETE;
4794 case 6: /* All Links Off, including permalinks */
4795 rpt_mutex_lock(&myrpt->lock);
4796 myrpt->savednodes[0] = 0;
4797 l = myrpt->links.next;
4798 /* loop through all links */
4799 while(l != &myrpt->links){
4800 struct ast_frame wf;
4801 if (l->name[0] == '0') /* Skip any IAXRPT monitoring */
4803 l = l->next;
4804 continue;
4806 /* Make a string of disconnected nodes for possible restoration */
4807 sprintf(tmp,"%c%c%s",(l->mode) ? 'X' : 'M',(l->perma) ? 'P':'T',l->name);
4808 if(strlen(tmp) + strlen(myrpt->savednodes) + 1 < MAXNODESTR){
4809 if(myrpt->savednodes[0])
4810 strcat(myrpt->savednodes, ",");
4811 strcat(myrpt->savednodes, tmp);
4813 l->retries = l->max_retries + 1;
4814 l->disced = 2; /* Silently disconnect */
4815 rpt_mutex_unlock(&myrpt->lock);
4816 /* ast_log(LOG_NOTICE,"dumping link %s\n",l->name); */
4818 wf.frametype = AST_FRAME_TEXT;
4819 wf.subclass = 0;
4820 wf.offset = 0;
4821 wf.mallocd = 0;
4822 wf.datalen = strlen(discstr) + 1;
4823 wf.samples = 0;
4824 wf.data = discstr;
4825 if (l->chan)
4827 ast_write(l->chan,&wf);
4828 ast_safe_sleep(l->chan,250); /* It's dead already, why check the return value? */
4829 ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
4831 rpt_mutex_lock(&myrpt->lock);
4832 l = l->next;
4834 rpt_mutex_unlock(&myrpt->lock);
4835 if(debug > 3)
4836 ast_log(LOG_NOTICE,"Nodes disconnected: %s\n",myrpt->savednodes);
4837 rpt_telemetry(myrpt, COMPLETE, NULL);
4838 return DC_COMPLETE;
4840 case 7: /* Identify last node which keyed us up */
4841 rpt_telemetry(myrpt, LASTNODEKEY, NULL);
4842 break;
4845 #ifdef _MDC_DECODE_H_
4846 case 8:
4847 myrpt->lastunit = 0xd00d;
4848 mdc1200_notify(myrpt,NULL,myrpt->lastunit);
4849 mdc1200_send(myrpt,myrpt->lastunit);
4850 break;
4851 #endif
4853 case 16: /* Restore links disconnected with "disconnect all links" command */
4854 strcpy(tmp, myrpt->savednodes); /* Make a copy */
4855 finddelim(tmp, strs, MAXLINKLIST); /* convert into substrings */
4856 for(i = 0; tmp[0] && strs[i] != NULL && i < MAXLINKLIST; i++){
4857 s1 = strs[i];
4858 mode = (s1[0] == 'X') ? 1 : 0;
4859 perma = (s1[1] == 'P') ? 1 : 0;
4860 connect_link(myrpt, s1 + 2, mode, perma); /* Try to reconnect */
4862 rpt_telemetry(myrpt, COMPLETE, NULL);
4863 break;
4865 case 200:
4866 case 201:
4867 case 202:
4868 case 203:
4869 case 204:
4870 case 205:
4871 case 206:
4872 case 207:
4873 case 208:
4874 case 209:
4875 case 210:
4876 case 211:
4877 case 212:
4878 case 213:
4879 case 214:
4880 case 215:
4881 if (((myrpt->p.propagate_dtmf) &&
4882 (command_source == SOURCE_LNK)) ||
4883 ((myrpt->p.propagate_phonedtmf) &&
4884 ((command_source == SOURCE_PHONE) ||
4885 (command_source == SOURCE_DPHONE))))
4886 do_dtmf_local(myrpt,
4887 remdtmfstr[myatoi(param) - 200]);
4888 default:
4889 return DC_ERROR;
4893 return DC_INDETERMINATE;
4897 * Autopatch up
4900 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
4902 pthread_attr_t attr;
4903 int i, index, paramlength;
4904 char *lparam;
4905 char *value = NULL;
4906 char *paramlist[20];
4908 static char *keywords[] = {
4909 "context",
4910 "dialtime",
4911 "farenddisconnect",
4912 "noct",
4913 "quiet",
4914 NULL
4917 if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
4918 return DC_ERROR;
4920 if(debug)
4921 printf("@@@@ Autopatch up\n");
4923 if(!myrpt->callmode){
4924 /* Set defaults */
4925 myrpt->patchnoct = 0;
4926 myrpt->patchdialtime = 0;
4927 myrpt->patchfarenddisconnect = 0;
4928 myrpt->patchquiet = 0;
4929 strncpy(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
4931 if(param){
4932 /* Process parameter list */
4933 lparam = ast_strdupa(param);
4934 if(!lparam){
4935 ast_log(LOG_ERROR,"App_rpt out of memory on line %d\n",__LINE__);
4936 return DC_ERROR;
4938 paramlength = finddelim(lparam, paramlist, 20);
4939 for(i = 0; i < paramlength; i++){
4940 index = matchkeyword(paramlist[i], &value, keywords);
4941 if(value)
4942 value = skipchars(value, "= ");
4943 switch(index){
4945 case 1: /* context */
4946 strncpy(myrpt->patchcontext, value, MAXPATCHCONTEXT - 1) ;
4947 break;
4949 case 2: /* dialtime */
4950 myrpt->patchdialtime = atoi(value);
4951 break;
4953 case 3: /* farenddisconnect */
4954 myrpt->patchfarenddisconnect = atoi(value);
4955 break;
4957 case 4: /* noct */
4958 myrpt->patchnoct = atoi(value);
4959 break;
4961 case 5: /* quiet */
4962 myrpt->patchquiet = atoi(value);
4963 break;
4965 default:
4966 break;
4972 rpt_mutex_lock(&myrpt->lock);
4974 /* if on call, force * into current audio stream */
4976 if ((myrpt->callmode == 2) || (myrpt->callmode == 3)){
4977 myrpt->mydtmf = myrpt->p.endchar;
4979 if (myrpt->callmode){
4980 rpt_mutex_unlock(&myrpt->lock);
4981 return DC_COMPLETE;
4983 myrpt->callmode = 1;
4984 myrpt->cidx = 0;
4985 myrpt->exten[myrpt->cidx] = 0;
4986 rpt_mutex_unlock(&myrpt->lock);
4987 pthread_attr_init(&attr);
4988 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
4989 ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *) myrpt);
4990 return DC_COMPLETE;
4994 * Autopatch down
4997 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
4999 if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
5000 return DC_ERROR;
5002 if(debug)
5003 printf("@@@@ Autopatch down\n");
5005 rpt_mutex_lock(&myrpt->lock);
5007 if (!myrpt->callmode){
5008 rpt_mutex_unlock(&myrpt->lock);
5009 return DC_COMPLETE;
5012 myrpt->callmode = 0;
5013 rpt_mutex_unlock(&myrpt->lock);
5014 rpt_telemetry(myrpt, TERM, NULL);
5015 return DC_COMPLETE;
5019 * Status
5022 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
5025 if (!param)
5026 return DC_ERROR;
5028 if ((myrpt->p.s[myrpt->p.sysstate_cur].txdisable) || (myrpt->p.s[myrpt->p.sysstate_cur].userfundisable))
5029 return DC_ERROR;
5031 if(debug)
5032 printf("@@@@ status param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
5034 switch(myatoi(param)){
5035 case 1: /* System ID */
5036 rpt_telemetry(myrpt, ID1, NULL);
5037 return DC_COMPLETE;
5038 case 2: /* System Time */
5039 rpt_telemetry(myrpt, STATS_TIME, NULL);
5040 return DC_COMPLETE;
5041 case 3: /* app_rpt.c version */
5042 rpt_telemetry(myrpt, STATS_VERSION, NULL);
5043 default:
5044 return DC_ERROR;
5046 return DC_INDETERMINATE;
5050 * Macro-oni (without Salami)
5053 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
5056 char *val;
5057 int i;
5058 if (myrpt->remote)
5059 return DC_ERROR;
5061 if(debug)
5062 printf("@@@@ macro-oni param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
5064 if(strlen(digitbuf) < 1) /* needs 1 digit */
5065 return DC_INDETERMINATE;
5067 for(i = 0 ; i < digitbuf[i] ; i++) {
5068 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
5069 return DC_ERROR;
5072 if (*digitbuf == '0') val = myrpt->p.startupmacro;
5073 else val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, digitbuf);
5074 /* param was 1 for local buf */
5075 if (!val){
5076 if (strlen(digitbuf) < myrpt->macro_longest)
5077 return DC_INDETERMINATE;
5078 rpt_telemetry(myrpt, MACRO_NOTFOUND, NULL);
5079 return DC_COMPLETE;
5081 rpt_mutex_lock(&myrpt->lock);
5082 if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val))
5084 rpt_mutex_unlock(&myrpt->lock);
5085 rpt_telemetry(myrpt, MACRO_BUSY, NULL);
5086 return DC_ERROR;
5088 myrpt->macrotimer = MACROTIME;
5089 strncat(myrpt->macrobuf, val, MAXMACRO - strlen(myrpt->macrobuf) - 1);
5090 rpt_mutex_unlock(&myrpt->lock);
5091 return DC_COMPLETE;
5095 * COP - Control operator
5098 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
5100 char string[16];
5102 if(!param)
5103 return DC_ERROR;
5105 switch(myatoi(param)){
5106 case 1: /* System reset */
5107 system("killall -9 asterisk");
5108 return DC_COMPLETE;
5110 case 2:
5111 myrpt->p.s[myrpt->p.sysstate_cur].txdisable = 0;
5112 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "RPTENA");
5113 return DC_COMPLETE;
5115 case 3:
5116 myrpt->p.s[myrpt->p.sysstate_cur].txdisable = 1;
5117 return DC_COMPLETE;
5119 case 4: /* test tone on */
5120 if (myrpt->stopgen < 0)
5122 myrpt->stopgen = 1;
5124 else
5126 myrpt->stopgen = 0;
5127 rpt_telemetry(myrpt, TEST_TONE, NULL);
5129 return DC_COMPLETE;
5131 case 5: /* Disgorge variables to log for debug purposes */
5132 myrpt->disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
5133 return DC_COMPLETE;
5135 case 6: /* Simulate COR being activated (phone only) */
5136 if (command_source != SOURCE_PHONE) return DC_INDETERMINATE;
5137 return DC_DOKEY;
5140 case 7: /* Time out timer enable */
5141 myrpt->p.s[myrpt->p.sysstate_cur].totdisable = 0;
5142 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "TOTENA");
5143 return DC_COMPLETE;
5145 case 8: /* Time out timer disable */
5146 myrpt->p.s[myrpt->p.sysstate_cur].totdisable = 1;
5147 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "TOTDIS");
5148 return DC_COMPLETE;
5150 case 9: /* Autopatch enable */
5151 myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable = 0;
5152 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "APENA");
5153 return DC_COMPLETE;
5155 case 10: /* Autopatch disable */
5156 myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable = 1;
5157 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "APDIS");
5158 return DC_COMPLETE;
5160 case 11: /* Link Enable */
5161 myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable = 0;
5162 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "LNKENA");
5163 return DC_COMPLETE;
5165 case 12: /* Link Disable */
5166 myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable = 1;
5167 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "LNKDIS");
5168 return DC_COMPLETE;
5170 case 13: /* Query System State */
5171 string[0] = string[1] = 'S';
5172 string[2] = myrpt->p.sysstate_cur + '0';
5173 string[3] = '\0';
5174 rpt_telemetry(myrpt, ARB_ALPHA, (void *) string);
5175 return DC_COMPLETE;
5177 case 14: /* Change System State */
5178 if(strlen(digitbuf) == 0)
5179 break;
5180 if((digitbuf[0] < '0') || (digitbuf[0] > '9'))
5181 return DC_ERROR;
5182 myrpt->p.sysstate_cur = digitbuf[0] - '0';
5183 string[0] = string[1] = 'S';
5184 string[2] = myrpt->p.sysstate_cur + '0';
5185 string[3] = '\0';
5186 rpt_telemetry(myrpt, ARB_ALPHA, (void *) string);
5187 return DC_COMPLETE;
5189 case 15: /* Scheduler Enable */
5190 myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable = 0;
5191 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "SKENA");
5192 return DC_COMPLETE;
5194 case 16: /* Scheduler Disable */
5195 myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable = 1;
5196 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "SKDIS");
5197 return DC_COMPLETE;
5199 case 17: /* User functions Enable */
5200 myrpt->p.s[myrpt->p.sysstate_cur].userfundisable = 0;
5201 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "UFENA");
5202 return DC_COMPLETE;
5204 case 18: /* User Functions Disable */
5205 myrpt->p.s[myrpt->p.sysstate_cur].userfundisable = 1;
5206 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "UFDIS");
5207 return DC_COMPLETE;
5209 case 19: /* Alternate Tail Enable */
5210 myrpt->p.s[myrpt->p.sysstate_cur].alternatetail = 1;
5211 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "ATENA");
5212 return DC_COMPLETE;
5214 case 20: /* Alternate Tail Disable */
5215 myrpt->p.s[myrpt->p.sysstate_cur].alternatetail = 0;
5216 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "ATDIS");
5217 return DC_COMPLETE;
5219 return DC_INDETERMINATE;
5223 * Collect digits one by one until something matches
5226 static int collect_function_digits(struct rpt *myrpt, char *digits,
5227 int command_source, struct rpt_link *mylink)
5229 int i;
5230 char *stringp,*action,*param,*functiondigits;
5231 char function_table_name[30] = "";
5232 char workstring[200];
5234 struct ast_variable *vp;
5236 if(debug)
5237 printf("@@@@ Digits collected: %s, source: %d\n", digits, command_source);
5239 if (command_source == SOURCE_DPHONE) {
5240 if (!myrpt->p.dphone_functions) return DC_INDETERMINATE;
5241 strncpy(function_table_name, myrpt->p.dphone_functions, sizeof(function_table_name) - 1);
5243 else if (command_source == SOURCE_PHONE) {
5244 if (!myrpt->p.phone_functions) return DC_INDETERMINATE;
5245 strncpy(function_table_name, myrpt->p.phone_functions, sizeof(function_table_name) - 1);
5247 else if (command_source == SOURCE_LNK)
5248 strncpy(function_table_name, myrpt->p.link_functions, sizeof(function_table_name) - 1);
5249 else
5250 strncpy(function_table_name, myrpt->p.functions, sizeof(function_table_name) - 1);
5251 vp = ast_variable_browse(myrpt->cfg, function_table_name);
5252 while(vp) {
5253 if(!strncasecmp(vp->name, digits, strlen(vp->name)))
5254 break;
5255 vp = vp->next;
5257 if(!vp) {
5258 int n;
5260 n = myrpt->longestfunc;
5261 if (command_source == SOURCE_LNK) n = myrpt->link_longestfunc;
5262 else
5263 if (command_source == SOURCE_PHONE) n = myrpt->phone_longestfunc;
5264 else
5265 if (command_source == SOURCE_DPHONE) n = myrpt->dphone_longestfunc;
5267 if(strlen(digits) >= n)
5268 return DC_ERROR;
5269 else
5270 return DC_INDETERMINATE;
5272 /* Found a match, retrieve value part and parse */
5273 strncpy(workstring, vp->value, sizeof(workstring) - 1 );
5274 stringp = workstring;
5275 action = strsep(&stringp, ",");
5276 param = stringp;
5277 if(debug)
5278 printf("@@@@ action: %s, param = %s\n",action, (param) ? param : "(null)");
5279 /* Look up the action */
5280 for(i = 0 ; i < (sizeof(function_table)/sizeof(struct function_table_tag)); i++){
5281 if(!strncasecmp(action, function_table[i].action, strlen(action)))
5282 break;
5284 if(debug)
5285 printf("@@@@ table index i = %d\n",i);
5286 if(i == (sizeof(function_table)/sizeof(struct function_table_tag))){
5287 /* Error, action not in table */
5288 return DC_ERROR;
5290 if(function_table[i].function == NULL){
5291 /* Error, function undefined */
5292 if(debug)
5293 printf("@@@@ NULL for action: %s\n",action);
5294 return DC_ERROR;
5296 functiondigits = digits + strlen(vp->name);
5297 return (*function_table[i].function)(myrpt, param, functiondigits, command_source, mylink);
5301 static void handle_link_data(struct rpt *myrpt, struct rpt_link *mylink,
5302 char *str)
5304 char tmp[512],cmd[300] = "",dest[300],src[300],c;
5305 int seq, res;
5306 struct rpt_link *l;
5307 struct ast_frame wf;
5309 wf.frametype = AST_FRAME_TEXT;
5310 wf.subclass = 0;
5311 wf.offset = 0;
5312 wf.mallocd = 0;
5313 wf.datalen = strlen(str) + 1;
5314 wf.samples = 0;
5315 /* put string in our buffer */
5316 strncpy(tmp,str,sizeof(tmp) - 1);
5318 if (!strcmp(tmp,discstr))
5320 mylink->disced = 1;
5321 mylink->retries = mylink->max_retries + 1;
5322 ast_softhangup(mylink->chan,AST_SOFTHANGUP_DEV);
5323 return;
5325 if (tmp[0] == 'L')
5327 rpt_mutex_lock(&myrpt->lock);
5328 strcpy(mylink->linklist,tmp + 2);
5329 time(&mylink->linklistreceived);
5330 rpt_mutex_unlock(&myrpt->lock);
5331 if (debug > 6) ast_log(LOG_NOTICE,"@@@@ node %s recieved node list %s from node %s\n",
5332 myrpt->name,tmp,mylink->name);
5333 return;
5335 if (tmp[0] == 'I')
5337 if (sscanf(tmp,"%s %s %x",cmd,src,&seq) != 3)
5339 ast_log(LOG_WARNING, "Unable to parse ident string %s\n",str);
5340 return;
5342 mdc1200_notify(myrpt,src,seq);
5343 strcpy(dest,"*");
5345 else
5347 if (sscanf(tmp,"%s %s %s %d %c",cmd,dest,src,&seq,&c) != 5)
5349 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
5350 return;
5352 if (strcmp(cmd,"D"))
5354 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
5355 return;
5358 if (dest[0] == '0')
5360 strcpy(dest,myrpt->name);
5363 /* if not for me, redistribute to all links */
5364 if (strcmp(dest,myrpt->name))
5366 l = myrpt->links.next;
5367 /* see if this is one in list */
5368 while(l != &myrpt->links)
5370 if (l->name[0] == '0')
5372 l = l->next;
5373 continue;
5375 /* dont send back from where it came */
5376 if ((l == mylink) || (!strcmp(l->name,mylink->name)))
5378 l = l->next;
5379 continue;
5381 /* if it is, send it and we're done */
5382 if (!strcmp(l->name,dest))
5384 /* send, but not to src */
5385 if (strcmp(l->name,src)) {
5386 wf.data = str;
5387 if (l->chan) ast_write(l->chan,&wf);
5389 return;
5391 l = l->next;
5393 l = myrpt->links.next;
5394 /* otherwise, send it to all of em */
5395 while(l != &myrpt->links)
5397 if (l->name[0] == '0')
5399 l = l->next;
5400 continue;
5402 /* dont send back from where it came */
5403 if ((l == mylink) || (!strcmp(l->name,mylink->name)))
5405 l = l->next;
5406 continue;
5408 /* send, but not to src */
5409 if (strcmp(l->name,src)) {
5410 wf.data = str;
5411 if (l->chan) ast_write(l->chan,&wf);
5413 l = l->next;
5415 return;
5417 if (myrpt->p.archivedir)
5419 char str[100];
5421 sprintf(str,"DTMF,%s,%c",mylink->name,c);
5422 donodelog(myrpt,str);
5424 c = func_xlat(myrpt,c,&myrpt->p.outxlat);
5425 if (!c) return;
5426 rpt_mutex_lock(&myrpt->lock);
5427 if (c == myrpt->p.endchar) myrpt->stopgen = 1;
5428 if (myrpt->callmode == 1)
5430 myrpt->exten[myrpt->cidx++] = c;
5431 myrpt->exten[myrpt->cidx] = 0;
5432 /* if this exists */
5433 if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
5435 myrpt->callmode = 2;
5436 if(!myrpt->patchquiet){
5437 rpt_mutex_unlock(&myrpt->lock);
5438 rpt_telemetry(myrpt,PROC,NULL);
5439 rpt_mutex_lock(&myrpt->lock);
5442 /* if can continue, do so */
5443 if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
5445 /* call has failed, inform user */
5446 myrpt->callmode = 4;
5449 if (c == myrpt->p.funcchar)
5451 myrpt->rem_dtmfidx = 0;
5452 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
5453 time(&myrpt->rem_dtmf_time);
5454 rpt_mutex_unlock(&myrpt->lock);
5455 return;
5457 else if (myrpt->rem_dtmfidx < 0)
5459 if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
5461 myrpt->mydtmf = c;
5463 if (myrpt->p.propagate_dtmf) do_dtmf_local(myrpt,c);
5464 if (myrpt->p.propagate_phonedtmf) do_dtmf_phone(myrpt,mylink,c);
5465 rpt_mutex_unlock(&myrpt->lock);
5466 return;
5468 else if ((c != myrpt->p.endchar) && (myrpt->rem_dtmfidx >= 0))
5470 time(&myrpt->rem_dtmf_time);
5471 if (myrpt->rem_dtmfidx < MAXDTMF)
5473 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
5474 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
5476 rpt_mutex_unlock(&myrpt->lock);
5477 strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
5478 res = collect_function_digits(myrpt, cmd, SOURCE_LNK, mylink);
5479 rpt_mutex_lock(&myrpt->lock);
5481 switch(res){
5483 case DC_INDETERMINATE:
5484 break;
5486 case DC_REQ_FLUSH:
5487 myrpt->rem_dtmfidx = 0;
5488 myrpt->rem_dtmfbuf[0] = 0;
5489 break;
5492 case DC_COMPLETE:
5493 case DC_COMPLETEQUIET:
5494 myrpt->totalexecdcommands++;
5495 myrpt->dailyexecdcommands++;
5496 strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
5497 myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
5498 myrpt->rem_dtmfbuf[0] = 0;
5499 myrpt->rem_dtmfidx = -1;
5500 myrpt->rem_dtmf_time = 0;
5501 break;
5503 case DC_ERROR:
5504 default:
5505 myrpt->rem_dtmfbuf[0] = 0;
5506 myrpt->rem_dtmfidx = -1;
5507 myrpt->rem_dtmf_time = 0;
5508 break;
5513 rpt_mutex_unlock(&myrpt->lock);
5514 return;
5517 static void handle_link_phone_dtmf(struct rpt *myrpt, struct rpt_link *mylink,
5518 char c)
5521 char cmd[300];
5522 int res;
5524 if (myrpt->p.archivedir)
5526 char str[100];
5528 sprintf(str,"DTMF(P),%s,%c",mylink->name,c);
5529 donodelog(myrpt,str);
5531 rpt_mutex_lock(&myrpt->lock);
5532 if (c == myrpt->p.endchar)
5534 if (mylink->lastrx)
5536 mylink->lastrx = 0;
5537 rpt_mutex_unlock(&myrpt->lock);
5538 return;
5540 myrpt->stopgen = 1;
5541 if (myrpt->cmdnode[0])
5543 myrpt->cmdnode[0] = 0;
5544 myrpt->dtmfidx = -1;
5545 myrpt->dtmfbuf[0] = 0;
5546 rpt_mutex_unlock(&myrpt->lock);
5547 rpt_telemetry(myrpt,COMPLETE,NULL);
5548 return;
5551 if (myrpt->cmdnode[0])
5553 rpt_mutex_unlock(&myrpt->lock);
5554 send_link_dtmf(myrpt,c);
5555 return;
5557 if (myrpt->callmode == 1)
5559 myrpt->exten[myrpt->cidx++] = c;
5560 myrpt->exten[myrpt->cidx] = 0;
5561 /* if this exists */
5562 if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
5564 myrpt->callmode = 2;
5565 if(!myrpt->patchquiet){
5566 rpt_mutex_unlock(&myrpt->lock);
5567 rpt_telemetry(myrpt,PROC,NULL);
5568 rpt_mutex_lock(&myrpt->lock);
5571 /* if can continue, do so */
5572 if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
5574 /* call has failed, inform user */
5575 myrpt->callmode = 4;
5578 if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
5580 myrpt->mydtmf = c;
5582 if (c == myrpt->p.funcchar)
5584 myrpt->rem_dtmfidx = 0;
5585 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
5586 time(&myrpt->rem_dtmf_time);
5587 rpt_mutex_unlock(&myrpt->lock);
5588 return;
5590 else if ((c != myrpt->p.endchar) && (myrpt->rem_dtmfidx >= 0))
5592 time(&myrpt->rem_dtmf_time);
5593 if (myrpt->rem_dtmfidx < MAXDTMF)
5595 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
5596 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
5598 rpt_mutex_unlock(&myrpt->lock);
5599 strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
5600 switch(mylink->phonemode)
5602 case 1:
5603 res = collect_function_digits(myrpt, cmd,
5604 SOURCE_PHONE, mylink);
5605 break;
5606 case 2:
5607 res = collect_function_digits(myrpt, cmd,
5608 SOURCE_DPHONE,mylink);
5609 break;
5610 default:
5611 res = collect_function_digits(myrpt, cmd,
5612 SOURCE_LNK, mylink);
5613 break;
5616 rpt_mutex_lock(&myrpt->lock);
5618 switch(res){
5620 case DC_INDETERMINATE:
5621 break;
5623 case DC_DOKEY:
5624 mylink->lastrx = 1;
5625 break;
5627 case DC_REQ_FLUSH:
5628 myrpt->rem_dtmfidx = 0;
5629 myrpt->rem_dtmfbuf[0] = 0;
5630 break;
5633 case DC_COMPLETE:
5634 case DC_COMPLETEQUIET:
5635 myrpt->totalexecdcommands++;
5636 myrpt->dailyexecdcommands++;
5637 strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
5638 myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
5639 myrpt->rem_dtmfbuf[0] = 0;
5640 myrpt->rem_dtmfidx = -1;
5641 myrpt->rem_dtmf_time = 0;
5642 break;
5644 case DC_ERROR:
5645 default:
5646 myrpt->rem_dtmfbuf[0] = 0;
5647 myrpt->rem_dtmfidx = -1;
5648 myrpt->rem_dtmf_time = 0;
5649 break;
5654 rpt_mutex_unlock(&myrpt->lock);
5655 return;
5658 /* Doug Hall RBI-1 serial data definitions:
5660 * Byte 0: Expansion external outputs
5661 * Byte 1:
5662 * Bits 0-3 are BAND as follows:
5663 * Bits 4-5 are POWER bits as follows:
5664 * 00 - Low Power
5665 * 01 - Hi Power
5666 * 02 - Med Power
5667 * Bits 6-7 are always set
5668 * Byte 2:
5669 * Bits 0-3 MHZ in BCD format
5670 * Bits 4-5 are offset as follows:
5671 * 00 - minus
5672 * 01 - plus
5673 * 02 - simplex
5674 * 03 - minus minus (whatever that is)
5675 * Bit 6 is the 0/5 KHZ bit
5676 * Bit 7 is always set
5677 * Byte 3:
5678 * Bits 0-3 are 10 KHZ in BCD format
5679 * Bits 4-7 are 100 KHZ in BCD format
5680 * Byte 4: PL Tone code and encode/decode enable bits
5681 * Bits 0-5 are PL tone code (comspec binary codes)
5682 * Bit 6 is encode enable/disable
5683 * Bit 7 is decode enable/disable
5686 /* take the frequency from the 10 mhz digits (and up) and convert it
5687 to a band number */
5689 static int rbi_mhztoband(char *str)
5691 int i;
5693 i = atoi(str) / 10; /* get the 10's of mhz */
5694 switch(i)
5696 case 2:
5697 return 10;
5698 case 5:
5699 return 11;
5700 case 14:
5701 return 2;
5702 case 22:
5703 return 3;
5704 case 44:
5705 return 4;
5706 case 124:
5707 return 0;
5708 case 125:
5709 return 1;
5710 case 126:
5711 return 8;
5712 case 127:
5713 return 5;
5714 case 128:
5715 return 6;
5716 case 129:
5717 return 7;
5718 default:
5719 break;
5721 return -1;
5724 /* take a PL frequency and turn it into a code */
5725 static int rbi_pltocode(char *str)
5727 int i;
5728 char *s;
5730 s = strchr(str,'.');
5731 i = 0;
5732 if (s) i = atoi(s + 1);
5733 i += atoi(str) * 10;
5734 switch(i)
5736 case 670:
5737 return 0;
5738 case 719:
5739 return 1;
5740 case 744:
5741 return 2;
5742 case 770:
5743 return 3;
5744 case 797:
5745 return 4;
5746 case 825:
5747 return 5;
5748 case 854:
5749 return 6;
5750 case 885:
5751 return 7;
5752 case 915:
5753 return 8;
5754 case 948:
5755 return 9;
5756 case 974:
5757 return 10;
5758 case 1000:
5759 return 11;
5760 case 1035:
5761 return 12;
5762 case 1072:
5763 return 13;
5764 case 1109:
5765 return 14;
5766 case 1148:
5767 return 15;
5768 case 1188:
5769 return 16;
5770 case 1230:
5771 return 17;
5772 case 1273:
5773 return 18;
5774 case 1318:
5775 return 19;
5776 case 1365:
5777 return 20;
5778 case 1413:
5779 return 21;
5780 case 1462:
5781 return 22;
5782 case 1514:
5783 return 23;
5784 case 1567:
5785 return 24;
5786 case 1622:
5787 return 25;
5788 case 1679:
5789 return 26;
5790 case 1738:
5791 return 27;
5792 case 1799:
5793 return 28;
5794 case 1862:
5795 return 29;
5796 case 1928:
5797 return 30;
5798 case 2035:
5799 return 31;
5800 case 2107:
5801 return 32;
5802 case 2181:
5803 return 33;
5804 case 2257:
5805 return 34;
5806 case 2336:
5807 return 35;
5808 case 2418:
5809 return 36;
5810 case 2503:
5811 return 37;
5813 return -1;
5817 * Shift out a formatted serial bit stream
5820 static void rbi_out_parallel(struct rpt *myrpt,unsigned char *data)
5822 #ifdef __i386__
5823 int i,j;
5824 unsigned char od,d;
5825 static volatile long long delayvar;
5827 for(i = 0 ; i < 5 ; i++){
5828 od = *data++;
5829 for(j = 0 ; j < 8 ; j++){
5830 d = od & 1;
5831 outb(d,myrpt->p.iobase);
5832 /* >= 15 us */
5833 for(delayvar = 1; delayvar < 15000; delayvar++);
5834 od >>= 1;
5835 outb(d | 2,myrpt->p.iobase);
5836 /* >= 30 us */
5837 for(delayvar = 1; delayvar < 30000; delayvar++);
5838 outb(d,myrpt->p.iobase);
5839 /* >= 10 us */
5840 for(delayvar = 1; delayvar < 10000; delayvar++);
5843 /* >= 50 us */
5844 for(delayvar = 1; delayvar < 50000; delayvar++);
5845 #endif
5848 static void rbi_out(struct rpt *myrpt,unsigned char *data)
5850 struct zt_radio_param r;
5852 memset(&r,0,sizeof(struct zt_radio_param));
5853 r.radpar = DAHDI_RADPAR_REMMODE;
5854 r.data = DAHDI_RADPAR_REM_RBI1;
5855 /* if setparam ioctl fails, its probably not a pciradio card */
5856 if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_SETPARAM,&r) == -1)
5858 rbi_out_parallel(myrpt,data);
5859 return;
5861 r.radpar = DAHDI_RADPAR_REMCOMMAND;
5862 memcpy(&r.data,data,5);
5863 if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_SETPARAM,&r) == -1)
5865 ast_log(LOG_WARNING,"Cannot send RBI command for channel %s\n",myrpt->zaprxchannel->name);
5866 return;
5870 static int serial_remote_io(struct rpt *myrpt, unsigned char *txbuf, int txbytes,
5871 unsigned char *rxbuf, int rxmaxbytes, int asciiflag)
5873 int i,j,index,oldmode,olddata;
5874 struct zt_radio_param prm;
5875 char c;
5877 if(debug){
5878 printf("String output was: ");
5879 for(i = 0; i < txbytes; i++)
5880 printf("%02X ", (unsigned char ) txbuf[i]);
5881 printf("\n");
5883 if (myrpt->iofd > 0) /* if to do out a serial port */
5885 if (rxmaxbytes && rxbuf) tcflush(myrpt->iofd,TCIFLUSH);
5886 if (write(myrpt->iofd,txbuf,txbytes) != txbytes) return -1;
5887 if ((!rxmaxbytes) || (rxbuf == NULL)) return(0);
5888 memset(rxbuf,0,rxmaxbytes);
5889 for(i = 0; i < rxmaxbytes; i++)
5891 j = read(myrpt->iofd,&c,1);
5892 if (j < 1) return(i);
5893 rxbuf[i] = c;
5894 if (asciiflag & 1)
5896 rxbuf[i + 1] = 0;
5897 if (c == '\r') break;
5900 if(debug){
5901 printf("String returned was: ");
5902 for(j = 0; j < i; j++)
5903 printf("%02X ", (unsigned char ) rxbuf[j]);
5904 printf("\n");
5906 return(i);
5909 /* if not a zap channel, cant use pciradio stuff */
5910 if (myrpt->rxchannel != myrpt->zaprxchannel) return -1;
5912 prm.radpar = DAHDI_RADPAR_UIOMODE;
5913 if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_GETPARAM,&prm) == -1) return -1;
5914 oldmode = prm.data;
5915 prm.radpar = DAHDI_RADPAR_UIODATA;
5916 if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_GETPARAM,&prm) == -1) return -1;
5917 olddata = prm.data;
5918 prm.radpar = DAHDI_RADPAR_REMMODE;
5919 if (asciiflag & 1) prm.data = DAHDI_RADPAR_REM_SERIAL_ASCII;
5920 else prm.data = DAHDI_RADPAR_REM_SERIAL;
5921 if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
5922 if (asciiflag & 2)
5924 i = DAHDI_ONHOOK;
5925 if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_HOOK,&i) == -1) return -1;
5926 usleep(100000);
5928 prm.radpar = DAHDI_RADPAR_REMCOMMAND;
5929 prm.data = rxmaxbytes;
5930 memcpy(prm.buf,txbuf,txbytes);
5931 prm.index = txbytes;
5932 if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
5933 if (rxbuf)
5935 *rxbuf = 0;
5936 memcpy(rxbuf,prm.buf,prm.index);
5938 index = prm.index;
5939 prm.radpar = DAHDI_RADPAR_REMMODE;
5940 prm.data = DAHDI_RADPAR_REM_NONE;
5941 if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
5942 if (asciiflag & 2)
5944 i = DAHDI_OFFHOOK;
5945 if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_HOOK,&i) == -1) return -1;
5947 prm.radpar = DAHDI_RADPAR_UIOMODE;
5948 prm.data = oldmode;
5949 if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
5950 prm.radpar = DAHDI_RADPAR_UIODATA;
5951 prm.data = olddata;
5952 if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
5953 return(index);
5956 static int civ_cmd(struct rpt *myrpt,unsigned char *cmd, int cmdlen)
5958 unsigned char rxbuf[100];
5959 int i,rv ;
5961 rv = serial_remote_io(myrpt,cmd,cmdlen,rxbuf,cmdlen + 6,0);
5962 if (rv == -1) return(-1);
5963 if (rv != (cmdlen + 6)) return(1);
5964 for(i = 0; i < 6; i++)
5965 if (rxbuf[i] != cmd[i]) return(1);
5966 if (rxbuf[cmdlen] != 0xfe) return(1);
5967 if (rxbuf[cmdlen + 1] != 0xfe) return(1);
5968 if (rxbuf[cmdlen + 4] != 0xfb) return(1);
5969 if (rxbuf[cmdlen + 5] != 0xfd) return(1);
5970 return(0);
5973 static int sendkenwood(struct rpt *myrpt,char *txstr, char *rxstr)
5975 int i;
5977 if (debug) printf("Send to kenwood: %s\n",txstr);
5978 i = serial_remote_io(myrpt, (unsigned char *)txstr, strlen(txstr),
5979 (unsigned char *)rxstr,RAD_SERIAL_BUFLEN - 1,3);
5980 if (i < 0) return -1;
5981 if ((i > 0) && (rxstr[i - 1] == '\r'))
5982 rxstr[i-- - 1] = 0;
5983 if (debug) printf("Got from kenwood: %s\n",rxstr);
5984 return(i);
5987 /* take a PL frequency and turn it into a code */
5988 static int kenwood_pltocode(char *str)
5990 int i;
5991 char *s;
5993 s = strchr(str,'.');
5994 i = 0;
5995 if (s) i = atoi(s + 1);
5996 i += atoi(str) * 10;
5997 switch(i)
5999 case 670:
6000 return 1;
6001 case 719:
6002 return 3;
6003 case 744:
6004 return 4;
6005 case 770:
6006 return 5;
6007 case 797:
6008 return 6;
6009 case 825:
6010 return 7;
6011 case 854:
6012 return 8;
6013 case 885:
6014 return 9;
6015 case 915:
6016 return 10;
6017 case 948:
6018 return 11;
6019 case 974:
6020 return 12;
6021 case 1000:
6022 return 13;
6023 case 1035:
6024 return 14;
6025 case 1072:
6026 return 15;
6027 case 1109:
6028 return 16;
6029 case 1148:
6030 return 17;
6031 case 1188:
6032 return 18;
6033 case 1230:
6034 return 19;
6035 case 1273:
6036 return 20;
6037 case 1318:
6038 return 21;
6039 case 1365:
6040 return 22;
6041 case 1413:
6042 return 23;
6043 case 1462:
6044 return 24;
6045 case 1514:
6046 return 25;
6047 case 1567:
6048 return 26;
6049 case 1622:
6050 return 27;
6051 case 1679:
6052 return 28;
6053 case 1738:
6054 return 29;
6055 case 1799:
6056 return 30;
6057 case 1862:
6058 return 31;
6059 case 1928:
6060 return 32;
6061 case 2035:
6062 return 33;
6063 case 2107:
6064 return 34;
6065 case 2181:
6066 return 35;
6067 case 2257:
6068 return 36;
6069 case 2336:
6070 return 37;
6071 case 2418:
6072 return 38;
6073 case 2503:
6074 return 39;
6076 return -1;
6079 static int sendrxkenwood(struct rpt *myrpt, char *txstr, char *rxstr,
6080 char *cmpstr)
6082 int i,j;
6084 for(i = 0;i < KENWOOD_RETRIES;i++)
6086 j = sendkenwood(myrpt,txstr,rxstr);
6087 if (j < 0) return(j);
6088 if (j == 0) continue;
6089 if (!strncmp(rxstr,cmpstr,strlen(cmpstr))) return(0);
6091 return(-1);
6094 static int setkenwood(struct rpt *myrpt)
6096 char rxstr[RAD_SERIAL_BUFLEN],txstr[RAD_SERIAL_BUFLEN],freq[20];
6097 char mhz[MAXREMSTR],offset[20],band,decimals[MAXREMSTR],band1,band2;
6099 int offsets[] = {0,2,1};
6100 int powers[] = {2,1,0};
6102 if (sendrxkenwood(myrpt,"VMC 0,0\r",rxstr,"VMC") < 0) return -1;
6103 split_freq(mhz, decimals, myrpt->freq);
6104 if (atoi(mhz) > 400)
6106 band = '6';
6107 band1 = '1';
6108 band2 = '5';
6109 strcpy(offset,"005000000");
6111 else
6113 band = '2';
6114 band1 = '0';
6115 band2 = '2';
6116 strcpy(offset,"000600000");
6118 strcpy(freq,"000000");
6119 strncpy(freq,decimals,strlen(decimals));
6120 sprintf(txstr,"VW %c,%05d%s,0,%d,0,%d,%d,,%02d,,%02d,%s\r",
6121 band,atoi(mhz),freq,offsets[(int)myrpt->offset],
6122 (myrpt->txplon != 0),(myrpt->rxplon != 0),
6123 kenwood_pltocode(myrpt->txpl),kenwood_pltocode(myrpt->rxpl),
6124 offset);
6125 if (sendrxkenwood(myrpt,txstr,rxstr,"VW") < 0) return -1;
6126 sprintf(txstr,"RBN %c\r",band2);
6127 if (sendrxkenwood(myrpt,txstr,rxstr,"RBN") < 0) return -1;
6128 sprintf(txstr,"PC %c,%d\r",band1,powers[(int)myrpt->powerlevel]);
6129 if (sendrxkenwood(myrpt,txstr,rxstr,"PC") < 0) return -1;
6130 return 0;
6133 static int setrbi(struct rpt *myrpt)
6135 char tmp[MAXREMSTR] = "",*s;
6136 unsigned char rbicmd[5];
6137 int band,txoffset = 0,txpower = 0,rxpl;
6139 /* must be a remote system */
6140 if (!myrpt->remote) return(0);
6141 /* must have rbi hardware */
6142 if (strncmp(myrpt->remote,remote_rig_rbi,3)) return(0);
6143 if (setrbi_check(myrpt) == -1) return(-1);
6144 strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
6145 s = strchr(tmp,'.');
6146 /* if no decimal, is invalid */
6148 if (s == NULL){
6149 if(debug)
6150 printf("@@@@ Frequency needs a decimal\n");
6151 return -1;
6154 *s++ = 0;
6155 if (strlen(tmp) < 2){
6156 if(debug)
6157 printf("@@@@ Bad MHz digits: %s\n", tmp);
6158 return -1;
6161 if (strlen(s) < 3){
6162 if(debug)
6163 printf("@@@@ Bad KHz digits: %s\n", s);
6164 return -1;
6167 if ((s[2] != '0') && (s[2] != '5')){
6168 if(debug)
6169 printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
6170 return -1;
6173 band = rbi_mhztoband(tmp);
6174 if (band == -1){
6175 if(debug)
6176 printf("@@@@ Bad Band: %s\n", tmp);
6177 return -1;
6180 rxpl = rbi_pltocode(myrpt->rxpl);
6182 if (rxpl == -1){
6183 if(debug)
6184 printf("@@@@ Bad TX PL: %s\n", myrpt->rxpl);
6185 return -1;
6189 switch(myrpt->offset)
6191 case REM_MINUS:
6192 txoffset = 0;
6193 break;
6194 case REM_PLUS:
6195 txoffset = 0x10;
6196 break;
6197 case REM_SIMPLEX:
6198 txoffset = 0x20;
6199 break;
6201 switch(myrpt->powerlevel)
6203 case REM_LOWPWR:
6204 txpower = 0;
6205 break;
6206 case REM_MEDPWR:
6207 txpower = 0x20;
6208 break;
6209 case REM_HIPWR:
6210 txpower = 0x10;
6211 break;
6213 rbicmd[0] = 0;
6214 rbicmd[1] = band | txpower | 0xc0;
6215 rbicmd[2] = (*(s - 2) - '0') | txoffset | 0x80;
6216 if (s[2] == '5') rbicmd[2] |= 0x40;
6217 rbicmd[3] = ((*s - '0') << 4) + (s[1] - '0');
6218 rbicmd[4] = rxpl;
6219 if (myrpt->txplon) rbicmd[4] |= 0x40;
6220 if (myrpt->rxplon) rbicmd[4] |= 0x80;
6221 rbi_out(myrpt,rbicmd);
6222 return 0;
6225 static int setrbi_check(struct rpt *myrpt)
6227 char tmp[MAXREMSTR] = "",*s;
6228 int band,txpl;
6230 /* must be a remote system */
6231 if (!myrpt->remote) return(0);
6232 /* must have rbi hardware */
6233 if (strncmp(myrpt->remote,remote_rig_rbi,3)) return(0);
6234 strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
6235 s = strchr(tmp,'.');
6236 /* if no decimal, is invalid */
6238 if (s == NULL){
6239 if(debug)
6240 printf("@@@@ Frequency needs a decimal\n");
6241 return -1;
6244 *s++ = 0;
6245 if (strlen(tmp) < 2){
6246 if(debug)
6247 printf("@@@@ Bad MHz digits: %s\n", tmp);
6248 return -1;
6251 if (strlen(s) < 3){
6252 if(debug)
6253 printf("@@@@ Bad KHz digits: %s\n", s);
6254 return -1;
6257 if ((s[2] != '0') && (s[2] != '5')){
6258 if(debug)
6259 printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
6260 return -1;
6263 band = rbi_mhztoband(tmp);
6264 if (band == -1){
6265 if(debug)
6266 printf("@@@@ Bad Band: %s\n", tmp);
6267 return -1;
6270 txpl = rbi_pltocode(myrpt->txpl);
6272 if (txpl == -1){
6273 if(debug)
6274 printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
6275 return -1;
6277 return 0;
6280 static int check_freq_kenwood(int m, int d, int *defmode)
6282 int dflmd = REM_MODE_FM;
6284 if (m == 144){ /* 2 meters */
6285 if(d < 10100)
6286 return -1;
6288 else if((m >= 145) && (m < 148)){
6291 else if((m >= 430) && (m < 450)){ /* 70 centimeters */
6294 else
6295 return -1;
6297 if(defmode)
6298 *defmode = dflmd;
6301 return 0;
6305 /* Check for valid rbi frequency */
6306 /* Hard coded limits now, configurable later, maybe? */
6308 static int check_freq_rbi(int m, int d, int *defmode)
6310 int dflmd = REM_MODE_FM;
6312 if(m == 50){ /* 6 meters */
6313 if(d < 10100)
6314 return -1;
6316 else if((m >= 51) && ( m < 54)){
6319 else if(m == 144){ /* 2 meters */
6320 if(d < 10100)
6321 return -1;
6323 else if((m >= 145) && (m < 148)){
6326 else if((m >= 222) && (m < 225)){ /* 1.25 meters */
6329 else if((m >= 430) && (m < 450)){ /* 70 centimeters */
6332 else if((m >= 1240) && (m < 1300)){ /* 23 centimeters */
6335 else
6336 return -1;
6338 if(defmode)
6339 *defmode = dflmd;
6342 return 0;
6346 * Convert decimals of frequency to int
6349 static int decimals2int(char *fraction)
6351 int i;
6352 char len = strlen(fraction);
6353 int multiplier = 100000;
6354 int res = 0;
6356 if(!len)
6357 return 0;
6358 for( i = 0 ; i < len ; i++, multiplier /= 10)
6359 res += (fraction[i] - '0') * multiplier;
6360 return res;
6365 * Split frequency into mhz and decimals
6368 static int split_freq(char *mhz, char *decimals, char *freq)
6370 char freq_copy[MAXREMSTR];
6371 char *decp;
6373 decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
6374 if(decp){
6375 *decp++ = 0;
6376 strncpy(mhz, freq_copy, MAXREMSTR);
6377 strcpy(decimals, "00000");
6378 strncpy(decimals, decp, strlen(decp));
6379 decimals[5] = 0;
6380 return 0;
6382 else
6383 return -1;
6388 * Split ctcss frequency into hertz and decimal
6391 static int split_ctcss_freq(char *hertz, char *decimal, char *freq)
6393 char freq_copy[MAXREMSTR];
6394 char *decp;
6396 decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
6397 if(decp){
6398 *decp++ = 0;
6399 strncpy(hertz, freq_copy, MAXREMSTR);
6400 strncpy(decimal, decp, strlen(decp));
6401 decimal[strlen(decp)] = '\0';
6402 return 0;
6404 else
6405 return -1;
6411 * FT-897 I/O handlers
6414 /* Check to see that the frequency is valid */
6415 /* Hard coded limits now, configurable later, maybe? */
6418 static int check_freq_ft897(int m, int d, int *defmode)
6420 int dflmd = REM_MODE_FM;
6422 if(m == 1){ /* 160 meters */
6423 dflmd = REM_MODE_LSB;
6424 if(d < 80000)
6425 return -1;
6427 else if(m == 3){ /* 80 meters */
6428 dflmd = REM_MODE_LSB;
6429 if(d < 50000)
6430 return -1;
6432 else if(m == 7){ /* 40 meters */
6433 dflmd = REM_MODE_LSB;
6434 if(d > 30000)
6435 return -1;
6437 else if(m == 14){ /* 20 meters */
6438 dflmd = REM_MODE_USB;
6439 if(d > 35000)
6440 return -1;
6442 else if(m == 18){ /* 17 meters */
6443 dflmd = REM_MODE_USB;
6444 if((d < 6800) || (d > 16800))
6445 return -1;
6447 else if(m == 21){ /* 15 meters */
6448 dflmd = REM_MODE_USB;
6449 if((d < 20000) || (d > 45000))
6450 return -1;
6452 else if(m == 24){ /* 12 meters */
6453 dflmd = REM_MODE_USB;
6454 if((d < 89000) || (d > 99000))
6455 return -1;
6457 else if(m == 28){ /* 10 meters */
6458 dflmd = REM_MODE_USB;
6460 else if(m == 29){
6461 if(d >= 51000)
6462 dflmd = REM_MODE_FM;
6463 else
6464 dflmd = REM_MODE_USB;
6465 if(d > 70000)
6466 return -1;
6468 else if(m == 50){ /* 6 meters */
6469 if(d >= 30000)
6470 dflmd = REM_MODE_FM;
6471 else
6472 dflmd = REM_MODE_USB;
6475 else if((m >= 51) && ( m < 54)){
6476 dflmd = REM_MODE_FM;
6478 else if(m == 144){ /* 2 meters */
6479 if(d >= 30000)
6480 dflmd = REM_MODE_FM;
6481 else
6482 dflmd = REM_MODE_USB;
6484 else if((m >= 145) && (m < 148)){
6485 dflmd = REM_MODE_FM;
6487 else if((m >= 430) && (m < 450)){ /* 70 centimeters */
6488 if(m < 438)
6489 dflmd = REM_MODE_USB;
6490 else
6491 dflmd = REM_MODE_FM;
6494 else
6495 return -1;
6497 if(defmode)
6498 *defmode = dflmd;
6500 return 0;
6504 * Set a new frequency for the FT897
6507 static int set_freq_ft897(struct rpt *myrpt, char *newfreq)
6509 unsigned char cmdstr[5];
6510 int fd,m,d;
6511 char mhz[MAXREMSTR];
6512 char decimals[MAXREMSTR];
6514 fd = 0;
6515 if(debug)
6516 printf("New frequency: %s\n",newfreq);
6518 if(split_freq(mhz, decimals, newfreq))
6519 return -1;
6521 m = atoi(mhz);
6522 d = atoi(decimals);
6524 /* The FT-897 likes packed BCD frequencies */
6526 cmdstr[0] = ((m / 100) << 4) + ((m % 100)/10); /* 100MHz 10Mhz */
6527 cmdstr[1] = ((m % 10) << 4) + (d / 10000); /* 1MHz 100KHz */
6528 cmdstr[2] = (((d % 10000)/1000) << 4) + ((d % 1000)/ 100); /* 10KHz 1KHz */
6529 cmdstr[3] = (((d % 100)/10) << 4) + (d % 10); /* 100Hz 10Hz */
6530 cmdstr[4] = 0x01; /* command */
6532 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
6536 /* ft-897 simple commands */
6538 static int simple_command_ft897(struct rpt *myrpt, char command)
6540 unsigned char cmdstr[5];
6542 memset(cmdstr, 0, 5);
6544 cmdstr[4] = command;
6546 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
6550 /* ft-897 offset */
6552 static int set_offset_ft897(struct rpt *myrpt, char offset)
6554 unsigned char cmdstr[5];
6556 memset(cmdstr, 0, 5);
6558 switch(offset){
6559 case REM_SIMPLEX:
6560 cmdstr[0] = 0x89;
6561 break;
6563 case REM_MINUS:
6564 cmdstr[0] = 0x09;
6565 break;
6567 case REM_PLUS:
6568 cmdstr[0] = 0x49;
6569 break;
6571 default:
6572 return -1;
6575 cmdstr[4] = 0x09;
6577 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
6580 /* ft-897 mode */
6582 static int set_mode_ft897(struct rpt *myrpt, char newmode)
6584 unsigned char cmdstr[5];
6586 memset(cmdstr, 0, 5);
6588 switch(newmode){
6589 case REM_MODE_FM:
6590 cmdstr[0] = 0x08;
6591 break;
6593 case REM_MODE_USB:
6594 cmdstr[0] = 0x01;
6595 break;
6597 case REM_MODE_LSB:
6598 cmdstr[0] = 0x00;
6599 break;
6601 case REM_MODE_AM:
6602 cmdstr[0] = 0x04;
6603 break;
6605 default:
6606 return -1;
6608 cmdstr[4] = 0x07;
6610 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
6613 /* Set tone encode and decode modes */
6615 static int set_ctcss_mode_ft897(struct rpt *myrpt, char txplon, char rxplon)
6617 unsigned char cmdstr[5];
6619 memset(cmdstr, 0, 5);
6621 if(rxplon && txplon)
6622 cmdstr[0] = 0x2A; /* Encode and Decode */
6623 else if (!rxplon && txplon)
6624 cmdstr[0] = 0x4A; /* Encode only */
6625 else if (rxplon && !txplon)
6626 cmdstr[0] = 0x3A; /* Encode only */
6627 else
6628 cmdstr[0] = 0x8A; /* OFF */
6630 cmdstr[4] = 0x0A;
6632 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
6636 /* Set transmit and receive ctcss tone frequencies */
6638 static int set_ctcss_freq_ft897(struct rpt *myrpt, char *txtone, char *rxtone)
6640 unsigned char cmdstr[5];
6641 char hertz[MAXREMSTR],decimal[MAXREMSTR];
6642 int h,d;
6644 memset(cmdstr, 0, 5);
6646 if(split_ctcss_freq(hertz, decimal, txtone))
6647 return -1;
6649 h = atoi(hertz);
6650 d = atoi(decimal);
6652 cmdstr[0] = ((h / 100) << 4) + (h % 100)/ 10;
6653 cmdstr[1] = ((h % 10) << 4) + (d % 10);
6655 if(rxtone){
6657 if(split_ctcss_freq(hertz, decimal, rxtone))
6658 return -1;
6660 h = atoi(hertz);
6661 d = atoi(decimal);
6663 cmdstr[2] = ((h / 100) << 4) + (h % 100)/ 10;
6664 cmdstr[3] = ((h % 10) << 4) + (d % 10);
6666 cmdstr[4] = 0x0B;
6668 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
6673 static int set_ft897(struct rpt *myrpt)
6675 int res;
6677 if(debug)
6678 printf("@@@@ lock on\n");
6680 res = simple_command_ft897(myrpt, 0x00); /* LOCK on */
6682 if(debug)
6683 printf("@@@@ ptt off\n");
6685 if(!res)
6686 res = simple_command_ft897(myrpt, 0x88); /* PTT off */
6688 if(debug)
6689 printf("Modulation mode\n");
6691 if(!res)
6692 res = set_mode_ft897(myrpt, myrpt->remmode); /* Modulation mode */
6694 if(debug)
6695 printf("Split off\n");
6697 if(!res)
6698 simple_command_ft897(myrpt, 0x82); /* Split off */
6700 if(debug)
6701 printf("Frequency\n");
6703 if(!res)
6704 res = set_freq_ft897(myrpt, myrpt->freq); /* Frequency */
6705 if((myrpt->remmode == REM_MODE_FM)){
6706 if(debug)
6707 printf("Offset\n");
6708 if(!res)
6709 res = set_offset_ft897(myrpt, myrpt->offset); /* Offset if FM */
6710 if((!res)&&(myrpt->rxplon || myrpt->txplon)){
6711 if(debug)
6712 printf("CTCSS tone freqs.\n");
6713 res = set_ctcss_freq_ft897(myrpt, myrpt->txpl, myrpt->rxpl); /* CTCSS freqs if CTCSS is enabled */
6715 if(!res){
6716 if(debug)
6717 printf("CTCSS mode\n");
6718 res = set_ctcss_mode_ft897(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */
6721 if((myrpt->remmode == REM_MODE_USB)||(myrpt->remmode == REM_MODE_LSB)){
6722 if(debug)
6723 printf("Clarifier off\n");
6724 simple_command_ft897(myrpt, 0x85); /* Clarifier off if LSB or USB */
6726 return res;
6729 static int closerem_ft897(struct rpt *myrpt)
6731 simple_command_ft897(myrpt, 0x88); /* PTT off */
6732 return 0;
6736 * Bump frequency up or down by a small amount
6737 * Return 0 if the new frequnecy is valid, or -1 if invalid
6738 * Interval is in Hz, resolution is 10Hz
6741 static int multimode_bump_freq_ft897(struct rpt *myrpt, int interval)
6743 int m,d;
6744 char mhz[MAXREMSTR], decimals[MAXREMSTR];
6746 if(debug)
6747 printf("Before bump: %s\n", myrpt->freq);
6749 if(split_freq(mhz, decimals, myrpt->freq))
6750 return -1;
6752 m = atoi(mhz);
6753 d = atoi(decimals);
6755 d += (interval / 10); /* 10Hz resolution */
6756 if(d < 0){
6757 m--;
6758 d += 100000;
6760 else if(d >= 100000){
6761 m++;
6762 d -= 100000;
6765 if(check_freq_ft897(m, d, NULL)){
6766 if(debug)
6767 printf("Bump freq invalid\n");
6768 return -1;
6771 snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d);
6773 if(debug)
6774 printf("After bump: %s\n", myrpt->freq);
6776 return set_freq_ft897(myrpt, myrpt->freq);
6782 * IC-706 I/O handlers
6785 /* Check to see that the frequency is valid */
6786 /* Hard coded limits now, configurable later, maybe? */
6789 static int check_freq_ic706(int m, int d, int *defmode)
6791 int dflmd = REM_MODE_FM;
6793 if(m == 1){ /* 160 meters */
6794 dflmd = REM_MODE_LSB;
6795 if(d < 80000)
6796 return -1;
6798 else if(m == 3){ /* 80 meters */
6799 dflmd = REM_MODE_LSB;
6800 if(d < 50000)
6801 return -1;
6803 else if(m == 7){ /* 40 meters */
6804 dflmd = REM_MODE_LSB;
6805 if(d > 30000)
6806 return -1;
6808 else if(m == 14){ /* 20 meters */
6809 dflmd = REM_MODE_USB;
6810 if(d > 35000)
6811 return -1;
6813 else if(m == 18){ /* 17 meters */
6814 dflmd = REM_MODE_USB;
6815 if((d < 6800) || (d > 16800))
6816 return -1;
6818 else if(m == 21){ /* 15 meters */
6819 dflmd = REM_MODE_USB;
6820 if((d < 20000) || (d > 45000))
6821 return -1;
6823 else if(m == 24){ /* 12 meters */
6824 dflmd = REM_MODE_USB;
6825 if((d < 89000) || (d > 99000))
6826 return -1;
6828 else if(m == 28){ /* 10 meters */
6829 dflmd = REM_MODE_USB;
6831 else if(m == 29){
6832 if(d >= 51000)
6833 dflmd = REM_MODE_FM;
6834 else
6835 dflmd = REM_MODE_USB;
6836 if(d > 70000)
6837 return -1;
6839 else if(m == 50){ /* 6 meters */
6840 if(d >= 30000)
6841 dflmd = REM_MODE_FM;
6842 else
6843 dflmd = REM_MODE_USB;
6846 else if((m >= 51) && ( m < 54)){
6847 dflmd = REM_MODE_FM;
6849 else if(m == 144){ /* 2 meters */
6850 if(d >= 30000)
6851 dflmd = REM_MODE_FM;
6852 else
6853 dflmd = REM_MODE_USB;
6855 else if((m >= 145) && (m < 148)){
6856 dflmd = REM_MODE_FM;
6858 else if((m >= 430) && (m < 450)){ /* 70 centimeters */
6859 if(m < 438)
6860 dflmd = REM_MODE_USB;
6861 else
6862 dflmd = REM_MODE_FM;
6865 else
6866 return -1;
6868 if(defmode)
6869 *defmode = dflmd;
6871 return 0;
6874 /* take a PL frequency and turn it into a code */
6875 static int ic706_pltocode(char *str)
6877 int i;
6878 char *s;
6880 s = strchr(str,'.');
6881 i = 0;
6882 if (s) i = atoi(s + 1);
6883 i += atoi(str) * 10;
6884 switch(i)
6886 case 670:
6887 return 0;
6888 case 693:
6889 return 1;
6890 case 719:
6891 return 2;
6892 case 744:
6893 return 3;
6894 case 770:
6895 return 4;
6896 case 797:
6897 return 5;
6898 case 825:
6899 return 6;
6900 case 854:
6901 return 7;
6902 case 885:
6903 return 8;
6904 case 915:
6905 return 9;
6906 case 948:
6907 return 10;
6908 case 974:
6909 return 11;
6910 case 1000:
6911 return 12;
6912 case 1035:
6913 return 13;
6914 case 1072:
6915 return 14;
6916 case 1109:
6917 return 15;
6918 case 1148:
6919 return 16;
6920 case 1188:
6921 return 17;
6922 case 1230:
6923 return 18;
6924 case 1273:
6925 return 19;
6926 case 1318:
6927 return 20;
6928 case 1365:
6929 return 21;
6930 case 1413:
6931 return 22;
6932 case 1462:
6933 return 23;
6934 case 1514:
6935 return 24;
6936 case 1567:
6937 return 25;
6938 case 1598:
6939 return 26;
6940 case 1622:
6941 return 27;
6942 case 1655:
6943 return 28;
6944 case 1679:
6945 return 29;
6946 case 1713:
6947 return 30;
6948 case 1738:
6949 return 31;
6950 case 1773:
6951 return 32;
6952 case 1799:
6953 return 33;
6954 case 1835:
6955 return 34;
6956 case 1862:
6957 return 35;
6958 case 1899:
6959 return 36;
6960 case 1928:
6961 return 37;
6962 case 1966:
6963 return 38;
6964 case 1995:
6965 return 39;
6966 case 2035:
6967 return 40;
6968 case 2065:
6969 return 41;
6970 case 2107:
6971 return 42;
6972 case 2181:
6973 return 43;
6974 case 2257:
6975 return 44;
6976 case 2291:
6977 return 45;
6978 case 2336:
6979 return 46;
6980 case 2418:
6981 return 47;
6982 case 2503:
6983 return 48;
6984 case 2541:
6985 return 49;
6987 return -1;
6990 /* ic-706 simple commands */
6992 static int simple_command_ic706(struct rpt *myrpt, char command, char subcommand)
6994 unsigned char cmdstr[10];
6996 cmdstr[0] = cmdstr[1] = 0xfe;
6997 cmdstr[2] = myrpt->p.civaddr;
6998 cmdstr[3] = 0xe0;
6999 cmdstr[4] = command;
7000 cmdstr[5] = subcommand;
7001 cmdstr[6] = 0xfd;
7003 return(civ_cmd(myrpt,cmdstr,7));
7007 * Set a new frequency for the ic706
7010 static int set_freq_ic706(struct rpt *myrpt, char *newfreq)
7012 unsigned char cmdstr[20];
7013 char mhz[MAXREMSTR], decimals[MAXREMSTR];
7014 int fd,m,d;
7016 fd = 0;
7017 if(debug)
7018 printf("New frequency: %s\n",newfreq);
7020 if(split_freq(mhz, decimals, newfreq))
7021 return -1;
7023 m = atoi(mhz);
7024 d = atoi(decimals);
7026 /* The ic-706 likes packed BCD frequencies */
7028 cmdstr[0] = cmdstr[1] = 0xfe;
7029 cmdstr[2] = myrpt->p.civaddr;
7030 cmdstr[3] = 0xe0;
7031 cmdstr[4] = 5;
7032 cmdstr[5] = ((d % 10) << 4);
7033 cmdstr[6] = (((d % 1000)/ 100) << 4) + ((d % 100)/10);
7034 cmdstr[7] = ((d / 10000) << 4) + ((d % 10000)/1000);
7035 cmdstr[8] = (((m % 100)/10) << 4) + (m % 10);
7036 cmdstr[9] = (m / 100);
7037 cmdstr[10] = 0xfd;
7039 return(civ_cmd(myrpt,cmdstr,11));
7042 /* ic-706 offset */
7044 static int set_offset_ic706(struct rpt *myrpt, char offset)
7046 unsigned char c;
7048 switch(offset){
7049 case REM_SIMPLEX:
7050 c = 0x10;
7051 break;
7053 case REM_MINUS:
7054 c = 0x11;
7055 break;
7057 case REM_PLUS:
7058 c = 0x12;
7059 break;
7061 default:
7062 return -1;
7065 return simple_command_ic706(myrpt,0x0f,c);
7069 /* ic-706 mode */
7071 static int set_mode_ic706(struct rpt *myrpt, char newmode)
7073 unsigned char c;
7075 switch(newmode){
7076 case REM_MODE_FM:
7077 c = 5;
7078 break;
7080 case REM_MODE_USB:
7081 c = 1;
7082 break;
7084 case REM_MODE_LSB:
7085 c = 0;
7086 break;
7088 case REM_MODE_AM:
7089 c = 2;
7090 break;
7092 default:
7093 return -1;
7095 return simple_command_ic706(myrpt,6,c);
7098 /* Set tone encode and decode modes */
7100 static int set_ctcss_mode_ic706(struct rpt *myrpt, char txplon, char rxplon)
7102 unsigned char cmdstr[10];
7103 int rv;
7105 cmdstr[0] = cmdstr[1] = 0xfe;
7106 cmdstr[2] = myrpt->p.civaddr;
7107 cmdstr[3] = 0xe0;
7108 cmdstr[4] = 0x16;
7109 cmdstr[5] = 0x42;
7110 cmdstr[6] = (txplon != 0);
7111 cmdstr[7] = 0xfd;
7113 rv = civ_cmd(myrpt,cmdstr,8);
7114 if (rv) return(-1);
7116 cmdstr[0] = cmdstr[1] = 0xfe;
7117 cmdstr[2] = myrpt->p.civaddr;
7118 cmdstr[3] = 0xe0;
7119 cmdstr[4] = 0x16;
7120 cmdstr[5] = 0x43;
7121 cmdstr[6] = (rxplon != 0);
7122 cmdstr[7] = 0xfd;
7124 return(civ_cmd(myrpt,cmdstr,8));
7127 #if 0
7128 /* Set transmit and receive ctcss tone frequencies */
7130 static int set_ctcss_freq_ic706(struct rpt *myrpt, char *txtone, char *rxtone)
7132 unsigned char cmdstr[10];
7133 char hertz[MAXREMSTR],decimal[MAXREMSTR];
7134 int h,d,rv;
7136 memset(cmdstr, 0, 5);
7138 if(split_ctcss_freq(hertz, decimal, txtone))
7139 return -1;
7141 h = atoi(hertz);
7142 d = atoi(decimal);
7144 cmdstr[0] = cmdstr[1] = 0xfe;
7145 cmdstr[2] = myrpt->p.civaddr;
7146 cmdstr[3] = 0xe0;
7147 cmdstr[4] = 0x1b;
7148 cmdstr[5] = 0;
7149 cmdstr[6] = ((h / 100) << 4) + (h % 100)/ 10;
7150 cmdstr[7] = ((h % 10) << 4) + (d % 10);
7151 cmdstr[8] = 0xfd;
7153 rv = civ_cmd(myrpt,cmdstr,9);
7154 if (rv) return(-1);
7156 if (!rxtone) return(0);
7158 if(split_ctcss_freq(hertz, decimal, rxtone))
7159 return -1;
7161 h = atoi(hertz);
7162 d = atoi(decimal);
7164 cmdstr[0] = cmdstr[1] = 0xfe;
7165 cmdstr[2] = myrpt->p.civaddr;
7166 cmdstr[3] = 0xe0;
7167 cmdstr[4] = 0x1b;
7168 cmdstr[5] = 1;
7169 cmdstr[6] = ((h / 100) << 4) + (h % 100)/ 10;
7170 cmdstr[7] = ((h % 10) << 4) + (d % 10);
7171 cmdstr[8] = 0xfd;
7172 return(civ_cmd(myrpt,cmdstr,9));
7174 #endif
7176 static int vfo_ic706(struct rpt *myrpt)
7178 unsigned char cmdstr[10];
7180 cmdstr[0] = cmdstr[1] = 0xfe;
7181 cmdstr[2] = myrpt->p.civaddr;
7182 cmdstr[3] = 0xe0;
7183 cmdstr[4] = 7;
7184 cmdstr[5] = 0xfd;
7186 return(civ_cmd(myrpt,cmdstr,6));
7189 static int mem2vfo_ic706(struct rpt *myrpt)
7191 unsigned char cmdstr[10];
7193 cmdstr[0] = cmdstr[1] = 0xfe;
7194 cmdstr[2] = myrpt->p.civaddr;
7195 cmdstr[3] = 0xe0;
7196 cmdstr[4] = 0x0a;
7197 cmdstr[5] = 0xfd;
7199 return(civ_cmd(myrpt,cmdstr,6));
7202 static int select_mem_ic706(struct rpt *myrpt, int slot)
7204 unsigned char cmdstr[10];
7206 cmdstr[0] = cmdstr[1] = 0xfe;
7207 cmdstr[2] = myrpt->p.civaddr;
7208 cmdstr[3] = 0xe0;
7209 cmdstr[4] = 8;
7210 cmdstr[5] = 0;
7211 cmdstr[6] = ((slot / 10) << 4) + (slot % 10);
7212 cmdstr[7] = 0xfd;
7214 return(civ_cmd(myrpt,cmdstr,8));
7217 static int set_ic706(struct rpt *myrpt)
7219 int res = 0,i;
7221 if(debug)
7222 printf("Set to VFO A\n");
7224 if (!res)
7225 res = simple_command_ic706(myrpt,7,0);
7228 if((myrpt->remmode == REM_MODE_FM))
7230 i = ic706_pltocode(myrpt->rxpl);
7231 if (i == -1) return -1;
7232 if(debug)
7233 printf("Select memory number\n");
7234 if (!res)
7235 res = select_mem_ic706(myrpt,i + IC706_PL_MEMORY_OFFSET);
7236 if(debug)
7237 printf("Transfer memory to VFO\n");
7238 if (!res)
7239 res = mem2vfo_ic706(myrpt);
7242 if(debug)
7243 printf("Set to VFO\n");
7245 if (!res)
7246 res = vfo_ic706(myrpt);
7248 if(debug)
7249 printf("Modulation mode\n");
7251 if (!res)
7252 res = set_mode_ic706(myrpt, myrpt->remmode); /* Modulation mode */
7254 if(debug)
7255 printf("Split off\n");
7257 if(!res)
7258 simple_command_ic706(myrpt, 0x82,0); /* Split off */
7260 if(debug)
7261 printf("Frequency\n");
7263 if(!res)
7264 res = set_freq_ic706(myrpt, myrpt->freq); /* Frequency */
7265 if((myrpt->remmode == REM_MODE_FM)){
7266 if(debug)
7267 printf("Offset\n");
7268 if(!res)
7269 res = set_offset_ic706(myrpt, myrpt->offset); /* Offset if FM */
7270 if(!res){
7271 if(debug)
7272 printf("CTCSS mode\n");
7273 res = set_ctcss_mode_ic706(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */
7276 return res;
7280 * Bump frequency up or down by a small amount
7281 * Return 0 if the new frequnecy is valid, or -1 if invalid
7282 * Interval is in Hz, resolution is 10Hz
7285 static int multimode_bump_freq_ic706(struct rpt *myrpt, int interval)
7287 int m,d;
7288 char mhz[MAXREMSTR], decimals[MAXREMSTR];
7289 unsigned char cmdstr[20];
7291 if(debug)
7292 printf("Before bump: %s\n", myrpt->freq);
7294 if(split_freq(mhz, decimals, myrpt->freq))
7295 return -1;
7297 m = atoi(mhz);
7298 d = atoi(decimals);
7300 d += (interval / 10); /* 10Hz resolution */
7301 if(d < 0){
7302 m--;
7303 d += 100000;
7305 else if(d >= 100000){
7306 m++;
7307 d -= 100000;
7310 if(check_freq_ic706(m, d, NULL)){
7311 if(debug)
7312 printf("Bump freq invalid\n");
7313 return -1;
7316 snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d);
7318 if(debug)
7319 printf("After bump: %s\n", myrpt->freq);
7321 /* The ic-706 likes packed BCD frequencies */
7323 cmdstr[0] = cmdstr[1] = 0xfe;
7324 cmdstr[2] = myrpt->p.civaddr;
7325 cmdstr[3] = 0xe0;
7326 cmdstr[4] = 0;
7327 cmdstr[5] = ((d % 10) << 4);
7328 cmdstr[6] = (((d % 1000)/ 100) << 4) + ((d % 100)/10);
7329 cmdstr[7] = ((d / 10000) << 4) + ((d % 10000)/1000);
7330 cmdstr[8] = (((m % 100)/10) << 4) + (m % 10);
7331 cmdstr[9] = (m / 100);
7332 cmdstr[10] = 0xfd;
7334 return(serial_remote_io(myrpt,cmdstr,11,NULL,0,0));
7340 * Dispatch to correct I/O handler
7343 static int setrem(struct rpt *myrpt)
7345 char str[300];
7346 char *offsets[] = {"MINUS","SIMPLEX","PLUS"};
7347 char *powerlevels[] = {"LOW","MEDIUM","HIGH"};
7348 char *modes[] = {"FM","USB","LSB","AM"};
7349 int res = -1;
7351 if (myrpt->p.archivedir)
7353 sprintf(str,"FREQ,%s,%s,%s,%s,%s,%s,%d,%d",myrpt->freq,
7354 modes[(int)myrpt->remmode],
7355 myrpt->txpl,myrpt->rxpl,offsets[(int)myrpt->offset],
7356 powerlevels[(int)myrpt->powerlevel],myrpt->txplon,
7357 myrpt->rxplon);
7358 donodelog(myrpt,str);
7360 if(!strcmp(myrpt->remote, remote_rig_ft897))
7362 rpt_telemetry(myrpt,SETREMOTE,NULL);
7363 res = 0;
7365 if(!strcmp(myrpt->remote, remote_rig_ic706))
7367 rpt_telemetry(myrpt,SETREMOTE,NULL);
7368 res = 0;
7370 else if(!strcmp(myrpt->remote, remote_rig_rbi))
7372 res = setrbi_check(myrpt);
7373 if (!res)
7375 rpt_telemetry(myrpt,SETREMOTE,NULL);
7376 res = 0;
7379 else if(!strcmp(myrpt->remote, remote_rig_kenwood)) {
7380 rpt_telemetry(myrpt,SETREMOTE,NULL);
7381 res = 0;
7383 else
7384 res = 0;
7386 if (res < 0) ast_log(LOG_ERROR,"Unable to send remote command on node %s\n",myrpt->name);
7388 return res;
7391 static int closerem(struct rpt *myrpt)
7393 if(!strcmp(myrpt->remote, remote_rig_ft897))
7394 return closerem_ft897(myrpt);
7395 else
7396 return 0;
7400 * Dispatch to correct RX frequency checker
7403 static int check_freq(struct rpt *myrpt, int m, int d, int *defmode)
7405 if(!strcmp(myrpt->remote, remote_rig_ft897))
7406 return check_freq_ft897(m, d, defmode);
7407 else if(!strcmp(myrpt->remote, remote_rig_ic706))
7408 return check_freq_ic706(m, d, defmode);
7409 else if(!strcmp(myrpt->remote, remote_rig_rbi))
7410 return check_freq_rbi(m, d, defmode);
7411 else if(!strcmp(myrpt->remote, remote_rig_kenwood))
7412 return check_freq_kenwood(m, d, defmode);
7413 else
7414 return -1;
7418 * Check TX frequency before transmitting
7421 static char check_tx_freq(struct rpt *myrpt)
7423 int i;
7424 int radio_mhz, radio_decimals, ulimit_mhz, ulimit_decimals, llimit_mhz, llimit_decimals;
7425 char radio_mhz_char[MAXREMSTR];
7426 char radio_decimals_char[MAXREMSTR];
7427 char limit_mhz_char[MAXREMSTR];
7428 char limit_decimals_char[MAXREMSTR];
7429 char limits[256];
7430 char *limit_ranges[40];
7431 struct ast_variable *limitlist;
7434 /* Must have user logged in and tx_limits defined */
7436 if(!myrpt->p.txlimitsstanzaname || !myrpt->loginuser[0] || !myrpt->loginlevel[0]){
7437 if(debug > 3){
7438 ast_log(LOG_NOTICE, "No tx band table defined, or no user logged in\n");
7440 return 1; /* Assume it's ok otherwise */
7443 /* Retrieve the band table for the loginlevel */
7444 limitlist = ast_variable_browse(myrpt->cfg, myrpt->p.txlimitsstanzaname);
7446 if(!limitlist){
7447 ast_log(LOG_WARNING, "No entries in %s band table stanza\n", myrpt->p.txlimitsstanzaname);
7448 return 0;
7451 split_freq(radio_mhz_char, radio_decimals_char, myrpt->freq);
7452 radio_mhz = atoi(radio_mhz_char);
7453 radio_decimals = decimals2int(radio_decimals_char);
7456 if(debug > 3){
7457 ast_log(LOG_NOTICE, "Login User = %s, login level = %s\n", myrpt->loginuser, myrpt->loginlevel);
7460 /* Find our entry */
7462 for(;limitlist; limitlist=limitlist->next){
7463 if(!strcmp(limitlist->name, myrpt->loginlevel))
7464 break;
7467 if(!limitlist){
7468 ast_log(LOG_WARNING, "Can't find %s entry in band table stanza %s\n", myrpt->loginlevel, myrpt->p.txlimitsstanzaname);
7469 return 0;
7472 if(debug > 3){
7473 ast_log(LOG_NOTICE, "Auth %s = %s\n", limitlist->name, limitlist->value);
7476 /* Parse the limits */
7478 strncpy(limits, limitlist->value, 256);
7479 limits[255] = 0;
7480 finddelim(limits, limit_ranges, 40);
7481 for(i = 0; i < 40 && limit_ranges[i] ; i++){
7482 char range[40];
7483 char *r,*s;
7484 strncpy(range, limit_ranges[i], 40);
7485 range[39] = 0;
7486 if(debug > 3){
7487 ast_log(LOG_NOTICE, "Checking to see if %s is within limits of %s\n", myrpt->freq, range);
7490 r = strchr(range, '-');
7491 if(!r){
7492 ast_log(LOG_WARNING, "Malformed range in %s tx band table entry\n", limitlist->name);
7493 return 0;
7495 *r++ = 0;
7496 s = eatwhite(range);
7497 r = eatwhite(r);
7498 split_freq(limit_mhz_char, limit_decimals_char, s);
7499 llimit_mhz = atoi(limit_mhz_char);
7500 llimit_decimals = decimals2int(limit_decimals_char);
7501 split_freq(limit_mhz_char, limit_decimals_char, r);
7502 ulimit_mhz = atoi(limit_mhz_char);
7503 ulimit_decimals = decimals2int(limit_decimals_char);
7505 if((radio_mhz >= llimit_mhz) && (radio_mhz <= ulimit_mhz)){
7506 if(radio_mhz == llimit_mhz){ /* CASE 1: TX freq is in llimit mhz portion of band */
7507 if(radio_decimals >= llimit_decimals){ /* Cannot be below llimit decimals */
7508 if(llimit_mhz == ulimit_mhz){ /* If bandwidth < 1Mhz, check ulimit decimals */
7509 if(radio_decimals <= ulimit_decimals){
7510 return 1;
7512 else{
7513 if(debug > 3)
7514 ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 1\n");
7515 return 0;
7518 else{
7519 return 1;
7522 else{ /* Is below llimit decimals */
7523 if(debug > 3)
7524 ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 2\n");
7525 return 0;
7528 else if(radio_mhz == ulimit_mhz){ /* CASE 2: TX freq not in llimit mhz portion of band */
7529 if(radio_decimals <= ulimit_decimals){
7530 return 1;
7532 else{ /* Is above ulimit decimals */
7533 if(debug > 3)
7534 ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 3\n");
7535 return 0;
7538 else /* CASE 3: TX freq within a multi-Mhz band and ok */
7539 return 1;
7542 if(debug > 3) /* No match found in TX band table */
7543 ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 4\n");
7544 return 0;
7549 * Dispatch to correct frequency bumping function
7552 static int multimode_bump_freq(struct rpt *myrpt, int interval)
7554 if(!strcmp(myrpt->remote, remote_rig_ft897))
7555 return multimode_bump_freq_ft897(myrpt, interval);
7556 else if(!strcmp(myrpt->remote, remote_rig_ic706))
7557 return multimode_bump_freq_ic706(myrpt, interval);
7558 else
7559 return -1;
7564 * Queue announcment that scan has been stopped
7567 static void stop_scan(struct rpt *myrpt)
7569 myrpt->hfscanstop = 1;
7570 rpt_telemetry(myrpt,SCAN,0);
7574 * This is called periodically when in scan mode
7578 static int service_scan(struct rpt *myrpt)
7580 int res, interval;
7581 char mhz[MAXREMSTR], decimals[MAXREMSTR], k10=0i, k100=0;
7583 switch(myrpt->hfscanmode){
7585 case HF_SCAN_DOWN_SLOW:
7586 interval = -10; /* 100Hz /sec */
7587 break;
7589 case HF_SCAN_DOWN_QUICK:
7590 interval = -50; /* 500Hz /sec */
7591 break;
7593 case HF_SCAN_DOWN_FAST:
7594 interval = -200; /* 2KHz /sec */
7595 break;
7597 case HF_SCAN_UP_SLOW:
7598 interval = 10; /* 100Hz /sec */
7599 break;
7601 case HF_SCAN_UP_QUICK:
7602 interval = 50; /* 500 Hz/sec */
7603 break;
7605 case HF_SCAN_UP_FAST:
7606 interval = 200; /* 2KHz /sec */
7607 break;
7609 default:
7610 myrpt->hfscanmode = 0; /* Huh? */
7611 return -1;
7614 res = split_freq(mhz, decimals, myrpt->freq);
7616 if(!res){
7617 k100 =decimals[0];
7618 k10 = decimals[1];
7619 res = multimode_bump_freq(myrpt, interval);
7622 if(!res)
7623 res = split_freq(mhz, decimals, myrpt->freq);
7626 if(res){
7627 myrpt->hfscanmode = 0;
7628 myrpt->hfscanstatus = -2;
7629 return -1;
7632 /* Announce 10KHz boundaries */
7633 if(k10 != decimals[1]){
7634 int myhund = (interval < 0) ? k100 : decimals[0];
7635 int myten = (interval < 0) ? k10 : decimals[1];
7636 myrpt->hfscanstatus = (myten == '0') ? (myhund - '0') * 100 : (myten - '0') * 10;
7637 } else myrpt->hfscanstatus = 0;
7638 return res;
7643 * Retrieve a memory channel
7644 * Return 0 if sucessful,
7645 * -1 if channel not found,
7646 * 1 if parse error
7649 static int retreive_memory(struct rpt *myrpt, char *memory)
7651 char tmp[30], *s, *s1, *val;
7653 val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.memory, memory);
7654 if (!val){
7655 return -1;
7657 strncpy(tmp,val,sizeof(tmp) - 1);
7658 tmp[sizeof(tmp)-1] = 0;
7660 s = strchr(tmp,',');
7661 if (!s)
7662 return 1;
7663 *s++ = 0;
7664 s1 = strchr(s,',');
7665 if (!s1)
7666 return 1;
7667 *s1++ = 0;
7668 strncpy(myrpt->freq, tmp, sizeof(myrpt->freq) - 1);
7669 strncpy(myrpt->rxpl, s, sizeof(myrpt->rxpl) - 1);
7670 strncpy(myrpt->txpl, s, sizeof(myrpt->rxpl) - 1);
7671 myrpt->remmode = REM_MODE_FM;
7672 myrpt->offset = REM_SIMPLEX;
7673 myrpt->powerlevel = REM_MEDPWR;
7674 myrpt->txplon = myrpt->rxplon = 0;
7675 while(*s1){
7676 switch(*s1++){
7677 case 'A':
7678 case 'a':
7679 strcpy(myrpt->rxpl, "100.0");
7680 strcpy(myrpt->txpl, "100.0");
7681 myrpt->remmode = REM_MODE_AM;
7682 break;
7683 case 'B':
7684 case 'b':
7685 strcpy(myrpt->rxpl, "100.0");
7686 strcpy(myrpt->txpl, "100.0");
7687 myrpt->remmode = REM_MODE_LSB;
7688 break;
7689 case 'F':
7690 myrpt->remmode = REM_MODE_FM;
7691 break;
7692 case 'L':
7693 case 'l':
7694 myrpt->powerlevel = REM_LOWPWR;
7695 break;
7696 case 'H':
7697 case 'h':
7698 myrpt->powerlevel = REM_HIPWR;
7699 break;
7701 case 'M':
7702 case 'm':
7703 myrpt->powerlevel = REM_MEDPWR;
7704 break;
7706 case '-':
7707 myrpt->offset = REM_MINUS;
7708 break;
7710 case '+':
7711 myrpt->offset = REM_PLUS;
7712 break;
7714 case 'S':
7715 case 's':
7716 myrpt->offset = REM_SIMPLEX;
7717 break;
7719 case 'T':
7720 case 't':
7721 myrpt->txplon = 1;
7722 break;
7724 case 'R':
7725 case 'r':
7726 myrpt->rxplon = 1;
7727 break;
7729 case 'U':
7730 case 'u':
7731 strcpy(myrpt->rxpl, "100.0");
7732 strcpy(myrpt->txpl, "100.0");
7733 myrpt->remmode = REM_MODE_USB;
7734 break;
7735 default:
7736 return 1;
7739 return 0;
7745 * Remote base function
7748 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
7750 char *s,*s1,*s2;
7751 int i,j,p,r,ht,k,l,ls2,m,d,offset,offsave, modesave, defmode;
7752 char multimode = 0;
7753 char oc,*cp,*cp1,*cp2;
7754 char tmp[20], freq[20] = "", savestr[20] = "";
7755 char mhz[MAXREMSTR], decimals[MAXREMSTR];
7757 if((!param) || (command_source == SOURCE_RPT) || (command_source == SOURCE_LNK))
7758 return DC_ERROR;
7760 p = myatoi(param);
7762 if ((p != 99) && (p != 5) && (p != 140) && myrpt->p.authlevel &&
7763 (!myrpt->loginlevel[0])) return DC_ERROR;
7764 multimode = multimode_capable(myrpt);
7766 switch(p){
7768 case 1: /* retrieve memory */
7769 if(strlen(digitbuf) < 2) /* needs 2 digits */
7770 break;
7772 for(i = 0 ; i < 2 ; i++){
7773 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
7774 return DC_ERROR;
7777 r = retreive_memory(myrpt, digitbuf);
7778 if (r < 0){
7779 rpt_telemetry(myrpt,MEMNOTFOUND,NULL);
7780 return DC_COMPLETE;
7782 if (r > 0){
7783 return DC_ERROR;
7785 if (setrem(myrpt) == -1) return DC_ERROR;
7786 return DC_COMPLETE;
7788 case 2: /* set freq and offset */
7791 for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for M+*K+*O or M+*H+* depending on mode */
7792 if(digitbuf[i] == '*'){
7793 j++;
7794 continue;
7796 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
7797 goto invalid_freq;
7798 else{
7799 if(j == 0)
7800 l++; /* # of digits before first * */
7801 if(j == 1)
7802 k++; /* # of digits after first * */
7806 i = strlen(digitbuf) - 1;
7807 if(multimode){
7808 if((j > 2) || (l > 3) || (k > 6))
7809 goto invalid_freq; /* &^@#! */
7811 else{
7812 if((j > 2) || (l > 4) || (k > 3))
7813 goto invalid_freq; /* &^@#! */
7816 /* Wait for M+*K+* */
7818 if(j < 2)
7819 break; /* Not yet */
7821 /* We have a frequency */
7823 strncpy(tmp, digitbuf ,sizeof(tmp) - 1);
7825 s = tmp;
7826 s1 = strsep(&s, "*"); /* Pick off MHz */
7827 s2 = strsep(&s,"*"); /* Pick off KHz and Hz */
7828 ls2 = strlen(s2);
7830 switch(ls2){ /* Allow partial entry of khz and hz digits for laziness support */
7831 case 1:
7832 ht = 0;
7833 k = 100 * atoi(s2);
7834 break;
7836 case 2:
7837 ht = 0;
7838 k = 10 * atoi(s2);
7839 break;
7841 case 3:
7842 if(!multimode){
7843 if((s2[2] != '0')&&(s2[2] != '5'))
7844 goto invalid_freq;
7846 ht = 0;
7847 k = atoi(s2);
7848 break;
7849 case 4:
7850 k = atoi(s2)/10;
7851 ht = 10 * (atoi(s2+(ls2-1)));
7852 break;
7854 case 5:
7855 k = atoi(s2)/100;
7856 ht = (atoi(s2+(ls2-2)));
7857 break;
7859 default:
7860 goto invalid_freq;
7863 /* Check frequency for validity and establish a default mode */
7865 snprintf(freq, sizeof(freq), "%s.%03d%02d",s1, k, ht);
7867 if(debug)
7868 printf("New frequency: %s\n", freq);
7870 split_freq(mhz, decimals, freq);
7871 m = atoi(mhz);
7872 d = atoi(decimals);
7874 if(check_freq(myrpt, m, d, &defmode)) /* Check to see if frequency entered is legit */
7875 goto invalid_freq;
7878 if((defmode == REM_MODE_FM) && (digitbuf[i] == '*')) /* If FM, user must enter and additional offset digit */
7879 break; /* Not yet */
7882 offset = REM_SIMPLEX; /* Assume simplex */
7884 if(defmode == REM_MODE_FM){
7885 oc = *s; /* Pick off offset */
7887 if (oc){
7888 switch(oc){
7889 case '1':
7890 offset = REM_MINUS;
7891 break;
7893 case '2':
7894 offset = REM_SIMPLEX;
7895 break;
7897 case '3':
7898 offset = REM_PLUS;
7899 break;
7901 default:
7902 goto invalid_freq;
7906 offsave = myrpt->offset;
7907 modesave = myrpt->remmode;
7908 strncpy(savestr, myrpt->freq, sizeof(savestr) - 1);
7909 strncpy(myrpt->freq, freq, sizeof(myrpt->freq) - 1);
7910 myrpt->offset = offset;
7911 myrpt->remmode = defmode;
7913 if (setrem(myrpt) == -1){
7914 myrpt->offset = offsave;
7915 myrpt->remmode = modesave;
7916 strncpy(myrpt->freq, savestr, sizeof(myrpt->freq) - 1);
7917 goto invalid_freq;
7920 return DC_COMPLETE;
7922 invalid_freq:
7923 rpt_telemetry(myrpt,INVFREQ,NULL);
7924 return DC_ERROR;
7926 case 3: /* set rx PL tone */
7927 for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
7928 if(digitbuf[i] == '*'){
7929 j++;
7930 continue;
7932 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
7933 return DC_ERROR;
7934 else{
7935 if(j)
7936 l++;
7937 else
7938 k++;
7941 if((j > 1) || (k > 3) || (l > 1))
7942 return DC_ERROR; /* &$@^! */
7943 i = strlen(digitbuf) - 1;
7944 if((j != 1) || (k < 2)|| (l != 1))
7945 break; /* Not yet */
7946 if(debug)
7947 printf("PL digits entered %s\n", digitbuf);
7949 strncpy(tmp, digitbuf, sizeof(tmp) - 1);
7950 /* see if we have at least 1 */
7951 s = strchr(tmp,'*');
7952 if(s)
7953 *s = '.';
7954 strncpy(savestr, myrpt->rxpl, sizeof(savestr) - 1);
7955 strncpy(myrpt->rxpl, tmp, sizeof(myrpt->rxpl) - 1);
7956 if(!strcmp(myrpt->remote, remote_rig_rbi))
7958 strncpy(myrpt->txpl, tmp, sizeof(myrpt->txpl) - 1);
7960 if (setrem(myrpt) == -1){
7961 strncpy(myrpt->rxpl, savestr, sizeof(myrpt->rxpl) - 1);
7962 return DC_ERROR;
7966 return DC_COMPLETE;
7968 case 4: /* set tx PL tone */
7969 /* cant set tx tone on RBI (rx tone does both) */
7970 if(!strcmp(myrpt->remote, remote_rig_rbi))
7971 return DC_ERROR;
7972 if(!strcmp(myrpt->remote, remote_rig_ic706))
7973 return DC_ERROR;
7974 for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
7975 if(digitbuf[i] == '*'){
7976 j++;
7977 continue;
7979 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
7980 return DC_ERROR;
7981 else{
7982 if(j)
7983 l++;
7984 else
7985 k++;
7988 if((j > 1) || (k > 3) || (l > 1))
7989 return DC_ERROR; /* &$@^! */
7990 i = strlen(digitbuf) - 1;
7991 if((j != 1) || (k < 2)|| (l != 1))
7992 break; /* Not yet */
7993 if(debug)
7994 printf("PL digits entered %s\n", digitbuf);
7996 strncpy(tmp, digitbuf, sizeof(tmp) - 1);
7997 /* see if we have at least 1 */
7998 s = strchr(tmp,'*');
7999 if(s)
8000 *s = '.';
8001 strncpy(savestr, myrpt->txpl, sizeof(savestr) - 1);
8002 strncpy(myrpt->txpl, tmp, sizeof(myrpt->txpl) - 1);
8004 if (setrem(myrpt) == -1){
8005 strncpy(myrpt->txpl, savestr, sizeof(myrpt->txpl) - 1);
8006 return DC_ERROR;
8010 return DC_COMPLETE;
8013 case 6: /* MODE (FM,USB,LSB,AM) */
8014 if(strlen(digitbuf) < 1)
8015 break;
8017 if(!multimode)
8018 return DC_ERROR; /* Multimode radios only */
8020 switch(*digitbuf){
8021 case '1':
8022 split_freq(mhz, decimals, myrpt->freq);
8023 m=atoi(mhz);
8024 if(m < 29) /* No FM allowed below 29MHz! */
8025 return DC_ERROR;
8026 myrpt->remmode = REM_MODE_FM;
8028 rpt_telemetry(myrpt,REMMODE,NULL);
8029 break;
8031 case '2':
8032 myrpt->remmode = REM_MODE_USB;
8033 rpt_telemetry(myrpt,REMMODE,NULL);
8034 break;
8036 case '3':
8037 myrpt->remmode = REM_MODE_LSB;
8038 rpt_telemetry(myrpt,REMMODE,NULL);
8039 break;
8041 case '4':
8042 myrpt->remmode = REM_MODE_AM;
8043 rpt_telemetry(myrpt,REMMODE,NULL);
8044 break;
8046 default:
8047 return DC_ERROR;
8050 if(setrem(myrpt))
8051 return DC_ERROR;
8052 return DC_COMPLETEQUIET;
8053 case 99:
8054 /* cant log in when logged in */
8055 if (myrpt->loginlevel[0])
8056 return DC_ERROR;
8057 *myrpt->loginuser = 0;
8058 myrpt->loginlevel[0] = 0;
8059 cp = strdup(param);
8060 cp1 = strchr(cp,',');
8061 ast_mutex_lock(&myrpt->lock);
8062 if (cp1)
8064 *cp1 = 0;
8065 cp2 = strchr(cp1 + 1,',');
8066 if (cp2)
8068 *cp2 = 0;
8069 strncpy(myrpt->loginlevel,cp2 + 1,
8070 sizeof(myrpt->loginlevel) - 1);
8072 strncpy(myrpt->loginuser,cp1 + 1,sizeof(myrpt->loginuser));
8073 ast_mutex_unlock(&myrpt->lock);
8074 if (myrpt->p.archivedir)
8076 char str[100];
8078 sprintf(str,"LOGIN,%s,%s",
8079 myrpt->loginuser,myrpt->loginlevel);
8080 donodelog(myrpt,str);
8082 if (debug)
8083 printf("loginuser %s level %s\n",myrpt->loginuser,myrpt->loginlevel);
8084 rpt_telemetry(myrpt,REMLOGIN,NULL);
8086 free(cp);
8087 return DC_COMPLETEQUIET;
8088 case 100: /* RX PL Off */
8089 myrpt->rxplon = 0;
8090 setrem(myrpt);
8091 rpt_telemetry(myrpt,REMXXX,(void *)p);
8092 return DC_COMPLETEQUIET;
8093 case 101: /* RX PL On */
8094 myrpt->rxplon = 1;
8095 setrem(myrpt);
8096 rpt_telemetry(myrpt,REMXXX,(void *)p);
8097 return DC_COMPLETEQUIET;
8098 case 102: /* TX PL Off */
8099 myrpt->txplon = 0;
8100 setrem(myrpt);
8101 rpt_telemetry(myrpt,REMXXX,(void *)p);
8102 return DC_COMPLETEQUIET;
8103 case 103: /* TX PL On */
8104 myrpt->txplon = 1;
8105 setrem(myrpt);
8106 rpt_telemetry(myrpt,REMXXX,(void *)p);
8107 return DC_COMPLETEQUIET;
8108 case 104: /* Low Power */
8109 if(!strcmp(myrpt->remote, remote_rig_ic706))
8110 return DC_ERROR;
8111 myrpt->powerlevel = REM_LOWPWR;
8112 setrem(myrpt);
8113 rpt_telemetry(myrpt,REMXXX,(void *)p);
8114 return DC_COMPLETEQUIET;
8115 case 105: /* Medium Power */
8116 if(!strcmp(myrpt->remote, remote_rig_ic706))
8117 return DC_ERROR;
8118 myrpt->powerlevel = REM_MEDPWR;
8119 setrem(myrpt);
8120 rpt_telemetry(myrpt,REMXXX,(void *)p);
8121 return DC_COMPLETEQUIET;
8122 case 106: /* Hi Power */
8123 if(!strcmp(myrpt->remote, remote_rig_ic706))
8124 return DC_ERROR;
8125 myrpt->powerlevel = REM_HIPWR;
8126 setrem(myrpt);
8127 rpt_telemetry(myrpt,REMXXX,(void *)p);
8128 return DC_COMPLETEQUIET;
8129 case 107: /* Bump down 20Hz */
8130 multimode_bump_freq(myrpt, -20);
8131 return DC_COMPLETE;
8132 case 108: /* Bump down 100Hz */
8133 multimode_bump_freq(myrpt, -100);
8134 return DC_COMPLETE;
8135 case 109: /* Bump down 500Hz */
8136 multimode_bump_freq(myrpt, -500);
8137 return DC_COMPLETE;
8138 case 110: /* Bump up 20Hz */
8139 multimode_bump_freq(myrpt, 20);
8140 return DC_COMPLETE;
8141 case 111: /* Bump up 100Hz */
8142 multimode_bump_freq(myrpt, 100);
8143 return DC_COMPLETE;
8144 case 112: /* Bump up 500Hz */
8145 multimode_bump_freq(myrpt, 500);
8146 return DC_COMPLETE;
8147 case 113: /* Scan down slow */
8148 myrpt->scantimer = REM_SCANTIME;
8149 myrpt->hfscanmode = HF_SCAN_DOWN_SLOW;
8150 rpt_telemetry(myrpt,REMXXX,(void *)p);
8151 return DC_COMPLETEQUIET;
8152 case 114: /* Scan down quick */
8153 myrpt->scantimer = REM_SCANTIME;
8154 myrpt->hfscanmode = HF_SCAN_DOWN_QUICK;
8155 rpt_telemetry(myrpt,REMXXX,(void *)p);
8156 return DC_COMPLETEQUIET;
8157 case 115: /* Scan down fast */
8158 myrpt->scantimer = REM_SCANTIME;
8159 myrpt->hfscanmode = HF_SCAN_DOWN_FAST;
8160 rpt_telemetry(myrpt,REMXXX,(void *)p);
8161 return DC_COMPLETEQUIET;
8162 case 116: /* Scan up slow */
8163 myrpt->scantimer = REM_SCANTIME;
8164 myrpt->hfscanmode = HF_SCAN_UP_SLOW;
8165 rpt_telemetry(myrpt,REMXXX,(void *)p);
8166 return DC_COMPLETEQUIET;
8167 case 117: /* Scan up quick */
8168 myrpt->scantimer = REM_SCANTIME;
8169 myrpt->hfscanmode = HF_SCAN_UP_QUICK;
8170 rpt_telemetry(myrpt,REMXXX,(void *)p);
8171 return DC_COMPLETEQUIET;
8172 case 118: /* Scan up fast */
8173 myrpt->scantimer = REM_SCANTIME;
8174 myrpt->hfscanmode = HF_SCAN_UP_FAST;
8175 rpt_telemetry(myrpt,REMXXX,(void *)p);
8176 return DC_COMPLETEQUIET;
8177 case 119: /* Tune Request */
8178 /* if not currently going, and valid to do */
8179 if((!myrpt->tunerequest) &&
8180 ((!strcmp(myrpt->remote, remote_rig_ft897) ||
8181 !strcmp(myrpt->remote, remote_rig_ic706)) )) {
8182 myrpt->remotetx = 0;
8183 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
8184 myrpt->tunerequest = 1;
8185 rpt_telemetry(myrpt,TUNE,NULL);
8186 return DC_COMPLETEQUIET;
8188 return DC_ERROR;
8189 case 5: /* Long Status */
8190 rpt_telemetry(myrpt,REMLONGSTATUS,NULL);
8191 return DC_COMPLETEQUIET;
8192 case 140: /* Short Status */
8193 rpt_telemetry(myrpt,REMSHORTSTATUS,NULL);
8194 return DC_COMPLETEQUIET;
8195 case 200:
8196 case 201:
8197 case 202:
8198 case 203:
8199 case 204:
8200 case 205:
8201 case 206:
8202 case 207:
8203 case 208:
8204 case 209:
8205 case 210:
8206 case 211:
8207 case 212:
8208 case 213:
8209 case 214:
8210 case 215:
8211 do_dtmf_local(myrpt,remdtmfstr[p - 200]);
8212 return DC_COMPLETEQUIET;
8213 default:
8214 break;
8216 return DC_INDETERMINATE;
8220 static int handle_remote_dtmf_digit(struct rpt *myrpt,char c, char *keyed, int phonemode)
8222 time_t now;
8223 int ret,res = 0,src;
8225 time(&myrpt->last_activity_time);
8226 /* Stop scan mode if in scan mode */
8227 if(myrpt->hfscanmode){
8228 stop_scan(myrpt);
8229 return 0;
8232 time(&now);
8233 /* if timed-out */
8234 if ((myrpt->dtmf_time_rem + DTMF_TIMEOUT) < now)
8236 myrpt->dtmfidx = -1;
8237 myrpt->dtmfbuf[0] = 0;
8238 myrpt->dtmf_time_rem = 0;
8240 /* if decode not active */
8241 if (myrpt->dtmfidx == -1)
8243 /* if not lead-in digit, dont worry */
8244 if (c != myrpt->p.funcchar)
8246 if (!myrpt->p.propagate_dtmf)
8248 rpt_mutex_lock(&myrpt->lock);
8249 do_dtmf_local(myrpt,c);
8250 rpt_mutex_unlock(&myrpt->lock);
8252 return 0;
8254 myrpt->dtmfidx = 0;
8255 myrpt->dtmfbuf[0] = 0;
8256 myrpt->dtmf_time_rem = now;
8257 return 0;
8259 /* if too many in buffer, start over */
8260 if (myrpt->dtmfidx >= MAXDTMF)
8262 myrpt->dtmfidx = 0;
8263 myrpt->dtmfbuf[0] = 0;
8264 myrpt->dtmf_time_rem = now;
8266 if (c == myrpt->p.funcchar)
8268 /* if star at beginning, or 2 together, erase buffer */
8269 if ((myrpt->dtmfidx < 1) ||
8270 (myrpt->dtmfbuf[myrpt->dtmfidx - 1] == myrpt->p.funcchar))
8272 myrpt->dtmfidx = 0;
8273 myrpt->dtmfbuf[0] = 0;
8274 myrpt->dtmf_time_rem = now;
8275 return 0;
8278 myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
8279 myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
8280 myrpt->dtmf_time_rem = now;
8283 src = SOURCE_RMT;
8284 if (phonemode > 1) src = SOURCE_DPHONE;
8285 else if (phonemode) src = SOURCE_PHONE;
8286 ret = collect_function_digits(myrpt, myrpt->dtmfbuf, src, NULL);
8288 switch(ret){
8290 case DC_INDETERMINATE:
8291 res = 0;
8292 break;
8294 case DC_DOKEY:
8295 if (keyed) *keyed = 1;
8296 res = 0;
8297 break;
8299 case DC_REQ_FLUSH:
8300 myrpt->dtmfidx = 0;
8301 myrpt->dtmfbuf[0] = 0;
8302 res = 0;
8303 break;
8306 case DC_COMPLETE:
8307 res = 1;
8308 case DC_COMPLETEQUIET:
8309 myrpt->totalexecdcommands++;
8310 myrpt->dailyexecdcommands++;
8311 strncpy(myrpt->lastdtmfcommand, myrpt->dtmfbuf, MAXDTMF-1);
8312 myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
8313 myrpt->dtmfbuf[0] = 0;
8314 myrpt->dtmfidx = -1;
8315 myrpt->dtmf_time_rem = 0;
8316 break;
8318 case DC_ERROR:
8319 default:
8320 myrpt->dtmfbuf[0] = 0;
8321 myrpt->dtmfidx = -1;
8322 myrpt->dtmf_time_rem = 0;
8323 res = 0;
8324 break;
8327 return res;
8330 static int handle_remote_data(struct rpt *myrpt, char *str)
8332 char tmp[300],cmd[300],dest[300],src[300],c;
8333 int seq,res;
8335 /* put string in our buffer */
8336 strncpy(tmp,str,sizeof(tmp) - 1);
8337 if (!strcmp(tmp,discstr)) return 0;
8339 #ifndef DO_NOT_NOTIFY_MDC1200_ON_REMOTE_BASES
8340 if (tmp[0] == 'I')
8342 if (sscanf(tmp,"%s %s %x",cmd,src,&seq) != 3)
8344 ast_log(LOG_WARNING, "Unable to parse ident string %s\n",str);
8345 return 0;
8347 mdc1200_notify(myrpt,src,seq);
8348 return 0;
8350 #endif
8351 if (sscanf(tmp,"%s %s %s %d %c",cmd,dest,src,&seq,&c) != 5)
8353 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
8354 return 0;
8356 if (strcmp(cmd,"D"))
8358 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
8359 return 0;
8361 /* if not for me, ignore */
8362 if (strcmp(dest,myrpt->name)) return 0;
8363 if (myrpt->p.archivedir)
8365 char str[100];
8367 sprintf(str,"DTMF,%c",c);
8368 donodelog(myrpt,str);
8370 c = func_xlat(myrpt,c,&myrpt->p.outxlat);
8371 if (!c) return(0);
8372 res = handle_remote_dtmf_digit(myrpt,c, NULL, 0);
8373 if (res != 1)
8374 return res;
8375 rpt_telemetry(myrpt,COMPLETE,NULL);
8376 return 0;
8379 static int handle_remote_phone_dtmf(struct rpt *myrpt, char c, char *keyed, int phonemode)
8381 int res;
8384 if (keyed && *keyed && (c == myrpt->p.endchar))
8386 *keyed = 0;
8387 return DC_INDETERMINATE;
8390 if (myrpt->p.archivedir)
8392 char str[100];
8394 sprintf(str,"DTMF(P),%c",c);
8395 donodelog(myrpt,str);
8397 res = handle_remote_dtmf_digit(myrpt,c,keyed, phonemode);
8398 if (res != 1)
8399 return res;
8400 rpt_telemetry(myrpt,COMPLETE,NULL);
8401 return 0;
8404 static int attempt_reconnect(struct rpt *myrpt, struct rpt_link *l)
8406 char *val, *s, *s1, *s2, *tele;
8407 char tmp[300], deststr[300] = "";
8409 val = node_lookup(myrpt,l->name);
8410 if (!val)
8412 fprintf(stderr,"attempt_reconnect: cannot find node %s\n",l->name);
8413 return -1;
8416 rpt_mutex_lock(&myrpt->lock);
8417 /* remove from queue */
8418 remque((struct qelem *) l);
8419 rpt_mutex_unlock(&myrpt->lock);
8420 strncpy(tmp,val,sizeof(tmp) - 1);
8421 s = tmp;
8422 s1 = strsep(&s,",");
8423 s2 = strsep(&s,",");
8424 snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
8425 tele = strchr(deststr, '/');
8426 if (!tele) {
8427 fprintf(stderr,"attempt_reconnect:Dial number (%s) must be in format tech/number\n",deststr);
8428 return -1;
8430 *tele++ = 0;
8431 l->elaptime = 0;
8432 l->connecttime = 0;
8433 l->thisconnected = 0;
8434 l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL);
8435 if (l->chan){
8436 ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
8437 ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
8438 l->chan->whentohangup = 0;
8439 l->chan->appl = "Apprpt";
8440 l->chan->data = "(Remote Rx)";
8441 if (option_verbose > 2)
8442 ast_verbose(VERBOSE_PREFIX_3 "rpt (attempt_reconnect) initiating call to %s/%s on %s\n",
8443 deststr, tele, l->chan->name);
8444 if(l->chan->cid.cid_num)
8445 free(l->chan->cid.cid_num);
8446 l->chan->cid.cid_num = strdup(myrpt->name);
8447 ast_call(l->chan,tele,999);
8450 else
8452 if (option_verbose > 2)
8453 ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
8454 deststr,tele,l->chan->name);
8455 return -1;
8457 rpt_mutex_lock(&myrpt->lock);
8458 /* put back in queue */
8459 insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
8460 rpt_mutex_unlock(&myrpt->lock);
8461 ast_log(LOG_NOTICE,"Reconnect Attempt to %s in process\n",l->name);
8462 return 0;
8465 /* 0 return=continue, 1 return = break, -1 return = error */
8466 static void local_dtmf_helper(struct rpt *myrpt,char c)
8468 int res;
8469 pthread_attr_t attr;
8470 char cmd[MAXDTMF+1] = "";
8472 if (myrpt->p.archivedir)
8474 char str[100];
8476 sprintf(str,"DTMF,MAIN,%c",c);
8477 donodelog(myrpt,str);
8479 if (c == myrpt->p.endchar)
8481 /* if in simple mode, kill autopatch */
8482 if (myrpt->p.simple && myrpt->callmode)
8484 rpt_mutex_lock(&myrpt->lock);
8485 myrpt->callmode = 0;
8486 rpt_mutex_unlock(&myrpt->lock);
8487 rpt_telemetry(myrpt,TERM,NULL);
8488 return;
8490 rpt_mutex_lock(&myrpt->lock);
8491 myrpt->stopgen = 1;
8492 if (myrpt->cmdnode[0])
8494 myrpt->cmdnode[0] = 0;
8495 myrpt->dtmfidx = -1;
8496 myrpt->dtmfbuf[0] = 0;
8497 rpt_mutex_unlock(&myrpt->lock);
8498 rpt_telemetry(myrpt,COMPLETE,NULL);
8500 else
8502 rpt_mutex_unlock(&myrpt->lock);
8503 if (myrpt->p.propagate_phonedtmf)
8504 do_dtmf_phone(myrpt,NULL,c);
8506 return;
8508 rpt_mutex_lock(&myrpt->lock);
8509 if (myrpt->cmdnode[0])
8511 rpt_mutex_unlock(&myrpt->lock);
8512 send_link_dtmf(myrpt,c);
8513 return;
8515 if (!myrpt->p.simple)
8517 if (c == myrpt->p.funcchar)
8519 myrpt->dtmfidx = 0;
8520 myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
8521 rpt_mutex_unlock(&myrpt->lock);
8522 time(&myrpt->dtmf_time);
8523 return;
8525 else if ((c != myrpt->p.endchar) && (myrpt->dtmfidx >= 0))
8527 time(&myrpt->dtmf_time);
8529 if (myrpt->dtmfidx < MAXDTMF)
8531 myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
8532 myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
8534 strncpy(cmd, myrpt->dtmfbuf, sizeof(cmd) - 1);
8536 rpt_mutex_unlock(&myrpt->lock);
8537 res = collect_function_digits(myrpt, cmd, SOURCE_RPT, NULL);
8538 rpt_mutex_lock(&myrpt->lock);
8539 switch(res){
8540 case DC_INDETERMINATE:
8541 break;
8542 case DC_REQ_FLUSH:
8543 myrpt->dtmfidx = 0;
8544 myrpt->dtmfbuf[0] = 0;
8545 break;
8546 case DC_COMPLETE:
8547 case DC_COMPLETEQUIET:
8548 myrpt->totalexecdcommands++;
8549 myrpt->dailyexecdcommands++;
8550 strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
8551 myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
8552 myrpt->dtmfbuf[0] = 0;
8553 myrpt->dtmfidx = -1;
8554 myrpt->dtmf_time = 0;
8555 break;
8557 case DC_ERROR:
8558 default:
8559 myrpt->dtmfbuf[0] = 0;
8560 myrpt->dtmfidx = -1;
8561 myrpt->dtmf_time = 0;
8562 break;
8564 if(res != DC_INDETERMINATE) {
8565 rpt_mutex_unlock(&myrpt->lock);
8566 return;
8571 else /* if simple */
8573 if ((!myrpt->callmode) && (c == myrpt->p.funcchar))
8575 myrpt->callmode = 1;
8576 myrpt->patchnoct = 0;
8577 myrpt->patchquiet = 0;
8578 myrpt->patchfarenddisconnect = 0;
8579 myrpt->patchdialtime = 0;
8580 strncpy(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
8581 myrpt->cidx = 0;
8582 myrpt->exten[myrpt->cidx] = 0;
8583 rpt_mutex_unlock(&myrpt->lock);
8584 pthread_attr_init(&attr);
8585 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
8586 ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *)myrpt);
8587 return;
8590 if (myrpt->callmode == 1)
8592 myrpt->exten[myrpt->cidx++] = c;
8593 myrpt->exten[myrpt->cidx] = 0;
8594 /* if this exists */
8595 if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
8597 myrpt->callmode = 2;
8598 rpt_mutex_unlock(&myrpt->lock);
8599 if(!myrpt->patchquiet)
8600 rpt_telemetry(myrpt,PROC,NULL);
8601 return;
8603 /* if can continue, do so */
8604 if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
8606 /* call has failed, inform user */
8607 myrpt->callmode = 4;
8609 rpt_mutex_unlock(&myrpt->lock);
8610 return;
8612 if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
8614 myrpt->mydtmf = c;
8616 rpt_mutex_unlock(&myrpt->lock);
8617 if ((myrpt->dtmfidx < 0) && myrpt->p.propagate_phonedtmf)
8618 do_dtmf_phone(myrpt,NULL,c);
8619 return;
8623 /* place an ID event in the telemetry queue */
8625 static void queue_id(struct rpt *myrpt)
8627 if(myrpt->p.idtime){ /* ID time must be non-zero */
8628 myrpt->mustid = myrpt->tailid = 0;
8629 myrpt->idtimer = myrpt->p.idtime; /* Reset our ID timer */
8630 rpt_mutex_unlock(&myrpt->lock);
8631 rpt_telemetry(myrpt,ID,NULL);
8632 rpt_mutex_lock(&myrpt->lock);
8636 /* Scheduler */
8637 /* must be called locked */
8639 static void do_scheduler(struct rpt *myrpt)
8641 int i,res;
8642 struct tm tmnow;
8643 struct ast_variable *skedlist;
8644 char *strs[5],*vp,*val,value[100];
8646 memcpy(&myrpt->lasttv, &myrpt->curtv, sizeof(struct timeval));
8648 if( (res = gettimeofday(&myrpt->curtv, NULL)) < 0)
8649 ast_log(LOG_NOTICE, "Scheduler gettime of day returned: %s\n", strerror(res));
8651 /* Try to get close to a 1 second resolution */
8653 if(myrpt->lasttv.tv_sec == myrpt->curtv.tv_sec)
8654 return;
8656 rpt_localtime(&myrpt->curtv.tv_sec, &tmnow);
8658 /* If midnight, then reset all daily statistics */
8660 if((tmnow.tm_hour == 0)&&(tmnow.tm_min == 0)&&(tmnow.tm_sec == 0)){
8661 myrpt->dailykeyups = 0;
8662 myrpt->dailytxtime = 0;
8663 myrpt->dailykerchunks = 0;
8664 myrpt->dailyexecdcommands = 0;
8667 if(tmnow.tm_sec != 0)
8668 return;
8670 /* Code below only executes once per minute */
8673 /* Don't schedule if remote */
8675 if (myrpt->remote)
8676 return;
8678 /* Don't schedule if disabled */
8680 if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable){
8681 if(debug > 6)
8682 ast_log(LOG_NOTICE, "Scheduler disabled\n");
8683 return;
8686 if(!myrpt->p.skedstanzaname){ /* No stanza means we do nothing */
8687 if(debug > 6)
8688 ast_log(LOG_NOTICE,"No stanza for scheduler in rpt.conf\n");
8689 return;
8692 /* get pointer to linked list of scheduler entries */
8693 skedlist = ast_variable_browse(myrpt->cfg, myrpt->p.skedstanzaname);
8695 if(debug > 6){
8696 ast_log(LOG_NOTICE, "Time now: %02d:%02d %02d %02d %02d\n",
8697 tmnow.tm_hour,tmnow.tm_min,tmnow.tm_mday,tmnow.tm_mon + 1, tmnow.tm_wday);
8699 /* walk the list */
8700 for(; skedlist; skedlist = skedlist->next){
8701 if(debug > 6)
8702 ast_log(LOG_NOTICE, "Scheduler entry %s = %s being considered\n",skedlist->name, skedlist->value);
8703 strncpy(value,skedlist->value,99);
8704 value[99] = 0;
8705 /* point to the substrings for minute, hour, dom, month, and dow */
8706 for( i = 0, vp = value ; i < 5; i++){
8707 if(!*vp)
8708 break;
8709 while((*vp == ' ') || (*vp == 0x09)) /* get rid of any leading white space */
8710 vp++;
8711 strs[i] = vp; /* save pointer to beginning of substring */
8712 while((*vp != ' ') && (*vp != 0x09) && (*vp != 0)) /* skip over substring */
8713 vp++;
8714 if(*vp)
8715 *vp++ = 0; /* mark end of substring */
8717 if(debug > 6)
8718 ast_log(LOG_NOTICE, "i = %d, min = %s, hour = %s, mday=%s, mon=%s, wday=%s\n",i,
8719 strs[0], strs[1], strs[2], strs[3], strs[4]);
8720 if(i == 5){
8721 if((*strs[0] != '*')&&(atoi(strs[0]) != tmnow.tm_min))
8722 continue;
8723 if((*strs[1] != '*')&&(atoi(strs[1]) != tmnow.tm_hour))
8724 continue;
8725 if((*strs[2] != '*')&&(atoi(strs[2]) != tmnow.tm_mday))
8726 continue;
8727 if((*strs[3] != '*')&&(atoi(strs[3]) != tmnow.tm_mon + 1))
8728 continue;
8729 if(atoi(strs[4]) == 7)
8730 strs[4] = "0";
8731 if((*strs[4] != '*')&&(atoi(strs[4]) != tmnow.tm_wday))
8732 continue;
8733 if(debug)
8734 ast_log(LOG_NOTICE, "Executing scheduler entry %s = %s\n", skedlist->name, skedlist->value);
8735 if(atoi(skedlist->name) == 0)
8736 return; /* Zero is reserved for the startup macro */
8737 val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, skedlist->name);
8738 if (!val){
8739 ast_log(LOG_WARNING,"Scheduler could not find macro %s\n",skedlist->name);
8740 return; /* Macro not found */
8742 if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val)){
8743 ast_log(LOG_WARNING, "Scheduler could not execute macro %s: Macro buffer full\n",
8744 skedlist->name);
8745 return; /* Macro buffer full */
8747 myrpt->macrotimer = MACROTIME;
8748 strncat(myrpt->macrobuf,val,MAXMACRO - strlen(myrpt->macrobuf) - 1);
8750 else{
8751 ast_log(LOG_WARNING,"Malformed scheduler entry in rpt.conf: %s = %s\n",
8752 skedlist->name, skedlist->value);
8758 /* single thread with one file (request) to dial */
8759 static void *rpt(void *this)
8761 struct rpt *myrpt = (struct rpt *)this;
8762 char *tele,*idtalkover,c;
8763 int ms = MSWAIT,i,lasttx=0,val,remrx=0,identqueued,othertelemqueued;
8764 int tailmessagequeued,ctqueued,dtmfed;
8765 struct ast_channel *who;
8766 DAHDI_CONFINFO ci; /* conference info */
8767 time_t t;
8768 struct rpt_link *l,*m;
8769 struct rpt_tele *telem;
8770 char tmpstr[300],lstr[MAXLINKLIST];
8773 if (myrpt->p.archivedir) mkdir(myrpt->p.archivedir,0600);
8774 sprintf(tmpstr,"%s/%s",myrpt->p.archivedir,myrpt->name);
8775 mkdir(tmpstr,0600);
8776 rpt_mutex_lock(&myrpt->lock);
8778 telem = myrpt->tele.next;
8779 while(telem != &myrpt->tele)
8781 ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
8782 telem = telem->next;
8784 rpt_mutex_unlock(&myrpt->lock);
8785 /* find our index, and load the vars initially */
8786 for(i = 0; i < nrpts; i++)
8788 if (&rpt_vars[i] == myrpt)
8790 load_rpt_vars(i,0);
8791 break;
8794 rpt_mutex_lock(&myrpt->lock);
8795 strncpy(tmpstr,myrpt->rxchanname,sizeof(tmpstr) - 1);
8796 tele = strchr(tmpstr,'/');
8797 if (!tele)
8799 fprintf(stderr,"rpt:Rxchannel Dial number (%s) must be in format tech/number\n",myrpt->rxchanname);
8800 rpt_mutex_unlock(&myrpt->lock);
8801 myrpt->rpt_thread = AST_PTHREADT_STOP;
8802 pthread_exit(NULL);
8804 *tele++ = 0;
8805 myrpt->rxchannel = ast_request(tmpstr,AST_FORMAT_SLINEAR,tele,NULL);
8806 myrpt->zaprxchannel = NULL;
8807 if (!strcasecmp(tmpstr,"Zap"))
8808 myrpt->zaprxchannel = myrpt->rxchannel;
8809 if (myrpt->rxchannel)
8811 if (myrpt->rxchannel->_state == AST_STATE_BUSY)
8813 fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
8814 rpt_mutex_unlock(&myrpt->lock);
8815 ast_hangup(myrpt->rxchannel);
8816 myrpt->rpt_thread = AST_PTHREADT_STOP;
8817 pthread_exit(NULL);
8819 ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
8820 ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
8821 #ifdef AST_CDR_FLAG_POST_DISABLED
8822 ast_set_flag(myrpt->rxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
8823 #endif
8824 myrpt->rxchannel->whentohangup = 0;
8825 myrpt->rxchannel->appl = "Apprpt";
8826 myrpt->rxchannel->data = "(Repeater Rx)";
8827 if (option_verbose > 2)
8828 ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
8829 tmpstr,tele,myrpt->rxchannel->name);
8830 ast_call(myrpt->rxchannel,tele,999);
8831 if (myrpt->rxchannel->_state != AST_STATE_UP)
8833 rpt_mutex_unlock(&myrpt->lock);
8834 ast_hangup(myrpt->rxchannel);
8835 myrpt->rpt_thread = AST_PTHREADT_STOP;
8836 pthread_exit(NULL);
8839 else
8841 fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
8842 rpt_mutex_unlock(&myrpt->lock);
8843 myrpt->rpt_thread = AST_PTHREADT_STOP;
8844 pthread_exit(NULL);
8846 myrpt->zaptxchannel = NULL;
8847 if (myrpt->txchanname)
8849 strncpy(tmpstr,myrpt->txchanname,sizeof(tmpstr) - 1);
8850 tele = strchr(tmpstr,'/');
8851 if (!tele)
8853 fprintf(stderr,"rpt:Txchannel Dial number (%s) must be in format tech/number\n",myrpt->txchanname);
8854 rpt_mutex_unlock(&myrpt->lock);
8855 ast_hangup(myrpt->rxchannel);
8856 myrpt->rpt_thread = AST_PTHREADT_STOP;
8857 pthread_exit(NULL);
8859 *tele++ = 0;
8860 myrpt->txchannel = ast_request(tmpstr,AST_FORMAT_SLINEAR,tele,NULL);
8861 if (!strcasecmp(tmpstr,"Zap"))
8862 myrpt->zaptxchannel = myrpt->txchannel;
8863 if (myrpt->txchannel)
8865 if (myrpt->txchannel->_state == AST_STATE_BUSY)
8867 fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
8868 rpt_mutex_unlock(&myrpt->lock);
8869 ast_hangup(myrpt->txchannel);
8870 ast_hangup(myrpt->rxchannel);
8871 myrpt->rpt_thread = AST_PTHREADT_STOP;
8872 pthread_exit(NULL);
8874 ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
8875 ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
8876 #ifdef AST_CDR_FLAG_POST_DISABLED
8877 ast_set_flag(myrpt->txchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
8878 #endif
8879 myrpt->txchannel->whentohangup = 0;
8880 myrpt->txchannel->appl = "Apprpt";
8881 myrpt->txchannel->data = "(Repeater Tx)";
8882 if (option_verbose > 2)
8883 ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
8884 tmpstr,tele,myrpt->txchannel->name);
8885 ast_call(myrpt->txchannel,tele,999);
8886 if (myrpt->rxchannel->_state != AST_STATE_UP)
8888 rpt_mutex_unlock(&myrpt->lock);
8889 ast_hangup(myrpt->rxchannel);
8890 ast_hangup(myrpt->txchannel);
8891 myrpt->rpt_thread = AST_PTHREADT_STOP;
8892 pthread_exit(NULL);
8895 else
8897 fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
8898 rpt_mutex_unlock(&myrpt->lock);
8899 ast_hangup(myrpt->rxchannel);
8900 myrpt->rpt_thread = AST_PTHREADT_STOP;
8901 pthread_exit(NULL);
8904 else
8906 myrpt->txchannel = myrpt->rxchannel;
8908 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
8909 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
8910 /* allocate a pseudo-channel thru asterisk */
8911 myrpt->pchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
8912 if (!myrpt->pchannel)
8914 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
8915 rpt_mutex_unlock(&myrpt->lock);
8916 if (myrpt->txchannel != myrpt->rxchannel)
8917 ast_hangup(myrpt->txchannel);
8918 ast_hangup(myrpt->rxchannel);
8919 myrpt->rpt_thread = AST_PTHREADT_STOP;
8920 pthread_exit(NULL);
8922 #ifdef AST_CDR_FLAG_POST_DISABLED
8923 ast_set_flag(myrpt->pchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
8924 #endif
8925 if (!myrpt->zaprxchannel) myrpt->zaprxchannel = myrpt->pchannel;
8926 if (!myrpt->zaptxchannel)
8928 /* allocate a pseudo-channel thru asterisk */
8929 myrpt->zaptxchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
8930 if (!myrpt->zaptxchannel)
8932 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
8933 rpt_mutex_unlock(&myrpt->lock);
8934 if (myrpt->txchannel != myrpt->rxchannel)
8935 ast_hangup(myrpt->txchannel);
8936 ast_hangup(myrpt->rxchannel);
8937 myrpt->rpt_thread = AST_PTHREADT_STOP;
8938 pthread_exit(NULL);
8940 ast_set_read_format(myrpt->zaptxchannel,AST_FORMAT_SLINEAR);
8941 ast_set_write_format(myrpt->zaptxchannel,AST_FORMAT_SLINEAR);
8942 #ifdef AST_CDR_FLAG_POST_DISABLED
8943 ast_set_flag(myrpt->zaptxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
8944 #endif
8946 /* allocate a pseudo-channel thru asterisk */
8947 myrpt->monchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
8948 if (!myrpt->monchannel)
8950 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
8951 rpt_mutex_unlock(&myrpt->lock);
8952 if (myrpt->txchannel != myrpt->rxchannel)
8953 ast_hangup(myrpt->txchannel);
8954 ast_hangup(myrpt->rxchannel);
8955 myrpt->rpt_thread = AST_PTHREADT_STOP;
8956 pthread_exit(NULL);
8958 ast_set_read_format(myrpt->monchannel,AST_FORMAT_SLINEAR);
8959 ast_set_write_format(myrpt->monchannel,AST_FORMAT_SLINEAR);
8960 #ifdef AST_CDR_FLAG_POST_DISABLED
8961 ast_set_flag(myrpt->monchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
8962 #endif
8963 /* make a conference for the tx */
8964 ci.chan = 0;
8965 ci.confno = -1; /* make a new conf */
8966 ci.confmode = DAHDI_CONF_CONF | ZT_CONF_LISTENER;
8967 /* first put the channel on the conference in proper mode */
8968 if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
8970 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
8971 rpt_mutex_unlock(&myrpt->lock);
8972 ast_hangup(myrpt->pchannel);
8973 ast_hangup(myrpt->monchannel);
8974 if (myrpt->txchannel != myrpt->rxchannel)
8975 ast_hangup(myrpt->txchannel);
8976 ast_hangup(myrpt->rxchannel);
8977 myrpt->rpt_thread = AST_PTHREADT_STOP;
8978 pthread_exit(NULL);
8980 /* save tx conference number */
8981 myrpt->txconf = ci.confno;
8982 /* make a conference for the pseudo */
8983 ci.chan = 0;
8984 ci.confno = -1; /* make a new conf */
8985 ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? DAHDI_CONF_CONFANNMON :
8986 (DAHDI_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER);
8987 /* first put the channel on the conference in announce mode */
8988 if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
8990 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
8991 rpt_mutex_unlock(&myrpt->lock);
8992 ast_hangup(myrpt->pchannel);
8993 ast_hangup(myrpt->monchannel);
8994 if (myrpt->txchannel != myrpt->rxchannel)
8995 ast_hangup(myrpt->txchannel);
8996 ast_hangup(myrpt->rxchannel);
8997 myrpt->rpt_thread = AST_PTHREADT_STOP;
8998 pthread_exit(NULL);
9000 /* save pseudo channel conference number */
9001 myrpt->conf = ci.confno;
9002 /* make a conference for the pseudo */
9003 ci.chan = 0;
9004 if ((strstr(myrpt->txchannel->name,"pseudo") == NULL) &&
9005 (myrpt->zaptxchannel == myrpt->txchannel))
9007 /* get tx channel's port number */
9008 if (ioctl(myrpt->txchannel->fds[0],DAHDI_CHANNO,&ci.confno) == -1)
9010 ast_log(LOG_WARNING, "Unable to set tx channel's chan number\n");
9011 rpt_mutex_unlock(&myrpt->lock);
9012 ast_hangup(myrpt->pchannel);
9013 ast_hangup(myrpt->monchannel);
9014 if (myrpt->txchannel != myrpt->rxchannel)
9015 ast_hangup(myrpt->txchannel);
9016 ast_hangup(myrpt->rxchannel);
9017 myrpt->rpt_thread = AST_PTHREADT_STOP;
9018 pthread_exit(NULL);
9020 ci.confmode = DAHDI_CONF_MONITORTX;
9022 else
9024 ci.confno = myrpt->txconf;
9025 ci.confmode = DAHDI_CONF_CONFANNMON;
9027 /* first put the channel on the conference in announce mode */
9028 if (ioctl(myrpt->monchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
9030 ast_log(LOG_WARNING, "Unable to set conference mode for monitor\n");
9031 rpt_mutex_unlock(&myrpt->lock);
9032 ast_hangup(myrpt->pchannel);
9033 ast_hangup(myrpt->monchannel);
9034 if (myrpt->txchannel != myrpt->rxchannel)
9035 ast_hangup(myrpt->txchannel);
9036 ast_hangup(myrpt->rxchannel);
9037 myrpt->rpt_thread = AST_PTHREADT_STOP;
9038 pthread_exit(NULL);
9040 /* allocate a pseudo-channel thru asterisk */
9041 myrpt->txpchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
9042 if (!myrpt->txpchannel)
9044 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
9045 rpt_mutex_unlock(&myrpt->lock);
9046 ast_hangup(myrpt->pchannel);
9047 ast_hangup(myrpt->monchannel);
9048 if (myrpt->txchannel != myrpt->rxchannel)
9049 ast_hangup(myrpt->txchannel);
9050 ast_hangup(myrpt->rxchannel);
9051 myrpt->rpt_thread = AST_PTHREADT_STOP;
9052 pthread_exit(NULL);
9054 #ifdef AST_CDR_FLAG_POST_DISABLED
9055 ast_set_flag(myrpt->txpchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
9056 #endif
9057 /* make a conference for the tx */
9058 ci.chan = 0;
9059 ci.confno = myrpt->txconf;
9060 ci.confmode = DAHDI_CONF_CONF | ZT_CONF_TALKER ;
9061 /* first put the channel on the conference in proper mode */
9062 if (ioctl(myrpt->txpchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
9064 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
9065 rpt_mutex_unlock(&myrpt->lock);
9066 ast_hangup(myrpt->txpchannel);
9067 ast_hangup(myrpt->monchannel);
9068 if (myrpt->txchannel != myrpt->rxchannel)
9069 ast_hangup(myrpt->txchannel);
9070 ast_hangup(myrpt->rxchannel);
9071 myrpt->rpt_thread = AST_PTHREADT_STOP;
9072 pthread_exit(NULL);
9074 /* Now, the idea here is to copy from the physical rx channel buffer
9075 into the pseudo tx buffer, and from the pseudo rx buffer into the
9076 tx channel buffer */
9077 myrpt->links.next = &myrpt->links;
9078 myrpt->links.prev = &myrpt->links;
9079 myrpt->tailtimer = 0;
9080 myrpt->totimer = 0;
9081 myrpt->tmsgtimer = myrpt->p.tailmessagetime;
9082 myrpt->idtimer = myrpt->p.politeid;
9083 myrpt->mustid = myrpt->tailid = 0;
9084 myrpt->callmode = 0;
9085 myrpt->tounkeyed = 0;
9086 myrpt->tonotify = 0;
9087 myrpt->retxtimer = 0;
9088 myrpt->rerxtimer = 0;
9089 myrpt->skedtimer = 0;
9090 myrpt->tailevent = 0;
9091 lasttx = 0;
9092 myrpt->keyed = 0;
9093 idtalkover = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "idtalkover");
9094 myrpt->dtmfidx = -1;
9095 myrpt->dtmfbuf[0] = 0;
9096 myrpt->rem_dtmfidx = -1;
9097 myrpt->rem_dtmfbuf[0] = 0;
9098 myrpt->dtmf_time = 0;
9099 myrpt->rem_dtmf_time = 0;
9100 myrpt->disgorgetime = 0;
9101 myrpt->lastnodewhichkeyedusup[0] = '\0';
9102 myrpt->dailytxtime = 0;
9103 myrpt->totaltxtime = 0;
9104 myrpt->dailykeyups = 0;
9105 myrpt->totalkeyups = 0;
9106 myrpt->dailykerchunks = 0;
9107 myrpt->totalkerchunks = 0;
9108 myrpt->dailyexecdcommands = 0;
9109 myrpt->totalexecdcommands = 0;
9110 myrpt->timeouts = 0;
9111 myrpt->exten[0] = '\0';
9112 myrpt->lastdtmfcommand[0] = '\0';
9113 if (myrpt->p.startupmacro)
9115 snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
9117 rpt_mutex_unlock(&myrpt->lock);
9118 val = 1;
9119 ast_channel_setoption(myrpt->rxchannel,AST_OPTION_RELAXDTMF,&val,sizeof(char),0);
9120 val = 1;
9121 ast_channel_setoption(myrpt->rxchannel,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0);
9122 if (myrpt->p.archivedir) donodelog(myrpt,"STARTUP");
9123 dtmfed = 0;
9124 while (ms >= 0)
9126 struct ast_frame *f,*f1,*f2;
9127 struct ast_channel *cs[300],*cs1[300];
9128 int totx=0,elap=0,n,x,toexit=0;
9130 /* DEBUG Dump */
9131 if((myrpt->disgorgetime) && (time(NULL) >= myrpt->disgorgetime)){
9132 struct rpt_link *zl;
9133 struct rpt_tele *zt;
9135 myrpt->disgorgetime = 0;
9136 ast_log(LOG_NOTICE,"********** Variable Dump Start (app_rpt) **********\n");
9137 ast_log(LOG_NOTICE,"totx = %d\n",totx);
9138 ast_log(LOG_NOTICE,"remrx = %d\n",remrx);
9139 ast_log(LOG_NOTICE,"lasttx = %d\n",lasttx);
9140 ast_log(LOG_NOTICE,"elap = %d\n",elap);
9141 ast_log(LOG_NOTICE,"toexit = %d\n",toexit);
9143 ast_log(LOG_NOTICE,"myrpt->keyed = %d\n",myrpt->keyed);
9144 ast_log(LOG_NOTICE,"myrpt->localtx = %d\n",myrpt->localtx);
9145 ast_log(LOG_NOTICE,"myrpt->callmode = %d\n",myrpt->callmode);
9146 ast_log(LOG_NOTICE,"myrpt->mustid = %d\n",myrpt->mustid);
9147 ast_log(LOG_NOTICE,"myrpt->tounkeyed = %d\n",myrpt->tounkeyed);
9148 ast_log(LOG_NOTICE,"myrpt->tonotify = %d\n",myrpt->tonotify);
9149 ast_log(LOG_NOTICE,"myrpt->retxtimer = %ld\n",myrpt->retxtimer);
9150 ast_log(LOG_NOTICE,"myrpt->totimer = %d\n",myrpt->totimer);
9151 ast_log(LOG_NOTICE,"myrpt->tailtimer = %d\n",myrpt->tailtimer);
9152 ast_log(LOG_NOTICE,"myrpt->tailevent = %d\n",myrpt->tailevent);
9154 zl = myrpt->links.next;
9155 while(zl != &myrpt->links){
9156 ast_log(LOG_NOTICE,"*** Link Name: %s ***\n",zl->name);
9157 ast_log(LOG_NOTICE," link->lasttx %d\n",zl->lasttx);
9158 ast_log(LOG_NOTICE," link->lastrx %d\n",zl->lastrx);
9159 ast_log(LOG_NOTICE," link->connected %d\n",zl->connected);
9160 ast_log(LOG_NOTICE," link->hasconnected %d\n",zl->hasconnected);
9161 ast_log(LOG_NOTICE," link->outbound %d\n",zl->outbound);
9162 ast_log(LOG_NOTICE," link->disced %d\n",zl->disced);
9163 ast_log(LOG_NOTICE," link->killme %d\n",zl->killme);
9164 ast_log(LOG_NOTICE," link->disctime %ld\n",zl->disctime);
9165 ast_log(LOG_NOTICE," link->retrytimer %ld\n",zl->retrytimer);
9166 ast_log(LOG_NOTICE," link->retries = %d\n",zl->retries);
9167 ast_log(LOG_NOTICE," link->reconnects = %d\n",zl->reconnects);
9168 zl = zl->next;
9171 zt = myrpt->tele.next;
9172 if(zt != &myrpt->tele)
9173 ast_log(LOG_NOTICE,"*** Telemetry Queue ***\n");
9174 while(zt != &myrpt->tele){
9175 ast_log(LOG_NOTICE," Telemetry mode: %d\n",zt->mode);
9176 zt = zt->next;
9178 ast_log(LOG_NOTICE,"******* Variable Dump End (app_rpt) *******\n");
9183 if (myrpt->reload)
9185 struct rpt_tele *telem;
9187 rpt_mutex_lock(&myrpt->lock);
9188 telem = myrpt->tele.next;
9189 while(telem != &myrpt->tele)
9191 ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
9192 telem = telem->next;
9194 myrpt->reload = 0;
9195 rpt_mutex_unlock(&myrpt->lock);
9196 usleep(10000);
9197 /* find our index, and load the vars */
9198 for(i = 0; i < nrpts; i++)
9200 if (&rpt_vars[i] == myrpt)
9202 load_rpt_vars(i,0);
9203 break;
9208 rpt_mutex_lock(&myrpt->lock);
9209 if (ast_check_hangup(myrpt->rxchannel)) break;
9210 if (ast_check_hangup(myrpt->txchannel)) break;
9211 if (ast_check_hangup(myrpt->pchannel)) break;
9212 if (ast_check_hangup(myrpt->monchannel)) break;
9213 if (ast_check_hangup(myrpt->txpchannel)) break;
9214 if (myrpt->zaptxchannel && ast_check_hangup(myrpt->zaptxchannel)) break;
9216 /* Set local tx with keyed */
9217 myrpt->localtx = myrpt->keyed;
9218 /* If someone's connected, and they're transmitting from their end to us, set remrx true */
9219 l = myrpt->links.next;
9220 remrx = 0;
9221 while(l != &myrpt->links)
9223 if (l->lastrx){
9224 remrx = 1;
9225 if(l->name[0] != '0') /* Ignore '0' nodes */
9226 strcpy(myrpt->lastnodewhichkeyedusup, l->name); /* Note the node which is doing the key up */
9228 l = l->next;
9230 /* Create a "must_id" flag for the cleanup ID */
9231 if(myrpt->p.idtime) /* ID time must be non-zero */
9232 myrpt->mustid |= (myrpt->idtimer) && (myrpt->keyed || remrx) ;
9233 /* Build a fresh totx from myrpt->keyed and autopatch activated */
9234 totx = myrpt->callmode;
9235 /* If full duplex, add local tx to totx */
9236 if (myrpt->p.duplex > 1)
9238 totx = totx || myrpt->localtx;
9240 /* Traverse the telemetry list to see what's queued */
9241 identqueued = 0;
9242 othertelemqueued = 0;
9243 tailmessagequeued = 0;
9244 ctqueued = 0;
9245 telem = myrpt->tele.next;
9246 while(telem != &myrpt->tele)
9248 if((telem->mode == ID) || (telem->mode == IDTALKOVER)){
9249 identqueued = 1; /* Identification telemetry */
9251 else if(telem->mode == TAILMSG)
9253 tailmessagequeued = 1; /* Tail message telemetry */
9255 else
9257 if ((telem->mode != UNKEY) && (telem->mode != LINKUNKEY))
9258 othertelemqueued = 1; /* Other telemetry */
9259 else
9260 ctqueued = 1; /* Courtesy tone telemetry */
9262 telem = telem->next;
9265 /* Add in any "other" telemetry, unless specified otherwise */
9266 if (!myrpt->p.notelemtx) totx = totx || othertelemqueued;
9267 /* Update external (to links) transmitter PTT state with everything but ID, CT, and tailmessage telemetry */
9268 myrpt->exttx = totx;
9269 totx = totx || myrpt->dtmf_local_timer;
9270 /* If half or 3/4 duplex, add localtx to external link tx */
9271 if (myrpt->p.duplex < 2) myrpt->exttx = myrpt->exttx || myrpt->localtx;
9272 /* Add in ID telemetry to local transmitter */
9273 totx = totx || remrx;
9274 /* If 3/4 or full duplex, add in ident and CT telemetry */
9275 if (myrpt->p.duplex > 0)
9276 totx = totx || identqueued || ctqueued;
9277 /* If full duplex, add local dtmf stuff active */
9278 if (myrpt->p.duplex > 1)
9280 totx = totx || (myrpt->dtmfidx > -1) ||
9281 myrpt->cmdnode[0];
9283 /* Reset time out timer variables if there is no activity */
9284 if (!totx)
9286 myrpt->totimer = myrpt->p.totime;
9287 myrpt->tounkeyed = 0;
9288 myrpt->tonotify = 0;
9290 else{
9291 myrpt->tailtimer = myrpt->p.s[myrpt->p.sysstate_cur].alternatetail ?
9292 myrpt->p.althangtime : /* Initialize tail timer */
9293 myrpt->p.hangtime;
9295 /* Disable the local transmitter if we are timed out */
9296 totx = totx && myrpt->totimer;
9297 /* if timed-out and not said already, say it */
9298 if ((!myrpt->totimer) && (!myrpt->tonotify))
9300 myrpt->tonotify = 1;
9301 myrpt->timeouts++;
9302 rpt_mutex_unlock(&myrpt->lock);
9303 rpt_telemetry(myrpt,TIMEOUT,NULL);
9304 rpt_mutex_lock(&myrpt->lock);
9307 /* If unkey and re-key, reset time out timer */
9308 if ((!totx) && (!myrpt->totimer) && (!myrpt->tounkeyed) && (!myrpt->keyed))
9310 myrpt->tounkeyed = 1;
9312 if ((!totx) && (!myrpt->totimer) && myrpt->tounkeyed && myrpt->keyed)
9314 myrpt->totimer = myrpt->p.totime;
9315 myrpt->tounkeyed = 0;
9316 myrpt->tonotify = 0;
9317 rpt_mutex_unlock(&myrpt->lock);
9318 continue;
9320 /* if timed-out and in circuit busy after call */
9321 if ((!totx) && (!myrpt->totimer) && (myrpt->callmode == 4))
9323 myrpt->callmode = 0;
9325 /* get rid of tail if timed out */
9326 if (!myrpt->totimer) myrpt->tailtimer = 0;
9327 /* if not timed-out, add in tail */
9328 if (myrpt->totimer) totx = totx || myrpt->tailtimer;
9329 /* If user or links key up or are keyed up over standard ID, switch to talkover ID, if one is defined */
9330 /* If tail message, kill the message if someone keys up over it */
9331 if ((myrpt->keyed || remrx) && ((identqueued && idtalkover) || (tailmessagequeued))) {
9332 int hasid = 0,hastalkover = 0;
9334 telem = myrpt->tele.next;
9335 while(telem != &myrpt->tele){
9336 if(telem->mode == ID){
9337 if (telem->chan) ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
9338 hasid = 1;
9340 if(telem->mode == TAILMSG){
9341 if (telem->chan) ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
9343 if (telem->mode == IDTALKOVER) hastalkover = 1;
9344 telem = telem->next;
9346 rpt_mutex_unlock(&myrpt->lock);
9347 if (hasid && (!hastalkover)) rpt_telemetry(myrpt, IDTALKOVER, NULL); /* Start Talkover ID */
9348 rpt_mutex_lock(&myrpt->lock);
9350 /* Try to be polite */
9351 /* If the repeater has been inactive for longer than the ID time, do an initial ID in the tail*/
9352 /* If within 30 seconds of the time to ID, try do it in the tail */
9353 /* else if at ID time limit, do it right over the top of them */
9354 /* Lastly, if the repeater has been keyed, and the ID timer is expired, do a clean up ID */
9355 if(myrpt->mustid && (!myrpt->idtimer))
9356 queue_id(myrpt);
9358 if ((myrpt->p.idtime && totx && (!myrpt->exttx) &&
9359 (myrpt->idtimer <= myrpt->p.politeid) && myrpt->tailtimer)) /* ID time must be non-zero */
9361 myrpt->tailid = 1;
9364 /* If tail timer expires, then check for tail messages */
9366 if(myrpt->tailevent){
9367 myrpt->tailevent = 0;
9368 if(myrpt->tailid){
9369 totx = 1;
9370 queue_id(myrpt);
9372 else if ((myrpt->p.tailmessages[0]) &&
9373 (myrpt->p.tailmessagetime) && (myrpt->tmsgtimer == 0)){
9374 totx = 1;
9375 myrpt->tmsgtimer = myrpt->p.tailmessagetime;
9376 rpt_mutex_unlock(&myrpt->lock);
9377 rpt_telemetry(myrpt, TAILMSG, NULL);
9378 rpt_mutex_lock(&myrpt->lock);
9382 /* Main TX control */
9384 /* let telemetry transmit anyway (regardless of timeout) */
9385 if (myrpt->p.duplex > 0) totx = totx || (myrpt->tele.next != &myrpt->tele);
9386 if (totx && (!lasttx))
9388 char mydate[100],myfname[100];
9389 time_t myt;
9391 if (myrpt->monstream) ast_closestream(myrpt->monstream);
9392 if (myrpt->p.archivedir)
9394 long blocksleft;
9396 time(&myt);
9397 strftime(mydate,sizeof(mydate) - 1,"%Y%m%d%H%M%S",
9398 localtime(&myt));
9399 sprintf(myfname,"%s/%s/%s",myrpt->p.archivedir,
9400 myrpt->name,mydate);
9401 myrpt->monstream = ast_writefile(myfname,"wav49",
9402 "app_rpt Air Archive",O_CREAT | O_APPEND,0,0600);
9403 if (myrpt->p.monminblocks)
9405 blocksleft = diskavail(myrpt);
9406 if (blocksleft >= myrpt->p.monminblocks)
9407 donodelog(myrpt,"TXKEY,MAIN");
9408 } else donodelog(myrpt,"TXKEY,MAIN");
9410 lasttx = 1;
9411 myrpt->dailykeyups++;
9412 myrpt->totalkeyups++;
9413 rpt_mutex_unlock(&myrpt->lock);
9414 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
9415 rpt_mutex_lock(&myrpt->lock);
9417 totx = totx && !myrpt->p.s[myrpt->p.sysstate_cur].txdisable;
9418 if ((!totx) && lasttx)
9420 if (myrpt->monstream) ast_closestream(myrpt->monstream);
9421 myrpt->monstream = NULL;
9423 lasttx = 0;
9424 rpt_mutex_unlock(&myrpt->lock);
9425 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
9426 rpt_mutex_lock(&myrpt->lock);
9427 donodelog(myrpt,"TXUNKEY,MAIN");
9429 time(&t);
9430 /* if DTMF timeout */
9431 if ((!myrpt->cmdnode[0]) && (myrpt->dtmfidx >= 0) && ((myrpt->dtmf_time + DTMF_TIMEOUT) < t))
9433 myrpt->dtmfidx = -1;
9434 myrpt->dtmfbuf[0] = 0;
9436 /* if remote DTMF timeout */
9437 if ((myrpt->rem_dtmfidx >= 0) && ((myrpt->rem_dtmf_time + DTMF_TIMEOUT) < t))
9439 myrpt->rem_dtmfidx = -1;
9440 myrpt->rem_dtmfbuf[0] = 0;
9443 /* Reconnect */
9445 l = myrpt->links.next;
9446 while(l != &myrpt->links)
9448 if (l->killme)
9450 /* remove from queue */
9451 remque((struct qelem *) l);
9452 if (!strcmp(myrpt->cmdnode,l->name))
9453 myrpt->cmdnode[0] = 0;
9454 rpt_mutex_unlock(&myrpt->lock);
9455 /* hang-up on call to device */
9456 if (l->chan) ast_hangup(l->chan);
9457 ast_hangup(l->pchan);
9458 free(l);
9459 rpt_mutex_lock(&myrpt->lock);
9460 /* re-start link traversal */
9461 l = myrpt->links.next;
9462 continue;
9464 l = l->next;
9466 n = 0;
9467 cs[n++] = myrpt->rxchannel;
9468 cs[n++] = myrpt->pchannel;
9469 cs[n++] = myrpt->monchannel;
9470 cs[n++] = myrpt->txpchannel;
9471 if (myrpt->txchannel != myrpt->rxchannel) cs[n++] = myrpt->txchannel;
9472 if (myrpt->zaptxchannel != myrpt->txchannel)
9473 cs[n++] = myrpt->zaptxchannel;
9474 l = myrpt->links.next;
9475 while(l != &myrpt->links)
9477 if ((!l->killme) && (!l->disctime) && l->chan)
9479 cs[n++] = l->chan;
9480 cs[n++] = l->pchan;
9482 l = l->next;
9484 rpt_mutex_unlock(&myrpt->lock);
9485 ms = MSWAIT;
9486 for(x = 0; x < n; x++)
9488 int s = -(-x - myrpt->scram - 1) % n;
9489 cs1[x] = cs[s];
9491 myrpt->scram++;
9492 who = ast_waitfor_n(cs1,n,&ms);
9493 if (who == NULL) ms = 0;
9494 elap = MSWAIT - ms;
9495 rpt_mutex_lock(&myrpt->lock);
9496 l = myrpt->links.next;
9497 while(l != &myrpt->links)
9499 if (l->linklisttimer)
9501 l->linklisttimer -= elap;
9502 if (l->linklisttimer < 0) l->linklisttimer = 0;
9504 if ((!l->linklisttimer) && (l->name[0] != '0') && (!l->isremote))
9506 struct ast_frame lf;
9508 memset(&lf,0,sizeof(lf));
9509 lf.frametype = AST_FRAME_TEXT;
9510 lf.subclass = 0;
9511 lf.offset = 0;
9512 lf.mallocd = 0;
9513 lf.samples = 0;
9514 l->linklisttimer = LINKLISTTIME;
9515 strcpy(lstr,"L ");
9516 __mklinklist(myrpt,l,lstr + 2);
9517 if (l->chan)
9519 lf.datalen = strlen(lstr) + 1;
9520 lf.data = lstr;
9521 ast_write(l->chan,&lf);
9522 if (debug > 6) ast_log(LOG_NOTICE,
9523 "@@@@ node %s sent node string %s to node %s\n",
9524 myrpt->name,lstr,l->name);
9527 #ifndef OLDKEY
9528 if ((l->retxtimer += elap) >= REDUNDANT_TX_TIME)
9530 l->retxtimer = 0;
9531 if (l->chan && l->phonemode == 0)
9533 if (l->lasttx)
9534 ast_indicate(l->chan,AST_CONTROL_RADIO_KEY);
9535 else
9536 ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
9539 if ((l->rerxtimer += elap) >= (REDUNDANT_TX_TIME * 5))
9541 if (debug == 7) printf("@@@@ rx un-key\n");
9542 l->lastrx = 0;
9543 l->rerxtimer = 0;
9544 if(myrpt->p.duplex)
9545 rpt_telemetry(myrpt,LINKUNKEY,l);
9546 if (myrpt->p.archivedir)
9548 char str[100];
9550 l->lastrx1 = 0;
9551 sprintf(str,"RXUNKEY(T),%s",l->name);
9552 donodelog(myrpt,str);
9555 #endif
9556 if (l->disctime) /* Disconnect timer active on a channel ? */
9558 l->disctime -= elap;
9559 if (l->disctime <= 0) /* Disconnect timer expired on inbound channel ? */
9560 l->disctime = 0; /* Yep */
9563 if (l->retrytimer)
9565 l->retrytimer -= elap;
9566 if (l->retrytimer < 0) l->retrytimer = 0;
9569 /* Tally connect time */
9570 l->connecttime += elap;
9572 /* ignore non-timing channels */
9573 if (l->elaptime < 0)
9575 l = l->next;
9576 continue;
9578 l->elaptime += elap;
9579 /* if connection has taken too long */
9580 if ((l->elaptime > MAXCONNECTTIME) &&
9581 ((!l->chan) || (l->chan->_state != AST_STATE_UP)))
9583 l->elaptime = 0;
9584 rpt_mutex_unlock(&myrpt->lock);
9585 if (l->chan) ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
9586 rpt_mutex_lock(&myrpt->lock);
9587 break;
9589 if ((!l->chan) && (!l->retrytimer) && l->outbound &&
9590 (l->retries++ < l->max_retries) && (l->hasconnected))
9592 if (l->chan) ast_hangup(l->chan);
9593 l->chan = 0;
9594 rpt_mutex_unlock(&myrpt->lock);
9595 if ((l->name[0] != '0') && (!l->isremote))
9597 if (attempt_reconnect(myrpt,l) == -1)
9599 l->retrytimer = RETRY_TIMER_MS;
9602 else
9604 l->retrytimer = l->max_retries + 1;
9607 rpt_mutex_lock(&myrpt->lock);
9608 break;
9610 if ((!l->chan) && (!l->retrytimer) && l->outbound &&
9611 (l->retries >= l->max_retries))
9613 /* remove from queue */
9614 remque((struct qelem *) l);
9615 if (!strcmp(myrpt->cmdnode,l->name))
9616 myrpt->cmdnode[0] = 0;
9617 rpt_mutex_unlock(&myrpt->lock);
9618 if (l->name[0] != '0')
9620 if (!l->hasconnected)
9621 rpt_telemetry(myrpt,CONNFAIL,l);
9622 else rpt_telemetry(myrpt,REMDISC,l);
9624 if (myrpt->p.archivedir)
9626 char str[100];
9628 if (!l->hasconnected)
9629 sprintf(str,"LINKFAIL,%s",l->name);
9630 else
9631 sprintf(str,"LINKDISC,%s",l->name);
9632 donodelog(myrpt,str);
9634 /* hang-up on call to device */
9635 ast_hangup(l->pchan);
9636 free(l);
9637 rpt_mutex_lock(&myrpt->lock);
9638 break;
9640 if ((!l->chan) && (!l->disctime) && (!l->outbound))
9642 /* remove from queue */
9643 remque((struct qelem *) l);
9644 if (!strcmp(myrpt->cmdnode,l->name))
9645 myrpt->cmdnode[0] = 0;
9646 rpt_mutex_unlock(&myrpt->lock);
9647 if (l->name[0] != '0')
9649 rpt_telemetry(myrpt,REMDISC,l);
9651 if (myrpt->p.archivedir)
9653 char str[100];
9655 sprintf(str,"LINKDISC,%s",l->name);
9656 donodelog(myrpt,str);
9658 /* hang-up on call to device */
9659 ast_hangup(l->pchan);
9660 free(l);
9661 rpt_mutex_lock(&myrpt->lock);
9662 break;
9664 l = l->next;
9666 if(totx){
9667 myrpt->dailytxtime += elap;
9668 myrpt->totaltxtime += elap;
9670 i = myrpt->tailtimer;
9671 if (myrpt->tailtimer) myrpt->tailtimer -= elap;
9672 if (myrpt->tailtimer < 0) myrpt->tailtimer = 0;
9673 if((i) && (myrpt->tailtimer == 0))
9674 myrpt->tailevent = 1;
9675 if ((!myrpt->p.s[myrpt->p.sysstate_cur].totdisable) && myrpt->totimer) myrpt->totimer -= elap;
9676 if (myrpt->totimer < 0) myrpt->totimer = 0;
9677 if (myrpt->idtimer) myrpt->idtimer -= elap;
9678 if (myrpt->idtimer < 0) myrpt->idtimer = 0;
9679 if (myrpt->tmsgtimer) myrpt->tmsgtimer -= elap;
9680 if (myrpt->tmsgtimer < 0) myrpt->tmsgtimer = 0;
9681 /* do macro timers */
9682 if (myrpt->macrotimer) myrpt->macrotimer -= elap;
9683 if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
9684 /* do local dtmf timer */
9685 if (myrpt->dtmf_local_timer)
9687 if (myrpt->dtmf_local_timer > 1) myrpt->dtmf_local_timer -= elap;
9688 if (myrpt->dtmf_local_timer < 1) myrpt->dtmf_local_timer = 1;
9690 do_dtmf_local(myrpt,0);
9691 /* Execute scheduler appx. every 2 tenths of a second */
9692 if (myrpt->skedtimer <= 0){
9693 myrpt->skedtimer = 200;
9694 do_scheduler(myrpt);
9696 else
9697 myrpt->skedtimer -=elap;
9698 if (!ms)
9700 rpt_mutex_unlock(&myrpt->lock);
9701 continue;
9703 c = myrpt->macrobuf[0];
9704 time(&t);
9705 if (c && (!myrpt->macrotimer) &&
9706 starttime && (t > (starttime + START_DELAY)))
9708 myrpt->macrotimer = MACROTIME;
9709 memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1);
9710 if ((c == 'p') || (c == 'P'))
9711 myrpt->macrotimer = MACROPTIME;
9712 rpt_mutex_unlock(&myrpt->lock);
9713 if (myrpt->p.archivedir)
9715 char str[100];
9717 sprintf(str,"DTMF(M),MAIN,%c",c);
9718 donodelog(myrpt,str);
9720 local_dtmf_helper(myrpt,c);
9721 } else rpt_mutex_unlock(&myrpt->lock);
9722 if (who == myrpt->rxchannel) /* if it was a read from rx */
9724 int ismuted;
9726 f = ast_read(myrpt->rxchannel);
9727 if (!f)
9729 if (debug) printf("@@@@ rpt:Hung Up\n");
9730 break;
9732 if (f->frametype == AST_FRAME_VOICE)
9734 #ifdef _MDC_DECODE_H_
9735 unsigned char ubuf[2560];
9736 short *sp;
9737 int n;
9738 #endif
9740 if ((!myrpt->localtx) && (!myrpt->p.linktolink)) {
9741 memset(f->data,0,f->datalen);
9744 #ifdef _MDC_DECODE_H_
9745 sp = (short *) f->data;
9746 /* convert block to unsigned char */
9747 for(n = 0; n < f->datalen / 2; n++)
9749 ubuf[n] = (*sp++ >> 8) + 128;
9751 n = mdc_decoder_process_samples(myrpt->mdc,ubuf,f->datalen / 2);
9752 if (n == 1)
9754 unsigned char op,arg;
9755 unsigned short unitID;
9757 mdc_decoder_get_packet(myrpt->mdc,&op,&arg,&unitID);
9758 if (debug > 2)
9760 ast_log(LOG_NOTICE,"Got (single-length) packet:\n");
9761 ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
9762 op & 255,arg & 255,unitID);
9764 if ((op == 1) && (arg == 0))
9766 myrpt->lastunit = unitID;
9767 mdc1200_notify(myrpt,NULL,myrpt->lastunit);
9768 mdc1200_send(myrpt,myrpt->lastunit);
9771 if ((debug > 2) && (i == 2))
9773 unsigned char op,arg,ex1,ex2,ex3,ex4;
9774 unsigned short unitID;
9776 mdc_decoder_get_double_packet(myrpt->mdc,&op,&arg,&unitID,
9777 &ex1,&ex2,&ex3,&ex4);
9778 ast_log(LOG_NOTICE,"Got (double-length) packet:\n");
9779 ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
9780 op & 255,arg & 255,unitID);
9781 ast_log(LOG_NOTICE,"ex1: %02x, ex2: %02x, ex3: %02x, ex4: %02x\n",
9782 ex1 & 255, ex2 & 255, ex3 & 255, ex4 & 255);
9784 #endif
9785 #ifdef __RPT_NOTCH
9786 /* apply inbound filters, if any */
9787 rpt_filter(myrpt,f->data,f->datalen / 2);
9788 #endif
9789 if (ioctl(myrpt->zaprxchannel->fds[0], DAHDI_GETCONFMUTE, &ismuted) == -1)
9791 ismuted = 0;
9793 if (dtmfed) ismuted = 1;
9794 dtmfed = 0;
9795 if (ismuted)
9797 memset(f->data,0,f->datalen);
9798 if (myrpt->lastf1)
9799 memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
9800 if (myrpt->lastf2)
9801 memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
9803 if (f) f2 = ast_frdup(f);
9804 else f2 = NULL;
9805 f1 = myrpt->lastf2;
9806 myrpt->lastf2 = myrpt->lastf1;
9807 myrpt->lastf1 = f2;
9808 if (ismuted)
9810 if (myrpt->lastf1)
9811 memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
9812 if (myrpt->lastf2)
9813 memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
9815 if (f1)
9817 ast_write(myrpt->pchannel,f1);
9818 ast_frfree(f1);
9821 #ifndef OLD_ASTERISK
9822 else if (f->frametype == AST_FRAME_DTMF_BEGIN)
9824 if (myrpt->lastf1)
9825 memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
9826 if (myrpt->lastf2)
9827 memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
9828 dtmfed = 1;
9830 #endif
9831 else if (f->frametype == AST_FRAME_DTMF)
9833 c = (char) f->subclass; /* get DTMF char */
9834 ast_frfree(f);
9835 if (myrpt->lastf1)
9836 memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
9837 if (myrpt->lastf2)
9838 memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
9839 dtmfed = 1;
9840 if (!myrpt->keyed) continue;
9841 c = func_xlat(myrpt,c,&myrpt->p.inxlat);
9842 if (c) local_dtmf_helper(myrpt,c);
9843 continue;
9845 else if (f->frametype == AST_FRAME_CONTROL)
9847 if (f->subclass == AST_CONTROL_HANGUP)
9849 if (debug) printf("@@@@ rpt:Hung Up\n");
9850 ast_frfree(f);
9851 break;
9853 /* if RX key */
9854 if (f->subclass == AST_CONTROL_RADIO_KEY)
9856 if ((!lasttx) || (myrpt->p.duplex > 1) || (myrpt->p.linktolink))
9858 if (debug == 7) printf("@@@@ rx key\n");
9859 myrpt->keyed = 1;
9861 if (myrpt->p.archivedir)
9863 donodelog(myrpt,"RXKEY,MAIN");
9866 /* if RX un-key */
9867 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
9869 if ((!lasttx) || (myrpt->p.duplex > 1) || (myrpt->p.linktolink))
9871 if (debug == 7) printf("@@@@ rx un-key\n");
9872 if(myrpt->p.duplex && myrpt->keyed) {
9873 rpt_telemetry(myrpt,UNKEY,NULL);
9876 myrpt->keyed = 0;
9877 if (myrpt->p.archivedir)
9879 donodelog(myrpt,"RXUNKEY,MAIN");
9883 ast_frfree(f);
9884 continue;
9886 if (who == myrpt->pchannel) /* if it was a read from pseudo */
9888 f = ast_read(myrpt->pchannel);
9889 if (!f)
9891 if (debug) printf("@@@@ rpt:Hung Up\n");
9892 break;
9894 if (f->frametype == AST_FRAME_VOICE)
9896 ast_write(myrpt->txpchannel,f);
9898 if (f->frametype == AST_FRAME_CONTROL)
9900 if (f->subclass == AST_CONTROL_HANGUP)
9902 if (debug) printf("@@@@ rpt:Hung Up\n");
9903 ast_frfree(f);
9904 break;
9907 ast_frfree(f);
9908 continue;
9910 if (who == myrpt->txchannel) /* if it was a read from tx */
9912 f = ast_read(myrpt->txchannel);
9913 if (!f)
9915 if (debug) printf("@@@@ rpt:Hung Up\n");
9916 break;
9918 if (f->frametype == AST_FRAME_CONTROL)
9920 if (f->subclass == AST_CONTROL_HANGUP)
9922 if (debug) printf("@@@@ rpt:Hung Up\n");
9923 ast_frfree(f);
9924 break;
9927 ast_frfree(f);
9928 continue;
9930 if (who == myrpt->zaptxchannel) /* if it was a read from pseudo-tx */
9932 f = ast_read(myrpt->zaptxchannel);
9933 if (!f)
9935 if (debug) printf("@@@@ rpt:Hung Up\n");
9936 break;
9938 if (f->frametype == AST_FRAME_VOICE)
9940 ast_write(myrpt->txchannel,f);
9942 if (f->frametype == AST_FRAME_CONTROL)
9944 if (f->subclass == AST_CONTROL_HANGUP)
9946 if (debug) printf("@@@@ rpt:Hung Up\n");
9947 ast_frfree(f);
9948 break;
9951 ast_frfree(f);
9952 continue;
9954 toexit = 0;
9955 rpt_mutex_lock(&myrpt->lock);
9956 l = myrpt->links.next;
9957 while(l != &myrpt->links)
9959 if (l->disctime)
9961 l = l->next;
9962 continue;
9964 if (who == l->chan) /* if it was a read from rx */
9966 int remnomute;
9968 remrx = 0;
9969 /* see if any other links are receiving */
9970 m = myrpt->links.next;
9971 while(m != &myrpt->links)
9973 /* if not us, count it */
9974 if ((m != l) && (m->lastrx)) remrx = 1;
9975 m = m->next;
9977 rpt_mutex_unlock(&myrpt->lock);
9978 remnomute = myrpt->localtx &&
9979 (!(myrpt->cmdnode[0] ||
9980 (myrpt->dtmfidx > -1)));
9981 totx = (((l->isremote) ? (remnomute) :
9982 myrpt->exttx) || remrx) && l->mode;
9983 if (l->phonemode == 0 && l->chan && (l->lasttx != totx))
9985 if (totx)
9987 ast_indicate(l->chan,AST_CONTROL_RADIO_KEY);
9989 else
9991 ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
9993 if (myrpt->p.archivedir)
9995 char str[100];
9997 if (totx)
9998 sprintf(str,"TXKEY,%s",l->name);
9999 else
10000 sprintf(str,"TXUNKEY,%s",l->name);
10001 donodelog(myrpt,str);
10004 l->lasttx = totx;
10005 f = ast_read(l->chan);
10006 if (!f)
10008 rpt_mutex_lock(&myrpt->lock);
10009 __kickshort(myrpt);
10010 rpt_mutex_unlock(&myrpt->lock);
10011 if ((!l->disced) && (!l->outbound))
10013 if ((l->name[0] == '0') || l->isremote)
10014 l->disctime = 1;
10015 else
10016 l->disctime = DISC_TIME;
10017 rpt_mutex_lock(&myrpt->lock);
10018 ast_hangup(l->chan);
10019 l->chan = 0;
10020 break;
10023 if (l->retrytimer)
10025 ast_hangup(l->chan);
10026 l->chan = 0;
10027 rpt_mutex_lock(&myrpt->lock);
10028 break;
10030 if (l->outbound && (l->retries++ < l->max_retries) && (l->hasconnected))
10032 rpt_mutex_lock(&myrpt->lock);
10033 if (l->chan) ast_hangup(l->chan);
10034 l->chan = 0;
10035 l->hasconnected = 1;
10036 l->retrytimer = RETRY_TIMER_MS;
10037 l->elaptime = 0;
10038 l->connecttime = 0;
10039 l->thisconnected = 0;
10040 break;
10042 rpt_mutex_lock(&myrpt->lock);
10043 /* remove from queue */
10044 remque((struct qelem *) l);
10045 if (!strcmp(myrpt->cmdnode,l->name))
10046 myrpt->cmdnode[0] = 0;
10047 __kickshort(myrpt);
10048 rpt_mutex_unlock(&myrpt->lock);
10049 if (!l->hasconnected)
10050 rpt_telemetry(myrpt,CONNFAIL,l);
10051 else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
10052 if (myrpt->p.archivedir)
10054 char str[100];
10056 if (!l->hasconnected)
10057 sprintf(str,"LINKFAIL,%s",l->name);
10058 else
10059 sprintf(str,"LINKDISC,%s",l->name);
10060 donodelog(myrpt,str);
10062 if (l->lastf1) ast_frfree(l->lastf1);
10063 l->lastf1 = NULL;
10064 if (l->lastf2) ast_frfree(l->lastf2);
10065 l->lastf2 = NULL;
10066 /* hang-up on call to device */
10067 ast_hangup(l->chan);
10068 ast_hangup(l->pchan);
10069 free(l);
10070 rpt_mutex_lock(&myrpt->lock);
10071 break;
10073 if (f->frametype == AST_FRAME_VOICE)
10075 int ismuted;
10077 if (l->phonemode)
10079 if (ioctl(l->chan->fds[0], DAHDI_GETCONFMUTE, &ismuted) == -1)
10081 ismuted = 0;
10083 /* if not receiving, zero-out audio */
10084 ismuted |= (!l->lastrx);
10085 if (l->dtmfed && l->phonemode) ismuted = 1;
10086 l->dtmfed = 0;
10087 if (ismuted)
10089 memset(f->data,0,f->datalen);
10090 if (l->lastf1)
10091 memset(l->lastf1->data,0,l->lastf1->datalen);
10092 if (l->lastf2)
10093 memset(l->lastf2->data,0,l->lastf2->datalen);
10095 if (f) f2 = ast_frdup(f);
10096 else f2 = NULL;
10097 f1 = l->lastf2;
10098 l->lastf2 = l->lastf1;
10099 l->lastf1 = f2;
10100 if (ismuted)
10102 if (l->lastf1)
10103 memset(l->lastf1->data,0,l->lastf1->datalen);
10104 if (l->lastf2)
10105 memset(l->lastf2->data,0,l->lastf2->datalen);
10107 if (f1)
10109 ast_write(l->pchan,f1);
10110 ast_frfree(f1);
10113 else
10115 if (!l->lastrx)
10116 memset(f->data,0,f->datalen);
10117 ast_write(l->pchan,f);
10120 #ifndef OLD_ASTERISK
10121 else if (f->frametype == AST_FRAME_DTMF_BEGIN)
10123 if (l->lastf1)
10124 memset(l->lastf1->data,0,l->lastf1->datalen);
10125 if (l->lastf2)
10126 memset(l->lastf2->data,0,l->lastf2->datalen);
10127 l->dtmfed = 1;
10129 #endif
10131 if (f->frametype == AST_FRAME_TEXT)
10133 handle_link_data(myrpt,l,f->data);
10135 if (f->frametype == AST_FRAME_DTMF)
10137 if (l->lastf1)
10138 memset(l->lastf1->data,0,l->lastf1->datalen);
10139 if (l->lastf2)
10140 memset(l->lastf2->data,0,l->lastf2->datalen);
10141 l->dtmfed = 1;
10142 handle_link_phone_dtmf(myrpt,l,f->subclass);
10144 if (f->frametype == AST_FRAME_CONTROL)
10146 if (f->subclass == AST_CONTROL_ANSWER)
10148 char lconnected = l->connected;
10150 __kickshort(myrpt);
10151 l->connected = 1;
10152 l->hasconnected = 1;
10153 l->thisconnected = 1;
10154 l->elaptime = -1;
10155 if (!l->isremote) l->retries = 0;
10156 if (!lconnected)
10158 rpt_telemetry(myrpt,CONNECTED,l);
10159 if (myrpt->p.archivedir)
10161 char str[100];
10163 if (l->mode)
10164 sprintf(str,"LINKTRX,%s",l->name);
10165 else
10166 sprintf(str,"LINKMONITOR,%s",l->name);
10167 donodelog(myrpt,str);
10170 else
10171 l->reconnects++;
10173 /* if RX key */
10174 if (f->subclass == AST_CONTROL_RADIO_KEY)
10176 if (debug == 7 ) printf("@@@@ rx key\n");
10177 l->lastrx = 1;
10178 l->rerxtimer = 0;
10179 if (myrpt->p.archivedir && (!l->lastrx1))
10181 char str[100];
10183 l->lastrx1 = 1;
10184 sprintf(str,"RXKEY,%s",l->name);
10185 donodelog(myrpt,str);
10188 /* if RX un-key */
10189 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
10191 if (debug == 7) printf("@@@@ rx un-key\n");
10192 l->lastrx = 0;
10193 l->rerxtimer = 0;
10194 if(myrpt->p.duplex)
10195 rpt_telemetry(myrpt,LINKUNKEY,l);
10196 if (myrpt->p.archivedir && (l->lastrx1))
10198 char str[100];
10200 l->lastrx1 = 0;
10201 sprintf(str,"RXUNKEY,%s",l->name);
10202 donodelog(myrpt,str);
10205 if (f->subclass == AST_CONTROL_HANGUP)
10207 ast_frfree(f);
10208 rpt_mutex_lock(&myrpt->lock);
10209 __kickshort(myrpt);
10210 rpt_mutex_unlock(&myrpt->lock);
10211 if ((!l->outbound) && (!l->disced))
10213 if ((l->name[0] == '0') || l->isremote)
10214 l->disctime = 1;
10215 else
10216 l->disctime = DISC_TIME;
10217 rpt_mutex_lock(&myrpt->lock);
10218 ast_hangup(l->chan);
10219 l->chan = 0;
10220 break;
10222 if (l->retrytimer)
10224 if (l->chan) ast_hangup(l->chan);
10225 l->chan = 0;
10226 rpt_mutex_lock(&myrpt->lock);
10227 break;
10229 if (l->outbound && (l->retries++ < l->max_retries) && (l->hasconnected))
10231 rpt_mutex_lock(&myrpt->lock);
10232 if (l->chan) ast_hangup(l->chan);
10233 l->chan = 0;
10234 l->hasconnected = 1;
10235 l->elaptime = 0;
10236 l->retrytimer = RETRY_TIMER_MS;
10237 l->connecttime = 0;
10238 l->thisconnected = 0;
10239 break;
10241 rpt_mutex_lock(&myrpt->lock);
10242 /* remove from queue */
10243 remque((struct qelem *) l);
10244 if (!strcmp(myrpt->cmdnode,l->name))
10245 myrpt->cmdnode[0] = 0;
10246 __kickshort(myrpt);
10247 rpt_mutex_unlock(&myrpt->lock);
10248 if (!l->hasconnected)
10249 rpt_telemetry(myrpt,CONNFAIL,l);
10250 else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
10251 if (myrpt->p.archivedir)
10253 char str[100];
10255 if (!l->hasconnected)
10256 sprintf(str,"LINKFAIL,%s",l->name);
10257 else
10258 sprintf(str,"LINKDISC,%s",l->name);
10259 donodelog(myrpt,str);
10261 if (l->lastf1) ast_frfree(l->lastf1);
10262 l->lastf1 = NULL;
10263 if (l->lastf2) ast_frfree(l->lastf2);
10264 l->lastf2 = NULL;
10265 /* hang-up on call to device */
10266 ast_hangup(l->chan);
10267 ast_hangup(l->pchan);
10268 free(l);
10269 rpt_mutex_lock(&myrpt->lock);
10270 break;
10273 ast_frfree(f);
10274 rpt_mutex_lock(&myrpt->lock);
10275 break;
10277 if (who == l->pchan)
10279 rpt_mutex_unlock(&myrpt->lock);
10280 f = ast_read(l->pchan);
10281 if (!f)
10283 if (debug) printf("@@@@ rpt:Hung Up\n");
10284 toexit = 1;
10285 rpt_mutex_lock(&myrpt->lock);
10286 break;
10288 if (f->frametype == AST_FRAME_VOICE)
10290 if (l->chan) ast_write(l->chan,f);
10292 if (f->frametype == AST_FRAME_CONTROL)
10294 if (f->subclass == AST_CONTROL_HANGUP)
10296 if (debug) printf("@@@@ rpt:Hung Up\n");
10297 ast_frfree(f);
10298 toexit = 1;
10299 rpt_mutex_lock(&myrpt->lock);
10300 break;
10303 ast_frfree(f);
10304 rpt_mutex_lock(&myrpt->lock);
10305 break;
10307 l = l->next;
10309 rpt_mutex_unlock(&myrpt->lock);
10310 if (toexit) break;
10311 if (who == myrpt->monchannel)
10313 f = ast_read(myrpt->monchannel);
10314 if (!f)
10316 if (debug) printf("@@@@ rpt:Hung Up\n");
10317 break;
10319 if (f->frametype == AST_FRAME_VOICE)
10321 if (myrpt->monstream)
10322 ast_writestream(myrpt->monstream,f);
10324 if (f->frametype == AST_FRAME_CONTROL)
10326 if (f->subclass == AST_CONTROL_HANGUP)
10328 if (debug) printf("@@@@ rpt:Hung Up\n");
10329 ast_frfree(f);
10330 break;
10333 ast_frfree(f);
10334 continue;
10336 if (who == myrpt->txpchannel) /* if it was a read from remote tx */
10338 f = ast_read(myrpt->txpchannel);
10339 if (!f)
10341 if (debug) printf("@@@@ rpt:Hung Up\n");
10342 break;
10344 if (f->frametype == AST_FRAME_CONTROL)
10346 if (f->subclass == AST_CONTROL_HANGUP)
10348 if (debug) printf("@@@@ rpt:Hung Up\n");
10349 ast_frfree(f);
10350 break;
10353 ast_frfree(f);
10354 continue;
10357 usleep(100000);
10358 ast_hangup(myrpt->pchannel);
10359 ast_hangup(myrpt->monchannel);
10360 ast_hangup(myrpt->txpchannel);
10361 if (myrpt->txchannel != myrpt->rxchannel) ast_hangup(myrpt->txchannel);
10362 if (myrpt->zaptxchannel != myrpt->txchannel) ast_hangup(myrpt->zaptxchannel);
10363 if (myrpt->lastf1) ast_frfree(myrpt->lastf1);
10364 myrpt->lastf1 = NULL;
10365 if (myrpt->lastf2) ast_frfree(myrpt->lastf2);
10366 myrpt->lastf2 = NULL;
10367 ast_hangup(myrpt->rxchannel);
10368 rpt_mutex_lock(&myrpt->lock);
10369 l = myrpt->links.next;
10370 while(l != &myrpt->links)
10372 struct rpt_link *ll = l;
10373 /* remove from queue */
10374 remque((struct qelem *) l);
10375 /* hang-up on call to device */
10376 if (l->chan) ast_hangup(l->chan);
10377 ast_hangup(l->pchan);
10378 l = l->next;
10379 free(ll);
10381 rpt_mutex_unlock(&myrpt->lock);
10382 if (debug) printf("@@@@ rpt:Hung up channel\n");
10383 myrpt->rpt_thread = AST_PTHREADT_STOP;
10384 pthread_exit(NULL);
10385 return NULL;
10389 static void *rpt_master(void *ignore)
10391 int i,n;
10392 pthread_attr_t attr;
10393 struct ast_config *cfg;
10394 char *this,*val;
10396 /* init nodelog queue */
10397 nodelog.next = nodelog.prev = &nodelog;
10398 /* go thru all the specified repeaters */
10399 this = NULL;
10400 n = 0;
10401 /* wait until asterisk starts */
10402 while(!ast_test_flag(&ast_options,AST_OPT_FLAG_FULLY_BOOTED))
10403 usleep(250000);
10404 rpt_vars[n].cfg = ast_config_load("rpt.conf");
10405 cfg = rpt_vars[n].cfg;
10406 if (!cfg) {
10407 ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf. Radio Repeater disabled.\n");
10408 pthread_exit(NULL);
10410 while((this = ast_category_browse(cfg,this)) != NULL)
10412 for(i = 0 ; i < strlen(this) ; i++){
10413 if((this[i] < '0') || (this[i] > '9'))
10414 break;
10416 if(i != strlen(this)) continue; /* Not a node defn */
10417 memset(&rpt_vars[n],0,sizeof(rpt_vars[n]));
10418 rpt_vars[n].name = strdup(this);
10419 val = (char *) ast_variable_retrieve(cfg,this,"rxchannel");
10420 if (val) rpt_vars[n].rxchanname = strdup(val);
10421 val = (char *) ast_variable_retrieve(cfg,this,"txchannel");
10422 if (val) rpt_vars[n].txchanname = strdup(val);
10423 val = (char *) ast_variable_retrieve(cfg,this,"remote");
10424 if (val) rpt_vars[n].remote = strdup(val);
10425 ast_mutex_init(&rpt_vars[n].lock);
10426 ast_mutex_init(&rpt_vars[n].remlock);
10427 rpt_vars[n].tele.next = &rpt_vars[n].tele;
10428 rpt_vars[n].tele.prev = &rpt_vars[n].tele;
10429 rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
10430 rpt_vars[n].tailmessagen = 0;
10431 #ifdef _MDC_DECODE_H_
10432 rpt_vars[n].mdc = mdc_decoder_new(8000);
10433 #endif
10434 n++;
10436 nrpts = n;
10437 ast_config_destroy(cfg);
10439 /* start em all */
10440 for(i = 0; i < n; i++)
10442 load_rpt_vars(i,1);
10444 /* if is a remote, dont start one for it */
10445 if (rpt_vars[i].remote)
10447 if(retreive_memory(&rpt_vars[i],"init")){ /* Try to retreive initial memory channel */
10448 strncpy(rpt_vars[i].freq, "146.580", sizeof(rpt_vars[i].freq) - 1);
10449 strncpy(rpt_vars[i].rxpl, "100.0", sizeof(rpt_vars[i].rxpl) - 1);
10451 strncpy(rpt_vars[i].txpl, "100.0", sizeof(rpt_vars[i].txpl) - 1);
10452 rpt_vars[i].remmode = REM_MODE_FM;
10453 rpt_vars[i].offset = REM_SIMPLEX;
10454 rpt_vars[i].powerlevel = REM_MEDPWR;
10456 continue;
10458 if (!rpt_vars[i].p.ident)
10460 ast_log(LOG_WARNING,"Did not specify ident for node %s\n",rpt_vars[i].name);
10461 ast_config_destroy(cfg);
10462 pthread_exit(NULL);
10464 pthread_attr_init(&attr);
10465 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
10466 ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]);
10468 usleep(500000);
10469 time(&starttime);
10470 for(;;)
10472 /* Now monitor each thread, and restart it if necessary */
10473 for(i = 0; i < n; i++)
10475 int rv;
10476 if (rpt_vars[i].remote) continue;
10477 if (rpt_vars[i].rpt_thread == AST_PTHREADT_STOP)
10478 rv = -1;
10479 else
10480 rv = pthread_kill(rpt_vars[i].rpt_thread,0);
10481 if (rv)
10483 if(time(NULL) - rpt_vars[i].lastthreadrestarttime <= 15)
10485 if(rpt_vars[i].threadrestarts >= 5)
10487 ast_log(LOG_ERROR,"Continual RPT thread restarts, killing Asterisk\n");
10488 exit(1); /* Stuck in a restart loop, kill Asterisk and start over */
10490 else
10492 ast_log(LOG_NOTICE,"RPT thread restarted on %s\n",rpt_vars[i].name);
10493 rpt_vars[i].threadrestarts++;
10496 else
10497 rpt_vars[i].threadrestarts = 0;
10499 rpt_vars[i].lastthreadrestarttime = time(NULL);
10500 pthread_attr_init(&attr);
10501 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
10502 ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]);
10503 ast_log(LOG_WARNING, "rpt_thread restarted on node %s\n", rpt_vars[i].name);
10507 for(;;)
10509 struct nodelog *nodep;
10510 char *space,datestr[100],fname[300];
10511 int fd;
10513 ast_mutex_lock(&nodeloglock);
10514 nodep = nodelog.next;
10515 if(nodep == &nodelog) /* if nothing in queue */
10517 ast_mutex_unlock(&nodeloglock);
10518 break;
10520 remque((struct qelem *)nodep);
10521 ast_mutex_unlock(&nodeloglock);
10522 space = strchr(nodep->str,' ');
10523 if (!space)
10525 free(nodep);
10526 continue;
10528 *space = 0;
10529 strftime(datestr,sizeof(datestr) - 1,"%Y%m%d",
10530 localtime(&nodep->timestamp));
10531 sprintf(fname,"%s/%s/%s.txt",nodep->archivedir,
10532 nodep->str,datestr);
10533 fd = open(fname,O_WRONLY | O_CREAT | O_APPEND,0600);
10534 if (fd == -1)
10536 ast_log(LOG_ERROR,"Cannot open node log file %s for write",space + 1);
10537 free(nodep);
10538 continue;
10540 if (write(fd,space + 1,strlen(space + 1)) !=
10541 strlen(space + 1))
10543 ast_log(LOG_ERROR,"Cannot write node log file %s for write",space + 1);
10544 free(nodep);
10545 continue;
10547 close(fd);
10548 free(nodep);
10550 usleep(2000000);
10552 ast_config_destroy(cfg);
10553 pthread_exit(NULL);
10556 static int rpt_exec(struct ast_channel *chan, void *data)
10558 int res=-1,i,rem_totx,rem_rx,remkeyed,n,phone_mode = 0;
10559 int iskenwood_pci4,authtold,authreq,setting,notremming,reming;
10560 int ismuted,dtmfed;
10561 #ifdef OLD_ASTERISK
10562 struct localuser *u;
10563 #endif
10564 char tmp[256], keyed = 0,keyed1 = 0;
10565 char *options,*stringp,*tele,c;
10566 struct rpt *myrpt;
10567 struct ast_frame *f,*f1,*f2;
10568 struct ast_channel *who;
10569 struct ast_channel *cs[20];
10570 struct rpt_link *l;
10571 DAHDI_CONFINFO ci; /* conference info */
10572 DAHDI_PARAMS par;
10573 int ms,elap,nullfd;
10574 time_t t,last_timeout_warning;
10575 struct zt_radio_param z;
10576 struct rpt_tele *telem;
10578 nullfd = open("/dev/null",O_RDWR);
10579 if (ast_strlen_zero(data)) {
10580 ast_log(LOG_WARNING, "Rpt requires an argument (system node)\n");
10581 return -1;
10584 strncpy(tmp, (char *)data, sizeof(tmp)-1);
10585 time(&t);
10586 /* if time has externally shifted negative, screw it */
10587 if (t < starttime) t = starttime + START_DELAY;
10588 if ((!starttime) || (t < (starttime + START_DELAY)))
10590 ast_log(LOG_NOTICE,"Node %s rejecting call: too soon!\n",tmp);
10591 ast_safe_sleep(chan,3000);
10592 return -1;
10594 stringp=tmp;
10595 strsep(&stringp, "|");
10596 options = stringp;
10597 myrpt = NULL;
10598 /* see if we can find our specified one */
10599 for(i = 0; i < nrpts; i++)
10601 /* if name matches, assign it and exit loop */
10602 if (!strcmp(tmp,rpt_vars[i].name))
10604 myrpt = &rpt_vars[i];
10605 break;
10608 if (myrpt == NULL)
10610 ast_log(LOG_WARNING, "Cannot find specified system node %s\n",tmp);
10611 return -1;
10614 if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable){ /* Do not allow incoming connections if disabled */
10615 ast_log(LOG_NOTICE, "Connect attempt to node %s with tx disabled", myrpt->name);
10616 return -1;
10619 /* if not phone access, must be an IAX connection */
10620 if (options && ((*options == 'P') || (*options == 'D') || (*options == 'R')))
10622 int val;
10624 phone_mode = 1;
10625 if (*options == 'D') phone_mode = 2;
10626 ast_set_callerid(chan,"0","app_rpt user","0");
10627 val = 1;
10628 ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0);
10630 else
10632 #ifdef ALLOW_LOCAL_CHANNELS
10633 /* Check to insure the connection is IAX2 or Local*/
10634 if ( (strncmp(chan->name,"IAX2",4)) && (strncmp(chan->name,"Local",5)) ) {
10635 ast_log(LOG_WARNING, "We only accept links via IAX2 or Local!!\n");
10636 return -1;
10638 #else
10639 if (strncmp(chan->name,"IAX2",4))
10641 ast_log(LOG_WARNING, "We only accept links via IAX2!!\n");
10642 return -1;
10644 #endif
10646 if (options && (*options == 'R'))
10649 /* Parts of this section taken from app_parkandannounce */
10650 char *return_context;
10651 int l, m, lot, timeout = 0;
10652 char tmp[256],*template;
10653 char *working, *context, *exten, *priority;
10654 char *s,*orig_s;
10657 rpt_mutex_lock(&myrpt->lock);
10658 m = myrpt->callmode;
10659 rpt_mutex_unlock(&myrpt->lock);
10661 if ((!myrpt->p.nobusyout) && m)
10663 if (chan->_state != AST_STATE_UP)
10665 ast_indicate(chan,AST_CONTROL_BUSY);
10667 while(ast_safe_sleep(chan,10000) != -1);
10668 return -1;
10671 if (chan->_state != AST_STATE_UP)
10673 ast_answer(chan);
10676 l=strlen(options)+2;
10677 orig_s=malloc(l);
10678 if(!orig_s) {
10679 ast_log(LOG_WARNING, "Out of memory\n");
10680 return -1;
10682 s=orig_s;
10683 strncpy(s,options,l);
10685 template=strsep(&s,"|");
10686 if(!template) {
10687 ast_log(LOG_WARNING, "An announce template must be defined\n");
10688 free(orig_s);
10689 return -1;
10692 if(s) {
10693 timeout = atoi(strsep(&s, "|"));
10694 timeout *= 1000;
10697 return_context = s;
10699 if(return_context != NULL) {
10700 /* set the return context. Code borrowed from the Goto builtin */
10702 working = return_context;
10703 context = strsep(&working, "|");
10704 exten = strsep(&working, "|");
10705 if(!exten) {
10706 /* Only a priority in this one */
10707 priority = context;
10708 exten = NULL;
10709 context = NULL;
10710 } else {
10711 priority = strsep(&working, "|");
10712 if(!priority) {
10713 /* Only an extension and priority in this one */
10714 priority = exten;
10715 exten = context;
10716 context = NULL;
10719 if(atoi(priority) < 0) {
10720 ast_log(LOG_WARNING, "Priority '%s' must be a number > 0\n", priority);
10721 free(orig_s);
10722 return -1;
10724 /* At this point we have a priority and maybe an extension and a context */
10725 chan->priority = atoi(priority);
10726 #ifdef OLD_ASTERISK
10727 if(exten && strcasecmp(exten, "BYEXTENSION"))
10728 #else
10729 if(exten)
10730 #endif
10731 strncpy(chan->exten, exten, sizeof(chan->exten)-1);
10732 if(context)
10733 strncpy(chan->context, context, sizeof(chan->context)-1);
10734 } else { /* increment the priority by default*/
10735 chan->priority++;
10738 if(option_verbose > 2) {
10739 ast_verbose( VERBOSE_PREFIX_3 "Return Context: (%s,%s,%d) ID: %s\n", chan->context,chan->exten, chan->priority, chan->cid.cid_num);
10740 if(!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) {
10741 ast_verbose( VERBOSE_PREFIX_3 "Warning: Return Context Invalid, call will return to default|s\n");
10745 /* we are using masq_park here to protect * from touching the channel once we park it. If the channel comes out of timeout
10746 before we are done announcing and the channel is messed with, Kablooeee. So we use Masq to prevent this. */
10748 ast_masq_park_call(chan, NULL, timeout, &lot);
10750 if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "Call Parking Called, lot: %d, timeout: %d, context: %s\n", lot, timeout, return_context);
10752 snprintf(tmp,sizeof(tmp) - 1,"%d,%s",lot,template + 1);
10754 rpt_telemetry(myrpt,REV_PATCH,tmp);
10756 free(orig_s);
10758 return 0;
10762 if (!options)
10764 struct ast_hostent ahp;
10765 struct hostent *hp;
10766 struct in_addr ia;
10767 char hisip[100],nodeip[100],*val, *s, *s1, *s2, *b,*b1;
10769 /* look at callerid to see what node this comes from */
10770 if (!chan->cid.cid_num) /* if doesn't have caller id */
10772 ast_log(LOG_WARNING, "Doesnt have callerid on %s\n",tmp);
10773 return -1;
10776 /* get his IP from IAX2 module */
10777 memset(hisip,0,sizeof(hisip));
10778 #ifdef ALLOW_LOCAL_CHANNELS
10779 /* set IP address if this is a local connection*/
10780 if (strncmp(chan->name,"Local",5)==0) {
10781 strcpy(hisip,"127.0.0.1");
10782 } else {
10783 pbx_substitute_variables_helper(chan,"${IAXPEER(CURRENTCHANNEL)}",hisip,sizeof(hisip) - 1);
10785 #else
10786 pbx_substitute_variables_helper(chan,"${IAXPEER(CURRENTCHANNEL)}",hisip,sizeof(hisip) - 1);
10787 #endif
10789 if (!hisip[0])
10791 ast_log(LOG_WARNING, "Link IP address cannot be determined!!\n");
10792 return -1;
10795 ast_callerid_parse(chan->cid.cid_num,&b,&b1);
10796 ast_shrink_phone_number(b1);
10797 if (!strcmp(myrpt->name,b1))
10799 ast_log(LOG_WARNING, "Trying to link to self!!\n");
10800 return -1;
10803 if (*b1 < '1')
10805 ast_log(LOG_WARNING, "Node %s Invalid for connection here!!\n",b1);
10806 return -1;
10810 /* look for his reported node string */
10811 val = node_lookup(myrpt,b1);
10812 if (!val)
10814 ast_log(LOG_WARNING, "Reported node %s cannot be found!!\n",b1);
10815 return -1;
10817 strncpy(tmp,val,sizeof(tmp) - 1);
10818 s = tmp;
10819 s1 = strsep(&s,",");
10820 s2 = strsep(&s,",");
10821 if (!s2)
10823 ast_log(LOG_WARNING, "Reported node %s not in correct format!!\n",b1);
10824 return -1;
10826 if (strcmp(s2,"NONE")) {
10827 hp = ast_gethostbyname(s2, &ahp);
10828 if (!hp)
10830 ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n",b1,s2);
10831 return -1;
10833 memcpy(&ia,hp->h_addr,sizeof(in_addr_t));
10834 #ifdef OLD_ASTERISK
10835 ast_inet_ntoa(nodeip,sizeof(nodeip) - 1,ia);
10836 #else
10837 strncpy(nodeip,ast_inet_ntoa(ia),sizeof(nodeip) - 1);
10838 #endif
10839 if (strcmp(hisip,nodeip))
10841 char *s3 = strchr(s1,'@');
10842 if (s3) s1 = s3 + 1;
10843 s3 = strchr(s1,'/');
10844 if (s3) *s3 = 0;
10845 hp = ast_gethostbyname(s1, &ahp);
10846 if (!hp)
10848 ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n",b1,s1);
10849 return -1;
10851 memcpy(&ia,hp->h_addr,sizeof(in_addr_t));
10852 #ifdef OLD_ASTERISK
10853 ast_inet_ntoa(nodeip,sizeof(nodeip) - 1,ia);
10854 #else
10855 strncpy(nodeip,ast_inet_ntoa(ia),sizeof(nodeip) - 1);
10856 #endif
10857 if (strcmp(hisip,nodeip))
10859 ast_log(LOG_WARNING, "Node %s IP %s does not match link IP %s!!\n",b1,nodeip,hisip);
10860 return -1;
10866 /* if is not a remote */
10867 if (!myrpt->remote)
10870 char *b,*b1;
10871 int reconnects = 0;
10873 /* look at callerid to see what node this comes from */
10874 if (!chan->cid.cid_num) /* if doesn't have caller id */
10876 ast_log(LOG_WARNING, "Doesnt have callerid on %s\n",tmp);
10877 return -1;
10880 ast_callerid_parse(chan->cid.cid_num,&b,&b1);
10881 ast_shrink_phone_number(b1);
10882 if (!strcmp(myrpt->name,b1))
10884 ast_log(LOG_WARNING, "Trying to link to self!!\n");
10885 return -1;
10887 rpt_mutex_lock(&myrpt->lock);
10888 l = myrpt->links.next;
10889 /* try to find this one in queue */
10890 while(l != &myrpt->links)
10892 if (l->name[0] == '0')
10894 l = l->next;
10895 continue;
10897 /* if found matching string */
10898 if (!strcmp(l->name,b1)) break;
10899 l = l->next;
10901 /* if found */
10902 if (l != &myrpt->links)
10904 l->killme = 1;
10905 l->retries = l->max_retries + 1;
10906 l->disced = 2;
10907 reconnects = l->reconnects;
10908 reconnects++;
10909 rpt_mutex_unlock(&myrpt->lock);
10910 usleep(500000);
10911 } else
10912 rpt_mutex_unlock(&myrpt->lock);
10913 /* establish call in tranceive mode */
10914 l = malloc(sizeof(struct rpt_link));
10915 if (!l)
10917 ast_log(LOG_WARNING, "Unable to malloc\n");
10918 pthread_exit(NULL);
10920 /* zero the silly thing */
10921 memset((char *)l,0,sizeof(struct rpt_link));
10922 l->mode = 1;
10923 strncpy(l->name,b1,MAXNODESTR - 1);
10924 l->isremote = 0;
10925 l->chan = chan;
10926 l->connected = 1;
10927 l->thisconnected = 1;
10928 l->hasconnected = 1;
10929 l->reconnects = reconnects;
10930 l->phonemode = phone_mode;
10931 l->lastf1 = NULL;
10932 l->lastf2 = NULL;
10933 l->dtmfed = 0;
10934 ast_set_read_format(l->chan,AST_FORMAT_SLINEAR);
10935 ast_set_write_format(l->chan,AST_FORMAT_SLINEAR);
10936 /* allocate a pseudo-channel thru asterisk */
10937 l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
10938 if (!l->pchan)
10940 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
10941 pthread_exit(NULL);
10943 ast_set_read_format(l->pchan,AST_FORMAT_SLINEAR);
10944 ast_set_write_format(l->pchan,AST_FORMAT_SLINEAR);
10945 #ifdef AST_CDR_FLAG_POST_DISABLED
10946 ast_set_flag(l->pchan->cdr,AST_CDR_FLAG_POST_DISABLED);
10947 #endif
10948 /* make a conference for the tx */
10949 ci.chan = 0;
10950 ci.confno = myrpt->conf;
10951 ci.confmode = DAHDI_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER;
10952 /* first put the channel on the conference in proper mode */
10953 if (ioctl(l->pchan->fds[0],DAHDI_SETCONF,&ci) == -1)
10955 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
10956 pthread_exit(NULL);
10958 rpt_mutex_lock(&myrpt->lock);
10959 if (phone_mode > 1) l->lastrx = 1;
10960 l->max_retries = MAX_RETRIES;
10961 /* insert at end of queue */
10962 insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
10963 __kickshort(myrpt);
10964 rpt_mutex_unlock(&myrpt->lock);
10965 if (chan->_state != AST_STATE_UP) {
10966 ast_answer(chan);
10968 if (myrpt->p.archivedir)
10970 char str[100];
10972 if (l->phonemode)
10973 sprintf(str,"LINK(P),%s",l->name);
10974 else
10975 sprintf(str,"LINK,%s",l->name);
10976 donodelog(myrpt,str);
10978 return AST_PBX_KEEPALIVE;
10980 /* well, then it is a remote */
10981 rpt_mutex_lock(&myrpt->lock);
10982 /* if remote, error if anyone else already linked */
10983 if (myrpt->remoteon)
10985 rpt_mutex_unlock(&myrpt->lock);
10986 usleep(500000);
10987 if (myrpt->remoteon)
10989 ast_log(LOG_WARNING, "Trying to use busy link on %s\n",tmp);
10990 return -1;
10992 rpt_mutex_lock(&myrpt->lock);
10994 if ((!strcmp(myrpt->remote, remote_rig_rbi)) &&
10995 (ioperm(myrpt->p.iobase,1,1) == -1))
10997 rpt_mutex_unlock(&myrpt->lock);
10998 ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase);
10999 return -1;
11001 myrpt->remoteon = 1;
11002 #ifdef OLD_ASTERISK
11003 LOCAL_USER_ADD(u);
11004 #endif
11005 rpt_mutex_unlock(&myrpt->lock);
11006 /* find our index, and load the vars initially */
11007 for(i = 0; i < nrpts; i++)
11009 if (&rpt_vars[i] == myrpt)
11011 load_rpt_vars(i,0);
11012 break;
11015 rpt_mutex_lock(&myrpt->lock);
11016 tele = strchr(myrpt->rxchanname,'/');
11017 if (!tele)
11019 fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
11020 rpt_mutex_unlock(&myrpt->lock);
11021 pthread_exit(NULL);
11023 *tele++ = 0;
11024 myrpt->rxchannel = ast_request(myrpt->rxchanname,AST_FORMAT_SLINEAR,tele,NULL);
11025 myrpt->zaprxchannel = NULL;
11026 if (!strcasecmp(myrpt->rxchanname,"Zap"))
11027 myrpt->zaprxchannel = myrpt->rxchannel;
11028 if (myrpt->rxchannel)
11030 ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
11031 ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
11032 #ifdef AST_CDR_FLAG_POST_DISABLED
11033 ast_set_flag(myrpt->rxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11034 #endif
11035 myrpt->rxchannel->whentohangup = 0;
11036 myrpt->rxchannel->appl = "Apprpt";
11037 myrpt->rxchannel->data = "(Link Rx)";
11038 if (option_verbose > 2)
11039 ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
11040 myrpt->rxchanname,tele,myrpt->rxchannel->name);
11041 rpt_mutex_unlock(&myrpt->lock);
11042 ast_call(myrpt->rxchannel,tele,999);
11043 rpt_mutex_lock(&myrpt->lock);
11045 else
11047 fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
11048 rpt_mutex_unlock(&myrpt->lock);
11049 pthread_exit(NULL);
11051 *--tele = '/';
11052 myrpt->zaptxchannel = NULL;
11053 if (myrpt->txchanname)
11055 tele = strchr(myrpt->txchanname,'/');
11056 if (!tele)
11058 fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
11059 rpt_mutex_unlock(&myrpt->lock);
11060 ast_hangup(myrpt->rxchannel);
11061 pthread_exit(NULL);
11063 *tele++ = 0;
11064 myrpt->txchannel = ast_request(myrpt->txchanname,AST_FORMAT_SLINEAR,tele,NULL);
11065 if (!strcasecmp(myrpt->txchanname,"Zap"))
11066 myrpt->zaptxchannel = myrpt->txchannel;
11067 if (myrpt->txchannel)
11069 ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
11070 ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
11071 #ifdef AST_CDR_FLAG_POST_DISABLED
11072 ast_set_flag(myrpt->txchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11073 #endif
11074 myrpt->txchannel->whentohangup = 0;
11075 myrpt->txchannel->appl = "Apprpt";
11076 myrpt->txchannel->data = "(Link Tx)";
11077 if (option_verbose > 2)
11078 ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
11079 myrpt->txchanname,tele,myrpt->txchannel->name);
11080 rpt_mutex_unlock(&myrpt->lock);
11081 ast_call(myrpt->txchannel,tele,999);
11082 rpt_mutex_lock(&myrpt->lock);
11084 else
11086 fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
11087 rpt_mutex_unlock(&myrpt->lock);
11088 ast_hangup(myrpt->rxchannel);
11089 pthread_exit(NULL);
11091 *--tele = '/';
11093 else
11095 myrpt->txchannel = myrpt->rxchannel;
11097 /* allocate a pseudo-channel thru asterisk */
11098 myrpt->pchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
11099 if (!myrpt->pchannel)
11101 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
11102 rpt_mutex_unlock(&myrpt->lock);
11103 if (myrpt->txchannel != myrpt->rxchannel)
11104 ast_hangup(myrpt->txchannel);
11105 ast_hangup(myrpt->rxchannel);
11106 pthread_exit(NULL);
11108 ast_set_read_format(myrpt->pchannel,AST_FORMAT_SLINEAR);
11109 ast_set_write_format(myrpt->pchannel,AST_FORMAT_SLINEAR);
11110 #ifdef AST_CDR_FLAG_POST_DISABLED
11111 ast_set_flag(myrpt->pchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11112 #endif
11113 if (!myrpt->zaprxchannel) myrpt->zaprxchannel = myrpt->pchannel;
11114 if (!myrpt->zaptxchannel) myrpt->zaptxchannel = myrpt->pchannel;
11115 /* make a conference for the pseudo */
11116 ci.chan = 0;
11117 ci.confno = -1; /* make a new conf */
11118 ci.confmode = DAHDI_CONF_CONFANNMON ;
11119 /* first put the channel on the conference in announce/monitor mode */
11120 if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11122 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
11123 rpt_mutex_unlock(&myrpt->lock);
11124 ast_hangup(myrpt->pchannel);
11125 if (myrpt->txchannel != myrpt->rxchannel)
11126 ast_hangup(myrpt->txchannel);
11127 ast_hangup(myrpt->rxchannel);
11128 pthread_exit(NULL);
11130 /* save pseudo channel conference number */
11131 myrpt->conf = myrpt->txconf = ci.confno;
11132 /* if serial io port, open it */
11133 myrpt->iofd = -1;
11134 if (myrpt->p.ioport && ((myrpt->iofd = openserial(myrpt->p.ioport)) == -1))
11136 rpt_mutex_unlock(&myrpt->lock);
11137 ast_hangup(myrpt->pchannel);
11138 if (myrpt->txchannel != myrpt->rxchannel)
11139 ast_hangup(myrpt->txchannel);
11140 ast_hangup(myrpt->rxchannel);
11141 pthread_exit(NULL);
11143 iskenwood_pci4 = 0;
11144 memset(&z,0,sizeof(z));
11145 if ((myrpt->iofd < 1) && (myrpt->txchannel == myrpt->zaptxchannel))
11147 z.radpar = DAHDI_RADPAR_REMMODE;
11148 z.data = DAHDI_RADPAR_REM_NONE;
11149 res = ioctl(myrpt->zaptxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z);
11150 /* if PCIRADIO and kenwood selected */
11151 if ((!res) && (!strcmp(myrpt->remote,remote_rig_kenwood)))
11153 z.radpar = DAHDI_RADPAR_UIOMODE;
11154 z.data = 1;
11155 if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
11157 ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
11158 return -1;
11160 z.radpar = DAHDI_RADPAR_UIODATA;
11161 z.data = 3;
11162 if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
11164 ast_log(LOG_ERROR,"Cannot set UIODATA\n");
11165 return -1;
11167 i = DAHDI_OFFHOOK;
11168 if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_HOOK,&i) == -1)
11170 ast_log(LOG_ERROR,"Cannot set hook\n");
11171 return -1;
11173 iskenwood_pci4 = 1;
11176 if (myrpt->txchannel == myrpt->zaptxchannel)
11178 i = DAHDI_ONHOOK;
11179 ioctl(myrpt->zaptxchannel->fds[0],DAHDI_HOOK,&i);
11180 /* if PCIRADIO and Yaesu ft897/ICOM IC-706 selected */
11181 if ((myrpt->iofd < 1) && (!res) &&
11182 (!strcmp(myrpt->remote,remote_rig_ft897) ||
11183 (!strcmp(myrpt->remote,remote_rig_ic706))))
11185 z.radpar = DAHDI_RADPAR_UIOMODE;
11186 z.data = 1;
11187 if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
11189 ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
11190 return -1;
11192 z.radpar = DAHDI_RADPAR_UIODATA;
11193 z.data = 3;
11194 if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
11196 ast_log(LOG_ERROR,"Cannot set UIODATA\n");
11197 return -1;
11201 myrpt->remoterx = 0;
11202 myrpt->remotetx = 0;
11203 myrpt->retxtimer = 0;
11204 myrpt->rerxtimer = 0;
11205 myrpt->remoteon = 1;
11206 myrpt->dtmfidx = -1;
11207 myrpt->dtmfbuf[0] = 0;
11208 myrpt->dtmf_time_rem = 0;
11209 myrpt->hfscanmode = 0;
11210 myrpt->hfscanstatus = 0;
11211 if (myrpt->p.startupmacro)
11213 snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
11215 time(&myrpt->start_time);
11216 myrpt->last_activity_time = myrpt->start_time;
11217 last_timeout_warning = 0;
11218 myrpt->reload = 0;
11219 myrpt->tele.next = &myrpt->tele;
11220 myrpt->tele.prev = &myrpt->tele;
11221 rpt_mutex_unlock(&myrpt->lock);
11222 ast_set_write_format(chan, AST_FORMAT_SLINEAR);
11223 ast_set_read_format(chan, AST_FORMAT_SLINEAR);
11224 rem_rx = 0;
11225 remkeyed = 0;
11226 /* if we are on 2w loop and are a remote, turn EC on */
11227 if (myrpt->remote && (myrpt->rxchannel == myrpt->txchannel))
11229 i = 128;
11230 ioctl(myrpt->zaprxchannel->fds[0],DAHDI_ECHOCANCEL,&i);
11232 if (chan->_state != AST_STATE_UP) {
11233 ast_answer(chan);
11236 if (myrpt->rxchannel == myrpt->zaprxchannel)
11238 if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_GET_PARAMS,&par) != -1)
11240 if (par.rxisoffhook)
11242 ast_indicate(chan,AST_CONTROL_RADIO_KEY);
11243 myrpt->remoterx = 1;
11244 remkeyed = 1;
11248 if (myrpt->p.archivedir)
11250 char mycmd[100],mydate[100],*b,*b1;
11251 time_t myt;
11252 long blocksleft;
11255 mkdir(myrpt->p.archivedir,0600);
11256 sprintf(mycmd,"%s/%s",myrpt->p.archivedir,myrpt->name);
11257 mkdir(mycmd,0600);
11258 time(&myt);
11259 strftime(mydate,sizeof(mydate) - 1,"%Y%m%d%H%M%S",
11260 localtime(&myt));
11261 sprintf(mycmd,"mixmonitor start %s %s/%s/%s.wav49 a",chan->name,
11262 myrpt->p.archivedir,myrpt->name,mydate);
11263 if (myrpt->p.monminblocks)
11265 blocksleft = diskavail(myrpt);
11266 if (myrpt->p.remotetimeout)
11268 blocksleft -= (myrpt->p.remotetimeout *
11269 MONITOR_DISK_BLOCKS_PER_MINUTE) / 60;
11271 if (blocksleft >= myrpt->p.monminblocks)
11272 ast_cli_command(nullfd,mycmd);
11273 } else ast_cli_command(nullfd,mycmd);
11274 /* look at callerid to see what node this comes from */
11275 if (!chan->cid.cid_num) /* if doesn't have caller id */
11277 b1 = "0";
11278 } else {
11279 ast_callerid_parse(chan->cid.cid_num,&b,&b1);
11280 ast_shrink_phone_number(b1);
11282 sprintf(mycmd,"CONNECT,%s",b1);
11283 donodelog(myrpt,mycmd);
11285 myrpt->loginuser[0] = 0;
11286 myrpt->loginlevel[0] = 0;
11287 myrpt->authtelltimer = 0;
11288 myrpt->authtimer = 0;
11289 authtold = 0;
11290 authreq = 0;
11291 if (myrpt->p.authlevel > 1) authreq = 1;
11292 setrem(myrpt);
11293 n = 0;
11294 dtmfed = 0;
11295 cs[n++] = chan;
11296 cs[n++] = myrpt->rxchannel;
11297 cs[n++] = myrpt->pchannel;
11298 if (myrpt->rxchannel != myrpt->txchannel)
11299 cs[n++] = myrpt->txchannel;
11300 /* start un-locked */
11301 for(;;)
11303 if (ast_check_hangup(chan)) break;
11304 if (ast_check_hangup(myrpt->rxchannel)) break;
11305 notremming = 0;
11306 setting = 0;
11307 reming = 0;
11308 telem = myrpt->tele.next;
11309 while(telem != &myrpt->tele)
11311 if (telem->mode == SETREMOTE) setting = 1;
11312 if ((telem->mode == SETREMOTE) ||
11313 (telem->mode == SCAN) ||
11314 (telem->mode == TUNE)) reming = 1;
11315 else notremming = 1;
11316 telem = telem->next;
11318 if (myrpt->reload)
11320 myrpt->reload = 0;
11321 /* find our index, and load the vars */
11322 for(i = 0; i < nrpts; i++)
11324 if (&rpt_vars[i] == myrpt)
11326 load_rpt_vars(i,0);
11327 break;
11331 time(&t);
11332 if (myrpt->p.remotetimeout)
11334 time_t r;
11336 r = (t - myrpt->start_time);
11337 if (r >= myrpt->p.remotetimeout)
11339 sayfile(chan,"rpt/node");
11340 ast_say_character_str(chan,myrpt->name,NULL,chan->language);
11341 sayfile(chan,"rpt/timeout");
11342 ast_safe_sleep(chan,1000);
11343 break;
11345 if ((myrpt->p.remotetimeoutwarning) &&
11346 (r >= (myrpt->p.remotetimeout -
11347 myrpt->p.remotetimeoutwarning)) &&
11348 (r <= (myrpt->p.remotetimeout -
11349 myrpt->p.remotetimeoutwarningfreq)))
11351 if (myrpt->p.remotetimeoutwarningfreq)
11353 if ((t - last_timeout_warning) >=
11354 myrpt->p.remotetimeoutwarningfreq)
11356 time(&last_timeout_warning);
11357 rpt_telemetry(myrpt,TIMEOUT_WARNING,0);
11360 else
11362 if (!last_timeout_warning)
11364 time(&last_timeout_warning);
11365 rpt_telemetry(myrpt,TIMEOUT_WARNING,0);
11370 if (myrpt->p.remoteinacttimeout && myrpt->last_activity_time)
11372 time_t r;
11374 r = (t - myrpt->last_activity_time);
11375 if (r >= myrpt->p.remoteinacttimeout)
11377 sayfile(chan,"rpt/node");
11378 ast_say_character_str(chan,myrpt->name,NULL,chan->language);
11379 sayfile(chan,"rpt/timeout");
11380 ast_safe_sleep(chan,1000);
11381 break;
11383 if ((myrpt->p.remotetimeoutwarning) &&
11384 (r >= (myrpt->p.remoteinacttimeout -
11385 myrpt->p.remotetimeoutwarning)) &&
11386 (r <= (myrpt->p.remoteinacttimeout -
11387 myrpt->p.remotetimeoutwarningfreq)))
11389 if (myrpt->p.remotetimeoutwarningfreq)
11391 if ((t - last_timeout_warning) >=
11392 myrpt->p.remotetimeoutwarningfreq)
11394 time(&last_timeout_warning);
11395 rpt_telemetry(myrpt,ACT_TIMEOUT_WARNING,0);
11398 else
11400 if (!last_timeout_warning)
11402 time(&last_timeout_warning);
11403 rpt_telemetry(myrpt,ACT_TIMEOUT_WARNING,0);
11408 ms = MSWAIT;
11409 who = ast_waitfor_n(cs,n,&ms);
11410 if (who == NULL) ms = 0;
11411 elap = MSWAIT - ms;
11412 if (myrpt->macrotimer) myrpt->macrotimer -= elap;
11413 if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
11414 if (!ms) continue;
11415 /* do local dtmf timer */
11416 if (myrpt->dtmf_local_timer)
11418 if (myrpt->dtmf_local_timer > 1) myrpt->dtmf_local_timer -= elap;
11419 if (myrpt->dtmf_local_timer < 1) myrpt->dtmf_local_timer = 1;
11421 rpt_mutex_lock(&myrpt->lock);
11422 do_dtmf_local(myrpt,0);
11423 rpt_mutex_unlock(&myrpt->lock);
11424 rem_totx = myrpt->dtmf_local_timer && (!phone_mode);
11425 rem_totx |= keyed && (!myrpt->tunerequest);
11426 rem_rx = (remkeyed && (!setting)) || (myrpt->tele.next != &myrpt->tele);
11427 if(!strcmp(myrpt->remote, remote_rig_ic706))
11428 rem_totx |= myrpt->tunerequest;
11429 if (keyed && (!keyed1))
11431 keyed1 = 1;
11434 if (!keyed && (keyed1))
11436 time_t myt;
11438 keyed1 = 0;
11439 time(&myt);
11440 /* if login necessary, and not too soon */
11441 if ((myrpt->p.authlevel) &&
11442 (!myrpt->loginlevel[0]) &&
11443 (myt > (t + 3)))
11445 authreq = 1;
11446 authtold = 0;
11447 myrpt->authtelltimer = AUTHTELLTIME - AUTHTXTIME;
11452 if (rem_rx && (!myrpt->remoterx))
11454 myrpt->remoterx = 1;
11455 ast_indicate(chan,AST_CONTROL_RADIO_KEY);
11457 if ((!rem_rx) && (myrpt->remoterx))
11459 myrpt->remoterx = 0;
11460 ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
11462 /* if auth requested, and not authed yet */
11463 if (authreq && (!myrpt->loginlevel[0]))
11465 if ((!authtold) && ((myrpt->authtelltimer += elap)
11466 >= AUTHTELLTIME))
11468 authtold = 1;
11469 rpt_telemetry(myrpt,LOGINREQ,NULL);
11471 if ((myrpt->authtimer += elap) >= AUTHLOGOUTTIME)
11473 break; /* if not logged in, hang up after a time */
11476 #ifndef OLDKEY
11477 if ((myrpt->retxtimer += elap) >= REDUNDANT_TX_TIME)
11479 myrpt->retxtimer = 0;
11480 if ((myrpt->remoterx) && (!myrpt->remotetx))
11481 ast_indicate(chan,AST_CONTROL_RADIO_KEY);
11482 else
11483 ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
11486 if ((myrpt->rerxtimer += elap) >= (REDUNDANT_TX_TIME * 2))
11488 keyed = 0;
11489 myrpt->rerxtimer = 0;
11491 #endif
11492 if (rem_totx && (!myrpt->remotetx))
11494 /* if not authed, and needed, dont transmit */
11495 if ((!myrpt->p.authlevel) || myrpt->loginlevel[0])
11497 myrpt->remotetx = 1;
11498 if((myrpt->remtxfreqok = check_tx_freq(myrpt)))
11500 time(&myrpt->last_activity_time);
11501 if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->zaptxchannel))
11503 z.radpar = DAHDI_RADPAR_UIODATA;
11504 z.data = 1;
11505 if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
11507 ast_log(LOG_ERROR,"Cannot set UIODATA\n");
11508 return -1;
11511 else
11513 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
11515 if (myrpt->p.archivedir) donodelog(myrpt,"TXKEY");
11519 if ((!rem_totx) && myrpt->remotetx) /* Remote base radio TX unkey */
11521 myrpt->remotetx = 0;
11522 if(!myrpt->remtxfreqok){
11523 rpt_telemetry(myrpt,UNAUTHTX,NULL);
11525 if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->zaptxchannel))
11527 z.radpar = DAHDI_RADPAR_UIODATA;
11528 z.data = 3;
11529 if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
11531 ast_log(LOG_ERROR,"Cannot set UIODATA\n");
11532 return -1;
11535 else
11537 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
11539 if (myrpt->p.archivedir) donodelog(myrpt,"TXUNKEY");
11541 if (myrpt->hfscanmode){
11542 myrpt->scantimer -= elap;
11543 if(myrpt->scantimer <= 0){
11544 if (!reming)
11546 myrpt->scantimer = REM_SCANTIME;
11547 rpt_telemetry(myrpt,SCAN,0);
11548 } else myrpt->scantimer = 1;
11551 rpt_mutex_lock(&myrpt->lock);
11552 c = myrpt->macrobuf[0];
11553 if (c && (!myrpt->macrotimer))
11555 myrpt->macrotimer = MACROTIME;
11556 memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1);
11557 if ((c == 'p') || (c == 'P'))
11558 myrpt->macrotimer = MACROPTIME;
11559 rpt_mutex_unlock(&myrpt->lock);
11560 if (myrpt->p.archivedir)
11562 char str[100];
11563 sprintf(str,"DTMF(M),%c",c);
11564 donodelog(myrpt,str);
11566 if (handle_remote_dtmf_digit(myrpt,c,&keyed,0) == -1) break;
11567 continue;
11568 } else rpt_mutex_unlock(&myrpt->lock);
11569 if (who == chan) /* if it was a read from incomming */
11571 f = ast_read(chan);
11572 if (!f)
11574 if (debug) printf("@@@@ link:Hung Up\n");
11575 break;
11577 if (f->frametype == AST_FRAME_VOICE)
11579 if (ioctl(chan->fds[0], DAHDI_GETCONFMUTE, &ismuted) == -1)
11581 ismuted = 0;
11583 /* if not transmitting, zero-out audio */
11584 ismuted |= (!myrpt->remotetx);
11585 if (dtmfed && phone_mode) ismuted = 1;
11586 dtmfed = 0;
11587 if (ismuted)
11589 memset(f->data,0,f->datalen);
11590 if (myrpt->lastf1)
11591 memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
11592 if (myrpt->lastf2)
11593 memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
11595 if (f) f2 = ast_frdup(f);
11596 else f2 = NULL;
11597 f1 = myrpt->lastf2;
11598 myrpt->lastf2 = myrpt->lastf1;
11599 myrpt->lastf1 = f2;
11600 if (ismuted)
11602 if (myrpt->lastf1)
11603 memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
11604 if (myrpt->lastf2)
11605 memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
11607 if (f1)
11609 if (phone_mode)
11610 ast_write(myrpt->txchannel,f1);
11611 else
11612 ast_write(myrpt->txchannel,f);
11613 ast_frfree(f1);
11616 #ifndef OLD_ASTERISK
11617 else if (f->frametype == AST_FRAME_DTMF_BEGIN)
11619 if (myrpt->lastf1)
11620 memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
11621 if (myrpt->lastf2)
11622 memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
11623 dtmfed = 1;
11625 #endif
11626 if (f->frametype == AST_FRAME_DTMF)
11628 if (myrpt->lastf1)
11629 memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
11630 if (myrpt->lastf2)
11631 memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
11632 dtmfed = 1;
11633 if (handle_remote_phone_dtmf(myrpt,f->subclass,&keyed,phone_mode) == -1)
11635 if (debug) printf("@@@@ rpt:Hung Up\n");
11636 ast_frfree(f);
11637 break;
11640 if (f->frametype == AST_FRAME_TEXT)
11642 if (handle_remote_data(myrpt,f->data) == -1)
11644 if (debug) printf("@@@@ rpt:Hung Up\n");
11645 ast_frfree(f);
11646 break;
11649 if (f->frametype == AST_FRAME_CONTROL)
11651 if (f->subclass == AST_CONTROL_HANGUP)
11653 if (debug) printf("@@@@ rpt:Hung Up\n");
11654 ast_frfree(f);
11655 break;
11657 /* if RX key */
11658 if (f->subclass == AST_CONTROL_RADIO_KEY)
11660 if (debug == 7) printf("@@@@ rx key\n");
11661 keyed = 1;
11662 myrpt->rerxtimer = 0;
11664 /* if RX un-key */
11665 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
11667 myrpt->rerxtimer = 0;
11668 if (debug == 7) printf("@@@@ rx un-key\n");
11669 keyed = 0;
11672 ast_frfree(f);
11673 continue;
11675 if (who == myrpt->rxchannel) /* if it was a read from radio */
11677 f = ast_read(myrpt->rxchannel);
11678 if (!f)
11680 if (debug) printf("@@@@ link:Hung Up\n");
11681 break;
11683 if (f->frametype == AST_FRAME_VOICE)
11685 int myreming = 0;
11687 if(!strcmp(myrpt->remote, remote_rig_kenwood))
11688 myreming = reming;
11690 if (myreming || (!remkeyed) ||
11691 ((myrpt->remote) && (myrpt->remotetx)) ||
11692 ((myrpt->remmode != REM_MODE_FM) &&
11693 notremming))
11694 memset(f->data,0,f->datalen);
11695 ast_write(myrpt->pchannel,f);
11697 else if (f->frametype == AST_FRAME_CONTROL)
11699 if (f->subclass == AST_CONTROL_HANGUP)
11701 if (debug) printf("@@@@ rpt:Hung Up\n");
11702 ast_frfree(f);
11703 break;
11705 /* if RX key */
11706 if (f->subclass == AST_CONTROL_RADIO_KEY)
11708 if (debug == 7) printf("@@@@ remote rx key\n");
11709 if (!myrpt->remotetx)
11711 remkeyed = 1;
11714 /* if RX un-key */
11715 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
11717 if (debug == 7) printf("@@@@ remote rx un-key\n");
11718 if (!myrpt->remotetx)
11720 remkeyed = 0;
11724 ast_frfree(f);
11725 continue;
11727 if (who == myrpt->pchannel) /* if is remote mix output */
11729 f = ast_read(myrpt->pchannel);
11730 if (!f)
11732 if (debug) printf("@@@@ link:Hung Up\n");
11733 break;
11735 if (f->frametype == AST_FRAME_VOICE)
11737 ast_write(chan,f);
11739 if (f->frametype == AST_FRAME_CONTROL)
11741 if (f->subclass == AST_CONTROL_HANGUP)
11743 if (debug) printf("@@@@ rpt:Hung Up\n");
11744 ast_frfree(f);
11745 break;
11748 ast_frfree(f);
11749 continue;
11751 if ((myrpt->rxchannel != myrpt->txchannel) &&
11752 (who == myrpt->txchannel)) /* do this cuz you have to */
11754 f = ast_read(myrpt->txchannel);
11755 if (!f)
11757 if (debug) printf("@@@@ link:Hung Up\n");
11758 break;
11760 if (f->frametype == AST_FRAME_CONTROL)
11762 if (f->subclass == AST_CONTROL_HANGUP)
11764 if (debug) printf("@@@@ rpt:Hung Up\n");
11765 ast_frfree(f);
11766 break;
11769 ast_frfree(f);
11770 continue;
11773 if (myrpt->p.archivedir)
11775 char mycmd[100],*b,*b1;
11777 /* look at callerid to see what node this comes from */
11778 if (!chan->cid.cid_num) /* if doesn't have caller id */
11780 b1 = "0";
11781 } else {
11782 ast_callerid_parse(chan->cid.cid_num,&b,&b1);
11783 ast_shrink_phone_number(b1);
11785 sprintf(mycmd,"DISCONNECT,%s",b1);
11786 donodelog(myrpt,mycmd);
11788 /* wait for telem to be done */
11789 while(myrpt->tele.next != &myrpt->tele) usleep(100000);
11790 sprintf(tmp,"mixmonitor stop %s",chan->name);
11791 ast_cli_command(nullfd,tmp);
11792 close(nullfd);
11793 rpt_mutex_lock(&myrpt->lock);
11794 myrpt->hfscanmode = 0;
11795 myrpt->hfscanstatus = 0;
11796 myrpt->remoteon = 0;
11797 rpt_mutex_unlock(&myrpt->lock);
11798 if (myrpt->lastf1) ast_frfree(myrpt->lastf1);
11799 myrpt->lastf1 = NULL;
11800 if (myrpt->lastf2) ast_frfree(myrpt->lastf2);
11801 myrpt->lastf2 = NULL;
11802 if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->zaptxchannel))
11804 z.radpar = DAHDI_RADPAR_UIOMODE;
11805 z.data = 3;
11806 if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
11808 ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
11809 return -1;
11811 z.radpar = DAHDI_RADPAR_UIODATA;
11812 z.data = 3;
11813 if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
11815 ast_log(LOG_ERROR,"Cannot set UIODATA\n");
11816 return -1;
11818 i = DAHDI_OFFHOOK;
11819 if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_HOOK,&i) == -1)
11821 ast_log(LOG_ERROR,"Cannot set hook\n");
11822 return -1;
11825 if (myrpt->iofd) close(myrpt->iofd);
11826 myrpt->iofd = -1;
11827 ast_hangup(myrpt->pchannel);
11828 if (myrpt->rxchannel != myrpt->txchannel) ast_hangup(myrpt->txchannel);
11829 ast_hangup(myrpt->rxchannel);
11830 closerem(myrpt);
11831 #ifdef OLD_ASTERISK
11832 LOCAL_USER_REMOVE(u);
11833 #endif
11834 return res;
11837 #ifdef OLD_ASTERISK
11838 int unload_module()
11839 #else
11840 static int unload_module(void)
11841 #endif
11843 int i;
11845 #ifdef OLD_ASTERISK
11846 STANDARD_HANGUP_LOCALUSERS;
11847 #endif
11848 for(i = 0; i < nrpts; i++) {
11849 if (!strcmp(rpt_vars[i].name,rpt_vars[i].p.nodes)) continue;
11850 ast_mutex_destroy(&rpt_vars[i].lock);
11851 ast_mutex_destroy(&rpt_vars[i].remlock);
11853 i = ast_unregister_application(app);
11855 /* Unregister cli extensions */
11856 ast_cli_unregister(&cli_debug);
11857 ast_cli_unregister(&cli_dump);
11858 ast_cli_unregister(&cli_stats);
11859 ast_cli_unregister(&cli_lstats);
11860 ast_cli_unregister(&cli_nodes);
11861 ast_cli_unregister(&cli_reload);
11862 ast_cli_unregister(&cli_restart);
11863 ast_cli_unregister(&cli_fun);
11865 return i;
11868 #ifdef OLD_ASTERISK
11869 int load_module()
11870 #else
11871 static int load_module(void)
11872 #endif
11874 ast_pthread_create(&rpt_master_thread,NULL,rpt_master,NULL);
11876 /* Register cli extensions */
11877 ast_cli_register(&cli_debug);
11878 ast_cli_register(&cli_dump);
11879 ast_cli_register(&cli_stats);
11880 ast_cli_register(&cli_lstats);
11881 ast_cli_register(&cli_nodes);
11882 ast_cli_register(&cli_reload);
11883 ast_cli_register(&cli_restart);
11884 ast_cli_register(&cli_fun);
11886 return ast_register_application(app, rpt_exec, synopsis, descrip);
11889 #ifdef OLD_ASTERISK
11890 char *description()
11892 return tdesc;
11894 int usecount(void)
11896 int res;
11897 STANDARD_USECOUNT(res);
11898 return res;
11901 char *key()
11903 return ASTERISK_GPL_KEY;
11905 #endif
11907 #ifdef OLD_ASTERISK
11908 int reload()
11909 #else
11910 static int reload(void)
11911 #endif
11913 int n;
11915 for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
11916 return(0);
11919 #ifndef OLD_ASTERISK
11920 /* STD_MOD(MOD_1, reload, NULL, NULL); */
11921 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Radio Repeater/Remote Base Application",
11922 .load = load_module,
11923 .unload = unload_module,
11924 .reload = reload,
11927 #endif