use the proper type for storing group number bits so that if someone specifies 'group...
[asterisk-bristuff.git] / apps / app_rpt.c
blob34732a25a179d0f7191f53e2ea9603fcb94941f7
1 /*
2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2002-2005, Jim Dixon, WB6NIL
6 * Jim Dixon, WB6NIL <jim@lambdatel.com>
7 * Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
9 * See http://www.asterisk.org for more information about
10 * the Asterisk project. Please do not directly contact
11 * any of the maintainers of this project for assistance;
12 * the project provides a web site, mailing lists and IRC
13 * channels for your use.
15 * This program is free software, distributed under the terms of
16 * the GNU General Public License Version 2. See the LICENSE file
17 * at the top of the source tree.
20 /*! \file
22 * \brief Radio Repeater / Remote Base program
23 * version 0.48 06/13/06
25 * \author Jim Dixon, WB6NIL <jim@lambdatel.com>
27 * \note Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
29 * See http://www.zapatatelephony.org/app_rpt.html
32 * Repeater / Remote Functions:
33 * "Simple" Mode: * - autopatch access, # - autopatch hangup
34 * Normal mode:
35 * See the function list in rpt.conf (autopatchup, autopatchdn)
36 * autopatchup can optionally take comma delimited setting=value pairs:
39 * context=string : Override default context with "string"
40 * dialtime=ms : Specify the max number of milliseconds between phone number digits (1000 milliseconds = 1 second)
41 * farenddisconnect=1 : Automatically disconnect when called party hangs up
42 * noct=1 : Don't send repeater courtesy tone during autopatch calls
43 * quiet=1 : Don't send dial tone, or connect messages. Do not send patch down message when called party hangs up
46 * Example: 123=autopatchup,dialtime=20000,noct=1,farenddisconnect=1
48 * To send an asterisk (*) while dialing or talking on phone,
49 * use the autopatch acess code.
52 * status cmds:
54 * 1 - Force ID
55 * 2 - Give Time of Day
56 * 3 - Give software Version
58 * cop (control operator) cmds:
60 * 1 - System warm boot
61 * 2 - System enable
62 * 3 - System disable
63 * 4 - Test Tone On
64 * 5 - Dump System Variables on Console (debug)
65 * 6 - PTT (phone mode only)
67 * ilink cmds:
69 * 1 - Disconnect specified link
70 * 2 - Connect specified link -- monitor only
71 * 3 - Connect specified link -- tranceive
72 * 4 - Enter command mode on specified link
73 * 5 - System status
74 * 6 - Disconnect all links
76 * remote cmds:
78 * 1 - Recall Memory MM (*000-*099) (Gets memory from rpt.conf)
79 * 2 - Set VFO MMMMM*KKK*O (Mhz digits, Khz digits, Offset)
80 * 3 - Set Rx PL Tone HHH*D*
81 * 4 - Set Tx PL Tone HHH*D* (Not currently implemented with DHE RBI-1)
82 * 5 - Link Status (long)
83 * 6 - Set operating mode M (FM, USB, LSB, AM, etc)
84 * 100 - RX PL off (Default)
85 * 101 - RX PL On
86 * 102 - TX PL Off (Default)
87 * 103 - TX PL On
88 * 104 - Low Power
89 * 105 - Med Power
90 * 106 - Hi Power
91 * 107 - Bump Down 20 Hz
92 * 108 - Bump Down 100 Hz
93 * 109 - Bump Down 500 Hz
94 * 110 - Bump Up 20 Hz
95 * 111 - Bump Up 100 Hz
96 * 112 - Bump Up 500 Hz
97 * 113 - Scan Down Slow
98 * 114 - Scan Down Medium
99 * 115 - Scan Down Fast
100 * 116 - Scan Up Slow
101 * 117 - Scan Up Medium
102 * 118 - Scan Up Fast
103 * 119 - Transmit allowing auto-tune
104 * 140 - Link Status (brief)
108 * 'duplex' modes: (defaults to duplex=2)
110 * 0 - Only remote links key Tx and no main repeat audio.
111 * 1 - Everything other then main Rx keys Tx, no main repeat audio.
112 * 2 - Normal mode
113 * 3 - Normal except no main repeat audio.
114 * 4 - Normal except no main repeat audio during autopatch only
118 /*** MODULEINFO
119 <depend>zaptel</depend>
120 <depend>tonezone</depend>
121 <defaultenabled>no</defaultenabled>
122 ***/
124 /* Un-comment the following to include support for MDC-1200 digital tone
125 signalling protocol (using KA6SQG's GPL'ed implementation) */
126 /* #include "mdc_decode.c" */
128 /* Un-comment the following to include support for notch filters in the
129 rx audio stream (using Tony Fisher's mknotch (mkfilter) implementation) */
130 /* #include "rpt_notch.c" */
132 /* maximum digits in DTMF buffer, and seconds after * for DTMF command timeout */
134 #define MAXDTMF 32
135 #define MAXMACRO 2048
136 #define MACROTIME 100
137 #define MACROPTIME 500
138 #define DTMF_TIMEOUT 3
140 #ifdef __RPT_NOTCH
141 #define MAXFILTERS 10
142 #endif
144 #define DISC_TIME 10000 /* report disc after 10 seconds of no connect */
145 #define MAX_RETRIES 5
147 #define REDUNDANT_TX_TIME 2000
149 #define RETRY_TIMER_MS 5000
151 #define MAXPEERSTR 31
152 #define MAXREMSTR 15
154 #define DELIMCHR ','
155 #define QUOTECHR 34
157 #define NODES "nodes"
158 #define MEMORY "memory"
159 #define MACRO "macro"
160 #define FUNCTIONS "functions"
161 #define TELEMETRY "telemetry"
162 #define MORSE "morse"
163 #define FUNCCHAR '*'
164 #define ENDCHAR '#'
166 #define DEFAULT_IOBASE 0x378
168 #define MAXCONNECTTIME 5000
170 #define MAXNODESTR 300
172 #define MAXPATCHCONTEXT 100
174 #define ACTIONSIZE 32
176 #define TELEPARAMSIZE 256
178 #define REM_SCANTIME 100
181 enum {REM_OFF,REM_MONITOR,REM_TX};
183 enum{ID,PROC,TERM,COMPLETE,UNKEY,REMDISC,REMALREADY,REMNOTFOUND,REMGO,
184 CONNECTED,CONNFAIL,STATUS,TIMEOUT,ID1, STATS_TIME,
185 STATS_VERSION, IDTALKOVER, ARB_ALPHA, TEST_TONE, REV_PATCH,
186 TAILMSG, MACRO_NOTFOUND, MACRO_BUSY, LASTNODEKEY};
188 enum {REM_SIMPLEX,REM_MINUS,REM_PLUS};
190 enum {REM_LOWPWR,REM_MEDPWR,REM_HIPWR};
192 enum {DC_INDETERMINATE, DC_REQ_FLUSH, DC_ERROR, DC_COMPLETE, DC_DOKEY};
194 enum {SOURCE_RPT, SOURCE_LNK, SOURCE_RMT, SOURCE_PHONE, SOURCE_DPHONE};
196 enum {DLY_TELEM, DLY_ID, DLY_UNKEY, DLY_CALLTERM};
198 enum {REM_MODE_FM,REM_MODE_USB,REM_MODE_LSB,REM_MODE_AM};
200 enum {HF_SCAN_OFF,HF_SCAN_DOWN_SLOW,HF_SCAN_DOWN_QUICK,
201 HF_SCAN_DOWN_FAST,HF_SCAN_UP_SLOW,HF_SCAN_UP_QUICK,HF_SCAN_UP_FAST};
203 #include "asterisk.h"
205 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
207 #include <signal.h>
208 #include <stdio.h>
209 #include <unistd.h>
210 #include <string.h>
211 #include <stdlib.h>
212 #include <search.h>
213 #include <sys/types.h>
214 #include <sys/stat.h>
215 #include <errno.h>
216 #include <dirent.h>
217 #include <ctype.h>
218 #include <sys/stat.h>
219 #include <sys/time.h>
220 #include <sys/file.h>
221 #include <sys/ioctl.h>
222 #include <sys/io.h>
223 #include <math.h>
224 #include <zaptel/zaptel.h>
225 #include <zaptel/tonezone.h>
226 #include <netinet/in.h>
227 #include <arpa/inet.h>
229 #include "asterisk/utils.h"
230 #include "asterisk/lock.h"
231 #include "asterisk/file.h"
232 #include "asterisk/logger.h"
233 #include "asterisk/channel.h"
234 #include "asterisk/callerid.h"
235 #include "asterisk/pbx.h"
236 #include "asterisk/module.h"
237 #include "asterisk/translate.h"
238 #include "asterisk/features.h"
239 #include "asterisk/options.h"
240 #include "asterisk/cli.h"
241 #include "asterisk/config.h"
242 #include "asterisk/say.h"
243 #include "asterisk/localtime.h"
245 static char *app = "Rpt";
247 static char *synopsis = "Radio Repeater/Remote Base Control System";
249 static char *descrip =
250 " Rpt(nodename[|options]): Radio Remote Link or Remote Base Link Endpoint Process.\n"
251 "\n"
252 " Not specifying an option puts it in normal endpoint mode (where source\n"
253 " IP and nodename are verified).\n"
254 "\n"
255 " Options are as follows:\n"
256 "\n"
257 " X - Normal endpoint mode WITHOUT security check. Only specify\n"
258 " this if you have checked security already (like with an IAX2\n"
259 " user/password or something).\n"
260 "\n"
261 " Rannounce-string[|timeout[|timeout-destination]] - Amateur Radio\n"
262 " Reverse Autopatch. Caller is put on hold, and announcement (as\n"
263 " specified by the 'announce-string') is played on radio system.\n"
264 " Users of radio system can access autopatch, dial specified\n"
265 " code, and pick up call. Announce-string is list of names of\n"
266 " recordings, or \"PARKED\" to substitute code for un-parking,\n"
267 " or \"NODE\" to substitute node number.\n"
268 "\n"
269 " P - Phone Control mode. This allows a regular phone user to have\n"
270 " full control and audio access to the radio system. For the\n"
271 " user to have DTMF control, the 'phone_functions' parameter\n"
272 " must be specified for the node in 'rpt.conf'. An additional\n"
273 " function (cop,6) must be listed so that PTT control is available.\n"
274 "\n"
275 " D - Dumb Phone Control mode. This allows a regular phone user to\n"
276 " have full control and audio access to the radio system. In this\n"
277 " mode, the PTT is activated for the entire length of the call.\n"
278 " For the user to have DTMF control (not generally recomended in\n"
279 " this mode), the 'dphone_functions' parameter must be specified\n"
280 " for the node in 'rpt.conf'. Otherwise no DTMF control will be\n"
281 " available to the phone user.\n"
282 "\n";
284 static unsigned int vmajor = 0;
285 static unsigned int vminor = 47;
287 static int debug = 0; /* FIXME Set this >0 for extra debug output */
288 static int nrpts = 0;
290 char *discstr = "!!DISCONNECT!!";
291 static char *remote_rig_ft897="ft897";
292 static char *remote_rig_rbi="rbi";
294 #ifdef OLD_ASTERISK
295 STANDARD_LOCAL_USER;
296 #endif
299 #define MSWAIT 200
300 #define HANGTIME 5000
301 #define TOTIME 180000
302 #define IDTIME 300000
303 #define MAXRPTS 20
304 #define MAX_STAT_LINKS 32
305 #define POLITEID 30000
306 #define FUNCTDELAY 1500
308 static pthread_t rpt_master_thread;
310 struct rpt;
312 struct rpt_link
314 struct rpt_link *next;
315 struct rpt_link *prev;
316 char mode; /* 1 if in tx mode */
317 char isremote;
318 char phonemode;
319 char name[MAXNODESTR]; /* identifier (routing) string */
320 char lasttx;
321 char lastrx;
322 char connected;
323 char hasconnected;
324 char outbound;
325 char disced;
326 char killme;
327 long elaptime;
328 long disctime;
329 long retrytimer;
330 long retxtimer;
331 int retries;
332 int reconnects;
333 long long connecttime;
334 struct ast_channel *chan;
335 struct ast_channel *pchan;
338 struct rpt_lstat
340 struct rpt_lstat *next;
341 struct rpt_lstat *prev;
342 char peer[MAXPEERSTR];
343 char name[MAXNODESTR];
344 char mode;
345 char outbound;
346 char reconnects;
347 long long connecttime;
350 struct rpt_tele
352 struct rpt_tele *next;
353 struct rpt_tele *prev;
354 struct rpt *rpt;
355 struct ast_channel *chan;
356 int mode;
357 struct rpt_link mylink;
358 char param[TELEPARAMSIZE];
359 pthread_t threadid;
362 struct function_table_tag
364 char action[ACTIONSIZE];
365 int (*function)(struct rpt *myrpt, char *param, char *digitbuf,
366 int command_source, struct rpt_link *mylink);
369 /* Used to store the morse code patterns */
371 struct morse_bits
373 int len;
374 int ddcomb;
377 struct telem_defaults
379 char name[20];
380 char value[80];
384 static struct rpt
386 ast_mutex_t lock;
387 struct ast_config *cfg;
388 char reload;
390 char *name;
391 char *rxchanname;
392 char *txchanname;
393 char *remote;
395 struct {
397 const char *ourcontext;
398 const char *ourcallerid;
399 const char *acctcode;
400 const char *ident;
401 char *tonezone;
402 char simple;
403 const char *functions;
404 const char *link_functions;
405 const char *phone_functions;
406 const char *dphone_functions;
407 const char *nodes;
408 int hangtime;
409 int totime;
410 int idtime;
411 int tailmessagetime;
412 int tailsquashedtime;
413 int duplex;
414 int politeid;
415 char *tailmessages[500];
416 int tailmessagemax;
417 const char *memory;
418 const char *macro;
419 const char *startupmacro;
420 int iobase;
421 char funcchar;
422 char endchar;
423 char nobusyout;
424 } p;
425 struct rpt_link links;
426 int unkeytocttimer;
427 char keyed;
428 char exttx;
429 char localtx;
430 char remoterx;
431 char remotetx;
432 char remoteon;
433 char tounkeyed;
434 char tonotify;
435 char enable;
436 char dtmfbuf[MAXDTMF];
437 char macrobuf[MAXMACRO];
438 char rem_dtmfbuf[MAXDTMF];
439 char lastdtmfcommand[MAXDTMF];
440 char cmdnode[50];
441 struct ast_channel *rxchannel,*txchannel;
442 struct ast_channel *pchannel,*txpchannel, *remchannel;
443 struct rpt_tele tele;
444 struct timeval lasttv,curtv;
445 pthread_t rpt_call_thread,rpt_thread;
446 time_t dtmf_time,rem_dtmf_time,dtmf_time_rem;
447 int tailtimer,totimer,idtimer,txconf,conf,callmode,cidx,scantimer,tmsgtimer,skedtimer;
448 int mustid,tailid;
449 int tailevent;
450 int telemrefcount;
451 int dtmfidx,rem_dtmfidx;
452 int dailytxtime,dailykerchunks,totalkerchunks,dailykeyups,totalkeyups,timeouts;
453 int totalexecdcommands, dailyexecdcommands;
454 long retxtimer;
455 long long totaltxtime;
456 char mydtmf;
457 char exten[AST_MAX_EXTENSION];
458 char freq[MAXREMSTR],rxpl[MAXREMSTR],txpl[MAXREMSTR];
459 char offset;
460 char powerlevel;
461 char txplon;
462 char rxplon;
463 char remmode;
464 char tunerequest;
465 char hfscanmode;
466 int hfscanstatus;
467 char lastlinknode[MAXNODESTR];
468 char stopgen;
469 char patchfarenddisconnect;
470 char patchnoct;
471 char patchquiet;
472 char patchcontext[MAXPATCHCONTEXT];
473 int patchdialtime;
474 int macro_longest;
475 int phone_longestfunc;
476 int dphone_longestfunc;
477 int link_longestfunc;
478 int longestfunc;
479 int longestnode;
480 int threadrestarts;
481 int tailmessagen;
482 time_t disgorgetime;
483 time_t lastthreadrestarttime;
484 long macrotimer;
485 char lastnodewhichkeyedusup[MAXNODESTR];
486 #ifdef __RPT_NOTCH
487 struct rptfilter
489 char desc[100];
490 float x0;
491 float x1;
492 float x2;
493 float y0;
494 float y1;
495 float y2;
496 float gain;
497 float const0;
498 float const1;
499 float const2;
500 } filters[MAXFILTERS];
501 #endif
502 #ifdef _MDC_DECODE_H_
503 mdc_decoder_t *mdc;
504 unsigned short lastunit;
505 #endif
506 } rpt_vars[MAXRPTS];
509 #ifdef APP_RPT_LOCK_DEBUG
511 #warning COMPILING WITH LOCK-DEBUGGING ENABLED!!
513 #define MAXLOCKTHREAD 100
515 #define rpt_mutex_lock(x) _rpt_mutex_lock(x,myrpt,__LINE__)
516 #define rpt_mutex_unlock(x) _rpt_mutex_unlock(x,myrpt,__LINE__)
518 struct lockthread
520 pthread_t id;
521 int lockcount;
522 int lastlock;
523 int lastunlock;
524 } lockthreads[MAXLOCKTHREAD];
527 struct by_lightning
529 int line;
530 struct timeval tv;
531 struct rpt *rpt;
532 struct lockthread lockthread;
533 } lock_ring[32];
536 int lock_ring_index = 0;
538 AST_MUTEX_DEFINE_STATIC(locklock);
540 static struct lockthread *get_lockthread(pthread_t id)
542 int i;
544 for(i = 0; i < MAXLOCKTHREAD; i++)
546 if (lockthreads[i].id == id) return(&lockthreads[i]);
548 return(NULL);
551 static struct lockthread *put_lockthread(pthread_t id)
553 int i;
555 for(i = 0; i < MAXLOCKTHREAD; i++)
557 if (lockthreads[i].id == id)
558 return(&lockthreads[i]);
560 for(i = 0; i < MAXLOCKTHREAD; i++)
562 if (!lockthreads[i].id)
564 lockthreads[i].lockcount = 0;
565 lockthreads[i].lastlock = 0;
566 lockthreads[i].lastunlock = 0;
567 lockthreads[i].id = id;
568 return(&lockthreads[i]);
571 return(NULL);
575 static void rpt_mutex_spew(void)
577 struct by_lightning lock_ring_copy[32];
578 int lock_ring_index_copy;
579 int i,j;
580 long long diff;
581 char a[100];
582 struct timeval lasttv;
584 ast_mutex_lock(&locklock);
585 memcpy(&lock_ring_copy, &lock_ring, sizeof(lock_ring_copy));
586 lock_ring_index_copy = lock_ring_index;
587 ast_mutex_unlock(&locklock);
589 lasttv.tv_sec = lasttv.tv_usec = 0;
590 for(i = 0 ; i < 32 ; i++)
592 j = (i + lock_ring_index_copy) % 32;
593 strftime(a,sizeof(a) - 1,"%m/%d/%Y %H:%M:%S",
594 localtime(&lock_ring_copy[j].tv.tv_sec));
595 diff = 0;
596 if(lasttv.tv_sec)
598 diff = (lock_ring_copy[j].tv.tv_sec - lasttv.tv_sec)
599 * 1000000;
600 diff += (lock_ring_copy[j].tv.tv_usec - lasttv.tv_usec);
602 lasttv.tv_sec = lock_ring_copy[j].tv.tv_sec;
603 lasttv.tv_usec = lock_ring_copy[j].tv.tv_usec;
604 if (!lock_ring_copy[j].tv.tv_sec) continue;
605 if (lock_ring_copy[j].line < 0)
607 ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] UNLOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
608 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);
610 else
612 ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] LOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
613 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);
619 static void _rpt_mutex_lock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
621 struct lockthread *t;
622 pthread_t id;
624 id = pthread_self();
625 ast_mutex_lock(&locklock);
626 t = put_lockthread(id);
627 if (!t)
629 ast_mutex_unlock(&locklock);
630 return;
632 if (t->lockcount)
634 int lastline = t->lastlock;
635 ast_mutex_unlock(&locklock);
636 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);
637 rpt_mutex_spew();
638 return;
640 t->lastlock = line;
641 t->lockcount = 1;
642 gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
643 lock_ring[lock_ring_index].rpt = myrpt;
644 memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
645 lock_ring[lock_ring_index++].line = line;
646 if(lock_ring_index == 32)
647 lock_ring_index = 0;
648 ast_mutex_unlock(&locklock);
649 ast_mutex_lock(lockp);
653 static void _rpt_mutex_unlock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
655 struct lockthread *t;
656 pthread_t id;
658 id = pthread_self();
659 ast_mutex_lock(&locklock);
660 t = put_lockthread(id);
661 if (!t)
663 ast_mutex_unlock(&locklock);
664 return;
666 if (!t->lockcount)
668 int lastline = t->lastunlock;
669 ast_mutex_unlock(&locklock);
670 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);
671 rpt_mutex_spew();
672 return;
674 t->lastunlock = line;
675 t->lockcount = 0;
676 gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
677 lock_ring[lock_ring_index].rpt = myrpt;
678 memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
679 lock_ring[lock_ring_index++].line = -line;
680 if(lock_ring_index == 32)
681 lock_ring_index = 0;
682 ast_mutex_unlock(&locklock);
683 ast_mutex_unlock(lockp);
686 #else /* APP_RPT_LOCK_DEBUG */
688 #define rpt_mutex_lock(x) ast_mutex_lock(x)
689 #define rpt_mutex_unlock(x) ast_mutex_unlock(x)
691 #endif /* APP_RPT_LOCK_DEBUG */
694 * CLI extensions
697 /* Debug mode */
698 static int rpt_do_debug(int fd, int argc, char *argv[]);
699 static int rpt_do_dump(int fd, int argc, char *argv[]);
700 static int rpt_do_stats(int fd, int argc, char *argv[]);
701 static int rpt_do_lstats(int fd, int argc, char *argv[]);
702 static int rpt_do_reload(int fd, int argc, char *argv[]);
703 static int rpt_do_restart(int fd, int argc, char *argv[]);
705 static char debug_usage[] =
706 "Usage: rpt debug level {0-7}\n"
707 " Enables debug messages in app_rpt\n";
709 static char dump_usage[] =
710 "Usage: rpt dump <nodename>\n"
711 " Dumps struct debug info to log\n";
713 static char dump_stats[] =
714 "Usage: rpt stats <nodename>\n"
715 " Dumps node statistics to console\n";
717 static char dump_lstats[] =
718 "Usage: rpt lstats <nodename>\n"
719 " Dumps link statistics to console\n";
721 static char reload_usage[] =
722 "Usage: rpt reload\n"
723 " Reloads app_rpt running config parameters\n";
725 static char restart_usage[] =
726 "Usage: rpt restart\n"
727 " Restarts app_rpt\n";
729 static struct ast_cli_entry cli_rpt[] = {
730 { { "rpt", "debug", "level" },
731 rpt_do_debug, "Enable app_rpt debugging",
732 debug_usage },
734 { { "rpt", "dump" },
735 rpt_do_dump, "Dump app_rpt structs for debugging",
736 dump_usage },
738 { { "rpt", "stats" },
739 rpt_do_stats, "Dump node statistics",
740 dump_stats },
741 { { "rpt", "lstats" },
742 rpt_do_lstats, "Dump link statistics",
743 dump_lstats },
745 { { "rpt", "reload" },
746 rpt_do_reload, "Reload app_rpt config",
747 reload_usage },
749 { { "rpt", "restart" },
750 rpt_do_restart, "Restart app_rpt",
751 restart_usage },
755 * Telemetry defaults
759 static struct telem_defaults tele_defs[] = {
760 {"ct1","|t(350,0,100,3072)(500,0,100,3072)(660,0,100,3072)"},
761 {"ct2","|t(660,880,150,3072)"},
762 {"ct3","|t(440,0,150,3072)"},
763 {"ct4","|t(550,0,150,3072)"},
764 {"ct5","|t(660,0,150,3072)"},
765 {"ct6","|t(880,0,150,3072)"},
766 {"ct7","|t(660,440,150,3072)"},
767 {"ct8","|t(700,1100,150,3072)"},
768 {"remotemon","|t(1600,0,75,2048)"},
769 {"remotetx","|t(2000,0,75,2048)(0,0,75,0)(1600,0,75,2048)"},
770 {"cmdmode","|t(900,904,200,2048)"},
771 {"functcomplete","|t(1000,0,100,2048)(0,0,100,0)(1000,0,100,2048)"}
775 * Forward decl's - these suppress compiler warnings when funcs coded further down the file than thier invokation
778 static int setrbi(struct rpt *myrpt);
783 * Define function protos for function table here
786 static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
787 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
788 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
789 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
790 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
791 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
792 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
794 * Function table
797 static struct function_table_tag function_table[] = {
798 {"cop", function_cop},
799 {"autopatchup", function_autopatchup},
800 {"autopatchdn", function_autopatchdn},
801 {"ilink", function_ilink},
802 {"status", function_status},
803 {"remote", function_remote},
804 {"macro", function_macro}
808 * Break up a delimited string into a table of substrings
810 * str - delimited string ( will be modified )
811 * strp- list of pointers to substrings (this is built by this function), NULL will be placed at end of list
812 * limit- maximum number of substrings to process
817 static int finddelim(char *str, char *strp[], int limit)
819 int i,l,inquo;
821 inquo = 0;
822 i = 0;
823 strp[i++] = str;
824 if (!*str)
826 strp[0] = 0;
827 return(0);
829 for(l = 0; *str && (l < limit) ; str++)
831 if (*str == QUOTECHR)
833 if (inquo)
835 *str = 0;
836 inquo = 0;
838 else
840 strp[i - 1] = str + 1;
841 inquo = 1;
844 if ((*str == DELIMCHR) && (!inquo))
846 *str = 0;
847 l++;
848 strp[i++] = str + 1;
851 strp[i] = 0;
852 return(i);
857 * Match a keyword in a list, and return index of string plus 1 if there was a match,
858 * else return 0. If param is passed in non-null, then it will be set to the first character past the match
861 static int matchkeyword(char *string, char **param, char *keywords[])
863 int i,ls;
864 for( i = 0 ; keywords[i] ; i++){
865 ls = strlen(keywords[i]);
866 if(!ls){
867 *param = NULL;
868 return 0;
870 if(!strncmp(string, keywords[i], ls)){
871 if(param)
872 *param = string + ls;
873 return i + 1;
876 param = NULL;
877 return 0;
881 * Skip characters in string which are in charlist, and return a pointer to the
882 * first non-matching character
885 static char *skipchars(char *string, char *charlist)
887 int i;
888 while(*string){
889 for(i = 0; charlist[i] ; i++){
890 if(*string == charlist[i]){
891 string++;
892 break;
895 if(!charlist[i])
896 return string;
898 return string;
903 static int myatoi(const char *str)
905 int ret;
907 if (str == NULL) return -1;
908 /* leave this %i alone, non-base-10 input is useful here */
909 if (sscanf(str,"%i",&ret) != 1) return -1;
910 return ret;
914 #ifdef __RPT_NOTCH
916 /* rpt filter routine */
917 static void rpt_filter(struct rpt *myrpt, volatile short *buf, int len)
919 int i,j;
920 struct rptfilter *f;
922 for(i = 0; i < len; i++)
924 for(j = 0; j < MAXFILTERS; j++)
926 f = &myrpt->filters[j];
927 if (!*f->desc) continue;
928 f->x0 = f->x1; f->x1 = f->x2;
929 f->x2 = ((float)buf[i]) / f->gain;
930 f->y0 = f->y1; f->y1 = f->y2;
931 f->y2 = (f->x0 + f->x2) + f->const0 * f->x1
932 + (f->const1 * f->y0) + (f->const2 * f->y1);
933 buf[i] = (short)f->y2;
938 #endif
940 /* Retrieve an int from a config file */
942 static int retrieve_astcfgint(struct rpt *myrpt,char *category, char *name, int min, int max, int defl)
944 const char *var;
945 int ret;
947 var = ast_variable_retrieve(myrpt->cfg, category, name);
948 if(var){
949 ret = myatoi(var);
950 if(ret < min)
951 ret = min;
952 if(ret > max)
953 ret = max;
955 else
956 ret = defl;
957 return ret;
961 static void load_rpt_vars(int n,int init)
963 char *this;
964 const char *val;
965 int j,longestnode;
966 struct ast_variable *vp;
967 struct ast_config *cfg;
968 #ifdef __RPT_NOTCH
969 int i;
970 char *strs[100];
971 #endif
973 if (option_verbose > 2)
974 ast_verbose(VERBOSE_PREFIX_3 "%s config for repeater %s\n",
975 (init) ? "Loading initial" : "Re-Loading",rpt_vars[n].name);
976 ast_mutex_lock(&rpt_vars[n].lock);
977 if (rpt_vars[n].cfg) ast_config_destroy(rpt_vars[n].cfg);
978 cfg = ast_config_load("rpt.conf");
979 if (!cfg) {
980 ast_mutex_unlock(&rpt_vars[n].lock);
981 ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf. Radio Repeater disabled.\n");
982 pthread_exit(NULL);
984 rpt_vars[n].cfg = cfg;
985 this = rpt_vars[n].name;
986 memset(&rpt_vars[n].p,0,sizeof(rpt_vars[n].p));
987 if (init)
989 char *cp;
990 int savearea = (char *)&rpt_vars[n].p - (char *)&rpt_vars[n];
992 cp = (char *) &rpt_vars[n].p;
993 memset(cp + sizeof(rpt_vars[n].p),0,
994 sizeof(rpt_vars[n]) - (sizeof(rpt_vars[n].p) + savearea));
995 rpt_vars[n].tele.next = &rpt_vars[n].tele;
996 rpt_vars[n].tele.prev = &rpt_vars[n].tele;
997 rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
998 rpt_vars[n].tailmessagen = 0;
1000 #ifdef __RPT_NOTCH
1001 /* zot out filters stuff */
1002 memset(&rpt_vars[n].filters,0,sizeof(rpt_vars[n].filters));
1003 #endif
1004 val = ast_variable_retrieve(cfg,this,"context");
1005 if (val) rpt_vars[n].p.ourcontext = val;
1006 else rpt_vars[n].p.ourcontext = this;
1007 val = ast_variable_retrieve(cfg,this,"callerid");
1008 if (val) rpt_vars[n].p.ourcallerid = val;
1009 val = ast_variable_retrieve(cfg,this,"accountcode");
1010 if (val) rpt_vars[n].p.acctcode = val;
1011 val = ast_variable_retrieve(cfg,this,"idrecording");
1012 if (val) rpt_vars[n].p.ident = val;
1013 val = ast_variable_retrieve(cfg,this,"hangtime");
1014 if (val) rpt_vars[n].p.hangtime = atoi(val);
1015 else rpt_vars[n].p.hangtime = HANGTIME;
1016 val = ast_variable_retrieve(cfg,this,"totime");
1017 if (val) rpt_vars[n].p.totime = atoi(val);
1018 else rpt_vars[n].p.totime = TOTIME;
1019 rpt_vars[n].p.tailmessagetime = retrieve_astcfgint(&rpt_vars[n],this, "tailmessagetime", 0, 2400000, 0);
1020 rpt_vars[n].p.tailsquashedtime = retrieve_astcfgint(&rpt_vars[n],this, "tailsquashedtime", 0, 2400000, 0);
1021 rpt_vars[n].p.duplex = retrieve_astcfgint(&rpt_vars[n],this,"duplex",0,4,2);
1022 rpt_vars[n].p.idtime = retrieve_astcfgint(&rpt_vars[n],this, "idtime", 60000, 2400000, IDTIME); /* Enforce a min max */
1023 rpt_vars[n].p.politeid = retrieve_astcfgint(&rpt_vars[n],this, "politeid", 30000, 300000, POLITEID); /* Enforce a min max */
1024 val = ast_variable_retrieve(cfg,this,"tonezone");
1025 if (val) rpt_vars[n].p.tonezone = ast_strdupa(val);
1026 rpt_vars[n].p.tailmessages[0] = 0;
1027 rpt_vars[n].p.tailmessagemax = 0;
1028 val = ast_variable_retrieve(cfg,this,"tailmessagelist");
1029 if (val) rpt_vars[n].p.tailmessagemax = finddelim(ast_strdupa(val), rpt_vars[n].p.tailmessages, 500);
1030 val = ast_variable_retrieve(cfg,this,"memory");
1031 if (!val) val = MEMORY;
1032 rpt_vars[n].p.memory = val;
1033 val = ast_variable_retrieve(cfg,this,"macro");
1034 if (!val) val = MACRO;
1035 rpt_vars[n].p.macro = val;
1036 val = ast_variable_retrieve(cfg,this,"startup_macro");
1037 if (val) rpt_vars[n].p.startupmacro = val;
1038 val = ast_variable_retrieve(cfg,this,"iobase");
1039 /* do not use atoi() here, we need to be able to have
1040 the input specified in hex or decimal so we use
1041 sscanf with a %i */
1042 if ((!val) || (sscanf(val,"%i",&rpt_vars[n].p.iobase) != 1))
1043 rpt_vars[n].p.iobase = DEFAULT_IOBASE;
1044 val = ast_variable_retrieve(cfg,this,"functions");
1045 if (!val)
1047 val = FUNCTIONS;
1048 rpt_vars[n].p.simple = 1;
1050 rpt_vars[n].p.functions = val;
1051 val = ast_variable_retrieve(cfg,this,"link_functions");
1052 if (val) rpt_vars[n].p.link_functions = val;
1053 else
1054 rpt_vars[n].p.link_functions = rpt_vars[n].p.functions;
1055 val = ast_variable_retrieve(cfg,this,"phone_functions");
1056 if (val) rpt_vars[n].p.phone_functions = val;
1057 val = ast_variable_retrieve(cfg,this,"dphone_functions");
1058 if (val) rpt_vars[n].p.dphone_functions = val;
1059 val = ast_variable_retrieve(cfg,this,"funcchar");
1060 if (!val) rpt_vars[n].p.funcchar = FUNCCHAR; else
1061 rpt_vars[n].p.funcchar = *val;
1062 val = ast_variable_retrieve(cfg,this,"endchar");
1063 if (!val) rpt_vars[n].p.endchar = ENDCHAR; else
1064 rpt_vars[n].p.endchar = *val;
1065 val = ast_variable_retrieve(cfg,this,"nobusyout");
1066 if (val) rpt_vars[n].p.nobusyout = ast_true(val);
1067 val = ast_variable_retrieve(cfg,this,"nodes");
1068 if (!val) val = NODES;
1069 rpt_vars[n].p.nodes = val;
1070 #ifdef __RPT_NOTCH
1071 val = ast_variable_retrieve(cfg,this,"rxnotch");
1072 if (val) {
1073 i = finddelim(ast_strdupa(val),strs,MAXFILTERS * 2);
1074 i &= ~1; /* force an even number, rounded down */
1075 if (i >= 2) for(j = 0; j < i; j += 2)
1077 rpt_mknotch(atof(strs[j]),atof(strs[j + 1]),
1078 &rpt_vars[n].filters[j >> 1].gain,
1079 &rpt_vars[n].filters[j >> 1].const0,
1080 &rpt_vars[n].filters[j >> 1].const1,
1081 &rpt_vars[n].filters[j >> 1].const2);
1082 sprintf(rpt_vars[n].filters[j >> 1].desc,"%s Hz, BW = %s",
1083 strs[j],strs[j + 1]);
1087 #endif
1088 longestnode = 0;
1090 vp = ast_variable_browse(cfg, rpt_vars[n].p.nodes);
1092 while(vp){
1093 j = strlen(vp->name);
1094 if (j > longestnode)
1095 longestnode = j;
1096 vp = vp->next;
1099 rpt_vars[n].longestnode = longestnode;
1102 * For this repeater, Determine the length of the longest function
1104 rpt_vars[n].longestfunc = 0;
1105 vp = ast_variable_browse(cfg, rpt_vars[n].p.functions);
1106 while(vp){
1107 j = strlen(vp->name);
1108 if (j > rpt_vars[n].longestfunc)
1109 rpt_vars[n].longestfunc = j;
1110 vp = vp->next;
1113 * For this repeater, Determine the length of the longest function
1115 rpt_vars[n].link_longestfunc = 0;
1116 vp = ast_variable_browse(cfg, rpt_vars[n].p.link_functions);
1117 while(vp){
1118 j = strlen(vp->name);
1119 if (j > rpt_vars[n].link_longestfunc)
1120 rpt_vars[n].link_longestfunc = j;
1121 vp = vp->next;
1123 rpt_vars[n].phone_longestfunc = 0;
1124 if (rpt_vars[n].p.phone_functions)
1126 vp = ast_variable_browse(cfg, rpt_vars[n].p.phone_functions);
1127 while(vp){
1128 j = strlen(vp->name);
1129 if (j > rpt_vars[n].phone_longestfunc)
1130 rpt_vars[n].phone_longestfunc = j;
1131 vp = vp->next;
1134 rpt_vars[n].dphone_longestfunc = 0;
1135 if (rpt_vars[n].p.dphone_functions)
1137 vp = ast_variable_browse(cfg, rpt_vars[n].p.dphone_functions);
1138 while(vp){
1139 j = strlen(vp->name);
1140 if (j > rpt_vars[n].dphone_longestfunc)
1141 rpt_vars[n].dphone_longestfunc = j;
1142 vp = vp->next;
1145 rpt_vars[n].macro_longest = 1;
1146 vp = ast_variable_browse(cfg, rpt_vars[n].p.macro);
1147 while(vp){
1148 j = strlen(vp->name);
1149 if (j > rpt_vars[n].macro_longest)
1150 rpt_vars[n].macro_longest = j;
1151 vp = vp->next;
1153 ast_mutex_unlock(&rpt_vars[n].lock);
1157 * Enable or disable debug output at a given level at the console
1160 static int rpt_do_debug(int fd, int argc, char *argv[])
1162 int newlevel;
1164 if (argc != 4)
1165 return RESULT_SHOWUSAGE;
1166 newlevel = myatoi(argv[3]);
1167 if((newlevel < 0) || (newlevel > 7))
1168 return RESULT_SHOWUSAGE;
1169 if(newlevel)
1170 ast_cli(fd, "app_rpt Debugging enabled, previous level: %d, new level: %d\n", debug, newlevel);
1171 else
1172 ast_cli(fd, "app_rpt Debugging disabled\n");
1174 debug = newlevel;
1175 return RESULT_SUCCESS;
1179 * Dump rpt struct debugging onto console
1182 static int rpt_do_dump(int fd, int argc, char *argv[])
1184 int i;
1186 if (argc != 3)
1187 return RESULT_SHOWUSAGE;
1189 for(i = 0; i < nrpts; i++)
1191 if (!strcmp(argv[2],rpt_vars[i].name))
1193 rpt_vars[i].disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
1194 ast_cli(fd, "app_rpt struct dump requested for node %s\n",argv[2]);
1195 return RESULT_SUCCESS;
1198 return RESULT_FAILURE;
1202 * Dump statistics onto console
1205 static int rpt_do_stats(int fd, int argc, char *argv[])
1207 int i,j;
1208 int dailytxtime, dailykerchunks;
1209 int totalkerchunks, dailykeyups, totalkeyups, timeouts;
1210 int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
1211 long long totaltxtime;
1212 struct rpt_link *l;
1213 char *listoflinks[MAX_STAT_LINKS];
1214 char *lastnodewhichkeyedusup, *lastdtmfcommand;
1215 char *tot_state, *ider_state, *patch_state;
1216 char *reverse_patch_state, *enable_state, *input_signal, *called_number;
1217 struct rpt *myrpt;
1219 static char *not_applicable = "N/A";
1221 if(argc != 3)
1222 return RESULT_SHOWUSAGE;
1224 for(i = 0 ; i <= MAX_STAT_LINKS; i++)
1225 listoflinks[i] = NULL;
1227 tot_state = ider_state =
1228 patch_state = reverse_patch_state =
1229 input_signal = called_number =
1230 lastdtmfcommand = not_applicable;
1232 for(i = 0; i < nrpts; i++)
1234 if (!strcmp(argv[2],rpt_vars[i].name)){
1235 /* Make a copy of all stat variables while locked */
1236 myrpt = &rpt_vars[i];
1237 rpt_mutex_lock(&myrpt->lock); /* LOCK */
1239 dailytxtime = myrpt->dailytxtime;
1240 totaltxtime = myrpt->totaltxtime;
1241 dailykeyups = myrpt->dailykeyups;
1242 totalkeyups = myrpt->totalkeyups;
1243 dailykerchunks = myrpt->dailykerchunks;
1244 totalkerchunks = myrpt->totalkerchunks;
1245 dailyexecdcommands = myrpt->dailyexecdcommands;
1246 totalexecdcommands = myrpt->totalexecdcommands;
1247 timeouts = myrpt->timeouts;
1249 /* Traverse the list of connected nodes */
1250 reverse_patch_state = "DOWN";
1251 j = 0;
1252 l = myrpt->links.next;
1253 while(l != &myrpt->links){
1254 if (l->name[0] == '0'){ /* Skip '0' nodes */
1255 reverse_patch_state = "UP";
1256 l = l->next;
1257 continue;
1259 listoflinks[j] = ast_strdupa(l->name);
1260 if(listoflinks[j])
1261 j++;
1262 l = l->next;
1265 lastnodewhichkeyedusup = ast_strdupa(myrpt->lastnodewhichkeyedusup);
1266 if((!lastnodewhichkeyedusup) || (!strlen(lastnodewhichkeyedusup)))
1267 lastnodewhichkeyedusup = not_applicable;
1269 if(myrpt->keyed)
1270 input_signal = "YES";
1271 else
1272 input_signal = "NO";
1274 if(myrpt->enable)
1275 enable_state = "YES";
1276 else
1277 enable_state = "NO";
1279 if(!myrpt->totimer)
1280 tot_state = "TIMED OUT!";
1281 else if(myrpt->totimer != myrpt->p.totime)
1282 tot_state = "ARMED";
1283 else
1284 tot_state = "RESET";
1286 if(myrpt->tailid)
1287 ider_state = "QUEUED IN TAIL";
1288 else if(myrpt->mustid)
1289 ider_state = "QUEUED FOR CLEANUP";
1290 else
1291 ider_state = "CLEAN";
1293 switch(myrpt->callmode){
1294 case 1:
1295 patch_state = "DIALING";
1296 break;
1297 case 2:
1298 patch_state = "CONNECTING";
1299 break;
1300 case 3:
1301 patch_state = "UP";
1302 break;
1304 case 4:
1305 patch_state = "CALL FAILED";
1306 break;
1308 default:
1309 patch_state = "DOWN";
1312 if(strlen(myrpt->exten)){
1313 called_number = ast_strdupa(myrpt->exten);
1314 if(!called_number)
1315 called_number = not_applicable;
1318 if(strlen(myrpt->lastdtmfcommand)){
1319 lastdtmfcommand = ast_strdupa(myrpt->lastdtmfcommand);
1320 if(!lastdtmfcommand)
1321 lastdtmfcommand = not_applicable;
1324 rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
1326 ast_cli(fd, "************************ NODE %s STATISTICS *************************\n\n", myrpt->name);
1327 ast_cli(fd, "Signal on input..................................: %s\n", input_signal);
1328 ast_cli(fd, "Transmitter enabled..............................: %s\n", enable_state);
1329 ast_cli(fd, "Time out timer state.............................: %s\n", tot_state);
1330 ast_cli(fd, "Time outs since system initialization............: %d\n", timeouts);
1331 ast_cli(fd, "Identifier state.................................: %s\n", ider_state);
1332 ast_cli(fd, "Kerchunks today..................................: %d\n", dailykerchunks);
1333 ast_cli(fd, "Kerchunks since system initialization............: %d\n", totalkerchunks);
1334 ast_cli(fd, "Keyups today.....................................: %d\n", dailykeyups);
1335 ast_cli(fd, "Keyups since system initialization...............: %d\n", totalkeyups);
1336 ast_cli(fd, "DTMF commands today..............................: %d\n", dailyexecdcommands);
1337 ast_cli(fd, "DTMF commands since system initialization........: %d\n", totalexecdcommands);
1338 ast_cli(fd, "Last DTMF command executed.......................: %s\n", lastdtmfcommand);
1340 hours = dailytxtime/3600000;
1341 dailytxtime %= 3600000;
1342 minutes = dailytxtime/60000;
1343 dailytxtime %= 60000;
1344 seconds = dailytxtime/1000;
1345 dailytxtime %= 1000;
1347 ast_cli(fd, "TX time today ...................................: %02d:%02d:%02d.%d\n",
1348 hours, minutes, seconds, dailytxtime);
1350 hours = (int) totaltxtime/3600000;
1351 totaltxtime %= 3600000;
1352 minutes = (int) totaltxtime/60000;
1353 totaltxtime %= 60000;
1354 seconds = (int) totaltxtime/1000;
1355 totaltxtime %= 1000;
1357 ast_cli(fd, "TX time since system initialization..............: %02d:%02d:%02d.%d\n",
1358 hours, minutes, seconds, (int) totaltxtime);
1359 ast_cli(fd, "Nodes currently connected to us..................: ");
1360 for(j = 0 ;; j++){
1361 if(!listoflinks[j]){
1362 if(!j){
1363 ast_cli(fd,"<NONE>");
1365 break;
1367 ast_cli(fd, "%s", listoflinks[j]);
1368 if(j % 4 == 3){
1369 ast_cli(fd, "\n");
1370 ast_cli(fd, " : ");
1372 else{
1373 if(listoflinks[j + 1])
1374 ast_cli(fd, ", ");
1377 ast_cli(fd,"\n");
1379 ast_cli(fd, "Last node which transmitted to us................: %s\n", lastnodewhichkeyedusup);
1380 ast_cli(fd, "Autopatch state..................................: %s\n", patch_state);
1381 ast_cli(fd, "Autopatch called number..........................: %s\n", called_number);
1382 ast_cli(fd, "Reverse patch/IAXRPT connected...................: %s\n\n", reverse_patch_state);
1384 return RESULT_SUCCESS;
1387 return RESULT_FAILURE;
1391 * Link stats function
1394 static int rpt_do_lstats(int fd, int argc, char *argv[])
1396 int i,j;
1397 struct rpt *myrpt;
1398 struct rpt_link *l;
1399 struct rpt_lstat *s,*t;
1400 struct rpt_lstat s_head;
1401 if(argc != 3)
1402 return RESULT_SHOWUSAGE;
1404 s = NULL;
1405 s_head.next = &s_head;
1406 s_head.prev = &s_head;
1408 for(i = 0; i < nrpts; i++)
1410 if (!strcmp(argv[2],rpt_vars[i].name)){
1411 /* Make a copy of all stat variables while locked */
1412 myrpt = &rpt_vars[i];
1413 rpt_mutex_lock(&myrpt->lock); /* LOCK */
1414 /* Traverse the list of connected nodes */
1415 j = 0;
1416 l = myrpt->links.next;
1417 while(l != &myrpt->links){
1418 if (l->name[0] == '0'){ /* Skip '0' nodes */
1419 l = l->next;
1420 continue;
1422 if((s = (struct rpt_lstat *) malloc(sizeof(struct rpt_lstat))) == NULL){
1423 ast_log(LOG_ERROR, "Malloc failed in rpt_do_lstats\n");
1424 rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
1425 return RESULT_FAILURE;
1427 memset(s, 0, sizeof(struct rpt_lstat));
1428 ast_copy_string(s->name, l->name, MAXREMSTR);
1429 pbx_substitute_variables_helper(l->chan, "${IAXPEER(CURRENTCHANNEL)}", s->peer, MAXPEERSTR - 1);
1430 s->mode = l->mode;
1431 s->outbound = l->outbound;
1432 s->reconnects = l->reconnects;
1433 s->connecttime = l->connecttime;
1434 insque((struct qelem *) s, (struct qelem *) s_head.next);
1435 l = l->next;
1437 rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
1438 ast_cli(fd, "NODE PEER RECONNECTS DIRECTION CONNECT TIME\n");
1439 ast_cli(fd, "---- ---- ---------- --------- ------------\n");
1441 for(s = s_head.next; s != &s_head; s = s->next){
1442 int hours, minutes, seconds;
1443 long long connecttime = s->connecttime;
1444 char conntime[31];
1445 hours = (int) connecttime/3600000;
1446 connecttime %= 3600000;
1447 minutes = (int) connecttime/60000;
1448 connecttime %= 60000;
1449 seconds = (int) connecttime/1000;
1450 connecttime %= 1000;
1451 snprintf(conntime, 30, "%02d:%02d:%02d.%d",
1452 hours, minutes, seconds, (int) connecttime);
1453 conntime[30] = 0;
1454 ast_cli(fd, "%-10s%-20s%-12d%-11s%-30s\n",
1455 s->name, s->peer, s->reconnects, (s->outbound)? "OUT":"IN", conntime);
1457 /* destroy our local link queue */
1458 s = s_head.next;
1459 while(s != &s_head){
1460 t = s;
1461 s = s->next;
1462 remque((struct qelem *)t);
1463 free(t);
1465 return RESULT_SUCCESS;
1468 return RESULT_FAILURE;
1472 * reload vars
1475 static int rpt_do_reload(int fd, int argc, char *argv[])
1477 int n;
1479 if (argc > 2) return RESULT_SHOWUSAGE;
1481 for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
1483 return RESULT_FAILURE;
1487 * restart app_rpt
1490 static int rpt_do_restart(int fd, int argc, char *argv[])
1492 int i;
1494 if (argc > 2) return RESULT_SHOWUSAGE;
1495 for(i = 0; i < nrpts; i++)
1497 if (rpt_vars[i].rxchannel) ast_softhangup(rpt_vars[i].rxchannel,AST_SOFTHANGUP_DEV);
1499 return RESULT_FAILURE;
1502 static int play_tone_pair(struct ast_channel *chan, int f1, int f2, int duration, int amplitude)
1504 int res;
1506 if ((res = ast_tonepair_start(chan, f1, f2, duration, amplitude)))
1507 return res;
1509 while(chan->generatordata) {
1510 if (ast_safe_sleep(chan,1)) return -1;
1513 return 0;
1516 static int play_tone(struct ast_channel *chan, int freq, int duration, int amplitude)
1518 return play_tone_pair(chan, freq, 0, duration, amplitude);
1521 static int play_silence(struct ast_channel *chan, int duration)
1523 return play_tone_pair(chan, 0, 0, duration, 0);
1527 static int send_morse(struct ast_channel *chan, const char *string, int speed, int freq, int amplitude)
1530 static struct morse_bits mbits[] = {
1531 {0, 0}, /* SPACE */
1532 {0, 0},
1533 {6, 18},/* " */
1534 {0, 0},
1535 {7, 72},/* $ */
1536 {0, 0},
1537 {0, 0},
1538 {6, 30},/* ' */
1539 {5, 13},/* ( */
1540 {6, 29},/* ) */
1541 {0, 0},
1542 {5, 10},/* + */
1543 {6, 51},/* , */
1544 {6, 33},/* - */
1545 {6, 42},/* . */
1546 {5, 9}, /* / */
1547 {5, 31},/* 0 */
1548 {5, 30},/* 1 */
1549 {5, 28},/* 2 */
1550 {5, 24},/* 3 */
1551 {5, 16},/* 4 */
1552 {5, 0}, /* 5 */
1553 {5, 1}, /* 6 */
1554 {5, 3}, /* 7 */
1555 {5, 7}, /* 8 */
1556 {5, 15},/* 9 */
1557 {6, 7}, /* : */
1558 {6, 21},/* ; */
1559 {0, 0},
1560 {5, 33},/* = */
1561 {0, 0},
1562 {6, 12},/* ? */
1563 {0, 0},
1564 {2, 2}, /* A */
1565 {4, 1}, /* B */
1566 {4, 5}, /* C */
1567 {3, 1}, /* D */
1568 {1, 0}, /* E */
1569 {4, 4}, /* F */
1570 {3, 3}, /* G */
1571 {4, 0}, /* H */
1572 {2, 0}, /* I */
1573 {4, 14},/* J */
1574 {3, 5}, /* K */
1575 {4, 2}, /* L */
1576 {2, 3}, /* M */
1577 {2, 1}, /* N */
1578 {3, 7}, /* O */
1579 {4, 6}, /* P */
1580 {4, 11},/* Q */
1581 {3, 2}, /* R */
1582 {3, 0}, /* S */
1583 {1, 1}, /* T */
1584 {3, 4}, /* U */
1585 {4, 8}, /* V */
1586 {3, 6}, /* W */
1587 {4, 9}, /* X */
1588 {4, 13},/* Y */
1589 {4, 3} /* Z */
1593 int dottime;
1594 int dashtime;
1595 int intralettertime;
1596 int interlettertime;
1597 int interwordtime;
1598 int len, ddcomb;
1599 int res;
1600 int c;
1601 int i;
1602 int flags;
1604 res = 0;
1606 /* Approximate the dot time from the speed arg. */
1608 dottime = 900/speed;
1610 /* Establish timing releationships */
1612 dashtime = 3 * dottime;
1613 intralettertime = dottime;
1614 interlettertime = dottime * 4 ;
1615 interwordtime = dottime * 7;
1617 for(;(*string) && (!res); string++){
1619 c = *string;
1621 /* Convert lower case to upper case */
1623 if((c >= 'a') && (c <= 'z'))
1624 c -= 0x20;
1626 /* Can't deal with any char code greater than Z, skip it */
1628 if(c > 'Z')
1629 continue;
1631 /* If space char, wait the inter word time */
1633 if(c == ' '){
1634 if(!res)
1635 res = play_silence(chan, interwordtime);
1636 continue;
1639 /* Subtract out control char offset to match our table */
1641 c -= 0x20;
1643 /* Get the character data */
1645 len = mbits[c].len;
1646 ddcomb = mbits[c].ddcomb;
1648 /* Send the character */
1650 for(; len ; len--){
1651 if(!res)
1652 res = play_tone(chan, freq, (ddcomb & 1) ? dashtime : dottime, amplitude);
1653 if(!res)
1654 res = play_silence(chan, intralettertime);
1655 ddcomb >>= 1;
1658 /* Wait the interletter time */
1660 if(!res)
1661 res = play_silence(chan, interlettertime - intralettertime);
1664 /* Wait for all the frames to be sent */
1666 if (!res)
1667 res = ast_waitstream(chan, "");
1668 ast_stopstream(chan);
1671 * Wait for the zaptel driver to physically write the tone blocks to the hardware
1674 for(i = 0; i < 20 ; i++){
1675 flags = ZT_IOMUX_WRITEEMPTY | ZT_IOMUX_NOWAIT;
1676 res = ioctl(chan->fds[0], ZT_IOMUX, &flags);
1677 if(flags & ZT_IOMUX_WRITEEMPTY)
1678 break;
1679 if( ast_safe_sleep(chan, 50)){
1680 res = -1;
1681 break;
1686 return res;
1689 static int send_tone_telemetry(struct ast_channel *chan, const char *tonestring)
1691 char *stringp;
1692 char *tonesubset;
1693 int f1,f2;
1694 int duration;
1695 int amplitude;
1696 int res;
1697 int i;
1698 int flags;
1700 res = 0;
1702 stringp = ast_strdupa(tonestring);
1704 for(;tonestring;){
1705 tonesubset = strsep(&stringp,")");
1706 if(!tonesubset)
1707 break;
1708 if(sscanf(tonesubset,"(%d,%d,%d,%d", &f1, &f2, &duration, &amplitude) != 4)
1709 break;
1710 res = play_tone_pair(chan, f1, f2, duration, amplitude);
1711 if(res)
1712 break;
1714 if(!res)
1715 res = play_tone_pair(chan, 0, 0, 100, 0); /* This is needed to ensure the last tone segment is timed correctly */
1717 if (!res)
1718 res = ast_waitstream(chan, "");
1719 ast_stopstream(chan);
1722 * Wait for the zaptel driver to physically write the tone blocks to the hardware
1725 for(i = 0; i < 20 ; i++){
1726 flags = ZT_IOMUX_WRITEEMPTY | ZT_IOMUX_NOWAIT;
1727 res = ioctl(chan->fds[0], ZT_IOMUX, &flags);
1728 if(flags & ZT_IOMUX_WRITEEMPTY)
1729 break;
1730 if( ast_safe_sleep(chan, 50)){
1731 res = -1;
1732 break;
1736 return res;
1741 static int sayfile(struct ast_channel *mychannel, const char *fname)
1743 int res;
1745 res = ast_streamfile(mychannel, fname, mychannel->language);
1746 if (!res)
1747 res = ast_waitstream(mychannel, "");
1748 else
1749 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1750 ast_stopstream(mychannel);
1751 return res;
1754 static int saycharstr(struct ast_channel *mychannel,char *str)
1756 int res;
1758 res = ast_say_character_str(mychannel,str,NULL,mychannel->language);
1759 if (!res)
1760 res = ast_waitstream(mychannel, "");
1761 else
1762 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1763 ast_stopstream(mychannel);
1764 return res;
1767 static int saynum(struct ast_channel *mychannel, int num)
1769 int res;
1770 res = ast_say_number(mychannel, num, NULL, mychannel->language, NULL);
1771 if(!res)
1772 res = ast_waitstream(mychannel, "");
1773 else
1774 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1775 ast_stopstream(mychannel);
1776 return res;
1780 static int telem_any(struct rpt *myrpt,struct ast_channel *chan, const char *entry)
1782 int res;
1783 char c;
1785 static int morsespeed;
1786 static int morsefreq;
1787 static int morseampl;
1788 static int morseidfreq = 0;
1789 static int morseidampl;
1790 static char mcat[] = MORSE;
1792 res = 0;
1794 if(!morseidfreq){ /* Get the morse parameters if not already loaded */
1795 morsespeed = retrieve_astcfgint(myrpt, mcat, "speed", 5, 20, 20);
1796 morsefreq = retrieve_astcfgint(myrpt, mcat, "frequency", 300, 3000, 800);
1797 morseampl = retrieve_astcfgint(myrpt, mcat, "amplitude", 200, 8192, 4096);
1798 morseidampl = retrieve_astcfgint(myrpt, mcat, "idamplitude", 200, 8192, 2048);
1799 morseidfreq = retrieve_astcfgint(myrpt, mcat, "idfrequency", 300, 3000, 330);
1802 /* Is it a file, or a tone sequence? */
1804 if(entry[0] == '|'){
1805 c = entry[1];
1806 if((c >= 'a')&&(c <= 'z'))
1807 c -= 0x20;
1809 switch(c){
1810 case 'I': /* Morse ID */
1811 res = send_morse(chan, entry + 2, morsespeed, morseidfreq, morseidampl);
1812 break;
1814 case 'M': /* Morse Message */
1815 res = send_morse(chan, entry + 2, morsespeed, morsefreq, morseampl);
1816 break;
1818 case 'T': /* Tone sequence */
1819 res = send_tone_telemetry(chan, entry + 2);
1820 break;
1821 default:
1822 res = -1;
1825 else
1826 res = sayfile(chan, entry); /* File */
1827 return res;
1831 * This function looks up a telemetry name in the config file, and does a telemetry response as configured.
1833 * 4 types of telemtry are handled: Morse ID, Morse Message, Tone Sequence, and a File containing a recording.
1836 static int telem_lookup(struct rpt *myrpt,struct ast_channel *chan, char *node, char *name)
1839 int res;
1840 int i;
1841 const char *entry;
1842 const char *telemetry;
1843 char *telemetry_save;
1845 res = 0;
1846 telemetry_save = NULL;
1847 entry = NULL;
1849 /* Retrieve the section name for telemetry from the node section */
1850 telemetry = ast_variable_retrieve(myrpt->cfg, node, TELEMETRY);
1851 if(telemetry ){
1852 telemetry_save = ast_strdupa(telemetry);
1853 if(!telemetry_save){
1854 ast_log(LOG_WARNING,"ast_strdupa() failed in telem_lookup()\n");
1855 return res;
1857 entry = ast_variable_retrieve(myrpt->cfg, telemetry_save, name);
1860 /* Try to look up the telemetry name */
1862 if(!entry){
1863 /* Telemetry name wasn't found in the config file, use the default */
1864 for(i = 0; i < sizeof(tele_defs)/sizeof(struct telem_defaults) ; i++){
1865 if(!strcasecmp(tele_defs[i].name, name))
1866 entry = tele_defs[i].value;
1869 if(entry){
1870 if(strlen(entry))
1871 telem_any(myrpt,chan, entry);
1873 else{
1874 res = -1;
1876 return res;
1880 * Retrieve a wait interval
1883 static int get_wait_interval(struct rpt *myrpt, int type)
1885 int interval;
1886 const char *wait_times;
1887 char *wait_times_save = NULL;
1889 wait_times = ast_variable_retrieve(myrpt->cfg, myrpt->name, "wait_times");
1891 if (wait_times) {
1892 wait_times_save = ast_strdupa(wait_times);
1893 if (!wait_times_save) {
1894 ast_log(LOG_WARNING, "Out of memory in wait_interval()\n");
1895 wait_times = NULL;
1899 switch (type) {
1900 case DLY_TELEM:
1901 if (wait_times)
1902 interval = retrieve_astcfgint(myrpt, wait_times_save, "telemwait", 500, 5000, 1000);
1903 else
1904 interval = 1000;
1905 break;
1907 case DLY_ID:
1908 if (wait_times)
1909 interval = retrieve_astcfgint(myrpt, wait_times_save, "idwait", 250, 5000, 500);
1910 else
1911 interval = 500;
1912 break;
1914 case DLY_UNKEY:
1915 if (wait_times)
1916 interval = retrieve_astcfgint(myrpt, wait_times_save, "unkeywait", 500, 5000, 1000);
1917 else
1918 interval = 1000;
1919 break;
1921 case DLY_CALLTERM:
1922 if (wait_times)
1923 interval = retrieve_astcfgint(myrpt, wait_times_save, "calltermwait", 500, 5000, 1500);
1924 else
1925 interval = 1500;
1926 break;
1928 default:
1929 return 0;
1931 return interval;
1936 * Wait a configurable interval of time
1940 static void wait_interval(struct rpt *myrpt, int type, struct ast_channel *chan)
1942 int interval;
1943 interval = get_wait_interval(myrpt, type);
1944 if(debug)
1945 ast_log(LOG_NOTICE," Delay interval = %d\n", interval);
1946 if(interval)
1947 ast_safe_sleep(chan,interval);
1948 if(debug)
1949 ast_log(LOG_NOTICE,"Delay complete\n");
1950 return;
1954 static void *rpt_tele_thread(void *this)
1956 ZT_CONFINFO ci; /* conference info */
1957 int res = 0,haslink,hastx,hasremote,imdone = 0, unkeys_queued, x;
1958 struct rpt_tele *mytele = (struct rpt_tele *)this;
1959 struct rpt_tele *tlist;
1960 struct rpt *myrpt;
1961 struct rpt_link *l,*m,linkbase;
1962 struct ast_channel *mychannel;
1963 const char *p, *ct;
1964 char *ct_copy, *ident, *nodename;
1965 time_t t;
1966 struct tm localtm;
1968 /* get a pointer to myrpt */
1969 myrpt = mytele->rpt;
1971 /* Snag copies of a few key myrpt variables */
1972 rpt_mutex_lock(&myrpt->lock);
1973 nodename = ast_strdupa(myrpt->name);
1974 ident = ast_strdupa(myrpt->p.ident);
1975 rpt_mutex_unlock(&myrpt->lock);
1977 /* allocate a pseudo-channel thru asterisk */
1978 mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
1979 if (!mychannel)
1981 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
1982 rpt_mutex_lock(&myrpt->lock);
1983 remque((struct qelem *)mytele);
1984 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
1985 rpt_mutex_unlock(&myrpt->lock);
1986 free(mytele);
1987 pthread_exit(NULL);
1989 rpt_mutex_lock(&myrpt->lock);
1990 mytele->chan = mychannel; /* Save a copy of the channel so we can access it externally if need be */
1991 rpt_mutex_unlock(&myrpt->lock);
1993 /* make a conference for the tx */
1994 ci.chan = 0;
1995 /* If there's an ID queued, or tail message queued, */
1996 /* only connect the ID audio to the local tx conference so */
1997 /* linked systems can't hear it */
1998 ci.confno = (((mytele->mode == ID) || (mytele->mode == IDTALKOVER) || (mytele->mode == UNKEY) ||
1999 (mytele->mode == TAILMSG)) ?
2000 myrpt->txconf : myrpt->conf);
2001 ci.confmode = ZT_CONF_CONFANN;
2002 /* first put the channel on the conference in announce mode */
2003 if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
2005 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2006 rpt_mutex_lock(&myrpt->lock);
2007 remque((struct qelem *)mytele);
2008 rpt_mutex_unlock(&myrpt->lock);
2009 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
2010 free(mytele);
2011 ast_hangup(mychannel);
2012 pthread_exit(NULL);
2014 ast_stopstream(mychannel);
2015 switch(mytele->mode)
2018 case ID:
2019 case ID1:
2020 /* wait a bit */
2021 wait_interval(myrpt, (mytele->mode == ID) ? DLY_ID : DLY_TELEM,mychannel);
2022 res = telem_any(myrpt,mychannel, ident);
2023 imdone=1;
2024 break;
2026 case TAILMSG:
2027 res = ast_streamfile(mychannel, myrpt->p.tailmessages[myrpt->tailmessagen], mychannel->language);
2028 break;
2030 case IDTALKOVER:
2031 p = ast_variable_retrieve(myrpt->cfg, nodename, "idtalkover");
2032 if(p)
2033 res = telem_any(myrpt,mychannel, p);
2034 imdone=1;
2035 break;
2037 case PROC:
2038 /* wait a little bit longer */
2039 wait_interval(myrpt, DLY_TELEM, mychannel);
2040 res = telem_lookup(myrpt, mychannel, myrpt->name, "patchup");
2041 if(res < 0){ /* Then default message */
2042 res = ast_streamfile(mychannel, "rpt/callproceeding", mychannel->language);
2044 break;
2045 case TERM:
2046 /* wait a little bit longer */
2047 wait_interval(myrpt, DLY_CALLTERM, mychannel);
2048 res = telem_lookup(myrpt, mychannel, myrpt->name, "patchdown");
2049 if(res < 0){ /* Then default message */
2050 res = ast_streamfile(mychannel, "rpt/callterminated", mychannel->language);
2052 break;
2053 case COMPLETE:
2054 /* wait a little bit */
2055 wait_interval(myrpt, DLY_TELEM, mychannel);
2056 res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
2057 break;
2058 case MACRO_NOTFOUND:
2059 /* wait a little bit */
2060 wait_interval(myrpt, DLY_TELEM, mychannel);
2061 res = ast_streamfile(mychannel, "rpt/macro_notfound", mychannel->language);
2062 break;
2063 case MACRO_BUSY:
2064 /* wait a little bit */
2065 wait_interval(myrpt, DLY_TELEM, mychannel);
2066 res = ast_streamfile(mychannel, "rpt/macro_busy", mychannel->language);
2067 break;
2068 case UNKEY:
2069 if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
2070 imdone = 1;
2071 break;
2075 * Reset the Unkey to CT timer
2078 x = get_wait_interval(myrpt, DLY_UNKEY);
2079 rpt_mutex_lock(&myrpt->lock);
2080 myrpt->unkeytocttimer = x; /* Must be protected as it is changed below */
2081 rpt_mutex_unlock(&myrpt->lock);
2084 * If there's one already queued, don't do another
2087 tlist = myrpt->tele.next;
2088 unkeys_queued = 0;
2089 if (tlist != &myrpt->tele)
2091 rpt_mutex_lock(&myrpt->lock);
2092 while(tlist != &myrpt->tele){
2093 if (tlist->mode == UNKEY) unkeys_queued++;
2094 tlist = tlist->next;
2096 rpt_mutex_unlock(&myrpt->lock);
2098 if( unkeys_queued > 1){
2099 imdone = 1;
2100 break;
2103 /* Wait for the telemetry timer to expire */
2104 /* Periodically check the timer since it can be re-initialized above */
2105 while(myrpt->unkeytocttimer)
2107 int ctint;
2108 if(myrpt->unkeytocttimer > 100)
2109 ctint = 100;
2110 else
2111 ctint = myrpt->unkeytocttimer;
2112 ast_safe_sleep(mychannel, ctint);
2113 rpt_mutex_lock(&myrpt->lock);
2114 if(myrpt->unkeytocttimer < ctint)
2115 myrpt->unkeytocttimer = 0;
2116 else
2117 myrpt->unkeytocttimer -= ctint;
2118 rpt_mutex_unlock(&myrpt->lock);
2122 * Now, the carrier on the rptr rx should be gone.
2123 * If it re-appeared, then forget about sending the CT
2125 if(myrpt->keyed){
2126 imdone = 1;
2127 break;
2130 rpt_mutex_lock(&myrpt->lock); /* Update the kerchunk counters */
2131 myrpt->dailykerchunks++;
2132 myrpt->totalkerchunks++;
2133 rpt_mutex_unlock(&myrpt->lock);
2135 haslink = 0;
2136 hastx = 0;
2137 hasremote = 0;
2138 l = myrpt->links.next;
2139 if (l != &myrpt->links)
2141 rpt_mutex_lock(&myrpt->lock);
2142 while(l != &myrpt->links)
2144 if (l->name[0] == '0')
2146 l = l->next;
2147 continue;
2149 haslink = 1;
2150 if (l->mode) {
2151 hastx++;
2152 if (l->isremote) hasremote++;
2154 l = l->next;
2156 rpt_mutex_unlock(&myrpt->lock);
2158 if (haslink)
2161 res = telem_lookup(myrpt,mychannel, myrpt->name, (!hastx) ? "remotemon" : "remotetx");
2162 if(res)
2163 ast_log(LOG_WARNING, "telem_lookup:remotexx failed on %s\n", mychannel->name);
2166 /* if in remote cmd mode, indicate it */
2167 if (myrpt->cmdnode[0])
2169 ast_safe_sleep(mychannel,200);
2170 res = telem_lookup(myrpt,mychannel, myrpt->name, "cmdmode");
2171 if(res)
2172 ast_log(LOG_WARNING, "telem_lookup:cmdmode failed on %s\n", mychannel->name);
2173 ast_stopstream(mychannel);
2176 else if((ct = ast_variable_retrieve(myrpt->cfg, nodename, "unlinkedct"))){ /* Unlinked Courtesy Tone */
2177 ct_copy = ast_strdupa(ct);
2178 res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
2179 if(res)
2180 ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);
2182 if (hasremote && (!myrpt->cmdnode[0]))
2184 /* set for all to hear */
2185 ci.chan = 0;
2186 ci.confno = myrpt->conf;
2187 ci.confmode = ZT_CONF_CONFANN;
2188 /* first put the channel on the conference in announce mode */
2189 if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
2191 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2192 rpt_mutex_lock(&myrpt->lock);
2193 remque((struct qelem *)mytele);
2194 rpt_mutex_unlock(&myrpt->lock);
2195 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
2196 free(mytele);
2197 ast_hangup(mychannel);
2198 pthread_exit(NULL);
2200 if((ct = ast_variable_retrieve(myrpt->cfg, nodename, "remotect"))){ /* Unlinked Courtesy Tone */
2201 ast_safe_sleep(mychannel,200);
2202 ct_copy = ast_strdupa(ct);
2203 res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
2204 if(res)
2205 ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);
2208 #ifdef _MDC_DECODE_H_
2209 if (myrpt->lastunit)
2211 char mystr[10];
2213 ast_safe_sleep(mychannel,200);
2214 /* set for all to hear */
2215 ci.chan = 0;
2216 ci.confno = myrpt->txconf;
2217 ci.confmode = ZT_CONF_CONFANN;
2218 /* first put the channel on the conference in announce mode */
2219 if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
2221 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2222 rpt_mutex_lock(&myrpt->lock);
2223 remque((struct qelem *)mytele);
2224 rpt_mutex_unlock(&myrpt->lock);
2225 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
2226 free(mytele);
2227 ast_hangup(mychannel);
2228 pthread_exit(NULL);
2230 sprintf(mystr,"%04x",myrpt->lastunit);
2231 myrpt->lastunit = 0;
2232 ast_say_character_str(mychannel,mystr,NULL,mychannel->language);
2233 break;
2235 #endif
2236 imdone = 1;
2237 break;
2238 case REMDISC:
2239 /* wait a little bit */
2240 wait_interval(myrpt, DLY_TELEM, mychannel);
2241 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
2242 if (!res)
2243 res = ast_waitstream(mychannel, "");
2244 else
2245 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2246 ast_stopstream(mychannel);
2247 ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
2248 res = ast_streamfile(mychannel, ((mytele->mylink.connected) ?
2249 "rpt/remote_disc" : "rpt/remote_busy"), mychannel->language);
2250 break;
2251 case REMALREADY:
2252 /* wait a little bit */
2253 wait_interval(myrpt, DLY_TELEM, mychannel);
2254 res = ast_streamfile(mychannel, "rpt/remote_already", mychannel->language);
2255 break;
2256 case REMNOTFOUND:
2257 /* wait a little bit */
2258 wait_interval(myrpt, DLY_TELEM, mychannel);
2259 res = ast_streamfile(mychannel, "rpt/remote_notfound", mychannel->language);
2260 break;
2261 case REMGO:
2262 /* wait a little bit */
2263 wait_interval(myrpt, DLY_TELEM, mychannel);
2264 res = ast_streamfile(mychannel, "rpt/remote_go", mychannel->language);
2265 break;
2266 case CONNECTED:
2267 /* wait a little bit */
2268 wait_interval(myrpt, DLY_TELEM, mychannel);
2269 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
2270 if (!res)
2271 res = ast_waitstream(mychannel, "");
2272 else
2273 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2274 ast_stopstream(mychannel);
2275 ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
2276 res = ast_streamfile(mychannel, "rpt/connected", mychannel->language);
2277 break;
2278 case CONNFAIL:
2279 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
2280 if (!res)
2281 res = ast_waitstream(mychannel, "");
2282 else
2283 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2284 ast_stopstream(mychannel);
2285 ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
2286 res = ast_streamfile(mychannel, "rpt/connection_failed", mychannel->language);
2287 break;
2288 case STATUS:
2289 /* wait a little bit */
2290 wait_interval(myrpt, DLY_TELEM, mychannel);
2291 hastx = 0;
2292 linkbase.next = &linkbase;
2293 linkbase.prev = &linkbase;
2294 rpt_mutex_lock(&myrpt->lock);
2295 /* make our own list of links */
2296 l = myrpt->links.next;
2297 while(l != &myrpt->links)
2299 if (l->name[0] == '0')
2301 l = l->next;
2302 continue;
2304 m = malloc(sizeof(struct rpt_link));
2305 if (!m)
2307 ast_log(LOG_WARNING, "Cannot alloc memory on %s\n", mychannel->name);
2308 remque((struct qelem *)mytele);
2309 rpt_mutex_unlock(&myrpt->lock);
2310 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
2311 free(mytele);
2312 ast_hangup(mychannel);
2313 pthread_exit(NULL);
2315 memcpy(m,l,sizeof(struct rpt_link));
2316 m->next = m->prev = NULL;
2317 insque((struct qelem *)m,(struct qelem *)linkbase.next);
2318 l = l->next;
2320 rpt_mutex_unlock(&myrpt->lock);
2321 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
2322 if (!res)
2323 res = ast_waitstream(mychannel, "");
2324 else
2325 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2326 ast_stopstream(mychannel);
2327 ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
2328 if (!res)
2329 res = ast_waitstream(mychannel, "");
2330 else
2331 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2332 ast_stopstream(mychannel);
2333 if (myrpt->callmode)
2335 hastx = 1;
2336 res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
2337 if (!res)
2338 res = ast_waitstream(mychannel, "");
2339 else
2340 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2341 ast_stopstream(mychannel);
2343 l = linkbase.next;
2344 while(l != &linkbase)
2346 hastx = 1;
2347 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
2348 if (!res)
2349 res = ast_waitstream(mychannel, "");
2350 else
2351 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2352 ast_stopstream(mychannel);
2353 ast_say_character_str(mychannel,l->name,NULL,mychannel->language);
2354 if (!res)
2355 res = ast_waitstream(mychannel, "");
2356 else
2357 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2358 ast_stopstream(mychannel);
2359 res = ast_streamfile(mychannel, ((l->mode) ?
2360 "rpt/tranceive" : "rpt/monitor"), mychannel->language);
2361 if (!res)
2362 res = ast_waitstream(mychannel, "");
2363 else
2364 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2365 ast_stopstream(mychannel);
2366 l = l->next;
2368 if (!hastx)
2370 res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
2371 if (!res)
2372 res = ast_waitstream(mychannel, "");
2373 else
2374 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2375 ast_stopstream(mychannel);
2377 /* destroy our local link queue */
2378 l = linkbase.next;
2379 while(l != &linkbase)
2381 m = l;
2382 l = l->next;
2383 remque((struct qelem *)m);
2384 free(m);
2386 imdone = 1;
2387 break;
2389 case LASTNODEKEY: /* Identify last node which keyed us up */
2390 rpt_mutex_lock(&myrpt->lock);
2391 if(myrpt->lastnodewhichkeyedusup)
2392 p = ast_strdupa(myrpt->lastnodewhichkeyedusup); /* Make a local copy of the node name */
2393 else
2394 p = NULL;
2395 rpt_mutex_unlock(&myrpt->lock);
2396 if(!p){
2397 imdone = 1; /* no node previously keyed us up, or the node which did has been disconnected */
2398 break;
2400 wait_interval(myrpt, DLY_TELEM, mychannel);
2401 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
2402 if (!res)
2403 res = ast_waitstream(mychannel, "");
2404 else
2405 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2406 ast_stopstream(mychannel);
2407 ast_say_character_str(mychannel, p, NULL, mychannel->language);
2408 if (!res)
2409 res = ast_waitstream(mychannel, "");
2410 else
2411 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2412 ast_stopstream(mychannel);
2413 imdone = 1;
2414 break;
2416 case TIMEOUT:
2417 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
2418 if (!res)
2419 res = ast_waitstream(mychannel, "");
2420 else
2421 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2422 ast_stopstream(mychannel);
2423 ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
2424 res = ast_streamfile(mychannel, "rpt/timeout", mychannel->language);
2425 break;
2427 case STATS_TIME:
2428 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
2429 t = time(NULL);
2430 localtime_r(&t, &localtm);
2431 /* Say the phase of the day is before the time */
2432 if((localtm.tm_hour >= 0) && (localtm.tm_hour < 12))
2433 p = "rpt/goodmorning";
2434 else if((localtm.tm_hour >= 12) && (localtm.tm_hour < 18))
2435 p = "rpt/goodafternoon";
2436 else
2437 p = "rpt/goodevening";
2438 if (sayfile(mychannel,p) == -1)
2440 imdone = 1;
2441 break;
2443 /* Say the time is ... */
2444 if (sayfile(mychannel,"rpt/thetimeis") == -1)
2446 imdone = 1;
2447 break;
2449 /* Say the time */
2450 res = ast_say_time(mychannel, t, "", mychannel->language);
2451 if (!res)
2452 res = ast_waitstream(mychannel, "");
2453 ast_stopstream(mychannel);
2454 imdone = 1;
2455 break;
2456 case STATS_VERSION:
2457 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
2458 /* Say "version" */
2459 if (sayfile(mychannel,"rpt/version") == -1)
2461 imdone = 1;
2462 break;
2464 if(!res) /* Say "X" */
2465 ast_say_number(mychannel, vmajor, "", mychannel->language, (char *) NULL);
2466 if (!res)
2467 res = ast_waitstream(mychannel, "");
2468 ast_stopstream(mychannel);
2469 if (saycharstr(mychannel,".") == -1)
2471 imdone = 1;
2472 break;
2474 if(!res) /* Say "Y" */
2475 ast_say_number(mychannel, vminor, "", mychannel->language, (char *) NULL);
2476 if (!res){
2477 res = ast_waitstream(mychannel, "");
2478 ast_stopstream(mychannel);
2480 else
2481 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2482 imdone = 1;
2483 break;
2484 case ARB_ALPHA:
2485 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
2486 if(mytele->param)
2487 saycharstr(mychannel, mytele->param);
2488 imdone = 1;
2489 break;
2490 case REV_PATCH:
2491 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
2492 if(mytele->param) {
2494 /* Parts of this section taken from app_parkandannounce */
2495 char *tpl_working, *tpl_current;
2496 char *tmp[100], *myparm;
2497 int looptemp=0,i=0, dres = 0;
2500 tpl_working = strdupa(mytele->param);
2501 myparm = strsep(&tpl_working,",");
2502 tpl_current=strsep(&tpl_working, ":");
2504 while(tpl_current && looptemp < sizeof(tmp)) {
2505 tmp[looptemp]=tpl_current;
2506 looptemp++;
2507 tpl_current=strsep(&tpl_working,":");
2510 for(i=0; i<looptemp; i++) {
2511 if(!strcmp(tmp[i], "PARKED")) {
2512 ast_say_digits(mychannel, atoi(myparm), "", mychannel->language);
2513 } else if(!strcmp(tmp[i], "NODE")) {
2514 ast_say_digits(mychannel, atoi(myrpt->name), "", mychannel->language);
2515 } else {
2516 dres = ast_streamfile(mychannel, tmp[i], mychannel->language);
2517 if(!dres) {
2518 dres = ast_waitstream(mychannel, "");
2519 } else {
2520 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[i], mychannel->name);
2521 dres = 0;
2526 imdone = 1;
2527 break;
2528 case TEST_TONE:
2529 imdone = 1;
2530 myrpt->stopgen = 0;
2531 if ((res = ast_tonepair_start(mychannel, 1004.0, 0, 99999999, 7200.0)))
2532 break;
2533 while(mychannel->generatordata && (!myrpt->stopgen)) {
2534 if (ast_safe_sleep(mychannel,1)) break;
2535 imdone = 1;
2537 break;
2538 default:
2539 break;
2541 myrpt->stopgen = 0;
2542 if (!imdone)
2544 if (!res)
2545 res = ast_waitstream(mychannel, "");
2546 else {
2547 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2548 res = 0;
2551 ast_stopstream(mychannel);
2552 rpt_mutex_lock(&myrpt->lock);
2553 if (mytele->mode == TAILMSG)
2555 if (!res)
2557 myrpt->tailmessagen++;
2558 if(myrpt->tailmessagen >= myrpt->p.tailmessagemax) myrpt->tailmessagen = 0;
2560 else
2562 myrpt->tmsgtimer = myrpt->p.tailsquashedtime;
2565 remque((struct qelem *)mytele);
2566 rpt_mutex_unlock(&myrpt->lock);
2567 free(mytele);
2568 ast_hangup(mychannel);
2569 #ifdef APP_RPT_LOCK_DEBUG
2571 struct lockthread *t;
2573 sleep(5);
2574 ast_mutex_lock(&locklock);
2575 t = get_lockthread(pthread_self());
2576 if (t) memset(t,0,sizeof(struct lockthread));
2577 ast_mutex_unlock(&locklock);
2579 #endif
2580 pthread_exit(NULL);
2583 static void rpt_telemetry(struct rpt *myrpt,int mode, void *data)
2585 struct rpt_tele *tele;
2586 struct rpt_link *mylink = (struct rpt_link *) data;
2587 int res;
2588 pthread_attr_t attr;
2590 tele = malloc(sizeof(struct rpt_tele));
2591 if (!tele)
2593 ast_log(LOG_WARNING, "Unable to allocate memory\n");
2594 pthread_exit(NULL);
2595 return;
2597 /* zero it out */
2598 memset((char *)tele,0,sizeof(struct rpt_tele));
2599 tele->rpt = myrpt;
2600 tele->mode = mode;
2601 rpt_mutex_lock(&myrpt->lock);
2602 if((mode == CONNFAIL) || (mode == REMDISC) || (mode == CONNECTED)){
2603 memset(&tele->mylink,0,sizeof(struct rpt_link));
2604 if (mylink){
2605 memcpy(&tele->mylink,mylink,sizeof(struct rpt_link));
2608 else if ((mode == ARB_ALPHA) || (mode == REV_PATCH)) {
2609 ast_copy_string(tele->param, (char *) data, TELEPARAMSIZE);
2611 insque((struct qelem *)tele, (struct qelem *)myrpt->tele.next);
2612 rpt_mutex_unlock(&myrpt->lock);
2613 pthread_attr_init(&attr);
2614 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2615 res = ast_pthread_create(&tele->threadid,&attr,rpt_tele_thread,(void *) tele);
2616 pthread_attr_destroy(&attr);
2617 if(res < 0){
2618 rpt_mutex_lock(&myrpt->lock);
2619 remque((struct qlem *) tele); /* We don't like stuck transmitters, remove it from the queue */
2620 rpt_mutex_unlock(&myrpt->lock);
2621 ast_log(LOG_WARNING, "Could not create telemetry thread: %s\n",strerror(res));
2623 return;
2626 static void *rpt_call(void *this)
2628 ZT_CONFINFO ci; /* conference info */
2629 struct rpt *myrpt = (struct rpt *)this;
2630 int res;
2631 struct ast_frame wf;
2632 int stopped,congstarted,dialtimer,lastcidx,aborted;
2633 struct ast_channel *mychannel,*genchannel;
2636 myrpt->mydtmf = 0;
2637 /* allocate a pseudo-channel thru asterisk */
2638 mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
2639 if (!mychannel)
2641 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
2642 pthread_exit(NULL);
2644 ci.chan = 0;
2645 ci.confno = myrpt->conf; /* use the pseudo conference */
2646 ci.confmode = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER
2647 | ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER;
2648 /* first put the channel on the conference */
2649 if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
2651 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2652 ast_hangup(mychannel);
2653 myrpt->callmode = 0;
2654 pthread_exit(NULL);
2656 /* allocate a pseudo-channel thru asterisk */
2657 genchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
2658 if (!genchannel)
2660 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
2661 ast_hangup(mychannel);
2662 pthread_exit(NULL);
2664 ci.chan = 0;
2665 ci.confno = myrpt->conf;
2666 ci.confmode = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER
2667 | ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER;
2668 /* first put the channel on the conference */
2669 if (ioctl(genchannel->fds[0],ZT_SETCONF,&ci) == -1)
2671 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2672 ast_hangup(mychannel);
2673 ast_hangup(genchannel);
2674 myrpt->callmode = 0;
2675 pthread_exit(NULL);
2677 if (myrpt->p.tonezone && (tone_zone_set_zone(mychannel->fds[0],myrpt->p.tonezone) == -1))
2679 ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
2680 ast_hangup(mychannel);
2681 ast_hangup(genchannel);
2682 myrpt->callmode = 0;
2683 pthread_exit(NULL);
2685 if (myrpt->p.tonezone && (tone_zone_set_zone(genchannel->fds[0],myrpt->p.tonezone) == -1))
2687 ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
2688 ast_hangup(mychannel);
2689 ast_hangup(genchannel);
2690 myrpt->callmode = 0;
2691 pthread_exit(NULL);
2693 /* start dialtone if patchquiet is 0. Special patch modes don't send dial tone */
2694 if ((!myrpt->patchquiet) && (tone_zone_play_tone(mychannel->fds[0],ZT_TONE_DIALTONE) < 0))
2696 ast_log(LOG_WARNING, "Cannot start dialtone\n");
2697 ast_hangup(mychannel);
2698 ast_hangup(genchannel);
2699 myrpt->callmode = 0;
2700 pthread_exit(NULL);
2702 stopped = 0;
2703 congstarted = 0;
2704 dialtimer = 0;
2705 lastcidx = 0;
2706 aborted = 0;
2709 while ((myrpt->callmode == 1) || (myrpt->callmode == 4))
2712 if((myrpt->patchdialtime)&&(myrpt->callmode == 1)&&(myrpt->cidx != lastcidx)){
2713 dialtimer = 0;
2714 lastcidx = myrpt->cidx;
2717 if((myrpt->patchdialtime)&&(dialtimer >= myrpt->patchdialtime)){
2718 rpt_mutex_lock(&myrpt->lock);
2719 aborted = 1;
2720 myrpt->callmode = 0;
2721 rpt_mutex_unlock(&myrpt->lock);
2722 break;
2725 if ((!myrpt->patchquiet) && (!stopped) && (myrpt->callmode == 1) && (myrpt->cidx > 0))
2727 stopped = 1;
2728 /* stop dial tone */
2729 tone_zone_play_tone(mychannel->fds[0],-1);
2731 if (myrpt->callmode == 4)
2733 if(!congstarted){
2734 congstarted = 1;
2735 /* start congestion tone */
2736 tone_zone_play_tone(mychannel->fds[0],ZT_TONE_CONGESTION);
2739 res = ast_safe_sleep(mychannel, MSWAIT);
2740 if (res < 0)
2742 ast_hangup(mychannel);
2743 ast_hangup(genchannel);
2744 rpt_mutex_lock(&myrpt->lock);
2745 myrpt->callmode = 0;
2746 rpt_mutex_unlock(&myrpt->lock);
2747 pthread_exit(NULL);
2749 dialtimer += MSWAIT;
2751 /* stop any tone generation */
2752 tone_zone_play_tone(mychannel->fds[0],-1);
2753 /* end if done */
2754 if (!myrpt->callmode)
2756 ast_hangup(mychannel);
2757 ast_hangup(genchannel);
2758 rpt_mutex_lock(&myrpt->lock);
2759 myrpt->callmode = 0;
2760 rpt_mutex_unlock(&myrpt->lock);
2761 if((!myrpt->patchquiet) && aborted)
2762 rpt_telemetry(myrpt, TERM, NULL);
2763 pthread_exit(NULL);
2766 if (myrpt->p.ourcallerid && *myrpt->p.ourcallerid){
2767 char *name, *loc, *instr;
2768 instr = strdup(myrpt->p.ourcallerid);
2769 if(instr){
2770 ast_callerid_parse(instr, &name, &loc);
2771 if(loc){
2772 if(mychannel->cid.cid_num)
2773 free(mychannel->cid.cid_num);
2774 mychannel->cid.cid_num = strdup(loc);
2776 if(name){
2777 if(mychannel->cid.cid_name)
2778 free(mychannel->cid.cid_name);
2779 mychannel->cid.cid_name = strdup(name);
2781 free(instr);
2785 ast_copy_string(mychannel->exten, myrpt->exten, sizeof(mychannel->exten));
2786 ast_copy_string(mychannel->context, myrpt->patchcontext, sizeof(mychannel->context));
2788 if (myrpt->p.acctcode)
2789 ast_string_field_set(mychannel, accountcode, myrpt->p.acctcode);
2790 mychannel->priority = 1;
2791 ast_channel_undefer_dtmf(mychannel);
2792 if (ast_pbx_start(mychannel) < 0)
2794 ast_log(LOG_WARNING, "Unable to start PBX!!\n");
2795 ast_hangup(mychannel);
2796 ast_hangup(genchannel);
2797 rpt_mutex_lock(&myrpt->lock);
2798 myrpt->callmode = 0;
2799 rpt_mutex_unlock(&myrpt->lock);
2800 pthread_exit(NULL);
2802 usleep(10000);
2803 rpt_mutex_lock(&myrpt->lock);
2804 myrpt->callmode = 3;
2805 /* set appropriate conference for the pseudo */
2806 ci.chan = 0;
2807 ci.confno = myrpt->conf;
2808 ci.confmode = (myrpt->p.duplex == 2) ? ZT_CONF_CONFANNMON :
2809 (ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER);
2810 /* first put the channel on the conference in announce mode */
2811 if (ioctl(myrpt->pchannel->fds[0],ZT_SETCONF,&ci) == -1)
2813 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2814 ast_hangup(mychannel);
2815 ast_hangup(genchannel);
2816 myrpt->callmode = 0;
2817 pthread_exit(NULL);
2819 while(myrpt->callmode)
2821 if ((!mychannel->pbx) && (myrpt->callmode != 4))
2823 if(myrpt->patchfarenddisconnect){ /* If patch is setup for far end disconnect */
2824 myrpt->callmode = 0;
2825 if(!myrpt->patchquiet){
2826 rpt_mutex_unlock(&myrpt->lock);
2827 rpt_telemetry(myrpt, TERM, NULL);
2828 rpt_mutex_lock(&myrpt->lock);
2831 else{ /* Send congestion until patch is downed by command */
2832 myrpt->callmode = 4;
2833 rpt_mutex_unlock(&myrpt->lock);
2834 /* start congestion tone */
2835 tone_zone_play_tone(genchannel->fds[0],ZT_TONE_CONGESTION);
2836 rpt_mutex_lock(&myrpt->lock);
2839 if (myrpt->mydtmf)
2841 wf.frametype = AST_FRAME_DTMF;
2842 wf.subclass = myrpt->mydtmf;
2843 wf.offset = 0;
2844 wf.mallocd = 0;
2845 wf.data = NULL;
2846 wf.datalen = 0;
2847 wf.samples = 0;
2848 rpt_mutex_unlock(&myrpt->lock);
2849 ast_write(genchannel,&wf);
2850 rpt_mutex_lock(&myrpt->lock);
2851 myrpt->mydtmf = 0;
2853 rpt_mutex_unlock(&myrpt->lock);
2854 usleep(MSWAIT * 1000);
2855 rpt_mutex_lock(&myrpt->lock);
2857 rpt_mutex_unlock(&myrpt->lock);
2858 tone_zone_play_tone(genchannel->fds[0],-1);
2859 if (mychannel->pbx) ast_softhangup(mychannel,AST_SOFTHANGUP_DEV);
2860 ast_hangup(genchannel);
2861 rpt_mutex_lock(&myrpt->lock);
2862 myrpt->callmode = 0;
2863 rpt_mutex_unlock(&myrpt->lock);
2864 /* set appropriate conference for the pseudo */
2865 ci.chan = 0;
2866 ci.confno = myrpt->conf;
2867 ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? ZT_CONF_CONFANNMON :
2868 (ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER);
2869 /* first put the channel on the conference in announce mode */
2870 if (ioctl(myrpt->pchannel->fds[0],ZT_SETCONF,&ci) == -1)
2872 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2874 pthread_exit(NULL);
2877 static void send_link_dtmf(struct rpt *myrpt,char c)
2879 char str[300];
2880 struct ast_frame wf;
2881 struct rpt_link *l;
2883 snprintf(str, sizeof(str), "D %s %s %d %c", myrpt->cmdnode, myrpt->name, ++(myrpt->dtmfidx), c);
2884 wf.frametype = AST_FRAME_TEXT;
2885 wf.subclass = 0;
2886 wf.offset = 0;
2887 wf.mallocd = 1;
2888 wf.datalen = strlen(str) + 1;
2889 wf.samples = 0;
2890 l = myrpt->links.next;
2891 /* first, see if our dude is there */
2892 while(l != &myrpt->links)
2894 if (l->name[0] == '0')
2896 l = l->next;
2897 continue;
2899 /* if we found it, write it and were done */
2900 if (!strcmp(l->name,myrpt->cmdnode))
2902 wf.data = strdup(str);
2903 if (l->chan) ast_write(l->chan,&wf);
2904 return;
2906 l = l->next;
2908 l = myrpt->links.next;
2909 /* if not, give it to everyone */
2910 while(l != &myrpt->links)
2912 wf.data = strdup(str);
2913 if (l->chan) ast_write(l->chan,&wf);
2914 l = l->next;
2916 return;
2920 * Internet linking function
2923 static int function_ilink(struct rpt *myrpt, char *param, char *digits, int command_source, struct rpt_link *mylink)
2926 const char *val;
2927 char *s, *s1, *s2, *tele;
2928 char tmp[300], deststr[300] = "",modechange = 0;
2929 char digitbuf[MAXNODESTR];
2930 struct rpt_link *l;
2931 int reconnects = 0;
2932 ZT_CONFINFO ci; /* conference info */
2934 if(!param)
2935 return DC_ERROR;
2938 if (!myrpt->enable)
2939 return DC_ERROR;
2941 ast_copy_string(digitbuf,digits,MAXNODESTR);
2943 if(debug)
2944 printf("@@@@ ilink param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
2946 switch(myatoi(param)){
2947 case 1: /* Link off */
2948 if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
2949 strcpy(digitbuf,myrpt->lastlinknode);
2950 val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
2951 if (!val){
2952 if(strlen(digitbuf) >= myrpt->longestnode)
2953 return DC_ERROR;
2954 break;
2956 ast_copy_string(tmp,val,sizeof(tmp));
2957 s = tmp;
2958 s1 = strsep(&s,",");
2959 s2 = strsep(&s,",");
2960 rpt_mutex_lock(&myrpt->lock);
2961 l = myrpt->links.next;
2962 /* try to find this one in queue */
2963 while(l != &myrpt->links){
2964 if (l->name[0] == '0')
2966 l = l->next;
2967 continue;
2969 /* if found matching string */
2970 if (!strcmp(l->name, digitbuf))
2971 break;
2972 l = l->next;
2974 if (l != &myrpt->links){ /* if found */
2975 struct ast_frame wf;
2976 ast_copy_string(myrpt->lastlinknode,digitbuf,MAXNODESTR);
2977 l->retries = MAX_RETRIES + 1;
2978 l->disced = 1;
2979 rpt_mutex_unlock(&myrpt->lock);
2980 wf.frametype = AST_FRAME_TEXT;
2981 wf.subclass = 0;
2982 wf.offset = 0;
2983 wf.mallocd = 1;
2984 wf.datalen = strlen(discstr) + 1;
2985 wf.samples = 0;
2986 wf.data = strdup(discstr);
2987 if (l->chan)
2989 ast_write(l->chan,&wf);
2990 if (ast_safe_sleep(l->chan,250) == -1) return DC_ERROR;
2991 ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
2993 rpt_telemetry(myrpt, COMPLETE, NULL);
2994 return DC_COMPLETE;
2996 rpt_mutex_unlock(&myrpt->lock);
2997 return DC_COMPLETE;
2998 case 2: /* Link Monitor */
2999 if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
3000 strcpy(digitbuf,myrpt->lastlinknode);
3001 val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
3002 if (!val){
3003 if(strlen(digitbuf) >= myrpt->longestnode)
3004 return DC_ERROR;
3005 break;
3007 ast_copy_string(tmp, val, sizeof(tmp));
3008 s = tmp;
3009 s1 = strsep(&s,",");
3010 s2 = strsep(&s,",");
3011 rpt_mutex_lock(&myrpt->lock);
3012 l = myrpt->links.next;
3013 /* try to find this one in queue */
3014 while(l != &myrpt->links){
3015 if (l->name[0] == '0')
3017 l = l->next;
3018 continue;
3020 /* if found matching string */
3021 if (!strcmp(l->name, digitbuf))
3022 break;
3023 l = l->next;
3025 /* if found */
3026 if (l != &myrpt->links)
3028 /* if already in this mode, just ignore */
3029 if ((!l->mode) || (!l->chan)) {
3030 rpt_mutex_unlock(&myrpt->lock);
3031 rpt_telemetry(myrpt,REMALREADY,NULL);
3032 return DC_COMPLETE;
3035 reconnects = l->reconnects;
3036 rpt_mutex_unlock(&myrpt->lock);
3037 if (l->chan) ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
3038 l->retries = MAX_RETRIES + 1;
3039 l->disced = 2;
3040 modechange = 1;
3041 } else
3042 rpt_mutex_unlock(&myrpt->lock);
3043 ast_copy_string(myrpt->lastlinknode,digitbuf,MAXNODESTR);
3044 /* establish call in monitor mode */
3045 l = malloc(sizeof(struct rpt_link));
3046 if (!l){
3047 ast_log(LOG_WARNING, "Unable to malloc\n");
3048 return DC_ERROR;
3050 /* zero the silly thing */
3051 memset((char *)l,0,sizeof(struct rpt_link));
3052 snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
3053 tele = strchr(deststr,'/');
3054 if (!tele){
3055 fprintf(stderr,"link2:Dial number (%s) must be in format tech/number\n",deststr);
3056 return DC_ERROR;
3058 *tele++ = 0;
3059 l->isremote = (s && ast_true(s));
3060 ast_copy_string(l->name, digitbuf, MAXNODESTR);
3061 l->chan = ast_request(deststr,AST_FORMAT_SLINEAR,tele,NULL);
3062 if (modechange) l->connected = 1;
3063 if (l->chan){
3064 ast_set_read_format(l->chan,AST_FORMAT_SLINEAR);
3065 ast_set_write_format(l->chan,AST_FORMAT_SLINEAR);
3066 l->chan->whentohangup = 0;
3067 l->chan->appl = "Apprpt";
3068 l->chan->data = "(Remote Rx)";
3069 if (option_verbose > 2)
3070 ast_verbose(VERBOSE_PREFIX_3 "rpt (remote) initiating call to %s/%s on %s\n",
3071 deststr,tele,l->chan->name);
3072 if(l->chan->cid.cid_num)
3073 free(l->chan->cid.cid_num);
3074 l->chan->cid.cid_num = strdup(myrpt->name);
3075 ast_call(l->chan,tele,0);
3077 else
3079 rpt_telemetry(myrpt,CONNFAIL,l);
3080 free(l);
3081 if (option_verbose > 2)
3082 ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
3083 deststr,tele,l->chan->name);
3084 return DC_ERROR;
3086 /* allocate a pseudo-channel thru asterisk */
3087 l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
3088 if (!l->pchan){
3089 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
3090 ast_hangup(l->chan);
3091 free(l);
3092 return DC_ERROR;
3094 ast_set_read_format(l->pchan,AST_FORMAT_SLINEAR);
3095 ast_set_write_format(l->pchan,AST_FORMAT_SLINEAR);
3096 /* make a conference for the pseudo-one */
3097 ci.chan = 0;
3098 ci.confno = myrpt->conf;
3099 ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER;
3100 /* first put the channel on the conference in proper mode */
3101 if (ioctl(l->pchan->fds[0],ZT_SETCONF,&ci) == -1)
3103 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
3104 ast_hangup(l->chan);
3105 ast_hangup(l->pchan);
3106 free(l);
3107 return DC_ERROR;
3109 rpt_mutex_lock(&myrpt->lock);
3110 l->reconnects = reconnects;
3111 /* insert at end of queue */
3112 insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
3113 rpt_mutex_unlock(&myrpt->lock);
3114 rpt_telemetry(myrpt,COMPLETE,NULL);
3115 return DC_COMPLETE;
3116 case 3: /* Link transceive */
3117 if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
3118 strcpy(digitbuf,myrpt->lastlinknode);
3119 val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
3120 if (!val){
3121 if(strlen(digitbuf) >= myrpt->longestnode)
3122 return DC_ERROR;
3123 break;
3125 ast_copy_string(tmp,val,sizeof(tmp));
3126 s = tmp;
3127 s1 = strsep(&s,",");
3128 s2 = strsep(&s,",");
3129 rpt_mutex_lock(&myrpt->lock);
3130 l = myrpt->links.next;
3131 /* try to find this one in queue */
3132 while(l != &myrpt->links){
3133 if (l->name[0] == '0')
3135 l = l->next;
3136 continue;
3138 /* if found matching string */
3139 if (!strcmp(l->name, digitbuf))
3140 break;
3141 l = l->next;
3143 /* if found */
3144 if (l != &myrpt->links){
3145 /* if already in this mode, just ignore */
3146 if ((l->mode) || (!l->chan)) {
3147 rpt_mutex_unlock(&myrpt->lock);
3148 rpt_telemetry(myrpt, REMALREADY, NULL);
3149 return DC_COMPLETE;
3151 reconnects = l->reconnects;
3152 rpt_mutex_unlock(&myrpt->lock);
3153 if (l->chan) ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
3154 l->retries = MAX_RETRIES + 1;
3155 l->disced = 2;
3156 modechange = 1;
3157 } else
3158 rpt_mutex_unlock(&myrpt->lock);
3159 ast_copy_string(myrpt->lastlinknode,digitbuf,MAXNODESTR);
3160 /* establish call in tranceive mode */
3161 l = malloc(sizeof(struct rpt_link));
3162 if (!l){
3163 ast_log(LOG_WARNING, "Unable to malloc\n");
3164 return(DC_ERROR);
3166 /* zero the silly thing */
3167 memset((char *)l,0,sizeof(struct rpt_link));
3168 l->mode = 1;
3169 l->outbound = 1;
3170 ast_copy_string(l->name, digitbuf, MAXNODESTR);
3171 l->isremote = (s && ast_true(s));
3172 if (modechange) l->connected = 1;
3173 snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
3174 tele = strchr(deststr, '/');
3175 if (!tele){
3176 fprintf(stderr,"link3:Dial number (%s) must be in format tech/number\n",deststr);
3177 free(l);
3178 return DC_ERROR;
3180 *tele++ = 0;
3181 l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL);
3182 if (l->chan){
3183 ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
3184 ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
3185 l->chan->whentohangup = 0;
3186 l->chan->appl = "Apprpt";
3187 l->chan->data = "(Remote Rx)";
3188 if (option_verbose > 2)
3189 ast_verbose(VERBOSE_PREFIX_3 "rpt (remote) initiating call to %s/%s on %s\n",
3190 deststr, tele, l->chan->name);
3191 if(l->chan->cid.cid_num)
3192 free(l->chan->cid.cid_num);
3193 l->chan->cid.cid_num = strdup(myrpt->name);
3194 ast_call(l->chan,tele,999);
3196 else{
3197 rpt_telemetry(myrpt,CONNFAIL,l);
3198 free(l);
3199 if (option_verbose > 2)
3200 ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
3201 deststr,tele,l->chan->name);
3202 return DC_ERROR;
3204 /* allocate a pseudo-channel thru asterisk */
3205 l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
3206 if (!l->pchan){
3207 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
3208 ast_hangup(l->chan);
3209 free(l);
3210 return DC_ERROR;
3212 ast_set_read_format(l->pchan, AST_FORMAT_SLINEAR);
3213 ast_set_write_format(l->pchan, AST_FORMAT_SLINEAR);
3214 /* make a conference for the tx */
3215 ci.chan = 0;
3216 ci.confno = myrpt->conf;
3217 ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER;
3218 /* first put the channel on the conference in proper mode */
3219 if (ioctl(l->pchan->fds[0], ZT_SETCONF, &ci) == -1)
3221 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
3222 ast_hangup(l->chan);
3223 ast_hangup(l->pchan);
3224 free(l);
3225 return DC_ERROR;
3227 rpt_mutex_lock(&myrpt->lock);
3228 l->reconnects = reconnects;
3229 /* insert at end of queue */
3230 insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
3231 rpt_mutex_unlock(&myrpt->lock);
3232 rpt_telemetry(myrpt,COMPLETE,NULL);
3233 return DC_COMPLETE;
3234 case 4: /* Enter Command Mode */
3236 /* if doesnt allow link cmd, or no links active, return */
3237 if (((command_source != SOURCE_RPT) && (command_source != SOURCE_PHONE) && (command_source != SOURCE_DPHONE)) || (myrpt->links.next == &myrpt->links))
3238 return DC_COMPLETE;
3240 /* if already in cmd mode, or selected self, fughetabahtit */
3241 if ((myrpt->cmdnode[0]) || (!strcmp(myrpt->name, digitbuf))){
3243 rpt_telemetry(myrpt, REMALREADY, NULL);
3244 return DC_COMPLETE;
3246 if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
3247 strcpy(digitbuf,myrpt->lastlinknode);
3248 /* node must at least exist in list */
3249 val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
3250 if (!val){
3251 if(strlen(digitbuf) >= myrpt->longestnode)
3252 return DC_ERROR;
3253 break;
3256 rpt_mutex_lock(&myrpt->lock);
3257 strcpy(myrpt->lastlinknode,digitbuf);
3258 ast_copy_string(myrpt->cmdnode, digitbuf, sizeof(myrpt->cmdnode));
3259 rpt_mutex_unlock(&myrpt->lock);
3260 rpt_telemetry(myrpt, REMGO, NULL);
3261 return DC_COMPLETE;
3263 case 5: /* Status */
3264 rpt_telemetry(myrpt, STATUS, NULL);
3265 return DC_COMPLETE;
3268 case 6: /* All Links Off */
3269 l = myrpt->links.next;
3271 while(l != &myrpt->links){ /* This code is broke and needs to be changed to work with the reconnect kludge */
3272 if (l->chan) ast_softhangup(l->chan, AST_SOFTHANGUP_DEV); /* Hang 'em up */
3273 l = l->next;
3275 rpt_telemetry(myrpt, COMPLETE, NULL);
3276 break;
3278 case 7: /* Identify last node which keyed us up */
3279 rpt_telemetry(myrpt, LASTNODEKEY, NULL);
3280 break;
3282 default:
3283 return DC_ERROR;
3287 return DC_INDETERMINATE;
3291 * Autopatch up
3294 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
3296 pthread_attr_t attr;
3297 int i, index, paramlength;
3298 char *lparam;
3299 char *value = NULL;
3300 char *paramlist[20];
3302 static char *keywords[] = {
3303 "context",
3304 "dialtime",
3305 "farenddisconnect",
3306 "noct",
3307 "quiet",
3308 NULL
3311 if (!myrpt->enable)
3312 return DC_ERROR;
3314 if(debug)
3315 printf("@@@@ Autopatch up\n");
3317 if(!myrpt->callmode){
3318 /* Set defaults */
3319 myrpt->patchnoct = 0;
3320 myrpt->patchdialtime = 0;
3321 myrpt->patchfarenddisconnect = 0;
3322 myrpt->patchquiet = 0;
3323 ast_copy_string(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
3325 if(param){
3326 /* Process parameter list */
3327 lparam = ast_strdupa(param);
3328 if(!lparam){
3329 ast_log(LOG_ERROR,"App_rpt out of memory on line %d\n",__LINE__);
3330 return DC_ERROR;
3332 paramlength = finddelim(lparam, paramlist, 20);
3333 for(i = 0; i < paramlength; i++){
3334 index = matchkeyword(paramlist[i], &value, keywords);
3335 if(value)
3336 value = skipchars(value, "= ");
3337 switch(index){
3339 case 1: /* context */
3340 ast_copy_string(myrpt->patchcontext, value, MAXPATCHCONTEXT) ;
3341 break;
3343 case 2: /* dialtime */
3344 myrpt->patchdialtime = atoi(value);
3345 break;
3347 case 3: /* farenddisconnect */
3348 myrpt->patchfarenddisconnect = atoi(value);
3349 break;
3351 case 4: /* noct */
3352 myrpt->patchnoct = atoi(value);
3353 break;
3355 case 5: /* quiet */
3356 myrpt->patchquiet = atoi(value);
3357 break;
3359 default:
3360 break;
3366 rpt_mutex_lock(&myrpt->lock);
3368 /* if on call, force * into current audio stream */
3370 if ((myrpt->callmode == 2) || (myrpt->callmode == 3)){
3371 myrpt->mydtmf = myrpt->p.funcchar;
3373 if (myrpt->callmode){
3374 rpt_mutex_unlock(&myrpt->lock);
3375 return DC_COMPLETE;
3377 myrpt->callmode = 1;
3378 myrpt->cidx = 0;
3379 myrpt->exten[myrpt->cidx] = 0;
3380 rpt_mutex_unlock(&myrpt->lock);
3381 pthread_attr_init(&attr);
3382 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
3383 ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *) myrpt);
3384 pthread_attr_destroy(&attr);
3385 return DC_COMPLETE;
3389 * Autopatch down
3392 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
3394 if (!myrpt->enable)
3395 return DC_ERROR;
3397 if(debug)
3398 printf("@@@@ Autopatch down\n");
3400 rpt_mutex_lock(&myrpt->lock);
3402 if (!myrpt->callmode){
3403 rpt_mutex_unlock(&myrpt->lock);
3404 return DC_COMPLETE;
3407 myrpt->callmode = 0;
3408 rpt_mutex_unlock(&myrpt->lock);
3409 rpt_telemetry(myrpt, TERM, NULL);
3410 return DC_COMPLETE;
3414 * Status
3417 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
3420 if (!param)
3421 return DC_ERROR;
3423 if (!myrpt->enable)
3424 return DC_ERROR;
3426 if(debug)
3427 printf("@@@@ status param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
3429 switch(myatoi(param)){
3430 case 1: /* System ID */
3431 rpt_telemetry(myrpt, ID1, NULL);
3432 return DC_COMPLETE;
3433 case 2: /* System Time */
3434 rpt_telemetry(myrpt, STATS_TIME, NULL);
3435 return DC_COMPLETE;
3436 case 3: /* app_rpt.c version */
3437 rpt_telemetry(myrpt, STATS_VERSION, NULL);
3438 default:
3439 return DC_ERROR;
3441 return DC_INDETERMINATE;
3445 * Macro-oni (without Salami)
3448 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
3451 const char *val;
3452 int i;
3453 struct ast_channel *mychannel;
3455 if ((!myrpt->remote) && (!myrpt->enable))
3456 return DC_ERROR;
3458 if(debug)
3459 printf("@@@@ macro-oni param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
3461 mychannel = myrpt->remchannel;
3463 if(strlen(digitbuf) < 1) /* needs 1 digit */
3464 return DC_INDETERMINATE;
3466 for(i = 0 ; i < digitbuf[i] ; i++) {
3467 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
3468 return DC_ERROR;
3471 if (*digitbuf == '0') val = myrpt->p.startupmacro;
3472 else val = ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, digitbuf);
3473 /* param was 1 for local buf */
3474 if (!val){
3475 rpt_telemetry(myrpt, MACRO_NOTFOUND, NULL);
3476 return DC_COMPLETE;
3478 rpt_mutex_lock(&myrpt->lock);
3479 if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val))
3481 rpt_mutex_unlock(&myrpt->lock);
3482 rpt_telemetry(myrpt, MACRO_BUSY, NULL);
3483 return DC_ERROR;
3485 myrpt->macrotimer = MACROTIME;
3486 strncat(myrpt->macrobuf,val,MAXMACRO - 1);
3487 rpt_mutex_unlock(&myrpt->lock);
3488 return DC_COMPLETE;
3492 * COP - Control operator
3495 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
3497 if(!param)
3498 return DC_ERROR;
3500 switch(myatoi(param)){
3501 case 1: /* System reset */
3502 system("killall -9 asterisk"); /* FIXME to drastic? */
3503 return DC_COMPLETE;
3505 case 2:
3506 myrpt->enable = 1;
3507 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "RPTENA");
3508 return DC_COMPLETE;
3510 case 3:
3511 myrpt->enable = 0;
3512 return DC_COMPLETE;
3514 case 4: /* test tone on */
3515 rpt_telemetry(myrpt, TEST_TONE, NULL);
3516 return DC_COMPLETE;
3518 case 5: /* Disgorge variables to log for debug purposes */
3519 myrpt->disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
3520 return DC_COMPLETE;
3522 case 6: /* Simulate COR being activated (phone only) */
3523 if (command_source != SOURCE_PHONE) return DC_INDETERMINATE;
3524 return DC_DOKEY;
3527 return DC_INDETERMINATE;
3531 * Collect digits one by one until something matches
3534 static int collect_function_digits(struct rpt *myrpt, char *digits,
3535 int command_source, struct rpt_link *mylink)
3537 int i;
3538 char *stringp,*action,*param,*functiondigits;
3539 char function_table_name[30] = "";
3540 char workstring[200];
3542 struct ast_variable *vp;
3544 if(debug)
3545 printf("@@@@ Digits collected: %s, source: %d\n", digits, command_source);
3547 if (command_source == SOURCE_DPHONE) {
3548 if (!myrpt->p.dphone_functions) return DC_INDETERMINATE;
3549 ast_copy_string(function_table_name, myrpt->p.dphone_functions, sizeof(function_table_name));
3551 else if (command_source == SOURCE_PHONE) {
3552 if (!myrpt->p.phone_functions) return DC_INDETERMINATE;
3553 ast_copy_string(function_table_name, myrpt->p.phone_functions, sizeof(function_table_name));
3555 else if (command_source == SOURCE_LNK)
3556 ast_copy_string(function_table_name, myrpt->p.link_functions, sizeof(function_table_name));
3557 else
3558 ast_copy_string(function_table_name, myrpt->p.functions, sizeof(function_table_name));
3559 vp = ast_variable_browse(myrpt->cfg, function_table_name);
3560 while(vp) {
3561 if(!strncasecmp(vp->name, digits, strlen(vp->name)))
3562 break;
3563 vp = vp->next;
3565 if(!vp) {
3566 int n;
3568 n = myrpt->longestfunc;
3569 if (command_source == SOURCE_LNK) n = myrpt->link_longestfunc;
3570 else
3571 if (command_source == SOURCE_PHONE) n = myrpt->phone_longestfunc;
3572 else
3573 if (command_source == SOURCE_DPHONE) n = myrpt->dphone_longestfunc;
3575 if(strlen(digits) >= n)
3576 return DC_ERROR;
3577 else
3578 return DC_INDETERMINATE;
3580 /* Found a match, retrieve value part and parse */
3581 ast_copy_string(workstring, vp->value, sizeof(workstring));
3582 stringp = workstring;
3583 action = strsep(&stringp, ",");
3584 param = stringp;
3585 if(debug)
3586 printf("@@@@ action: %s, param = %s\n",action, (param) ? param : "(null)");
3587 /* Look up the action */
3588 for(i = 0 ; i < (sizeof(function_table)/sizeof(struct function_table_tag)); i++){
3589 if(!strncasecmp(action, function_table[i].action, strlen(action)))
3590 break;
3592 if(debug)
3593 printf("@@@@ table index i = %d\n",i);
3594 if(i == (sizeof(function_table)/sizeof(struct function_table_tag))){
3595 /* Error, action not in table */
3596 return DC_ERROR;
3598 if(function_table[i].function == NULL){
3599 /* Error, function undefined */
3600 if(debug)
3601 printf("@@@@ NULL for action: %s\n",action);
3602 return DC_ERROR;
3604 functiondigits = digits + strlen(vp->name);
3605 return (*function_table[i].function)(myrpt, param, functiondigits, command_source, mylink);
3609 static void handle_link_data(struct rpt *myrpt, struct rpt_link *mylink,
3610 char *str)
3612 char tmp[300],cmd[300] = "",dest[300],src[300],c;
3613 int seq, res;
3614 struct rpt_link *l;
3615 struct ast_frame wf;
3617 wf.frametype = AST_FRAME_TEXT;
3618 wf.subclass = 0;
3619 wf.offset = 0;
3620 wf.mallocd = 1;
3621 wf.datalen = strlen(str) + 1;
3622 wf.samples = 0;
3623 /* put string in our buffer */
3624 ast_copy_string(tmp, str, sizeof(tmp));
3626 if (!strcmp(tmp,discstr))
3628 mylink->disced = 1;
3629 mylink->retries = MAX_RETRIES + 1;
3630 ast_softhangup(mylink->chan,AST_SOFTHANGUP_DEV);
3631 return;
3633 if (sscanf(tmp,"%s %s %s %d %c",cmd,dest,src,&seq,&c) != 5)
3635 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
3636 return;
3638 if (strcmp(cmd,"D"))
3640 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
3641 return;
3644 if (dest[0] == '0')
3646 strcpy(dest,myrpt->name);
3649 /* if not for me, redistribute to all links */
3650 if (strcmp(dest,myrpt->name))
3652 l = myrpt->links.next;
3653 /* see if this is one in list */
3654 while(l != &myrpt->links)
3656 if (l->name[0] == '0')
3658 l = l->next;
3659 continue;
3661 /* dont send back from where it came */
3662 if ((l == mylink) || (!strcmp(l->name,mylink->name)))
3664 l = l->next;
3665 continue;
3667 /* if it is, send it and we're done */
3668 if (!strcmp(l->name,dest))
3670 /* send, but not to src */
3671 if (strcmp(l->name,src)) {
3672 wf.data = strdup(str);
3673 if (l->chan) ast_write(l->chan,&wf);
3675 return;
3677 l = l->next;
3679 l = myrpt->links.next;
3680 /* otherwise, send it to all of em */
3681 while(l != &myrpt->links)
3683 if (l->name[0] == '0')
3685 l = l->next;
3686 continue;
3688 /* dont send back from where it came */
3689 if ((l == mylink) || (!strcmp(l->name,mylink->name)))
3691 l = l->next;
3692 continue;
3694 /* send, but not to src */
3695 if (strcmp(l->name,src)) {
3696 wf.data = strdup(str);
3697 if (l->chan) ast_write(l->chan,&wf);
3699 l = l->next;
3701 return;
3703 rpt_mutex_lock(&myrpt->lock);
3704 if (c == myrpt->p.endchar) myrpt->stopgen = 1;
3705 if (myrpt->callmode == 1)
3707 myrpt->exten[myrpt->cidx++] = c;
3708 myrpt->exten[myrpt->cidx] = 0;
3709 /* if this exists */
3710 if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
3712 myrpt->callmode = 2;
3713 if(!myrpt->patchquiet){
3714 rpt_mutex_unlock(&myrpt->lock);
3715 rpt_telemetry(myrpt,PROC,NULL);
3716 rpt_mutex_lock(&myrpt->lock);
3719 /* if can continue, do so */
3720 if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
3722 /* call has failed, inform user */
3723 myrpt->callmode = 4;
3726 if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
3728 myrpt->mydtmf = c;
3730 if (c == myrpt->p.funcchar)
3732 myrpt->rem_dtmfidx = 0;
3733 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
3734 time(&myrpt->rem_dtmf_time);
3735 rpt_mutex_unlock(&myrpt->lock);
3736 return;
3738 else if ((c != myrpt->p.endchar) && (myrpt->rem_dtmfidx >= 0))
3740 time(&myrpt->rem_dtmf_time);
3741 if (myrpt->rem_dtmfidx < MAXDTMF)
3743 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
3744 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
3746 rpt_mutex_unlock(&myrpt->lock);
3747 ast_copy_string(cmd, myrpt->rem_dtmfbuf, sizeof(cmd));
3748 res = collect_function_digits(myrpt, cmd, SOURCE_LNK, mylink);
3749 rpt_mutex_lock(&myrpt->lock);
3751 switch(res){
3753 case DC_INDETERMINATE:
3754 break;
3756 case DC_REQ_FLUSH:
3757 myrpt->rem_dtmfidx = 0;
3758 myrpt->rem_dtmfbuf[0] = 0;
3759 break;
3762 case DC_COMPLETE:
3763 myrpt->totalexecdcommands++;
3764 myrpt->dailyexecdcommands++;
3765 ast_copy_string(myrpt->lastdtmfcommand, cmd, MAXDTMF);
3766 myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
3767 myrpt->rem_dtmfbuf[0] = 0;
3768 myrpt->rem_dtmfidx = -1;
3769 myrpt->rem_dtmf_time = 0;
3770 break;
3772 case DC_ERROR:
3773 default:
3774 myrpt->rem_dtmfbuf[0] = 0;
3775 myrpt->rem_dtmfidx = -1;
3776 myrpt->rem_dtmf_time = 0;
3777 break;
3782 rpt_mutex_unlock(&myrpt->lock);
3783 return;
3786 static void handle_link_phone_dtmf(struct rpt *myrpt, struct rpt_link *mylink,
3787 char c)
3790 char cmd[300];
3791 int res;
3793 rpt_mutex_lock(&myrpt->lock);
3794 if (c == myrpt->p.endchar)
3796 if (mylink->lastrx)
3798 mylink->lastrx = 0;
3799 rpt_mutex_unlock(&myrpt->lock);
3800 return;
3802 myrpt->stopgen = 1;
3803 if (myrpt->cmdnode[0])
3805 myrpt->cmdnode[0] = 0;
3806 myrpt->dtmfidx = -1;
3807 myrpt->dtmfbuf[0] = 0;
3808 rpt_mutex_unlock(&myrpt->lock);
3809 rpt_telemetry(myrpt,COMPLETE,NULL);
3810 return;
3813 if (myrpt->cmdnode[0])
3815 rpt_mutex_unlock(&myrpt->lock);
3816 send_link_dtmf(myrpt,c);
3817 return;
3819 if (myrpt->callmode == 1)
3821 myrpt->exten[myrpt->cidx++] = c;
3822 myrpt->exten[myrpt->cidx] = 0;
3823 /* if this exists */
3824 if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
3826 myrpt->callmode = 2;
3827 if(!myrpt->patchquiet){
3828 rpt_mutex_unlock(&myrpt->lock);
3829 rpt_telemetry(myrpt,PROC,NULL);
3830 rpt_mutex_lock(&myrpt->lock);
3833 /* if can continue, do so */
3834 if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
3836 /* call has failed, inform user */
3837 myrpt->callmode = 4;
3840 if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
3842 myrpt->mydtmf = c;
3844 if (c == myrpt->p.funcchar)
3846 myrpt->rem_dtmfidx = 0;
3847 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
3848 time(&myrpt->rem_dtmf_time);
3849 rpt_mutex_unlock(&myrpt->lock);
3850 return;
3852 else if ((c != myrpt->p.endchar) && (myrpt->rem_dtmfidx >= 0))
3854 time(&myrpt->rem_dtmf_time);
3855 if (myrpt->rem_dtmfidx < MAXDTMF)
3857 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
3858 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
3860 rpt_mutex_unlock(&myrpt->lock);
3861 ast_copy_string(cmd, myrpt->rem_dtmfbuf, sizeof(cmd));
3862 switch(mylink->phonemode)
3864 case 1:
3865 res = collect_function_digits(myrpt, cmd,
3866 SOURCE_PHONE, mylink);
3867 break;
3868 case 2:
3869 res = collect_function_digits(myrpt, cmd,
3870 SOURCE_DPHONE,mylink);
3871 break;
3872 default:
3873 res = collect_function_digits(myrpt, cmd,
3874 SOURCE_LNK, mylink);
3875 break;
3878 rpt_mutex_lock(&myrpt->lock);
3880 switch(res){
3882 case DC_INDETERMINATE:
3883 break;
3885 case DC_DOKEY:
3886 mylink->lastrx = 1;
3887 break;
3889 case DC_REQ_FLUSH:
3890 myrpt->rem_dtmfidx = 0;
3891 myrpt->rem_dtmfbuf[0] = 0;
3892 break;
3895 case DC_COMPLETE:
3896 myrpt->totalexecdcommands++;
3897 myrpt->dailyexecdcommands++;
3898 ast_copy_string(myrpt->lastdtmfcommand, cmd, MAXDTMF);
3899 myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
3900 myrpt->rem_dtmfbuf[0] = 0;
3901 myrpt->rem_dtmfidx = -1;
3902 myrpt->rem_dtmf_time = 0;
3903 break;
3905 case DC_ERROR:
3906 default:
3907 myrpt->rem_dtmfbuf[0] = 0;
3908 myrpt->rem_dtmfidx = -1;
3909 myrpt->rem_dtmf_time = 0;
3910 break;
3915 rpt_mutex_unlock(&myrpt->lock);
3916 return;
3919 /* Doug Hall RBI-1 serial data definitions:
3921 * Byte 0: Expansion external outputs
3922 * Byte 1:
3923 * Bits 0-3 are BAND as follows:
3924 * Bits 4-5 are POWER bits as follows:
3925 * 00 - Low Power
3926 * 01 - Hi Power
3927 * 02 - Med Power
3928 * Bits 6-7 are always set
3929 * Byte 2:
3930 * Bits 0-3 MHZ in BCD format
3931 * Bits 4-5 are offset as follows:
3932 * 00 - minus
3933 * 01 - plus
3934 * 02 - simplex
3935 * 03 - minus minus (whatever that is)
3936 * Bit 6 is the 0/5 KHZ bit
3937 * Bit 7 is always set
3938 * Byte 3:
3939 * Bits 0-3 are 10 KHZ in BCD format
3940 * Bits 4-7 are 100 KHZ in BCD format
3941 * Byte 4: PL Tone code and encode/decode enable bits
3942 * Bits 0-5 are PL tone code (comspec binary codes)
3943 * Bit 6 is encode enable/disable
3944 * Bit 7 is decode enable/disable
3947 /* take the frequency from the 10 mhz digits (and up) and convert it
3948 to a band number */
3950 static int rbi_mhztoband(char *str)
3952 int i;
3954 i = atoi(str) / 10; /* get the 10's of mhz */
3955 switch(i)
3957 case 2:
3958 return 10;
3959 case 5:
3960 return 11;
3961 case 14:
3962 return 2;
3963 case 22:
3964 return 3;
3965 case 44:
3966 return 4;
3967 case 124:
3968 return 0;
3969 case 125:
3970 return 1;
3971 case 126:
3972 return 8;
3973 case 127:
3974 return 5;
3975 case 128:
3976 return 6;
3977 case 129:
3978 return 7;
3979 default:
3980 break;
3982 return -1;
3985 /* take a PL frequency and turn it into a code */
3986 static int rbi_pltocode(char *str)
3988 int i;
3989 char *s;
3991 s = strchr(str,'.');
3992 i = 0;
3993 if (s) i = atoi(s + 1);
3994 i += atoi(str) * 10;
3995 switch(i)
3997 case 670:
3998 return 0;
3999 case 719:
4000 return 1;
4001 case 744:
4002 return 2;
4003 case 770:
4004 return 3;
4005 case 797:
4006 return 4;
4007 case 825:
4008 return 5;
4009 case 854:
4010 return 6;
4011 case 885:
4012 return 7;
4013 case 915:
4014 return 8;
4015 case 948:
4016 return 9;
4017 case 974:
4018 return 10;
4019 case 1000:
4020 return 11;
4021 case 1035:
4022 return 12;
4023 case 1072:
4024 return 13;
4025 case 1109:
4026 return 14;
4027 case 1148:
4028 return 15;
4029 case 1188:
4030 return 16;
4031 case 1230:
4032 return 17;
4033 case 1273:
4034 return 18;
4035 case 1318:
4036 return 19;
4037 case 1365:
4038 return 20;
4039 case 1413:
4040 return 21;
4041 case 1462:
4042 return 22;
4043 case 1514:
4044 return 23;
4045 case 1567:
4046 return 24;
4047 case 1622:
4048 return 25;
4049 case 1679:
4050 return 26;
4051 case 1738:
4052 return 27;
4053 case 1799:
4054 return 28;
4055 case 1862:
4056 return 29;
4057 case 1928:
4058 return 30;
4059 case 2035:
4060 return 31;
4061 case 2107:
4062 return 32;
4063 case 2181:
4064 return 33;
4065 case 2257:
4066 return 34;
4067 case 2336:
4068 return 35;
4069 case 2418:
4070 return 36;
4071 case 2503:
4072 return 37;
4074 return -1;
4078 * Shift out a formatted serial bit stream
4081 static void rbi_out_parallel(struct rpt *myrpt,unsigned char *data)
4083 int i,j;
4084 unsigned char od,d;
4085 static volatile long long delayvar;
4087 for(i = 0 ; i < 5 ; i++){
4088 od = *data++;
4089 for(j = 0 ; j < 8 ; j++){
4090 d = od & 1;
4091 outb(d,myrpt->p.iobase);
4092 /* >= 15 us */
4093 for(delayvar = 1; delayvar < 15000; delayvar++);
4094 od >>= 1;
4095 outb(d | 2,myrpt->p.iobase);
4096 /* >= 30 us */
4097 for(delayvar = 1; delayvar < 30000; delayvar++);
4098 outb(d,myrpt->p.iobase);
4099 /* >= 10 us */
4100 for(delayvar = 1; delayvar < 10000; delayvar++);
4103 /* >= 50 us */
4104 for(delayvar = 1; delayvar < 50000; delayvar++);
4107 static void rbi_out(struct rpt *myrpt,unsigned char *data)
4109 struct zt_radio_param r;
4111 memset(&r,0,sizeof(struct zt_radio_param));
4112 r.radpar = ZT_RADPAR_REMMODE;
4113 r.data = ZT_RADPAR_REM_RBI1;
4114 /* if setparam ioctl fails, its probably not a pciradio card */
4115 if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&r) == -1)
4117 rbi_out_parallel(myrpt,data);
4118 return;
4120 r.radpar = ZT_RADPAR_REMCOMMAND;
4121 memcpy(&r.data,data,5);
4122 if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&r) == -1)
4124 ast_log(LOG_WARNING,"Cannot send RBI command for channel %s\n",myrpt->rxchannel->name);
4125 return;
4129 static int serial_remote_io(struct rpt *myrpt, unsigned char *txbuf, int txbytes, char *rxbuf,
4130 int rxmaxbytes, int asciiflag)
4132 int i;
4133 struct zt_radio_param prm;
4135 if(debug){
4136 printf("String output was: ");
4137 for(i = 0; i < txbytes; i++)
4138 printf("%02X ", (unsigned char ) txbuf[i]);
4139 printf("\n");
4142 prm.radpar = ZT_RADPAR_REMMODE;
4143 if (asciiflag) prm.data = ZT_RADPAR_REM_SERIAL_ASCII;
4144 else prm.data = ZT_RADPAR_REM_SERIAL;
4145 if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&prm) == -1) return -1;
4146 prm.radpar = ZT_RADPAR_REMCOMMAND;
4147 prm.data = rxmaxbytes;
4148 memcpy(prm.buf,txbuf,txbytes);
4149 prm.index = txbytes;
4150 if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&prm) == -1) return -1;
4151 if (rxbuf)
4153 *rxbuf = 0;
4154 memcpy(rxbuf,prm.buf,prm.index);
4156 return(prm.index);
4159 static int setrbi(struct rpt *myrpt)
4161 char tmp[MAXREMSTR] = "",*s;
4162 unsigned char rbicmd[5];
4163 int band,txoffset = 0,txpower = 0,txpl;
4165 /* must be a remote system */
4166 if (!myrpt->remote) return(0);
4167 /* must have rbi hardware */
4168 if (strncmp(myrpt->remote,remote_rig_rbi,3)) return(0);
4169 ast_copy_string(tmp, myrpt->freq, sizeof(tmp));
4170 s = strchr(tmp,'.');
4171 /* if no decimal, is invalid */
4173 if (s == NULL){
4174 if(debug)
4175 printf("@@@@ Frequency needs a decimal\n");
4176 return -1;
4179 *s++ = 0;
4180 if (strlen(tmp) < 2){
4181 if(debug)
4182 printf("@@@@ Bad MHz digits: %s\n", tmp);
4183 return -1;
4186 if (strlen(s) < 3){
4187 if(debug)
4188 printf("@@@@ Bad KHz digits: %s\n", s);
4189 return -1;
4192 if ((s[2] != '0') && (s[2] != '5')){
4193 if(debug)
4194 printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
4195 return -1;
4198 band = rbi_mhztoband(tmp);
4199 if (band == -1){
4200 if(debug)
4201 printf("@@@@ Bad Band: %s\n", tmp);
4202 return -1;
4205 txpl = rbi_pltocode(myrpt->txpl);
4207 if (txpl == -1){
4208 if(debug)
4209 printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
4210 return -1;
4214 switch(myrpt->offset)
4216 case REM_MINUS:
4217 txoffset = 0;
4218 break;
4219 case REM_PLUS:
4220 txoffset = 0x10;
4221 break;
4222 case REM_SIMPLEX:
4223 txoffset = 0x20;
4224 break;
4226 switch(myrpt->powerlevel)
4228 case REM_LOWPWR:
4229 txpower = 0;
4230 break;
4231 case REM_MEDPWR:
4232 txpower = 0x20;
4233 break;
4234 case REM_HIPWR:
4235 txpower = 0x10;
4236 break;
4238 rbicmd[0] = 0;
4239 rbicmd[1] = band | txpower | 0xc0;
4240 rbicmd[2] = (*(s - 2) - '0') | txoffset | 0x80;
4241 if (s[2] == '5') rbicmd[2] |= 0x40;
4242 rbicmd[3] = ((*s - '0') << 4) + (s[1] - '0');
4243 rbicmd[4] = txpl;
4244 if (myrpt->txplon) rbicmd[4] |= 0x40;
4245 if (myrpt->rxplon) rbicmd[4] |= 0x80;
4246 rbi_out(myrpt,rbicmd);
4247 return 0;
4251 /* Check for valid rbi frequency */
4252 /* Hard coded limits now, configurable later, maybe? */
4254 static int check_freq_rbi(int m, int d, int *defmode)
4256 int dflmd = REM_MODE_FM;
4258 if(m == 50){ /* 6 meters */
4259 if(d < 10100)
4260 return -1;
4262 else if((m >= 51) && ( m < 54)){
4265 else if(m == 144){ /* 2 meters */
4266 if(d < 10100)
4267 return -1;
4269 else if((m >= 145) && (m < 148)){
4272 else if((m >= 222) && (m < 225)){ /* 1.25 meters */
4275 else if((m >= 430) && (m < 450)){ /* 70 centimeters */
4278 else if((m >= 1240) && (m < 1300)){ /* 23 centimeters */
4281 else
4282 return -1;
4284 if(defmode)
4285 *defmode = dflmd;
4288 return 0;
4292 * Split frequency into mhz and decimals
4295 static int split_freq(char *mhz, char *decimals, char *freq)
4297 char *decp;
4299 freq = ast_strdupa(freq);
4300 if ((decp = strchr(freq, '.'))) {
4301 *decp++ = 0;
4302 ast_copy_string(mhz, freq, MAXREMSTR);
4303 strcpy(decimals, "00000");
4304 ast_copy_string(decimals, decp, 6);
4305 return 0;
4307 else
4308 return -1;
4313 * Split ctcss frequency into hertz and decimal
4316 static int split_ctcss_freq(char *hertz, char *decimal, char *freq)
4318 char *decp;
4320 freq = ast_strdupa(freq);
4321 if ((decp = strchr(freq, '.'))) {
4322 *decp++ = 0;
4323 ast_copy_string(hertz, freq, MAXREMSTR);
4324 ast_copy_string(decimal, decp, sizeof(decimal));
4325 return 0;
4327 else
4328 return -1;
4334 * FT-897 I/O handlers
4337 /* Check to see that the frequency is valid */
4338 /* Hard coded limits now, configurable later, maybe? */
4341 static int check_freq_ft897(int m, int d, int *defmode)
4343 int dflmd = REM_MODE_FM;
4345 if(m == 1){ /* 160 meters */
4346 dflmd = REM_MODE_LSB;
4347 if(d < 80001)
4348 return -1;
4350 else if(m == 3){ /* 80 meters */
4351 dflmd = REM_MODE_LSB;
4352 if(d < 75001)
4353 return -1;
4355 else if(m == 7){ /* 40 meters */
4356 dflmd = REM_MODE_LSB;
4357 if((d < 15001) || (d > 29999))
4358 return -1;
4360 else if(m == 14){ /* 20 meters */
4361 dflmd = REM_MODE_USB;
4362 if((d < 15001) || (d > 34999))
4363 return -1;
4365 else if(m == 18){ /* 17 meters */
4366 dflmd = REM_MODE_USB;
4367 if((d < 11001) || (d > 16797))
4368 return -1;
4370 else if(m == 21){ /* 15 meters */
4371 dflmd = REM_MODE_USB;
4372 if((d < 20001) || (d > 44999))
4373 return -1;
4375 else if(m == 24){ /* 12 meters */
4376 dflmd = REM_MODE_USB;
4377 if((d < 93001) || (d > 98999))
4378 return -1;
4380 else if(m == 28){ /* 10 meters */
4381 dflmd = REM_MODE_USB;
4382 if(d < 30001)
4383 return -1;
4385 else if(m == 29){
4386 if(d >= 51000)
4387 dflmd = REM_MODE_FM;
4388 else
4389 dflmd = REM_MODE_USB;
4390 if(d > 69999)
4391 return -1;
4393 else if(m == 50){ /* 6 meters */
4394 if(d < 10100)
4395 return -1;
4396 if(d >= 30000)
4397 dflmd = REM_MODE_FM;
4398 else
4399 dflmd = REM_MODE_USB;
4402 else if((m >= 51) && ( m < 54)){
4403 dflmd = REM_MODE_FM;
4405 else if(m == 144){ /* 2 meters */
4406 if(d < 10100)
4407 return -1;
4408 if(d >= 30000)
4409 dflmd = REM_MODE_FM;
4410 else
4411 dflmd = REM_MODE_USB;
4413 else if((m >= 145) && (m < 148)){
4414 dflmd = REM_MODE_FM;
4416 else if((m >= 430) && (m < 450)){ /* 70 centimeters */
4417 if(m < 438)
4418 dflmd = REM_MODE_USB;
4419 else
4420 dflmd = REM_MODE_FM;
4423 else
4424 return -1;
4426 if(defmode)
4427 *defmode = dflmd;
4429 return 0;
4433 * Set a new frequency for the FT897
4436 static int set_freq_ft897(struct rpt *myrpt, char *newfreq)
4438 char mhz[MAXREMSTR];
4439 char decimals[MAXREMSTR];
4440 unsigned char cmdstr[5];
4441 int fd,m,d;
4443 fd = 0;
4444 if(debug)
4445 printf("New frequency: %s\n",newfreq);
4447 if(split_freq(mhz, decimals, newfreq))
4448 return -1;
4450 m = atoi(mhz);
4451 d = atoi(decimals);
4453 /* The FT-897 likes packed BCD frequencies */
4455 cmdstr[0] = ((m / 100) << 4) + ((m % 100)/10); /* 100MHz 10Mhz */
4456 cmdstr[1] = ((m % 10) << 4) + (d / 10000); /* 1MHz 100KHz */
4457 cmdstr[2] = (((d % 10000)/1000) << 4) + ((d % 1000)/ 100); /* 10KHz 1KHz */
4458 cmdstr[3] = (((d % 100)/10) << 4) + (d % 10); /* 100Hz 10Hz */
4459 cmdstr[4] = 0x01; /* command */
4461 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
4465 /* ft-897 simple commands */
4467 static int simple_command_ft897(struct rpt *myrpt, char command)
4469 unsigned char cmdstr[5];
4471 memset(cmdstr, 0, 5);
4473 cmdstr[4] = command;
4475 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
4479 /* ft-897 offset */
4481 static int set_offset_ft897(struct rpt *myrpt, char offset)
4483 unsigned char cmdstr[5];
4485 memset(cmdstr, 0, 5);
4487 switch(offset){
4488 case REM_SIMPLEX:
4489 cmdstr[0] = 0x89;
4490 break;
4492 case REM_MINUS:
4493 cmdstr[0] = 0x09;
4494 break;
4496 case REM_PLUS:
4497 cmdstr[0] = 0x49;
4498 break;
4500 default:
4501 return -1;
4504 cmdstr[4] = 0x09;
4506 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
4509 /* ft-897 mode */
4511 static int set_mode_ft897(struct rpt *myrpt, char newmode)
4513 unsigned char cmdstr[5];
4515 memset(cmdstr, 0, 5);
4517 switch(newmode){
4518 case REM_MODE_FM:
4519 cmdstr[0] = 0x08;
4520 break;
4522 case REM_MODE_USB:
4523 cmdstr[0] = 0x01;
4524 break;
4526 case REM_MODE_LSB:
4527 cmdstr[0] = 0x00;
4528 break;
4530 case REM_MODE_AM:
4531 cmdstr[0] = 0x04;
4532 break;
4534 default:
4535 return -1;
4537 cmdstr[4] = 0x07;
4539 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
4542 /* Set tone encode and decode modes */
4544 static int set_ctcss_mode_ft897(struct rpt *myrpt, char txplon, char rxplon)
4546 unsigned char cmdstr[5];
4548 memset(cmdstr, 0, 5);
4550 if(rxplon && txplon)
4551 cmdstr[0] = 0x2A; /* Encode and Decode */
4552 else if (!rxplon && txplon)
4553 cmdstr[0] = 0x4A; /* Encode only */
4554 else if (rxplon && !txplon)
4555 cmdstr[0] = 0x3A; /* Encode only */
4556 else
4557 cmdstr[0] = 0x8A; /* OFF */
4559 cmdstr[4] = 0x0A;
4561 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
4565 /* Set transmit and receive ctcss tone frequencies */
4567 static int set_ctcss_freq_ft897(struct rpt *myrpt, char *txtone, char *rxtone)
4569 unsigned char cmdstr[5];
4570 char hertz[MAXREMSTR],decimal[MAXREMSTR];
4571 int h,d;
4573 memset(cmdstr, 0, 5);
4575 if(split_ctcss_freq(hertz, decimal, txtone))
4576 return -1;
4578 h = atoi(hertz);
4579 d = atoi(decimal);
4581 cmdstr[0] = ((h / 100) << 4) + (h % 100)/ 10;
4582 cmdstr[1] = ((h % 10) << 4) + (d % 10);
4584 if(rxtone){
4586 if(split_ctcss_freq(hertz, decimal, rxtone))
4587 return -1;
4589 h = atoi(hertz);
4590 d = atoi(decimal);
4592 cmdstr[2] = ((h / 100) << 4) + (h % 100)/ 10;
4593 cmdstr[3] = ((h % 10) << 4) + (d % 10);
4595 cmdstr[4] = 0x0B;
4597 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
4602 static int set_ft897(struct rpt *myrpt)
4604 int res;
4606 if(debug)
4607 printf("@@@@ lock on\n");
4609 res = simple_command_ft897(myrpt, 0x00); /* LOCK on */
4611 if(debug)
4612 printf("@@@@ ptt off\n");
4614 if(!res)
4615 res = simple_command_ft897(myrpt, 0x88); /* PTT off */
4617 if(debug)
4618 printf("Modulation mode\n");
4620 if(!res)
4621 res = set_mode_ft897(myrpt, myrpt->remmode); /* Modulation mode */
4623 if(debug)
4624 printf("Split off\n");
4626 if(!res)
4627 simple_command_ft897(myrpt, 0x82); /* Split off */
4629 if(debug)
4630 printf("Frequency\n");
4632 if(!res)
4633 res = set_freq_ft897(myrpt, myrpt->freq); /* Frequency */
4634 if((myrpt->remmode == REM_MODE_FM)){
4635 if(debug)
4636 printf("Offset\n");
4637 if(!res)
4638 res = set_offset_ft897(myrpt, myrpt->offset); /* Offset if FM */
4639 if((!res)&&(myrpt->rxplon || myrpt->txplon)){
4640 if(debug)
4641 printf("CTCSS tone freqs.\n");
4642 res = set_ctcss_freq_ft897(myrpt, myrpt->txpl, myrpt->rxpl); /* CTCSS freqs if CTCSS is enabled */
4644 if(!res){
4645 if(debug)
4646 printf("CTCSS mode\n");
4647 res = set_ctcss_mode_ft897(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */
4650 if((myrpt->remmode == REM_MODE_USB)||(myrpt->remmode == REM_MODE_LSB)){
4651 if(debug)
4652 printf("Clarifier off\n");
4653 simple_command_ft897(myrpt, 0x85); /* Clarifier off if LSB or USB */
4655 return res;
4658 static int closerem_ft897(struct rpt *myrpt)
4660 simple_command_ft897(myrpt, 0x88); /* PTT off */
4661 return 0;
4665 * Bump frequency up or down by a small amount
4666 * Return 0 if the new frequnecy is valid, or -1 if invalid
4667 * Interval is in Hz, resolution is 10Hz
4670 static int multimode_bump_freq_ft897(struct rpt *myrpt, int interval)
4672 int m,d;
4673 char mhz[MAXREMSTR], decimals[MAXREMSTR];
4675 if(debug)
4676 printf("Before bump: %s\n", myrpt->freq);
4678 if(split_freq(mhz, decimals, myrpt->freq))
4679 return -1;
4681 m = atoi(mhz);
4682 d = atoi(decimals);
4684 d += (interval / 10); /* 10Hz resolution */
4685 if(d < 0){
4686 m--;
4687 d += 100000;
4689 else if(d >= 100000){
4690 m++;
4691 d -= 100000;
4694 if(check_freq_ft897(m, d, NULL)){
4695 if(debug)
4696 printf("Bump freq invalid\n");
4697 return -1;
4700 snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d);
4702 if(debug)
4703 printf("After bump: %s\n", myrpt->freq);
4705 return set_freq_ft897(myrpt, myrpt->freq);
4711 * Dispatch to correct I/O handler
4714 static int setrem(struct rpt *myrpt)
4716 return 0; /* XXX BROKEN!! */
4717 if(!strcmp(myrpt->remote, remote_rig_ft897))
4718 return set_ft897(myrpt);
4719 else if(!strcmp(myrpt->remote, remote_rig_rbi))
4720 return setrbi(myrpt);
4721 else
4722 return -1;
4725 static int closerem(struct rpt *myrpt)
4727 return 0; /* XXX BROKEN!! */
4728 if(!strcmp(myrpt->remote, remote_rig_ft897))
4729 return closerem_ft897(myrpt);
4730 else
4731 return 0;
4735 * Dispatch to correct frequency checker
4738 static int check_freq(struct rpt *myrpt, int m, int d, int *defmode)
4740 if(!strcmp(myrpt->remote, remote_rig_ft897))
4741 return check_freq_ft897(m, d, defmode);
4742 else if(!strcmp(myrpt->remote, remote_rig_rbi))
4743 return check_freq_rbi(m, d, defmode);
4744 else
4745 return -1;
4749 * Return 1 if rig is multimode capable
4752 static int multimode_capable(struct rpt *myrpt)
4754 if(!strcmp(myrpt->remote, remote_rig_ft897))
4755 return 1;
4756 return 0;
4760 * Dispatch to correct frequency bumping function
4763 static int multimode_bump_freq(struct rpt *myrpt, int interval)
4765 if(!strcmp(myrpt->remote, remote_rig_ft897))
4766 return multimode_bump_freq_ft897(myrpt, interval);
4767 else
4768 return -1;
4773 * Queue announcment that scan has been stopped
4776 static void stop_scan(struct rpt *myrpt, int flag)
4778 myrpt->hfscanmode = 0;
4779 myrpt->hfscanstatus = ((flag) ? -2 : -1);
4783 * This is called periodically when in scan mode
4787 static int service_scan(struct rpt *myrpt)
4789 int res, interval;
4790 char mhz[MAXREMSTR], decimals[MAXREMSTR], k10=0i, k100=0;
4792 switch(myrpt->hfscanmode){
4794 case HF_SCAN_DOWN_SLOW:
4795 interval = -10; /* 100Hz /sec */
4796 break;
4798 case HF_SCAN_DOWN_QUICK:
4799 interval = -50; /* 500Hz /sec */
4800 break;
4802 case HF_SCAN_DOWN_FAST:
4803 interval = -200; /* 2KHz /sec */
4804 break;
4806 case HF_SCAN_UP_SLOW:
4807 interval = 10; /* 100Hz /sec */
4808 break;
4810 case HF_SCAN_UP_QUICK:
4811 interval = 50; /* 500 Hz/sec */
4812 break;
4814 case HF_SCAN_UP_FAST:
4815 interval = 200; /* 2KHz /sec */
4816 break;
4818 default:
4819 myrpt->hfscanmode = 0; /* Huh? */
4820 return -1;
4823 res = split_freq(mhz, decimals, myrpt->freq);
4825 if(!res){
4826 k100 =decimals[0];
4827 k10 = decimals[1];
4828 res = multimode_bump_freq(myrpt, interval);
4831 if(!res)
4832 res = split_freq(mhz, decimals, myrpt->freq);
4835 if(res){
4836 stop_scan(myrpt,1);
4837 return -1;
4840 /* Announce 10KHz boundaries */
4841 if(k10 != decimals[1]){
4842 int myhund = (interval < 0) ? k100 : decimals[0];
4843 int myten = (interval < 0) ? k10 : decimals[1];
4844 myrpt->hfscanstatus = (myten == '0') ? (myhund - '0') * 100 : (myten - '0') * 10;
4846 return res;
4851 static int rmt_telem_start(struct rpt *myrpt, struct ast_channel *chan, int delay)
4853 myrpt->remotetx = 0;
4854 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
4855 if (!myrpt->remoterx)
4856 ast_indicate(chan,AST_CONTROL_RADIO_KEY);
4857 if (ast_safe_sleep(chan, delay) == -1)
4858 return -1;
4859 return 0;
4863 static int rmt_telem_finish(struct rpt *myrpt, struct ast_channel *chan)
4866 struct zt_params par;
4868 if (ioctl(myrpt->txchannel->fds[0],ZT_GET_PARAMS,&par) == -1)
4870 return -1;
4873 if (!par.rxisoffhook)
4875 ast_indicate(myrpt->remchannel,AST_CONTROL_RADIO_UNKEY);
4876 myrpt->remoterx = 0;
4878 else
4880 myrpt->remoterx = 1;
4882 return 0;
4886 static int rmt_sayfile(struct rpt *myrpt, struct ast_channel *chan, int delay, char *filename)
4888 int res;
4890 res = rmt_telem_start(myrpt, chan, delay);
4892 if(!res)
4893 res = sayfile(chan, filename);
4895 if(!res)
4896 res = rmt_telem_finish(myrpt, chan);
4897 return res;
4900 static int rmt_saycharstr(struct rpt *myrpt, struct ast_channel *chan, int delay, char *charstr)
4902 int res;
4904 res = rmt_telem_start(myrpt, chan, delay);
4906 if(!res)
4907 res = saycharstr(chan, charstr);
4909 if(!res)
4910 res = rmt_telem_finish(myrpt, chan);
4911 return res;
4917 * Remote base function
4920 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
4922 char *s,*s1,*s2;
4923 const char *val;
4924 int i,j,ht,k,l,ls2,m,d,res,offset,offsave, modesave, defmode;
4925 char multimode = 0;
4926 char oc;
4927 char tmp[20], freq[20] = "", savestr[20] = "";
4928 char mhz[MAXREMSTR], decimals[MAXREMSTR];
4929 struct ast_channel *mychannel;
4931 if((!param) || (command_source == SOURCE_RPT) || (command_source == SOURCE_LNK))
4932 return DC_ERROR;
4934 multimode = multimode_capable(myrpt);
4936 mychannel = myrpt->remchannel;
4939 switch(myatoi(param)){
4941 case 1: /* retrieve memory */
4942 if(strlen(digitbuf) < 2) /* needs 2 digits */
4943 break;
4945 for(i = 0 ; i < 2 ; i++){
4946 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
4947 return DC_ERROR;
4950 val = ast_variable_retrieve(myrpt->cfg, myrpt->p.memory, digitbuf);
4951 if (!val){
4952 if (ast_safe_sleep(mychannel,1000) == -1)
4953 return DC_ERROR;
4954 sayfile(mychannel,"rpt/memory_notfound");
4955 return DC_COMPLETE;
4957 ast_copy_string(tmp, val, sizeof(tmp));
4958 s = strchr(tmp,',');
4959 if (!s)
4960 return DC_ERROR;
4961 *s++ = 0;
4962 s1 = strchr(s,',');
4963 if (!s1)
4964 return DC_ERROR;
4965 *s1++ = 0;
4966 ast_copy_string(myrpt->freq, tmp, sizeof(myrpt->freq));
4967 ast_copy_string(myrpt->rxpl, s, sizeof(myrpt->rxpl));
4968 ast_copy_string(myrpt->txpl, s, sizeof(myrpt->rxpl));
4969 myrpt->remmode = REM_MODE_FM;
4970 myrpt->offset = REM_SIMPLEX;
4971 myrpt->powerlevel = REM_MEDPWR;
4972 myrpt->txplon = myrpt->rxplon = 0;
4973 while(*s1)
4975 switch(*s1++){
4976 case 'A':
4977 case 'a':
4978 strcpy(myrpt->rxpl, "100.0");
4979 strcpy(myrpt->txpl, "100.0");
4980 myrpt->remmode = REM_MODE_AM;
4981 break;
4983 case 'B':
4984 case 'b':
4985 strcpy(myrpt->rxpl, "100.0");
4986 strcpy(myrpt->txpl, "100.0");
4987 myrpt->remmode = REM_MODE_LSB;
4988 break;
4990 case 'F':
4991 myrpt->remmode = REM_MODE_FM;
4992 break;
4994 case 'L':
4995 case 'l':
4996 myrpt->powerlevel = REM_LOWPWR;
4997 break;
4998 case 'H':
4999 case 'h':
5000 myrpt->powerlevel = REM_HIPWR;
5001 break;
5003 case 'M':
5004 case 'm':
5005 myrpt->powerlevel = REM_MEDPWR;
5006 break;
5008 case '-':
5009 myrpt->offset = REM_MINUS;
5010 break;
5012 case '+':
5013 myrpt->offset = REM_PLUS;
5014 break;
5016 case 'S':
5017 case 's':
5018 myrpt->offset = REM_SIMPLEX;
5019 break;
5021 case 'T':
5022 case 't':
5023 myrpt->txplon = 1;
5024 break;
5026 case 'R':
5027 case 'r':
5028 myrpt->rxplon = 1;
5029 break;
5031 case 'U':
5032 case 'u':
5033 strcpy(myrpt->rxpl, "100.0");
5034 strcpy(myrpt->txpl, "100.0");
5035 myrpt->remmode = REM_MODE_USB;
5036 break;
5041 if (setrem(myrpt) == -1)
5042 return DC_ERROR;
5045 return DC_COMPLETE;
5047 case 2: /* set freq and offset */
5050 for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for M+*K+*O or M+*H+* depending on mode */
5051 if(digitbuf[i] == '*'){
5052 j++;
5053 continue;
5055 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
5056 goto invalid_freq;
5057 else{
5058 if(j == 0)
5059 l++; /* # of digits before first * */
5060 if(j == 1)
5061 k++; /* # of digits after first * */
5065 i = strlen(digitbuf) - 1;
5066 if(multimode){
5067 if((j > 2) || (l > 3) || (k > 6))
5068 goto invalid_freq; /* &^@#! */
5070 else{
5071 if((j > 2) || (l > 4) || (k > 3))
5072 goto invalid_freq; /* &^@#! */
5075 /* Wait for M+*K+* */
5077 if(j < 2)
5078 break; /* Not yet */
5080 /* We have a frequency */
5082 ast_copy_string(tmp, digitbuf ,sizeof(tmp));
5084 s = tmp;
5085 s1 = strsep(&s, "*"); /* Pick off MHz */
5086 s2 = strsep(&s,"*"); /* Pick off KHz and Hz */
5087 ls2 = strlen(s2);
5089 switch(ls2){ /* Allow partial entry of khz and hz digits for laziness support */
5090 case 1:
5091 ht = 0;
5092 k = 100 * atoi(s2);
5093 break;
5095 case 2:
5096 ht = 0;
5097 k = 10 * atoi(s2);
5098 break;
5100 case 3:
5101 if(!multimode){
5102 if((s2[2] != '0')&&(s2[2] != '5'))
5103 goto invalid_freq;
5105 ht = 0;
5106 k = atoi(s2);
5107 break;
5108 case 4:
5109 k = atoi(s2)/10;
5110 ht = 10 * (atoi(s2+(ls2-1)));
5111 break;
5113 case 5:
5114 k = atoi(s2)/100;
5115 ht = (atoi(s2+(ls2-2)));
5116 break;
5118 default:
5119 goto invalid_freq;
5122 /* Check frequency for validity and establish a default mode */
5124 snprintf(freq, sizeof(freq), "%s.%03d%02d",s1, k, ht);
5126 if(debug)
5127 printf("New frequency: %s\n", freq);
5129 split_freq(mhz, decimals, freq);
5130 m = atoi(mhz);
5131 d = atoi(decimals);
5133 if(check_freq(myrpt, m, d, &defmode)) /* Check to see if frequency entered is legit */
5134 goto invalid_freq;
5137 if((defmode == REM_MODE_FM) && (digitbuf[i] == '*')) /* If FM, user must enter and additional offset digit */
5138 break; /* Not yet */
5141 offset = REM_SIMPLEX; /* Assume simplex */
5143 if(defmode == REM_MODE_FM){
5144 oc = *s; /* Pick off offset */
5146 if (oc){
5147 switch(oc){
5148 case '1':
5149 offset = REM_MINUS;
5150 break;
5152 case '2':
5153 offset = REM_SIMPLEX;
5154 break;
5156 case '3':
5157 offset = REM_PLUS;
5158 break;
5160 default:
5161 goto invalid_freq;
5165 offsave = myrpt->offset;
5166 modesave = myrpt->remmode;
5167 ast_copy_string(savestr, myrpt->freq, sizeof(savestr));
5168 ast_copy_string(myrpt->freq, freq, sizeof(myrpt->freq));
5169 myrpt->offset = offset;
5170 myrpt->remmode = defmode;
5172 if (setrem(myrpt) == -1){
5173 myrpt->offset = offsave;
5174 myrpt->remmode = modesave;
5175 ast_copy_string(myrpt->freq, savestr, sizeof(myrpt->freq));
5176 goto invalid_freq;
5179 return DC_COMPLETE;
5182 invalid_freq:
5184 rmt_sayfile(myrpt, mychannel, 1000, "rpt/invalid-freq");
5186 return DC_ERROR;
5188 case 3: /* set rx PL tone */
5190 for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
5191 if(digitbuf[i] == '*'){
5192 j++;
5193 continue;
5195 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
5196 return DC_ERROR;
5197 else{
5198 if(j)
5199 l++;
5200 else
5201 k++;
5204 if((j > 1) || (k > 3) || (l > 1))
5205 return DC_ERROR; /* &$@^! */
5206 i = strlen(digitbuf) - 1;
5207 if((j != 1) || (k < 2)|| (l != 1))
5208 break; /* Not yet */
5209 if(debug)
5210 printf("PL digits entered %s\n", digitbuf);
5212 ast_copy_string(tmp, digitbuf, sizeof(tmp));
5213 /* see if we have at least 1 */
5214 s = strchr(tmp,'*');
5215 if(s)
5216 *s = '.';
5217 ast_copy_string(savestr, myrpt->rxpl, sizeof(savestr));
5218 ast_copy_string(myrpt->rxpl, tmp, sizeof(myrpt->rxpl));
5220 if (setrem(myrpt) == -1){
5221 ast_copy_string(myrpt->rxpl, savestr, sizeof(myrpt->rxpl));
5222 return DC_ERROR;
5226 return DC_COMPLETE;
5228 case 4: /* set tx PL tone */
5230 for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
5231 if(digitbuf[i] == '*'){
5232 j++;
5233 continue;
5235 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
5236 return DC_ERROR;
5237 else{
5238 if(j)
5239 l++;
5240 else
5241 k++;
5244 if((j > 1) || (k > 3) || (l > 1))
5245 return DC_ERROR; /* &$@^! */
5246 i = strlen(digitbuf) - 1;
5247 if((j != 1) || (k < 2)|| (l != 1))
5248 break; /* Not yet */
5249 if(debug)
5250 printf("PL digits entered %s\n", digitbuf);
5252 ast_copy_string(tmp, digitbuf, sizeof(tmp));
5253 /* see if we have at least 1 */
5254 s = strchr(tmp,'*');
5255 if(s)
5256 *s = '.';
5257 ast_copy_string(savestr, myrpt->txpl, sizeof(savestr));
5258 ast_copy_string(myrpt->txpl, tmp, sizeof(myrpt->txpl));
5260 if (setrem(myrpt) == -1){
5261 ast_copy_string(myrpt->txpl, savestr, sizeof(myrpt->txpl) - 1);
5262 return DC_ERROR;
5266 return DC_COMPLETE;
5269 case 6: /* MODE (FM,USB,LSB,AM) */
5270 if(strlen(digitbuf) < 1)
5271 break;
5273 if(!multimode)
5274 return DC_ERROR; /* Multimode radios only */
5276 switch(*digitbuf){
5277 case '1':
5278 split_freq(mhz, decimals, myrpt->freq);
5279 m=atoi(mhz);
5280 if(m < 29) /* No FM allowed below 29MHz! */
5281 return DC_ERROR;
5282 myrpt->remmode = REM_MODE_FM;
5283 res = rmt_saycharstr(myrpt, mychannel, 1000,"FM");
5284 break;
5286 case '2':
5287 myrpt->remmode = REM_MODE_USB;
5288 res = rmt_saycharstr(myrpt, mychannel, 1000,"USB");
5289 break;
5291 case '3':
5292 myrpt->remmode = REM_MODE_LSB;
5293 res = rmt_saycharstr(myrpt, mychannel, 1000,"LSB");
5294 break;
5296 case '4':
5297 myrpt->remmode = REM_MODE_AM;
5298 res = rmt_saycharstr(myrpt, mychannel, 1000,"AM");
5299 break;
5301 default:
5302 return DC_ERROR;
5304 if(res)
5305 return DC_ERROR;
5307 if(setrem(myrpt))
5308 return DC_ERROR;
5309 return DC_COMPLETE;
5311 case 100: /* other stuff */
5312 case 101:
5313 case 102:
5314 case 103:
5315 case 104:
5316 case 105:
5317 case 106:
5318 res = rmt_telem_start(myrpt, mychannel, 1000);
5319 switch(myatoi(param)){ /* Quick commands requiring a setrem call */
5320 case 100: /* RX PL Off */
5321 myrpt->rxplon = 0;
5322 if(!res)
5323 res = sayfile(mychannel, "rpt/rxpl");
5324 if(!res)
5325 sayfile(mychannel, "rpt/off");
5326 break;
5328 case 101: /* RX PL On */
5329 myrpt->rxplon = 1;
5330 if(!res)
5331 res = sayfile(mychannel, "rpt/rxpl");
5332 if(!res)
5333 sayfile(mychannel, "rpt/on");
5334 break;
5337 case 102: /* TX PL Off */
5338 myrpt->txplon = 0;
5339 if(!res)
5340 res = sayfile(mychannel, "rpt/txpl");
5341 if(!res)
5342 sayfile(mychannel, "rpt/off");
5343 break;
5345 case 103: /* TX PL On */
5346 myrpt->txplon = 1;
5347 if(!res)
5348 res = sayfile(mychannel, "rpt/txpl");
5349 if(!res)
5350 sayfile(mychannel, "rpt/on");
5351 break;
5353 case 104: /* Low Power */
5354 myrpt->powerlevel = REM_LOWPWR;
5355 if(!res)
5356 res = sayfile(mychannel, "rpt/lopwr");
5357 break;
5359 case 105: /* Medium Power */
5360 myrpt->powerlevel = REM_MEDPWR;
5361 if(!res)
5362 res = sayfile(mychannel, "rpt/medpwr");
5363 break;
5365 case 106: /* Hi Power */
5366 myrpt->powerlevel = REM_HIPWR;
5367 if(!res)
5368 res = sayfile(mychannel, "rpt/hipwr");
5369 break;
5371 default:
5372 if(!res)
5373 rmt_telem_finish(myrpt, mychannel);
5374 return DC_ERROR;
5376 if(!res)
5377 res = rmt_telem_finish(myrpt, mychannel);
5378 if(res)
5379 return DC_ERROR;
5381 if (setrem(myrpt) == -1)
5382 return DC_ERROR;
5383 return DC_COMPLETE;
5385 case 107: /* Bump down 20Hz */
5386 multimode_bump_freq(myrpt, -20);
5387 return DC_COMPLETE;
5389 case 108: /* Bump down 100Hz */
5390 multimode_bump_freq(myrpt, -100);
5391 return DC_COMPLETE;
5393 case 109: /* Bump down 500Hz */
5394 multimode_bump_freq(myrpt, -500);
5395 return DC_COMPLETE;
5397 case 110: /* Bump up 20Hz */
5398 multimode_bump_freq(myrpt, 20);
5399 return DC_COMPLETE;
5401 case 111: /* Bump up 100Hz */
5402 multimode_bump_freq(myrpt, 100);
5403 return DC_COMPLETE;
5405 case 112: /* Bump up 500Hz */
5406 multimode_bump_freq(myrpt, 500);
5407 return DC_COMPLETE;
5410 case 113:
5411 case 114:
5412 case 115:
5413 case 116:
5414 case 117:
5415 case 118:
5416 myrpt->remotetx = 0;
5417 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
5418 if (!myrpt->remoterx)
5419 ast_indicate(mychannel,AST_CONTROL_RADIO_KEY);
5420 if (ast_safe_sleep(mychannel,1000) == -1)
5421 return DC_ERROR;
5423 switch(myatoi(param)){
5425 case 113: /* Scan down slow */
5426 res = sayfile(mychannel,"rpt/down");
5427 if(!res)
5428 res = sayfile(mychannel, "rpt/slow");
5429 if(!res){
5430 myrpt->scantimer = REM_SCANTIME;
5431 myrpt->hfscanmode = HF_SCAN_DOWN_SLOW;
5433 break;
5435 case 114: /* Scan down quick */
5436 res = sayfile(mychannel,"rpt/down");
5437 if(!res)
5438 res = sayfile(mychannel, "rpt/quick");
5439 if(!res){
5440 myrpt->scantimer = REM_SCANTIME;
5441 myrpt->hfscanmode = HF_SCAN_DOWN_QUICK;
5443 break;
5445 case 115: /* Scan down fast */
5446 res = sayfile(mychannel,"rpt/down");
5447 if(!res)
5448 res = sayfile(mychannel, "rpt/fast");
5449 if(!res){
5450 myrpt->scantimer = REM_SCANTIME;
5451 myrpt->hfscanmode = HF_SCAN_DOWN_FAST;
5453 break;
5455 case 116: /* Scan up slow */
5456 res = sayfile(mychannel,"rpt/up");
5457 if(!res)
5458 res = sayfile(mychannel, "rpt/slow");
5459 if(!res){
5460 myrpt->scantimer = REM_SCANTIME;
5461 myrpt->hfscanmode = HF_SCAN_UP_SLOW;
5463 break;
5465 case 117: /* Scan up quick */
5466 res = sayfile(mychannel,"rpt/up");
5467 if(!res)
5468 res = sayfile(mychannel, "rpt/quick");
5469 if(!res){
5470 myrpt->scantimer = REM_SCANTIME;
5471 myrpt->hfscanmode = HF_SCAN_UP_QUICK;
5473 break;
5475 case 118: /* Scan up fast */
5476 res = sayfile(mychannel,"rpt/up");
5477 if(!res)
5478 res = sayfile(mychannel, "rpt/fast");
5479 if(!res){
5480 myrpt->scantimer = REM_SCANTIME;
5481 myrpt->hfscanmode = HF_SCAN_UP_FAST;
5483 break;
5485 rmt_telem_finish(myrpt,mychannel);
5486 return DC_COMPLETE;
5489 case 119: /* Tune Request */
5490 myrpt->tunerequest = 1;
5491 return DC_COMPLETE;
5493 case 5: /* Long Status */
5494 case 140: /* Short Status */
5495 res = rmt_telem_start(myrpt, mychannel, 1000);
5497 res = sayfile(mychannel,"rpt/node");
5498 if(!res)
5499 res = saycharstr(mychannel, myrpt->name);
5500 if(!res)
5501 res = sayfile(mychannel,"rpt/frequency");
5502 if(!res)
5503 res = split_freq(mhz, decimals, myrpt->freq);
5504 if(!res){
5505 m = atoi(mhz);
5506 if(m < 100)
5507 res = saynum(mychannel, m);
5508 else
5509 res = saycharstr(mychannel, mhz);
5511 if(!res)
5512 res = sayfile(mychannel, "letters/dot");
5513 if(!res)
5514 res = saycharstr(mychannel, decimals);
5516 if(res){
5517 rmt_telem_finish(myrpt,mychannel);
5518 return DC_ERROR;
5520 if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */
5521 switch(myrpt->offset){
5523 case REM_MINUS:
5524 res = sayfile(mychannel,"rpt/minus");
5525 break;
5527 case REM_SIMPLEX:
5528 res = sayfile(mychannel,"rpt/simplex");
5529 break;
5531 case REM_PLUS:
5532 res = sayfile(mychannel,"rpt/plus");
5533 break;
5535 default:
5536 return DC_ERROR;
5540 else{ /* Must be USB, LSB, or AM */
5541 switch(myrpt->remmode){
5543 case REM_MODE_USB:
5544 res = saycharstr(mychannel, "USB");
5545 break;
5547 case REM_MODE_LSB:
5548 res = saycharstr(mychannel, "LSB");
5549 break;
5551 case REM_MODE_AM:
5552 res = saycharstr(mychannel, "AM");
5553 break;
5556 default:
5557 return DC_ERROR;
5561 if (res == -1){
5562 rmt_telem_finish(myrpt,mychannel);
5563 return DC_ERROR;
5566 if(myatoi(param) == 140){ /* Short status? */
5567 if(!res)
5568 res = rmt_telem_finish(myrpt, mychannel);
5569 if(res)
5570 return DC_ERROR;
5571 return DC_COMPLETE;
5574 switch(myrpt->powerlevel){
5576 case REM_LOWPWR:
5577 res = sayfile(mychannel,"rpt/lopwr") ;
5578 break;
5580 case REM_MEDPWR:
5581 res = sayfile(mychannel,"rpt/medpwr");
5582 break;
5583 case REM_HIPWR:
5584 res = sayfile(mychannel,"rpt/hipwr");
5585 break;
5587 if (res || (sayfile(mychannel,"rpt/rxpl") == -1) ||
5588 (sayfile(mychannel,"rpt/frequency") == -1) ||
5589 (saycharstr(mychannel,myrpt->rxpl) == -1) ||
5590 (sayfile(mychannel,"rpt/txpl") == -1) ||
5591 (sayfile(mychannel,"rpt/frequency") == -1) ||
5592 (saycharstr(mychannel,myrpt->txpl) == -1) ||
5593 (sayfile(mychannel,"rpt/txpl") == -1) ||
5594 (sayfile(mychannel,((myrpt->txplon) ? "rpt/on" : "rpt/off")) == -1) ||
5595 (sayfile(mychannel,"rpt/rxpl") == -1) ||
5596 (sayfile(mychannel,((myrpt->rxplon) ? "rpt/on" : "rpt/off")) == -1))
5598 rmt_telem_finish(myrpt,mychannel);
5599 return DC_ERROR;
5601 if(!res)
5602 res = rmt_telem_finish(myrpt,mychannel);
5603 if(res)
5604 return DC_ERROR;
5606 return DC_COMPLETE;
5607 default:
5608 return DC_ERROR;
5611 return DC_INDETERMINATE;
5614 static int handle_remote_dtmf_digit(struct rpt *myrpt,char c, char *keyed, int phonemode)
5616 time_t now;
5617 int ret,res = 0,src;
5619 /* Stop scan mode if in scan mode */
5620 if(myrpt->hfscanmode){
5621 stop_scan(myrpt,0);
5622 return 0;
5625 time(&now);
5626 /* if timed-out */
5627 if ((myrpt->dtmf_time_rem + DTMF_TIMEOUT) < now)
5629 myrpt->dtmfidx = -1;
5630 myrpt->dtmfbuf[0] = 0;
5631 myrpt->dtmf_time_rem = 0;
5633 /* if decode not active */
5634 if (myrpt->dtmfidx == -1)
5636 /* if not lead-in digit, dont worry */
5637 if (c != myrpt->p.funcchar) return 0;
5638 myrpt->dtmfidx = 0;
5639 myrpt->dtmfbuf[0] = 0;
5640 myrpt->dtmf_time_rem = now;
5641 return 0;
5643 /* if too many in buffer, start over */
5644 if (myrpt->dtmfidx >= MAXDTMF)
5646 myrpt->dtmfidx = 0;
5647 myrpt->dtmfbuf[0] = 0;
5648 myrpt->dtmf_time_rem = now;
5650 if (c == myrpt->p.funcchar)
5652 /* if star at beginning, or 2 together, erase buffer */
5653 if ((myrpt->dtmfidx < 1) ||
5654 (myrpt->dtmfbuf[myrpt->dtmfidx - 1] == myrpt->p.funcchar))
5656 myrpt->dtmfidx = 0;
5657 myrpt->dtmfbuf[0] = 0;
5658 myrpt->dtmf_time_rem = now;
5659 return 0;
5662 myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
5663 myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
5664 myrpt->dtmf_time_rem = now;
5667 src = SOURCE_RMT;
5668 if (phonemode > 1) src = SOURCE_DPHONE;
5669 else if (phonemode) src = SOURCE_PHONE;
5670 ret = collect_function_digits(myrpt, myrpt->dtmfbuf, src, NULL);
5672 switch(ret){
5674 case DC_INDETERMINATE:
5675 res = 0;
5676 break;
5678 case DC_DOKEY:
5679 if (keyed) *keyed = 1;
5680 res = 0;
5681 break;
5683 case DC_REQ_FLUSH:
5684 myrpt->dtmfidx = 0;
5685 myrpt->dtmfbuf[0] = 0;
5686 res = 0;
5687 break;
5690 case DC_COMPLETE:
5691 myrpt->totalexecdcommands++;
5692 myrpt->dailyexecdcommands++;
5693 ast_copy_string(myrpt->lastdtmfcommand, myrpt->dtmfbuf, MAXDTMF);
5694 myrpt->dtmfbuf[0] = 0;
5695 myrpt->dtmfidx = -1;
5696 myrpt->dtmf_time_rem = 0;
5697 res = 1;
5698 break;
5700 case DC_ERROR:
5701 default:
5702 myrpt->dtmfbuf[0] = 0;
5703 myrpt->dtmfidx = -1;
5704 myrpt->dtmf_time_rem = 0;
5705 res = 0;
5706 break;
5709 return res;
5712 static int handle_remote_data(struct rpt *myrpt, char *str)
5714 char tmp[300],cmd[300],dest[300],src[300],c;
5715 int seq,res;
5717 /* put string in our buffer */
5718 ast_copy_string(tmp,str,sizeof(tmp));
5719 if (!strcmp(tmp,discstr)) return 0;
5720 if (sscanf(tmp,"%s %s %s %d %c",cmd,dest,src,&seq,&c) != 5)
5722 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
5723 return 0;
5725 if (strcmp(cmd,"D"))
5727 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
5728 return 0;
5730 /* if not for me, ignore */
5731 if (strcmp(dest,myrpt->name)) return 0;
5732 res = handle_remote_dtmf_digit(myrpt,c, NULL, 0);
5733 if (res != 1)
5734 return res;
5735 myrpt->remotetx = 0;
5736 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
5737 if (!myrpt->remoterx)
5739 ast_indicate(myrpt->remchannel,AST_CONTROL_RADIO_KEY);
5741 if (ast_safe_sleep(myrpt->remchannel,1000) == -1) return -1;
5742 res = telem_lookup(myrpt,myrpt->remchannel, myrpt->name, "functcomplete");
5743 rmt_telem_finish(myrpt,myrpt->remchannel);
5744 return res;
5747 static int handle_remote_phone_dtmf(struct rpt *myrpt, char c, char *keyed, int phonemode)
5749 int res;
5752 if (keyed && *keyed && (c == myrpt->p.endchar))
5754 *keyed = 0;
5755 return DC_INDETERMINATE;
5758 res = handle_remote_dtmf_digit(myrpt,c,keyed, phonemode);
5759 if (res != 1)
5760 return res;
5761 myrpt->remotetx = 0;
5762 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
5763 if (!myrpt->remoterx)
5765 ast_indicate(myrpt->remchannel,AST_CONTROL_RADIO_KEY);
5767 if (ast_safe_sleep(myrpt->remchannel,1000) == -1) return -1;
5768 res = telem_lookup(myrpt,myrpt->remchannel, myrpt->name, "functcomplete");
5769 rmt_telem_finish(myrpt,myrpt->remchannel);
5770 return res;
5773 static int attempt_reconnect(struct rpt *myrpt, struct rpt_link *l)
5775 const char *val;
5776 char *s, *s1, *s2, *tele;
5777 char tmp[300], deststr[300] = "";
5779 val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, l->name);
5780 if (!val)
5782 fprintf(stderr,"attempt_reconnect: cannot find node %s\n",l->name);
5783 return -1;
5786 rpt_mutex_lock(&myrpt->lock);
5787 /* remove from queue */
5788 remque((struct qelem *) l);
5789 rpt_mutex_unlock(&myrpt->lock);
5790 ast_copy_string(tmp,val,sizeof(tmp));
5791 s = tmp;
5792 s1 = strsep(&s,",");
5793 s2 = strsep(&s,",");
5794 snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
5795 tele = strchr(deststr, '/');
5796 if (!tele) {
5797 fprintf(stderr,"attempt_reconnect:Dial number (%s) must be in format tech/number\n",deststr);
5798 return -1;
5800 *tele++ = 0;
5801 l->elaptime = 0;
5802 l->connecttime = 0;
5803 l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL);
5804 if (l->chan){
5805 ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
5806 ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
5807 l->chan->whentohangup = 0;
5808 l->chan->appl = "Apprpt";
5809 l->chan->data = "(Remote Rx)";
5810 if (option_verbose > 2)
5811 ast_verbose(VERBOSE_PREFIX_3 "rpt (attempt_reconnect) initiating call to %s/%s on %s\n",
5812 deststr, tele, l->chan->name);
5813 if(l->chan->cid.cid_num)
5814 free(l->chan->cid.cid_num);
5815 l->chan->cid.cid_num = strdup(myrpt->name);
5816 ast_call(l->chan,tele,999);
5819 else
5821 if (option_verbose > 2)
5822 ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
5823 deststr,tele,l->chan->name);
5824 return -1;
5826 rpt_mutex_lock(&myrpt->lock);
5827 /* put back in queue */
5828 insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
5829 rpt_mutex_unlock(&myrpt->lock);
5830 ast_log(LOG_NOTICE,"Reconnect Attempt to %s in process\n",l->name);
5831 return 0;
5834 /* 0 return=continue, 1 return = break, -1 return = error */
5835 static void local_dtmf_helper(struct rpt *myrpt,char c)
5837 int res;
5838 pthread_attr_t attr;
5839 char cmd[MAXDTMF+1] = "";
5841 if (c == myrpt->p.endchar)
5843 /* if in simple mode, kill autopatch */
5844 if (myrpt->p.simple && myrpt->callmode)
5846 rpt_mutex_lock(&myrpt->lock);
5847 myrpt->callmode = 0;
5848 rpt_mutex_unlock(&myrpt->lock);
5849 rpt_telemetry(myrpt,TERM,NULL);
5850 return;
5852 rpt_mutex_lock(&myrpt->lock);
5853 myrpt->stopgen = 1;
5854 if (myrpt->cmdnode[0])
5856 myrpt->cmdnode[0] = 0;
5857 myrpt->dtmfidx = -1;
5858 myrpt->dtmfbuf[0] = 0;
5859 rpt_mutex_unlock(&myrpt->lock);
5860 rpt_telemetry(myrpt,COMPLETE,NULL);
5861 } else rpt_mutex_unlock(&myrpt->lock);
5862 return;
5864 rpt_mutex_lock(&myrpt->lock);
5865 if (myrpt->cmdnode[0])
5867 rpt_mutex_unlock(&myrpt->lock);
5868 send_link_dtmf(myrpt,c);
5869 return;
5871 if (!myrpt->p.simple)
5873 if (c == myrpt->p.funcchar)
5875 myrpt->dtmfidx = 0;
5876 myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
5877 rpt_mutex_unlock(&myrpt->lock);
5878 time(&myrpt->dtmf_time);
5879 return;
5881 else if ((c != myrpt->p.endchar) && (myrpt->dtmfidx >= 0))
5883 time(&myrpt->dtmf_time);
5885 if (myrpt->dtmfidx < MAXDTMF)
5887 myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
5888 myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
5890 ast_copy_string(cmd, myrpt->dtmfbuf, sizeof(cmd));
5892 rpt_mutex_unlock(&myrpt->lock);
5893 res = collect_function_digits(myrpt, cmd, SOURCE_RPT, NULL);
5894 rpt_mutex_lock(&myrpt->lock);
5895 switch(res){
5896 case DC_INDETERMINATE:
5897 break;
5898 case DC_REQ_FLUSH:
5899 myrpt->dtmfidx = 0;
5900 myrpt->dtmfbuf[0] = 0;
5901 break;
5902 case DC_COMPLETE:
5903 myrpt->totalexecdcommands++;
5904 myrpt->dailyexecdcommands++;
5905 ast_copy_string(myrpt->lastdtmfcommand, cmd, MAXDTMF);
5906 myrpt->dtmfbuf[0] = 0;
5907 myrpt->dtmfidx = -1;
5908 myrpt->dtmf_time = 0;
5909 break;
5911 case DC_ERROR:
5912 default:
5913 myrpt->dtmfbuf[0] = 0;
5914 myrpt->dtmfidx = -1;
5915 myrpt->dtmf_time = 0;
5916 break;
5918 if(res != DC_INDETERMINATE) {
5919 rpt_mutex_unlock(&myrpt->lock);
5920 return;
5925 else /* if simple */
5927 if ((!myrpt->callmode) && (c == myrpt->p.funcchar))
5929 myrpt->callmode = 1;
5930 myrpt->patchnoct = 0;
5931 myrpt->patchquiet = 0;
5932 myrpt->patchfarenddisconnect = 0;
5933 myrpt->patchdialtime = 0;
5934 ast_copy_string(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
5935 myrpt->cidx = 0;
5936 myrpt->exten[myrpt->cidx] = 0;
5937 rpt_mutex_unlock(&myrpt->lock);
5938 pthread_attr_init(&attr);
5939 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
5940 ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *)myrpt);
5941 pthread_attr_destroy(&attr);
5942 return;
5945 if (myrpt->callmode == 1)
5947 myrpt->exten[myrpt->cidx++] = c;
5948 myrpt->exten[myrpt->cidx] = 0;
5949 /* if this exists */
5950 if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
5952 myrpt->callmode = 2;
5953 rpt_mutex_unlock(&myrpt->lock);
5954 if(!myrpt->patchquiet)
5955 rpt_telemetry(myrpt,PROC,NULL);
5956 return;
5958 /* if can continue, do so */
5959 if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
5961 /* call has failed, inform user */
5962 myrpt->callmode = 4;
5964 rpt_mutex_unlock(&myrpt->lock);
5965 return;
5967 if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
5969 myrpt->mydtmf = c;
5971 rpt_mutex_unlock(&myrpt->lock);
5972 return;
5976 /* place an ID event in the telemetry queue */
5978 static void queue_id(struct rpt *myrpt)
5980 myrpt->mustid = myrpt->tailid = 0;
5981 myrpt->idtimer = myrpt->p.idtime; /* Reset our ID timer */
5982 rpt_mutex_unlock(&myrpt->lock);
5983 rpt_telemetry(myrpt,ID,NULL);
5984 rpt_mutex_lock(&myrpt->lock);
5987 /* Scheduler */
5989 static void do_scheduler(struct rpt *myrpt)
5991 int res;
5992 struct tm tmnow;
5994 memcpy(&myrpt->lasttv, &myrpt->curtv, sizeof(struct timeval));
5996 if( (res = gettimeofday(&myrpt->curtv, NULL)) < 0)
5997 ast_log(LOG_NOTICE, "Scheduler gettime of day returned: %s\n", strerror(res));
5999 /* Try to get close to a 1 second resolution */
6001 if(myrpt->lasttv.tv_sec == myrpt->curtv.tv_sec)
6002 return;
6004 ast_localtime(&myrpt->curtv.tv_sec, &tmnow, NULL);
6006 /* If midnight, then reset all daily statistics */
6008 if((tmnow.tm_hour == 0)&&(tmnow.tm_min == 0)&&(tmnow.tm_sec == 0)){
6009 myrpt->dailykeyups = 0;
6010 myrpt->dailytxtime = 0;
6011 myrpt->dailykerchunks = 0;
6012 myrpt->dailyexecdcommands = 0;
6017 /* single thread with one file (request) to dial */
6018 static void *rpt(void *this)
6020 struct rpt *myrpt = (struct rpt *)this;
6021 char *tele, c;
6022 const char *idtalkover;
6023 int ms = MSWAIT,i,lasttx=0,val,remrx=0,identqueued,othertelemqueued,tailmessagequeued,ctqueued;
6024 struct ast_channel *who;
6025 ZT_CONFINFO ci; /* conference info */
6026 time_t t;
6027 struct rpt_link *l,*m;
6028 struct rpt_tele *telem;
6029 char tmpstr[300];
6031 rpt_mutex_lock(&myrpt->lock);
6033 telem = myrpt->tele.next;
6034 while(telem != &myrpt->tele)
6036 ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
6037 telem = telem->next;
6039 rpt_mutex_unlock(&myrpt->lock);
6040 /* find our index, and load the vars initially */
6041 for(i = 0; i < nrpts; i++)
6043 if (&rpt_vars[i] == myrpt)
6045 load_rpt_vars(i,0);
6046 break;
6049 rpt_mutex_lock(&myrpt->lock);
6050 ast_copy_string(tmpstr,myrpt->rxchanname,sizeof(tmpstr));
6051 tele = strchr(tmpstr,'/');
6052 if (!tele)
6054 fprintf(stderr,"rpt:Rxchannel Dial number (%s) must be in format tech/number\n",myrpt->rxchanname);
6055 rpt_mutex_unlock(&myrpt->lock);
6056 myrpt->rpt_thread = AST_PTHREADT_STOP;
6057 pthread_exit(NULL);
6059 *tele++ = 0;
6060 myrpt->rxchannel = ast_request(tmpstr,AST_FORMAT_SLINEAR,tele,NULL);
6061 if (myrpt->rxchannel)
6063 if (myrpt->rxchannel->_state == AST_STATE_BUSY)
6065 fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
6066 rpt_mutex_unlock(&myrpt->lock);
6067 ast_hangup(myrpt->rxchannel);
6068 myrpt->rpt_thread = AST_PTHREADT_STOP;
6069 pthread_exit(NULL);
6071 ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
6072 ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
6073 myrpt->rxchannel->whentohangup = 0;
6074 myrpt->rxchannel->appl = "Apprpt";
6075 myrpt->rxchannel->data = "(Repeater Rx)";
6076 if (option_verbose > 2)
6077 ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
6078 tmpstr,tele,myrpt->rxchannel->name);
6079 ast_call(myrpt->rxchannel,tele,999);
6080 if (myrpt->rxchannel->_state != AST_STATE_UP)
6082 rpt_mutex_unlock(&myrpt->lock);
6083 ast_hangup(myrpt->rxchannel);
6084 myrpt->rpt_thread = AST_PTHREADT_STOP;
6085 pthread_exit(NULL);
6088 else
6090 fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
6091 rpt_mutex_unlock(&myrpt->lock);
6092 myrpt->rpt_thread = AST_PTHREADT_STOP;
6093 pthread_exit(NULL);
6095 if (myrpt->txchanname)
6097 ast_copy_string(tmpstr,myrpt->txchanname,sizeof(tmpstr));
6098 tele = strchr(tmpstr,'/');
6099 if (!tele)
6101 fprintf(stderr,"rpt:Txchannel Dial number (%s) must be in format tech/number\n",myrpt->txchanname);
6102 rpt_mutex_unlock(&myrpt->lock);
6103 ast_hangup(myrpt->rxchannel);
6104 myrpt->rpt_thread = AST_PTHREADT_STOP;
6105 pthread_exit(NULL);
6107 *tele++ = 0;
6108 myrpt->txchannel = ast_request(tmpstr,AST_FORMAT_SLINEAR,tele,NULL);
6109 if (myrpt->txchannel)
6111 if (myrpt->txchannel->_state == AST_STATE_BUSY)
6113 fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
6114 rpt_mutex_unlock(&myrpt->lock);
6115 ast_hangup(myrpt->txchannel);
6116 ast_hangup(myrpt->rxchannel);
6117 myrpt->rpt_thread = AST_PTHREADT_STOP;
6118 pthread_exit(NULL);
6120 ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
6121 ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
6122 myrpt->txchannel->whentohangup = 0;
6123 myrpt->txchannel->appl = "Apprpt";
6124 myrpt->txchannel->data = "(Repeater Tx)";
6125 if (option_verbose > 2)
6126 ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
6127 tmpstr,tele,myrpt->txchannel->name);
6128 ast_call(myrpt->txchannel,tele,999);
6129 if (myrpt->rxchannel->_state != AST_STATE_UP)
6131 rpt_mutex_unlock(&myrpt->lock);
6132 ast_hangup(myrpt->rxchannel);
6133 ast_hangup(myrpt->txchannel);
6134 myrpt->rpt_thread = AST_PTHREADT_STOP;
6135 pthread_exit(NULL);
6138 else
6140 fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
6141 rpt_mutex_unlock(&myrpt->lock);
6142 ast_hangup(myrpt->rxchannel);
6143 myrpt->rpt_thread = AST_PTHREADT_STOP;
6144 pthread_exit(NULL);
6147 else
6149 myrpt->txchannel = myrpt->rxchannel;
6151 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
6152 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
6153 /* allocate a pseudo-channel thru asterisk */
6154 myrpt->pchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
6155 if (!myrpt->pchannel)
6157 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
6158 rpt_mutex_unlock(&myrpt->lock);
6159 if (myrpt->txchannel != myrpt->rxchannel)
6160 ast_hangup(myrpt->txchannel);
6161 ast_hangup(myrpt->rxchannel);
6162 myrpt->rpt_thread = AST_PTHREADT_STOP;
6163 pthread_exit(NULL);
6165 /* make a conference for the tx */
6166 ci.chan = 0;
6167 ci.confno = -1; /* make a new conf */
6168 ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER;
6169 /* first put the channel on the conference in proper mode */
6170 if (ioctl(myrpt->txchannel->fds[0],ZT_SETCONF,&ci) == -1)
6172 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
6173 rpt_mutex_unlock(&myrpt->lock);
6174 ast_hangup(myrpt->pchannel);
6175 if (myrpt->txchannel != myrpt->rxchannel)
6176 ast_hangup(myrpt->txchannel);
6177 ast_hangup(myrpt->rxchannel);
6178 myrpt->rpt_thread = AST_PTHREADT_STOP;
6179 pthread_exit(NULL);
6181 /* save tx conference number */
6182 myrpt->txconf = ci.confno;
6183 /* make a conference for the pseudo */
6184 ci.chan = 0;
6185 ci.confno = -1; /* make a new conf */
6186 ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? ZT_CONF_CONFANNMON :
6187 (ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER);
6188 /* first put the channel on the conference in announce mode */
6189 if (ioctl(myrpt->pchannel->fds[0],ZT_SETCONF,&ci) == -1)
6191 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
6192 rpt_mutex_unlock(&myrpt->lock);
6193 ast_hangup(myrpt->pchannel);
6194 if (myrpt->txchannel != myrpt->rxchannel)
6195 ast_hangup(myrpt->txchannel);
6196 ast_hangup(myrpt->rxchannel);
6197 myrpt->rpt_thread = AST_PTHREADT_STOP;
6198 pthread_exit(NULL);
6200 /* save pseudo channel conference number */
6201 myrpt->conf = ci.confno;
6202 /* allocate a pseudo-channel thru asterisk */
6203 myrpt->txpchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
6204 if (!myrpt->txpchannel)
6206 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
6207 rpt_mutex_unlock(&myrpt->lock);
6208 ast_hangup(myrpt->pchannel);
6209 if (myrpt->txchannel != myrpt->rxchannel)
6210 ast_hangup(myrpt->txchannel);
6211 ast_hangup(myrpt->rxchannel);
6212 myrpt->rpt_thread = AST_PTHREADT_STOP;
6213 pthread_exit(NULL);
6215 /* make a conference for the tx */
6216 ci.chan = 0;
6217 ci.confno = myrpt->txconf;
6218 ci.confmode = ZT_CONF_CONF | ZT_CONF_TALKER ;
6219 /* first put the channel on the conference in proper mode */
6220 if (ioctl(myrpt->txpchannel->fds[0],ZT_SETCONF,&ci) == -1)
6222 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
6223 rpt_mutex_unlock(&myrpt->lock);
6224 ast_hangup(myrpt->txpchannel);
6225 ast_hangup(myrpt->pchannel);
6226 if (myrpt->txchannel != myrpt->rxchannel)
6227 ast_hangup(myrpt->txchannel);
6228 ast_hangup(myrpt->rxchannel);
6229 myrpt->rpt_thread = AST_PTHREADT_STOP;
6230 pthread_exit(NULL);
6232 /* Now, the idea here is to copy from the physical rx channel buffer
6233 into the pseudo tx buffer, and from the pseudo rx buffer into the
6234 tx channel buffer */
6235 myrpt->links.next = &myrpt->links;
6236 myrpt->links.prev = &myrpt->links;
6237 myrpt->tailtimer = 0;
6238 myrpt->totimer = 0;
6239 myrpt->tmsgtimer = myrpt->p.tailmessagetime;
6240 myrpt->idtimer = myrpt->p.politeid;
6241 myrpt->mustid = myrpt->tailid = 0;
6242 myrpt->callmode = 0;
6243 myrpt->tounkeyed = 0;
6244 myrpt->tonotify = 0;
6245 myrpt->retxtimer = 0;
6246 myrpt->skedtimer = 0;
6247 myrpt->tailevent = 0;
6248 lasttx = 0;
6249 myrpt->keyed = 0;
6250 idtalkover = ast_variable_retrieve(myrpt->cfg, myrpt->name, "idtalkover");
6251 myrpt->dtmfidx = -1;
6252 myrpt->dtmfbuf[0] = 0;
6253 myrpt->rem_dtmfidx = -1;
6254 myrpt->rem_dtmfbuf[0] = 0;
6255 myrpt->dtmf_time = 0;
6256 myrpt->rem_dtmf_time = 0;
6257 myrpt->enable = 1;
6258 myrpt->disgorgetime = 0;
6259 myrpt->lastnodewhichkeyedusup[0] = '\0';
6260 myrpt->dailytxtime = 0;
6261 myrpt->totaltxtime = 0;
6262 myrpt->dailykeyups = 0;
6263 myrpt->totalkeyups = 0;
6264 myrpt->dailykerchunks = 0;
6265 myrpt->totalkerchunks = 0;
6266 myrpt->dailyexecdcommands = 0;
6267 myrpt->totalexecdcommands = 0;
6268 myrpt->timeouts = 0;
6269 myrpt->exten[0] = '\0';
6270 myrpt->lastdtmfcommand[0] = '\0';
6271 if (myrpt->p.startupmacro)
6273 snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
6275 rpt_mutex_unlock(&myrpt->lock);
6276 val = 0;
6277 ast_channel_setoption(myrpt->rxchannel,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0);
6278 val = 1;
6279 ast_channel_setoption(myrpt->rxchannel,AST_OPTION_RELAXDTMF,&val,sizeof(char),0);
6280 while (ms >= 0)
6282 struct ast_frame *f;
6283 struct ast_channel *cs[300];
6284 int totx=0,elap=0,n,toexit=0;
6286 /* DEBUG Dump */
6287 if((myrpt->disgorgetime) && (time(NULL) >= myrpt->disgorgetime)){
6288 struct rpt_link *zl;
6289 struct rpt_tele *zt;
6291 myrpt->disgorgetime = 0;
6292 ast_log(LOG_NOTICE,"********** Variable Dump Start (app_rpt) **********\n");
6293 ast_log(LOG_NOTICE,"totx = %d\n",totx);
6294 ast_log(LOG_NOTICE,"remrx = %d\n",remrx);
6295 ast_log(LOG_NOTICE,"lasttx = %d\n",lasttx);
6296 ast_log(LOG_NOTICE,"elap = %d\n",elap);
6297 ast_log(LOG_NOTICE,"toexit = %d\n",toexit);
6299 ast_log(LOG_NOTICE,"myrpt->keyed = %d\n",myrpt->keyed);
6300 ast_log(LOG_NOTICE,"myrpt->localtx = %d\n",myrpt->localtx);
6301 ast_log(LOG_NOTICE,"myrpt->callmode = %d\n",myrpt->callmode);
6302 ast_log(LOG_NOTICE,"myrpt->enable = %d\n",myrpt->enable);
6303 ast_log(LOG_NOTICE,"myrpt->mustid = %d\n",myrpt->mustid);
6304 ast_log(LOG_NOTICE,"myrpt->tounkeyed = %d\n",myrpt->tounkeyed);
6305 ast_log(LOG_NOTICE,"myrpt->tonotify = %d\n",myrpt->tonotify);
6306 ast_log(LOG_NOTICE,"myrpt->retxtimer = %ld\n",myrpt->retxtimer);
6307 ast_log(LOG_NOTICE,"myrpt->totimer = %d\n",myrpt->totimer);
6308 ast_log(LOG_NOTICE,"myrpt->tailtimer = %d\n",myrpt->tailtimer);
6309 ast_log(LOG_NOTICE,"myrpt->tailevent = %d\n",myrpt->tailevent);
6311 zl = myrpt->links.next;
6312 while(zl != &myrpt->links){
6313 ast_log(LOG_NOTICE,"*** Link Name: %s ***\n",zl->name);
6314 ast_log(LOG_NOTICE," link->lasttx %d\n",zl->lasttx);
6315 ast_log(LOG_NOTICE," link->lastrx %d\n",zl->lastrx);
6316 ast_log(LOG_NOTICE," link->connected %d\n",zl->connected);
6317 ast_log(LOG_NOTICE," link->hasconnected %d\n",zl->hasconnected);
6318 ast_log(LOG_NOTICE," link->outbound %d\n",zl->outbound);
6319 ast_log(LOG_NOTICE," link->disced %d\n",zl->disced);
6320 ast_log(LOG_NOTICE," link->killme %d\n",zl->killme);
6321 ast_log(LOG_NOTICE," link->disctime %ld\n",zl->disctime);
6322 ast_log(LOG_NOTICE," link->retrytimer %ld\n",zl->retrytimer);
6323 ast_log(LOG_NOTICE," link->retries = %d\n",zl->retries);
6324 ast_log(LOG_NOTICE," link->reconnects = %d\n",zl->reconnects);
6325 zl = zl->next;
6328 zt = myrpt->tele.next;
6329 if(zt != &myrpt->tele)
6330 ast_log(LOG_NOTICE,"*** Telemetry Queue ***\n");
6331 while(zt != &myrpt->tele){
6332 ast_log(LOG_NOTICE," Telemetry mode: %d\n",zt->mode);
6333 zt = zt->next;
6335 ast_log(LOG_NOTICE,"******* Variable Dump End (app_rpt) *******\n");
6340 if (myrpt->reload)
6342 struct rpt_tele *telem;
6344 rpt_mutex_lock(&myrpt->lock);
6345 telem = myrpt->tele.next;
6346 while(telem != &myrpt->tele)
6348 ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
6349 telem = telem->next;
6351 myrpt->reload = 0;
6352 rpt_mutex_unlock(&myrpt->lock);
6353 usleep(10000);
6354 /* find our index, and load the vars */
6355 for(i = 0; i < nrpts; i++)
6357 if (&rpt_vars[i] == myrpt)
6359 load_rpt_vars(i,0);
6360 break;
6365 rpt_mutex_lock(&myrpt->lock);
6366 if (ast_check_hangup(myrpt->rxchannel)) break;
6367 if (ast_check_hangup(myrpt->txchannel)) break;
6368 if (ast_check_hangup(myrpt->pchannel)) break;
6369 if (ast_check_hangup(myrpt->txpchannel)) break;
6371 /* Update local tx with keyed if not parsing a command */
6372 myrpt->localtx = myrpt->keyed && (myrpt->dtmfidx == -1) && (!myrpt->cmdnode[0]);
6373 /* If someone's connected, and they're transmitting from their end to us, set remrx true */
6374 l = myrpt->links.next;
6375 remrx = 0;
6376 while(l != &myrpt->links)
6378 if (l->lastrx){
6379 remrx = 1;
6380 if(l->name[0] != '0') /* Ignore '0' nodes */
6381 strcpy(myrpt->lastnodewhichkeyedusup, l->name); /* Note the node which is doing the key up */
6383 l = l->next;
6385 /* Create a "must_id" flag for the cleanup ID */
6386 myrpt->mustid |= (myrpt->idtimer) && (myrpt->keyed || remrx) ;
6387 /* Build a fresh totx from myrpt->keyed and autopatch activated */
6388 totx = myrpt->callmode;
6389 /* If full duplex, add local tx to totx */
6390 if (myrpt->p.duplex > 1) totx = totx || myrpt->localtx;
6391 /* Traverse the telemetry list to see what's queued */
6392 identqueued = 0;
6393 othertelemqueued = 0;
6394 tailmessagequeued = 0;
6395 ctqueued = 0;
6396 telem = myrpt->tele.next;
6397 while(telem != &myrpt->tele)
6399 if((telem->mode == ID) || (telem->mode == IDTALKOVER)){
6400 identqueued = 1; /* Identification telemetry */
6402 else if(telem->mode == TAILMSG)
6404 tailmessagequeued = 1; /* Tail message telemetry */
6406 else
6408 if (telem->mode != UNKEY)
6409 othertelemqueued = 1; /* Other telemetry */
6410 else
6411 ctqueued = 1; /* Courtesy tone telemetry */
6413 telem = telem->next;
6416 /* Add in any "other" telemetry, if 3/4 or full duplex */
6417 if (myrpt->p.duplex > 0) totx = totx || othertelemqueued;
6418 /* Update external (to links) transmitter PTT state with everything but ID, CT, and tailmessage telemetry */
6419 myrpt->exttx = totx;
6420 /* If half or 3/4 duplex, add localtx to external link tx */
6421 if (myrpt->p.duplex < 2) myrpt->exttx = myrpt->exttx || myrpt->localtx;
6422 /* Add in ID telemetry to local transmitter */
6423 totx = totx || remrx;
6424 /* If 3/4 or full duplex, add in ident and CT telemetry */
6425 if (myrpt->p.duplex > 0)
6426 totx = totx || identqueued || ctqueued;
6427 /* Reset time out timer variables if there is no activity */
6428 if (!totx)
6430 myrpt->totimer = myrpt->p.totime;
6431 myrpt->tounkeyed = 0;
6432 myrpt->tonotify = 0;
6434 else
6435 myrpt->tailtimer = myrpt->p.hangtime; /* Initialize tail timer */
6436 /* Disable the local transmitter if we are timed out */
6437 totx = totx && myrpt->totimer;
6438 /* if timed-out and not said already, say it */
6439 if ((!myrpt->totimer) && (!myrpt->tonotify))
6441 myrpt->tonotify = 1;
6442 myrpt->timeouts++;
6443 rpt_mutex_unlock(&myrpt->lock);
6444 rpt_telemetry(myrpt,TIMEOUT,NULL);
6445 rpt_mutex_lock(&myrpt->lock);
6448 /* If unkey and re-key, reset time out timer */
6449 if ((!totx) && (!myrpt->totimer) && (!myrpt->tounkeyed) && (!myrpt->keyed))
6451 myrpt->tounkeyed = 1;
6453 if ((!totx) && (!myrpt->totimer) && myrpt->tounkeyed && myrpt->keyed)
6455 myrpt->totimer = myrpt->p.totime;
6456 myrpt->tounkeyed = 0;
6457 myrpt->tonotify = 0;
6458 rpt_mutex_unlock(&myrpt->lock);
6459 continue;
6461 /* if timed-out and in circuit busy after call */
6462 if ((!totx) && (!myrpt->totimer) && (myrpt->callmode == 4))
6464 myrpt->callmode = 0;
6466 /* get rid of tail if timed out */
6467 if (!myrpt->totimer) myrpt->tailtimer = 0;
6468 /* if not timed-out, add in tail */
6469 if (myrpt->totimer) totx = totx || myrpt->tailtimer;
6470 /* If user or links key up or are keyed up over standard ID, switch to talkover ID, if one is defined */
6471 /* If tail message, kill the message if someone keys up over it */
6472 if ((myrpt->keyed || remrx) && ((identqueued && idtalkover) || (tailmessagequeued))) {
6473 int hasid = 0,hastalkover = 0;
6475 telem = myrpt->tele.next;
6476 while(telem != &myrpt->tele){
6477 if(telem->mode == ID){
6478 if (telem->chan) ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
6479 hasid = 1;
6481 if(telem->mode == TAILMSG){
6482 if (telem->chan) ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
6484 if (telem->mode == IDTALKOVER) hastalkover = 1;
6485 telem = telem->next;
6487 rpt_mutex_unlock(&myrpt->lock);
6488 if (hasid && (!hastalkover)) rpt_telemetry(myrpt, IDTALKOVER, NULL); /* Start Talkover ID */
6489 rpt_mutex_lock(&myrpt->lock);
6491 /* Try to be polite */
6492 /* If the repeater has been inactive for longer than the ID time, do an initial ID in the tail*/
6493 /* If within 30 seconds of the time to ID, try do it in the tail */
6494 /* else if at ID time limit, do it right over the top of them */
6495 /* Lastly, if the repeater has been keyed, and the ID timer is expired, do a clean up ID */
6496 if(myrpt->mustid && (!myrpt->idtimer))
6497 queue_id(myrpt);
6499 if ((totx && (!myrpt->exttx) &&
6500 (myrpt->idtimer <= myrpt->p.politeid) && myrpt->tailtimer))
6502 myrpt->tailid = 1;
6505 /* If tail timer expires, then check for tail messages */
6507 if(myrpt->tailevent){
6508 myrpt->tailevent = 0;
6509 if(myrpt->tailid){
6510 totx = 1;
6511 queue_id(myrpt);
6513 else if ((myrpt->p.tailmessages[0]) &&
6514 (myrpt->p.tailmessagetime) && (myrpt->tmsgtimer == 0)){
6515 totx = 1;
6516 myrpt->tmsgtimer = myrpt->p.tailmessagetime;
6517 rpt_mutex_unlock(&myrpt->lock);
6518 rpt_telemetry(myrpt, TAILMSG, NULL);
6519 rpt_mutex_lock(&myrpt->lock);
6523 /* Main TX control */
6525 /* let telemetry transmit anyway (regardless of timeout) */
6526 if (myrpt->p.duplex > 0) totx = totx || (myrpt->tele.next != &myrpt->tele);
6527 if (totx && (!lasttx))
6529 lasttx = 1;
6530 myrpt->dailykeyups++;
6531 myrpt->totalkeyups++;
6532 rpt_mutex_unlock(&myrpt->lock);
6533 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
6534 rpt_mutex_lock(&myrpt->lock);
6536 totx = totx && myrpt->enable;
6537 if ((!totx) && lasttx)
6539 lasttx = 0;
6540 rpt_mutex_unlock(&myrpt->lock);
6541 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
6542 rpt_mutex_lock(&myrpt->lock);
6544 time(&t);
6545 /* if DTMF timeout */
6546 if ((!myrpt->cmdnode[0]) && (myrpt->dtmfidx >= 0) && ((myrpt->dtmf_time + DTMF_TIMEOUT) < t))
6548 myrpt->dtmfidx = -1;
6549 myrpt->dtmfbuf[0] = 0;
6551 /* if remote DTMF timeout */
6552 if ((myrpt->rem_dtmfidx >= 0) && ((myrpt->rem_dtmf_time + DTMF_TIMEOUT) < t))
6554 myrpt->rem_dtmfidx = -1;
6555 myrpt->rem_dtmfbuf[0] = 0;
6558 /* Reconnect */
6560 l = myrpt->links.next;
6561 while(l != &myrpt->links)
6563 if (l->killme)
6565 /* remove from queue */
6566 remque((struct qelem *) l);
6567 if (!strcmp(myrpt->cmdnode,l->name))
6568 myrpt->cmdnode[0] = 0;
6569 rpt_mutex_unlock(&myrpt->lock);
6570 /* hang-up on call to device */
6571 if (l->chan) ast_hangup(l->chan);
6572 ast_hangup(l->pchan);
6573 free(l);
6574 rpt_mutex_lock(&myrpt->lock);
6575 /* re-start link traversal */
6576 l = myrpt->links.next;
6577 continue;
6579 l = l->next;
6581 n = 0;
6582 cs[n++] = myrpt->rxchannel;
6583 cs[n++] = myrpt->pchannel;
6584 cs[n++] = myrpt->txpchannel;
6585 if (myrpt->txchannel != myrpt->rxchannel) cs[n++] = myrpt->txchannel;
6586 l = myrpt->links.next;
6587 while(l != &myrpt->links)
6589 if ((!l->killme) && (!l->disctime) && l->chan)
6591 cs[n++] = l->chan;
6592 cs[n++] = l->pchan;
6594 l = l->next;
6596 rpt_mutex_unlock(&myrpt->lock);
6597 ms = MSWAIT;
6598 who = ast_waitfor_n(cs,n,&ms);
6599 if (who == NULL) ms = 0;
6600 elap = MSWAIT - ms;
6601 rpt_mutex_lock(&myrpt->lock);
6602 l = myrpt->links.next;
6603 while(l != &myrpt->links)
6605 if (!l->lasttx)
6607 if ((l->retxtimer += elap) >= REDUNDANT_TX_TIME)
6609 l->retxtimer = 0;
6610 if (l->chan) ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
6612 } else l->retxtimer = 0;
6613 if (l->disctime) /* Disconnect timer active on a channel ? */
6615 l->disctime -= elap;
6616 if (l->disctime <= 0) /* Disconnect timer expired on inbound channel ? */
6617 l->disctime = 0; /* Yep */
6620 if (l->retrytimer)
6622 l->retrytimer -= elap;
6623 if (l->retrytimer < 0) l->retrytimer = 0;
6626 /* Tally connect time */
6627 l->connecttime += elap;
6629 /* ignore non-timing channels */
6630 if (l->elaptime < 0)
6632 l = l->next;
6633 continue;
6635 l->elaptime += elap;
6636 /* if connection has taken too long */
6637 if ((l->elaptime > MAXCONNECTTIME) &&
6638 ((!l->chan) || (l->chan->_state != AST_STATE_UP)))
6640 l->elaptime = 0;
6641 rpt_mutex_unlock(&myrpt->lock);
6642 if (l->chan) ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
6643 rpt_mutex_lock(&myrpt->lock);
6644 break;
6646 if ((!l->chan) && (!l->retrytimer) && l->outbound &&
6647 (l->retries++ < MAX_RETRIES) && (l->hasconnected))
6649 if (l->chan) ast_hangup(l->chan);
6650 rpt_mutex_unlock(&myrpt->lock);
6651 if ((l->name[0] != '0') && (!l->isremote))
6653 l->retrytimer = MAX_RETRIES + 1;
6655 else
6657 if (attempt_reconnect(myrpt,l) == -1)
6659 l->retrytimer = RETRY_TIMER_MS;
6662 rpt_mutex_lock(&myrpt->lock);
6663 break;
6665 if ((!l->chan) && (!l->retrytimer) && l->outbound &&
6666 (l->retries >= MAX_RETRIES))
6668 /* remove from queue */
6669 remque((struct qelem *) l);
6670 if (!strcmp(myrpt->cmdnode,l->name))
6671 myrpt->cmdnode[0] = 0;
6672 rpt_mutex_unlock(&myrpt->lock);
6673 if (l->name[0] != '0')
6675 if (!l->hasconnected)
6676 rpt_telemetry(myrpt,CONNFAIL,l);
6677 else rpt_telemetry(myrpt,REMDISC,l);
6679 /* hang-up on call to device */
6680 ast_hangup(l->pchan);
6681 free(l);
6682 rpt_mutex_lock(&myrpt->lock);
6683 break;
6685 if ((!l->chan) && (!l->disctime) && (!l->outbound))
6687 /* remove from queue */
6688 remque((struct qelem *) l);
6689 if (!strcmp(myrpt->cmdnode,l->name))
6690 myrpt->cmdnode[0] = 0;
6691 rpt_mutex_unlock(&myrpt->lock);
6692 if (l->name[0] != '0')
6694 rpt_telemetry(myrpt,REMDISC,l);
6696 /* hang-up on call to device */
6697 ast_hangup(l->pchan);
6698 free(l);
6699 rpt_mutex_lock(&myrpt->lock);
6700 break;
6702 l = l->next;
6704 if(totx){
6705 myrpt->dailytxtime += elap;
6706 myrpt->totaltxtime += elap;
6708 i = myrpt->tailtimer;
6709 if (myrpt->tailtimer) myrpt->tailtimer -= elap;
6710 if (myrpt->tailtimer < 0) myrpt->tailtimer = 0;
6711 if((i) && (myrpt->tailtimer == 0))
6712 myrpt->tailevent = 1;
6713 if (myrpt->totimer) myrpt->totimer -= elap;
6714 if (myrpt->totimer < 0) myrpt->totimer = 0;
6715 if (myrpt->idtimer) myrpt->idtimer -= elap;
6716 if (myrpt->idtimer < 0) myrpt->idtimer = 0;
6717 if (myrpt->tmsgtimer) myrpt->tmsgtimer -= elap;
6718 if (myrpt->tmsgtimer < 0) myrpt->tmsgtimer = 0;
6719 /* do macro timers */
6720 if (myrpt->macrotimer) myrpt->macrotimer -= elap;
6721 if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
6722 /* Execute scheduler appx. every 2 tenths of a second */
6723 if (myrpt->skedtimer <= 0){
6724 myrpt->skedtimer = 200;
6725 do_scheduler(myrpt);
6727 else
6728 myrpt->skedtimer -=elap;
6729 if (!ms)
6731 rpt_mutex_unlock(&myrpt->lock);
6732 continue;
6734 c = myrpt->macrobuf[0];
6735 if (c && (!myrpt->macrotimer))
6737 myrpt->macrotimer = MACROTIME;
6738 memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1);
6739 if ((c == 'p') || (c == 'P'))
6740 myrpt->macrotimer = MACROPTIME;
6741 rpt_mutex_unlock(&myrpt->lock);
6742 local_dtmf_helper(myrpt,c);
6743 } else rpt_mutex_unlock(&myrpt->lock);
6744 if (who == myrpt->rxchannel) /* if it was a read from rx */
6746 f = ast_read(myrpt->rxchannel);
6747 if (!f)
6749 if (debug) printf("@@@@ rpt:Hung Up\n");
6750 break;
6752 if (f->frametype == AST_FRAME_VOICE)
6754 #ifdef _MDC_DECODE_H_
6755 unsigned char ubuf[2560];
6756 short *sp;
6757 int n;
6758 #endif
6760 if (!myrpt->localtx) {
6761 memset(f->data,0,f->datalen);
6764 #ifdef _MDC_DECODE_H_
6765 sp = (short *) f->data;
6766 /* convert block to unsigned char */
6767 for(n = 0; n < f->datalen / 2; n++)
6769 ubuf[n] = (*sp++ >> 8) + 128;
6771 n = mdc_decoder_process_samples(myrpt->mdc,ubuf,f->datalen / 2);
6772 if (n == 1)
6774 unsigned char op,arg;
6775 unsigned short unitID;
6777 mdc_decoder_get_packet(myrpt->mdc,&op,&arg,&unitID);
6778 if (debug > 2)
6780 ast_log(LOG_NOTICE,"Got (single-length) packet:\n");
6781 ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
6782 op & 255,arg & 255,unitID);
6784 if ((op == 1) && (arg == 0))
6786 myrpt->lastunit = unitID;
6789 if ((debug > 2) && (i == 2))
6791 unsigned char op,arg,ex1,ex2,ex3,ex4;
6792 unsigned short unitID;
6794 mdc_decoder_get_double_packet(myrpt->mdc,&op,&arg,&unitID,
6795 &ex1,&ex2,&ex3,&ex4);
6796 ast_log(LOG_NOTICE,"Got (double-length) packet:\n");
6797 ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
6798 op & 255,arg & 255,unitID);
6799 ast_log(LOG_NOTICE,"ex1: %02x, ex2: %02x, ex3: %02x, ex4: %02x\n",
6800 ex1 & 255, ex2 & 255, ex3 & 255, ex4 & 255);
6802 #endif
6803 #ifdef __RPT_NOTCH
6804 /* apply inbound filters, if any */
6805 rpt_filter(myrpt,f->data,f->datalen / 2);
6806 #endif
6807 ast_write(myrpt->pchannel,f);
6809 else if (f->frametype == AST_FRAME_DTMF)
6811 c = (char) f->subclass; /* get DTMF char */
6812 ast_frfree(f);
6813 if (!myrpt->keyed) continue;
6814 local_dtmf_helper(myrpt,c);
6815 continue;
6817 else if (f->frametype == AST_FRAME_CONTROL)
6819 if (f->subclass == AST_CONTROL_HANGUP)
6821 if (debug) printf("@@@@ rpt:Hung Up\n");
6822 ast_frfree(f);
6823 break;
6825 /* if RX key */
6826 if (f->subclass == AST_CONTROL_RADIO_KEY)
6828 if ((!lasttx) || (myrpt->p.duplex > 1))
6830 if (debug == 7) printf("@@@@ rx key\n");
6831 myrpt->keyed = 1;
6834 /* if RX un-key */
6835 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
6837 if ((!lasttx) || (myrpt->p.duplex > 1))
6839 if (debug == 7) printf("@@@@ rx un-key\n");
6840 if(myrpt->keyed) {
6841 rpt_telemetry(myrpt,UNKEY,NULL);
6843 myrpt->keyed = 0;
6847 ast_frfree(f);
6848 continue;
6850 if (who == myrpt->pchannel) /* if it was a read from pseudo */
6852 f = ast_read(myrpt->pchannel);
6853 if (!f)
6855 if (debug) printf("@@@@ rpt:Hung Up\n");
6856 break;
6858 if (f->frametype == AST_FRAME_VOICE)
6860 ast_write(myrpt->txpchannel,f);
6862 if (f->frametype == AST_FRAME_CONTROL)
6864 if (f->subclass == AST_CONTROL_HANGUP)
6866 if (debug) printf("@@@@ rpt:Hung Up\n");
6867 ast_frfree(f);
6868 break;
6871 ast_frfree(f);
6872 continue;
6874 if (who == myrpt->txchannel) /* if it was a read from tx */
6876 f = ast_read(myrpt->txchannel);
6877 if (!f)
6879 if (debug) printf("@@@@ rpt:Hung Up\n");
6880 break;
6882 if (f->frametype == AST_FRAME_CONTROL)
6884 if (f->subclass == AST_CONTROL_HANGUP)
6886 if (debug) printf("@@@@ rpt:Hung Up\n");
6887 ast_frfree(f);
6888 break;
6891 ast_frfree(f);
6892 continue;
6894 toexit = 0;
6895 rpt_mutex_lock(&myrpt->lock);
6896 l = myrpt->links.next;
6897 while(l != &myrpt->links)
6899 if (l->disctime)
6901 l = l->next;
6902 continue;
6904 if (who == l->chan) /* if it was a read from rx */
6906 remrx = 0;
6907 /* see if any other links are receiving */
6908 m = myrpt->links.next;
6909 while(m != &myrpt->links)
6911 /* if not us, count it */
6912 if ((m != l) && (m->lastrx)) remrx = 1;
6913 m = m->next;
6915 rpt_mutex_unlock(&myrpt->lock);
6916 totx = (((l->isremote) ? myrpt->localtx :
6917 myrpt->exttx) || remrx) && l->mode;
6918 if (l->chan && (l->lasttx != totx))
6920 if (totx)
6922 ast_indicate(l->chan,AST_CONTROL_RADIO_KEY);
6924 else
6926 ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
6929 l->lasttx = totx;
6930 f = ast_read(l->chan);
6931 if (!f)
6933 if ((!l->disced) && (!l->outbound))
6935 if ((l->name[0] == '0') || l->isremote)
6936 l->disctime = 1;
6937 else
6938 l->disctime = DISC_TIME;
6939 rpt_mutex_lock(&myrpt->lock);
6940 ast_hangup(l->chan);
6941 l->chan = 0;
6942 break;
6945 if (l->retrytimer)
6947 rpt_mutex_lock(&myrpt->lock);
6948 break;
6950 if (l->outbound && (l->retries++ < MAX_RETRIES) && (l->hasconnected))
6952 rpt_mutex_lock(&myrpt->lock);
6953 ast_hangup(l->chan);
6954 l->chan = 0;
6955 rpt_mutex_unlock(&myrpt->lock);
6956 if (attempt_reconnect(myrpt,l) == -1)
6958 l->retrytimer = RETRY_TIMER_MS;
6960 rpt_mutex_lock(&myrpt->lock);
6961 break;
6963 rpt_mutex_lock(&myrpt->lock);
6964 /* remove from queue */
6965 remque((struct qelem *) l);
6966 if (!strcmp(myrpt->cmdnode,l->name))
6967 myrpt->cmdnode[0] = 0;
6968 rpt_mutex_unlock(&myrpt->lock);
6969 if (!l->hasconnected)
6970 rpt_telemetry(myrpt,CONNFAIL,l);
6971 else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
6972 /* hang-up on call to device */
6973 ast_hangup(l->chan);
6974 ast_hangup(l->pchan);
6975 free(l);
6976 rpt_mutex_lock(&myrpt->lock);
6977 break;
6979 if (f->frametype == AST_FRAME_VOICE)
6981 if (!l->lastrx)
6983 memset(f->data,0,f->datalen);
6985 ast_write(l->pchan,f);
6987 if (f->frametype == AST_FRAME_TEXT)
6989 handle_link_data(myrpt,l,f->data);
6991 if (f->frametype == AST_FRAME_DTMF)
6993 handle_link_phone_dtmf(myrpt,l,f->subclass);
6995 if (f->frametype == AST_FRAME_CONTROL)
6997 if (f->subclass == AST_CONTROL_ANSWER)
6999 char lconnected = l->connected;
7000 l->connected = 1;
7001 l->hasconnected = 1;
7002 l->elaptime = -1;
7003 l->retries = 0;
7004 if (!lconnected)
7005 rpt_telemetry(myrpt,CONNECTED,l);
7006 else
7007 l->reconnects++;
7009 /* if RX key */
7010 if (f->subclass == AST_CONTROL_RADIO_KEY)
7012 if (debug == 7 ) printf("@@@@ rx key\n");
7013 l->lastrx = 1;
7015 /* if RX un-key */
7016 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
7018 if (debug == 7) printf("@@@@ rx un-key\n");
7019 l->lastrx = 0;
7021 if (f->subclass == AST_CONTROL_HANGUP)
7023 ast_frfree(f);
7024 if ((!l->outbound) && (!l->disced))
7026 if ((l->name[0] == '0') || l->isremote)
7027 l->disctime = 1;
7028 else
7029 l->disctime = DISC_TIME;
7030 rpt_mutex_lock(&myrpt->lock);
7031 ast_hangup(l->chan);
7032 l->chan = 0;
7033 break;
7035 if (l->retrytimer)
7037 rpt_mutex_lock(&myrpt->lock);
7038 break;
7040 if (l->outbound && (l->retries++ < MAX_RETRIES) && (l->hasconnected))
7042 rpt_mutex_lock(&myrpt->lock);
7043 ast_hangup(l->chan);
7044 l->chan = 0;
7045 rpt_mutex_unlock(&myrpt->lock);
7046 if (attempt_reconnect(myrpt,l) == -1)
7048 l->retrytimer = RETRY_TIMER_MS;
7050 rpt_mutex_lock(&myrpt->lock);
7051 break;
7053 rpt_mutex_lock(&myrpt->lock);
7054 /* remove from queue */
7055 remque((struct qelem *) l);
7056 if (!strcmp(myrpt->cmdnode,l->name))
7057 myrpt->cmdnode[0] = 0;
7058 rpt_mutex_unlock(&myrpt->lock);
7059 if (!l->hasconnected)
7060 rpt_telemetry(myrpt,CONNFAIL,l);
7061 else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
7062 /* hang-up on call to device */
7063 ast_hangup(l->chan);
7064 ast_hangup(l->pchan);
7065 free(l);
7066 rpt_mutex_lock(&myrpt->lock);
7067 break;
7070 ast_frfree(f);
7071 rpt_mutex_lock(&myrpt->lock);
7072 break;
7074 if (who == l->pchan)
7076 rpt_mutex_unlock(&myrpt->lock);
7077 f = ast_read(l->pchan);
7078 if (!f)
7080 if (debug) printf("@@@@ rpt:Hung Up\n");
7081 toexit = 1;
7082 rpt_mutex_lock(&myrpt->lock);
7083 break;
7085 if (f->frametype == AST_FRAME_VOICE)
7087 if (l->chan) ast_write(l->chan,f);
7089 if (f->frametype == AST_FRAME_CONTROL)
7091 if (f->subclass == AST_CONTROL_HANGUP)
7093 if (debug) printf("@@@@ rpt:Hung Up\n");
7094 ast_frfree(f);
7095 toexit = 1;
7096 rpt_mutex_lock(&myrpt->lock);
7097 break;
7100 ast_frfree(f);
7101 rpt_mutex_lock(&myrpt->lock);
7102 break;
7104 l = l->next;
7106 rpt_mutex_unlock(&myrpt->lock);
7107 if (toexit) break;
7108 if (who == myrpt->txpchannel) /* if it was a read from remote tx */
7110 f = ast_read(myrpt->txpchannel);
7111 if (!f)
7113 if (debug) printf("@@@@ rpt:Hung Up\n");
7114 break;
7116 if (f->frametype == AST_FRAME_CONTROL)
7118 if (f->subclass == AST_CONTROL_HANGUP)
7120 if (debug) printf("@@@@ rpt:Hung Up\n");
7121 ast_frfree(f);
7122 break;
7125 ast_frfree(f);
7126 continue;
7129 usleep(100000);
7130 ast_hangup(myrpt->pchannel);
7131 ast_hangup(myrpt->txpchannel);
7132 if (myrpt->txchannel != myrpt->rxchannel) ast_hangup(myrpt->txchannel);
7133 ast_hangup(myrpt->rxchannel);
7134 rpt_mutex_lock(&myrpt->lock);
7135 l = myrpt->links.next;
7136 while(l != &myrpt->links)
7138 struct rpt_link *ll = l;
7139 /* remove from queue */
7140 remque((struct qelem *) l);
7141 /* hang-up on call to device */
7142 if (l->chan) ast_hangup(l->chan);
7143 ast_hangup(l->pchan);
7144 l = l->next;
7145 free(ll);
7147 rpt_mutex_unlock(&myrpt->lock);
7148 if (debug) printf("@@@@ rpt:Hung up channel\n");
7149 myrpt->rpt_thread = AST_PTHREADT_STOP;
7150 pthread_exit(NULL);
7151 return NULL;
7155 static void *rpt_master(void *config)
7157 int i,n;
7158 pthread_attr_t attr;
7159 struct ast_config *cfg;
7160 char *this;
7161 const char *val;
7163 /* go thru all the specified repeaters */
7164 this = NULL;
7165 n = 0;
7166 rpt_vars[n].cfg = config;
7167 cfg = rpt_vars[n].cfg;
7168 if (!cfg) {
7169 ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf. Radio Repeater disabled.\n");
7170 pthread_exit(NULL);
7172 while((this = ast_category_browse(cfg,this)) != NULL)
7174 for(i = 0 ; i < strlen(this) ; i++){
7175 if((this[i] < '0') || (this[i] > '9'))
7176 break;
7178 if(i != strlen(this)) continue; /* Not a node defn */
7179 memset(&rpt_vars[n],0,sizeof(rpt_vars[n]));
7180 rpt_vars[n].name = strdup(this);
7181 val = ast_variable_retrieve(cfg,this,"rxchannel");
7182 if (val) rpt_vars[n].rxchanname = strdup(val);
7183 val = ast_variable_retrieve(cfg,this,"txchannel");
7184 if (val) rpt_vars[n].txchanname = strdup(val);
7185 val = ast_variable_retrieve(cfg,this,"remote");
7186 if (val) rpt_vars[n].remote = strdup(val);
7187 ast_mutex_init(&rpt_vars[n].lock);
7188 rpt_vars[n].tele.next = &rpt_vars[n].tele;
7189 rpt_vars[n].tele.prev = &rpt_vars[n].tele;
7190 rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
7191 rpt_vars[n].tailmessagen = 0;
7192 #ifdef _MDC_DECODE_H_
7193 rpt_vars[n].mdc = mdc_decoder_new(8000);
7194 #endif
7195 n++;
7197 nrpts = n;
7198 ast_config_destroy(cfg);
7200 /* start em all */
7201 for(i = 0; i < n; i++)
7203 load_rpt_vars(i,1);
7205 /* if is a remote, dont start one for it */
7206 if (rpt_vars[i].remote)
7208 strcpy(rpt_vars[i].freq, "146.580");
7209 strcpy(rpt_vars[i].rxpl, "100.0");
7210 strcpy(rpt_vars[i].txpl, "100.0");
7211 rpt_vars[i].remmode = REM_MODE_FM;
7212 rpt_vars[i].offset = REM_SIMPLEX;
7213 rpt_vars[i].powerlevel = REM_MEDPWR;
7214 continue;
7216 if (!rpt_vars[i].p.ident)
7218 ast_log(LOG_WARNING,"Did not specify ident for node %s\n",rpt_vars[i].name);
7219 ast_config_destroy(cfg);
7220 pthread_exit(NULL);
7222 pthread_attr_init(&attr);
7223 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
7224 ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]);
7225 pthread_attr_destroy(&attr);
7227 usleep(500000);
7228 for(;;)
7230 /* Now monitor each thread, and restart it if necessary */
7231 for(i = 0; i < n; i++)
7233 int rv;
7234 if (rpt_vars[i].remote) continue;
7235 if (rpt_vars[i].rpt_thread == AST_PTHREADT_STOP)
7236 rv = -1;
7237 else
7238 rv = pthread_kill(rpt_vars[i].rpt_thread,0);
7239 if (rv)
7241 if(time(NULL) - rpt_vars[i].lastthreadrestarttime <= 15)
7243 if(rpt_vars[i].threadrestarts >= 5)
7245 ast_log(LOG_ERROR,"Continual RPT thread restarts, killing Asterisk\n");
7246 exit(1); /* Stuck in a restart loop, kill Asterisk and start over */
7248 else
7250 ast_log(LOG_NOTICE,"RPT thread restarted on %s\n",rpt_vars[i].name);
7251 rpt_vars[i].threadrestarts++;
7254 else
7255 rpt_vars[i].threadrestarts = 0;
7257 rpt_vars[i].lastthreadrestarttime = time(NULL);
7258 pthread_attr_init(&attr);
7259 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
7260 ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]);
7261 pthread_attr_destroy(&attr);
7262 ast_log(LOG_WARNING, "rpt_thread restarted on node %s\n", rpt_vars[i].name);
7266 usleep(2000000);
7268 ast_config_destroy(cfg);
7269 pthread_exit(NULL);
7272 static int rpt_exec(struct ast_channel *chan, void *data)
7274 int res=-1,i,rem_totx,n,phone_mode = 0;
7275 struct ast_module_user *u;
7276 char tmp[256], keyed = 0;
7277 char *options,*stringp,*tele,c;
7278 struct rpt *myrpt;
7279 struct ast_frame *f;
7280 struct ast_channel *who;
7281 struct ast_channel *cs[20];
7282 struct rpt_link *l;
7283 ZT_CONFINFO ci; /* conference info */
7284 ZT_PARAMS par;
7285 int ms,elap;
7287 if (ast_strlen_zero(data)) {
7288 ast_log(LOG_WARNING, "Rpt requires an argument (system node)\n");
7289 return -1;
7291 ast_copy_string(tmp, (char *)data, sizeof(tmp));
7292 stringp=tmp;
7293 strsep(&stringp, "|");
7294 options = stringp;
7295 myrpt = NULL;
7296 /* see if we can find our specified one */
7297 for(i = 0; i < nrpts; i++)
7299 /* if name matches, assign it and exit loop */
7300 if (!strcmp(tmp,rpt_vars[i].name))
7302 myrpt = &rpt_vars[i];
7303 break;
7306 if (myrpt == NULL)
7308 ast_log(LOG_WARNING, "Cannot find specified system node %s\n",tmp);
7309 return -1;
7312 /* if not phone access, must be an IAX connection */
7313 if (options && ((*options == 'P') || (*options == 'D') || (*options == 'R')))
7315 phone_mode = 1;
7316 if (*options == 'D') phone_mode = 2;
7317 ast_set_callerid(chan,"0","app_rpt user","0");
7319 else
7321 if (strncmp(chan->name,"IAX2",4))
7323 ast_log(LOG_WARNING, "We only accept links via IAX2!!\n");
7324 return -1;
7327 if (options && (*options == 'R'))
7330 /* Parts of this section taken from app_parkandannounce */
7331 char *return_context;
7332 int l, m, lot, timeout = 0;
7333 char tmp[256],*template;
7334 char *working, *context, *exten, *priority;
7335 char *s,*orig_s;
7338 rpt_mutex_lock(&myrpt->lock);
7339 m = myrpt->callmode;
7340 rpt_mutex_unlock(&myrpt->lock);
7342 if ((!myrpt->p.nobusyout) && m)
7344 if (chan->_state != AST_STATE_UP)
7346 ast_indicate(chan,AST_CONTROL_BUSY);
7348 while(ast_safe_sleep(chan,10000) != -1);
7349 return -1;
7352 if (chan->_state != AST_STATE_UP)
7354 ast_answer(chan);
7357 l=strlen(options)+2;
7358 orig_s=malloc(l);
7359 if(!orig_s) {
7360 ast_log(LOG_WARNING, "Out of memory\n");
7361 return -1;
7363 s=orig_s;
7364 ast_copy_string(s,options,l);
7366 template=strsep(&s,"|");
7367 if(!template) {
7368 ast_log(LOG_WARNING, "An announce template must be defined\n");
7369 free(orig_s);
7370 return -1;
7373 if(s) {
7374 timeout = atoi(strsep(&s, "|"));
7375 timeout *= 1000;
7378 return_context = s;
7380 if(return_context != NULL) {
7381 /* set the return context. Code borrowed from the Goto builtin */
7383 working = return_context;
7384 context = strsep(&working, "|");
7385 exten = strsep(&working, "|");
7386 if(!exten) {
7387 /* Only a priority in this one */
7388 priority = context;
7389 exten = NULL;
7390 context = NULL;
7391 } else {
7392 priority = strsep(&working, "|");
7393 if(!priority) {
7394 /* Only an extension and priority in this one */
7395 priority = exten;
7396 exten = context;
7397 context = NULL;
7400 if(atoi(priority) < 0) {
7401 ast_log(LOG_WARNING, "Priority '%s' must be a number > 0\n", priority);
7402 free(orig_s);
7403 return -1;
7405 /* At this point we have a priority and maybe an extension and a context */
7406 chan->priority = atoi(priority);
7407 #ifdef OLD_ASTERISK
7408 if(exten && strcasecmp(exten, "BYEXTENSION"))
7409 #else
7410 if(exten)
7411 #endif
7412 ast_copy_string(chan->exten, exten, sizeof(chan->exten));
7413 if(context)
7414 ast_copy_string(chan->context, context, sizeof(chan->context));
7415 } else { /* increment the priority by default*/
7416 chan->priority++;
7419 if(option_verbose > 2) {
7420 ast_verbose( VERBOSE_PREFIX_3 "Return Context: (%s,%s,%d) ID: %s\n", chan->context,chan->exten, chan->priority, chan->cid.cid_num);
7421 if(!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) {
7422 ast_verbose( VERBOSE_PREFIX_3 "Warning: Return Context Invalid, call will return to default|s\n");
7426 /* we are using masq_park here to protect * from touching the channel once we park it. If the channel comes out of timeout
7427 before we are done announcing and the channel is messed with, Kablooeee. So we use Masq to prevent this. */
7429 ast_masq_park_call(chan, NULL, timeout, &lot);
7431 if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "Call Parking Called, lot: %d, timeout: %d, context: %s\n", lot, timeout, return_context);
7433 snprintf(tmp,sizeof(tmp) - 1,"%d,%s",lot,template + 1);
7435 rpt_telemetry(myrpt,REV_PATCH,tmp);
7437 free(orig_s);
7439 return 0;
7443 if (!options)
7445 struct ast_hostent ahp;
7446 struct hostent *hp;
7447 struct in_addr ia;
7448 char hisip[100],nodeip[100];
7449 const char *val;
7450 char *s, *s1, *s2, *b,*b1;
7452 /* look at callerid to see what node this comes from */
7453 if (!chan->cid.cid_num) /* if doesn't have caller id */
7455 ast_log(LOG_WARNING, "Doesnt have callerid on %s\n",tmp);
7456 return -1;
7459 /* get his IP from IAX2 module */
7460 memset(hisip,0,sizeof(hisip));
7461 pbx_substitute_variables_helper(chan,"${IAXPEER(CURRENTCHANNEL)}",hisip,sizeof(hisip) - 1);
7462 if (!hisip[0])
7464 ast_log(LOG_WARNING, "Link IP address cannot be determined!!\n");
7465 return -1;
7468 ast_callerid_parse(chan->cid.cid_num,&b,&b1);
7469 ast_shrink_phone_number(b1);
7470 if (!strcmp(myrpt->name,b1))
7472 ast_log(LOG_WARNING, "Trying to link to self!!\n");
7473 return -1;
7476 if (*b1 < '1')
7478 ast_log(LOG_WARNING, "Node %s Invalid for connection here!!\n",b1);
7479 return -1;
7483 /* look for his reported node string */
7484 val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, b1);
7485 if (!val)
7487 ast_log(LOG_WARNING, "Reported node %s cannot be found!!\n",b1);
7488 return -1;
7490 ast_copy_string(tmp,val,sizeof(tmp));
7491 s = tmp;
7492 s1 = strsep(&s,",");
7493 s2 = strsep(&s,",");
7494 if (!s2)
7496 ast_log(LOG_WARNING, "Reported node %s not in correct format!!\n",b1);
7497 return -1;
7499 if (strcmp(s2,"NONE")) {
7500 hp = ast_gethostbyname(s2, &ahp);
7501 if (!hp)
7503 ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n",b1,s2);
7504 return -1;
7506 memcpy(&ia,hp->h_addr,sizeof(in_addr_t));
7507 ast_copy_string(nodeip, ast_inet_ntoa(ia), sizeof(nodeip));
7508 if (strcmp(hisip,nodeip))
7510 char *s3 = strchr(s1,'@');
7511 if (s3) s1 = s3 + 1;
7512 s3 = strchr(s1,'/');
7513 if (s3) *s3 = 0;
7514 hp = ast_gethostbyname(s1, &ahp);
7515 if (!hp)
7517 ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n",b1,s1);
7518 return -1;
7520 memcpy(&ia,hp->h_addr,sizeof(in_addr_t));
7521 ast_copy_string(nodeip, ast_inet_ntoa(ia), sizeof(nodeip));
7522 if (strcmp(hisip,nodeip))
7524 ast_log(LOG_WARNING, "Node %s IP %s does not match link IP %s!!\n",b1,nodeip,hisip);
7525 return -1;
7531 /* if is not a remote */
7532 if (!myrpt->remote)
7535 char *b,*b1;
7536 int reconnects = 0;
7538 /* look at callerid to see what node this comes from */
7539 if (!chan->cid.cid_num) /* if doesn't have caller id */
7541 ast_log(LOG_WARNING, "Doesnt have callerid on %s\n",tmp);
7542 return -1;
7545 ast_callerid_parse(chan->cid.cid_num,&b,&b1);
7546 ast_shrink_phone_number(b1);
7547 if (!strcmp(myrpt->name,b1))
7549 ast_log(LOG_WARNING, "Trying to link to self!!\n");
7550 return -1;
7552 rpt_mutex_lock(&myrpt->lock);
7553 l = myrpt->links.next;
7554 /* try to find this one in queue */
7555 while(l != &myrpt->links)
7557 if (l->name[0] == '0')
7559 l = l->next;
7560 continue;
7562 /* if found matching string */
7563 if (!strcmp(l->name,b1)) break;
7564 l = l->next;
7566 /* if found */
7567 if (l != &myrpt->links)
7569 l->killme = 1;
7570 l->retries = MAX_RETRIES + 1;
7571 l->disced = 2;
7572 reconnects = l->reconnects;
7573 reconnects++;
7574 rpt_mutex_unlock(&myrpt->lock);
7575 usleep(500000);
7576 } else
7577 rpt_mutex_unlock(&myrpt->lock);
7578 /* establish call in tranceive mode */
7579 l = malloc(sizeof(struct rpt_link));
7580 if (!l)
7582 ast_log(LOG_WARNING, "Unable to malloc\n");
7583 pthread_exit(NULL);
7585 /* zero the silly thing */
7586 memset((char *)l,0,sizeof(struct rpt_link));
7587 l->mode = 1;
7588 ast_copy_string(l->name,b1,MAXNODESTR);
7589 l->isremote = 0;
7590 l->chan = chan;
7591 l->connected = 1;
7592 l->hasconnected = 1;
7593 l->reconnects = reconnects;
7594 l->phonemode = phone_mode;
7595 ast_set_read_format(l->chan,AST_FORMAT_SLINEAR);
7596 ast_set_write_format(l->chan,AST_FORMAT_SLINEAR);
7597 /* allocate a pseudo-channel thru asterisk */
7598 l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
7599 if (!l->pchan)
7601 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
7602 pthread_exit(NULL);
7604 ast_set_read_format(l->pchan,AST_FORMAT_SLINEAR);
7605 ast_set_write_format(l->pchan,AST_FORMAT_SLINEAR);
7606 /* make a conference for the tx */
7607 ci.chan = 0;
7608 ci.confno = myrpt->conf;
7609 ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER;
7610 /* first put the channel on the conference in proper mode */
7611 if (ioctl(l->pchan->fds[0],ZT_SETCONF,&ci) == -1)
7613 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
7614 pthread_exit(NULL);
7616 rpt_mutex_lock(&myrpt->lock);
7617 if (phone_mode > 1) l->lastrx = 1;
7618 /* insert at end of queue */
7619 insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
7620 rpt_mutex_unlock(&myrpt->lock);
7621 if (chan->_state != AST_STATE_UP) {
7622 ast_answer(chan);
7624 return AST_PBX_KEEPALIVE;
7626 rpt_mutex_lock(&myrpt->lock);
7627 /* if remote, error if anyone else already linked */
7628 if (myrpt->remoteon)
7630 rpt_mutex_unlock(&myrpt->lock);
7631 usleep(500000);
7632 if (myrpt->remoteon)
7634 ast_log(LOG_WARNING, "Trying to use busy link on %s\n",tmp);
7635 return -1;
7637 rpt_mutex_lock(&myrpt->lock);
7639 myrpt->remoteon = 1;
7640 if (ioperm(myrpt->p.iobase,1,1) == -1)
7642 rpt_mutex_unlock(&myrpt->lock);
7643 ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase);
7644 return -1;
7646 u = ast_module_user_add(chan);
7647 rpt_mutex_unlock(&myrpt->lock);
7648 /* find our index, and load the vars initially */
7649 for(i = 0; i < nrpts; i++)
7651 if (&rpt_vars[i] == myrpt)
7653 load_rpt_vars(i,0);
7654 break;
7657 rpt_mutex_lock(&myrpt->lock);
7658 tele = strchr(myrpt->rxchanname,'/');
7659 if (!tele)
7661 fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
7662 rpt_mutex_unlock(&myrpt->lock);
7663 pthread_exit(NULL);
7665 *tele++ = 0;
7666 myrpt->rxchannel = ast_request(myrpt->rxchanname,AST_FORMAT_SLINEAR,tele,NULL);
7667 if (myrpt->rxchannel)
7669 ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
7670 ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
7671 myrpt->rxchannel->whentohangup = 0;
7672 myrpt->rxchannel->appl = "Apprpt";
7673 myrpt->rxchannel->data = "(Link Rx)";
7674 if (option_verbose > 2)
7675 ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
7676 myrpt->rxchanname,tele,myrpt->rxchannel->name);
7677 rpt_mutex_unlock(&myrpt->lock);
7678 ast_call(myrpt->rxchannel,tele,999);
7679 rpt_mutex_lock(&myrpt->lock);
7681 else
7683 fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
7684 rpt_mutex_unlock(&myrpt->lock);
7685 pthread_exit(NULL);
7687 *--tele = '/';
7688 if (myrpt->txchanname)
7690 tele = strchr(myrpt->txchanname,'/');
7691 if (!tele)
7693 fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
7694 rpt_mutex_unlock(&myrpt->lock);
7695 ast_hangup(myrpt->rxchannel);
7696 pthread_exit(NULL);
7698 *tele++ = 0;
7699 myrpt->txchannel = ast_request(myrpt->txchanname,AST_FORMAT_SLINEAR,tele,NULL);
7700 if (myrpt->txchannel)
7702 ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
7703 ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
7704 myrpt->txchannel->whentohangup = 0;
7705 myrpt->txchannel->appl = "Apprpt";
7706 myrpt->txchannel->data = "(Link Tx)";
7707 if (option_verbose > 2)
7708 ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
7709 myrpt->txchanname,tele,myrpt->txchannel->name);
7710 rpt_mutex_unlock(&myrpt->lock);
7711 ast_call(myrpt->txchannel,tele,999);
7712 rpt_mutex_lock(&myrpt->lock);
7714 else
7716 fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
7717 rpt_mutex_unlock(&myrpt->lock);
7718 ast_hangup(myrpt->rxchannel);
7719 pthread_exit(NULL);
7721 *--tele = '/';
7723 else
7725 myrpt->txchannel = myrpt->rxchannel;
7727 myrpt->remoterx = 0;
7728 myrpt->remotetx = 0;
7729 myrpt->retxtimer = 0;
7730 myrpt->remoteon = 1;
7731 myrpt->dtmfidx = -1;
7732 myrpt->dtmfbuf[0] = 0;
7733 myrpt->dtmf_time_rem = 0;
7734 myrpt->hfscanmode = 0;
7735 myrpt->hfscanstatus = 0;
7736 if (myrpt->p.startupmacro)
7738 myrpt->remchannel = chan; /* Save copy of channel */
7739 snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
7741 myrpt->reload = 0;
7742 rpt_mutex_unlock(&myrpt->lock);
7743 setrem(myrpt);
7744 ast_set_write_format(chan, AST_FORMAT_SLINEAR);
7745 ast_set_read_format(chan, AST_FORMAT_SLINEAR);
7746 /* if we are on 2w loop and are a remote, turn EC on */
7747 if (myrpt->remote && (myrpt->rxchannel == myrpt->txchannel))
7749 i = 128;
7750 ioctl(myrpt->rxchannel->fds[0],ZT_ECHOCANCEL,&i);
7752 if (chan->_state != AST_STATE_UP) {
7753 ast_answer(chan);
7756 if (ioctl(myrpt->txchannel->fds[0],ZT_GET_PARAMS,&par) != -1)
7758 if (par.rxisoffhook)
7760 ast_indicate(chan,AST_CONTROL_RADIO_KEY);
7761 myrpt->remoterx = 1;
7764 n = 0;
7765 cs[n++] = chan;
7766 cs[n++] = myrpt->rxchannel;
7767 if (myrpt->rxchannel != myrpt->txchannel)
7768 cs[n++] = myrpt->txchannel;
7769 for(;;)
7771 if (ast_check_hangup(chan)) break;
7772 if (ast_check_hangup(myrpt->rxchannel)) break;
7773 if (myrpt->reload)
7775 myrpt->reload = 0;
7776 rpt_mutex_unlock(&myrpt->lock);
7777 /* find our index, and load the vars */
7778 for(i = 0; i < nrpts; i++)
7780 if (&rpt_vars[i] == myrpt)
7782 load_rpt_vars(i,0);
7783 break;
7786 rpt_mutex_lock(&myrpt->lock);
7788 ms = MSWAIT;
7789 who = ast_waitfor_n(cs,n,&ms);
7790 if (who == NULL) ms = 0;
7791 elap = MSWAIT - ms;
7792 if (myrpt->macrotimer) myrpt->macrotimer -= elap;
7793 if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
7794 rpt_mutex_unlock(&myrpt->lock);
7795 if (!ms) continue;
7796 rem_totx = keyed;
7799 if ((!myrpt->remoterx) && (!myrpt->remotetx))
7801 if ((myrpt->retxtimer += elap) >= REDUNDANT_TX_TIME)
7803 myrpt->retxtimer = 0;
7804 ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
7806 } else myrpt->retxtimer = 0;
7807 if (rem_totx && (!myrpt->remotetx)) /* Remote base radio TX key */
7809 myrpt->remotetx = 1;
7810 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
7812 if ((!rem_totx) && myrpt->remotetx) /* Remote base radio TX unkey */
7814 myrpt->remotetx = 0;
7815 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
7818 if(myrpt->tunerequest && (!strcmp(myrpt->remote, remote_rig_ft897))){ /* ft-897 specific for now... */
7819 myrpt->tunerequest = 0;
7820 set_mode_ft897(myrpt, REM_MODE_AM);
7821 simple_command_ft897(myrpt, 8);
7822 myrpt->remotetx = 0;
7823 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
7824 if (!myrpt->remoterx)
7825 ast_indicate(chan, AST_CONTROL_RADIO_KEY);
7826 if(play_tone(chan, 800, 6000, 8192) == -1)
7827 break;
7829 rmt_telem_finish(myrpt,chan);
7830 set_mode_ft897(myrpt, 0x88);
7831 setrem(myrpt);
7834 if (myrpt->hfscanmode){
7835 myrpt->scantimer -= elap;
7836 if(myrpt->scantimer <= 0){
7837 myrpt->scantimer = REM_SCANTIME;
7838 service_scan(myrpt);
7841 if (who == chan) /* if it was a read from incomming */
7843 f = ast_read(chan);
7844 if (!f)
7846 if (debug) printf("@@@@ link:Hung Up\n");
7847 break;
7849 if (f->frametype == AST_FRAME_VOICE)
7851 /* if not transmitting, zero-out audio */
7852 if (!myrpt->remotetx)
7853 memset(f->data,0,f->datalen);
7854 ast_write(myrpt->txchannel,f);
7856 if (f->frametype == AST_FRAME_DTMF)
7858 myrpt->remchannel = chan; /* Save copy of channel */
7859 if (handle_remote_phone_dtmf(myrpt,f->subclass,&keyed,phone_mode) == -1)
7861 if (debug) printf("@@@@ rpt:Hung Up\n");
7862 ast_frfree(f);
7863 break;
7866 if (f->frametype == AST_FRAME_TEXT)
7868 myrpt->remchannel = chan; /* Save copy of channel */
7869 if (handle_remote_data(myrpt,f->data) == -1)
7871 if (debug) printf("@@@@ rpt:Hung Up\n");
7872 ast_frfree(f);
7873 break;
7876 if (f->frametype == AST_FRAME_CONTROL)
7878 if (f->subclass == AST_CONTROL_HANGUP)
7880 if (debug) printf("@@@@ rpt:Hung Up\n");
7881 ast_frfree(f);
7882 break;
7884 /* if RX key */
7885 if (f->subclass == AST_CONTROL_RADIO_KEY)
7887 if (debug == 7) printf("@@@@ rx key\n");
7888 keyed = 1;
7890 /* if RX un-key */
7891 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
7893 if (debug == 7) printf("@@@@ rx un-key\n");
7894 keyed = 0;
7897 if (myrpt->hfscanstatus){
7898 myrpt->remchannel = chan; /* Save copy of channel */
7899 myrpt->remotetx = 0;
7900 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
7901 if (!myrpt->remoterx)
7903 ast_indicate(myrpt->remchannel,AST_CONTROL_RADIO_KEY);
7905 if(myrpt->hfscanstatus < 0) {
7906 if (myrpt->hfscanstatus == -1) {
7907 if (ast_safe_sleep(myrpt->remchannel,1000) == -1) break;
7909 sayfile(myrpt->remchannel, "rpt/stop");
7911 else
7913 saynum(myrpt->remchannel, myrpt->hfscanstatus );
7915 rmt_telem_finish(myrpt,myrpt->remchannel);
7916 myrpt->hfscanstatus = 0;
7918 ast_frfree(f);
7919 rpt_mutex_lock(&myrpt->lock);
7920 c = myrpt->macrobuf[0];
7921 if (c && (!myrpt->macrotimer))
7923 myrpt->macrotimer = MACROTIME;
7924 memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1);
7925 if ((c == 'p') || (c == 'P'))
7926 myrpt->macrotimer = MACROPTIME;
7927 rpt_mutex_unlock(&myrpt->lock);
7928 if (handle_remote_dtmf_digit(myrpt,c,&keyed,0) == -1) break;
7929 continue;
7931 rpt_mutex_unlock(&myrpt->lock);
7932 continue;
7934 if (who == myrpt->rxchannel) /* if it was a read from radio */
7936 f = ast_read(myrpt->rxchannel);
7937 if (!f)
7939 if (debug) printf("@@@@ link:Hung Up\n");
7940 break;
7942 if (f->frametype == AST_FRAME_VOICE)
7944 if ((myrpt->remote) && (myrpt->remotetx))
7945 memset(f->data,0,f->datalen);
7946 ast_write(chan,f);
7948 else if (f->frametype == AST_FRAME_CONTROL)
7950 if (f->subclass == AST_CONTROL_HANGUP)
7952 if (debug) printf("@@@@ rpt:Hung Up\n");
7953 ast_frfree(f);
7954 break;
7956 /* if RX key */
7957 if (f->subclass == AST_CONTROL_RADIO_KEY)
7959 if (debug == 7) printf("@@@@ remote rx key\n");
7960 if (!myrpt->remotetx)
7962 ast_indicate(chan,AST_CONTROL_RADIO_KEY);
7963 myrpt->remoterx = 1;
7966 /* if RX un-key */
7967 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
7969 if (debug == 7) printf("@@@@ remote rx un-key\n");
7970 if (!myrpt->remotetx)
7972 ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
7973 myrpt->remoterx = 0;
7977 ast_frfree(f);
7978 continue;
7980 if ((myrpt->rxchannel != myrpt->txchannel) &&
7981 (who == myrpt->txchannel)) /* do this cuz you have to */
7983 f = ast_read(myrpt->txchannel);
7984 if (!f)
7986 if (debug) printf("@@@@ link:Hung Up\n");
7987 break;
7989 if (f->frametype == AST_FRAME_CONTROL)
7991 if (f->subclass == AST_CONTROL_HANGUP)
7993 if (debug) printf("@@@@ rpt:Hung Up\n");
7994 ast_frfree(f);
7995 break;
7998 ast_frfree(f);
7999 continue;
8003 rpt_mutex_lock(&myrpt->lock);
8004 if (myrpt->rxchannel != myrpt->txchannel) ast_hangup(myrpt->txchannel);
8005 ast_hangup(myrpt->rxchannel);
8006 myrpt->hfscanmode = 0;
8007 myrpt->hfscanstatus = 0;
8008 myrpt->remoteon = 0;
8009 rpt_mutex_unlock(&myrpt->lock);
8010 closerem(myrpt);
8011 ast_module_user_remove(u);
8012 return res;
8015 static int unload_module(void)
8017 int i;
8019 ast_module_user_hangup_all();
8020 for(i = 0; i < nrpts; i++) {
8021 if (!strcmp(rpt_vars[i].name,rpt_vars[i].p.nodes)) continue;
8022 ast_mutex_destroy(&rpt_vars[i].lock);
8024 i = ast_unregister_application(app);
8026 /* Unregister cli extensions */
8027 ast_cli_unregister_multiple(cli_rpt, sizeof(cli_rpt) / sizeof(struct ast_cli_entry));
8029 return i;
8032 static int load_module(void)
8034 struct ast_config *cfg = ast_config_load("rpt.conf");
8035 if (!cfg) {
8036 ast_log(LOG_WARNING, "No such configuration file rpt.conf\n");
8037 return AST_MODULE_LOAD_DECLINE;
8039 ast_pthread_create(&rpt_master_thread,NULL,rpt_master,cfg);
8041 /* Register cli extensions */
8042 ast_cli_register_multiple(cli_rpt, sizeof(cli_rpt) / sizeof(struct ast_cli_entry));
8044 return ast_register_application(app, rpt_exec, synopsis, descrip);
8047 static int reload(void)
8049 int n;
8051 for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
8052 return(0);
8055 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Radio Repeater / Remote Base",
8056 .load = load_module,
8057 .unload = unload_module,
8058 .reload = reload,