when loadable modules are disabled, if someone tries to load a module that does not...
[asterisk-bristuff.git] / apps / app_rpt.c
blobe1da544c91f7d13107caee7c26fcc4bcfe12de07
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 char *ourcontext;
398 char *ourcallerid;
399 char *acctcode;
400 char *ident;
401 char *tonezone;
402 char simple;
403 char *functions;
404 char *link_functions;
405 char *phone_functions;
406 char *dphone_functions;
407 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 char *memory;
418 char *macro;
419 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_debug =
730 { { "rpt", "debug", "level" }, rpt_do_debug,
731 "Enable app_rpt debugging", debug_usage };
733 static struct ast_cli_entry cli_dump =
734 { { "rpt", "dump" }, rpt_do_dump,
735 "Dump app_rpt structs for debugging", dump_usage };
737 static struct ast_cli_entry cli_stats =
738 { { "rpt", "stats" }, rpt_do_stats,
739 "Dump node statistics", dump_stats };
741 static struct ast_cli_entry cli_lstats =
742 { { "rpt", "lstats" }, rpt_do_lstats,
743 "Dump link statistics", dump_lstats };
745 static struct ast_cli_entry cli_reload =
746 { { "rpt", "reload" }, rpt_do_reload,
747 "Reload app_rpt config", reload_usage };
749 static struct ast_cli_entry cli_restart =
750 { { "rpt", "restart" }, rpt_do_restart,
751 "Restart app_rpt", restart_usage };
754 * Telemetry defaults
758 static struct telem_defaults tele_defs[] = {
759 {"ct1","|t(350,0,100,3072)(500,0,100,3072)(660,0,100,3072)"},
760 {"ct2","|t(660,880,150,3072)"},
761 {"ct3","|t(440,0,150,3072)"},
762 {"ct4","|t(550,0,150,3072)"},
763 {"ct5","|t(660,0,150,3072)"},
764 {"ct6","|t(880,0,150,3072)"},
765 {"ct7","|t(660,440,150,3072)"},
766 {"ct8","|t(700,1100,150,3072)"},
767 {"remotemon","|t(1600,0,75,2048)"},
768 {"remotetx","|t(2000,0,75,2048)(0,0,75,0)(1600,0,75,2048)"},
769 {"cmdmode","|t(900,904,200,2048)"},
770 {"functcomplete","|t(1000,0,100,2048)(0,0,100,0)(1000,0,100,2048)"}
774 * Forward decl's - these suppress compiler warnings when funcs coded further down the file than thier invokation
777 static int setrbi(struct rpt *myrpt);
782 * Define function protos for function table here
785 static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
786 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
787 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
788 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
789 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
790 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
791 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
793 * Function table
796 static struct function_table_tag function_table[] = {
797 {"cop", function_cop},
798 {"autopatchup", function_autopatchup},
799 {"autopatchdn", function_autopatchdn},
800 {"ilink", function_ilink},
801 {"status", function_status},
802 {"remote", function_remote},
803 {"macro", function_macro}
807 * Break up a delimited string into a table of substrings
809 * str - delimited string ( will be modified )
810 * strp- list of pointers to substrings (this is built by this function), NULL will be placed at end of list
811 * limit- maximum number of substrings to process
816 static int finddelim(char *str, char *strp[], int limit)
818 int i,l,inquo;
820 inquo = 0;
821 i = 0;
822 strp[i++] = str;
823 if (!*str)
825 strp[0] = 0;
826 return(0);
828 for(l = 0; *str && (l < limit) ; str++)
830 if (*str == QUOTECHR)
832 if (inquo)
834 *str = 0;
835 inquo = 0;
837 else
839 strp[i - 1] = str + 1;
840 inquo = 1;
843 if ((*str == DELIMCHR) && (!inquo))
845 *str = 0;
846 l++;
847 strp[i++] = str + 1;
850 strp[i] = 0;
851 return(i);
856 * Match a keyword in a list, and return index of string plus 1 if there was a match,
857 * else return 0. If param is passed in non-null, then it will be set to the first character past the match
860 static int matchkeyword(char *string, char **param, char *keywords[])
862 int i,ls;
863 for( i = 0 ; keywords[i] ; i++){
864 ls = strlen(keywords[i]);
865 if(!ls){
866 *param = NULL;
867 return 0;
869 if(!strncmp(string, keywords[i], ls)){
870 if(param)
871 *param = string + ls;
872 return i + 1;
875 param = NULL;
876 return 0;
880 * Skip characters in string which are in charlist, and return a pointer to the
881 * first non-matching character
884 static char *skipchars(char *string, char *charlist)
886 int i;
887 while(*string){
888 for(i = 0; charlist[i] ; i++){
889 if(*string == charlist[i]){
890 string++;
891 break;
894 if(!charlist[i])
895 return string;
897 return string;
902 static int myatoi(char *str)
904 int ret;
906 if (str == NULL) return -1;
907 /* leave this %i alone, non-base-10 input is useful here */
908 if (sscanf(str,"%i",&ret) != 1) return -1;
909 return ret;
913 #ifdef __RPT_NOTCH
915 /* rpt filter routine */
916 static void rpt_filter(struct rpt *myrpt, volatile short *buf, int len)
918 int i,j;
919 struct rptfilter *f;
921 for(i = 0; i < len; i++)
923 for(j = 0; j < MAXFILTERS; j++)
925 f = &myrpt->filters[j];
926 if (!*f->desc) continue;
927 f->x0 = f->x1; f->x1 = f->x2;
928 f->x2 = ((float)buf[i]) / f->gain;
929 f->y0 = f->y1; f->y1 = f->y2;
930 f->y2 = (f->x0 + f->x2) + f->const0 * f->x1
931 + (f->const1 * f->y0) + (f->const2 * f->y1);
932 buf[i] = (short)f->y2;
937 #endif
939 /* Retrieve an int from a config file */
941 static int retrieve_astcfgint(struct rpt *myrpt,char *category, char *name, int min, int max, int defl)
943 char *var;
944 int ret;
946 var = ast_variable_retrieve(myrpt->cfg, category, name);
947 if(var){
948 ret = myatoi(var);
949 if(ret < min)
950 ret = min;
951 if(ret > max)
952 ret = max;
954 else
955 ret = defl;
956 return ret;
960 static void load_rpt_vars(int n,int init)
962 char *this,*val;
963 int j,longestnode;
964 struct ast_variable *vp;
965 struct ast_config *cfg;
966 #ifdef __RPT_NOTCH
967 int i;
968 char *strs[100];
969 #endif
971 if (option_verbose > 2)
972 ast_verbose(VERBOSE_PREFIX_3 "%s config for repeater %s\n",
973 (init) ? "Loading initial" : "Re-Loading",rpt_vars[n].name);
974 ast_mutex_lock(&rpt_vars[n].lock);
975 if (rpt_vars[n].cfg) ast_config_destroy(rpt_vars[n].cfg);
976 cfg = ast_config_load("rpt.conf");
977 if (!cfg) {
978 ast_mutex_unlock(&rpt_vars[n].lock);
979 ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf. Radio Repeater disabled.\n");
980 pthread_exit(NULL);
982 rpt_vars[n].cfg = cfg;
983 this = rpt_vars[n].name;
984 memset(&rpt_vars[n].p,0,sizeof(rpt_vars[n].p));
985 if (init)
987 char *cp;
988 int savearea = (char *)&rpt_vars[n].p - (char *)&rpt_vars[n];
990 cp = (char *) &rpt_vars[n].p;
991 memset(cp + sizeof(rpt_vars[n].p),0,
992 sizeof(rpt_vars[n]) - (sizeof(rpt_vars[n].p) + savearea));
993 rpt_vars[n].tele.next = &rpt_vars[n].tele;
994 rpt_vars[n].tele.prev = &rpt_vars[n].tele;
995 rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
996 rpt_vars[n].tailmessagen = 0;
998 #ifdef __RPT_NOTCH
999 /* zot out filters stuff */
1000 memset(&rpt_vars[n].filters,0,sizeof(rpt_vars[n].filters));
1001 #endif
1002 val = ast_variable_retrieve(cfg,this,"context");
1003 if (val) rpt_vars[n].p.ourcontext = val;
1004 else rpt_vars[n].p.ourcontext = this;
1005 val = ast_variable_retrieve(cfg,this,"callerid");
1006 if (val) rpt_vars[n].p.ourcallerid = val;
1007 val = ast_variable_retrieve(cfg,this,"accountcode");
1008 if (val) rpt_vars[n].p.acctcode = val;
1009 val = ast_variable_retrieve(cfg,this,"idrecording");
1010 if (val) rpt_vars[n].p.ident = val;
1011 val = ast_variable_retrieve(cfg,this,"hangtime");
1012 if (val) rpt_vars[n].p.hangtime = atoi(val);
1013 else rpt_vars[n].p.hangtime = HANGTIME;
1014 val = ast_variable_retrieve(cfg,this,"totime");
1015 if (val) rpt_vars[n].p.totime = atoi(val);
1016 else rpt_vars[n].p.totime = TOTIME;
1017 rpt_vars[n].p.tailmessagetime = retrieve_astcfgint(&rpt_vars[n],this, "tailmessagetime", 0, 2400000, 0);
1018 rpt_vars[n].p.tailsquashedtime = retrieve_astcfgint(&rpt_vars[n],this, "tailsquashedtime", 0, 2400000, 0);
1019 rpt_vars[n].p.duplex = retrieve_astcfgint(&rpt_vars[n],this,"duplex",0,4,2);
1020 rpt_vars[n].p.idtime = retrieve_astcfgint(&rpt_vars[n],this, "idtime", 60000, 2400000, IDTIME); /* Enforce a min max */
1021 rpt_vars[n].p.politeid = retrieve_astcfgint(&rpt_vars[n],this, "politeid", 30000, 300000, POLITEID); /* Enforce a min max */
1022 val = ast_variable_retrieve(cfg,this,"tonezone");
1023 if (val) rpt_vars[n].p.tonezone = val;
1024 rpt_vars[n].p.tailmessages[0] = 0;
1025 rpt_vars[n].p.tailmessagemax = 0;
1026 val = ast_variable_retrieve(cfg,this,"tailmessagelist");
1027 if (val) rpt_vars[n].p.tailmessagemax = finddelim(val, rpt_vars[n].p.tailmessages, 500);
1028 val = ast_variable_retrieve(cfg,this,"memory");
1029 if (!val) val = MEMORY;
1030 rpt_vars[n].p.memory = val;
1031 val = ast_variable_retrieve(cfg,this,"macro");
1032 if (!val) val = MACRO;
1033 rpt_vars[n].p.macro = val;
1034 val = ast_variable_retrieve(cfg,this,"startup_macro");
1035 if (val) rpt_vars[n].p.startupmacro = val;
1036 val = ast_variable_retrieve(cfg,this,"iobase");
1037 /* do not use atoi() here, we need to be able to have
1038 the input specified in hex or decimal so we use
1039 sscanf with a %i */
1040 if ((!val) || (sscanf(val,"%i",&rpt_vars[n].p.iobase) != 1))
1041 rpt_vars[n].p.iobase = DEFAULT_IOBASE;
1042 val = ast_variable_retrieve(cfg,this,"functions");
1043 if (!val)
1045 val = FUNCTIONS;
1046 rpt_vars[n].p.simple = 1;
1048 rpt_vars[n].p.functions = val;
1049 val = ast_variable_retrieve(cfg,this,"link_functions");
1050 if (val) rpt_vars[n].p.link_functions = val;
1051 else
1052 rpt_vars[n].p.link_functions = rpt_vars[n].p.functions;
1053 val = ast_variable_retrieve(cfg,this,"phone_functions");
1054 if (val) rpt_vars[n].p.phone_functions = val;
1055 val = ast_variable_retrieve(cfg,this,"dphone_functions");
1056 if (val) rpt_vars[n].p.dphone_functions = val;
1057 val = ast_variable_retrieve(cfg,this,"funcchar");
1058 if (!val) rpt_vars[n].p.funcchar = FUNCCHAR; else
1059 rpt_vars[n].p.funcchar = *val;
1060 val = ast_variable_retrieve(cfg,this,"endchar");
1061 if (!val) rpt_vars[n].p.endchar = ENDCHAR; else
1062 rpt_vars[n].p.endchar = *val;
1063 val = ast_variable_retrieve(cfg,this,"nobusyout");
1064 if (val) rpt_vars[n].p.nobusyout = ast_true(val);
1065 val = ast_variable_retrieve(cfg,this,"nodes");
1066 if (!val) val = NODES;
1067 rpt_vars[n].p.nodes = val;
1068 #ifdef __RPT_NOTCH
1069 val = ast_variable_retrieve(cfg,this,"rxnotch");
1070 if (val) {
1071 i = finddelim(val,strs,MAXFILTERS * 2);
1072 i &= ~1; /* force an even number, rounded down */
1073 if (i >= 2) for(j = 0; j < i; j += 2)
1075 rpt_mknotch(atof(strs[j]),atof(strs[j + 1]),
1076 &rpt_vars[n].filters[j >> 1].gain,
1077 &rpt_vars[n].filters[j >> 1].const0,
1078 &rpt_vars[n].filters[j >> 1].const1,
1079 &rpt_vars[n].filters[j >> 1].const2);
1080 sprintf(rpt_vars[n].filters[j >> 1].desc,"%s Hz, BW = %s",
1081 strs[j],strs[j + 1]);
1085 #endif
1086 longestnode = 0;
1088 vp = ast_variable_browse(cfg, rpt_vars[n].p.nodes);
1090 while(vp){
1091 j = strlen(vp->name);
1092 if (j > longestnode)
1093 longestnode = j;
1094 vp = vp->next;
1097 rpt_vars[n].longestnode = longestnode;
1100 * For this repeater, Determine the length of the longest function
1102 rpt_vars[n].longestfunc = 0;
1103 vp = ast_variable_browse(cfg, rpt_vars[n].p.functions);
1104 while(vp){
1105 j = strlen(vp->name);
1106 if (j > rpt_vars[n].longestfunc)
1107 rpt_vars[n].longestfunc = j;
1108 vp = vp->next;
1111 * For this repeater, Determine the length of the longest function
1113 rpt_vars[n].link_longestfunc = 0;
1114 vp = ast_variable_browse(cfg, rpt_vars[n].p.link_functions);
1115 while(vp){
1116 j = strlen(vp->name);
1117 if (j > rpt_vars[n].link_longestfunc)
1118 rpt_vars[n].link_longestfunc = j;
1119 vp = vp->next;
1121 rpt_vars[n].phone_longestfunc = 0;
1122 if (rpt_vars[n].p.phone_functions)
1124 vp = ast_variable_browse(cfg, rpt_vars[n].p.phone_functions);
1125 while(vp){
1126 j = strlen(vp->name);
1127 if (j > rpt_vars[n].phone_longestfunc)
1128 rpt_vars[n].phone_longestfunc = j;
1129 vp = vp->next;
1132 rpt_vars[n].dphone_longestfunc = 0;
1133 if (rpt_vars[n].p.dphone_functions)
1135 vp = ast_variable_browse(cfg, rpt_vars[n].p.dphone_functions);
1136 while(vp){
1137 j = strlen(vp->name);
1138 if (j > rpt_vars[n].dphone_longestfunc)
1139 rpt_vars[n].dphone_longestfunc = j;
1140 vp = vp->next;
1143 rpt_vars[n].macro_longest = 1;
1144 vp = ast_variable_browse(cfg, rpt_vars[n].p.macro);
1145 while(vp){
1146 j = strlen(vp->name);
1147 if (j > rpt_vars[n].macro_longest)
1148 rpt_vars[n].macro_longest = j;
1149 vp = vp->next;
1151 ast_mutex_unlock(&rpt_vars[n].lock);
1155 * Enable or disable debug output at a given level at the console
1158 static int rpt_do_debug(int fd, int argc, char *argv[])
1160 int newlevel;
1162 if (argc != 4)
1163 return RESULT_SHOWUSAGE;
1164 newlevel = myatoi(argv[3]);
1165 if((newlevel < 0) || (newlevel > 7))
1166 return RESULT_SHOWUSAGE;
1167 if(newlevel)
1168 ast_cli(fd, "app_rpt Debugging enabled, previous level: %d, new level: %d\n", debug, newlevel);
1169 else
1170 ast_cli(fd, "app_rpt Debugging disabled\n");
1172 debug = newlevel;
1173 return RESULT_SUCCESS;
1177 * Dump rpt struct debugging onto console
1180 static int rpt_do_dump(int fd, int argc, char *argv[])
1182 int i;
1184 if (argc != 3)
1185 return RESULT_SHOWUSAGE;
1187 for(i = 0; i < nrpts; i++)
1189 if (!strcmp(argv[2],rpt_vars[i].name))
1191 rpt_vars[i].disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
1192 ast_cli(fd, "app_rpt struct dump requested for node %s\n",argv[2]);
1193 return RESULT_SUCCESS;
1196 return RESULT_FAILURE;
1200 * Dump statistics onto console
1203 static int rpt_do_stats(int fd, int argc, char *argv[])
1205 int i,j;
1206 int dailytxtime, dailykerchunks;
1207 int totalkerchunks, dailykeyups, totalkeyups, timeouts;
1208 int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
1209 long long totaltxtime;
1210 struct rpt_link *l;
1211 char *listoflinks[MAX_STAT_LINKS];
1212 char *lastnodewhichkeyedusup, *lastdtmfcommand;
1213 char *tot_state, *ider_state, *patch_state;
1214 char *reverse_patch_state, *enable_state, *input_signal, *called_number;
1215 struct rpt *myrpt;
1217 static char *not_applicable = "N/A";
1219 if(argc != 3)
1220 return RESULT_SHOWUSAGE;
1222 for(i = 0 ; i <= MAX_STAT_LINKS; i++)
1223 listoflinks[i] = NULL;
1225 tot_state = ider_state =
1226 patch_state = reverse_patch_state =
1227 input_signal = called_number =
1228 lastdtmfcommand = not_applicable;
1230 for(i = 0; i < nrpts; i++)
1232 if (!strcmp(argv[2],rpt_vars[i].name)){
1233 /* Make a copy of all stat variables while locked */
1234 myrpt = &rpt_vars[i];
1235 rpt_mutex_lock(&myrpt->lock); /* LOCK */
1237 dailytxtime = myrpt->dailytxtime;
1238 totaltxtime = myrpt->totaltxtime;
1239 dailykeyups = myrpt->dailykeyups;
1240 totalkeyups = myrpt->totalkeyups;
1241 dailykerchunks = myrpt->dailykerchunks;
1242 totalkerchunks = myrpt->totalkerchunks;
1243 dailyexecdcommands = myrpt->dailyexecdcommands;
1244 totalexecdcommands = myrpt->totalexecdcommands;
1245 timeouts = myrpt->timeouts;
1247 /* Traverse the list of connected nodes */
1248 reverse_patch_state = "DOWN";
1249 j = 0;
1250 l = myrpt->links.next;
1251 while(l != &myrpt->links){
1252 if (l->name[0] == '0'){ /* Skip '0' nodes */
1253 reverse_patch_state = "UP";
1254 l = l->next;
1255 continue;
1257 listoflinks[j] = ast_strdupa(l->name);
1258 if(listoflinks[j])
1259 j++;
1260 l = l->next;
1263 lastnodewhichkeyedusup = ast_strdupa(myrpt->lastnodewhichkeyedusup);
1264 if((!lastnodewhichkeyedusup) || (!strlen(lastnodewhichkeyedusup)))
1265 lastnodewhichkeyedusup = not_applicable;
1267 if(myrpt->keyed)
1268 input_signal = "YES";
1269 else
1270 input_signal = "NO";
1272 if(myrpt->enable)
1273 enable_state = "YES";
1274 else
1275 enable_state = "NO";
1277 if(!myrpt->totimer)
1278 tot_state = "TIMED OUT!";
1279 else if(myrpt->totimer != myrpt->p.totime)
1280 tot_state = "ARMED";
1281 else
1282 tot_state = "RESET";
1284 if(myrpt->tailid)
1285 ider_state = "QUEUED IN TAIL";
1286 else if(myrpt->mustid)
1287 ider_state = "QUEUED FOR CLEANUP";
1288 else
1289 ider_state = "CLEAN";
1291 switch(myrpt->callmode){
1292 case 1:
1293 patch_state = "DIALING";
1294 break;
1295 case 2:
1296 patch_state = "CONNECTING";
1297 break;
1298 case 3:
1299 patch_state = "UP";
1300 break;
1302 case 4:
1303 patch_state = "CALL FAILED";
1304 break;
1306 default:
1307 patch_state = "DOWN";
1310 if(strlen(myrpt->exten)){
1311 called_number = ast_strdupa(myrpt->exten);
1312 if(!called_number)
1313 called_number = not_applicable;
1316 if(strlen(myrpt->lastdtmfcommand)){
1317 lastdtmfcommand = ast_strdupa(myrpt->lastdtmfcommand);
1318 if(!lastdtmfcommand)
1319 lastdtmfcommand = not_applicable;
1322 rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
1324 ast_cli(fd, "************************ NODE %s STATISTICS *************************\n\n", myrpt->name);
1325 ast_cli(fd, "Signal on input..................................: %s\n", input_signal);
1326 ast_cli(fd, "Transmitter enabled..............................: %s\n", enable_state);
1327 ast_cli(fd, "Time out timer state.............................: %s\n", tot_state);
1328 ast_cli(fd, "Time outs since system initialization............: %d\n", timeouts);
1329 ast_cli(fd, "Identifier state.................................: %s\n", ider_state);
1330 ast_cli(fd, "Kerchunks today..................................: %d\n", dailykerchunks);
1331 ast_cli(fd, "Kerchunks since system initialization............: %d\n", totalkerchunks);
1332 ast_cli(fd, "Keyups today.....................................: %d\n", dailykeyups);
1333 ast_cli(fd, "Keyups since system initialization...............: %d\n", totalkeyups);
1334 ast_cli(fd, "DTMF commands today..............................: %d\n", dailyexecdcommands);
1335 ast_cli(fd, "DTMF commands since system initialization........: %d\n", totalexecdcommands);
1336 ast_cli(fd, "Last DTMF command executed.......................: %s\n", lastdtmfcommand);
1338 hours = dailytxtime/3600000;
1339 dailytxtime %= 3600000;
1340 minutes = dailytxtime/60000;
1341 dailytxtime %= 60000;
1342 seconds = dailytxtime/1000;
1343 dailytxtime %= 1000;
1345 ast_cli(fd, "TX time today ...................................: %02d:%02d:%02d.%d\n",
1346 hours, minutes, seconds, dailytxtime);
1348 hours = (int) totaltxtime/3600000;
1349 totaltxtime %= 3600000;
1350 minutes = (int) totaltxtime/60000;
1351 totaltxtime %= 60000;
1352 seconds = (int) totaltxtime/1000;
1353 totaltxtime %= 1000;
1355 ast_cli(fd, "TX time since system initialization..............: %02d:%02d:%02d.%d\n",
1356 hours, minutes, seconds, (int) totaltxtime);
1357 ast_cli(fd, "Nodes currently connected to us..................: ");
1358 for(j = 0 ;; j++){
1359 if(!listoflinks[j]){
1360 if(!j){
1361 ast_cli(fd,"<NONE>");
1363 break;
1365 ast_cli(fd, "%s", listoflinks[j]);
1366 if(j % 4 == 3){
1367 ast_cli(fd, "\n");
1368 ast_cli(fd, " : ");
1370 else{
1371 if(listoflinks[j + 1])
1372 ast_cli(fd, ", ");
1375 ast_cli(fd,"\n");
1377 ast_cli(fd, "Last node which transmitted to us................: %s\n", lastnodewhichkeyedusup);
1378 ast_cli(fd, "Autopatch state..................................: %s\n", patch_state);
1379 ast_cli(fd, "Autopatch called number..........................: %s\n", called_number);
1380 ast_cli(fd, "Reverse patch/IAXRPT connected...................: %s\n\n", reverse_patch_state);
1382 return RESULT_SUCCESS;
1385 return RESULT_FAILURE;
1389 * Link stats function
1392 static int rpt_do_lstats(int fd, int argc, char *argv[])
1394 int i,j;
1395 struct rpt *myrpt;
1396 struct rpt_link *l;
1397 struct rpt_lstat *s,*t;
1398 struct rpt_lstat s_head;
1399 if(argc != 3)
1400 return RESULT_SHOWUSAGE;
1402 s = NULL;
1403 s_head.next = &s_head;
1404 s_head.prev = &s_head;
1406 for(i = 0; i < nrpts; i++)
1408 if (!strcmp(argv[2],rpt_vars[i].name)){
1409 /* Make a copy of all stat variables while locked */
1410 myrpt = &rpt_vars[i];
1411 rpt_mutex_lock(&myrpt->lock); /* LOCK */
1412 /* Traverse the list of connected nodes */
1413 j = 0;
1414 l = myrpt->links.next;
1415 while(l != &myrpt->links){
1416 if (l->name[0] == '0'){ /* Skip '0' nodes */
1417 l = l->next;
1418 continue;
1420 if((s = (struct rpt_lstat *) malloc(sizeof(struct rpt_lstat))) == NULL){
1421 ast_log(LOG_ERROR, "Malloc failed in rpt_do_lstats\n");
1422 rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
1423 return RESULT_FAILURE;
1425 memset(s, 0, sizeof(struct rpt_lstat));
1426 strncpy(s->name, l->name, MAXREMSTR - 1);
1427 pbx_substitute_variables_helper(l->chan, "${IAXPEER(CURRENTCHANNEL)}", s->peer, MAXPEERSTR - 1);
1428 s->mode = l->mode;
1429 s->outbound = l->outbound;
1430 s->reconnects = l->reconnects;
1431 s->connecttime = l->connecttime;
1432 insque((struct qelem *) s, (struct qelem *) s_head.next);
1433 l = l->next;
1435 rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
1436 ast_cli(fd, "NODE PEER RECONNECTS DIRECTION CONNECT TIME\n");
1437 ast_cli(fd, "---- ---- ---------- --------- ------------\n");
1439 for(s = s_head.next; s != &s_head; s = s->next){
1440 int hours, minutes, seconds;
1441 long long connecttime = s->connecttime;
1442 char conntime[31];
1443 hours = (int) connecttime/3600000;
1444 connecttime %= 3600000;
1445 minutes = (int) connecttime/60000;
1446 connecttime %= 60000;
1447 seconds = (int) connecttime/1000;
1448 connecttime %= 1000;
1449 snprintf(conntime, 30, "%02d:%02d:%02d.%d",
1450 hours, minutes, seconds, (int) connecttime);
1451 conntime[30] = 0;
1452 ast_cli(fd, "%-10s%-20s%-12d%-11s%-30s\n",
1453 s->name, s->peer, s->reconnects, (s->outbound)? "OUT":"IN", conntime);
1455 /* destroy our local link queue */
1456 s = s_head.next;
1457 while(s != &s_head){
1458 t = s;
1459 s = s->next;
1460 remque((struct qelem *)t);
1461 free(t);
1463 return RESULT_SUCCESS;
1466 return RESULT_FAILURE;
1470 * reload vars
1473 static int rpt_do_reload(int fd, int argc, char *argv[])
1475 int n;
1477 if (argc > 2) return RESULT_SHOWUSAGE;
1479 for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
1481 return RESULT_FAILURE;
1485 * restart app_rpt
1488 static int rpt_do_restart(int fd, int argc, char *argv[])
1490 int i;
1492 if (argc > 2) return RESULT_SHOWUSAGE;
1493 for(i = 0; i < nrpts; i++)
1495 if (rpt_vars[i].rxchannel) ast_softhangup(rpt_vars[i].rxchannel,AST_SOFTHANGUP_DEV);
1497 return RESULT_FAILURE;
1500 static int play_tone_pair(struct ast_channel *chan, int f1, int f2, int duration, int amplitude)
1502 int res;
1504 if ((res = ast_tonepair_start(chan, f1, f2, duration, amplitude)))
1505 return res;
1507 while(chan->generatordata) {
1508 if (ast_safe_sleep(chan,1)) return -1;
1511 return 0;
1514 static int play_tone(struct ast_channel *chan, int freq, int duration, int amplitude)
1516 return play_tone_pair(chan, freq, 0, duration, amplitude);
1519 static int play_silence(struct ast_channel *chan, int duration)
1521 return play_tone_pair(chan, 0, 0, duration, 0);
1525 static int send_morse(struct ast_channel *chan, char *string, int speed, int freq, int amplitude)
1528 static struct morse_bits mbits[] = {
1529 {0, 0}, /* SPACE */
1530 {0, 0},
1531 {6, 18},/* " */
1532 {0, 0},
1533 {7, 72},/* $ */
1534 {0, 0},
1535 {0, 0},
1536 {6, 30},/* ' */
1537 {5, 13},/* ( */
1538 {6, 29},/* ) */
1539 {0, 0},
1540 {5, 10},/* + */
1541 {6, 51},/* , */
1542 {6, 33},/* - */
1543 {6, 42},/* . */
1544 {5, 9}, /* / */
1545 {5, 31},/* 0 */
1546 {5, 30},/* 1 */
1547 {5, 28},/* 2 */
1548 {5, 24},/* 3 */
1549 {5, 16},/* 4 */
1550 {5, 0}, /* 5 */
1551 {5, 1}, /* 6 */
1552 {5, 3}, /* 7 */
1553 {5, 7}, /* 8 */
1554 {5, 15},/* 9 */
1555 {6, 7}, /* : */
1556 {6, 21},/* ; */
1557 {0, 0},
1558 {5, 33},/* = */
1559 {0, 0},
1560 {6, 12},/* ? */
1561 {0, 0},
1562 {2, 2}, /* A */
1563 {4, 1}, /* B */
1564 {4, 5}, /* C */
1565 {3, 1}, /* D */
1566 {1, 0}, /* E */
1567 {4, 4}, /* F */
1568 {3, 3}, /* G */
1569 {4, 0}, /* H */
1570 {2, 0}, /* I */
1571 {4, 14},/* J */
1572 {3, 5}, /* K */
1573 {4, 2}, /* L */
1574 {2, 3}, /* M */
1575 {2, 1}, /* N */
1576 {3, 7}, /* O */
1577 {4, 6}, /* P */
1578 {4, 11},/* Q */
1579 {3, 2}, /* R */
1580 {3, 0}, /* S */
1581 {1, 1}, /* T */
1582 {3, 4}, /* U */
1583 {4, 8}, /* V */
1584 {3, 6}, /* W */
1585 {4, 9}, /* X */
1586 {4, 13},/* Y */
1587 {4, 3} /* Z */
1591 int dottime;
1592 int dashtime;
1593 int intralettertime;
1594 int interlettertime;
1595 int interwordtime;
1596 int len, ddcomb;
1597 int res;
1598 int c;
1599 int i;
1600 int flags;
1602 res = 0;
1604 /* Approximate the dot time from the speed arg. */
1606 dottime = 900/speed;
1608 /* Establish timing releationships */
1610 dashtime = 3 * dottime;
1611 intralettertime = dottime;
1612 interlettertime = dottime * 4 ;
1613 interwordtime = dottime * 7;
1615 for(;(*string) && (!res); string++){
1617 c = *string;
1619 /* Convert lower case to upper case */
1621 if((c >= 'a') && (c <= 'z'))
1622 c -= 0x20;
1624 /* Can't deal with any char code greater than Z, skip it */
1626 if(c > 'Z')
1627 continue;
1629 /* If space char, wait the inter word time */
1631 if(c == ' '){
1632 if(!res)
1633 res = play_silence(chan, interwordtime);
1634 continue;
1637 /* Subtract out control char offset to match our table */
1639 c -= 0x20;
1641 /* Get the character data */
1643 len = mbits[c].len;
1644 ddcomb = mbits[c].ddcomb;
1646 /* Send the character */
1648 for(; len ; len--){
1649 if(!res)
1650 res = play_tone(chan, freq, (ddcomb & 1) ? dashtime : dottime, amplitude);
1651 if(!res)
1652 res = play_silence(chan, intralettertime);
1653 ddcomb >>= 1;
1656 /* Wait the interletter time */
1658 if(!res)
1659 res = play_silence(chan, interlettertime - intralettertime);
1662 /* Wait for all the frames to be sent */
1664 if (!res)
1665 res = ast_waitstream(chan, "");
1666 ast_stopstream(chan);
1669 * Wait for the zaptel driver to physically write the tone blocks to the hardware
1672 for(i = 0; i < 20 ; i++){
1673 flags = ZT_IOMUX_WRITEEMPTY | ZT_IOMUX_NOWAIT;
1674 res = ioctl(chan->fds[0], ZT_IOMUX, &flags);
1675 if(flags & ZT_IOMUX_WRITEEMPTY)
1676 break;
1677 if( ast_safe_sleep(chan, 50)){
1678 res = -1;
1679 break;
1684 return res;
1687 static int send_tone_telemetry(struct ast_channel *chan, char *tonestring)
1689 char *stringp;
1690 char *tonesubset;
1691 int f1,f2;
1692 int duration;
1693 int amplitude;
1694 int res;
1695 int i;
1696 int flags;
1698 res = 0;
1700 stringp = ast_strdupa(tonestring);
1702 for(;tonestring;){
1703 tonesubset = strsep(&stringp,")");
1704 if(!tonesubset)
1705 break;
1706 if(sscanf(tonesubset,"(%d,%d,%d,%d", &f1, &f2, &duration, &amplitude) != 4)
1707 break;
1708 res = play_tone_pair(chan, f1, f2, duration, amplitude);
1709 if(res)
1710 break;
1712 if(!res)
1713 res = play_tone_pair(chan, 0, 0, 100, 0); /* This is needed to ensure the last tone segment is timed correctly */
1715 if (!res)
1716 res = ast_waitstream(chan, "");
1717 ast_stopstream(chan);
1720 * Wait for the zaptel driver to physically write the tone blocks to the hardware
1723 for(i = 0; i < 20 ; i++){
1724 flags = ZT_IOMUX_WRITEEMPTY | ZT_IOMUX_NOWAIT;
1725 res = ioctl(chan->fds[0], ZT_IOMUX, &flags);
1726 if(flags & ZT_IOMUX_WRITEEMPTY)
1727 break;
1728 if( ast_safe_sleep(chan, 50)){
1729 res = -1;
1730 break;
1734 return res;
1739 static int sayfile(struct ast_channel *mychannel,char *fname)
1741 int res;
1743 res = ast_streamfile(mychannel, fname, mychannel->language);
1744 if (!res)
1745 res = ast_waitstream(mychannel, "");
1746 else
1747 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1748 ast_stopstream(mychannel);
1749 return res;
1752 static int saycharstr(struct ast_channel *mychannel,char *str)
1754 int res;
1756 res = ast_say_character_str(mychannel,str,NULL,mychannel->language);
1757 if (!res)
1758 res = ast_waitstream(mychannel, "");
1759 else
1760 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1761 ast_stopstream(mychannel);
1762 return res;
1765 static int saynum(struct ast_channel *mychannel, int num)
1767 int res;
1768 res = ast_say_number(mychannel, num, NULL, mychannel->language, NULL);
1769 if(!res)
1770 res = ast_waitstream(mychannel, "");
1771 else
1772 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1773 ast_stopstream(mychannel);
1774 return res;
1778 static int telem_any(struct rpt *myrpt,struct ast_channel *chan, char *entry)
1780 int res;
1781 char c;
1783 static int morsespeed;
1784 static int morsefreq;
1785 static int morseampl;
1786 static int morseidfreq = 0;
1787 static int morseidampl;
1788 static char mcat[] = MORSE;
1790 res = 0;
1792 if(!morseidfreq){ /* Get the morse parameters if not already loaded */
1793 morsespeed = retrieve_astcfgint(myrpt, mcat, "speed", 5, 20, 20);
1794 morsefreq = retrieve_astcfgint(myrpt, mcat, "frequency", 300, 3000, 800);
1795 morseampl = retrieve_astcfgint(myrpt, mcat, "amplitude", 200, 8192, 4096);
1796 morseidampl = retrieve_astcfgint(myrpt, mcat, "idamplitude", 200, 8192, 2048);
1797 morseidfreq = retrieve_astcfgint(myrpt, mcat, "idfrequency", 300, 3000, 330);
1800 /* Is it a file, or a tone sequence? */
1802 if(entry[0] == '|'){
1803 c = entry[1];
1804 if((c >= 'a')&&(c <= 'z'))
1805 c -= 0x20;
1807 switch(c){
1808 case 'I': /* Morse ID */
1809 res = send_morse(chan, entry + 2, morsespeed, morseidfreq, morseidampl);
1810 break;
1812 case 'M': /* Morse Message */
1813 res = send_morse(chan, entry + 2, morsespeed, morsefreq, morseampl);
1814 break;
1816 case 'T': /* Tone sequence */
1817 res = send_tone_telemetry(chan, entry + 2);
1818 break;
1819 default:
1820 res = -1;
1823 else
1824 res = sayfile(chan, entry); /* File */
1825 return res;
1829 * This function looks up a telemetry name in the config file, and does a telemetry response as configured.
1831 * 4 types of telemtry are handled: Morse ID, Morse Message, Tone Sequence, and a File containing a recording.
1834 static int telem_lookup(struct rpt *myrpt,struct ast_channel *chan, char *node, char *name)
1837 int res;
1838 int i;
1839 char *entry;
1840 char *telemetry;
1841 char *telemetry_save;
1843 res = 0;
1844 telemetry_save = NULL;
1845 entry = NULL;
1847 /* Retrieve the section name for telemetry from the node section */
1848 telemetry = ast_variable_retrieve(myrpt->cfg, node, TELEMETRY);
1849 if(telemetry ){
1850 telemetry_save = ast_strdupa(telemetry);
1851 if(!telemetry_save){
1852 ast_log(LOG_WARNING,"ast_strdupa() failed in telem_lookup()\n");
1853 return res;
1855 entry = ast_variable_retrieve(myrpt->cfg, telemetry_save, name);
1858 /* Try to look up the telemetry name */
1860 if(!entry){
1861 /* Telemetry name wasn't found in the config file, use the default */
1862 for(i = 0; i < sizeof(tele_defs)/sizeof(struct telem_defaults) ; i++){
1863 if(!strcasecmp(tele_defs[i].name, name))
1864 entry = tele_defs[i].value;
1867 if(entry){
1868 if(strlen(entry))
1869 telem_any(myrpt,chan, entry);
1871 else{
1872 res = -1;
1874 return res;
1878 * Retrieve a wait interval
1881 static int get_wait_interval(struct rpt *myrpt, int type)
1883 int interval;
1884 char *wait_times;
1885 char *wait_times_save;
1887 wait_times_save = NULL;
1888 wait_times = ast_variable_retrieve(myrpt->cfg, myrpt->name, "wait_times");
1890 if(wait_times){
1891 wait_times_save = ast_strdupa(wait_times);
1892 if(!wait_times_save){
1893 ast_log(LOG_WARNING, "Out of memory in wait_interval()\n");
1894 wait_times = NULL;
1898 switch(type){
1899 case DLY_TELEM:
1900 if(wait_times)
1901 interval = retrieve_astcfgint(myrpt,wait_times_save, "telemwait", 500, 5000, 1000);
1902 else
1903 interval = 1000;
1904 break;
1906 case DLY_ID:
1907 if(wait_times)
1908 interval = retrieve_astcfgint(myrpt,wait_times_save, "idwait",250,5000,500);
1909 else
1910 interval = 500;
1911 break;
1913 case DLY_UNKEY:
1914 if(wait_times)
1915 interval = retrieve_astcfgint(myrpt,wait_times_save, "unkeywait",500,5000,1000);
1916 else
1917 interval = 1000;
1918 break;
1920 case DLY_CALLTERM:
1921 if(wait_times)
1922 interval = retrieve_astcfgint(myrpt,wait_times_save, "calltermwait",500,5000,1500);
1923 else
1924 interval = 1500;
1925 break;
1927 default:
1928 return 0;
1930 return interval;
1935 * Wait a configurable interval of time
1939 static void wait_interval(struct rpt *myrpt, int type, struct ast_channel *chan)
1941 int interval;
1942 interval = get_wait_interval(myrpt, type);
1943 if(debug)
1944 ast_log(LOG_NOTICE," Delay interval = %d\n", interval);
1945 if(interval)
1946 ast_safe_sleep(chan,interval);
1947 if(debug)
1948 ast_log(LOG_NOTICE,"Delay complete\n");
1949 return;
1953 static void *rpt_tele_thread(void *this)
1955 ZT_CONFINFO ci; /* conference info */
1956 int res = 0,haslink,hastx,hasremote,imdone = 0, unkeys_queued, x;
1957 struct rpt_tele *mytele = (struct rpt_tele *)this;
1958 struct rpt_tele *tlist;
1959 struct rpt *myrpt;
1960 struct rpt_link *l,*m,linkbase;
1961 struct ast_channel *mychannel;
1962 char *p,*ct,*ct_copy,*ident, *nodename;
1963 time_t t;
1964 struct tm localtm;
1966 /* get a pointer to myrpt */
1967 myrpt = mytele->rpt;
1969 /* Snag copies of a few key myrpt variables */
1970 rpt_mutex_lock(&myrpt->lock);
1971 nodename = ast_strdupa(myrpt->name);
1972 ident = ast_strdupa(myrpt->p.ident);
1973 rpt_mutex_unlock(&myrpt->lock);
1975 /* allocate a pseudo-channel thru asterisk */
1976 mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
1977 if (!mychannel)
1979 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
1980 rpt_mutex_lock(&myrpt->lock);
1981 remque((struct qelem *)mytele);
1982 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
1983 rpt_mutex_unlock(&myrpt->lock);
1984 free(mytele);
1985 pthread_exit(NULL);
1987 rpt_mutex_lock(&myrpt->lock);
1988 mytele->chan = mychannel; /* Save a copy of the channel so we can access it externally if need be */
1989 rpt_mutex_unlock(&myrpt->lock);
1991 /* make a conference for the tx */
1992 ci.chan = 0;
1993 /* If there's an ID queued, or tail message queued, */
1994 /* only connect the ID audio to the local tx conference so */
1995 /* linked systems can't hear it */
1996 ci.confno = (((mytele->mode == ID) || (mytele->mode == IDTALKOVER) || (mytele->mode == UNKEY) ||
1997 (mytele->mode == TAILMSG)) ?
1998 myrpt->txconf : myrpt->conf);
1999 ci.confmode = ZT_CONF_CONFANN;
2000 /* first put the channel on the conference in announce mode */
2001 if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
2003 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2004 rpt_mutex_lock(&myrpt->lock);
2005 remque((struct qelem *)mytele);
2006 rpt_mutex_unlock(&myrpt->lock);
2007 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
2008 free(mytele);
2009 ast_hangup(mychannel);
2010 pthread_exit(NULL);
2012 ast_stopstream(mychannel);
2013 switch(mytele->mode)
2016 case ID:
2017 case ID1:
2018 /* wait a bit */
2019 wait_interval(myrpt, (mytele->mode == ID) ? DLY_ID : DLY_TELEM,mychannel);
2020 res = telem_any(myrpt,mychannel, ident);
2021 imdone=1;
2022 break;
2024 case TAILMSG:
2025 res = ast_streamfile(mychannel, myrpt->p.tailmessages[myrpt->tailmessagen], mychannel->language);
2026 break;
2028 case IDTALKOVER:
2029 p = ast_variable_retrieve(myrpt->cfg, nodename, "idtalkover");
2030 if(p)
2031 res = telem_any(myrpt,mychannel, p);
2032 imdone=1;
2033 break;
2035 case PROC:
2036 /* wait a little bit longer */
2037 wait_interval(myrpt, DLY_TELEM, mychannel);
2038 res = telem_lookup(myrpt, mychannel, myrpt->name, "patchup");
2039 if(res < 0){ /* Then default message */
2040 res = ast_streamfile(mychannel, "rpt/callproceeding", mychannel->language);
2042 break;
2043 case TERM:
2044 /* wait a little bit longer */
2045 wait_interval(myrpt, DLY_CALLTERM, mychannel);
2046 res = telem_lookup(myrpt, mychannel, myrpt->name, "patchdown");
2047 if(res < 0){ /* Then default message */
2048 res = ast_streamfile(mychannel, "rpt/callterminated", mychannel->language);
2050 break;
2051 case COMPLETE:
2052 /* wait a little bit */
2053 wait_interval(myrpt, DLY_TELEM, mychannel);
2054 res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
2055 break;
2056 case MACRO_NOTFOUND:
2057 /* wait a little bit */
2058 wait_interval(myrpt, DLY_TELEM, mychannel);
2059 res = ast_streamfile(mychannel, "rpt/macro_notfound", mychannel->language);
2060 break;
2061 case MACRO_BUSY:
2062 /* wait a little bit */
2063 wait_interval(myrpt, DLY_TELEM, mychannel);
2064 res = ast_streamfile(mychannel, "rpt/macro_busy", mychannel->language);
2065 break;
2066 case UNKEY:
2067 if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
2068 imdone = 1;
2069 break;
2073 * Reset the Unkey to CT timer
2076 x = get_wait_interval(myrpt, DLY_UNKEY);
2077 rpt_mutex_lock(&myrpt->lock);
2078 myrpt->unkeytocttimer = x; /* Must be protected as it is changed below */
2079 rpt_mutex_unlock(&myrpt->lock);
2082 * If there's one already queued, don't do another
2085 tlist = myrpt->tele.next;
2086 unkeys_queued = 0;
2087 if (tlist != &myrpt->tele)
2089 rpt_mutex_lock(&myrpt->lock);
2090 while(tlist != &myrpt->tele){
2091 if (tlist->mode == UNKEY) unkeys_queued++;
2092 tlist = tlist->next;
2094 rpt_mutex_unlock(&myrpt->lock);
2096 if( unkeys_queued > 1){
2097 imdone = 1;
2098 break;
2101 /* Wait for the telemetry timer to expire */
2102 /* Periodically check the timer since it can be re-initialized above */
2103 while(myrpt->unkeytocttimer)
2105 int ctint;
2106 if(myrpt->unkeytocttimer > 100)
2107 ctint = 100;
2108 else
2109 ctint = myrpt->unkeytocttimer;
2110 ast_safe_sleep(mychannel, ctint);
2111 rpt_mutex_lock(&myrpt->lock);
2112 if(myrpt->unkeytocttimer < ctint)
2113 myrpt->unkeytocttimer = 0;
2114 else
2115 myrpt->unkeytocttimer -= ctint;
2116 rpt_mutex_unlock(&myrpt->lock);
2120 * Now, the carrier on the rptr rx should be gone.
2121 * If it re-appeared, then forget about sending the CT
2123 if(myrpt->keyed){
2124 imdone = 1;
2125 break;
2128 rpt_mutex_lock(&myrpt->lock); /* Update the kerchunk counters */
2129 myrpt->dailykerchunks++;
2130 myrpt->totalkerchunks++;
2131 rpt_mutex_unlock(&myrpt->lock);
2133 haslink = 0;
2134 hastx = 0;
2135 hasremote = 0;
2136 l = myrpt->links.next;
2137 if (l != &myrpt->links)
2139 rpt_mutex_lock(&myrpt->lock);
2140 while(l != &myrpt->links)
2142 if (l->name[0] == '0')
2144 l = l->next;
2145 continue;
2147 haslink = 1;
2148 if (l->mode) {
2149 hastx++;
2150 if (l->isremote) hasremote++;
2152 l = l->next;
2154 rpt_mutex_unlock(&myrpt->lock);
2156 if (haslink)
2159 res = telem_lookup(myrpt,mychannel, myrpt->name, (!hastx) ? "remotemon" : "remotetx");
2160 if(res)
2161 ast_log(LOG_WARNING, "telem_lookup:remotexx failed on %s\n", mychannel->name);
2164 /* if in remote cmd mode, indicate it */
2165 if (myrpt->cmdnode[0])
2167 ast_safe_sleep(mychannel,200);
2168 res = telem_lookup(myrpt,mychannel, myrpt->name, "cmdmode");
2169 if(res)
2170 ast_log(LOG_WARNING, "telem_lookup:cmdmode failed on %s\n", mychannel->name);
2171 ast_stopstream(mychannel);
2174 else if((ct = ast_variable_retrieve(myrpt->cfg, nodename, "unlinkedct"))){ /* Unlinked Courtesy Tone */
2175 ct_copy = ast_strdupa(ct);
2176 res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
2177 if(res)
2178 ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);
2180 if (hasremote && (!myrpt->cmdnode[0]))
2182 /* set for all to hear */
2183 ci.chan = 0;
2184 ci.confno = myrpt->conf;
2185 ci.confmode = ZT_CONF_CONFANN;
2186 /* first put the channel on the conference in announce mode */
2187 if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
2189 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2190 rpt_mutex_lock(&myrpt->lock);
2191 remque((struct qelem *)mytele);
2192 rpt_mutex_unlock(&myrpt->lock);
2193 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
2194 free(mytele);
2195 ast_hangup(mychannel);
2196 pthread_exit(NULL);
2198 if((ct = ast_variable_retrieve(myrpt->cfg, nodename, "remotect"))){ /* Unlinked Courtesy Tone */
2199 ast_safe_sleep(mychannel,200);
2200 ct_copy = ast_strdupa(ct);
2201 res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
2202 if(res)
2203 ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);
2206 #ifdef _MDC_DECODE_H_
2207 if (myrpt->lastunit)
2209 char mystr[10];
2211 ast_safe_sleep(mychannel,200);
2212 /* set for all to hear */
2213 ci.chan = 0;
2214 ci.confno = myrpt->txconf;
2215 ci.confmode = ZT_CONF_CONFANN;
2216 /* first put the channel on the conference in announce mode */
2217 if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
2219 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2220 rpt_mutex_lock(&myrpt->lock);
2221 remque((struct qelem *)mytele);
2222 rpt_mutex_unlock(&myrpt->lock);
2223 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
2224 free(mytele);
2225 ast_hangup(mychannel);
2226 pthread_exit(NULL);
2228 sprintf(mystr,"%04x",myrpt->lastunit);
2229 myrpt->lastunit = 0;
2230 ast_say_character_str(mychannel,mystr,NULL,mychannel->language);
2231 break;
2233 #endif
2234 imdone = 1;
2235 break;
2236 case REMDISC:
2237 /* wait a little bit */
2238 wait_interval(myrpt, DLY_TELEM, mychannel);
2239 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
2240 if (!res)
2241 res = ast_waitstream(mychannel, "");
2242 else
2243 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2244 ast_stopstream(mychannel);
2245 ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
2246 res = ast_streamfile(mychannel, ((mytele->mylink.connected) ?
2247 "rpt/remote_disc" : "rpt/remote_busy"), mychannel->language);
2248 break;
2249 case REMALREADY:
2250 /* wait a little bit */
2251 wait_interval(myrpt, DLY_TELEM, mychannel);
2252 res = ast_streamfile(mychannel, "rpt/remote_already", mychannel->language);
2253 break;
2254 case REMNOTFOUND:
2255 /* wait a little bit */
2256 wait_interval(myrpt, DLY_TELEM, mychannel);
2257 res = ast_streamfile(mychannel, "rpt/remote_notfound", mychannel->language);
2258 break;
2259 case REMGO:
2260 /* wait a little bit */
2261 wait_interval(myrpt, DLY_TELEM, mychannel);
2262 res = ast_streamfile(mychannel, "rpt/remote_go", mychannel->language);
2263 break;
2264 case CONNECTED:
2265 /* wait a little bit */
2266 wait_interval(myrpt, DLY_TELEM, mychannel);
2267 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
2268 if (!res)
2269 res = ast_waitstream(mychannel, "");
2270 else
2271 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2272 ast_stopstream(mychannel);
2273 ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
2274 res = ast_streamfile(mychannel, "rpt/connected", mychannel->language);
2275 break;
2276 case CONNFAIL:
2277 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
2278 if (!res)
2279 res = ast_waitstream(mychannel, "");
2280 else
2281 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2282 ast_stopstream(mychannel);
2283 ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
2284 res = ast_streamfile(mychannel, "rpt/connection_failed", mychannel->language);
2285 break;
2286 case STATUS:
2287 /* wait a little bit */
2288 wait_interval(myrpt, DLY_TELEM, mychannel);
2289 hastx = 0;
2290 linkbase.next = &linkbase;
2291 linkbase.prev = &linkbase;
2292 rpt_mutex_lock(&myrpt->lock);
2293 /* make our own list of links */
2294 l = myrpt->links.next;
2295 while(l != &myrpt->links)
2297 if (l->name[0] == '0')
2299 l = l->next;
2300 continue;
2302 m = malloc(sizeof(struct rpt_link));
2303 if (!m)
2305 ast_log(LOG_WARNING, "Cannot alloc memory on %s\n", mychannel->name);
2306 remque((struct qelem *)mytele);
2307 rpt_mutex_unlock(&myrpt->lock);
2308 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
2309 free(mytele);
2310 ast_hangup(mychannel);
2311 pthread_exit(NULL);
2313 memcpy(m,l,sizeof(struct rpt_link));
2314 m->next = m->prev = NULL;
2315 insque((struct qelem *)m,(struct qelem *)linkbase.next);
2316 l = l->next;
2318 rpt_mutex_unlock(&myrpt->lock);
2319 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
2320 if (!res)
2321 res = ast_waitstream(mychannel, "");
2322 else
2323 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2324 ast_stopstream(mychannel);
2325 ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
2326 if (!res)
2327 res = ast_waitstream(mychannel, "");
2328 else
2329 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2330 ast_stopstream(mychannel);
2331 if (myrpt->callmode)
2333 hastx = 1;
2334 res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
2335 if (!res)
2336 res = ast_waitstream(mychannel, "");
2337 else
2338 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2339 ast_stopstream(mychannel);
2341 l = linkbase.next;
2342 while(l != &linkbase)
2344 hastx = 1;
2345 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
2346 if (!res)
2347 res = ast_waitstream(mychannel, "");
2348 else
2349 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2350 ast_stopstream(mychannel);
2351 ast_say_character_str(mychannel,l->name,NULL,mychannel->language);
2352 if (!res)
2353 res = ast_waitstream(mychannel, "");
2354 else
2355 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2356 ast_stopstream(mychannel);
2357 res = ast_streamfile(mychannel, ((l->mode) ?
2358 "rpt/tranceive" : "rpt/monitor"), mychannel->language);
2359 if (!res)
2360 res = ast_waitstream(mychannel, "");
2361 else
2362 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2363 ast_stopstream(mychannel);
2364 l = l->next;
2366 if (!hastx)
2368 res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
2369 if (!res)
2370 res = ast_waitstream(mychannel, "");
2371 else
2372 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2373 ast_stopstream(mychannel);
2375 /* destroy our local link queue */
2376 l = linkbase.next;
2377 while(l != &linkbase)
2379 m = l;
2380 l = l->next;
2381 remque((struct qelem *)m);
2382 free(m);
2384 imdone = 1;
2385 break;
2387 case LASTNODEKEY: /* Identify last node which keyed us up */
2388 rpt_mutex_lock(&myrpt->lock);
2389 if(myrpt->lastnodewhichkeyedusup)
2390 p = ast_strdupa(myrpt->lastnodewhichkeyedusup); /* Make a local copy of the node name */
2391 else
2392 p = NULL;
2393 rpt_mutex_unlock(&myrpt->lock);
2394 if(!p){
2395 imdone = 1; /* no node previously keyed us up, or the node which did has been disconnected */
2396 break;
2398 wait_interval(myrpt, DLY_TELEM, mychannel);
2399 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
2400 if (!res)
2401 res = ast_waitstream(mychannel, "");
2402 else
2403 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2404 ast_stopstream(mychannel);
2405 ast_say_character_str(mychannel, p, NULL, mychannel->language);
2406 if (!res)
2407 res = ast_waitstream(mychannel, "");
2408 else
2409 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2410 ast_stopstream(mychannel);
2411 imdone = 1;
2412 break;
2414 case TIMEOUT:
2415 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
2416 if (!res)
2417 res = ast_waitstream(mychannel, "");
2418 else
2419 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2420 ast_stopstream(mychannel);
2421 ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
2422 res = ast_streamfile(mychannel, "rpt/timeout", mychannel->language);
2423 break;
2425 case STATS_TIME:
2426 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
2427 t = time(NULL);
2428 localtime_r(&t, &localtm);
2429 /* Say the phase of the day is before the time */
2430 if((localtm.tm_hour >= 0) && (localtm.tm_hour < 12))
2431 p = "rpt/goodmorning";
2432 else if((localtm.tm_hour >= 12) && (localtm.tm_hour < 18))
2433 p = "rpt/goodafternoon";
2434 else
2435 p = "rpt/goodevening";
2436 if (sayfile(mychannel,p) == -1)
2438 imdone = 1;
2439 break;
2441 /* Say the time is ... */
2442 if (sayfile(mychannel,"rpt/thetimeis") == -1)
2444 imdone = 1;
2445 break;
2447 /* Say the time */
2448 res = ast_say_time(mychannel, t, "", mychannel->language);
2449 if (!res)
2450 res = ast_waitstream(mychannel, "");
2451 ast_stopstream(mychannel);
2452 imdone = 1;
2453 break;
2454 case STATS_VERSION:
2455 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
2456 /* Say "version" */
2457 if (sayfile(mychannel,"rpt/version") == -1)
2459 imdone = 1;
2460 break;
2462 if(!res) /* Say "X" */
2463 ast_say_number(mychannel, vmajor, "", mychannel->language, (char *) NULL);
2464 if (!res)
2465 res = ast_waitstream(mychannel, "");
2466 ast_stopstream(mychannel);
2467 if (saycharstr(mychannel,".") == -1)
2469 imdone = 1;
2470 break;
2472 if(!res) /* Say "Y" */
2473 ast_say_number(mychannel, vminor, "", mychannel->language, (char *) NULL);
2474 if (!res){
2475 res = ast_waitstream(mychannel, "");
2476 ast_stopstream(mychannel);
2478 else
2479 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2480 imdone = 1;
2481 break;
2482 case ARB_ALPHA:
2483 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
2484 if(mytele->param)
2485 saycharstr(mychannel, mytele->param);
2486 imdone = 1;
2487 break;
2488 case REV_PATCH:
2489 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
2490 if(mytele->param) {
2492 /* Parts of this section taken from app_parkandannounce */
2493 char *tpl_working, *tpl_current;
2494 char *tmp[100], *myparm;
2495 int looptemp=0,i=0, dres = 0;
2498 tpl_working = strdupa(mytele->param);
2499 myparm = strsep(&tpl_working,",");
2500 tpl_current=strsep(&tpl_working, ":");
2502 while(tpl_current && looptemp < sizeof(tmp)) {
2503 tmp[looptemp]=tpl_current;
2504 looptemp++;
2505 tpl_current=strsep(&tpl_working,":");
2508 for(i=0; i<looptemp; i++) {
2509 if(!strcmp(tmp[i], "PARKED")) {
2510 ast_say_digits(mychannel, atoi(myparm), "", mychannel->language);
2511 } else if(!strcmp(tmp[i], "NODE")) {
2512 ast_say_digits(mychannel, atoi(myrpt->name), "", mychannel->language);
2513 } else {
2514 dres = ast_streamfile(mychannel, tmp[i], mychannel->language);
2515 if(!dres) {
2516 dres = ast_waitstream(mychannel, "");
2517 } else {
2518 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[i], mychannel->name);
2519 dres = 0;
2524 imdone = 1;
2525 break;
2526 case TEST_TONE:
2527 imdone = 1;
2528 myrpt->stopgen = 0;
2529 if ((res = ast_tonepair_start(mychannel, 1004.0, 0, 99999999, 7200.0)))
2530 break;
2531 while(mychannel->generatordata && (!myrpt->stopgen)) {
2532 if (ast_safe_sleep(mychannel,1)) break;
2533 imdone = 1;
2535 break;
2536 default:
2537 break;
2539 myrpt->stopgen = 0;
2540 if (!imdone)
2542 if (!res)
2543 res = ast_waitstream(mychannel, "");
2544 else {
2545 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2546 res = 0;
2549 ast_stopstream(mychannel);
2550 rpt_mutex_lock(&myrpt->lock);
2551 if (mytele->mode == TAILMSG)
2553 if (!res)
2555 myrpt->tailmessagen++;
2556 if(myrpt->tailmessagen >= myrpt->p.tailmessagemax) myrpt->tailmessagen = 0;
2558 else
2560 myrpt->tmsgtimer = myrpt->p.tailsquashedtime;
2563 remque((struct qelem *)mytele);
2564 rpt_mutex_unlock(&myrpt->lock);
2565 free(mytele);
2566 ast_hangup(mychannel);
2567 #ifdef APP_RPT_LOCK_DEBUG
2569 struct lockthread *t;
2571 sleep(5);
2572 ast_mutex_lock(&locklock);
2573 t = get_lockthread(pthread_self());
2574 if (t) memset(t,0,sizeof(struct lockthread));
2575 ast_mutex_unlock(&locklock);
2577 #endif
2578 pthread_exit(NULL);
2581 static void rpt_telemetry(struct rpt *myrpt,int mode, void *data)
2583 struct rpt_tele *tele;
2584 struct rpt_link *mylink = (struct rpt_link *) data;
2585 int res;
2586 pthread_attr_t attr;
2588 tele = malloc(sizeof(struct rpt_tele));
2589 if (!tele)
2591 ast_log(LOG_WARNING, "Unable to allocate memory\n");
2592 pthread_exit(NULL);
2593 return;
2595 /* zero it out */
2596 memset((char *)tele,0,sizeof(struct rpt_tele));
2597 tele->rpt = myrpt;
2598 tele->mode = mode;
2599 rpt_mutex_lock(&myrpt->lock);
2600 if((mode == CONNFAIL) || (mode == REMDISC) || (mode == CONNECTED)){
2601 memset(&tele->mylink,0,sizeof(struct rpt_link));
2602 if (mylink){
2603 memcpy(&tele->mylink,mylink,sizeof(struct rpt_link));
2606 else if ((mode == ARB_ALPHA) || (mode == REV_PATCH)) {
2607 strncpy(tele->param, (char *) data, TELEPARAMSIZE - 1);
2608 tele->param[TELEPARAMSIZE - 1] = 0;
2610 insque((struct qelem *)tele, (struct qelem *)myrpt->tele.next);
2611 rpt_mutex_unlock(&myrpt->lock);
2612 pthread_attr_init(&attr);
2613 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2614 res = ast_pthread_create(&tele->threadid,&attr,rpt_tele_thread,(void *) tele);
2615 if(res < 0){
2616 rpt_mutex_lock(&myrpt->lock);
2617 remque((struct qlem *) tele); /* We don't like stuck transmitters, remove it from the queue */
2618 rpt_mutex_unlock(&myrpt->lock);
2619 ast_log(LOG_WARNING, "Could not create telemetry thread: %s",strerror(res));
2621 return;
2624 static void *rpt_call(void *this)
2626 ZT_CONFINFO ci; /* conference info */
2627 struct rpt *myrpt = (struct rpt *)this;
2628 int res;
2629 struct ast_frame wf;
2630 int stopped,congstarted,dialtimer,lastcidx,aborted;
2631 struct ast_channel *mychannel,*genchannel;
2634 myrpt->mydtmf = 0;
2635 /* allocate a pseudo-channel thru asterisk */
2636 mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
2637 if (!mychannel)
2639 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
2640 pthread_exit(NULL);
2642 ci.chan = 0;
2643 ci.confno = myrpt->conf; /* use the pseudo conference */
2644 ci.confmode = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER
2645 | ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER;
2646 /* first put the channel on the conference */
2647 if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
2649 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2650 ast_hangup(mychannel);
2651 myrpt->callmode = 0;
2652 pthread_exit(NULL);
2654 /* allocate a pseudo-channel thru asterisk */
2655 genchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
2656 if (!genchannel)
2658 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
2659 ast_hangup(mychannel);
2660 pthread_exit(NULL);
2662 ci.chan = 0;
2663 ci.confno = myrpt->conf;
2664 ci.confmode = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER
2665 | ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER;
2666 /* first put the channel on the conference */
2667 if (ioctl(genchannel->fds[0],ZT_SETCONF,&ci) == -1)
2669 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2670 ast_hangup(mychannel);
2671 ast_hangup(genchannel);
2672 myrpt->callmode = 0;
2673 pthread_exit(NULL);
2675 if (myrpt->p.tonezone && (tone_zone_set_zone(mychannel->fds[0],myrpt->p.tonezone) == -1))
2677 ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
2678 ast_hangup(mychannel);
2679 ast_hangup(genchannel);
2680 myrpt->callmode = 0;
2681 pthread_exit(NULL);
2683 if (myrpt->p.tonezone && (tone_zone_set_zone(genchannel->fds[0],myrpt->p.tonezone) == -1))
2685 ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
2686 ast_hangup(mychannel);
2687 ast_hangup(genchannel);
2688 myrpt->callmode = 0;
2689 pthread_exit(NULL);
2691 /* start dialtone if patchquiet is 0. Special patch modes don't send dial tone */
2692 if ((!myrpt->patchquiet) && (tone_zone_play_tone(mychannel->fds[0],ZT_TONE_DIALTONE) < 0))
2694 ast_log(LOG_WARNING, "Cannot start dialtone\n");
2695 ast_hangup(mychannel);
2696 ast_hangup(genchannel);
2697 myrpt->callmode = 0;
2698 pthread_exit(NULL);
2700 stopped = 0;
2701 congstarted = 0;
2702 dialtimer = 0;
2703 lastcidx = 0;
2704 aborted = 0;
2707 while ((myrpt->callmode == 1) || (myrpt->callmode == 4))
2710 if((myrpt->patchdialtime)&&(myrpt->callmode == 1)&&(myrpt->cidx != lastcidx)){
2711 dialtimer = 0;
2712 lastcidx = myrpt->cidx;
2715 if((myrpt->patchdialtime)&&(dialtimer >= myrpt->patchdialtime)){
2716 rpt_mutex_lock(&myrpt->lock);
2717 aborted = 1;
2718 myrpt->callmode = 0;
2719 rpt_mutex_unlock(&myrpt->lock);
2720 break;
2723 if ((!myrpt->patchquiet) && (!stopped) && (myrpt->callmode == 1) && (myrpt->cidx > 0))
2725 stopped = 1;
2726 /* stop dial tone */
2727 tone_zone_play_tone(mychannel->fds[0],-1);
2729 if (myrpt->callmode == 4)
2731 if(!congstarted){
2732 congstarted = 1;
2733 /* start congestion tone */
2734 tone_zone_play_tone(mychannel->fds[0],ZT_TONE_CONGESTION);
2737 res = ast_safe_sleep(mychannel, MSWAIT);
2738 if (res < 0)
2740 ast_hangup(mychannel);
2741 ast_hangup(genchannel);
2742 rpt_mutex_lock(&myrpt->lock);
2743 myrpt->callmode = 0;
2744 rpt_mutex_unlock(&myrpt->lock);
2745 pthread_exit(NULL);
2747 dialtimer += MSWAIT;
2749 /* stop any tone generation */
2750 tone_zone_play_tone(mychannel->fds[0],-1);
2751 /* end if done */
2752 if (!myrpt->callmode)
2754 ast_hangup(mychannel);
2755 ast_hangup(genchannel);
2756 rpt_mutex_lock(&myrpt->lock);
2757 myrpt->callmode = 0;
2758 rpt_mutex_unlock(&myrpt->lock);
2759 if((!myrpt->patchquiet) && aborted)
2760 rpt_telemetry(myrpt, TERM, NULL);
2761 pthread_exit(NULL);
2764 if (myrpt->p.ourcallerid && *myrpt->p.ourcallerid){
2765 char *name, *loc, *instr;
2766 instr = strdup(myrpt->p.ourcallerid);
2767 if(instr){
2768 ast_callerid_parse(instr, &name, &loc);
2769 if(loc){
2770 if(mychannel->cid.cid_num)
2771 free(mychannel->cid.cid_num);
2772 mychannel->cid.cid_num = strdup(loc);
2774 if(name){
2775 if(mychannel->cid.cid_name)
2776 free(mychannel->cid.cid_name);
2777 mychannel->cid.cid_name = strdup(name);
2779 free(instr);
2783 strncpy(mychannel->exten, myrpt->exten, sizeof(mychannel->exten) - 1);
2784 strncpy(mychannel->context, myrpt->patchcontext, sizeof(mychannel->context) - 1);
2786 if (myrpt->p.acctcode)
2787 strncpy((char *)mychannel->accountcode, myrpt->p.acctcode, sizeof(mychannel->accountcode) - 1);
2788 mychannel->priority = 1;
2789 ast_channel_undefer_dtmf(mychannel);
2790 if (ast_pbx_start(mychannel) < 0)
2792 ast_log(LOG_WARNING, "Unable to start PBX!!\n");
2793 ast_hangup(mychannel);
2794 ast_hangup(genchannel);
2795 rpt_mutex_lock(&myrpt->lock);
2796 myrpt->callmode = 0;
2797 rpt_mutex_unlock(&myrpt->lock);
2798 pthread_exit(NULL);
2800 usleep(10000);
2801 rpt_mutex_lock(&myrpt->lock);
2802 myrpt->callmode = 3;
2803 /* set appropriate conference for the pseudo */
2804 ci.chan = 0;
2805 ci.confno = myrpt->conf;
2806 ci.confmode = (myrpt->p.duplex == 2) ? ZT_CONF_CONFANNMON :
2807 (ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER);
2808 /* first put the channel on the conference in announce mode */
2809 if (ioctl(myrpt->pchannel->fds[0],ZT_SETCONF,&ci) == -1)
2811 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2812 ast_hangup(mychannel);
2813 ast_hangup(genchannel);
2814 myrpt->callmode = 0;
2815 pthread_exit(NULL);
2817 while(myrpt->callmode)
2819 if ((!mychannel->pbx) && (myrpt->callmode != 4))
2821 if(myrpt->patchfarenddisconnect){ /* If patch is setup for far end disconnect */
2822 myrpt->callmode = 0;
2823 if(!myrpt->patchquiet){
2824 rpt_mutex_unlock(&myrpt->lock);
2825 rpt_telemetry(myrpt, TERM, NULL);
2826 rpt_mutex_lock(&myrpt->lock);
2829 else{ /* Send congestion until patch is downed by command */
2830 myrpt->callmode = 4;
2831 rpt_mutex_unlock(&myrpt->lock);
2832 /* start congestion tone */
2833 tone_zone_play_tone(genchannel->fds[0],ZT_TONE_CONGESTION);
2834 rpt_mutex_lock(&myrpt->lock);
2837 if (myrpt->mydtmf)
2839 wf.frametype = AST_FRAME_DTMF;
2840 wf.subclass = myrpt->mydtmf;
2841 wf.offset = 0;
2842 wf.mallocd = 0;
2843 wf.data = NULL;
2844 wf.datalen = 0;
2845 wf.samples = 0;
2846 rpt_mutex_unlock(&myrpt->lock);
2847 ast_write(genchannel,&wf);
2848 rpt_mutex_lock(&myrpt->lock);
2849 myrpt->mydtmf = 0;
2851 rpt_mutex_unlock(&myrpt->lock);
2852 usleep(MSWAIT * 1000);
2853 rpt_mutex_lock(&myrpt->lock);
2855 rpt_mutex_unlock(&myrpt->lock);
2856 tone_zone_play_tone(genchannel->fds[0],-1);
2857 if (mychannel->pbx) ast_softhangup(mychannel,AST_SOFTHANGUP_DEV);
2858 ast_hangup(genchannel);
2859 rpt_mutex_lock(&myrpt->lock);
2860 myrpt->callmode = 0;
2861 rpt_mutex_unlock(&myrpt->lock);
2862 /* set appropriate conference for the pseudo */
2863 ci.chan = 0;
2864 ci.confno = myrpt->conf;
2865 ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? ZT_CONF_CONFANNMON :
2866 (ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER);
2867 /* first put the channel on the conference in announce mode */
2868 if (ioctl(myrpt->pchannel->fds[0],ZT_SETCONF,&ci) == -1)
2870 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2872 pthread_exit(NULL);
2875 static void send_link_dtmf(struct rpt *myrpt,char c)
2877 char str[300];
2878 struct ast_frame wf;
2879 struct rpt_link *l;
2881 snprintf(str, sizeof(str), "D %s %s %d %c", myrpt->cmdnode, myrpt->name, ++(myrpt->dtmfidx), c);
2882 wf.frametype = AST_FRAME_TEXT;
2883 wf.subclass = 0;
2884 wf.offset = 0;
2885 wf.mallocd = 1;
2886 wf.datalen = strlen(str) + 1;
2887 wf.samples = 0;
2888 l = myrpt->links.next;
2889 /* first, see if our dude is there */
2890 while(l != &myrpt->links)
2892 if (l->name[0] == '0')
2894 l = l->next;
2895 continue;
2897 /* if we found it, write it and were done */
2898 if (!strcmp(l->name,myrpt->cmdnode))
2900 wf.data = strdup(str);
2901 if (l->chan) ast_write(l->chan,&wf);
2902 return;
2904 l = l->next;
2906 l = myrpt->links.next;
2907 /* if not, give it to everyone */
2908 while(l != &myrpt->links)
2910 wf.data = strdup(str);
2911 if (l->chan) ast_write(l->chan,&wf);
2912 l = l->next;
2914 return;
2918 * Internet linking function
2921 static int function_ilink(struct rpt *myrpt, char *param, char *digits, int command_source, struct rpt_link *mylink)
2924 char *val, *s, *s1, *s2, *tele;
2925 char tmp[300], deststr[300] = "",modechange = 0;
2926 char digitbuf[MAXNODESTR];
2927 struct rpt_link *l;
2928 int reconnects = 0;
2929 ZT_CONFINFO ci; /* conference info */
2931 if(!param)
2932 return DC_ERROR;
2935 if (!myrpt->enable)
2936 return DC_ERROR;
2938 strncpy(digitbuf,digits,MAXNODESTR - 1);
2940 if(debug)
2941 printf("@@@@ ilink param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
2943 switch(myatoi(param)){
2944 case 1: /* Link off */
2945 if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
2946 strcpy(digitbuf,myrpt->lastlinknode);
2947 val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
2948 if (!val){
2949 if(strlen(digitbuf) >= myrpt->longestnode)
2950 return DC_ERROR;
2951 break;
2953 strncpy(tmp,val,sizeof(tmp) - 1);
2954 s = tmp;
2955 s1 = strsep(&s,",");
2956 s2 = strsep(&s,",");
2957 rpt_mutex_lock(&myrpt->lock);
2958 l = myrpt->links.next;
2959 /* try to find this one in queue */
2960 while(l != &myrpt->links){
2961 if (l->name[0] == '0')
2963 l = l->next;
2964 continue;
2966 /* if found matching string */
2967 if (!strcmp(l->name, digitbuf))
2968 break;
2969 l = l->next;
2971 if (l != &myrpt->links){ /* if found */
2972 struct ast_frame wf;
2973 strncpy(myrpt->lastlinknode,digitbuf,MAXNODESTR - 1);
2974 l->retries = MAX_RETRIES + 1;
2975 l->disced = 1;
2976 rpt_mutex_unlock(&myrpt->lock);
2977 wf.frametype = AST_FRAME_TEXT;
2978 wf.subclass = 0;
2979 wf.offset = 0;
2980 wf.mallocd = 1;
2981 wf.datalen = strlen(discstr) + 1;
2982 wf.samples = 0;
2983 wf.data = strdup(discstr);
2984 if (l->chan)
2986 ast_write(l->chan,&wf);
2987 if (ast_safe_sleep(l->chan,250) == -1) return DC_ERROR;
2988 ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
2990 rpt_telemetry(myrpt, COMPLETE, NULL);
2991 return DC_COMPLETE;
2993 rpt_mutex_unlock(&myrpt->lock);
2994 return DC_COMPLETE;
2995 case 2: /* Link Monitor */
2996 if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
2997 strcpy(digitbuf,myrpt->lastlinknode);
2998 val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
2999 if (!val){
3000 if(strlen(digitbuf) >= myrpt->longestnode)
3001 return DC_ERROR;
3002 break;
3004 strncpy(tmp,val,sizeof(tmp) - 1);
3005 s = tmp;
3006 s1 = strsep(&s,",");
3007 s2 = strsep(&s,",");
3008 rpt_mutex_lock(&myrpt->lock);
3009 l = myrpt->links.next;
3010 /* try to find this one in queue */
3011 while(l != &myrpt->links){
3012 if (l->name[0] == '0')
3014 l = l->next;
3015 continue;
3017 /* if found matching string */
3018 if (!strcmp(l->name, digitbuf))
3019 break;
3020 l = l->next;
3022 /* if found */
3023 if (l != &myrpt->links)
3025 /* if already in this mode, just ignore */
3026 if ((!l->mode) || (!l->chan)) {
3027 rpt_mutex_unlock(&myrpt->lock);
3028 rpt_telemetry(myrpt,REMALREADY,NULL);
3029 return DC_COMPLETE;
3032 reconnects = l->reconnects;
3033 rpt_mutex_unlock(&myrpt->lock);
3034 if (l->chan) ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
3035 l->retries = MAX_RETRIES + 1;
3036 l->disced = 2;
3037 modechange = 1;
3038 } else
3039 rpt_mutex_unlock(&myrpt->lock);
3040 strncpy(myrpt->lastlinknode,digitbuf,MAXNODESTR - 1);
3041 /* establish call in monitor mode */
3042 l = malloc(sizeof(struct rpt_link));
3043 if (!l){
3044 ast_log(LOG_WARNING, "Unable to malloc\n");
3045 return DC_ERROR;
3047 /* zero the silly thing */
3048 memset((char *)l,0,sizeof(struct rpt_link));
3049 snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
3050 tele = strchr(deststr,'/');
3051 if (!tele){
3052 fprintf(stderr,"link2:Dial number (%s) must be in format tech/number\n",deststr);
3053 return DC_ERROR;
3055 *tele++ = 0;
3056 l->isremote = (s && ast_true(s));
3057 strncpy(l->name, digitbuf, MAXNODESTR - 1);
3058 l->chan = ast_request(deststr,AST_FORMAT_SLINEAR,tele,NULL);
3059 if (modechange) l->connected = 1;
3060 if (l->chan){
3061 ast_set_read_format(l->chan,AST_FORMAT_SLINEAR);
3062 ast_set_write_format(l->chan,AST_FORMAT_SLINEAR);
3063 l->chan->whentohangup = 0;
3064 l->chan->appl = "Apprpt";
3065 l->chan->data = "(Remote Rx)";
3066 if (option_verbose > 2)
3067 ast_verbose(VERBOSE_PREFIX_3 "rpt (remote) initiating call to %s/%s on %s\n",
3068 deststr,tele,l->chan->name);
3069 if(l->chan->cid.cid_num)
3070 free(l->chan->cid.cid_num);
3071 l->chan->cid.cid_num = strdup(myrpt->name);
3072 ast_call(l->chan,tele,0);
3074 else
3076 rpt_telemetry(myrpt,CONNFAIL,l);
3077 free(l);
3078 if (option_verbose > 2)
3079 ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
3080 deststr,tele,l->chan->name);
3081 return DC_ERROR;
3083 /* allocate a pseudo-channel thru asterisk */
3084 l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
3085 if (!l->pchan){
3086 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
3087 ast_hangup(l->chan);
3088 free(l);
3089 return DC_ERROR;
3091 ast_set_read_format(l->pchan,AST_FORMAT_SLINEAR);
3092 ast_set_write_format(l->pchan,AST_FORMAT_SLINEAR);
3093 /* make a conference for the pseudo-one */
3094 ci.chan = 0;
3095 ci.confno = myrpt->conf;
3096 ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER;
3097 /* first put the channel on the conference in proper mode */
3098 if (ioctl(l->pchan->fds[0],ZT_SETCONF,&ci) == -1)
3100 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
3101 ast_hangup(l->chan);
3102 ast_hangup(l->pchan);
3103 free(l);
3104 return DC_ERROR;
3106 rpt_mutex_lock(&myrpt->lock);
3107 l->reconnects = reconnects;
3108 /* insert at end of queue */
3109 insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
3110 rpt_mutex_unlock(&myrpt->lock);
3111 rpt_telemetry(myrpt,COMPLETE,NULL);
3112 return DC_COMPLETE;
3113 case 3: /* Link transceive */
3114 if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
3115 strcpy(digitbuf,myrpt->lastlinknode);
3116 val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
3117 if (!val){
3118 if(strlen(digitbuf) >= myrpt->longestnode)
3119 return DC_ERROR;
3120 break;
3122 strncpy(tmp,val,sizeof(tmp) - 1);
3123 s = tmp;
3124 s1 = strsep(&s,",");
3125 s2 = strsep(&s,",");
3126 rpt_mutex_lock(&myrpt->lock);
3127 l = myrpt->links.next;
3128 /* try to find this one in queue */
3129 while(l != &myrpt->links){
3130 if (l->name[0] == '0')
3132 l = l->next;
3133 continue;
3135 /* if found matching string */
3136 if (!strcmp(l->name, digitbuf))
3137 break;
3138 l = l->next;
3140 /* if found */
3141 if (l != &myrpt->links){
3142 /* if already in this mode, just ignore */
3143 if ((l->mode) || (!l->chan)) {
3144 rpt_mutex_unlock(&myrpt->lock);
3145 rpt_telemetry(myrpt, REMALREADY, NULL);
3146 return DC_COMPLETE;
3148 reconnects = l->reconnects;
3149 rpt_mutex_unlock(&myrpt->lock);
3150 if (l->chan) ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
3151 l->retries = MAX_RETRIES + 1;
3152 l->disced = 2;
3153 modechange = 1;
3154 } else
3155 rpt_mutex_unlock(&myrpt->lock);
3156 strncpy(myrpt->lastlinknode,digitbuf,MAXNODESTR - 1);
3157 /* establish call in tranceive mode */
3158 l = malloc(sizeof(struct rpt_link));
3159 if (!l){
3160 ast_log(LOG_WARNING, "Unable to malloc\n");
3161 return(DC_ERROR);
3163 /* zero the silly thing */
3164 memset((char *)l,0,sizeof(struct rpt_link));
3165 l->mode = 1;
3166 l->outbound = 1;
3167 strncpy(l->name, digitbuf, MAXNODESTR - 1);
3168 l->isremote = (s && ast_true(s));
3169 if (modechange) l->connected = 1;
3170 snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
3171 tele = strchr(deststr, '/');
3172 if (!tele){
3173 fprintf(stderr,"link3:Dial number (%s) must be in format tech/number\n",deststr);
3174 free(l);
3175 return DC_ERROR;
3177 *tele++ = 0;
3178 l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL);
3179 if (l->chan){
3180 ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
3181 ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
3182 l->chan->whentohangup = 0;
3183 l->chan->appl = "Apprpt";
3184 l->chan->data = "(Remote Rx)";
3185 if (option_verbose > 2)
3186 ast_verbose(VERBOSE_PREFIX_3 "rpt (remote) initiating call to %s/%s on %s\n",
3187 deststr, tele, l->chan->name);
3188 if(l->chan->cid.cid_num)
3189 free(l->chan->cid.cid_num);
3190 l->chan->cid.cid_num = strdup(myrpt->name);
3191 ast_call(l->chan,tele,999);
3193 else{
3194 rpt_telemetry(myrpt,CONNFAIL,l);
3195 free(l);
3196 if (option_verbose > 2)
3197 ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
3198 deststr,tele,l->chan->name);
3199 return DC_ERROR;
3201 /* allocate a pseudo-channel thru asterisk */
3202 l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
3203 if (!l->pchan){
3204 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
3205 ast_hangup(l->chan);
3206 free(l);
3207 return DC_ERROR;
3209 ast_set_read_format(l->pchan, AST_FORMAT_SLINEAR);
3210 ast_set_write_format(l->pchan, AST_FORMAT_SLINEAR);
3211 /* make a conference for the tx */
3212 ci.chan = 0;
3213 ci.confno = myrpt->conf;
3214 ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER;
3215 /* first put the channel on the conference in proper mode */
3216 if (ioctl(l->pchan->fds[0], ZT_SETCONF, &ci) == -1)
3218 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
3219 ast_hangup(l->chan);
3220 ast_hangup(l->pchan);
3221 free(l);
3222 return DC_ERROR;
3224 rpt_mutex_lock(&myrpt->lock);
3225 l->reconnects = reconnects;
3226 /* insert at end of queue */
3227 insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
3228 rpt_mutex_unlock(&myrpt->lock);
3229 rpt_telemetry(myrpt,COMPLETE,NULL);
3230 return DC_COMPLETE;
3231 case 4: /* Enter Command Mode */
3233 /* if doesnt allow link cmd, or no links active, return */
3234 if (((command_source != SOURCE_RPT) && (command_source != SOURCE_PHONE) && (command_source != SOURCE_DPHONE)) || (myrpt->links.next == &myrpt->links))
3235 return DC_COMPLETE;
3237 /* if already in cmd mode, or selected self, fughetabahtit */
3238 if ((myrpt->cmdnode[0]) || (!strcmp(myrpt->name, digitbuf))){
3240 rpt_telemetry(myrpt, REMALREADY, NULL);
3241 return DC_COMPLETE;
3243 if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
3244 strcpy(digitbuf,myrpt->lastlinknode);
3245 /* node must at least exist in list */
3246 val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
3247 if (!val){
3248 if(strlen(digitbuf) >= myrpt->longestnode)
3249 return DC_ERROR;
3250 break;
3253 rpt_mutex_lock(&myrpt->lock);
3254 strcpy(myrpt->lastlinknode,digitbuf);
3255 strncpy(myrpt->cmdnode, digitbuf, sizeof(myrpt->cmdnode) - 1);
3256 rpt_mutex_unlock(&myrpt->lock);
3257 rpt_telemetry(myrpt, REMGO, NULL);
3258 return DC_COMPLETE;
3260 case 5: /* Status */
3261 rpt_telemetry(myrpt, STATUS, NULL);
3262 return DC_COMPLETE;
3265 case 6: /* All Links Off */
3266 l = myrpt->links.next;
3268 while(l != &myrpt->links){ /* This code is broke and needs to be changed to work with the reconnect kludge */
3269 if (l->chan) ast_softhangup(l->chan, AST_SOFTHANGUP_DEV); /* Hang 'em up */
3270 l = l->next;
3272 rpt_telemetry(myrpt, COMPLETE, NULL);
3273 break;
3275 case 7: /* Identify last node which keyed us up */
3276 rpt_telemetry(myrpt, LASTNODEKEY, NULL);
3277 break;
3279 default:
3280 return DC_ERROR;
3284 return DC_INDETERMINATE;
3288 * Autopatch up
3291 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
3293 pthread_attr_t attr;
3294 int i, index, paramlength;
3295 char *lparam;
3296 char *value = NULL;
3297 char *paramlist[20];
3299 static char *keywords[] = {
3300 "context",
3301 "dialtime",
3302 "farenddisconnect",
3303 "noct",
3304 "quiet",
3305 NULL
3308 if (!myrpt->enable)
3309 return DC_ERROR;
3311 if(debug)
3312 printf("@@@@ Autopatch up\n");
3314 if(!myrpt->callmode){
3315 /* Set defaults */
3316 myrpt->patchnoct = 0;
3317 myrpt->patchdialtime = 0;
3318 myrpt->patchfarenddisconnect = 0;
3319 myrpt->patchquiet = 0;
3320 strncpy(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
3322 if(param){
3323 /* Process parameter list */
3324 lparam = ast_strdupa(param);
3325 if(!lparam){
3326 ast_log(LOG_ERROR,"App_rpt out of memory on line %d\n",__LINE__);
3327 return DC_ERROR;
3329 paramlength = finddelim(lparam, paramlist, 20);
3330 for(i = 0; i < paramlength; i++){
3331 index = matchkeyword(paramlist[i], &value, keywords);
3332 if(value)
3333 value = skipchars(value, "= ");
3334 switch(index){
3336 case 1: /* context */
3337 strncpy(myrpt->patchcontext, value, MAXPATCHCONTEXT - 1) ;
3338 break;
3340 case 2: /* dialtime */
3341 myrpt->patchdialtime = atoi(value);
3342 break;
3344 case 3: /* farenddisconnect */
3345 myrpt->patchfarenddisconnect = atoi(value);
3346 break;
3348 case 4: /* noct */
3349 myrpt->patchnoct = atoi(value);
3350 break;
3352 case 5: /* quiet */
3353 myrpt->patchquiet = atoi(value);
3354 break;
3356 default:
3357 break;
3363 rpt_mutex_lock(&myrpt->lock);
3365 /* if on call, force * into current audio stream */
3367 if ((myrpt->callmode == 2) || (myrpt->callmode == 3)){
3368 myrpt->mydtmf = myrpt->p.funcchar;
3370 if (myrpt->callmode){
3371 rpt_mutex_unlock(&myrpt->lock);
3372 return DC_COMPLETE;
3374 myrpt->callmode = 1;
3375 myrpt->cidx = 0;
3376 myrpt->exten[myrpt->cidx] = 0;
3377 rpt_mutex_unlock(&myrpt->lock);
3378 pthread_attr_init(&attr);
3379 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
3380 ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *) myrpt);
3381 return DC_COMPLETE;
3385 * Autopatch down
3388 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
3390 if (!myrpt->enable)
3391 return DC_ERROR;
3393 if(debug)
3394 printf("@@@@ Autopatch down\n");
3396 rpt_mutex_lock(&myrpt->lock);
3398 if (!myrpt->callmode){
3399 rpt_mutex_unlock(&myrpt->lock);
3400 return DC_COMPLETE;
3403 myrpt->callmode = 0;
3404 rpt_mutex_unlock(&myrpt->lock);
3405 rpt_telemetry(myrpt, TERM, NULL);
3406 return DC_COMPLETE;
3410 * Status
3413 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
3416 if (!param)
3417 return DC_ERROR;
3419 if (!myrpt->enable)
3420 return DC_ERROR;
3422 if(debug)
3423 printf("@@@@ status param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
3425 switch(myatoi(param)){
3426 case 1: /* System ID */
3427 rpt_telemetry(myrpt, ID1, NULL);
3428 return DC_COMPLETE;
3429 case 2: /* System Time */
3430 rpt_telemetry(myrpt, STATS_TIME, NULL);
3431 return DC_COMPLETE;
3432 case 3: /* app_rpt.c version */
3433 rpt_telemetry(myrpt, STATS_VERSION, NULL);
3434 default:
3435 return DC_ERROR;
3437 return DC_INDETERMINATE;
3441 * Macro-oni (without Salami)
3444 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
3447 char *val;
3448 int i;
3449 struct ast_channel *mychannel;
3451 if ((!myrpt->remote) && (!myrpt->enable))
3452 return DC_ERROR;
3454 if(debug)
3455 printf("@@@@ macro-oni param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
3457 mychannel = myrpt->remchannel;
3459 if(strlen(digitbuf) < 1) /* needs 1 digit */
3460 return DC_INDETERMINATE;
3462 for(i = 0 ; i < digitbuf[i] ; i++) {
3463 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
3464 return DC_ERROR;
3467 if (*digitbuf == '0') val = myrpt->p.startupmacro;
3468 else val = ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, digitbuf);
3469 /* param was 1 for local buf */
3470 if (!val){
3471 rpt_telemetry(myrpt, MACRO_NOTFOUND, NULL);
3472 return DC_COMPLETE;
3474 rpt_mutex_lock(&myrpt->lock);
3475 if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val))
3477 rpt_mutex_unlock(&myrpt->lock);
3478 rpt_telemetry(myrpt, MACRO_BUSY, NULL);
3479 return DC_ERROR;
3481 myrpt->macrotimer = MACROTIME;
3482 strncat(myrpt->macrobuf,val,MAXMACRO - 1);
3483 rpt_mutex_unlock(&myrpt->lock);
3484 return DC_COMPLETE;
3488 * COP - Control operator
3491 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
3493 if(!param)
3494 return DC_ERROR;
3496 switch(myatoi(param)){
3497 case 1: /* System reset */
3498 system("killall -9 asterisk"); /* FIXME to drastic? */
3499 return DC_COMPLETE;
3501 case 2:
3502 myrpt->enable = 1;
3503 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "RPTENA");
3504 return DC_COMPLETE;
3506 case 3:
3507 myrpt->enable = 0;
3508 return DC_COMPLETE;
3510 case 4: /* test tone on */
3511 rpt_telemetry(myrpt, TEST_TONE, NULL);
3512 return DC_COMPLETE;
3514 case 5: /* Disgorge variables to log for debug purposes */
3515 myrpt->disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
3516 return DC_COMPLETE;
3518 case 6: /* Simulate COR being activated (phone only) */
3519 if (command_source != SOURCE_PHONE) return DC_INDETERMINATE;
3520 return DC_DOKEY;
3523 return DC_INDETERMINATE;
3527 * Collect digits one by one until something matches
3530 static int collect_function_digits(struct rpt *myrpt, char *digits,
3531 int command_source, struct rpt_link *mylink)
3533 int i;
3534 char *stringp,*action,*param,*functiondigits;
3535 char function_table_name[30] = "";
3536 char workstring[200];
3538 struct ast_variable *vp;
3540 if(debug)
3541 printf("@@@@ Digits collected: %s, source: %d\n", digits, command_source);
3543 if (command_source == SOURCE_DPHONE) {
3544 if (!myrpt->p.dphone_functions) return DC_INDETERMINATE;
3545 strncpy(function_table_name, myrpt->p.dphone_functions, sizeof(function_table_name) - 1);
3547 else if (command_source == SOURCE_PHONE) {
3548 if (!myrpt->p.phone_functions) return DC_INDETERMINATE;
3549 strncpy(function_table_name, myrpt->p.phone_functions, sizeof(function_table_name) - 1);
3551 else if (command_source == SOURCE_LNK)
3552 strncpy(function_table_name, myrpt->p.link_functions, sizeof(function_table_name) - 1);
3553 else
3554 strncpy(function_table_name, myrpt->p.functions, sizeof(function_table_name) - 1);
3555 vp = ast_variable_browse(myrpt->cfg, function_table_name);
3556 while(vp) {
3557 if(!strncasecmp(vp->name, digits, strlen(vp->name)))
3558 break;
3559 vp = vp->next;
3561 if(!vp) {
3562 int n;
3564 n = myrpt->longestfunc;
3565 if (command_source == SOURCE_LNK) n = myrpt->link_longestfunc;
3566 else
3567 if (command_source == SOURCE_PHONE) n = myrpt->phone_longestfunc;
3568 else
3569 if (command_source == SOURCE_DPHONE) n = myrpt->dphone_longestfunc;
3571 if(strlen(digits) >= n)
3572 return DC_ERROR;
3573 else
3574 return DC_INDETERMINATE;
3576 /* Found a match, retrieve value part and parse */
3577 strncpy(workstring, vp->value, sizeof(workstring) - 1 );
3578 stringp = workstring;
3579 action = strsep(&stringp, ",");
3580 param = stringp;
3581 if(debug)
3582 printf("@@@@ action: %s, param = %s\n",action, (param) ? param : "(null)");
3583 /* Look up the action */
3584 for(i = 0 ; i < (sizeof(function_table)/sizeof(struct function_table_tag)); i++){
3585 if(!strncasecmp(action, function_table[i].action, strlen(action)))
3586 break;
3588 if(debug)
3589 printf("@@@@ table index i = %d\n",i);
3590 if(i == (sizeof(function_table)/sizeof(struct function_table_tag))){
3591 /* Error, action not in table */
3592 return DC_ERROR;
3594 if(function_table[i].function == NULL){
3595 /* Error, function undefined */
3596 if(debug)
3597 printf("@@@@ NULL for action: %s\n",action);
3598 return DC_ERROR;
3600 functiondigits = digits + strlen(vp->name);
3601 return (*function_table[i].function)(myrpt, param, functiondigits, command_source, mylink);
3605 static void handle_link_data(struct rpt *myrpt, struct rpt_link *mylink,
3606 char *str)
3608 char tmp[300],cmd[300] = "",dest[300],src[300],c;
3609 int seq, res;
3610 struct rpt_link *l;
3611 struct ast_frame wf;
3613 wf.frametype = AST_FRAME_TEXT;
3614 wf.subclass = 0;
3615 wf.offset = 0;
3616 wf.mallocd = 1;
3617 wf.datalen = strlen(str) + 1;
3618 wf.samples = 0;
3619 /* put string in our buffer */
3620 strncpy(tmp,str,sizeof(tmp) - 1);
3622 if (!strcmp(tmp,discstr))
3624 mylink->disced = 1;
3625 mylink->retries = MAX_RETRIES + 1;
3626 ast_softhangup(mylink->chan,AST_SOFTHANGUP_DEV);
3627 return;
3629 if (sscanf(tmp,"%s %s %s %d %c",cmd,dest,src,&seq,&c) != 5)
3631 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
3632 return;
3634 if (strcmp(cmd,"D"))
3636 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
3637 return;
3640 if (dest[0] == '0')
3642 strcpy(dest,myrpt->name);
3645 /* if not for me, redistribute to all links */
3646 if (strcmp(dest,myrpt->name))
3648 l = myrpt->links.next;
3649 /* see if this is one in list */
3650 while(l != &myrpt->links)
3652 if (l->name[0] == '0')
3654 l = l->next;
3655 continue;
3657 /* dont send back from where it came */
3658 if ((l == mylink) || (!strcmp(l->name,mylink->name)))
3660 l = l->next;
3661 continue;
3663 /* if it is, send it and we're done */
3664 if (!strcmp(l->name,dest))
3666 /* send, but not to src */
3667 if (strcmp(l->name,src)) {
3668 wf.data = strdup(str);
3669 if (l->chan) ast_write(l->chan,&wf);
3671 return;
3673 l = l->next;
3675 l = myrpt->links.next;
3676 /* otherwise, send it to all of em */
3677 while(l != &myrpt->links)
3679 if (l->name[0] == '0')
3681 l = l->next;
3682 continue;
3684 /* dont send back from where it came */
3685 if ((l == mylink) || (!strcmp(l->name,mylink->name)))
3687 l = l->next;
3688 continue;
3690 /* send, but not to src */
3691 if (strcmp(l->name,src)) {
3692 wf.data = strdup(str);
3693 if (l->chan) ast_write(l->chan,&wf);
3695 l = l->next;
3697 return;
3699 rpt_mutex_lock(&myrpt->lock);
3700 if (c == myrpt->p.endchar) myrpt->stopgen = 1;
3701 if (myrpt->callmode == 1)
3703 myrpt->exten[myrpt->cidx++] = c;
3704 myrpt->exten[myrpt->cidx] = 0;
3705 /* if this exists */
3706 if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
3708 myrpt->callmode = 2;
3709 if(!myrpt->patchquiet){
3710 rpt_mutex_unlock(&myrpt->lock);
3711 rpt_telemetry(myrpt,PROC,NULL);
3712 rpt_mutex_lock(&myrpt->lock);
3715 /* if can continue, do so */
3716 if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
3718 /* call has failed, inform user */
3719 myrpt->callmode = 4;
3722 if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
3724 myrpt->mydtmf = c;
3726 if (c == myrpt->p.funcchar)
3728 myrpt->rem_dtmfidx = 0;
3729 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
3730 time(&myrpt->rem_dtmf_time);
3731 rpt_mutex_unlock(&myrpt->lock);
3732 return;
3734 else if ((c != myrpt->p.endchar) && (myrpt->rem_dtmfidx >= 0))
3736 time(&myrpt->rem_dtmf_time);
3737 if (myrpt->rem_dtmfidx < MAXDTMF)
3739 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
3740 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
3742 rpt_mutex_unlock(&myrpt->lock);
3743 strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
3744 res = collect_function_digits(myrpt, cmd, SOURCE_LNK, mylink);
3745 rpt_mutex_lock(&myrpt->lock);
3747 switch(res){
3749 case DC_INDETERMINATE:
3750 break;
3752 case DC_REQ_FLUSH:
3753 myrpt->rem_dtmfidx = 0;
3754 myrpt->rem_dtmfbuf[0] = 0;
3755 break;
3758 case DC_COMPLETE:
3759 myrpt->totalexecdcommands++;
3760 myrpt->dailyexecdcommands++;
3761 strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
3762 myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
3763 myrpt->rem_dtmfbuf[0] = 0;
3764 myrpt->rem_dtmfidx = -1;
3765 myrpt->rem_dtmf_time = 0;
3766 break;
3768 case DC_ERROR:
3769 default:
3770 myrpt->rem_dtmfbuf[0] = 0;
3771 myrpt->rem_dtmfidx = -1;
3772 myrpt->rem_dtmf_time = 0;
3773 break;
3778 rpt_mutex_unlock(&myrpt->lock);
3779 return;
3782 static void handle_link_phone_dtmf(struct rpt *myrpt, struct rpt_link *mylink,
3783 char c)
3786 char cmd[300];
3787 int res;
3789 rpt_mutex_lock(&myrpt->lock);
3790 if (c == myrpt->p.endchar)
3792 if (mylink->lastrx)
3794 mylink->lastrx = 0;
3795 rpt_mutex_unlock(&myrpt->lock);
3796 return;
3798 myrpt->stopgen = 1;
3799 if (myrpt->cmdnode[0])
3801 myrpt->cmdnode[0] = 0;
3802 myrpt->dtmfidx = -1;
3803 myrpt->dtmfbuf[0] = 0;
3804 rpt_mutex_unlock(&myrpt->lock);
3805 rpt_telemetry(myrpt,COMPLETE,NULL);
3806 return;
3809 if (myrpt->cmdnode[0])
3811 rpt_mutex_unlock(&myrpt->lock);
3812 send_link_dtmf(myrpt,c);
3813 return;
3815 if (myrpt->callmode == 1)
3817 myrpt->exten[myrpt->cidx++] = c;
3818 myrpt->exten[myrpt->cidx] = 0;
3819 /* if this exists */
3820 if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
3822 myrpt->callmode = 2;
3823 if(!myrpt->patchquiet){
3824 rpt_mutex_unlock(&myrpt->lock);
3825 rpt_telemetry(myrpt,PROC,NULL);
3826 rpt_mutex_lock(&myrpt->lock);
3829 /* if can continue, do so */
3830 if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
3832 /* call has failed, inform user */
3833 myrpt->callmode = 4;
3836 if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
3838 myrpt->mydtmf = c;
3840 if (c == myrpt->p.funcchar)
3842 myrpt->rem_dtmfidx = 0;
3843 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
3844 time(&myrpt->rem_dtmf_time);
3845 rpt_mutex_unlock(&myrpt->lock);
3846 return;
3848 else if ((c != myrpt->p.endchar) && (myrpt->rem_dtmfidx >= 0))
3850 time(&myrpt->rem_dtmf_time);
3851 if (myrpt->rem_dtmfidx < MAXDTMF)
3853 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
3854 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
3856 rpt_mutex_unlock(&myrpt->lock);
3857 strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
3858 switch(mylink->phonemode)
3860 case 1:
3861 res = collect_function_digits(myrpt, cmd,
3862 SOURCE_PHONE, mylink);
3863 break;
3864 case 2:
3865 res = collect_function_digits(myrpt, cmd,
3866 SOURCE_DPHONE,mylink);
3867 break;
3868 default:
3869 res = collect_function_digits(myrpt, cmd,
3870 SOURCE_LNK, mylink);
3871 break;
3874 rpt_mutex_lock(&myrpt->lock);
3876 switch(res){
3878 case DC_INDETERMINATE:
3879 break;
3881 case DC_DOKEY:
3882 mylink->lastrx = 1;
3883 break;
3885 case DC_REQ_FLUSH:
3886 myrpt->rem_dtmfidx = 0;
3887 myrpt->rem_dtmfbuf[0] = 0;
3888 break;
3891 case DC_COMPLETE:
3892 myrpt->totalexecdcommands++;
3893 myrpt->dailyexecdcommands++;
3894 strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
3895 myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
3896 myrpt->rem_dtmfbuf[0] = 0;
3897 myrpt->rem_dtmfidx = -1;
3898 myrpt->rem_dtmf_time = 0;
3899 break;
3901 case DC_ERROR:
3902 default:
3903 myrpt->rem_dtmfbuf[0] = 0;
3904 myrpt->rem_dtmfidx = -1;
3905 myrpt->rem_dtmf_time = 0;
3906 break;
3911 rpt_mutex_unlock(&myrpt->lock);
3912 return;
3915 /* Doug Hall RBI-1 serial data definitions:
3917 * Byte 0: Expansion external outputs
3918 * Byte 1:
3919 * Bits 0-3 are BAND as follows:
3920 * Bits 4-5 are POWER bits as follows:
3921 * 00 - Low Power
3922 * 01 - Hi Power
3923 * 02 - Med Power
3924 * Bits 6-7 are always set
3925 * Byte 2:
3926 * Bits 0-3 MHZ in BCD format
3927 * Bits 4-5 are offset as follows:
3928 * 00 - minus
3929 * 01 - plus
3930 * 02 - simplex
3931 * 03 - minus minus (whatever that is)
3932 * Bit 6 is the 0/5 KHZ bit
3933 * Bit 7 is always set
3934 * Byte 3:
3935 * Bits 0-3 are 10 KHZ in BCD format
3936 * Bits 4-7 are 100 KHZ in BCD format
3937 * Byte 4: PL Tone code and encode/decode enable bits
3938 * Bits 0-5 are PL tone code (comspec binary codes)
3939 * Bit 6 is encode enable/disable
3940 * Bit 7 is decode enable/disable
3943 /* take the frequency from the 10 mhz digits (and up) and convert it
3944 to a band number */
3946 static int rbi_mhztoband(char *str)
3948 int i;
3950 i = atoi(str) / 10; /* get the 10's of mhz */
3951 switch(i)
3953 case 2:
3954 return 10;
3955 case 5:
3956 return 11;
3957 case 14:
3958 return 2;
3959 case 22:
3960 return 3;
3961 case 44:
3962 return 4;
3963 case 124:
3964 return 0;
3965 case 125:
3966 return 1;
3967 case 126:
3968 return 8;
3969 case 127:
3970 return 5;
3971 case 128:
3972 return 6;
3973 case 129:
3974 return 7;
3975 default:
3976 break;
3978 return -1;
3981 /* take a PL frequency and turn it into a code */
3982 static int rbi_pltocode(char *str)
3984 int i;
3985 char *s;
3987 s = strchr(str,'.');
3988 i = 0;
3989 if (s) i = atoi(s + 1);
3990 i += atoi(str) * 10;
3991 switch(i)
3993 case 670:
3994 return 0;
3995 case 719:
3996 return 1;
3997 case 744:
3998 return 2;
3999 case 770:
4000 return 3;
4001 case 797:
4002 return 4;
4003 case 825:
4004 return 5;
4005 case 854:
4006 return 6;
4007 case 885:
4008 return 7;
4009 case 915:
4010 return 8;
4011 case 948:
4012 return 9;
4013 case 974:
4014 return 10;
4015 case 1000:
4016 return 11;
4017 case 1035:
4018 return 12;
4019 case 1072:
4020 return 13;
4021 case 1109:
4022 return 14;
4023 case 1148:
4024 return 15;
4025 case 1188:
4026 return 16;
4027 case 1230:
4028 return 17;
4029 case 1273:
4030 return 18;
4031 case 1318:
4032 return 19;
4033 case 1365:
4034 return 20;
4035 case 1413:
4036 return 21;
4037 case 1462:
4038 return 22;
4039 case 1514:
4040 return 23;
4041 case 1567:
4042 return 24;
4043 case 1622:
4044 return 25;
4045 case 1679:
4046 return 26;
4047 case 1738:
4048 return 27;
4049 case 1799:
4050 return 28;
4051 case 1862:
4052 return 29;
4053 case 1928:
4054 return 30;
4055 case 2035:
4056 return 31;
4057 case 2107:
4058 return 32;
4059 case 2181:
4060 return 33;
4061 case 2257:
4062 return 34;
4063 case 2336:
4064 return 35;
4065 case 2418:
4066 return 36;
4067 case 2503:
4068 return 37;
4070 return -1;
4074 * Shift out a formatted serial bit stream
4077 static void rbi_out_parallel(struct rpt *myrpt,unsigned char *data)
4079 int i,j;
4080 unsigned char od,d;
4081 static volatile long long delayvar;
4083 for(i = 0 ; i < 5 ; i++){
4084 od = *data++;
4085 for(j = 0 ; j < 8 ; j++){
4086 d = od & 1;
4087 outb(d,myrpt->p.iobase);
4088 /* >= 15 us */
4089 for(delayvar = 1; delayvar < 15000; delayvar++);
4090 od >>= 1;
4091 outb(d | 2,myrpt->p.iobase);
4092 /* >= 30 us */
4093 for(delayvar = 1; delayvar < 30000; delayvar++);
4094 outb(d,myrpt->p.iobase);
4095 /* >= 10 us */
4096 for(delayvar = 1; delayvar < 10000; delayvar++);
4099 /* >= 50 us */
4100 for(delayvar = 1; delayvar < 50000; delayvar++);
4103 static void rbi_out(struct rpt *myrpt,unsigned char *data)
4105 struct zt_radio_param r;
4107 memset(&r,0,sizeof(struct zt_radio_param));
4108 r.radpar = ZT_RADPAR_REMMODE;
4109 r.data = ZT_RADPAR_REM_RBI1;
4110 /* if setparam ioctl fails, its probably not a pciradio card */
4111 if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&r) == -1)
4113 rbi_out_parallel(myrpt,data);
4114 return;
4116 r.radpar = ZT_RADPAR_REMCOMMAND;
4117 memcpy(&r.data,data,5);
4118 if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&r) == -1)
4120 ast_log(LOG_WARNING,"Cannot send RBI command for channel %s\n",myrpt->rxchannel->name);
4121 return;
4125 static int serial_remote_io(struct rpt *myrpt, unsigned char *txbuf, int txbytes, char *rxbuf,
4126 int rxmaxbytes, int asciiflag)
4128 int i;
4129 struct zt_radio_param prm;
4131 if(debug){
4132 printf("String output was: ");
4133 for(i = 0; i < txbytes; i++)
4134 printf("%02X ", (unsigned char ) txbuf[i]);
4135 printf("\n");
4138 prm.radpar = ZT_RADPAR_REMMODE;
4139 if (asciiflag) prm.data = ZT_RADPAR_REM_SERIAL_ASCII;
4140 else prm.data = ZT_RADPAR_REM_SERIAL;
4141 if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&prm) == -1) return -1;
4142 prm.radpar = ZT_RADPAR_REMCOMMAND;
4143 prm.data = rxmaxbytes;
4144 memcpy(prm.buf,txbuf,txbytes);
4145 prm.index = txbytes;
4146 if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&prm) == -1) return -1;
4147 if (rxbuf)
4149 *rxbuf = 0;
4150 memcpy(rxbuf,prm.buf,prm.index);
4152 return(prm.index);
4155 static int setrbi(struct rpt *myrpt)
4157 char tmp[MAXREMSTR] = "",*s;
4158 unsigned char rbicmd[5];
4159 int band,txoffset = 0,txpower = 0,txpl;
4161 /* must be a remote system */
4162 if (!myrpt->remote) return(0);
4163 /* must have rbi hardware */
4164 if (strncmp(myrpt->remote,remote_rig_rbi,3)) return(0);
4165 strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
4166 s = strchr(tmp,'.');
4167 /* if no decimal, is invalid */
4169 if (s == NULL){
4170 if(debug)
4171 printf("@@@@ Frequency needs a decimal\n");
4172 return -1;
4175 *s++ = 0;
4176 if (strlen(tmp) < 2){
4177 if(debug)
4178 printf("@@@@ Bad MHz digits: %s\n", tmp);
4179 return -1;
4182 if (strlen(s) < 3){
4183 if(debug)
4184 printf("@@@@ Bad KHz digits: %s\n", s);
4185 return -1;
4188 if ((s[2] != '0') && (s[2] != '5')){
4189 if(debug)
4190 printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
4191 return -1;
4194 band = rbi_mhztoband(tmp);
4195 if (band == -1){
4196 if(debug)
4197 printf("@@@@ Bad Band: %s\n", tmp);
4198 return -1;
4201 txpl = rbi_pltocode(myrpt->txpl);
4203 if (txpl == -1){
4204 if(debug)
4205 printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
4206 return -1;
4210 switch(myrpt->offset)
4212 case REM_MINUS:
4213 txoffset = 0;
4214 break;
4215 case REM_PLUS:
4216 txoffset = 0x10;
4217 break;
4218 case REM_SIMPLEX:
4219 txoffset = 0x20;
4220 break;
4222 switch(myrpt->powerlevel)
4224 case REM_LOWPWR:
4225 txpower = 0;
4226 break;
4227 case REM_MEDPWR:
4228 txpower = 0x20;
4229 break;
4230 case REM_HIPWR:
4231 txpower = 0x10;
4232 break;
4234 rbicmd[0] = 0;
4235 rbicmd[1] = band | txpower | 0xc0;
4236 rbicmd[2] = (*(s - 2) - '0') | txoffset | 0x80;
4237 if (s[2] == '5') rbicmd[2] |= 0x40;
4238 rbicmd[3] = ((*s - '0') << 4) + (s[1] - '0');
4239 rbicmd[4] = txpl;
4240 if (myrpt->txplon) rbicmd[4] |= 0x40;
4241 if (myrpt->rxplon) rbicmd[4] |= 0x80;
4242 rbi_out(myrpt,rbicmd);
4243 return 0;
4247 /* Check for valid rbi frequency */
4248 /* Hard coded limits now, configurable later, maybe? */
4250 static int check_freq_rbi(int m, int d, int *defmode)
4252 int dflmd = REM_MODE_FM;
4254 if(m == 50){ /* 6 meters */
4255 if(d < 10100)
4256 return -1;
4258 else if((m >= 51) && ( m < 54)){
4261 else if(m == 144){ /* 2 meters */
4262 if(d < 10100)
4263 return -1;
4265 else if((m >= 145) && (m < 148)){
4268 else if((m >= 222) && (m < 225)){ /* 1.25 meters */
4271 else if((m >= 430) && (m < 450)){ /* 70 centimeters */
4274 else if((m >= 1240) && (m < 1300)){ /* 23 centimeters */
4277 else
4278 return -1;
4280 if(defmode)
4281 *defmode = dflmd;
4284 return 0;
4288 * Split frequency into mhz and decimals
4291 static int split_freq(char *mhz, char *decimals, char *freq)
4293 char freq_copy[MAXREMSTR];
4294 char *decp;
4296 decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
4297 if(decp){
4298 *decp++ = 0;
4299 strncpy(mhz, freq_copy, MAXREMSTR);
4300 strcpy(decimals, "00000");
4301 strncpy(decimals, decp, strlen(decp));
4302 decimals[5] = 0;
4303 return 0;
4305 else
4306 return -1;
4311 * Split ctcss frequency into hertz and decimal
4314 static int split_ctcss_freq(char *hertz, char *decimal, char *freq)
4316 char freq_copy[MAXREMSTR];
4317 char *decp;
4319 decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
4320 if(decp){
4321 *decp++ = 0;
4322 strncpy(hertz, freq_copy, MAXREMSTR);
4323 strncpy(decimal, decp, strlen(decp));
4324 decimal[strlen(decp)] = '\0';
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,*val;
4923 int i,j,ht,k,l,ls2,m,d,res,offset,offsave, modesave, defmode;
4924 char multimode = 0;
4925 char oc;
4926 char tmp[20], freq[20] = "", savestr[20] = "";
4927 char mhz[MAXREMSTR], decimals[MAXREMSTR];
4928 struct ast_channel *mychannel;
4930 if((!param) || (command_source == SOURCE_RPT) || (command_source == SOURCE_LNK))
4931 return DC_ERROR;
4933 multimode = multimode_capable(myrpt);
4935 mychannel = myrpt->remchannel;
4938 switch(myatoi(param)){
4940 case 1: /* retrieve memory */
4941 if(strlen(digitbuf) < 2) /* needs 2 digits */
4942 break;
4944 for(i = 0 ; i < 2 ; i++){
4945 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
4946 return DC_ERROR;
4949 val = ast_variable_retrieve(myrpt->cfg, myrpt->p.memory, digitbuf);
4950 if (!val){
4951 if (ast_safe_sleep(mychannel,1000) == -1)
4952 return DC_ERROR;
4953 sayfile(mychannel,"rpt/memory_notfound");
4954 return DC_COMPLETE;
4956 strncpy(tmp,val,sizeof(tmp) - 1);
4957 s = strchr(tmp,',');
4958 if (!s)
4959 return DC_ERROR;
4960 *s++ = 0;
4961 s1 = strchr(s,',');
4962 if (!s1)
4963 return DC_ERROR;
4964 *s1++ = 0;
4965 strncpy(myrpt->freq, tmp, sizeof(myrpt->freq) - 1);
4966 strncpy(myrpt->rxpl, s, sizeof(myrpt->rxpl) - 1);
4967 strncpy(myrpt->txpl, s, sizeof(myrpt->rxpl) - 1);
4968 myrpt->remmode = REM_MODE_FM;
4969 myrpt->offset = REM_SIMPLEX;
4970 myrpt->powerlevel = REM_MEDPWR;
4971 myrpt->txplon = myrpt->rxplon = 0;
4972 while(*s1)
4974 switch(*s1++){
4975 case 'A':
4976 case 'a':
4977 strcpy(myrpt->rxpl, "100.0");
4978 strcpy(myrpt->txpl, "100.0");
4979 myrpt->remmode = REM_MODE_AM;
4980 break;
4982 case 'B':
4983 case 'b':
4984 strcpy(myrpt->rxpl, "100.0");
4985 strcpy(myrpt->txpl, "100.0");
4986 myrpt->remmode = REM_MODE_LSB;
4987 break;
4989 case 'F':
4990 myrpt->remmode = REM_MODE_FM;
4991 break;
4993 case 'L':
4994 case 'l':
4995 myrpt->powerlevel = REM_LOWPWR;
4996 break;
4997 case 'H':
4998 case 'h':
4999 myrpt->powerlevel = REM_HIPWR;
5000 break;
5002 case 'M':
5003 case 'm':
5004 myrpt->powerlevel = REM_MEDPWR;
5005 break;
5007 case '-':
5008 myrpt->offset = REM_MINUS;
5009 break;
5011 case '+':
5012 myrpt->offset = REM_PLUS;
5013 break;
5015 case 'S':
5016 case 's':
5017 myrpt->offset = REM_SIMPLEX;
5018 break;
5020 case 'T':
5021 case 't':
5022 myrpt->txplon = 1;
5023 break;
5025 case 'R':
5026 case 'r':
5027 myrpt->rxplon = 1;
5028 break;
5030 case 'U':
5031 case 'u':
5032 strcpy(myrpt->rxpl, "100.0");
5033 strcpy(myrpt->txpl, "100.0");
5034 myrpt->remmode = REM_MODE_USB;
5035 break;
5040 if (setrem(myrpt) == -1)
5041 return DC_ERROR;
5044 return DC_COMPLETE;
5046 case 2: /* set freq and offset */
5049 for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for M+*K+*O or M+*H+* depending on mode */
5050 if(digitbuf[i] == '*'){
5051 j++;
5052 continue;
5054 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
5055 goto invalid_freq;
5056 else{
5057 if(j == 0)
5058 l++; /* # of digits before first * */
5059 if(j == 1)
5060 k++; /* # of digits after first * */
5064 i = strlen(digitbuf) - 1;
5065 if(multimode){
5066 if((j > 2) || (l > 3) || (k > 6))
5067 goto invalid_freq; /* &^@#! */
5069 else{
5070 if((j > 2) || (l > 4) || (k > 3))
5071 goto invalid_freq; /* &^@#! */
5074 /* Wait for M+*K+* */
5076 if(j < 2)
5077 break; /* Not yet */
5079 /* We have a frequency */
5081 strncpy(tmp, digitbuf ,sizeof(tmp) - 1);
5083 s = tmp;
5084 s1 = strsep(&s, "*"); /* Pick off MHz */
5085 s2 = strsep(&s,"*"); /* Pick off KHz and Hz */
5086 ls2 = strlen(s2);
5088 switch(ls2){ /* Allow partial entry of khz and hz digits for laziness support */
5089 case 1:
5090 ht = 0;
5091 k = 100 * atoi(s2);
5092 break;
5094 case 2:
5095 ht = 0;
5096 k = 10 * atoi(s2);
5097 break;
5099 case 3:
5100 if(!multimode){
5101 if((s2[2] != '0')&&(s2[2] != '5'))
5102 goto invalid_freq;
5104 ht = 0;
5105 k = atoi(s2);
5106 break;
5107 case 4:
5108 k = atoi(s2)/10;
5109 ht = 10 * (atoi(s2+(ls2-1)));
5110 break;
5112 case 5:
5113 k = atoi(s2)/100;
5114 ht = (atoi(s2+(ls2-2)));
5115 break;
5117 default:
5118 goto invalid_freq;
5121 /* Check frequency for validity and establish a default mode */
5123 snprintf(freq, sizeof(freq), "%s.%03d%02d",s1, k, ht);
5125 if(debug)
5126 printf("New frequency: %s\n", freq);
5128 split_freq(mhz, decimals, freq);
5129 m = atoi(mhz);
5130 d = atoi(decimals);
5132 if(check_freq(myrpt, m, d, &defmode)) /* Check to see if frequency entered is legit */
5133 goto invalid_freq;
5136 if((defmode == REM_MODE_FM) && (digitbuf[i] == '*')) /* If FM, user must enter and additional offset digit */
5137 break; /* Not yet */
5140 offset = REM_SIMPLEX; /* Assume simplex */
5142 if(defmode == REM_MODE_FM){
5143 oc = *s; /* Pick off offset */
5145 if (oc){
5146 switch(oc){
5147 case '1':
5148 offset = REM_MINUS;
5149 break;
5151 case '2':
5152 offset = REM_SIMPLEX;
5153 break;
5155 case '3':
5156 offset = REM_PLUS;
5157 break;
5159 default:
5160 goto invalid_freq;
5164 offsave = myrpt->offset;
5165 modesave = myrpt->remmode;
5166 strncpy(savestr, myrpt->freq, sizeof(savestr) - 1);
5167 strncpy(myrpt->freq, freq, sizeof(myrpt->freq) - 1);
5168 myrpt->offset = offset;
5169 myrpt->remmode = defmode;
5171 if (setrem(myrpt) == -1){
5172 myrpt->offset = offsave;
5173 myrpt->remmode = modesave;
5174 strncpy(myrpt->freq, savestr, sizeof(myrpt->freq) - 1);
5175 goto invalid_freq;
5178 return DC_COMPLETE;
5181 invalid_freq:
5183 rmt_sayfile(myrpt, mychannel, 1000, "rpt/invalid-freq");
5185 return DC_ERROR;
5187 case 3: /* set rx PL tone */
5189 for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
5190 if(digitbuf[i] == '*'){
5191 j++;
5192 continue;
5194 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
5195 return DC_ERROR;
5196 else{
5197 if(j)
5198 l++;
5199 else
5200 k++;
5203 if((j > 1) || (k > 3) || (l > 1))
5204 return DC_ERROR; /* &$@^! */
5205 i = strlen(digitbuf) - 1;
5206 if((j != 1) || (k < 2)|| (l != 1))
5207 break; /* Not yet */
5208 if(debug)
5209 printf("PL digits entered %s\n", digitbuf);
5211 strncpy(tmp, digitbuf, sizeof(tmp) - 1);
5212 /* see if we have at least 1 */
5213 s = strchr(tmp,'*');
5214 if(s)
5215 *s = '.';
5216 strncpy(savestr, myrpt->rxpl, sizeof(savestr) - 1);
5217 strncpy(myrpt->rxpl, tmp, sizeof(myrpt->rxpl) - 1);
5219 if (setrem(myrpt) == -1){
5220 strncpy(myrpt->rxpl, savestr, sizeof(myrpt->rxpl) - 1);
5221 return DC_ERROR;
5225 return DC_COMPLETE;
5227 case 4: /* set tx PL tone */
5229 for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
5230 if(digitbuf[i] == '*'){
5231 j++;
5232 continue;
5234 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
5235 return DC_ERROR;
5236 else{
5237 if(j)
5238 l++;
5239 else
5240 k++;
5243 if((j > 1) || (k > 3) || (l > 1))
5244 return DC_ERROR; /* &$@^! */
5245 i = strlen(digitbuf) - 1;
5246 if((j != 1) || (k < 2)|| (l != 1))
5247 break; /* Not yet */
5248 if(debug)
5249 printf("PL digits entered %s\n", digitbuf);
5251 strncpy(tmp, digitbuf, sizeof(tmp) - 1);
5252 /* see if we have at least 1 */
5253 s = strchr(tmp,'*');
5254 if(s)
5255 *s = '.';
5256 strncpy(savestr, myrpt->txpl, sizeof(savestr) - 1);
5257 strncpy(myrpt->txpl, tmp, sizeof(myrpt->txpl) - 1);
5259 if (setrem(myrpt) == -1){
5260 strncpy(myrpt->txpl, savestr, sizeof(myrpt->txpl) - 1);
5261 return DC_ERROR;
5265 return DC_COMPLETE;
5268 case 6: /* MODE (FM,USB,LSB,AM) */
5269 if(strlen(digitbuf) < 1)
5270 break;
5272 if(!multimode)
5273 return DC_ERROR; /* Multimode radios only */
5275 switch(*digitbuf){
5276 case '1':
5277 split_freq(mhz, decimals, myrpt->freq);
5278 m=atoi(mhz);
5279 if(m < 29) /* No FM allowed below 29MHz! */
5280 return DC_ERROR;
5281 myrpt->remmode = REM_MODE_FM;
5282 res = rmt_saycharstr(myrpt, mychannel, 1000,"FM");
5283 break;
5285 case '2':
5286 myrpt->remmode = REM_MODE_USB;
5287 res = rmt_saycharstr(myrpt, mychannel, 1000,"USB");
5288 break;
5290 case '3':
5291 myrpt->remmode = REM_MODE_LSB;
5292 res = rmt_saycharstr(myrpt, mychannel, 1000,"LSB");
5293 break;
5295 case '4':
5296 myrpt->remmode = REM_MODE_AM;
5297 res = rmt_saycharstr(myrpt, mychannel, 1000,"AM");
5298 break;
5300 default:
5301 return DC_ERROR;
5303 if(res)
5304 return DC_ERROR;
5306 if(setrem(myrpt))
5307 return DC_ERROR;
5308 return DC_COMPLETE;
5310 case 100: /* other stuff */
5311 case 101:
5312 case 102:
5313 case 103:
5314 case 104:
5315 case 105:
5316 case 106:
5317 res = rmt_telem_start(myrpt, mychannel, 1000);
5318 switch(myatoi(param)){ /* Quick commands requiring a setrem call */
5319 case 100: /* RX PL Off */
5320 myrpt->rxplon = 0;
5321 if(!res)
5322 res = sayfile(mychannel, "rpt/rxpl");
5323 if(!res)
5324 sayfile(mychannel, "rpt/off");
5325 break;
5327 case 101: /* RX PL On */
5328 myrpt->rxplon = 1;
5329 if(!res)
5330 res = sayfile(mychannel, "rpt/rxpl");
5331 if(!res)
5332 sayfile(mychannel, "rpt/on");
5333 break;
5336 case 102: /* TX PL Off */
5337 myrpt->txplon = 0;
5338 if(!res)
5339 res = sayfile(mychannel, "rpt/txpl");
5340 if(!res)
5341 sayfile(mychannel, "rpt/off");
5342 break;
5344 case 103: /* TX PL On */
5345 myrpt->txplon = 1;
5346 if(!res)
5347 res = sayfile(mychannel, "rpt/txpl");
5348 if(!res)
5349 sayfile(mychannel, "rpt/on");
5350 break;
5352 case 104: /* Low Power */
5353 myrpt->powerlevel = REM_LOWPWR;
5354 if(!res)
5355 res = sayfile(mychannel, "rpt/lopwr");
5356 break;
5358 case 105: /* Medium Power */
5359 myrpt->powerlevel = REM_MEDPWR;
5360 if(!res)
5361 res = sayfile(mychannel, "rpt/medpwr");
5362 break;
5364 case 106: /* Hi Power */
5365 myrpt->powerlevel = REM_HIPWR;
5366 if(!res)
5367 res = sayfile(mychannel, "rpt/hipwr");
5368 break;
5370 default:
5371 if(!res)
5372 rmt_telem_finish(myrpt, mychannel);
5373 return DC_ERROR;
5375 if(!res)
5376 res = rmt_telem_finish(myrpt, mychannel);
5377 if(res)
5378 return DC_ERROR;
5380 if (setrem(myrpt) == -1)
5381 return DC_ERROR;
5382 return DC_COMPLETE;
5384 case 107: /* Bump down 20Hz */
5385 multimode_bump_freq(myrpt, -20);
5386 return DC_COMPLETE;
5388 case 108: /* Bump down 100Hz */
5389 multimode_bump_freq(myrpt, -100);
5390 return DC_COMPLETE;
5392 case 109: /* Bump down 500Hz */
5393 multimode_bump_freq(myrpt, -500);
5394 return DC_COMPLETE;
5396 case 110: /* Bump up 20Hz */
5397 multimode_bump_freq(myrpt, 20);
5398 return DC_COMPLETE;
5400 case 111: /* Bump up 100Hz */
5401 multimode_bump_freq(myrpt, 100);
5402 return DC_COMPLETE;
5404 case 112: /* Bump up 500Hz */
5405 multimode_bump_freq(myrpt, 500);
5406 return DC_COMPLETE;
5409 case 113:
5410 case 114:
5411 case 115:
5412 case 116:
5413 case 117:
5414 case 118:
5415 myrpt->remotetx = 0;
5416 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
5417 if (!myrpt->remoterx)
5418 ast_indicate(mychannel,AST_CONTROL_RADIO_KEY);
5419 if (ast_safe_sleep(mychannel,1000) == -1)
5420 return DC_ERROR;
5422 switch(myatoi(param)){
5424 case 113: /* Scan down slow */
5425 res = sayfile(mychannel,"rpt/down");
5426 if(!res)
5427 res = sayfile(mychannel, "rpt/slow");
5428 if(!res){
5429 myrpt->scantimer = REM_SCANTIME;
5430 myrpt->hfscanmode = HF_SCAN_DOWN_SLOW;
5432 break;
5434 case 114: /* Scan down quick */
5435 res = sayfile(mychannel,"rpt/down");
5436 if(!res)
5437 res = sayfile(mychannel, "rpt/quick");
5438 if(!res){
5439 myrpt->scantimer = REM_SCANTIME;
5440 myrpt->hfscanmode = HF_SCAN_DOWN_QUICK;
5442 break;
5444 case 115: /* Scan down fast */
5445 res = sayfile(mychannel,"rpt/down");
5446 if(!res)
5447 res = sayfile(mychannel, "rpt/fast");
5448 if(!res){
5449 myrpt->scantimer = REM_SCANTIME;
5450 myrpt->hfscanmode = HF_SCAN_DOWN_FAST;
5452 break;
5454 case 116: /* Scan up slow */
5455 res = sayfile(mychannel,"rpt/up");
5456 if(!res)
5457 res = sayfile(mychannel, "rpt/slow");
5458 if(!res){
5459 myrpt->scantimer = REM_SCANTIME;
5460 myrpt->hfscanmode = HF_SCAN_UP_SLOW;
5462 break;
5464 case 117: /* Scan up quick */
5465 res = sayfile(mychannel,"rpt/up");
5466 if(!res)
5467 res = sayfile(mychannel, "rpt/quick");
5468 if(!res){
5469 myrpt->scantimer = REM_SCANTIME;
5470 myrpt->hfscanmode = HF_SCAN_UP_QUICK;
5472 break;
5474 case 118: /* Scan up fast */
5475 res = sayfile(mychannel,"rpt/up");
5476 if(!res)
5477 res = sayfile(mychannel, "rpt/fast");
5478 if(!res){
5479 myrpt->scantimer = REM_SCANTIME;
5480 myrpt->hfscanmode = HF_SCAN_UP_FAST;
5482 break;
5484 rmt_telem_finish(myrpt,mychannel);
5485 return DC_COMPLETE;
5488 case 119: /* Tune Request */
5489 myrpt->tunerequest = 1;
5490 return DC_COMPLETE;
5492 case 5: /* Long Status */
5493 case 140: /* Short Status */
5494 res = rmt_telem_start(myrpt, mychannel, 1000);
5496 res = sayfile(mychannel,"rpt/node");
5497 if(!res)
5498 res = saycharstr(mychannel, myrpt->name);
5499 if(!res)
5500 res = sayfile(mychannel,"rpt/frequency");
5501 if(!res)
5502 res = split_freq(mhz, decimals, myrpt->freq);
5503 if(!res){
5504 m = atoi(mhz);
5505 if(m < 100)
5506 res = saynum(mychannel, m);
5507 else
5508 res = saycharstr(mychannel, mhz);
5510 if(!res)
5511 res = sayfile(mychannel, "letters/dot");
5512 if(!res)
5513 res = saycharstr(mychannel, decimals);
5515 if(res){
5516 rmt_telem_finish(myrpt,mychannel);
5517 return DC_ERROR;
5519 if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */
5520 switch(myrpt->offset){
5522 case REM_MINUS:
5523 res = sayfile(mychannel,"rpt/minus");
5524 break;
5526 case REM_SIMPLEX:
5527 res = sayfile(mychannel,"rpt/simplex");
5528 break;
5530 case REM_PLUS:
5531 res = sayfile(mychannel,"rpt/plus");
5532 break;
5534 default:
5535 return DC_ERROR;
5539 else{ /* Must be USB, LSB, or AM */
5540 switch(myrpt->remmode){
5542 case REM_MODE_USB:
5543 res = saycharstr(mychannel, "USB");
5544 break;
5546 case REM_MODE_LSB:
5547 res = saycharstr(mychannel, "LSB");
5548 break;
5550 case REM_MODE_AM:
5551 res = saycharstr(mychannel, "AM");
5552 break;
5555 default:
5556 return DC_ERROR;
5560 if (res == -1){
5561 rmt_telem_finish(myrpt,mychannel);
5562 return DC_ERROR;
5565 if(myatoi(param) == 140){ /* Short status? */
5566 if(!res)
5567 res = rmt_telem_finish(myrpt, mychannel);
5568 if(res)
5569 return DC_ERROR;
5570 return DC_COMPLETE;
5573 switch(myrpt->powerlevel){
5575 case REM_LOWPWR:
5576 res = sayfile(mychannel,"rpt/lopwr") ;
5577 break;
5579 case REM_MEDPWR:
5580 res = sayfile(mychannel,"rpt/medpwr");
5581 break;
5582 case REM_HIPWR:
5583 res = sayfile(mychannel,"rpt/hipwr");
5584 break;
5586 if (res || (sayfile(mychannel,"rpt/rxpl") == -1) ||
5587 (sayfile(mychannel,"rpt/frequency") == -1) ||
5588 (saycharstr(mychannel,myrpt->rxpl) == -1) ||
5589 (sayfile(mychannel,"rpt/txpl") == -1) ||
5590 (sayfile(mychannel,"rpt/frequency") == -1) ||
5591 (saycharstr(mychannel,myrpt->txpl) == -1) ||
5592 (sayfile(mychannel,"rpt/txpl") == -1) ||
5593 (sayfile(mychannel,((myrpt->txplon) ? "rpt/on" : "rpt/off")) == -1) ||
5594 (sayfile(mychannel,"rpt/rxpl") == -1) ||
5595 (sayfile(mychannel,((myrpt->rxplon) ? "rpt/on" : "rpt/off")) == -1))
5597 rmt_telem_finish(myrpt,mychannel);
5598 return DC_ERROR;
5600 if(!res)
5601 res = rmt_telem_finish(myrpt,mychannel);
5602 if(res)
5603 return DC_ERROR;
5605 return DC_COMPLETE;
5606 default:
5607 return DC_ERROR;
5610 return DC_INDETERMINATE;
5613 static int handle_remote_dtmf_digit(struct rpt *myrpt,char c, char *keyed, int phonemode)
5615 time_t now;
5616 int ret,res = 0,src;
5618 /* Stop scan mode if in scan mode */
5619 if(myrpt->hfscanmode){
5620 stop_scan(myrpt,0);
5621 return 0;
5624 time(&now);
5625 /* if timed-out */
5626 if ((myrpt->dtmf_time_rem + DTMF_TIMEOUT) < now)
5628 myrpt->dtmfidx = -1;
5629 myrpt->dtmfbuf[0] = 0;
5630 myrpt->dtmf_time_rem = 0;
5632 /* if decode not active */
5633 if (myrpt->dtmfidx == -1)
5635 /* if not lead-in digit, dont worry */
5636 if (c != myrpt->p.funcchar) return 0;
5637 myrpt->dtmfidx = 0;
5638 myrpt->dtmfbuf[0] = 0;
5639 myrpt->dtmf_time_rem = now;
5640 return 0;
5642 /* if too many in buffer, start over */
5643 if (myrpt->dtmfidx >= MAXDTMF)
5645 myrpt->dtmfidx = 0;
5646 myrpt->dtmfbuf[0] = 0;
5647 myrpt->dtmf_time_rem = now;
5649 if (c == myrpt->p.funcchar)
5651 /* if star at beginning, or 2 together, erase buffer */
5652 if ((myrpt->dtmfidx < 1) ||
5653 (myrpt->dtmfbuf[myrpt->dtmfidx - 1] == myrpt->p.funcchar))
5655 myrpt->dtmfidx = 0;
5656 myrpt->dtmfbuf[0] = 0;
5657 myrpt->dtmf_time_rem = now;
5658 return 0;
5661 myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
5662 myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
5663 myrpt->dtmf_time_rem = now;
5666 src = SOURCE_RMT;
5667 if (phonemode > 1) src = SOURCE_DPHONE;
5668 else if (phonemode) src = SOURCE_PHONE;
5669 ret = collect_function_digits(myrpt, myrpt->dtmfbuf, src, NULL);
5671 switch(ret){
5673 case DC_INDETERMINATE:
5674 res = 0;
5675 break;
5677 case DC_DOKEY:
5678 if (keyed) *keyed = 1;
5679 res = 0;
5680 break;
5682 case DC_REQ_FLUSH:
5683 myrpt->dtmfidx = 0;
5684 myrpt->dtmfbuf[0] = 0;
5685 res = 0;
5686 break;
5689 case DC_COMPLETE:
5690 myrpt->totalexecdcommands++;
5691 myrpt->dailyexecdcommands++;
5692 strncpy(myrpt->lastdtmfcommand, myrpt->dtmfbuf, MAXDTMF-1);
5693 myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
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 strncpy(tmp,str,sizeof(tmp) - 1);
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 char *val, *s, *s1, *s2, *tele;
5776 char tmp[300], deststr[300] = "";
5778 val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, l->name);
5779 if (!val)
5781 fprintf(stderr,"attempt_reconnect: cannot find node %s\n",l->name);
5782 return -1;
5785 rpt_mutex_lock(&myrpt->lock);
5786 /* remove from queue */
5787 remque((struct qelem *) l);
5788 rpt_mutex_unlock(&myrpt->lock);
5789 strncpy(tmp,val,sizeof(tmp) - 1);
5790 s = tmp;
5791 s1 = strsep(&s,",");
5792 s2 = strsep(&s,",");
5793 snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
5794 tele = strchr(deststr, '/');
5795 if (!tele) {
5796 fprintf(stderr,"attempt_reconnect:Dial number (%s) must be in format tech/number\n",deststr);
5797 return -1;
5799 *tele++ = 0;
5800 l->elaptime = 0;
5801 l->connecttime = 0;
5802 l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL);
5803 if (l->chan){
5804 ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
5805 ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
5806 l->chan->whentohangup = 0;
5807 l->chan->appl = "Apprpt";
5808 l->chan->data = "(Remote Rx)";
5809 if (option_verbose > 2)
5810 ast_verbose(VERBOSE_PREFIX_3 "rpt (attempt_reconnect) initiating call to %s/%s on %s\n",
5811 deststr, tele, l->chan->name);
5812 if(l->chan->cid.cid_num)
5813 free(l->chan->cid.cid_num);
5814 l->chan->cid.cid_num = strdup(myrpt->name);
5815 ast_call(l->chan,tele,999);
5818 else
5820 if (option_verbose > 2)
5821 ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
5822 deststr,tele,l->chan->name);
5823 return -1;
5825 rpt_mutex_lock(&myrpt->lock);
5826 /* put back in queue */
5827 insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
5828 rpt_mutex_unlock(&myrpt->lock);
5829 ast_log(LOG_NOTICE,"Reconnect Attempt to %s in process\n",l->name);
5830 return 0;
5833 /* 0 return=continue, 1 return = break, -1 return = error */
5834 static void local_dtmf_helper(struct rpt *myrpt,char c)
5836 int res;
5837 pthread_attr_t attr;
5838 char cmd[MAXDTMF+1] = "";
5840 if (c == myrpt->p.endchar)
5842 /* if in simple mode, kill autopatch */
5843 if (myrpt->p.simple && myrpt->callmode)
5845 rpt_mutex_lock(&myrpt->lock);
5846 myrpt->callmode = 0;
5847 rpt_mutex_unlock(&myrpt->lock);
5848 rpt_telemetry(myrpt,TERM,NULL);
5849 return;
5851 rpt_mutex_lock(&myrpt->lock);
5852 myrpt->stopgen = 1;
5853 if (myrpt->cmdnode[0])
5855 myrpt->cmdnode[0] = 0;
5856 myrpt->dtmfidx = -1;
5857 myrpt->dtmfbuf[0] = 0;
5858 rpt_mutex_unlock(&myrpt->lock);
5859 rpt_telemetry(myrpt,COMPLETE,NULL);
5860 } else rpt_mutex_unlock(&myrpt->lock);
5861 return;
5863 rpt_mutex_lock(&myrpt->lock);
5864 if (myrpt->cmdnode[0])
5866 rpt_mutex_unlock(&myrpt->lock);
5867 send_link_dtmf(myrpt,c);
5868 return;
5870 if (!myrpt->p.simple)
5872 if (c == myrpt->p.funcchar)
5874 myrpt->dtmfidx = 0;
5875 myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
5876 rpt_mutex_unlock(&myrpt->lock);
5877 time(&myrpt->dtmf_time);
5878 return;
5880 else if ((c != myrpt->p.endchar) && (myrpt->dtmfidx >= 0))
5882 time(&myrpt->dtmf_time);
5884 if (myrpt->dtmfidx < MAXDTMF)
5886 myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
5887 myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
5889 strncpy(cmd, myrpt->dtmfbuf, sizeof(cmd) - 1);
5891 rpt_mutex_unlock(&myrpt->lock);
5892 res = collect_function_digits(myrpt, cmd, SOURCE_RPT, NULL);
5893 rpt_mutex_lock(&myrpt->lock);
5894 switch(res){
5895 case DC_INDETERMINATE:
5896 break;
5897 case DC_REQ_FLUSH:
5898 myrpt->dtmfidx = 0;
5899 myrpt->dtmfbuf[0] = 0;
5900 break;
5901 case DC_COMPLETE:
5902 myrpt->totalexecdcommands++;
5903 myrpt->dailyexecdcommands++;
5904 strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
5905 myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
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 strncpy(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 return;
5944 if (myrpt->callmode == 1)
5946 myrpt->exten[myrpt->cidx++] = c;
5947 myrpt->exten[myrpt->cidx] = 0;
5948 /* if this exists */
5949 if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
5951 myrpt->callmode = 2;
5952 rpt_mutex_unlock(&myrpt->lock);
5953 if(!myrpt->patchquiet)
5954 rpt_telemetry(myrpt,PROC,NULL);
5955 return;
5957 /* if can continue, do so */
5958 if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
5960 /* call has failed, inform user */
5961 myrpt->callmode = 4;
5963 rpt_mutex_unlock(&myrpt->lock);
5964 return;
5966 if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
5968 myrpt->mydtmf = c;
5970 rpt_mutex_unlock(&myrpt->lock);
5971 return;
5975 /* place an ID event in the telemetry queue */
5977 static void queue_id(struct rpt *myrpt)
5979 myrpt->mustid = myrpt->tailid = 0;
5980 myrpt->idtimer = myrpt->p.idtime; /* Reset our ID timer */
5981 rpt_mutex_unlock(&myrpt->lock);
5982 rpt_telemetry(myrpt,ID,NULL);
5983 rpt_mutex_lock(&myrpt->lock);
5986 /* Scheduler */
5988 static void do_scheduler(struct rpt *myrpt)
5990 int res;
5991 struct tm tmnow;
5993 memcpy(&myrpt->lasttv, &myrpt->curtv, sizeof(struct timeval));
5995 if( (res = gettimeofday(&myrpt->curtv, NULL)) < 0)
5996 ast_log(LOG_NOTICE, "Scheduler gettime of day returned: %s\n", strerror(res));
5998 /* Try to get close to a 1 second resolution */
6000 if(myrpt->lasttv.tv_sec == myrpt->curtv.tv_sec)
6001 return;
6003 ast_localtime(&myrpt->curtv.tv_sec, &tmnow, NULL);
6005 /* If midnight, then reset all daily statistics */
6007 if((tmnow.tm_hour == 0)&&(tmnow.tm_min == 0)&&(tmnow.tm_sec == 0)){
6008 myrpt->dailykeyups = 0;
6009 myrpt->dailytxtime = 0;
6010 myrpt->dailykerchunks = 0;
6011 myrpt->dailyexecdcommands = 0;
6016 /* single thread with one file (request) to dial */
6017 static void *rpt(void *this)
6019 struct rpt *myrpt = (struct rpt *)this;
6020 char *tele,*idtalkover,c;
6021 int ms = MSWAIT,i,lasttx=0,val,remrx=0,identqueued,othertelemqueued,tailmessagequeued,ctqueued;
6022 struct ast_channel *who;
6023 ZT_CONFINFO ci; /* conference info */
6024 time_t t;
6025 struct rpt_link *l,*m;
6026 struct rpt_tele *telem;
6027 char tmpstr[300];
6029 rpt_mutex_lock(&myrpt->lock);
6031 telem = myrpt->tele.next;
6032 while(telem != &myrpt->tele)
6034 ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
6035 telem = telem->next;
6037 rpt_mutex_unlock(&myrpt->lock);
6038 /* find our index, and load the vars initially */
6039 for(i = 0; i < nrpts; i++)
6041 if (&rpt_vars[i] == myrpt)
6043 load_rpt_vars(i,0);
6044 break;
6047 rpt_mutex_lock(&myrpt->lock);
6048 strncpy(tmpstr,myrpt->rxchanname,sizeof(tmpstr) - 1);
6049 tele = strchr(tmpstr,'/');
6050 if (!tele)
6052 fprintf(stderr,"rpt:Rxchannel Dial number (%s) must be in format tech/number\n",myrpt->rxchanname);
6053 rpt_mutex_unlock(&myrpt->lock);
6054 myrpt->rpt_thread = AST_PTHREADT_STOP;
6055 pthread_exit(NULL);
6057 *tele++ = 0;
6058 myrpt->rxchannel = ast_request(tmpstr,AST_FORMAT_SLINEAR,tele,NULL);
6059 if (myrpt->rxchannel)
6061 if (myrpt->rxchannel->_state == AST_STATE_BUSY)
6063 fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
6064 rpt_mutex_unlock(&myrpt->lock);
6065 ast_hangup(myrpt->rxchannel);
6066 myrpt->rpt_thread = AST_PTHREADT_STOP;
6067 pthread_exit(NULL);
6069 ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
6070 ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
6071 myrpt->rxchannel->whentohangup = 0;
6072 myrpt->rxchannel->appl = "Apprpt";
6073 myrpt->rxchannel->data = "(Repeater Rx)";
6074 if (option_verbose > 2)
6075 ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
6076 tmpstr,tele,myrpt->rxchannel->name);
6077 ast_call(myrpt->rxchannel,tele,999);
6078 if (myrpt->rxchannel->_state != AST_STATE_UP)
6080 rpt_mutex_unlock(&myrpt->lock);
6081 ast_hangup(myrpt->rxchannel);
6082 myrpt->rpt_thread = AST_PTHREADT_STOP;
6083 pthread_exit(NULL);
6086 else
6088 fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
6089 rpt_mutex_unlock(&myrpt->lock);
6090 myrpt->rpt_thread = AST_PTHREADT_STOP;
6091 pthread_exit(NULL);
6093 if (myrpt->txchanname)
6095 strncpy(tmpstr,myrpt->txchanname,sizeof(tmpstr) - 1);
6096 tele = strchr(tmpstr,'/');
6097 if (!tele)
6099 fprintf(stderr,"rpt:Txchannel Dial number (%s) must be in format tech/number\n",myrpt->txchanname);
6100 rpt_mutex_unlock(&myrpt->lock);
6101 ast_hangup(myrpt->rxchannel);
6102 myrpt->rpt_thread = AST_PTHREADT_STOP;
6103 pthread_exit(NULL);
6105 *tele++ = 0;
6106 myrpt->txchannel = ast_request(tmpstr,AST_FORMAT_SLINEAR,tele,NULL);
6107 if (myrpt->txchannel)
6109 if (myrpt->txchannel->_state == AST_STATE_BUSY)
6111 fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
6112 rpt_mutex_unlock(&myrpt->lock);
6113 ast_hangup(myrpt->txchannel);
6114 ast_hangup(myrpt->rxchannel);
6115 myrpt->rpt_thread = AST_PTHREADT_STOP;
6116 pthread_exit(NULL);
6118 ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
6119 ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
6120 myrpt->txchannel->whentohangup = 0;
6121 myrpt->txchannel->appl = "Apprpt";
6122 myrpt->txchannel->data = "(Repeater Tx)";
6123 if (option_verbose > 2)
6124 ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
6125 tmpstr,tele,myrpt->txchannel->name);
6126 ast_call(myrpt->txchannel,tele,999);
6127 if (myrpt->rxchannel->_state != AST_STATE_UP)
6129 rpt_mutex_unlock(&myrpt->lock);
6130 ast_hangup(myrpt->rxchannel);
6131 ast_hangup(myrpt->txchannel);
6132 myrpt->rpt_thread = AST_PTHREADT_STOP;
6133 pthread_exit(NULL);
6136 else
6138 fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
6139 rpt_mutex_unlock(&myrpt->lock);
6140 ast_hangup(myrpt->rxchannel);
6141 myrpt->rpt_thread = AST_PTHREADT_STOP;
6142 pthread_exit(NULL);
6145 else
6147 myrpt->txchannel = myrpt->rxchannel;
6149 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
6150 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
6151 /* allocate a pseudo-channel thru asterisk */
6152 myrpt->pchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
6153 if (!myrpt->pchannel)
6155 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
6156 rpt_mutex_unlock(&myrpt->lock);
6157 if (myrpt->txchannel != myrpt->rxchannel)
6158 ast_hangup(myrpt->txchannel);
6159 ast_hangup(myrpt->rxchannel);
6160 myrpt->rpt_thread = AST_PTHREADT_STOP;
6161 pthread_exit(NULL);
6163 /* make a conference for the tx */
6164 ci.chan = 0;
6165 ci.confno = -1; /* make a new conf */
6166 ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER;
6167 /* first put the channel on the conference in proper mode */
6168 if (ioctl(myrpt->txchannel->fds[0],ZT_SETCONF,&ci) == -1)
6170 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
6171 rpt_mutex_unlock(&myrpt->lock);
6172 ast_hangup(myrpt->pchannel);
6173 if (myrpt->txchannel != myrpt->rxchannel)
6174 ast_hangup(myrpt->txchannel);
6175 ast_hangup(myrpt->rxchannel);
6176 myrpt->rpt_thread = AST_PTHREADT_STOP;
6177 pthread_exit(NULL);
6179 /* save tx conference number */
6180 myrpt->txconf = ci.confno;
6181 /* make a conference for the pseudo */
6182 ci.chan = 0;
6183 ci.confno = -1; /* make a new conf */
6184 ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? ZT_CONF_CONFANNMON :
6185 (ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER);
6186 /* first put the channel on the conference in announce mode */
6187 if (ioctl(myrpt->pchannel->fds[0],ZT_SETCONF,&ci) == -1)
6189 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
6190 rpt_mutex_unlock(&myrpt->lock);
6191 ast_hangup(myrpt->pchannel);
6192 if (myrpt->txchannel != myrpt->rxchannel)
6193 ast_hangup(myrpt->txchannel);
6194 ast_hangup(myrpt->rxchannel);
6195 myrpt->rpt_thread = AST_PTHREADT_STOP;
6196 pthread_exit(NULL);
6198 /* save pseudo channel conference number */
6199 myrpt->conf = ci.confno;
6200 /* allocate a pseudo-channel thru asterisk */
6201 myrpt->txpchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
6202 if (!myrpt->txpchannel)
6204 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
6205 rpt_mutex_unlock(&myrpt->lock);
6206 ast_hangup(myrpt->pchannel);
6207 if (myrpt->txchannel != myrpt->rxchannel)
6208 ast_hangup(myrpt->txchannel);
6209 ast_hangup(myrpt->rxchannel);
6210 myrpt->rpt_thread = AST_PTHREADT_STOP;
6211 pthread_exit(NULL);
6213 /* make a conference for the tx */
6214 ci.chan = 0;
6215 ci.confno = myrpt->txconf;
6216 ci.confmode = ZT_CONF_CONF | ZT_CONF_TALKER ;
6217 /* first put the channel on the conference in proper mode */
6218 if (ioctl(myrpt->txpchannel->fds[0],ZT_SETCONF,&ci) == -1)
6220 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
6221 rpt_mutex_unlock(&myrpt->lock);
6222 ast_hangup(myrpt->txpchannel);
6223 ast_hangup(myrpt->pchannel);
6224 if (myrpt->txchannel != myrpt->rxchannel)
6225 ast_hangup(myrpt->txchannel);
6226 ast_hangup(myrpt->rxchannel);
6227 myrpt->rpt_thread = AST_PTHREADT_STOP;
6228 pthread_exit(NULL);
6230 /* Now, the idea here is to copy from the physical rx channel buffer
6231 into the pseudo tx buffer, and from the pseudo rx buffer into the
6232 tx channel buffer */
6233 myrpt->links.next = &myrpt->links;
6234 myrpt->links.prev = &myrpt->links;
6235 myrpt->tailtimer = 0;
6236 myrpt->totimer = 0;
6237 myrpt->tmsgtimer = myrpt->p.tailmessagetime;
6238 myrpt->idtimer = myrpt->p.politeid;
6239 myrpt->mustid = myrpt->tailid = 0;
6240 myrpt->callmode = 0;
6241 myrpt->tounkeyed = 0;
6242 myrpt->tonotify = 0;
6243 myrpt->retxtimer = 0;
6244 myrpt->skedtimer = 0;
6245 myrpt->tailevent = 0;
6246 lasttx = 0;
6247 myrpt->keyed = 0;
6248 idtalkover = ast_variable_retrieve(myrpt->cfg, myrpt->name, "idtalkover");
6249 myrpt->dtmfidx = -1;
6250 myrpt->dtmfbuf[0] = 0;
6251 myrpt->rem_dtmfidx = -1;
6252 myrpt->rem_dtmfbuf[0] = 0;
6253 myrpt->dtmf_time = 0;
6254 myrpt->rem_dtmf_time = 0;
6255 myrpt->enable = 1;
6256 myrpt->disgorgetime = 0;
6257 myrpt->lastnodewhichkeyedusup[0] = '\0';
6258 myrpt->dailytxtime = 0;
6259 myrpt->totaltxtime = 0;
6260 myrpt->dailykeyups = 0;
6261 myrpt->totalkeyups = 0;
6262 myrpt->dailykerchunks = 0;
6263 myrpt->totalkerchunks = 0;
6264 myrpt->dailyexecdcommands = 0;
6265 myrpt->totalexecdcommands = 0;
6266 myrpt->timeouts = 0;
6267 myrpt->exten[0] = '\0';
6268 myrpt->lastdtmfcommand[0] = '\0';
6269 if (myrpt->p.startupmacro)
6271 snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
6273 rpt_mutex_unlock(&myrpt->lock);
6274 val = 0;
6275 ast_channel_setoption(myrpt->rxchannel,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0);
6276 val = 1;
6277 ast_channel_setoption(myrpt->rxchannel,AST_OPTION_RELAXDTMF,&val,sizeof(char),0);
6278 while (ms >= 0)
6280 struct ast_frame *f;
6281 struct ast_channel *cs[300];
6282 int totx=0,elap=0,n,toexit=0;
6284 /* DEBUG Dump */
6285 if((myrpt->disgorgetime) && (time(NULL) >= myrpt->disgorgetime)){
6286 struct rpt_link *zl;
6287 struct rpt_tele *zt;
6289 myrpt->disgorgetime = 0;
6290 ast_log(LOG_NOTICE,"********** Variable Dump Start (app_rpt) **********\n");
6291 ast_log(LOG_NOTICE,"totx = %d\n",totx);
6292 ast_log(LOG_NOTICE,"remrx = %d\n",remrx);
6293 ast_log(LOG_NOTICE,"lasttx = %d\n",lasttx);
6294 ast_log(LOG_NOTICE,"elap = %d\n",elap);
6295 ast_log(LOG_NOTICE,"toexit = %d\n",toexit);
6297 ast_log(LOG_NOTICE,"myrpt->keyed = %d\n",myrpt->keyed);
6298 ast_log(LOG_NOTICE,"myrpt->localtx = %d\n",myrpt->localtx);
6299 ast_log(LOG_NOTICE,"myrpt->callmode = %d\n",myrpt->callmode);
6300 ast_log(LOG_NOTICE,"myrpt->enable = %d\n",myrpt->enable);
6301 ast_log(LOG_NOTICE,"myrpt->mustid = %d\n",myrpt->mustid);
6302 ast_log(LOG_NOTICE,"myrpt->tounkeyed = %d\n",myrpt->tounkeyed);
6303 ast_log(LOG_NOTICE,"myrpt->tonotify = %d\n",myrpt->tonotify);
6304 ast_log(LOG_NOTICE,"myrpt->retxtimer = %ld\n",myrpt->retxtimer);
6305 ast_log(LOG_NOTICE,"myrpt->totimer = %d\n",myrpt->totimer);
6306 ast_log(LOG_NOTICE,"myrpt->tailtimer = %d\n",myrpt->tailtimer);
6307 ast_log(LOG_NOTICE,"myrpt->tailevent = %d\n",myrpt->tailevent);
6309 zl = myrpt->links.next;
6310 while(zl != &myrpt->links){
6311 ast_log(LOG_NOTICE,"*** Link Name: %s ***\n",zl->name);
6312 ast_log(LOG_NOTICE," link->lasttx %d\n",zl->lasttx);
6313 ast_log(LOG_NOTICE," link->lastrx %d\n",zl->lastrx);
6314 ast_log(LOG_NOTICE," link->connected %d\n",zl->connected);
6315 ast_log(LOG_NOTICE," link->hasconnected %d\n",zl->hasconnected);
6316 ast_log(LOG_NOTICE," link->outbound %d\n",zl->outbound);
6317 ast_log(LOG_NOTICE," link->disced %d\n",zl->disced);
6318 ast_log(LOG_NOTICE," link->killme %d\n",zl->killme);
6319 ast_log(LOG_NOTICE," link->disctime %ld\n",zl->disctime);
6320 ast_log(LOG_NOTICE," link->retrytimer %ld\n",zl->retrytimer);
6321 ast_log(LOG_NOTICE," link->retries = %d\n",zl->retries);
6322 ast_log(LOG_NOTICE," link->reconnects = %d\n",zl->reconnects);
6323 zl = zl->next;
6326 zt = myrpt->tele.next;
6327 if(zt != &myrpt->tele)
6328 ast_log(LOG_NOTICE,"*** Telemetry Queue ***\n");
6329 while(zt != &myrpt->tele){
6330 ast_log(LOG_NOTICE," Telemetry mode: %d\n",zt->mode);
6331 zt = zt->next;
6333 ast_log(LOG_NOTICE,"******* Variable Dump End (app_rpt) *******\n");
6338 if (myrpt->reload)
6340 struct rpt_tele *telem;
6342 rpt_mutex_lock(&myrpt->lock);
6343 telem = myrpt->tele.next;
6344 while(telem != &myrpt->tele)
6346 ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
6347 telem = telem->next;
6349 myrpt->reload = 0;
6350 rpt_mutex_unlock(&myrpt->lock);
6351 usleep(10000);
6352 /* find our index, and load the vars */
6353 for(i = 0; i < nrpts; i++)
6355 if (&rpt_vars[i] == myrpt)
6357 load_rpt_vars(i,0);
6358 break;
6363 rpt_mutex_lock(&myrpt->lock);
6364 if (ast_check_hangup(myrpt->rxchannel)) break;
6365 if (ast_check_hangup(myrpt->txchannel)) break;
6366 if (ast_check_hangup(myrpt->pchannel)) break;
6367 if (ast_check_hangup(myrpt->txpchannel)) break;
6369 /* Update local tx with keyed if not parsing a command */
6370 myrpt->localtx = myrpt->keyed && (myrpt->dtmfidx == -1) && (!myrpt->cmdnode[0]);
6371 /* If someone's connected, and they're transmitting from their end to us, set remrx true */
6372 l = myrpt->links.next;
6373 remrx = 0;
6374 while(l != &myrpt->links)
6376 if (l->lastrx){
6377 remrx = 1;
6378 if(l->name[0] != '0') /* Ignore '0' nodes */
6379 strcpy(myrpt->lastnodewhichkeyedusup, l->name); /* Note the node which is doing the key up */
6381 l = l->next;
6383 /* Create a "must_id" flag for the cleanup ID */
6384 myrpt->mustid |= (myrpt->idtimer) && (myrpt->keyed || remrx) ;
6385 /* Build a fresh totx from myrpt->keyed and autopatch activated */
6386 totx = myrpt->callmode;
6387 /* If full duplex, add local tx to totx */
6388 if (myrpt->p.duplex > 1) totx = totx || myrpt->localtx;
6389 /* Traverse the telemetry list to see what's queued */
6390 identqueued = 0;
6391 othertelemqueued = 0;
6392 tailmessagequeued = 0;
6393 ctqueued = 0;
6394 telem = myrpt->tele.next;
6395 while(telem != &myrpt->tele)
6397 if((telem->mode == ID) || (telem->mode == IDTALKOVER)){
6398 identqueued = 1; /* Identification telemetry */
6400 else if(telem->mode == TAILMSG)
6402 tailmessagequeued = 1; /* Tail message telemetry */
6404 else
6406 if (telem->mode != UNKEY)
6407 othertelemqueued = 1; /* Other telemetry */
6408 else
6409 ctqueued = 1; /* Courtesy tone telemetry */
6411 telem = telem->next;
6414 /* Add in any "other" telemetry, if 3/4 or full duplex */
6415 if (myrpt->p.duplex > 0) totx = totx || othertelemqueued;
6416 /* Update external (to links) transmitter PTT state with everything but ID, CT, and tailmessage telemetry */
6417 myrpt->exttx = totx;
6418 /* If half or 3/4 duplex, add localtx to external link tx */
6419 if (myrpt->p.duplex < 2) myrpt->exttx = myrpt->exttx || myrpt->localtx;
6420 /* Add in ID telemetry to local transmitter */
6421 totx = totx || remrx;
6422 /* If 3/4 or full duplex, add in ident and CT telemetry */
6423 if (myrpt->p.duplex > 0)
6424 totx = totx || identqueued || ctqueued;
6425 /* Reset time out timer variables if there is no activity */
6426 if (!totx)
6428 myrpt->totimer = myrpt->p.totime;
6429 myrpt->tounkeyed = 0;
6430 myrpt->tonotify = 0;
6432 else
6433 myrpt->tailtimer = myrpt->p.hangtime; /* Initialize tail timer */
6434 /* Disable the local transmitter if we are timed out */
6435 totx = totx && myrpt->totimer;
6436 /* if timed-out and not said already, say it */
6437 if ((!myrpt->totimer) && (!myrpt->tonotify))
6439 myrpt->tonotify = 1;
6440 myrpt->timeouts++;
6441 rpt_mutex_unlock(&myrpt->lock);
6442 rpt_telemetry(myrpt,TIMEOUT,NULL);
6443 rpt_mutex_lock(&myrpt->lock);
6446 /* If unkey and re-key, reset time out timer */
6447 if ((!totx) && (!myrpt->totimer) && (!myrpt->tounkeyed) && (!myrpt->keyed))
6449 myrpt->tounkeyed = 1;
6451 if ((!totx) && (!myrpt->totimer) && myrpt->tounkeyed && myrpt->keyed)
6453 myrpt->totimer = myrpt->p.totime;
6454 myrpt->tounkeyed = 0;
6455 myrpt->tonotify = 0;
6456 rpt_mutex_unlock(&myrpt->lock);
6457 continue;
6459 /* if timed-out and in circuit busy after call */
6460 if ((!totx) && (!myrpt->totimer) && (myrpt->callmode == 4))
6462 myrpt->callmode = 0;
6464 /* get rid of tail if timed out */
6465 if (!myrpt->totimer) myrpt->tailtimer = 0;
6466 /* if not timed-out, add in tail */
6467 if (myrpt->totimer) totx = totx || myrpt->tailtimer;
6468 /* If user or links key up or are keyed up over standard ID, switch to talkover ID, if one is defined */
6469 /* If tail message, kill the message if someone keys up over it */
6470 if ((myrpt->keyed || remrx) && ((identqueued && idtalkover) || (tailmessagequeued))) {
6471 int hasid = 0,hastalkover = 0;
6473 telem = myrpt->tele.next;
6474 while(telem != &myrpt->tele){
6475 if(telem->mode == ID){
6476 if (telem->chan) ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
6477 hasid = 1;
6479 if(telem->mode == TAILMSG){
6480 if (telem->chan) ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
6482 if (telem->mode == IDTALKOVER) hastalkover = 1;
6483 telem = telem->next;
6485 rpt_mutex_unlock(&myrpt->lock);
6486 if (hasid && (!hastalkover)) rpt_telemetry(myrpt, IDTALKOVER, NULL); /* Start Talkover ID */
6487 rpt_mutex_lock(&myrpt->lock);
6489 /* Try to be polite */
6490 /* If the repeater has been inactive for longer than the ID time, do an initial ID in the tail*/
6491 /* If within 30 seconds of the time to ID, try do it in the tail */
6492 /* else if at ID time limit, do it right over the top of them */
6493 /* Lastly, if the repeater has been keyed, and the ID timer is expired, do a clean up ID */
6494 if(myrpt->mustid && (!myrpt->idtimer))
6495 queue_id(myrpt);
6497 if ((totx && (!myrpt->exttx) &&
6498 (myrpt->idtimer <= myrpt->p.politeid) && myrpt->tailtimer))
6500 myrpt->tailid = 1;
6503 /* If tail timer expires, then check for tail messages */
6505 if(myrpt->tailevent){
6506 myrpt->tailevent = 0;
6507 if(myrpt->tailid){
6508 totx = 1;
6509 queue_id(myrpt);
6511 else if ((myrpt->p.tailmessages[0]) &&
6512 (myrpt->p.tailmessagetime) && (myrpt->tmsgtimer == 0)){
6513 totx = 1;
6514 myrpt->tmsgtimer = myrpt->p.tailmessagetime;
6515 rpt_mutex_unlock(&myrpt->lock);
6516 rpt_telemetry(myrpt, TAILMSG, NULL);
6517 rpt_mutex_lock(&myrpt->lock);
6521 /* Main TX control */
6523 /* let telemetry transmit anyway (regardless of timeout) */
6524 if (myrpt->p.duplex > 0) totx = totx || (myrpt->tele.next != &myrpt->tele);
6525 if (totx && (!lasttx))
6527 lasttx = 1;
6528 myrpt->dailykeyups++;
6529 myrpt->totalkeyups++;
6530 rpt_mutex_unlock(&myrpt->lock);
6531 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
6532 rpt_mutex_lock(&myrpt->lock);
6534 totx = totx && myrpt->enable;
6535 if ((!totx) && lasttx)
6537 lasttx = 0;
6538 rpt_mutex_unlock(&myrpt->lock);
6539 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
6540 rpt_mutex_lock(&myrpt->lock);
6542 time(&t);
6543 /* if DTMF timeout */
6544 if ((!myrpt->cmdnode[0]) && (myrpt->dtmfidx >= 0) && ((myrpt->dtmf_time + DTMF_TIMEOUT) < t))
6546 myrpt->dtmfidx = -1;
6547 myrpt->dtmfbuf[0] = 0;
6549 /* if remote DTMF timeout */
6550 if ((myrpt->rem_dtmfidx >= 0) && ((myrpt->rem_dtmf_time + DTMF_TIMEOUT) < t))
6552 myrpt->rem_dtmfidx = -1;
6553 myrpt->rem_dtmfbuf[0] = 0;
6556 /* Reconnect */
6558 l = myrpt->links.next;
6559 while(l != &myrpt->links)
6561 if (l->killme)
6563 /* remove from queue */
6564 remque((struct qelem *) l);
6565 if (!strcmp(myrpt->cmdnode,l->name))
6566 myrpt->cmdnode[0] = 0;
6567 rpt_mutex_unlock(&myrpt->lock);
6568 /* hang-up on call to device */
6569 if (l->chan) ast_hangup(l->chan);
6570 ast_hangup(l->pchan);
6571 free(l);
6572 rpt_mutex_lock(&myrpt->lock);
6573 /* re-start link traversal */
6574 l = myrpt->links.next;
6575 continue;
6577 l = l->next;
6579 n = 0;
6580 cs[n++] = myrpt->rxchannel;
6581 cs[n++] = myrpt->pchannel;
6582 cs[n++] = myrpt->txpchannel;
6583 if (myrpt->txchannel != myrpt->rxchannel) cs[n++] = myrpt->txchannel;
6584 l = myrpt->links.next;
6585 while(l != &myrpt->links)
6587 if ((!l->killme) && (!l->disctime) && l->chan)
6589 cs[n++] = l->chan;
6590 cs[n++] = l->pchan;
6592 l = l->next;
6594 rpt_mutex_unlock(&myrpt->lock);
6595 ms = MSWAIT;
6596 who = ast_waitfor_n(cs,n,&ms);
6597 if (who == NULL) ms = 0;
6598 elap = MSWAIT - ms;
6599 rpt_mutex_lock(&myrpt->lock);
6600 l = myrpt->links.next;
6601 while(l != &myrpt->links)
6603 if (!l->lasttx)
6605 if ((l->retxtimer += elap) >= REDUNDANT_TX_TIME)
6607 l->retxtimer = 0;
6608 if (l->chan) ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
6610 } else l->retxtimer = 0;
6611 if (l->disctime) /* Disconnect timer active on a channel ? */
6613 l->disctime -= elap;
6614 if (l->disctime <= 0) /* Disconnect timer expired on inbound channel ? */
6615 l->disctime = 0; /* Yep */
6618 if (l->retrytimer)
6620 l->retrytimer -= elap;
6621 if (l->retrytimer < 0) l->retrytimer = 0;
6624 /* Tally connect time */
6625 l->connecttime += elap;
6627 /* ignore non-timing channels */
6628 if (l->elaptime < 0)
6630 l = l->next;
6631 continue;
6633 l->elaptime += elap;
6634 /* if connection has taken too long */
6635 if ((l->elaptime > MAXCONNECTTIME) &&
6636 ((!l->chan) || (l->chan->_state != AST_STATE_UP)))
6638 l->elaptime = 0;
6639 rpt_mutex_unlock(&myrpt->lock);
6640 if (l->chan) ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
6641 rpt_mutex_lock(&myrpt->lock);
6642 break;
6644 if ((!l->chan) && (!l->retrytimer) && l->outbound &&
6645 (l->retries++ < MAX_RETRIES) && (l->hasconnected))
6647 if (l->chan) ast_hangup(l->chan);
6648 rpt_mutex_unlock(&myrpt->lock);
6649 if ((l->name[0] != '0') && (!l->isremote))
6651 l->retrytimer = MAX_RETRIES + 1;
6653 else
6655 if (attempt_reconnect(myrpt,l) == -1)
6657 l->retrytimer = RETRY_TIMER_MS;
6660 rpt_mutex_lock(&myrpt->lock);
6661 break;
6663 if ((!l->chan) && (!l->retrytimer) && l->outbound &&
6664 (l->retries >= MAX_RETRIES))
6666 /* remove from queue */
6667 remque((struct qelem *) l);
6668 if (!strcmp(myrpt->cmdnode,l->name))
6669 myrpt->cmdnode[0] = 0;
6670 rpt_mutex_unlock(&myrpt->lock);
6671 if (l->name[0] != '0')
6673 if (!l->hasconnected)
6674 rpt_telemetry(myrpt,CONNFAIL,l);
6675 else rpt_telemetry(myrpt,REMDISC,l);
6677 /* hang-up on call to device */
6678 ast_hangup(l->pchan);
6679 free(l);
6680 rpt_mutex_lock(&myrpt->lock);
6681 break;
6683 if ((!l->chan) && (!l->disctime) && (!l->outbound))
6685 /* remove from queue */
6686 remque((struct qelem *) l);
6687 if (!strcmp(myrpt->cmdnode,l->name))
6688 myrpt->cmdnode[0] = 0;
6689 rpt_mutex_unlock(&myrpt->lock);
6690 if (l->name[0] != '0')
6692 rpt_telemetry(myrpt,REMDISC,l);
6694 /* hang-up on call to device */
6695 ast_hangup(l->pchan);
6696 free(l);
6697 rpt_mutex_lock(&myrpt->lock);
6698 break;
6700 l = l->next;
6702 if(totx){
6703 myrpt->dailytxtime += elap;
6704 myrpt->totaltxtime += elap;
6706 i = myrpt->tailtimer;
6707 if (myrpt->tailtimer) myrpt->tailtimer -= elap;
6708 if (myrpt->tailtimer < 0) myrpt->tailtimer = 0;
6709 if((i) && (myrpt->tailtimer == 0))
6710 myrpt->tailevent = 1;
6711 if (myrpt->totimer) myrpt->totimer -= elap;
6712 if (myrpt->totimer < 0) myrpt->totimer = 0;
6713 if (myrpt->idtimer) myrpt->idtimer -= elap;
6714 if (myrpt->idtimer < 0) myrpt->idtimer = 0;
6715 if (myrpt->tmsgtimer) myrpt->tmsgtimer -= elap;
6716 if (myrpt->tmsgtimer < 0) myrpt->tmsgtimer = 0;
6717 /* do macro timers */
6718 if (myrpt->macrotimer) myrpt->macrotimer -= elap;
6719 if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
6720 /* Execute scheduler appx. every 2 tenths of a second */
6721 if (myrpt->skedtimer <= 0){
6722 myrpt->skedtimer = 200;
6723 do_scheduler(myrpt);
6725 else
6726 myrpt->skedtimer -=elap;
6727 if (!ms)
6729 rpt_mutex_unlock(&myrpt->lock);
6730 continue;
6732 c = myrpt->macrobuf[0];
6733 if (c && (!myrpt->macrotimer))
6735 myrpt->macrotimer = MACROTIME;
6736 memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1);
6737 if ((c == 'p') || (c == 'P'))
6738 myrpt->macrotimer = MACROPTIME;
6739 rpt_mutex_unlock(&myrpt->lock);
6740 local_dtmf_helper(myrpt,c);
6741 } else rpt_mutex_unlock(&myrpt->lock);
6742 if (who == myrpt->rxchannel) /* if it was a read from rx */
6744 f = ast_read(myrpt->rxchannel);
6745 if (!f)
6747 if (debug) printf("@@@@ rpt:Hung Up\n");
6748 break;
6750 if (f->frametype == AST_FRAME_VOICE)
6752 #ifdef _MDC_DECODE_H_
6753 unsigned char ubuf[2560];
6754 short *sp;
6755 int n;
6756 #endif
6758 if (!myrpt->localtx) {
6759 memset(f->data,0,f->datalen);
6762 #ifdef _MDC_DECODE_H_
6763 sp = (short *) f->data;
6764 /* convert block to unsigned char */
6765 for(n = 0; n < f->datalen / 2; n++)
6767 ubuf[n] = (*sp++ >> 8) + 128;
6769 n = mdc_decoder_process_samples(myrpt->mdc,ubuf,f->datalen / 2);
6770 if (n == 1)
6772 unsigned char op,arg;
6773 unsigned short unitID;
6775 mdc_decoder_get_packet(myrpt->mdc,&op,&arg,&unitID);
6776 if (debug > 2)
6778 ast_log(LOG_NOTICE,"Got (single-length) packet:\n");
6779 ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
6780 op & 255,arg & 255,unitID);
6782 if ((op == 1) && (arg == 0))
6784 myrpt->lastunit = unitID;
6787 if ((debug > 2) && (i == 2))
6789 unsigned char op,arg,ex1,ex2,ex3,ex4;
6790 unsigned short unitID;
6792 mdc_decoder_get_double_packet(myrpt->mdc,&op,&arg,&unitID,
6793 &ex1,&ex2,&ex3,&ex4);
6794 ast_log(LOG_NOTICE,"Got (double-length) packet:\n");
6795 ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
6796 op & 255,arg & 255,unitID);
6797 ast_log(LOG_NOTICE,"ex1: %02x, ex2: %02x, ex3: %02x, ex4: %02x\n",
6798 ex1 & 255, ex2 & 255, ex3 & 255, ex4 & 255);
6800 #endif
6801 #ifdef __RPT_NOTCH
6802 /* apply inbound filters, if any */
6803 rpt_filter(myrpt,f->data,f->datalen / 2);
6804 #endif
6805 ast_write(myrpt->pchannel,f);
6807 else if (f->frametype == AST_FRAME_DTMF)
6809 c = (char) f->subclass; /* get DTMF char */
6810 ast_frfree(f);
6811 if (!myrpt->keyed) continue;
6812 local_dtmf_helper(myrpt,c);
6813 continue;
6815 else if (f->frametype == AST_FRAME_CONTROL)
6817 if (f->subclass == AST_CONTROL_HANGUP)
6819 if (debug) printf("@@@@ rpt:Hung Up\n");
6820 ast_frfree(f);
6821 break;
6823 /* if RX key */
6824 if (f->subclass == AST_CONTROL_RADIO_KEY)
6826 if ((!lasttx) || (myrpt->p.duplex > 1))
6828 if (debug == 7) printf("@@@@ rx key\n");
6829 myrpt->keyed = 1;
6832 /* if RX un-key */
6833 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
6835 if ((!lasttx) || (myrpt->p.duplex > 1))
6837 if (debug == 7) printf("@@@@ rx un-key\n");
6838 if(myrpt->keyed) {
6839 rpt_telemetry(myrpt,UNKEY,NULL);
6841 myrpt->keyed = 0;
6845 ast_frfree(f);
6846 continue;
6848 if (who == myrpt->pchannel) /* if it was a read from pseudo */
6850 f = ast_read(myrpt->pchannel);
6851 if (!f)
6853 if (debug) printf("@@@@ rpt:Hung Up\n");
6854 break;
6856 if (f->frametype == AST_FRAME_VOICE)
6858 ast_write(myrpt->txpchannel,f);
6860 if (f->frametype == AST_FRAME_CONTROL)
6862 if (f->subclass == AST_CONTROL_HANGUP)
6864 if (debug) printf("@@@@ rpt:Hung Up\n");
6865 ast_frfree(f);
6866 break;
6869 ast_frfree(f);
6870 continue;
6872 if (who == myrpt->txchannel) /* if it was a read from tx */
6874 f = ast_read(myrpt->txchannel);
6875 if (!f)
6877 if (debug) printf("@@@@ rpt:Hung Up\n");
6878 break;
6880 if (f->frametype == AST_FRAME_CONTROL)
6882 if (f->subclass == AST_CONTROL_HANGUP)
6884 if (debug) printf("@@@@ rpt:Hung Up\n");
6885 ast_frfree(f);
6886 break;
6889 ast_frfree(f);
6890 continue;
6892 toexit = 0;
6893 rpt_mutex_lock(&myrpt->lock);
6894 l = myrpt->links.next;
6895 while(l != &myrpt->links)
6897 if (l->disctime)
6899 l = l->next;
6900 continue;
6902 if (who == l->chan) /* if it was a read from rx */
6904 remrx = 0;
6905 /* see if any other links are receiving */
6906 m = myrpt->links.next;
6907 while(m != &myrpt->links)
6909 /* if not us, count it */
6910 if ((m != l) && (m->lastrx)) remrx = 1;
6911 m = m->next;
6913 rpt_mutex_unlock(&myrpt->lock);
6914 totx = (((l->isremote) ? myrpt->localtx :
6915 myrpt->exttx) || remrx) && l->mode;
6916 if (l->chan && (l->lasttx != totx))
6918 if (totx)
6920 ast_indicate(l->chan,AST_CONTROL_RADIO_KEY);
6922 else
6924 ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
6927 l->lasttx = totx;
6928 f = ast_read(l->chan);
6929 if (!f)
6931 if ((!l->disced) && (!l->outbound))
6933 if ((l->name[0] == '0') || l->isremote)
6934 l->disctime = 1;
6935 else
6936 l->disctime = DISC_TIME;
6937 rpt_mutex_lock(&myrpt->lock);
6938 ast_hangup(l->chan);
6939 l->chan = 0;
6940 break;
6943 if (l->retrytimer)
6945 rpt_mutex_lock(&myrpt->lock);
6946 break;
6948 if (l->outbound && (l->retries++ < MAX_RETRIES) && (l->hasconnected))
6950 rpt_mutex_lock(&myrpt->lock);
6951 ast_hangup(l->chan);
6952 l->chan = 0;
6953 rpt_mutex_unlock(&myrpt->lock);
6954 if (attempt_reconnect(myrpt,l) == -1)
6956 l->retrytimer = RETRY_TIMER_MS;
6958 rpt_mutex_lock(&myrpt->lock);
6959 break;
6961 rpt_mutex_lock(&myrpt->lock);
6962 /* remove from queue */
6963 remque((struct qelem *) l);
6964 if (!strcmp(myrpt->cmdnode,l->name))
6965 myrpt->cmdnode[0] = 0;
6966 rpt_mutex_unlock(&myrpt->lock);
6967 if (!l->hasconnected)
6968 rpt_telemetry(myrpt,CONNFAIL,l);
6969 else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
6970 /* hang-up on call to device */
6971 ast_hangup(l->chan);
6972 ast_hangup(l->pchan);
6973 free(l);
6974 rpt_mutex_lock(&myrpt->lock);
6975 break;
6977 if (f->frametype == AST_FRAME_VOICE)
6979 if (!l->lastrx)
6981 memset(f->data,0,f->datalen);
6983 ast_write(l->pchan,f);
6985 if (f->frametype == AST_FRAME_TEXT)
6987 handle_link_data(myrpt,l,f->data);
6989 if (f->frametype == AST_FRAME_DTMF)
6991 handle_link_phone_dtmf(myrpt,l,f->subclass);
6993 if (f->frametype == AST_FRAME_CONTROL)
6995 if (f->subclass == AST_CONTROL_ANSWER)
6997 char lconnected = l->connected;
6998 l->connected = 1;
6999 l->hasconnected = 1;
7000 l->elaptime = -1;
7001 l->retries = 0;
7002 if (!lconnected)
7003 rpt_telemetry(myrpt,CONNECTED,l);
7004 else
7005 l->reconnects++;
7007 /* if RX key */
7008 if (f->subclass == AST_CONTROL_RADIO_KEY)
7010 if (debug == 7 ) printf("@@@@ rx key\n");
7011 l->lastrx = 1;
7013 /* if RX un-key */
7014 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
7016 if (debug == 7) printf("@@@@ rx un-key\n");
7017 l->lastrx = 0;
7019 if (f->subclass == AST_CONTROL_HANGUP)
7021 ast_frfree(f);
7022 if ((!l->outbound) && (!l->disced))
7024 if ((l->name[0] == '0') || l->isremote)
7025 l->disctime = 1;
7026 else
7027 l->disctime = DISC_TIME;
7028 rpt_mutex_lock(&myrpt->lock);
7029 ast_hangup(l->chan);
7030 l->chan = 0;
7031 break;
7033 if (l->retrytimer)
7035 rpt_mutex_lock(&myrpt->lock);
7036 break;
7038 if (l->outbound && (l->retries++ < MAX_RETRIES) && (l->hasconnected))
7040 rpt_mutex_lock(&myrpt->lock);
7041 ast_hangup(l->chan);
7042 l->chan = 0;
7043 rpt_mutex_unlock(&myrpt->lock);
7044 if (attempt_reconnect(myrpt,l) == -1)
7046 l->retrytimer = RETRY_TIMER_MS;
7048 rpt_mutex_lock(&myrpt->lock);
7049 break;
7051 rpt_mutex_lock(&myrpt->lock);
7052 /* remove from queue */
7053 remque((struct qelem *) l);
7054 if (!strcmp(myrpt->cmdnode,l->name))
7055 myrpt->cmdnode[0] = 0;
7056 rpt_mutex_unlock(&myrpt->lock);
7057 if (!l->hasconnected)
7058 rpt_telemetry(myrpt,CONNFAIL,l);
7059 else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
7060 /* hang-up on call to device */
7061 ast_hangup(l->chan);
7062 ast_hangup(l->pchan);
7063 free(l);
7064 rpt_mutex_lock(&myrpt->lock);
7065 break;
7068 ast_frfree(f);
7069 rpt_mutex_lock(&myrpt->lock);
7070 break;
7072 if (who == l->pchan)
7074 rpt_mutex_unlock(&myrpt->lock);
7075 f = ast_read(l->pchan);
7076 if (!f)
7078 if (debug) printf("@@@@ rpt:Hung Up\n");
7079 toexit = 1;
7080 rpt_mutex_lock(&myrpt->lock);
7081 break;
7083 if (f->frametype == AST_FRAME_VOICE)
7085 if (l->chan) ast_write(l->chan,f);
7087 if (f->frametype == AST_FRAME_CONTROL)
7089 if (f->subclass == AST_CONTROL_HANGUP)
7091 if (debug) printf("@@@@ rpt:Hung Up\n");
7092 ast_frfree(f);
7093 toexit = 1;
7094 rpt_mutex_lock(&myrpt->lock);
7095 break;
7098 ast_frfree(f);
7099 rpt_mutex_lock(&myrpt->lock);
7100 break;
7102 l = l->next;
7104 rpt_mutex_unlock(&myrpt->lock);
7105 if (toexit) break;
7106 if (who == myrpt->txpchannel) /* if it was a read from remote tx */
7108 f = ast_read(myrpt->txpchannel);
7109 if (!f)
7111 if (debug) printf("@@@@ rpt:Hung Up\n");
7112 break;
7114 if (f->frametype == AST_FRAME_CONTROL)
7116 if (f->subclass == AST_CONTROL_HANGUP)
7118 if (debug) printf("@@@@ rpt:Hung Up\n");
7119 ast_frfree(f);
7120 break;
7123 ast_frfree(f);
7124 continue;
7127 usleep(100000);
7128 ast_hangup(myrpt->pchannel);
7129 ast_hangup(myrpt->txpchannel);
7130 if (myrpt->txchannel != myrpt->rxchannel) ast_hangup(myrpt->txchannel);
7131 ast_hangup(myrpt->rxchannel);
7132 rpt_mutex_lock(&myrpt->lock);
7133 l = myrpt->links.next;
7134 while(l != &myrpt->links)
7136 struct rpt_link *ll = l;
7137 /* remove from queue */
7138 remque((struct qelem *) l);
7139 /* hang-up on call to device */
7140 if (l->chan) ast_hangup(l->chan);
7141 ast_hangup(l->pchan);
7142 l = l->next;
7143 free(ll);
7145 rpt_mutex_unlock(&myrpt->lock);
7146 if (debug) printf("@@@@ rpt:Hung up channel\n");
7147 myrpt->rpt_thread = AST_PTHREADT_STOP;
7148 pthread_exit(NULL);
7149 return NULL;
7153 static void *rpt_master(void *ignore)
7155 int i,n;
7156 pthread_attr_t attr;
7157 struct ast_config *cfg;
7158 char *this,*val;
7160 /* go thru all the specified repeaters */
7161 this = NULL;
7162 n = 0;
7163 rpt_vars[n].cfg = ast_config_load("rpt.conf");
7164 cfg = rpt_vars[n].cfg;
7165 if (!cfg) {
7166 ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf. Radio Repeater disabled.\n");
7167 pthread_exit(NULL);
7169 while((this = ast_category_browse(cfg,this)) != NULL)
7171 for(i = 0 ; i < strlen(this) ; i++){
7172 if((this[i] < '0') || (this[i] > '9'))
7173 break;
7175 if(i != strlen(this)) continue; /* Not a node defn */
7176 memset(&rpt_vars[n],0,sizeof(rpt_vars[n]));
7177 rpt_vars[n].name = strdup(this);
7178 val = ast_variable_retrieve(cfg,this,"rxchannel");
7179 if (val) rpt_vars[n].rxchanname = strdup(val);
7180 val = ast_variable_retrieve(cfg,this,"txchannel");
7181 if (val) rpt_vars[n].txchanname = strdup(val);
7182 val = ast_variable_retrieve(cfg,this,"remote");
7183 if (val) rpt_vars[n].remote = strdup(val);
7184 ast_mutex_init(&rpt_vars[n].lock);
7185 rpt_vars[n].tele.next = &rpt_vars[n].tele;
7186 rpt_vars[n].tele.prev = &rpt_vars[n].tele;
7187 rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
7188 rpt_vars[n].tailmessagen = 0;
7189 #ifdef _MDC_DECODE_H_
7190 rpt_vars[n].mdc = mdc_decoder_new(8000);
7191 #endif
7192 n++;
7194 nrpts = n;
7195 ast_config_destroy(cfg);
7197 /* start em all */
7198 for(i = 0; i < n; i++)
7200 load_rpt_vars(i,1);
7202 /* if is a remote, dont start one for it */
7203 if (rpt_vars[i].remote)
7205 strncpy(rpt_vars[i].freq, "146.580", sizeof(rpt_vars[i].freq) - 1);
7206 strncpy(rpt_vars[i].rxpl, "100.0", sizeof(rpt_vars[i].rxpl) - 1);
7208 strncpy(rpt_vars[i].txpl, "100.0", sizeof(rpt_vars[i].txpl) - 1);
7209 rpt_vars[i].remmode = REM_MODE_FM;
7210 rpt_vars[i].offset = REM_SIMPLEX;
7211 rpt_vars[i].powerlevel = REM_MEDPWR;
7212 continue;
7214 if (!rpt_vars[i].p.ident)
7216 ast_log(LOG_WARNING,"Did not specify ident for node %s\n",rpt_vars[i].name);
7217 ast_config_destroy(cfg);
7218 pthread_exit(NULL);
7220 pthread_attr_init(&attr);
7221 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
7222 ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]);
7224 usleep(500000);
7225 for(;;)
7227 /* Now monitor each thread, and restart it if necessary */
7228 for(i = 0; i < n; i++)
7230 int rv;
7231 if (rpt_vars[i].remote) continue;
7232 if (rpt_vars[i].rpt_thread == AST_PTHREADT_STOP)
7233 rv = -1;
7234 else
7235 rv = pthread_kill(rpt_vars[i].rpt_thread,0);
7236 if (rv)
7238 if(time(NULL) - rpt_vars[i].lastthreadrestarttime <= 15)
7240 if(rpt_vars[i].threadrestarts >= 5)
7242 ast_log(LOG_ERROR,"Continual RPT thread restarts, killing Asterisk\n");
7243 exit(1); /* Stuck in a restart loop, kill Asterisk and start over */
7245 else
7247 ast_log(LOG_NOTICE,"RPT thread restarted on %s\n",rpt_vars[i].name);
7248 rpt_vars[i].threadrestarts++;
7251 else
7252 rpt_vars[i].threadrestarts = 0;
7254 rpt_vars[i].lastthreadrestarttime = time(NULL);
7255 pthread_attr_init(&attr);
7256 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
7257 ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]);
7258 ast_log(LOG_WARNING, "rpt_thread restarted on node %s\n", rpt_vars[i].name);
7262 usleep(2000000);
7264 ast_config_destroy(cfg);
7265 pthread_exit(NULL);
7268 static int rpt_exec(struct ast_channel *chan, void *data)
7270 int res=-1,i,rem_totx,n,phone_mode = 0;
7271 struct ast_module_user *u;
7272 char tmp[256], keyed = 0;
7273 char *options,*stringp,*tele,c;
7274 struct rpt *myrpt;
7275 struct ast_frame *f;
7276 struct ast_channel *who;
7277 struct ast_channel *cs[20];
7278 struct rpt_link *l;
7279 ZT_CONFINFO ci; /* conference info */
7280 ZT_PARAMS par;
7281 int ms,elap;
7283 if (ast_strlen_zero(data)) {
7284 ast_log(LOG_WARNING, "Rpt requires an argument (system node)\n");
7285 return -1;
7287 strncpy(tmp, (char *)data, sizeof(tmp)-1);
7288 stringp=tmp;
7289 strsep(&stringp, "|");
7290 options = stringp;
7291 myrpt = NULL;
7292 /* see if we can find our specified one */
7293 for(i = 0; i < nrpts; i++)
7295 /* if name matches, assign it and exit loop */
7296 if (!strcmp(tmp,rpt_vars[i].name))
7298 myrpt = &rpt_vars[i];
7299 break;
7302 if (myrpt == NULL)
7304 ast_log(LOG_WARNING, "Cannot find specified system node %s\n",tmp);
7305 return -1;
7308 /* if not phone access, must be an IAX connection */
7309 if (options && ((*options == 'P') || (*options == 'D') || (*options == 'R')))
7311 phone_mode = 1;
7312 if (*options == 'D') phone_mode = 2;
7313 ast_set_callerid(chan,"0","app_rpt user","0");
7315 else
7317 if (strncmp(chan->name,"IAX2",4))
7319 ast_log(LOG_WARNING, "We only accept links via IAX2!!\n");
7320 return -1;
7323 if (options && (*options == 'R'))
7326 /* Parts of this section taken from app_parkandannounce */
7327 char *return_context;
7328 int l, m, lot, timeout = 0;
7329 char tmp[256],*template;
7330 char *working, *context, *exten, *priority;
7331 char *s,*orig_s;
7334 rpt_mutex_lock(&myrpt->lock);
7335 m = myrpt->callmode;
7336 rpt_mutex_unlock(&myrpt->lock);
7338 if ((!myrpt->p.nobusyout) && m)
7340 if (chan->_state != AST_STATE_UP)
7342 ast_indicate(chan,AST_CONTROL_BUSY);
7344 while(ast_safe_sleep(chan,10000) != -1);
7345 return -1;
7348 if (chan->_state != AST_STATE_UP)
7350 ast_answer(chan);
7353 l=strlen(options)+2;
7354 orig_s=malloc(l);
7355 if(!orig_s) {
7356 ast_log(LOG_WARNING, "Out of memory\n");
7357 return -1;
7359 s=orig_s;
7360 strncpy(s,options,l);
7362 template=strsep(&s,"|");
7363 if(!template) {
7364 ast_log(LOG_WARNING, "An announce template must be defined\n");
7365 free(orig_s);
7366 return -1;
7369 if(s) {
7370 timeout = atoi(strsep(&s, "|"));
7371 timeout *= 1000;
7374 return_context = s;
7376 if(return_context != NULL) {
7377 /* set the return context. Code borrowed from the Goto builtin */
7379 working = return_context;
7380 context = strsep(&working, "|");
7381 exten = strsep(&working, "|");
7382 if(!exten) {
7383 /* Only a priority in this one */
7384 priority = context;
7385 exten = NULL;
7386 context = NULL;
7387 } else {
7388 priority = strsep(&working, "|");
7389 if(!priority) {
7390 /* Only an extension and priority in this one */
7391 priority = exten;
7392 exten = context;
7393 context = NULL;
7396 if(atoi(priority) < 0) {
7397 ast_log(LOG_WARNING, "Priority '%s' must be a number > 0\n", priority);
7398 free(orig_s);
7399 return -1;
7401 /* At this point we have a priority and maybe an extension and a context */
7402 chan->priority = atoi(priority);
7403 #ifdef OLD_ASTERISK
7404 if(exten && strcasecmp(exten, "BYEXTENSION"))
7405 #else
7406 if(exten)
7407 #endif
7408 strncpy(chan->exten, exten, sizeof(chan->exten)-1);
7409 if(context)
7410 strncpy(chan->context, context, sizeof(chan->context)-1);
7411 } else { /* increment the priority by default*/
7412 chan->priority++;
7415 if(option_verbose > 2) {
7416 ast_verbose( VERBOSE_PREFIX_3 "Return Context: (%s,%s,%d) ID: %s\n", chan->context,chan->exten, chan->priority, chan->cid.cid_num);
7417 if(!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) {
7418 ast_verbose( VERBOSE_PREFIX_3 "Warning: Return Context Invalid, call will return to default|s\n");
7422 /* we are using masq_park here to protect * from touching the channel once we park it. If the channel comes out of timeout
7423 before we are done announcing and the channel is messed with, Kablooeee. So we use Masq to prevent this. */
7425 ast_masq_park_call(chan, NULL, timeout, &lot);
7427 if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "Call Parking Called, lot: %d, timeout: %d, context: %s\n", lot, timeout, return_context);
7429 snprintf(tmp,sizeof(tmp) - 1,"%d,%s",lot,template + 1);
7431 rpt_telemetry(myrpt,REV_PATCH,tmp);
7433 free(orig_s);
7435 return 0;
7439 if (!options)
7441 struct ast_hostent ahp;
7442 struct hostent *hp;
7443 struct in_addr ia;
7444 char hisip[100],nodeip[100],*val, *s, *s1, *s2, *b,*b1;
7446 /* look at callerid to see what node this comes from */
7447 if (!chan->cid.cid_num) /* if doesn't have caller id */
7449 ast_log(LOG_WARNING, "Doesnt have callerid on %s\n",tmp);
7450 return -1;
7453 /* get his IP from IAX2 module */
7454 memset(hisip,0,sizeof(hisip));
7455 pbx_substitute_variables_helper(chan,"${IAXPEER(CURRENTCHANNEL)}",hisip,sizeof(hisip) - 1);
7456 if (!hisip[0])
7458 ast_log(LOG_WARNING, "Link IP address cannot be determined!!\n");
7459 return -1;
7462 ast_callerid_parse(chan->cid.cid_num,&b,&b1);
7463 ast_shrink_phone_number(b1);
7464 if (!strcmp(myrpt->name,b1))
7466 ast_log(LOG_WARNING, "Trying to link to self!!\n");
7467 return -1;
7470 if (*b1 < '1')
7472 ast_log(LOG_WARNING, "Node %s Invalid for connection here!!\n",b1);
7473 return -1;
7477 /* look for his reported node string */
7478 val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, b1);
7479 if (!val)
7481 ast_log(LOG_WARNING, "Reported node %s cannot be found!!\n",b1);
7482 return -1;
7484 strncpy(tmp,val,sizeof(tmp) - 1);
7485 s = tmp;
7486 s1 = strsep(&s,",");
7487 s2 = strsep(&s,",");
7488 if (!s2)
7490 ast_log(LOG_WARNING, "Reported node %s not in correct format!!\n",b1);
7491 return -1;
7493 if (strcmp(s2,"NONE")) {
7494 hp = ast_gethostbyname(s2, &ahp);
7495 if (!hp)
7497 ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n",b1,s2);
7498 return -1;
7500 memcpy(&ia,hp->h_addr,sizeof(in_addr_t));
7501 ast_copy_string(nodeip, ast_inet_ntoa(ia), sizeof(nodeip));
7502 if (strcmp(hisip,nodeip))
7504 char *s3 = strchr(s1,'@');
7505 if (s3) s1 = s3 + 1;
7506 s3 = strchr(s1,'/');
7507 if (s3) *s3 = 0;
7508 hp = ast_gethostbyname(s1, &ahp);
7509 if (!hp)
7511 ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n",b1,s1);
7512 return -1;
7514 memcpy(&ia,hp->h_addr,sizeof(in_addr_t));
7515 ast_copy_string(nodeip, ast_inet_ntoa(ia), sizeof(nodeip));
7516 if (strcmp(hisip,nodeip))
7518 ast_log(LOG_WARNING, "Node %s IP %s does not match link IP %s!!\n",b1,nodeip,hisip);
7519 return -1;
7525 /* if is not a remote */
7526 if (!myrpt->remote)
7529 char *b,*b1;
7530 int reconnects = 0;
7532 /* look at callerid to see what node this comes from */
7533 if (!chan->cid.cid_num) /* if doesn't have caller id */
7535 ast_log(LOG_WARNING, "Doesnt have callerid on %s\n",tmp);
7536 return -1;
7539 ast_callerid_parse(chan->cid.cid_num,&b,&b1);
7540 ast_shrink_phone_number(b1);
7541 if (!strcmp(myrpt->name,b1))
7543 ast_log(LOG_WARNING, "Trying to link to self!!\n");
7544 return -1;
7546 rpt_mutex_lock(&myrpt->lock);
7547 l = myrpt->links.next;
7548 /* try to find this one in queue */
7549 while(l != &myrpt->links)
7551 if (l->name[0] == '0')
7553 l = l->next;
7554 continue;
7556 /* if found matching string */
7557 if (!strcmp(l->name,b1)) break;
7558 l = l->next;
7560 /* if found */
7561 if (l != &myrpt->links)
7563 l->killme = 1;
7564 l->retries = MAX_RETRIES + 1;
7565 l->disced = 2;
7566 reconnects = l->reconnects;
7567 reconnects++;
7568 rpt_mutex_unlock(&myrpt->lock);
7569 usleep(500000);
7570 } else
7571 rpt_mutex_unlock(&myrpt->lock);
7572 /* establish call in tranceive mode */
7573 l = malloc(sizeof(struct rpt_link));
7574 if (!l)
7576 ast_log(LOG_WARNING, "Unable to malloc\n");
7577 pthread_exit(NULL);
7579 /* zero the silly thing */
7580 memset((char *)l,0,sizeof(struct rpt_link));
7581 l->mode = 1;
7582 strncpy(l->name,b1,MAXNODESTR - 1);
7583 l->isremote = 0;
7584 l->chan = chan;
7585 l->connected = 1;
7586 l->hasconnected = 1;
7587 l->reconnects = reconnects;
7588 l->phonemode = phone_mode;
7589 ast_set_read_format(l->chan,AST_FORMAT_SLINEAR);
7590 ast_set_write_format(l->chan,AST_FORMAT_SLINEAR);
7591 /* allocate a pseudo-channel thru asterisk */
7592 l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
7593 if (!l->pchan)
7595 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
7596 pthread_exit(NULL);
7598 ast_set_read_format(l->pchan,AST_FORMAT_SLINEAR);
7599 ast_set_write_format(l->pchan,AST_FORMAT_SLINEAR);
7600 /* make a conference for the tx */
7601 ci.chan = 0;
7602 ci.confno = myrpt->conf;
7603 ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER;
7604 /* first put the channel on the conference in proper mode */
7605 if (ioctl(l->pchan->fds[0],ZT_SETCONF,&ci) == -1)
7607 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
7608 pthread_exit(NULL);
7610 rpt_mutex_lock(&myrpt->lock);
7611 if (phone_mode > 1) l->lastrx = 1;
7612 /* insert at end of queue */
7613 insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
7614 rpt_mutex_unlock(&myrpt->lock);
7615 if (chan->_state != AST_STATE_UP) {
7616 ast_answer(chan);
7618 return AST_PBX_KEEPALIVE;
7620 rpt_mutex_lock(&myrpt->lock);
7621 /* if remote, error if anyone else already linked */
7622 if (myrpt->remoteon)
7624 rpt_mutex_unlock(&myrpt->lock);
7625 usleep(500000);
7626 if (myrpt->remoteon)
7628 ast_log(LOG_WARNING, "Trying to use busy link on %s\n",tmp);
7629 return -1;
7631 rpt_mutex_lock(&myrpt->lock);
7633 myrpt->remoteon = 1;
7634 if (ioperm(myrpt->p.iobase,1,1) == -1)
7636 rpt_mutex_unlock(&myrpt->lock);
7637 ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase);
7638 return -1;
7640 u = ast_module_user_add(chan);
7641 rpt_mutex_unlock(&myrpt->lock);
7642 /* find our index, and load the vars initially */
7643 for(i = 0; i < nrpts; i++)
7645 if (&rpt_vars[i] == myrpt)
7647 load_rpt_vars(i,0);
7648 break;
7651 rpt_mutex_lock(&myrpt->lock);
7652 tele = strchr(myrpt->rxchanname,'/');
7653 if (!tele)
7655 fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
7656 rpt_mutex_unlock(&myrpt->lock);
7657 pthread_exit(NULL);
7659 *tele++ = 0;
7660 myrpt->rxchannel = ast_request(myrpt->rxchanname,AST_FORMAT_SLINEAR,tele,NULL);
7661 if (myrpt->rxchannel)
7663 ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
7664 ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
7665 myrpt->rxchannel->whentohangup = 0;
7666 myrpt->rxchannel->appl = "Apprpt";
7667 myrpt->rxchannel->data = "(Link Rx)";
7668 if (option_verbose > 2)
7669 ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
7670 myrpt->rxchanname,tele,myrpt->rxchannel->name);
7671 rpt_mutex_unlock(&myrpt->lock);
7672 ast_call(myrpt->rxchannel,tele,999);
7673 rpt_mutex_lock(&myrpt->lock);
7675 else
7677 fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
7678 rpt_mutex_unlock(&myrpt->lock);
7679 pthread_exit(NULL);
7681 *--tele = '/';
7682 if (myrpt->txchanname)
7684 tele = strchr(myrpt->txchanname,'/');
7685 if (!tele)
7687 fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
7688 rpt_mutex_unlock(&myrpt->lock);
7689 ast_hangup(myrpt->rxchannel);
7690 pthread_exit(NULL);
7692 *tele++ = 0;
7693 myrpt->txchannel = ast_request(myrpt->txchanname,AST_FORMAT_SLINEAR,tele,NULL);
7694 if (myrpt->txchannel)
7696 ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
7697 ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
7698 myrpt->txchannel->whentohangup = 0;
7699 myrpt->txchannel->appl = "Apprpt";
7700 myrpt->txchannel->data = "(Link Tx)";
7701 if (option_verbose > 2)
7702 ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
7703 myrpt->txchanname,tele,myrpt->txchannel->name);
7704 rpt_mutex_unlock(&myrpt->lock);
7705 ast_call(myrpt->txchannel,tele,999);
7706 rpt_mutex_lock(&myrpt->lock);
7708 else
7710 fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
7711 rpt_mutex_unlock(&myrpt->lock);
7712 ast_hangup(myrpt->rxchannel);
7713 pthread_exit(NULL);
7715 *--tele = '/';
7717 else
7719 myrpt->txchannel = myrpt->rxchannel;
7721 myrpt->remoterx = 0;
7722 myrpt->remotetx = 0;
7723 myrpt->retxtimer = 0;
7724 myrpt->remoteon = 1;
7725 myrpt->dtmfidx = -1;
7726 myrpt->dtmfbuf[0] = 0;
7727 myrpt->dtmf_time_rem = 0;
7728 myrpt->hfscanmode = 0;
7729 myrpt->hfscanstatus = 0;
7730 if (myrpt->p.startupmacro)
7732 myrpt->remchannel = chan; /* Save copy of channel */
7733 snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
7735 myrpt->reload = 0;
7736 rpt_mutex_unlock(&myrpt->lock);
7737 setrem(myrpt);
7738 ast_set_write_format(chan, AST_FORMAT_SLINEAR);
7739 ast_set_read_format(chan, AST_FORMAT_SLINEAR);
7740 /* if we are on 2w loop and are a remote, turn EC on */
7741 if (myrpt->remote && (myrpt->rxchannel == myrpt->txchannel))
7743 i = 128;
7744 ioctl(myrpt->rxchannel->fds[0],ZT_ECHOCANCEL,&i);
7746 if (chan->_state != AST_STATE_UP) {
7747 ast_answer(chan);
7750 if (ioctl(myrpt->txchannel->fds[0],ZT_GET_PARAMS,&par) != -1)
7752 if (par.rxisoffhook)
7754 ast_indicate(chan,AST_CONTROL_RADIO_KEY);
7755 myrpt->remoterx = 1;
7758 n = 0;
7759 cs[n++] = chan;
7760 cs[n++] = myrpt->rxchannel;
7761 if (myrpt->rxchannel != myrpt->txchannel)
7762 cs[n++] = myrpt->txchannel;
7763 for(;;)
7765 if (ast_check_hangup(chan)) break;
7766 if (ast_check_hangup(myrpt->rxchannel)) break;
7767 if (myrpt->reload)
7769 myrpt->reload = 0;
7770 rpt_mutex_unlock(&myrpt->lock);
7771 /* find our index, and load the vars */
7772 for(i = 0; i < nrpts; i++)
7774 if (&rpt_vars[i] == myrpt)
7776 load_rpt_vars(i,0);
7777 break;
7780 rpt_mutex_lock(&myrpt->lock);
7782 ms = MSWAIT;
7783 who = ast_waitfor_n(cs,n,&ms);
7784 if (who == NULL) ms = 0;
7785 elap = MSWAIT - ms;
7786 if (myrpt->macrotimer) myrpt->macrotimer -= elap;
7787 if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
7788 rpt_mutex_unlock(&myrpt->lock);
7789 if (!ms) continue;
7790 rem_totx = keyed;
7793 if ((!myrpt->remoterx) && (!myrpt->remotetx))
7795 if ((myrpt->retxtimer += elap) >= REDUNDANT_TX_TIME)
7797 myrpt->retxtimer = 0;
7798 ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
7800 } else myrpt->retxtimer = 0;
7801 if (rem_totx && (!myrpt->remotetx)) /* Remote base radio TX key */
7803 myrpt->remotetx = 1;
7804 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
7806 if ((!rem_totx) && myrpt->remotetx) /* Remote base radio TX unkey */
7808 myrpt->remotetx = 0;
7809 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
7812 if(myrpt->tunerequest && (!strcmp(myrpt->remote, remote_rig_ft897))){ /* ft-897 specific for now... */
7813 myrpt->tunerequest = 0;
7814 set_mode_ft897(myrpt, REM_MODE_AM);
7815 simple_command_ft897(myrpt, 8);
7816 myrpt->remotetx = 0;
7817 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
7818 if (!myrpt->remoterx)
7819 ast_indicate(chan, AST_CONTROL_RADIO_KEY);
7820 if(play_tone(chan, 800, 6000, 8192) == -1)
7821 break;
7823 rmt_telem_finish(myrpt,chan);
7824 set_mode_ft897(myrpt, 0x88);
7825 setrem(myrpt);
7828 if (myrpt->hfscanmode){
7829 myrpt->scantimer -= elap;
7830 if(myrpt->scantimer <= 0){
7831 myrpt->scantimer = REM_SCANTIME;
7832 service_scan(myrpt);
7835 if (who == chan) /* if it was a read from incomming */
7837 f = ast_read(chan);
7838 if (!f)
7840 if (debug) printf("@@@@ link:Hung Up\n");
7841 break;
7843 if (f->frametype == AST_FRAME_VOICE)
7845 /* if not transmitting, zero-out audio */
7846 if (!myrpt->remotetx)
7847 memset(f->data,0,f->datalen);
7848 ast_write(myrpt->txchannel,f);
7850 if (f->frametype == AST_FRAME_DTMF)
7852 myrpt->remchannel = chan; /* Save copy of channel */
7853 if (handle_remote_phone_dtmf(myrpt,f->subclass,&keyed,phone_mode) == -1)
7855 if (debug) printf("@@@@ rpt:Hung Up\n");
7856 ast_frfree(f);
7857 break;
7860 if (f->frametype == AST_FRAME_TEXT)
7862 myrpt->remchannel = chan; /* Save copy of channel */
7863 if (handle_remote_data(myrpt,f->data) == -1)
7865 if (debug) printf("@@@@ rpt:Hung Up\n");
7866 ast_frfree(f);
7867 break;
7870 if (f->frametype == AST_FRAME_CONTROL)
7872 if (f->subclass == AST_CONTROL_HANGUP)
7874 if (debug) printf("@@@@ rpt:Hung Up\n");
7875 ast_frfree(f);
7876 break;
7878 /* if RX key */
7879 if (f->subclass == AST_CONTROL_RADIO_KEY)
7881 if (debug == 7) printf("@@@@ rx key\n");
7882 keyed = 1;
7884 /* if RX un-key */
7885 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
7887 if (debug == 7) printf("@@@@ rx un-key\n");
7888 keyed = 0;
7891 if (myrpt->hfscanstatus){
7892 myrpt->remchannel = chan; /* Save copy of channel */
7893 myrpt->remotetx = 0;
7894 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
7895 if (!myrpt->remoterx)
7897 ast_indicate(myrpt->remchannel,AST_CONTROL_RADIO_KEY);
7899 if(myrpt->hfscanstatus < 0) {
7900 if (myrpt->hfscanstatus == -1) {
7901 if (ast_safe_sleep(myrpt->remchannel,1000) == -1) break;
7903 sayfile(myrpt->remchannel, "rpt/stop");
7905 else
7907 saynum(myrpt->remchannel, myrpt->hfscanstatus );
7909 rmt_telem_finish(myrpt,myrpt->remchannel);
7910 myrpt->hfscanstatus = 0;
7912 ast_frfree(f);
7913 rpt_mutex_lock(&myrpt->lock);
7914 c = myrpt->macrobuf[0];
7915 if (c && (!myrpt->macrotimer))
7917 myrpt->macrotimer = MACROTIME;
7918 memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1);
7919 if ((c == 'p') || (c == 'P'))
7920 myrpt->macrotimer = MACROPTIME;
7921 rpt_mutex_unlock(&myrpt->lock);
7922 if (handle_remote_dtmf_digit(myrpt,c,&keyed,0) == -1) break;
7923 continue;
7925 rpt_mutex_unlock(&myrpt->lock);
7926 continue;
7928 if (who == myrpt->rxchannel) /* if it was a read from radio */
7930 f = ast_read(myrpt->rxchannel);
7931 if (!f)
7933 if (debug) printf("@@@@ link:Hung Up\n");
7934 break;
7936 if (f->frametype == AST_FRAME_VOICE)
7938 if ((myrpt->remote) && (myrpt->remotetx))
7939 memset(f->data,0,f->datalen);
7940 ast_write(chan,f);
7942 else if (f->frametype == AST_FRAME_CONTROL)
7944 if (f->subclass == AST_CONTROL_HANGUP)
7946 if (debug) printf("@@@@ rpt:Hung Up\n");
7947 ast_frfree(f);
7948 break;
7950 /* if RX key */
7951 if (f->subclass == AST_CONTROL_RADIO_KEY)
7953 if (debug == 7) printf("@@@@ remote rx key\n");
7954 if (!myrpt->remotetx)
7956 ast_indicate(chan,AST_CONTROL_RADIO_KEY);
7957 myrpt->remoterx = 1;
7960 /* if RX un-key */
7961 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
7963 if (debug == 7) printf("@@@@ remote rx un-key\n");
7964 if (!myrpt->remotetx)
7966 ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
7967 myrpt->remoterx = 0;
7971 ast_frfree(f);
7972 continue;
7974 if ((myrpt->rxchannel != myrpt->txchannel) &&
7975 (who == myrpt->txchannel)) /* do this cuz you have to */
7977 f = ast_read(myrpt->txchannel);
7978 if (!f)
7980 if (debug) printf("@@@@ link:Hung Up\n");
7981 break;
7983 if (f->frametype == AST_FRAME_CONTROL)
7985 if (f->subclass == AST_CONTROL_HANGUP)
7987 if (debug) printf("@@@@ rpt:Hung Up\n");
7988 ast_frfree(f);
7989 break;
7992 ast_frfree(f);
7993 continue;
7997 rpt_mutex_lock(&myrpt->lock);
7998 if (myrpt->rxchannel != myrpt->txchannel) ast_hangup(myrpt->txchannel);
7999 ast_hangup(myrpt->rxchannel);
8000 myrpt->hfscanmode = 0;
8001 myrpt->hfscanstatus = 0;
8002 myrpt->remoteon = 0;
8003 rpt_mutex_unlock(&myrpt->lock);
8004 closerem(myrpt);
8005 ast_module_user_remove(u);
8006 return res;
8009 static int unload_module(void)
8011 int i;
8013 ast_module_user_hangup_all();
8014 for(i = 0; i < nrpts; i++) {
8015 if (!strcmp(rpt_vars[i].name,rpt_vars[i].p.nodes)) continue;
8016 ast_mutex_destroy(&rpt_vars[i].lock);
8018 i = ast_unregister_application(app);
8020 /* Unregister cli extensions */
8021 ast_cli_unregister(&cli_debug);
8022 ast_cli_unregister(&cli_dump);
8023 ast_cli_unregister(&cli_stats);
8024 ast_cli_unregister(&cli_lstats);
8025 ast_cli_unregister(&cli_reload);
8026 ast_cli_unregister(&cli_restart);
8028 return i;
8031 static int load_module(void)
8033 ast_pthread_create(&rpt_master_thread,NULL,rpt_master,NULL);
8035 /* Register cli extensions */
8036 ast_cli_register(&cli_debug);
8037 ast_cli_register(&cli_dump);
8038 ast_cli_register(&cli_stats);
8039 ast_cli_register(&cli_lstats);
8040 ast_cli_register(&cli_reload);
8041 ast_cli_register(&cli_restart);
8043 return ast_register_application(app, rpt_exec, synopsis, descrip);
8046 static int reload(void)
8048 int n;
8050 for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
8051 return(0);
8054 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Radio Repeater / Remote Base",
8055 .load = load_module,
8056 .unload = unload_module,
8057 .reload = reload,