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.
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
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.
55 * 2 - Give Time of Day
56 * 3 - Give software Version
58 * cop (control operator) cmds:
60 * 1 - System warm boot
64 * 5 - Dump System Variables on Console (debug)
65 * 6 - PTT (phone mode only)
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
74 * 6 - Disconnect all links
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)
86 * 102 - TX PL Off (Default)
91 * 107 - Bump Down 20 Hz
92 * 108 - Bump Down 100 Hz
93 * 109 - Bump Down 500 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
101 * 117 - Scan Up Medium
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.
113 * 3 - Normal except no main repeat audio.
114 * 4 - Normal except no main repeat audio during autopatch only
119 <depend>zaptel</depend>
120 <depend>tonezone</depend>
121 <defaultenabled>no</defaultenabled>
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 */
135 #define MAXMACRO 2048
136 #define MACROTIME 100
137 #define MACROPTIME 500
138 #define DTMF_TIMEOUT 3
141 #define MAXFILTERS 10
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
157 #define NODES "nodes"
158 #define MEMORY "memory"
159 #define MACRO "macro"
160 #define FUNCTIONS "functions"
161 #define TELEMETRY "telemetry"
162 #define MORSE "morse"
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$")
213 #include <sys/types.h>
214 #include <sys/stat.h>
218 #include <sys/stat.h>
219 #include <sys/time.h>
220 #include <sys/file.h>
221 #include <sys/ioctl.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"
252 " Not specifying an option puts it in normal endpoint mode (where source\n"
253 " IP and nodename are verified).\n"
255 " Options are as follows:\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"
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"
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"
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"
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";
300 #define HANGTIME 5000
301 #define TOTIME 180000
302 #define IDTIME 300000
304 #define MAX_STAT_LINKS 32
305 #define POLITEID 30000
306 #define FUNCTDELAY 1500
308 static pthread_t rpt_master_thread
;
314 struct rpt_link
*next
;
315 struct rpt_link
*prev
;
316 char mode
; /* 1 if in tx mode */
319 char name
[MAXNODESTR
]; /* identifier (routing) string */
333 long long connecttime
;
334 struct ast_channel
*chan
;
335 struct ast_channel
*pchan
;
340 struct rpt_lstat
*next
;
341 struct rpt_lstat
*prev
;
342 char peer
[MAXPEERSTR
];
343 char name
[MAXNODESTR
];
347 long long connecttime
;
352 struct rpt_tele
*next
;
353 struct rpt_tele
*prev
;
355 struct ast_channel
*chan
;
357 struct rpt_link mylink
;
358 char param
[TELEPARAMSIZE
];
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 */
377 struct telem_defaults
387 struct ast_config
*cfg
;
397 const char *ourcontext
;
398 const char *ourcallerid
;
399 const char *acctcode
;
403 const char *functions
;
404 const char *link_functions
;
405 const char *phone_functions
;
406 const char *dphone_functions
;
412 int tailsquashedtime
;
415 char *tailmessages
[500];
419 const char *startupmacro
;
425 struct rpt_link links
;
436 char dtmfbuf
[MAXDTMF
];
437 char macrobuf
[MAXMACRO
];
438 char rem_dtmfbuf
[MAXDTMF
];
439 char lastdtmfcommand
[MAXDTMF
];
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
;
451 int dtmfidx
,rem_dtmfidx
;
452 int dailytxtime
,dailykerchunks
,totalkerchunks
,dailykeyups
,totalkeyups
,timeouts
;
453 int totalexecdcommands
, dailyexecdcommands
;
455 long long totaltxtime
;
457 char exten
[AST_MAX_EXTENSION
];
458 char freq
[MAXREMSTR
],rxpl
[MAXREMSTR
],txpl
[MAXREMSTR
];
467 char lastlinknode
[MAXNODESTR
];
469 char patchfarenddisconnect
;
472 char patchcontext
[MAXPATCHCONTEXT
];
475 int phone_longestfunc
;
476 int dphone_longestfunc
;
477 int link_longestfunc
;
483 time_t lastthreadrestarttime
;
485 char lastnodewhichkeyedusup
[MAXNODESTR
];
500 } filters
[MAXFILTERS
];
502 #ifdef _MDC_DECODE_H_
504 unsigned short lastunit
;
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__)
524 } lockthreads
[MAXLOCKTHREAD
];
532 struct lockthread lockthread
;
536 int lock_ring_index
= 0;
538 AST_MUTEX_DEFINE_STATIC(locklock
);
540 static struct lockthread
*get_lockthread(pthread_t id
)
544 for(i
= 0; i
< MAXLOCKTHREAD
; i
++)
546 if (lockthreads
[i
].id
== id
) return(&lockthreads
[i
]);
551 static struct lockthread
*put_lockthread(pthread_t id
)
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
]);
575 static void rpt_mutex_spew(void)
577 struct by_lightning lock_ring_copy
[32];
578 int lock_ring_index_copy
;
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
));
598 diff
= (lock_ring_copy
[j
].tv
.tv_sec
- lasttv
.tv_sec
)
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
);
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
;
625 ast_mutex_lock(&locklock
);
626 t
= put_lockthread(id
);
629 ast_mutex_unlock(&locklock
);
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
);
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)
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
;
659 ast_mutex_lock(&locklock
);
660 t
= put_lockthread(id
);
663 ast_mutex_unlock(&locklock
);
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
);
674 t
->lastunlock
= line
;
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)
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 */
698 static int rpt_do_debug(int fd
, int argc
, char *argv
[]);
699 static int rpt_do_dump(int fd
, int argc
, char *argv
[]);
700 static int rpt_do_stats(int fd
, int argc
, char *argv
[]);
701 static int rpt_do_lstats(int fd
, int argc
, char *argv
[]);
702 static int rpt_do_reload(int fd
, int argc
, char *argv
[]);
703 static int rpt_do_restart(int fd
, int argc
, char *argv
[]);
705 static char debug_usage
[] =
706 "Usage: rpt debug level {0-7}\n"
707 " Enables debug messages in app_rpt\n";
709 static char dump_usage
[] =
710 "Usage: rpt dump <nodename>\n"
711 " Dumps struct debug info to log\n";
713 static char dump_stats
[] =
714 "Usage: rpt stats <nodename>\n"
715 " Dumps node statistics to console\n";
717 static char dump_lstats
[] =
718 "Usage: rpt lstats <nodename>\n"
719 " Dumps link statistics to console\n";
721 static char reload_usage
[] =
722 "Usage: rpt reload\n"
723 " Reloads app_rpt running config parameters\n";
725 static char restart_usage
[] =
726 "Usage: rpt restart\n"
727 " Restarts app_rpt\n";
729 static struct ast_cli_entry cli_rpt
[] = {
730 { { "rpt", "debug", "level" },
731 rpt_do_debug
, "Enable app_rpt debugging",
735 rpt_do_dump
, "Dump app_rpt structs for debugging",
738 { { "rpt", "stats" },
739 rpt_do_stats
, "Dump node statistics",
741 { { "rpt", "lstats" },
742 rpt_do_lstats
, "Dump link statistics",
745 { { "rpt", "reload" },
746 rpt_do_reload
, "Reload app_rpt config",
749 { { "rpt", "restart" },
750 rpt_do_restart
, "Restart app_rpt",
759 static struct telem_defaults tele_defs
[] = {
760 {"ct1","|t(350,0,100,3072)(500,0,100,3072)(660,0,100,3072)"},
761 {"ct2","|t(660,880,150,3072)"},
762 {"ct3","|t(440,0,150,3072)"},
763 {"ct4","|t(550,0,150,3072)"},
764 {"ct5","|t(660,0,150,3072)"},
765 {"ct6","|t(880,0,150,3072)"},
766 {"ct7","|t(660,440,150,3072)"},
767 {"ct8","|t(700,1100,150,3072)"},
768 {"remotemon","|t(1600,0,75,2048)"},
769 {"remotetx","|t(2000,0,75,2048)(0,0,75,0)(1600,0,75,2048)"},
770 {"cmdmode","|t(900,904,200,2048)"},
771 {"functcomplete","|t(1000,0,100,2048)(0,0,100,0)(1000,0,100,2048)"}
775 * Forward decl's - these suppress compiler warnings when funcs coded further down the file than thier invokation
778 static int setrbi(struct rpt
*myrpt
);
783 * Define function protos for function table here
786 static int function_ilink(struct rpt
*myrpt
, char *param
, char *digitbuf
, int command_source
, struct rpt_link
*mylink
);
787 static int function_autopatchup(struct rpt
*myrpt
, char *param
, char *digitbuf
, int command_source
, struct rpt_link
*mylink
);
788 static int function_autopatchdn(struct rpt
*myrpt
, char *param
, char *digitbuf
, int command_source
, struct rpt_link
*mylink
);
789 static int function_status(struct rpt
*myrpt
, char *param
, char *digitbuf
, int command_source
, struct rpt_link
*mylink
);
790 static int function_cop(struct rpt
*myrpt
, char *param
, char *digitbuf
, int command_source
, struct rpt_link
*mylink
);
791 static int function_remote(struct rpt
*myrpt
, char *param
, char *digitbuf
, int command_source
, struct rpt_link
*mylink
);
792 static int function_macro(struct rpt
*myrpt
, char *param
, char *digitbuf
, int command_source
, struct rpt_link
*mylink
);
797 static struct function_table_tag function_table
[] = {
798 {"cop", function_cop
},
799 {"autopatchup", function_autopatchup
},
800 {"autopatchdn", function_autopatchdn
},
801 {"ilink", function_ilink
},
802 {"status", function_status
},
803 {"remote", function_remote
},
804 {"macro", function_macro
}
808 * Break up a delimited string into a table of substrings
810 * str - delimited string ( will be modified )
811 * strp- list of pointers to substrings (this is built by this function), NULL will be placed at end of list
812 * limit- maximum number of substrings to process
817 static int finddelim(char *str
, char *strp
[], int limit
)
829 for(l
= 0; *str
&& (l
< limit
) ; str
++)
831 if (*str
== QUOTECHR
)
840 strp
[i
- 1] = str
+ 1;
844 if ((*str
== DELIMCHR
) && (!inquo
))
857 * Match a keyword in a list, and return index of string plus 1 if there was a match,
858 * else return 0. If param is passed in non-null, then it will be set to the first character past the match
861 static int matchkeyword(char *string
, char **param
, char *keywords
[])
864 for( i
= 0 ; keywords
[i
] ; i
++){
865 ls
= strlen(keywords
[i
]);
870 if(!strncmp(string
, keywords
[i
], ls
)){
872 *param
= string
+ ls
;
881 * Skip characters in string which are in charlist, and return a pointer to the
882 * first non-matching character
885 static char *skipchars(char *string
, char *charlist
)
889 for(i
= 0; charlist
[i
] ; i
++){
890 if(*string
== charlist
[i
]){
903 static int myatoi(const char *str
)
907 if (str
== NULL
) return -1;
908 /* leave this %i alone, non-base-10 input is useful here */
909 if (sscanf(str
,"%i",&ret
) != 1) return -1;
916 /* rpt filter routine */
917 static void rpt_filter(struct rpt
*myrpt
, volatile short *buf
, int len
)
922 for(i
= 0; i
< len
; i
++)
924 for(j
= 0; j
< MAXFILTERS
; j
++)
926 f
= &myrpt
->filters
[j
];
927 if (!*f
->desc
) continue;
928 f
->x0
= f
->x1
; f
->x1
= f
->x2
;
929 f
->x2
= ((float)buf
[i
]) / f
->gain
;
930 f
->y0
= f
->y1
; f
->y1
= f
->y2
;
931 f
->y2
= (f
->x0
+ f
->x2
) + f
->const0
* f
->x1
932 + (f
->const1
* f
->y0
) + (f
->const2
* f
->y1
);
933 buf
[i
] = (short)f
->y2
;
940 /* Retrieve an int from a config file */
942 static int retrieve_astcfgint(struct rpt
*myrpt
,char *category
, char *name
, int min
, int max
, int defl
)
947 var
= ast_variable_retrieve(myrpt
->cfg
, category
, name
);
961 static void load_rpt_vars(int n
,int init
)
966 struct ast_variable
*vp
;
967 struct ast_config
*cfg
;
973 if (option_verbose
> 2)
974 ast_verbose(VERBOSE_PREFIX_3
"%s config for repeater %s\n",
975 (init
) ? "Loading initial" : "Re-Loading",rpt_vars
[n
].name
);
976 ast_mutex_lock(&rpt_vars
[n
].lock
);
977 if (rpt_vars
[n
].cfg
) ast_config_destroy(rpt_vars
[n
].cfg
);
978 cfg
= ast_config_load("rpt.conf");
980 ast_mutex_unlock(&rpt_vars
[n
].lock
);
981 ast_log(LOG_NOTICE
, "Unable to open radio repeater configuration rpt.conf. Radio Repeater disabled.\n");
984 rpt_vars
[n
].cfg
= cfg
;
985 this = rpt_vars
[n
].name
;
986 memset(&rpt_vars
[n
].p
,0,sizeof(rpt_vars
[n
].p
));
990 int savearea
= (char *)&rpt_vars
[n
].p
- (char *)&rpt_vars
[n
];
992 cp
= (char *) &rpt_vars
[n
].p
;
993 memset(cp
+ sizeof(rpt_vars
[n
].p
),0,
994 sizeof(rpt_vars
[n
]) - (sizeof(rpt_vars
[n
].p
) + savearea
));
995 rpt_vars
[n
].tele
.next
= &rpt_vars
[n
].tele
;
996 rpt_vars
[n
].tele
.prev
= &rpt_vars
[n
].tele
;
997 rpt_vars
[n
].rpt_thread
= AST_PTHREADT_NULL
;
998 rpt_vars
[n
].tailmessagen
= 0;
1001 /* zot out filters stuff */
1002 memset(&rpt_vars
[n
].filters
,0,sizeof(rpt_vars
[n
].filters
));
1004 val
= ast_variable_retrieve(cfg
,this,"context");
1005 if (val
) rpt_vars
[n
].p
.ourcontext
= val
;
1006 else rpt_vars
[n
].p
.ourcontext
= this;
1007 val
= ast_variable_retrieve(cfg
,this,"callerid");
1008 if (val
) rpt_vars
[n
].p
.ourcallerid
= val
;
1009 val
= ast_variable_retrieve(cfg
,this,"accountcode");
1010 if (val
) rpt_vars
[n
].p
.acctcode
= val
;
1011 val
= ast_variable_retrieve(cfg
,this,"idrecording");
1012 if (val
) rpt_vars
[n
].p
.ident
= val
;
1013 val
= ast_variable_retrieve(cfg
,this,"hangtime");
1014 if (val
) rpt_vars
[n
].p
.hangtime
= atoi(val
);
1015 else rpt_vars
[n
].p
.hangtime
= HANGTIME
;
1016 val
= ast_variable_retrieve(cfg
,this,"totime");
1017 if (val
) rpt_vars
[n
].p
.totime
= atoi(val
);
1018 else rpt_vars
[n
].p
.totime
= TOTIME
;
1019 rpt_vars
[n
].p
.tailmessagetime
= retrieve_astcfgint(&rpt_vars
[n
],this, "tailmessagetime", 0, 2400000, 0);
1020 rpt_vars
[n
].p
.tailsquashedtime
= retrieve_astcfgint(&rpt_vars
[n
],this, "tailsquashedtime", 0, 2400000, 0);
1021 rpt_vars
[n
].p
.duplex
= retrieve_astcfgint(&rpt_vars
[n
],this,"duplex",0,4,2);
1022 rpt_vars
[n
].p
.idtime
= retrieve_astcfgint(&rpt_vars
[n
],this, "idtime", 60000, 2400000, IDTIME
); /* Enforce a min max */
1023 rpt_vars
[n
].p
.politeid
= retrieve_astcfgint(&rpt_vars
[n
],this, "politeid", 30000, 300000, POLITEID
); /* Enforce a min max */
1024 val
= ast_variable_retrieve(cfg
,this,"tonezone");
1025 if (val
) rpt_vars
[n
].p
.tonezone
= ast_strdupa(val
);
1026 rpt_vars
[n
].p
.tailmessages
[0] = 0;
1027 rpt_vars
[n
].p
.tailmessagemax
= 0;
1028 val
= ast_variable_retrieve(cfg
,this,"tailmessagelist");
1029 if (val
) rpt_vars
[n
].p
.tailmessagemax
= finddelim(ast_strdupa(val
), rpt_vars
[n
].p
.tailmessages
, 500);
1030 val
= ast_variable_retrieve(cfg
,this,"memory");
1031 if (!val
) val
= MEMORY
;
1032 rpt_vars
[n
].p
.memory
= val
;
1033 val
= ast_variable_retrieve(cfg
,this,"macro");
1034 if (!val
) val
= MACRO
;
1035 rpt_vars
[n
].p
.macro
= val
;
1036 val
= ast_variable_retrieve(cfg
,this,"startup_macro");
1037 if (val
) rpt_vars
[n
].p
.startupmacro
= val
;
1038 val
= ast_variable_retrieve(cfg
,this,"iobase");
1039 /* do not use atoi() here, we need to be able to have
1040 the input specified in hex or decimal so we use
1042 if ((!val
) || (sscanf(val
,"%i",&rpt_vars
[n
].p
.iobase
) != 1))
1043 rpt_vars
[n
].p
.iobase
= DEFAULT_IOBASE
;
1044 val
= ast_variable_retrieve(cfg
,this,"functions");
1048 rpt_vars
[n
].p
.simple
= 1;
1050 rpt_vars
[n
].p
.functions
= val
;
1051 val
= ast_variable_retrieve(cfg
,this,"link_functions");
1052 if (val
) rpt_vars
[n
].p
.link_functions
= val
;
1054 rpt_vars
[n
].p
.link_functions
= rpt_vars
[n
].p
.functions
;
1055 val
= ast_variable_retrieve(cfg
,this,"phone_functions");
1056 if (val
) rpt_vars
[n
].p
.phone_functions
= val
;
1057 val
= ast_variable_retrieve(cfg
,this,"dphone_functions");
1058 if (val
) rpt_vars
[n
].p
.dphone_functions
= val
;
1059 val
= ast_variable_retrieve(cfg
,this,"funcchar");
1060 if (!val
) rpt_vars
[n
].p
.funcchar
= FUNCCHAR
; else
1061 rpt_vars
[n
].p
.funcchar
= *val
;
1062 val
= ast_variable_retrieve(cfg
,this,"endchar");
1063 if (!val
) rpt_vars
[n
].p
.endchar
= ENDCHAR
; else
1064 rpt_vars
[n
].p
.endchar
= *val
;
1065 val
= ast_variable_retrieve(cfg
,this,"nobusyout");
1066 if (val
) rpt_vars
[n
].p
.nobusyout
= ast_true(val
);
1067 val
= ast_variable_retrieve(cfg
,this,"nodes");
1068 if (!val
) val
= NODES
;
1069 rpt_vars
[n
].p
.nodes
= val
;
1071 val
= ast_variable_retrieve(cfg
,this,"rxnotch");
1073 i
= finddelim(ast_strdupa(val
),strs
,MAXFILTERS
* 2);
1074 i
&= ~1; /* force an even number, rounded down */
1075 if (i
>= 2) for(j
= 0; j
< i
; j
+= 2)
1077 rpt_mknotch(atof(strs
[j
]),atof(strs
[j
+ 1]),
1078 &rpt_vars
[n
].filters
[j
>> 1].gain
,
1079 &rpt_vars
[n
].filters
[j
>> 1].const0
,
1080 &rpt_vars
[n
].filters
[j
>> 1].const1
,
1081 &rpt_vars
[n
].filters
[j
>> 1].const2
);
1082 sprintf(rpt_vars
[n
].filters
[j
>> 1].desc
,"%s Hz, BW = %s",
1083 strs
[j
],strs
[j
+ 1]);
1090 vp
= ast_variable_browse(cfg
, rpt_vars
[n
].p
.nodes
);
1093 j
= strlen(vp
->name
);
1094 if (j
> longestnode
)
1099 rpt_vars
[n
].longestnode
= longestnode
;
1102 * For this repeater, Determine the length of the longest function
1104 rpt_vars
[n
].longestfunc
= 0;
1105 vp
= ast_variable_browse(cfg
, rpt_vars
[n
].p
.functions
);
1107 j
= strlen(vp
->name
);
1108 if (j
> rpt_vars
[n
].longestfunc
)
1109 rpt_vars
[n
].longestfunc
= j
;
1113 * For this repeater, Determine the length of the longest function
1115 rpt_vars
[n
].link_longestfunc
= 0;
1116 vp
= ast_variable_browse(cfg
, rpt_vars
[n
].p
.link_functions
);
1118 j
= strlen(vp
->name
);
1119 if (j
> rpt_vars
[n
].link_longestfunc
)
1120 rpt_vars
[n
].link_longestfunc
= j
;
1123 rpt_vars
[n
].phone_longestfunc
= 0;
1124 if (rpt_vars
[n
].p
.phone_functions
)
1126 vp
= ast_variable_browse(cfg
, rpt_vars
[n
].p
.phone_functions
);
1128 j
= strlen(vp
->name
);
1129 if (j
> rpt_vars
[n
].phone_longestfunc
)
1130 rpt_vars
[n
].phone_longestfunc
= j
;
1134 rpt_vars
[n
].dphone_longestfunc
= 0;
1135 if (rpt_vars
[n
].p
.dphone_functions
)
1137 vp
= ast_variable_browse(cfg
, rpt_vars
[n
].p
.dphone_functions
);
1139 j
= strlen(vp
->name
);
1140 if (j
> rpt_vars
[n
].dphone_longestfunc
)
1141 rpt_vars
[n
].dphone_longestfunc
= j
;
1145 rpt_vars
[n
].macro_longest
= 1;
1146 vp
= ast_variable_browse(cfg
, rpt_vars
[n
].p
.macro
);
1148 j
= strlen(vp
->name
);
1149 if (j
> rpt_vars
[n
].macro_longest
)
1150 rpt_vars
[n
].macro_longest
= j
;
1153 ast_mutex_unlock(&rpt_vars
[n
].lock
);
1157 * Enable or disable debug output at a given level at the console
1160 static int rpt_do_debug(int fd
, int argc
, char *argv
[])
1165 return RESULT_SHOWUSAGE
;
1166 newlevel
= myatoi(argv
[3]);
1167 if((newlevel
< 0) || (newlevel
> 7))
1168 return RESULT_SHOWUSAGE
;
1170 ast_cli(fd
, "app_rpt Debugging enabled, previous level: %d, new level: %d\n", debug
, newlevel
);
1172 ast_cli(fd
, "app_rpt Debugging disabled\n");
1175 return RESULT_SUCCESS
;
1179 * Dump rpt struct debugging onto console
1182 static int rpt_do_dump(int fd
, int argc
, char *argv
[])
1187 return RESULT_SHOWUSAGE
;
1189 for(i
= 0; i
< nrpts
; i
++)
1191 if (!strcmp(argv
[2],rpt_vars
[i
].name
))
1193 rpt_vars
[i
].disgorgetime
= time(NULL
) + 10; /* Do it 10 seconds later */
1194 ast_cli(fd
, "app_rpt struct dump requested for node %s\n",argv
[2]);
1195 return RESULT_SUCCESS
;
1198 return RESULT_FAILURE
;
1202 * Dump statistics onto console
1205 static int rpt_do_stats(int fd
, int argc
, char *argv
[])
1208 int dailytxtime
, dailykerchunks
;
1209 int totalkerchunks
, dailykeyups
, totalkeyups
, timeouts
;
1210 int totalexecdcommands
, dailyexecdcommands
, hours
, minutes
, seconds
;
1211 long long totaltxtime
;
1213 char *listoflinks
[MAX_STAT_LINKS
];
1214 char *lastnodewhichkeyedusup
, *lastdtmfcommand
;
1215 char *tot_state
, *ider_state
, *patch_state
;
1216 char *reverse_patch_state
, *enable_state
, *input_signal
, *called_number
;
1219 static char *not_applicable
= "N/A";
1222 return RESULT_SHOWUSAGE
;
1224 for(i
= 0 ; i
<= MAX_STAT_LINKS
; i
++)
1225 listoflinks
[i
] = NULL
;
1227 tot_state
= ider_state
=
1228 patch_state
= reverse_patch_state
=
1229 input_signal
= called_number
=
1230 lastdtmfcommand
= not_applicable
;
1232 for(i
= 0; i
< nrpts
; i
++)
1234 if (!strcmp(argv
[2],rpt_vars
[i
].name
)){
1235 /* Make a copy of all stat variables while locked */
1236 myrpt
= &rpt_vars
[i
];
1237 rpt_mutex_lock(&myrpt
->lock
); /* LOCK */
1239 dailytxtime
= myrpt
->dailytxtime
;
1240 totaltxtime
= myrpt
->totaltxtime
;
1241 dailykeyups
= myrpt
->dailykeyups
;
1242 totalkeyups
= myrpt
->totalkeyups
;
1243 dailykerchunks
= myrpt
->dailykerchunks
;
1244 totalkerchunks
= myrpt
->totalkerchunks
;
1245 dailyexecdcommands
= myrpt
->dailyexecdcommands
;
1246 totalexecdcommands
= myrpt
->totalexecdcommands
;
1247 timeouts
= myrpt
->timeouts
;
1249 /* Traverse the list of connected nodes */
1250 reverse_patch_state
= "DOWN";
1252 l
= myrpt
->links
.next
;
1253 while(l
!= &myrpt
->links
){
1254 if (l
->name
[0] == '0'){ /* Skip '0' nodes */
1255 reverse_patch_state
= "UP";
1259 listoflinks
[j
] = ast_strdupa(l
->name
);
1265 lastnodewhichkeyedusup
= ast_strdupa(myrpt
->lastnodewhichkeyedusup
);
1266 if((!lastnodewhichkeyedusup
) || (!strlen(lastnodewhichkeyedusup
)))
1267 lastnodewhichkeyedusup
= not_applicable
;
1270 input_signal
= "YES";
1272 input_signal
= "NO";
1275 enable_state
= "YES";
1277 enable_state
= "NO";
1280 tot_state
= "TIMED OUT!";
1281 else if(myrpt
->totimer
!= myrpt
->p
.totime
)
1282 tot_state
= "ARMED";
1284 tot_state
= "RESET";
1287 ider_state
= "QUEUED IN TAIL";
1288 else if(myrpt
->mustid
)
1289 ider_state
= "QUEUED FOR CLEANUP";
1291 ider_state
= "CLEAN";
1293 switch(myrpt
->callmode
){
1295 patch_state
= "DIALING";
1298 patch_state
= "CONNECTING";
1305 patch_state
= "CALL FAILED";
1309 patch_state
= "DOWN";
1312 if(strlen(myrpt
->exten
)){
1313 called_number
= ast_strdupa(myrpt
->exten
);
1315 called_number
= not_applicable
;
1318 if(strlen(myrpt
->lastdtmfcommand
)){
1319 lastdtmfcommand
= ast_strdupa(myrpt
->lastdtmfcommand
);
1320 if(!lastdtmfcommand
)
1321 lastdtmfcommand
= not_applicable
;
1324 rpt_mutex_unlock(&myrpt
->lock
); /* UNLOCK */
1326 ast_cli(fd
, "************************ NODE %s STATISTICS *************************\n\n", myrpt
->name
);
1327 ast_cli(fd
, "Signal on input..................................: %s\n", input_signal
);
1328 ast_cli(fd
, "Transmitter enabled..............................: %s\n", enable_state
);
1329 ast_cli(fd
, "Time out timer state.............................: %s\n", tot_state
);
1330 ast_cli(fd
, "Time outs since system initialization............: %d\n", timeouts
);
1331 ast_cli(fd
, "Identifier state.................................: %s\n", ider_state
);
1332 ast_cli(fd
, "Kerchunks today..................................: %d\n", dailykerchunks
);
1333 ast_cli(fd
, "Kerchunks since system initialization............: %d\n", totalkerchunks
);
1334 ast_cli(fd
, "Keyups today.....................................: %d\n", dailykeyups
);
1335 ast_cli(fd
, "Keyups since system initialization...............: %d\n", totalkeyups
);
1336 ast_cli(fd
, "DTMF commands today..............................: %d\n", dailyexecdcommands
);
1337 ast_cli(fd
, "DTMF commands since system initialization........: %d\n", totalexecdcommands
);
1338 ast_cli(fd
, "Last DTMF command executed.......................: %s\n", lastdtmfcommand
);
1340 hours
= dailytxtime
/3600000;
1341 dailytxtime
%= 3600000;
1342 minutes
= dailytxtime
/60000;
1343 dailytxtime
%= 60000;
1344 seconds
= dailytxtime
/1000;
1345 dailytxtime
%= 1000;
1347 ast_cli(fd
, "TX time today ...................................: %02d:%02d:%02d.%d\n",
1348 hours
, minutes
, seconds
, dailytxtime
);
1350 hours
= (int) totaltxtime
/3600000;
1351 totaltxtime
%= 3600000;
1352 minutes
= (int) totaltxtime
/60000;
1353 totaltxtime
%= 60000;
1354 seconds
= (int) totaltxtime
/1000;
1355 totaltxtime
%= 1000;
1357 ast_cli(fd
, "TX time since system initialization..............: %02d:%02d:%02d.%d\n",
1358 hours
, minutes
, seconds
, (int) totaltxtime
);
1359 ast_cli(fd
, "Nodes currently connected to us..................: ");
1361 if(!listoflinks
[j
]){
1363 ast_cli(fd
,"<NONE>");
1367 ast_cli(fd
, "%s", listoflinks
[j
]);
1373 if(listoflinks
[j
+ 1])
1379 ast_cli(fd
, "Last node which transmitted to us................: %s\n", lastnodewhichkeyedusup
);
1380 ast_cli(fd
, "Autopatch state..................................: %s\n", patch_state
);
1381 ast_cli(fd
, "Autopatch called number..........................: %s\n", called_number
);
1382 ast_cli(fd
, "Reverse patch/IAXRPT connected...................: %s\n\n", reverse_patch_state
);
1384 return RESULT_SUCCESS
;
1387 return RESULT_FAILURE
;
1391 * Link stats function
1394 static int rpt_do_lstats(int fd
, int argc
, char *argv
[])
1399 struct rpt_lstat
*s
,*t
;
1400 struct rpt_lstat s_head
;
1402 return RESULT_SHOWUSAGE
;
1405 s_head
.next
= &s_head
;
1406 s_head
.prev
= &s_head
;
1408 for(i
= 0; i
< nrpts
; i
++)
1410 if (!strcmp(argv
[2],rpt_vars
[i
].name
)){
1411 /* Make a copy of all stat variables while locked */
1412 myrpt
= &rpt_vars
[i
];
1413 rpt_mutex_lock(&myrpt
->lock
); /* LOCK */
1414 /* Traverse the list of connected nodes */
1416 l
= myrpt
->links
.next
;
1417 while(l
!= &myrpt
->links
){
1418 if (l
->name
[0] == '0'){ /* Skip '0' nodes */
1422 if((s
= (struct rpt_lstat
*) malloc(sizeof(struct rpt_lstat
))) == NULL
){
1423 ast_log(LOG_ERROR
, "Malloc failed in rpt_do_lstats\n");
1424 rpt_mutex_unlock(&myrpt
->lock
); /* UNLOCK */
1425 return RESULT_FAILURE
;
1427 memset(s
, 0, sizeof(struct rpt_lstat
));
1428 ast_copy_string(s
->name
, l
->name
, MAXREMSTR
);
1429 pbx_substitute_variables_helper(l
->chan
, "${IAXPEER(CURRENTCHANNEL)}", s
->peer
, MAXPEERSTR
- 1);
1431 s
->outbound
= l
->outbound
;
1432 s
->reconnects
= l
->reconnects
;
1433 s
->connecttime
= l
->connecttime
;
1434 insque((struct qelem
*) s
, (struct qelem
*) s_head
.next
);
1437 rpt_mutex_unlock(&myrpt
->lock
); /* UNLOCK */
1438 ast_cli(fd
, "NODE PEER RECONNECTS DIRECTION CONNECT TIME\n");
1439 ast_cli(fd
, "---- ---- ---------- --------- ------------\n");
1441 for(s
= s_head
.next
; s
!= &s_head
; s
= s
->next
){
1442 int hours
, minutes
, seconds
;
1443 long long connecttime
= s
->connecttime
;
1445 hours
= (int) connecttime
/3600000;
1446 connecttime
%= 3600000;
1447 minutes
= (int) connecttime
/60000;
1448 connecttime
%= 60000;
1449 seconds
= (int) connecttime
/1000;
1450 connecttime
%= 1000;
1451 snprintf(conntime
, 30, "%02d:%02d:%02d.%d",
1452 hours
, minutes
, seconds
, (int) connecttime
);
1454 ast_cli(fd
, "%-10s%-20s%-12d%-11s%-30s\n",
1455 s
->name
, s
->peer
, s
->reconnects
, (s
->outbound
)? "OUT":"IN", conntime
);
1457 /* destroy our local link queue */
1459 while(s
!= &s_head
){
1462 remque((struct qelem
*)t
);
1465 return RESULT_SUCCESS
;
1468 return RESULT_FAILURE
;
1475 static int rpt_do_reload(int fd
, int argc
, char *argv
[])
1479 if (argc
> 2) return RESULT_SHOWUSAGE
;
1481 for(n
= 0; n
< nrpts
; n
++) rpt_vars
[n
].reload
= 1;
1483 return RESULT_FAILURE
;
1490 static int rpt_do_restart(int fd
, int argc
, char *argv
[])
1494 if (argc
> 2) return RESULT_SHOWUSAGE
;
1495 for(i
= 0; i
< nrpts
; i
++)
1497 if (rpt_vars
[i
].rxchannel
) ast_softhangup(rpt_vars
[i
].rxchannel
,AST_SOFTHANGUP_DEV
);
1499 return RESULT_FAILURE
;
1502 static int play_tone_pair(struct ast_channel
*chan
, int f1
, int f2
, int duration
, int amplitude
)
1506 if ((res
= ast_tonepair_start(chan
, f1
, f2
, duration
, amplitude
)))
1509 while(chan
->generatordata
) {
1510 if (ast_safe_sleep(chan
,1)) return -1;
1516 static int play_tone(struct ast_channel
*chan
, int freq
, int duration
, int amplitude
)
1518 return play_tone_pair(chan
, freq
, 0, duration
, amplitude
);
1521 static int play_silence(struct ast_channel
*chan
, int duration
)
1523 return play_tone_pair(chan
, 0, 0, duration
, 0);
1527 static int send_morse(struct ast_channel
*chan
, const char *string
, int speed
, int freq
, int amplitude
)
1530 static struct morse_bits mbits
[] = {
1595 int intralettertime
;
1596 int interlettertime
;
1606 /* Approximate the dot time from the speed arg. */
1608 dottime
= 900/speed
;
1610 /* Establish timing releationships */
1612 dashtime
= 3 * dottime
;
1613 intralettertime
= dottime
;
1614 interlettertime
= dottime
* 4 ;
1615 interwordtime
= dottime
* 7;
1617 for(;(*string
) && (!res
); string
++){
1621 /* Convert lower case to upper case */
1623 if((c
>= 'a') && (c
<= 'z'))
1626 /* Can't deal with any char code greater than Z, skip it */
1631 /* If space char, wait the inter word time */
1635 res
= play_silence(chan
, interwordtime
);
1639 /* Subtract out control char offset to match our table */
1643 /* Get the character data */
1646 ddcomb
= mbits
[c
].ddcomb
;
1648 /* Send the character */
1652 res
= play_tone(chan
, freq
, (ddcomb
& 1) ? dashtime
: dottime
, amplitude
);
1654 res
= play_silence(chan
, intralettertime
);
1658 /* Wait the interletter time */
1661 res
= play_silence(chan
, interlettertime
- intralettertime
);
1664 /* Wait for all the frames to be sent */
1667 res
= ast_waitstream(chan
, "");
1668 ast_stopstream(chan
);
1671 * Wait for the zaptel driver to physically write the tone blocks to the hardware
1674 for(i
= 0; i
< 20 ; i
++){
1675 flags
= ZT_IOMUX_WRITEEMPTY
| ZT_IOMUX_NOWAIT
;
1676 res
= ioctl(chan
->fds
[0], ZT_IOMUX
, &flags
);
1677 if(flags
& ZT_IOMUX_WRITEEMPTY
)
1679 if( ast_safe_sleep(chan
, 50)){
1689 static int send_tone_telemetry(struct ast_channel
*chan
, const char *tonestring
)
1702 stringp
= ast_strdupa(tonestring
);
1705 tonesubset
= strsep(&stringp
,")");
1708 if(sscanf(tonesubset
,"(%d,%d,%d,%d", &f1
, &f2
, &duration
, &litude
) != 4)
1710 res
= play_tone_pair(chan
, f1
, f2
, duration
, amplitude
);
1715 res
= play_tone_pair(chan
, 0, 0, 100, 0); /* This is needed to ensure the last tone segment is timed correctly */
1718 res
= ast_waitstream(chan
, "");
1719 ast_stopstream(chan
);
1722 * Wait for the zaptel driver to physically write the tone blocks to the hardware
1725 for(i
= 0; i
< 20 ; i
++){
1726 flags
= ZT_IOMUX_WRITEEMPTY
| ZT_IOMUX_NOWAIT
;
1727 res
= ioctl(chan
->fds
[0], ZT_IOMUX
, &flags
);
1728 if(flags
& ZT_IOMUX_WRITEEMPTY
)
1730 if( ast_safe_sleep(chan
, 50)){
1741 static int sayfile(struct ast_channel
*mychannel
, const char *fname
)
1745 res
= ast_streamfile(mychannel
, fname
, mychannel
->language
);
1747 res
= ast_waitstream(mychannel
, "");
1749 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
1750 ast_stopstream(mychannel
);
1754 static int saycharstr(struct ast_channel
*mychannel
,char *str
)
1758 res
= ast_say_character_str(mychannel
,str
,NULL
,mychannel
->language
);
1760 res
= ast_waitstream(mychannel
, "");
1762 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
1763 ast_stopstream(mychannel
);
1767 static int saynum(struct ast_channel
*mychannel
, int num
)
1770 res
= ast_say_number(mychannel
, num
, NULL
, mychannel
->language
, NULL
);
1772 res
= ast_waitstream(mychannel
, "");
1774 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
1775 ast_stopstream(mychannel
);
1780 static int telem_any(struct rpt
*myrpt
,struct ast_channel
*chan
, const char *entry
)
1785 static int morsespeed
;
1786 static int morsefreq
;
1787 static int morseampl
;
1788 static int morseidfreq
= 0;
1789 static int morseidampl
;
1790 static char mcat
[] = MORSE
;
1794 if(!morseidfreq
){ /* Get the morse parameters if not already loaded */
1795 morsespeed
= retrieve_astcfgint(myrpt
, mcat
, "speed", 5, 20, 20);
1796 morsefreq
= retrieve_astcfgint(myrpt
, mcat
, "frequency", 300, 3000, 800);
1797 morseampl
= retrieve_astcfgint(myrpt
, mcat
, "amplitude", 200, 8192, 4096);
1798 morseidampl
= retrieve_astcfgint(myrpt
, mcat
, "idamplitude", 200, 8192, 2048);
1799 morseidfreq
= retrieve_astcfgint(myrpt
, mcat
, "idfrequency", 300, 3000, 330);
1802 /* Is it a file, or a tone sequence? */
1804 if(entry
[0] == '|'){
1806 if((c
>= 'a')&&(c
<= 'z'))
1810 case 'I': /* Morse ID */
1811 res
= send_morse(chan
, entry
+ 2, morsespeed
, morseidfreq
, morseidampl
);
1814 case 'M': /* Morse Message */
1815 res
= send_morse(chan
, entry
+ 2, morsespeed
, morsefreq
, morseampl
);
1818 case 'T': /* Tone sequence */
1819 res
= send_tone_telemetry(chan
, entry
+ 2);
1826 res
= sayfile(chan
, entry
); /* File */
1831 * This function looks up a telemetry name in the config file, and does a telemetry response as configured.
1833 * 4 types of telemtry are handled: Morse ID, Morse Message, Tone Sequence, and a File containing a recording.
1836 static int telem_lookup(struct rpt
*myrpt
,struct ast_channel
*chan
, char *node
, char *name
)
1842 const char *telemetry
;
1843 char *telemetry_save
;
1846 telemetry_save
= NULL
;
1849 /* Retrieve the section name for telemetry from the node section */
1850 telemetry
= ast_variable_retrieve(myrpt
->cfg
, node
, TELEMETRY
);
1852 telemetry_save
= ast_strdupa(telemetry
);
1853 if(!telemetry_save
){
1854 ast_log(LOG_WARNING
,"ast_strdupa() failed in telem_lookup()\n");
1857 entry
= ast_variable_retrieve(myrpt
->cfg
, telemetry_save
, name
);
1860 /* Try to look up the telemetry name */
1863 /* Telemetry name wasn't found in the config file, use the default */
1864 for(i
= 0; i
< sizeof(tele_defs
)/sizeof(struct telem_defaults
) ; i
++){
1865 if(!strcasecmp(tele_defs
[i
].name
, name
))
1866 entry
= tele_defs
[i
].value
;
1871 telem_any(myrpt
,chan
, entry
);
1880 * Retrieve a wait interval
1883 static int get_wait_interval(struct rpt
*myrpt
, int type
)
1886 const char *wait_times
;
1887 char *wait_times_save
= NULL
;
1889 wait_times
= ast_variable_retrieve(myrpt
->cfg
, myrpt
->name
, "wait_times");
1892 wait_times_save
= ast_strdupa(wait_times
);
1893 if (!wait_times_save
) {
1894 ast_log(LOG_WARNING
, "Out of memory in wait_interval()\n");
1902 interval
= retrieve_astcfgint(myrpt
, wait_times_save
, "telemwait", 500, 5000, 1000);
1909 interval
= retrieve_astcfgint(myrpt
, wait_times_save
, "idwait", 250, 5000, 500);
1916 interval
= retrieve_astcfgint(myrpt
, wait_times_save
, "unkeywait", 500, 5000, 1000);
1923 interval
= retrieve_astcfgint(myrpt
, wait_times_save
, "calltermwait", 500, 5000, 1500);
1936 * Wait a configurable interval of time
1940 static void wait_interval(struct rpt
*myrpt
, int type
, struct ast_channel
*chan
)
1943 interval
= get_wait_interval(myrpt
, type
);
1945 ast_log(LOG_NOTICE
," Delay interval = %d\n", interval
);
1947 ast_safe_sleep(chan
,interval
);
1949 ast_log(LOG_NOTICE
,"Delay complete\n");
1954 static void *rpt_tele_thread(void *this)
1956 ZT_CONFINFO ci
; /* conference info */
1957 int res
= 0,haslink
,hastx
,hasremote
,imdone
= 0, unkeys_queued
, x
;
1958 struct rpt_tele
*mytele
= (struct rpt_tele
*)this;
1959 struct rpt_tele
*tlist
;
1961 struct rpt_link
*l
,*m
,linkbase
;
1962 struct ast_channel
*mychannel
;
1964 char *ct_copy
, *ident
, *nodename
;
1968 /* get a pointer to myrpt */
1969 myrpt
= mytele
->rpt
;
1971 /* Snag copies of a few key myrpt variables */
1972 rpt_mutex_lock(&myrpt
->lock
);
1973 nodename
= ast_strdupa(myrpt
->name
);
1974 ident
= ast_strdupa(myrpt
->p
.ident
);
1975 rpt_mutex_unlock(&myrpt
->lock
);
1977 /* allocate a pseudo-channel thru asterisk */
1978 mychannel
= ast_request("zap",AST_FORMAT_SLINEAR
,"pseudo",NULL
);
1981 fprintf(stderr
,"rpt:Sorry unable to obtain pseudo channel\n");
1982 rpt_mutex_lock(&myrpt
->lock
);
1983 remque((struct qelem
*)mytele
);
1984 ast_log(LOG_NOTICE
,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__
, mytele
->mode
); /*@@@@@@@@@@@*/
1985 rpt_mutex_unlock(&myrpt
->lock
);
1989 rpt_mutex_lock(&myrpt
->lock
);
1990 mytele
->chan
= mychannel
; /* Save a copy of the channel so we can access it externally if need be */
1991 rpt_mutex_unlock(&myrpt
->lock
);
1993 /* make a conference for the tx */
1995 /* If there's an ID queued, or tail message queued, */
1996 /* only connect the ID audio to the local tx conference so */
1997 /* linked systems can't hear it */
1998 ci
.confno
= (((mytele
->mode
== ID
) || (mytele
->mode
== IDTALKOVER
) || (mytele
->mode
== UNKEY
) ||
1999 (mytele
->mode
== TAILMSG
)) ?
2000 myrpt
->txconf
: myrpt
->conf
);
2001 ci
.confmode
= ZT_CONF_CONFANN
;
2002 /* first put the channel on the conference in announce mode */
2003 if (ioctl(mychannel
->fds
[0],ZT_SETCONF
,&ci
) == -1)
2005 ast_log(LOG_WARNING
, "Unable to set conference mode to Announce\n");
2006 rpt_mutex_lock(&myrpt
->lock
);
2007 remque((struct qelem
*)mytele
);
2008 rpt_mutex_unlock(&myrpt
->lock
);
2009 ast_log(LOG_NOTICE
,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__
, mytele
->mode
); /*@@@@@@@@@@@*/
2011 ast_hangup(mychannel
);
2014 ast_stopstream(mychannel
);
2015 switch(mytele
->mode
)
2021 wait_interval(myrpt
, (mytele
->mode
== ID
) ? DLY_ID
: DLY_TELEM
,mychannel
);
2022 res
= telem_any(myrpt
,mychannel
, ident
);
2027 res
= ast_streamfile(mychannel
, myrpt
->p
.tailmessages
[myrpt
->tailmessagen
], mychannel
->language
);
2031 p
= ast_variable_retrieve(myrpt
->cfg
, nodename
, "idtalkover");
2033 res
= telem_any(myrpt
,mychannel
, p
);
2038 /* wait a little bit longer */
2039 wait_interval(myrpt
, DLY_TELEM
, mychannel
);
2040 res
= telem_lookup(myrpt
, mychannel
, myrpt
->name
, "patchup");
2041 if(res
< 0){ /* Then default message */
2042 res
= ast_streamfile(mychannel
, "rpt/callproceeding", mychannel
->language
);
2046 /* wait a little bit longer */
2047 wait_interval(myrpt
, DLY_CALLTERM
, mychannel
);
2048 res
= telem_lookup(myrpt
, mychannel
, myrpt
->name
, "patchdown");
2049 if(res
< 0){ /* Then default message */
2050 res
= ast_streamfile(mychannel
, "rpt/callterminated", mychannel
->language
);
2054 /* wait a little bit */
2055 wait_interval(myrpt
, DLY_TELEM
, mychannel
);
2056 res
= telem_lookup(myrpt
,mychannel
, myrpt
->name
, "functcomplete");
2058 case MACRO_NOTFOUND
:
2059 /* wait a little bit */
2060 wait_interval(myrpt
, DLY_TELEM
, mychannel
);
2061 res
= ast_streamfile(mychannel
, "rpt/macro_notfound", mychannel
->language
);
2064 /* wait a little bit */
2065 wait_interval(myrpt
, DLY_TELEM
, mychannel
);
2066 res
= ast_streamfile(mychannel
, "rpt/macro_busy", mychannel
->language
);
2069 if(myrpt
->patchnoct
&& myrpt
->callmode
){ /* If no CT during patch configured, then don't send one */
2075 * Reset the Unkey to CT timer
2078 x
= get_wait_interval(myrpt
, DLY_UNKEY
);
2079 rpt_mutex_lock(&myrpt
->lock
);
2080 myrpt
->unkeytocttimer
= x
; /* Must be protected as it is changed below */
2081 rpt_mutex_unlock(&myrpt
->lock
);
2084 * If there's one already queued, don't do another
2087 tlist
= myrpt
->tele
.next
;
2089 if (tlist
!= &myrpt
->tele
)
2091 rpt_mutex_lock(&myrpt
->lock
);
2092 while(tlist
!= &myrpt
->tele
){
2093 if (tlist
->mode
== UNKEY
) unkeys_queued
++;
2094 tlist
= tlist
->next
;
2096 rpt_mutex_unlock(&myrpt
->lock
);
2098 if( unkeys_queued
> 1){
2103 /* Wait for the telemetry timer to expire */
2104 /* Periodically check the timer since it can be re-initialized above */
2105 while(myrpt
->unkeytocttimer
)
2108 if(myrpt
->unkeytocttimer
> 100)
2111 ctint
= myrpt
->unkeytocttimer
;
2112 ast_safe_sleep(mychannel
, ctint
);
2113 rpt_mutex_lock(&myrpt
->lock
);
2114 if(myrpt
->unkeytocttimer
< ctint
)
2115 myrpt
->unkeytocttimer
= 0;
2117 myrpt
->unkeytocttimer
-= ctint
;
2118 rpt_mutex_unlock(&myrpt
->lock
);
2122 * Now, the carrier on the rptr rx should be gone.
2123 * If it re-appeared, then forget about sending the CT
2130 rpt_mutex_lock(&myrpt
->lock
); /* Update the kerchunk counters */
2131 myrpt
->dailykerchunks
++;
2132 myrpt
->totalkerchunks
++;
2133 rpt_mutex_unlock(&myrpt
->lock
);
2138 l
= myrpt
->links
.next
;
2139 if (l
!= &myrpt
->links
)
2141 rpt_mutex_lock(&myrpt
->lock
);
2142 while(l
!= &myrpt
->links
)
2144 if (l
->name
[0] == '0')
2152 if (l
->isremote
) hasremote
++;
2156 rpt_mutex_unlock(&myrpt
->lock
);
2161 res
= telem_lookup(myrpt
,mychannel
, myrpt
->name
, (!hastx
) ? "remotemon" : "remotetx");
2163 ast_log(LOG_WARNING
, "telem_lookup:remotexx failed on %s\n", mychannel
->name
);
2166 /* if in remote cmd mode, indicate it */
2167 if (myrpt
->cmdnode
[0])
2169 ast_safe_sleep(mychannel
,200);
2170 res
= telem_lookup(myrpt
,mychannel
, myrpt
->name
, "cmdmode");
2172 ast_log(LOG_WARNING
, "telem_lookup:cmdmode failed on %s\n", mychannel
->name
);
2173 ast_stopstream(mychannel
);
2176 else if((ct
= ast_variable_retrieve(myrpt
->cfg
, nodename
, "unlinkedct"))){ /* Unlinked Courtesy Tone */
2177 ct_copy
= ast_strdupa(ct
);
2178 res
= telem_lookup(myrpt
,mychannel
, myrpt
->name
, ct_copy
);
2180 ast_log(LOG_WARNING
, "telem_lookup:ctx failed on %s\n", mychannel
->name
);
2182 if (hasremote
&& (!myrpt
->cmdnode
[0]))
2184 /* set for all to hear */
2186 ci
.confno
= myrpt
->conf
;
2187 ci
.confmode
= ZT_CONF_CONFANN
;
2188 /* first put the channel on the conference in announce mode */
2189 if (ioctl(mychannel
->fds
[0],ZT_SETCONF
,&ci
) == -1)
2191 ast_log(LOG_WARNING
, "Unable to set conference mode to Announce\n");
2192 rpt_mutex_lock(&myrpt
->lock
);
2193 remque((struct qelem
*)mytele
);
2194 rpt_mutex_unlock(&myrpt
->lock
);
2195 ast_log(LOG_NOTICE
,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__
, mytele
->mode
); /*@@@@@@@@@@@*/
2197 ast_hangup(mychannel
);
2200 if((ct
= ast_variable_retrieve(myrpt
->cfg
, nodename
, "remotect"))){ /* Unlinked Courtesy Tone */
2201 ast_safe_sleep(mychannel
,200);
2202 ct_copy
= ast_strdupa(ct
);
2203 res
= telem_lookup(myrpt
,mychannel
, myrpt
->name
, ct_copy
);
2205 ast_log(LOG_WARNING
, "telem_lookup:ctx failed on %s\n", mychannel
->name
);
2208 #ifdef _MDC_DECODE_H_
2209 if (myrpt
->lastunit
)
2213 ast_safe_sleep(mychannel
,200);
2214 /* set for all to hear */
2216 ci
.confno
= myrpt
->txconf
;
2217 ci
.confmode
= ZT_CONF_CONFANN
;
2218 /* first put the channel on the conference in announce mode */
2219 if (ioctl(mychannel
->fds
[0],ZT_SETCONF
,&ci
) == -1)
2221 ast_log(LOG_WARNING
, "Unable to set conference mode to Announce\n");
2222 rpt_mutex_lock(&myrpt
->lock
);
2223 remque((struct qelem
*)mytele
);
2224 rpt_mutex_unlock(&myrpt
->lock
);
2225 ast_log(LOG_NOTICE
,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__
, mytele
->mode
); /*@@@@@@@@@@@*/
2227 ast_hangup(mychannel
);
2230 sprintf(mystr
,"%04x",myrpt
->lastunit
);
2231 myrpt
->lastunit
= 0;
2232 ast_say_character_str(mychannel
,mystr
,NULL
,mychannel
->language
);
2239 /* wait a little bit */
2240 wait_interval(myrpt
, DLY_TELEM
, mychannel
);
2241 res
= ast_streamfile(mychannel
, "rpt/node", mychannel
->language
);
2243 res
= ast_waitstream(mychannel
, "");
2245 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
2246 ast_stopstream(mychannel
);
2247 ast_say_character_str(mychannel
,mytele
->mylink
.name
,NULL
,mychannel
->language
);
2248 res
= ast_streamfile(mychannel
, ((mytele
->mylink
.connected
) ?
2249 "rpt/remote_disc" : "rpt/remote_busy"), mychannel
->language
);
2252 /* wait a little bit */
2253 wait_interval(myrpt
, DLY_TELEM
, mychannel
);
2254 res
= ast_streamfile(mychannel
, "rpt/remote_already", mychannel
->language
);
2257 /* wait a little bit */
2258 wait_interval(myrpt
, DLY_TELEM
, mychannel
);
2259 res
= ast_streamfile(mychannel
, "rpt/remote_notfound", mychannel
->language
);
2262 /* wait a little bit */
2263 wait_interval(myrpt
, DLY_TELEM
, mychannel
);
2264 res
= ast_streamfile(mychannel
, "rpt/remote_go", mychannel
->language
);
2267 /* wait a little bit */
2268 wait_interval(myrpt
, DLY_TELEM
, mychannel
);
2269 res
= ast_streamfile(mychannel
, "rpt/node", mychannel
->language
);
2271 res
= ast_waitstream(mychannel
, "");
2273 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
2274 ast_stopstream(mychannel
);
2275 ast_say_character_str(mychannel
,mytele
->mylink
.name
,NULL
,mychannel
->language
);
2276 res
= ast_streamfile(mychannel
, "rpt/connected", mychannel
->language
);
2279 res
= ast_streamfile(mychannel
, "rpt/node", mychannel
->language
);
2281 res
= ast_waitstream(mychannel
, "");
2283 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
2284 ast_stopstream(mychannel
);
2285 ast_say_character_str(mychannel
,mytele
->mylink
.name
,NULL
,mychannel
->language
);
2286 res
= ast_streamfile(mychannel
, "rpt/connection_failed", mychannel
->language
);
2289 /* wait a little bit */
2290 wait_interval(myrpt
, DLY_TELEM
, mychannel
);
2292 linkbase
.next
= &linkbase
;
2293 linkbase
.prev
= &linkbase
;
2294 rpt_mutex_lock(&myrpt
->lock
);
2295 /* make our own list of links */
2296 l
= myrpt
->links
.next
;
2297 while(l
!= &myrpt
->links
)
2299 if (l
->name
[0] == '0')
2304 m
= malloc(sizeof(struct rpt_link
));
2307 ast_log(LOG_WARNING
, "Cannot alloc memory on %s\n", mychannel
->name
);
2308 remque((struct qelem
*)mytele
);
2309 rpt_mutex_unlock(&myrpt
->lock
);
2310 ast_log(LOG_NOTICE
,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__
, mytele
->mode
); /*@@@@@@@@@@@*/
2312 ast_hangup(mychannel
);
2315 memcpy(m
,l
,sizeof(struct rpt_link
));
2316 m
->next
= m
->prev
= NULL
;
2317 insque((struct qelem
*)m
,(struct qelem
*)linkbase
.next
);
2320 rpt_mutex_unlock(&myrpt
->lock
);
2321 res
= ast_streamfile(mychannel
, "rpt/node", mychannel
->language
);
2323 res
= ast_waitstream(mychannel
, "");
2325 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
2326 ast_stopstream(mychannel
);
2327 ast_say_character_str(mychannel
,myrpt
->name
,NULL
,mychannel
->language
);
2329 res
= ast_waitstream(mychannel
, "");
2331 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
2332 ast_stopstream(mychannel
);
2333 if (myrpt
->callmode
)
2336 res
= ast_streamfile(mychannel
, "rpt/autopatch_on", mychannel
->language
);
2338 res
= ast_waitstream(mychannel
, "");
2340 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
2341 ast_stopstream(mychannel
);
2344 while(l
!= &linkbase
)
2347 res
= ast_streamfile(mychannel
, "rpt/node", mychannel
->language
);
2349 res
= ast_waitstream(mychannel
, "");
2351 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
2352 ast_stopstream(mychannel
);
2353 ast_say_character_str(mychannel
,l
->name
,NULL
,mychannel
->language
);
2355 res
= ast_waitstream(mychannel
, "");
2357 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
2358 ast_stopstream(mychannel
);
2359 res
= ast_streamfile(mychannel
, ((l
->mode
) ?
2360 "rpt/tranceive" : "rpt/monitor"), mychannel
->language
);
2362 res
= ast_waitstream(mychannel
, "");
2364 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
2365 ast_stopstream(mychannel
);
2370 res
= ast_streamfile(mychannel
, "rpt/repeat_only", mychannel
->language
);
2372 res
= ast_waitstream(mychannel
, "");
2374 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
2375 ast_stopstream(mychannel
);
2377 /* destroy our local link queue */
2379 while(l
!= &linkbase
)
2383 remque((struct qelem
*)m
);
2389 case LASTNODEKEY
: /* Identify last node which keyed us up */
2390 rpt_mutex_lock(&myrpt
->lock
);
2391 if(myrpt
->lastnodewhichkeyedusup
)
2392 p
= ast_strdupa(myrpt
->lastnodewhichkeyedusup
); /* Make a local copy of the node name */
2395 rpt_mutex_unlock(&myrpt
->lock
);
2397 imdone
= 1; /* no node previously keyed us up, or the node which did has been disconnected */
2400 wait_interval(myrpt
, DLY_TELEM
, mychannel
);
2401 res
= ast_streamfile(mychannel
, "rpt/node", mychannel
->language
);
2403 res
= ast_waitstream(mychannel
, "");
2405 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
2406 ast_stopstream(mychannel
);
2407 ast_say_character_str(mychannel
, p
, NULL
, mychannel
->language
);
2409 res
= ast_waitstream(mychannel
, "");
2411 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
2412 ast_stopstream(mychannel
);
2417 res
= ast_streamfile(mychannel
, "rpt/node", mychannel
->language
);
2419 res
= ast_waitstream(mychannel
, "");
2421 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
2422 ast_stopstream(mychannel
);
2423 ast_say_character_str(mychannel
,myrpt
->name
,NULL
,mychannel
->language
);
2424 res
= ast_streamfile(mychannel
, "rpt/timeout", mychannel
->language
);
2428 wait_interval(myrpt
, DLY_TELEM
, mychannel
); /* Wait a little bit */
2430 localtime_r(&t
, &localtm
);
2431 /* Say the phase of the day is before the time */
2432 if((localtm
.tm_hour
>= 0) && (localtm
.tm_hour
< 12))
2433 p
= "rpt/goodmorning";
2434 else if((localtm
.tm_hour
>= 12) && (localtm
.tm_hour
< 18))
2435 p
= "rpt/goodafternoon";
2437 p
= "rpt/goodevening";
2438 if (sayfile(mychannel
,p
) == -1)
2443 /* Say the time is ... */
2444 if (sayfile(mychannel
,"rpt/thetimeis") == -1)
2450 res
= ast_say_time(mychannel
, t
, "", mychannel
->language
);
2452 res
= ast_waitstream(mychannel
, "");
2453 ast_stopstream(mychannel
);
2457 wait_interval(myrpt
, DLY_TELEM
, mychannel
); /* Wait a little bit */
2459 if (sayfile(mychannel
,"rpt/version") == -1)
2464 if(!res
) /* Say "X" */
2465 ast_say_number(mychannel
, vmajor
, "", mychannel
->language
, (char *) NULL
);
2467 res
= ast_waitstream(mychannel
, "");
2468 ast_stopstream(mychannel
);
2469 if (saycharstr(mychannel
,".") == -1)
2474 if(!res
) /* Say "Y" */
2475 ast_say_number(mychannel
, vminor
, "", mychannel
->language
, (char *) NULL
);
2477 res
= ast_waitstream(mychannel
, "");
2478 ast_stopstream(mychannel
);
2481 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
2485 wait_interval(myrpt
, DLY_TELEM
, mychannel
); /* Wait a little bit */
2487 saycharstr(mychannel
, mytele
->param
);
2491 wait_interval(myrpt
, DLY_TELEM
, mychannel
); /* Wait a little bit */
2494 /* Parts of this section taken from app_parkandannounce */
2495 char *tpl_working
, *tpl_current
;
2496 char *tmp
[100], *myparm
;
2497 int looptemp
=0,i
=0, dres
= 0;
2500 tpl_working
= strdupa(mytele
->param
);
2501 myparm
= strsep(&tpl_working
,",");
2502 tpl_current
=strsep(&tpl_working
, ":");
2504 while(tpl_current
&& looptemp
< sizeof(tmp
)) {
2505 tmp
[looptemp
]=tpl_current
;
2507 tpl_current
=strsep(&tpl_working
,":");
2510 for(i
=0; i
<looptemp
; i
++) {
2511 if(!strcmp(tmp
[i
], "PARKED")) {
2512 ast_say_digits(mychannel
, atoi(myparm
), "", mychannel
->language
);
2513 } else if(!strcmp(tmp
[i
], "NODE")) {
2514 ast_say_digits(mychannel
, atoi(myrpt
->name
), "", mychannel
->language
);
2516 dres
= ast_streamfile(mychannel
, tmp
[i
], mychannel
->language
);
2518 dres
= ast_waitstream(mychannel
, "");
2520 ast_log(LOG_WARNING
, "ast_streamfile of %s failed on %s\n", tmp
[i
], mychannel
->name
);
2531 if ((res
= ast_tonepair_start(mychannel
, 1004.0, 0, 99999999, 7200.0)))
2533 while(mychannel
->generatordata
&& (!myrpt
->stopgen
)) {
2534 if (ast_safe_sleep(mychannel
,1)) break;
2545 res
= ast_waitstream(mychannel
, "");
2547 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
2551 ast_stopstream(mychannel
);
2552 rpt_mutex_lock(&myrpt
->lock
);
2553 if (mytele
->mode
== TAILMSG
)
2557 myrpt
->tailmessagen
++;
2558 if(myrpt
->tailmessagen
>= myrpt
->p
.tailmessagemax
) myrpt
->tailmessagen
= 0;
2562 myrpt
->tmsgtimer
= myrpt
->p
.tailsquashedtime
;
2565 remque((struct qelem
*)mytele
);
2566 rpt_mutex_unlock(&myrpt
->lock
);
2568 ast_hangup(mychannel
);
2569 #ifdef APP_RPT_LOCK_DEBUG
2571 struct lockthread
*t
;
2574 ast_mutex_lock(&locklock
);
2575 t
= get_lockthread(pthread_self());
2576 if (t
) memset(t
,0,sizeof(struct lockthread
));
2577 ast_mutex_unlock(&locklock
);
2583 static void rpt_telemetry(struct rpt
*myrpt
,int mode
, void *data
)
2585 struct rpt_tele
*tele
;
2586 struct rpt_link
*mylink
= (struct rpt_link
*) data
;
2588 pthread_attr_t attr
;
2590 tele
= malloc(sizeof(struct rpt_tele
));
2593 ast_log(LOG_WARNING
, "Unable to allocate memory\n");
2598 memset((char *)tele
,0,sizeof(struct rpt_tele
));
2601 rpt_mutex_lock(&myrpt
->lock
);
2602 if((mode
== CONNFAIL
) || (mode
== REMDISC
) || (mode
== CONNECTED
)){
2603 memset(&tele
->mylink
,0,sizeof(struct rpt_link
));
2605 memcpy(&tele
->mylink
,mylink
,sizeof(struct rpt_link
));
2608 else if ((mode
== ARB_ALPHA
) || (mode
== REV_PATCH
)) {
2609 ast_copy_string(tele
->param
, (char *) data
, TELEPARAMSIZE
);
2611 insque((struct qelem
*)tele
, (struct qelem
*)myrpt
->tele
.next
);
2612 rpt_mutex_unlock(&myrpt
->lock
);
2613 pthread_attr_init(&attr
);
2614 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
2615 res
= ast_pthread_create(&tele
->threadid
,&attr
,rpt_tele_thread
,(void *) tele
);
2616 pthread_attr_destroy(&attr
);
2618 rpt_mutex_lock(&myrpt
->lock
);
2619 remque((struct qlem
*) tele
); /* We don't like stuck transmitters, remove it from the queue */
2620 rpt_mutex_unlock(&myrpt
->lock
);
2621 ast_log(LOG_WARNING
, "Could not create telemetry thread: %s\n",strerror(res
));
2626 static void *rpt_call(void *this)
2628 ZT_CONFINFO ci
; /* conference info */
2629 struct rpt
*myrpt
= (struct rpt
*)this;
2631 struct ast_frame wf
;
2632 int stopped
,congstarted
,dialtimer
,lastcidx
,aborted
;
2633 struct ast_channel
*mychannel
,*genchannel
;
2637 /* allocate a pseudo-channel thru asterisk */
2638 mychannel
= ast_request("zap",AST_FORMAT_SLINEAR
,"pseudo",NULL
);
2641 fprintf(stderr
,"rpt:Sorry unable to obtain pseudo channel\n");
2645 ci
.confno
= myrpt
->conf
; /* use the pseudo conference */
2646 ci
.confmode
= ZT_CONF_REALANDPSEUDO
| ZT_CONF_TALKER
| ZT_CONF_LISTENER
2647 | ZT_CONF_PSEUDO_TALKER
| ZT_CONF_PSEUDO_LISTENER
;
2648 /* first put the channel on the conference */
2649 if (ioctl(mychannel
->fds
[0],ZT_SETCONF
,&ci
) == -1)
2651 ast_log(LOG_WARNING
, "Unable to set conference mode to Announce\n");
2652 ast_hangup(mychannel
);
2653 myrpt
->callmode
= 0;
2656 /* allocate a pseudo-channel thru asterisk */
2657 genchannel
= ast_request("zap",AST_FORMAT_SLINEAR
,"pseudo",NULL
);
2660 fprintf(stderr
,"rpt:Sorry unable to obtain pseudo channel\n");
2661 ast_hangup(mychannel
);
2665 ci
.confno
= myrpt
->conf
;
2666 ci
.confmode
= ZT_CONF_REALANDPSEUDO
| ZT_CONF_TALKER
| ZT_CONF_LISTENER
2667 | ZT_CONF_PSEUDO_TALKER
| ZT_CONF_PSEUDO_LISTENER
;
2668 /* first put the channel on the conference */
2669 if (ioctl(genchannel
->fds
[0],ZT_SETCONF
,&ci
) == -1)
2671 ast_log(LOG_WARNING
, "Unable to set conference mode to Announce\n");
2672 ast_hangup(mychannel
);
2673 ast_hangup(genchannel
);
2674 myrpt
->callmode
= 0;
2677 if (myrpt
->p
.tonezone
&& (tone_zone_set_zone(mychannel
->fds
[0],myrpt
->p
.tonezone
) == -1))
2679 ast_log(LOG_WARNING
, "Unable to set tone zone %s\n",myrpt
->p
.tonezone
);
2680 ast_hangup(mychannel
);
2681 ast_hangup(genchannel
);
2682 myrpt
->callmode
= 0;
2685 if (myrpt
->p
.tonezone
&& (tone_zone_set_zone(genchannel
->fds
[0],myrpt
->p
.tonezone
) == -1))
2687 ast_log(LOG_WARNING
, "Unable to set tone zone %s\n",myrpt
->p
.tonezone
);
2688 ast_hangup(mychannel
);
2689 ast_hangup(genchannel
);
2690 myrpt
->callmode
= 0;
2693 /* start dialtone if patchquiet is 0. Special patch modes don't send dial tone */
2694 if ((!myrpt
->patchquiet
) && (tone_zone_play_tone(mychannel
->fds
[0],ZT_TONE_DIALTONE
) < 0))
2696 ast_log(LOG_WARNING
, "Cannot start dialtone\n");
2697 ast_hangup(mychannel
);
2698 ast_hangup(genchannel
);
2699 myrpt
->callmode
= 0;
2709 while ((myrpt
->callmode
== 1) || (myrpt
->callmode
== 4))
2712 if((myrpt
->patchdialtime
)&&(myrpt
->callmode
== 1)&&(myrpt
->cidx
!= lastcidx
)){
2714 lastcidx
= myrpt
->cidx
;
2717 if((myrpt
->patchdialtime
)&&(dialtimer
>= myrpt
->patchdialtime
)){
2718 rpt_mutex_lock(&myrpt
->lock
);
2720 myrpt
->callmode
= 0;
2721 rpt_mutex_unlock(&myrpt
->lock
);
2725 if ((!myrpt
->patchquiet
) && (!stopped
) && (myrpt
->callmode
== 1) && (myrpt
->cidx
> 0))
2728 /* stop dial tone */
2729 tone_zone_play_tone(mychannel
->fds
[0],-1);
2731 if (myrpt
->callmode
== 4)
2735 /* start congestion tone */
2736 tone_zone_play_tone(mychannel
->fds
[0],ZT_TONE_CONGESTION
);
2739 res
= ast_safe_sleep(mychannel
, MSWAIT
);
2742 ast_hangup(mychannel
);
2743 ast_hangup(genchannel
);
2744 rpt_mutex_lock(&myrpt
->lock
);
2745 myrpt
->callmode
= 0;
2746 rpt_mutex_unlock(&myrpt
->lock
);
2749 dialtimer
+= MSWAIT
;
2751 /* stop any tone generation */
2752 tone_zone_play_tone(mychannel
->fds
[0],-1);
2754 if (!myrpt
->callmode
)
2756 ast_hangup(mychannel
);
2757 ast_hangup(genchannel
);
2758 rpt_mutex_lock(&myrpt
->lock
);
2759 myrpt
->callmode
= 0;
2760 rpt_mutex_unlock(&myrpt
->lock
);
2761 if((!myrpt
->patchquiet
) && aborted
)
2762 rpt_telemetry(myrpt
, TERM
, NULL
);
2766 if (myrpt
->p
.ourcallerid
&& *myrpt
->p
.ourcallerid
){
2767 char *name
, *loc
, *instr
;
2768 instr
= strdup(myrpt
->p
.ourcallerid
);
2770 ast_callerid_parse(instr
, &name
, &loc
);
2772 if(mychannel
->cid
.cid_num
)
2773 free(mychannel
->cid
.cid_num
);
2774 mychannel
->cid
.cid_num
= strdup(loc
);
2777 if(mychannel
->cid
.cid_name
)
2778 free(mychannel
->cid
.cid_name
);
2779 mychannel
->cid
.cid_name
= strdup(name
);
2785 ast_copy_string(mychannel
->exten
, myrpt
->exten
, sizeof(mychannel
->exten
));
2786 ast_copy_string(mychannel
->context
, myrpt
->patchcontext
, sizeof(mychannel
->context
));
2788 if (myrpt
->p
.acctcode
)
2789 ast_string_field_set(mychannel
, accountcode
, myrpt
->p
.acctcode
);
2790 mychannel
->priority
= 1;
2791 ast_channel_undefer_dtmf(mychannel
);
2792 if (ast_pbx_start(mychannel
) < 0)
2794 ast_log(LOG_WARNING
, "Unable to start PBX!!\n");
2795 ast_hangup(mychannel
);
2796 ast_hangup(genchannel
);
2797 rpt_mutex_lock(&myrpt
->lock
);
2798 myrpt
->callmode
= 0;
2799 rpt_mutex_unlock(&myrpt
->lock
);
2803 rpt_mutex_lock(&myrpt
->lock
);
2804 myrpt
->callmode
= 3;
2805 /* set appropriate conference for the pseudo */
2807 ci
.confno
= myrpt
->conf
;
2808 ci
.confmode
= (myrpt
->p
.duplex
== 2) ? ZT_CONF_CONFANNMON
:
2809 (ZT_CONF_CONF
| ZT_CONF_LISTENER
| ZT_CONF_TALKER
);
2810 /* first put the channel on the conference in announce mode */
2811 if (ioctl(myrpt
->pchannel
->fds
[0],ZT_SETCONF
,&ci
) == -1)
2813 ast_log(LOG_WARNING
, "Unable to set conference mode to Announce\n");
2814 ast_hangup(mychannel
);
2815 ast_hangup(genchannel
);
2816 myrpt
->callmode
= 0;
2819 while(myrpt
->callmode
)
2821 if ((!mychannel
->pbx
) && (myrpt
->callmode
!= 4))
2823 if(myrpt
->patchfarenddisconnect
){ /* If patch is setup for far end disconnect */
2824 myrpt
->callmode
= 0;
2825 if(!myrpt
->patchquiet
){
2826 rpt_mutex_unlock(&myrpt
->lock
);
2827 rpt_telemetry(myrpt
, TERM
, NULL
);
2828 rpt_mutex_lock(&myrpt
->lock
);
2831 else{ /* Send congestion until patch is downed by command */
2832 myrpt
->callmode
= 4;
2833 rpt_mutex_unlock(&myrpt
->lock
);
2834 /* start congestion tone */
2835 tone_zone_play_tone(genchannel
->fds
[0],ZT_TONE_CONGESTION
);
2836 rpt_mutex_lock(&myrpt
->lock
);
2841 wf
.frametype
= AST_FRAME_DTMF
;
2842 wf
.subclass
= myrpt
->mydtmf
;
2848 rpt_mutex_unlock(&myrpt
->lock
);
2849 ast_write(genchannel
,&wf
);
2850 rpt_mutex_lock(&myrpt
->lock
);
2853 rpt_mutex_unlock(&myrpt
->lock
);
2854 usleep(MSWAIT
* 1000);
2855 rpt_mutex_lock(&myrpt
->lock
);
2857 rpt_mutex_unlock(&myrpt
->lock
);
2858 tone_zone_play_tone(genchannel
->fds
[0],-1);
2859 if (mychannel
->pbx
) ast_softhangup(mychannel
,AST_SOFTHANGUP_DEV
);
2860 ast_hangup(genchannel
);
2861 rpt_mutex_lock(&myrpt
->lock
);
2862 myrpt
->callmode
= 0;
2863 rpt_mutex_unlock(&myrpt
->lock
);
2864 /* set appropriate conference for the pseudo */
2866 ci
.confno
= myrpt
->conf
;
2867 ci
.confmode
= ((myrpt
->p
.duplex
== 2) || (myrpt
->p
.duplex
== 4)) ? ZT_CONF_CONFANNMON
:
2868 (ZT_CONF_CONF
| ZT_CONF_LISTENER
| ZT_CONF_TALKER
);
2869 /* first put the channel on the conference in announce mode */
2870 if (ioctl(myrpt
->pchannel
->fds
[0],ZT_SETCONF
,&ci
) == -1)
2872 ast_log(LOG_WARNING
, "Unable to set conference mode to Announce\n");
2877 static void send_link_dtmf(struct rpt
*myrpt
,char c
)
2880 struct ast_frame wf
;
2883 snprintf(str
, sizeof(str
), "D %s %s %d %c", myrpt
->cmdnode
, myrpt
->name
, ++(myrpt
->dtmfidx
), c
);
2884 wf
.frametype
= AST_FRAME_TEXT
;
2888 wf
.datalen
= strlen(str
) + 1;
2890 l
= myrpt
->links
.next
;
2891 /* first, see if our dude is there */
2892 while(l
!= &myrpt
->links
)
2894 if (l
->name
[0] == '0')
2899 /* if we found it, write it and were done */
2900 if (!strcmp(l
->name
,myrpt
->cmdnode
))
2902 wf
.data
= strdup(str
);
2903 if (l
->chan
) ast_write(l
->chan
,&wf
);
2908 l
= myrpt
->links
.next
;
2909 /* if not, give it to everyone */
2910 while(l
!= &myrpt
->links
)
2912 wf
.data
= strdup(str
);
2913 if (l
->chan
) ast_write(l
->chan
,&wf
);
2920 * Internet linking function
2923 static int function_ilink(struct rpt
*myrpt
, char *param
, char *digits
, int command_source
, struct rpt_link
*mylink
)
2927 char *s
, *s1
, *s2
, *tele
;
2928 char tmp
[300], deststr
[300] = "",modechange
= 0;
2929 char digitbuf
[MAXNODESTR
];
2932 ZT_CONFINFO ci
; /* conference info */
2941 ast_copy_string(digitbuf
,digits
,MAXNODESTR
);
2944 printf("@@@@ ilink param = %s, digitbuf = %s\n", (param
)? param
: "(null)", digitbuf
);
2946 switch(myatoi(param
)){
2947 case 1: /* Link off */
2948 if ((digitbuf
[0] == '0') && (myrpt
->lastlinknode
[0]))
2949 strcpy(digitbuf
,myrpt
->lastlinknode
);
2950 val
= ast_variable_retrieve(myrpt
->cfg
, myrpt
->p
.nodes
, digitbuf
);
2952 if(strlen(digitbuf
) >= myrpt
->longestnode
)
2956 ast_copy_string(tmp
,val
,sizeof(tmp
));
2958 s1
= strsep(&s
,",");
2959 s2
= strsep(&s
,",");
2960 rpt_mutex_lock(&myrpt
->lock
);
2961 l
= myrpt
->links
.next
;
2962 /* try to find this one in queue */
2963 while(l
!= &myrpt
->links
){
2964 if (l
->name
[0] == '0')
2969 /* if found matching string */
2970 if (!strcmp(l
->name
, digitbuf
))
2974 if (l
!= &myrpt
->links
){ /* if found */
2975 struct ast_frame wf
;
2976 ast_copy_string(myrpt
->lastlinknode
,digitbuf
,MAXNODESTR
);
2977 l
->retries
= MAX_RETRIES
+ 1;
2979 rpt_mutex_unlock(&myrpt
->lock
);
2980 wf
.frametype
= AST_FRAME_TEXT
;
2984 wf
.datalen
= strlen(discstr
) + 1;
2986 wf
.data
= strdup(discstr
);
2989 ast_write(l
->chan
,&wf
);
2990 if (ast_safe_sleep(l
->chan
,250) == -1) return DC_ERROR
;
2991 ast_softhangup(l
->chan
,AST_SOFTHANGUP_DEV
);
2993 rpt_telemetry(myrpt
, COMPLETE
, NULL
);
2996 rpt_mutex_unlock(&myrpt
->lock
);
2998 case 2: /* Link Monitor */
2999 if ((digitbuf
[0] == '0') && (myrpt
->lastlinknode
[0]))
3000 strcpy(digitbuf
,myrpt
->lastlinknode
);
3001 val
= ast_variable_retrieve(myrpt
->cfg
, myrpt
->p
.nodes
, digitbuf
);
3003 if(strlen(digitbuf
) >= myrpt
->longestnode
)
3007 ast_copy_string(tmp
, val
, sizeof(tmp
));
3009 s1
= strsep(&s
,",");
3010 s2
= strsep(&s
,",");
3011 rpt_mutex_lock(&myrpt
->lock
);
3012 l
= myrpt
->links
.next
;
3013 /* try to find this one in queue */
3014 while(l
!= &myrpt
->links
){
3015 if (l
->name
[0] == '0')
3020 /* if found matching string */
3021 if (!strcmp(l
->name
, digitbuf
))
3026 if (l
!= &myrpt
->links
)
3028 /* if already in this mode, just ignore */
3029 if ((!l
->mode
) || (!l
->chan
)) {
3030 rpt_mutex_unlock(&myrpt
->lock
);
3031 rpt_telemetry(myrpt
,REMALREADY
,NULL
);
3035 reconnects
= l
->reconnects
;
3036 rpt_mutex_unlock(&myrpt
->lock
);
3037 if (l
->chan
) ast_softhangup(l
->chan
,AST_SOFTHANGUP_DEV
);
3038 l
->retries
= MAX_RETRIES
+ 1;
3042 rpt_mutex_unlock(&myrpt
->lock
);
3043 ast_copy_string(myrpt
->lastlinknode
,digitbuf
,MAXNODESTR
);
3044 /* establish call in monitor mode */
3045 l
= malloc(sizeof(struct rpt_link
));
3047 ast_log(LOG_WARNING
, "Unable to malloc\n");
3050 /* zero the silly thing */
3051 memset((char *)l
,0,sizeof(struct rpt_link
));
3052 snprintf(deststr
, sizeof(deststr
), "IAX2/%s", s1
);
3053 tele
= strchr(deststr
,'/');
3055 fprintf(stderr
,"link2:Dial number (%s) must be in format tech/number\n",deststr
);
3059 l
->isremote
= (s
&& ast_true(s
));
3060 ast_copy_string(l
->name
, digitbuf
, MAXNODESTR
);
3061 l
->chan
= ast_request(deststr
,AST_FORMAT_SLINEAR
,tele
,NULL
);
3062 if (modechange
) l
->connected
= 1;
3064 ast_set_read_format(l
->chan
,AST_FORMAT_SLINEAR
);
3065 ast_set_write_format(l
->chan
,AST_FORMAT_SLINEAR
);
3066 l
->chan
->whentohangup
= 0;
3067 l
->chan
->appl
= "Apprpt";
3068 l
->chan
->data
= "(Remote Rx)";
3069 if (option_verbose
> 2)
3070 ast_verbose(VERBOSE_PREFIX_3
"rpt (remote) initiating call to %s/%s on %s\n",
3071 deststr
,tele
,l
->chan
->name
);
3072 if(l
->chan
->cid
.cid_num
)
3073 free(l
->chan
->cid
.cid_num
);
3074 l
->chan
->cid
.cid_num
= strdup(myrpt
->name
);
3075 ast_call(l
->chan
,tele
,0);
3079 rpt_telemetry(myrpt
,CONNFAIL
,l
);
3081 if (option_verbose
> 2)
3082 ast_verbose(VERBOSE_PREFIX_3
"Unable to place call to %s/%s on %s\n",
3083 deststr
,tele
,l
->chan
->name
);
3086 /* allocate a pseudo-channel thru asterisk */
3087 l
->pchan
= ast_request("zap",AST_FORMAT_SLINEAR
,"pseudo",NULL
);
3089 fprintf(stderr
,"rpt:Sorry unable to obtain pseudo channel\n");
3090 ast_hangup(l
->chan
);
3094 ast_set_read_format(l
->pchan
,AST_FORMAT_SLINEAR
);
3095 ast_set_write_format(l
->pchan
,AST_FORMAT_SLINEAR
);
3096 /* make a conference for the pseudo-one */
3098 ci
.confno
= myrpt
->conf
;
3099 ci
.confmode
= ZT_CONF_CONF
| ZT_CONF_LISTENER
| ZT_CONF_TALKER
;
3100 /* first put the channel on the conference in proper mode */
3101 if (ioctl(l
->pchan
->fds
[0],ZT_SETCONF
,&ci
) == -1)
3103 ast_log(LOG_WARNING
, "Unable to set conference mode to Announce\n");
3104 ast_hangup(l
->chan
);
3105 ast_hangup(l
->pchan
);
3109 rpt_mutex_lock(&myrpt
->lock
);
3110 l
->reconnects
= reconnects
;
3111 /* insert at end of queue */
3112 insque((struct qelem
*)l
,(struct qelem
*)myrpt
->links
.next
);
3113 rpt_mutex_unlock(&myrpt
->lock
);
3114 rpt_telemetry(myrpt
,COMPLETE
,NULL
);
3116 case 3: /* Link transceive */
3117 if ((digitbuf
[0] == '0') && (myrpt
->lastlinknode
[0]))
3118 strcpy(digitbuf
,myrpt
->lastlinknode
);
3119 val
= ast_variable_retrieve(myrpt
->cfg
, myrpt
->p
.nodes
, digitbuf
);
3121 if(strlen(digitbuf
) >= myrpt
->longestnode
)
3125 ast_copy_string(tmp
,val
,sizeof(tmp
));
3127 s1
= strsep(&s
,",");
3128 s2
= strsep(&s
,",");
3129 rpt_mutex_lock(&myrpt
->lock
);
3130 l
= myrpt
->links
.next
;
3131 /* try to find this one in queue */
3132 while(l
!= &myrpt
->links
){
3133 if (l
->name
[0] == '0')
3138 /* if found matching string */
3139 if (!strcmp(l
->name
, digitbuf
))
3144 if (l
!= &myrpt
->links
){
3145 /* if already in this mode, just ignore */
3146 if ((l
->mode
) || (!l
->chan
)) {
3147 rpt_mutex_unlock(&myrpt
->lock
);
3148 rpt_telemetry(myrpt
, REMALREADY
, NULL
);
3151 reconnects
= l
->reconnects
;
3152 rpt_mutex_unlock(&myrpt
->lock
);
3153 if (l
->chan
) ast_softhangup(l
->chan
, AST_SOFTHANGUP_DEV
);
3154 l
->retries
= MAX_RETRIES
+ 1;
3158 rpt_mutex_unlock(&myrpt
->lock
);
3159 ast_copy_string(myrpt
->lastlinknode
,digitbuf
,MAXNODESTR
);
3160 /* establish call in tranceive mode */
3161 l
= malloc(sizeof(struct rpt_link
));
3163 ast_log(LOG_WARNING
, "Unable to malloc\n");
3166 /* zero the silly thing */
3167 memset((char *)l
,0,sizeof(struct rpt_link
));
3170 ast_copy_string(l
->name
, digitbuf
, MAXNODESTR
);
3171 l
->isremote
= (s
&& ast_true(s
));
3172 if (modechange
) l
->connected
= 1;
3173 snprintf(deststr
, sizeof(deststr
), "IAX2/%s", s1
);
3174 tele
= strchr(deststr
, '/');
3176 fprintf(stderr
,"link3:Dial number (%s) must be in format tech/number\n",deststr
);
3181 l
->chan
= ast_request(deststr
, AST_FORMAT_SLINEAR
, tele
,NULL
);
3183 ast_set_read_format(l
->chan
, AST_FORMAT_SLINEAR
);
3184 ast_set_write_format(l
->chan
, AST_FORMAT_SLINEAR
);
3185 l
->chan
->whentohangup
= 0;
3186 l
->chan
->appl
= "Apprpt";
3187 l
->chan
->data
= "(Remote Rx)";
3188 if (option_verbose
> 2)
3189 ast_verbose(VERBOSE_PREFIX_3
"rpt (remote) initiating call to %s/%s on %s\n",
3190 deststr
, tele
, l
->chan
->name
);
3191 if(l
->chan
->cid
.cid_num
)
3192 free(l
->chan
->cid
.cid_num
);
3193 l
->chan
->cid
.cid_num
= strdup(myrpt
->name
);
3194 ast_call(l
->chan
,tele
,999);
3197 rpt_telemetry(myrpt
,CONNFAIL
,l
);
3199 if (option_verbose
> 2)
3200 ast_verbose(VERBOSE_PREFIX_3
"Unable to place call to %s/%s on %s\n",
3201 deststr
,tele
,l
->chan
->name
);
3204 /* allocate a pseudo-channel thru asterisk */
3205 l
->pchan
= ast_request("zap",AST_FORMAT_SLINEAR
,"pseudo",NULL
);
3207 fprintf(stderr
,"rpt:Sorry unable to obtain pseudo channel\n");
3208 ast_hangup(l
->chan
);
3212 ast_set_read_format(l
->pchan
, AST_FORMAT_SLINEAR
);
3213 ast_set_write_format(l
->pchan
, AST_FORMAT_SLINEAR
);
3214 /* make a conference for the tx */
3216 ci
.confno
= myrpt
->conf
;
3217 ci
.confmode
= ZT_CONF_CONF
| ZT_CONF_LISTENER
| ZT_CONF_TALKER
;
3218 /* first put the channel on the conference in proper mode */
3219 if (ioctl(l
->pchan
->fds
[0], ZT_SETCONF
, &ci
) == -1)
3221 ast_log(LOG_WARNING
, "Unable to set conference mode to Announce\n");
3222 ast_hangup(l
->chan
);
3223 ast_hangup(l
->pchan
);
3227 rpt_mutex_lock(&myrpt
->lock
);
3228 l
->reconnects
= reconnects
;
3229 /* insert at end of queue */
3230 insque((struct qelem
*)l
,(struct qelem
*)myrpt
->links
.next
);
3231 rpt_mutex_unlock(&myrpt
->lock
);
3232 rpt_telemetry(myrpt
,COMPLETE
,NULL
);
3234 case 4: /* Enter Command Mode */
3236 /* if doesnt allow link cmd, or no links active, return */
3237 if (((command_source
!= SOURCE_RPT
) && (command_source
!= SOURCE_PHONE
) && (command_source
!= SOURCE_DPHONE
)) || (myrpt
->links
.next
== &myrpt
->links
))
3240 /* if already in cmd mode, or selected self, fughetabahtit */
3241 if ((myrpt
->cmdnode
[0]) || (!strcmp(myrpt
->name
, digitbuf
))){
3243 rpt_telemetry(myrpt
, REMALREADY
, NULL
);
3246 if ((digitbuf
[0] == '0') && (myrpt
->lastlinknode
[0]))
3247 strcpy(digitbuf
,myrpt
->lastlinknode
);
3248 /* node must at least exist in list */
3249 val
= ast_variable_retrieve(myrpt
->cfg
, myrpt
->p
.nodes
, digitbuf
);
3251 if(strlen(digitbuf
) >= myrpt
->longestnode
)
3256 rpt_mutex_lock(&myrpt
->lock
);
3257 strcpy(myrpt
->lastlinknode
,digitbuf
);
3258 ast_copy_string(myrpt
->cmdnode
, digitbuf
, sizeof(myrpt
->cmdnode
));
3259 rpt_mutex_unlock(&myrpt
->lock
);
3260 rpt_telemetry(myrpt
, REMGO
, NULL
);
3263 case 5: /* Status */
3264 rpt_telemetry(myrpt
, STATUS
, NULL
);
3268 case 6: /* All Links Off */
3269 l
= myrpt
->links
.next
;
3271 while(l
!= &myrpt
->links
){ /* This code is broke and needs to be changed to work with the reconnect kludge */
3272 if (l
->chan
) ast_softhangup(l
->chan
, AST_SOFTHANGUP_DEV
); /* Hang 'em up */
3275 rpt_telemetry(myrpt
, COMPLETE
, NULL
);
3278 case 7: /* Identify last node which keyed us up */
3279 rpt_telemetry(myrpt
, LASTNODEKEY
, NULL
);
3287 return DC_INDETERMINATE
;
3294 static int function_autopatchup(struct rpt
*myrpt
, char *param
, char *digitbuf
, int command_source
, struct rpt_link
*mylink
)
3296 pthread_attr_t attr
;
3297 int i
, index
, paramlength
;
3300 char *paramlist
[20];
3302 static char *keywords
[] = {
3315 printf("@@@@ Autopatch up\n");
3317 if(!myrpt
->callmode
){
3319 myrpt
->patchnoct
= 0;
3320 myrpt
->patchdialtime
= 0;
3321 myrpt
->patchfarenddisconnect
= 0;
3322 myrpt
->patchquiet
= 0;
3323 ast_copy_string(myrpt
->patchcontext
, myrpt
->p
.ourcontext
, MAXPATCHCONTEXT
);
3326 /* Process parameter list */
3327 lparam
= ast_strdupa(param
);
3329 ast_log(LOG_ERROR
,"App_rpt out of memory on line %d\n",__LINE__
);
3332 paramlength
= finddelim(lparam
, paramlist
, 20);
3333 for(i
= 0; i
< paramlength
; i
++){
3334 index
= matchkeyword(paramlist
[i
], &value
, keywords
);
3336 value
= skipchars(value
, "= ");
3339 case 1: /* context */
3340 ast_copy_string(myrpt
->patchcontext
, value
, MAXPATCHCONTEXT
) ;
3343 case 2: /* dialtime */
3344 myrpt
->patchdialtime
= atoi(value
);
3347 case 3: /* farenddisconnect */
3348 myrpt
->patchfarenddisconnect
= atoi(value
);
3352 myrpt
->patchnoct
= atoi(value
);
3356 myrpt
->patchquiet
= atoi(value
);
3366 rpt_mutex_lock(&myrpt
->lock
);
3368 /* if on call, force * into current audio stream */
3370 if ((myrpt
->callmode
== 2) || (myrpt
->callmode
== 3)){
3371 myrpt
->mydtmf
= myrpt
->p
.funcchar
;
3373 if (myrpt
->callmode
){
3374 rpt_mutex_unlock(&myrpt
->lock
);
3377 myrpt
->callmode
= 1;
3379 myrpt
->exten
[myrpt
->cidx
] = 0;
3380 rpt_mutex_unlock(&myrpt
->lock
);
3381 pthread_attr_init(&attr
);
3382 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
3383 ast_pthread_create(&myrpt
->rpt_call_thread
,&attr
,rpt_call
,(void *) myrpt
);
3384 pthread_attr_destroy(&attr
);
3392 static int function_autopatchdn(struct rpt
*myrpt
, char *param
, char *digitbuf
, int command_source
, struct rpt_link
*mylink
)
3398 printf("@@@@ Autopatch down\n");
3400 rpt_mutex_lock(&myrpt
->lock
);
3402 if (!myrpt
->callmode
){
3403 rpt_mutex_unlock(&myrpt
->lock
);
3407 myrpt
->callmode
= 0;
3408 rpt_mutex_unlock(&myrpt
->lock
);
3409 rpt_telemetry(myrpt
, TERM
, NULL
);
3417 static int function_status(struct rpt
*myrpt
, char *param
, char *digitbuf
, int command_source
, struct rpt_link
*mylink
)
3427 printf("@@@@ status param = %s, digitbuf = %s\n", (param
)? param
: "(null)", digitbuf
);
3429 switch(myatoi(param
)){
3430 case 1: /* System ID */
3431 rpt_telemetry(myrpt
, ID1
, NULL
);
3433 case 2: /* System Time */
3434 rpt_telemetry(myrpt
, STATS_TIME
, NULL
);
3436 case 3: /* app_rpt.c version */
3437 rpt_telemetry(myrpt
, STATS_VERSION
, NULL
);
3441 return DC_INDETERMINATE
;
3445 * Macro-oni (without Salami)
3448 static int function_macro(struct rpt
*myrpt
, char *param
, char *digitbuf
, int command_source
, struct rpt_link
*mylink
)
3453 struct ast_channel
*mychannel
;
3455 if ((!myrpt
->remote
) && (!myrpt
->enable
))
3459 printf("@@@@ macro-oni param = %s, digitbuf = %s\n", (param
)? param
: "(null)", digitbuf
);
3461 mychannel
= myrpt
->remchannel
;
3463 if(strlen(digitbuf
) < 1) /* needs 1 digit */
3464 return DC_INDETERMINATE
;
3466 for(i
= 0 ; i
< digitbuf
[i
] ; i
++) {
3467 if((digitbuf
[i
] < '0') || (digitbuf
[i
] > '9'))
3471 if (*digitbuf
== '0') val
= myrpt
->p
.startupmacro
;
3472 else val
= ast_variable_retrieve(myrpt
->cfg
, myrpt
->p
.macro
, digitbuf
);
3473 /* param was 1 for local buf */
3475 rpt_telemetry(myrpt
, MACRO_NOTFOUND
, NULL
);
3478 rpt_mutex_lock(&myrpt
->lock
);
3479 if ((MAXMACRO
- strlen(myrpt
->macrobuf
)) < strlen(val
))
3481 rpt_mutex_unlock(&myrpt
->lock
);
3482 rpt_telemetry(myrpt
, MACRO_BUSY
, NULL
);
3485 myrpt
->macrotimer
= MACROTIME
;
3486 strncat(myrpt
->macrobuf
,val
,MAXMACRO
- 1);
3487 rpt_mutex_unlock(&myrpt
->lock
);
3492 * COP - Control operator
3495 static int function_cop(struct rpt
*myrpt
, char *param
, char *digitbuf
, int command_source
, struct rpt_link
*mylink
)
3500 switch(myatoi(param
)){
3501 case 1: /* System reset */
3502 system("killall -9 asterisk"); /* FIXME to drastic? */
3507 rpt_telemetry(myrpt
, ARB_ALPHA
, (void *) "RPTENA");
3514 case 4: /* test tone on */
3515 rpt_telemetry(myrpt
, TEST_TONE
, NULL
);
3518 case 5: /* Disgorge variables to log for debug purposes */
3519 myrpt
->disgorgetime
= time(NULL
) + 10; /* Do it 10 seconds later */
3522 case 6: /* Simulate COR being activated (phone only) */
3523 if (command_source
!= SOURCE_PHONE
) return DC_INDETERMINATE
;
3527 return DC_INDETERMINATE
;
3531 * Collect digits one by one until something matches
3534 static int collect_function_digits(struct rpt
*myrpt
, char *digits
,
3535 int command_source
, struct rpt_link
*mylink
)
3538 char *stringp
,*action
,*param
,*functiondigits
;
3539 char function_table_name
[30] = "";
3540 char workstring
[200];
3542 struct ast_variable
*vp
;
3545 printf("@@@@ Digits collected: %s, source: %d\n", digits
, command_source
);
3547 if (command_source
== SOURCE_DPHONE
) {
3548 if (!myrpt
->p
.dphone_functions
) return DC_INDETERMINATE
;
3549 ast_copy_string(function_table_name
, myrpt
->p
.dphone_functions
, sizeof(function_table_name
));
3551 else if (command_source
== SOURCE_PHONE
) {
3552 if (!myrpt
->p
.phone_functions
) return DC_INDETERMINATE
;
3553 ast_copy_string(function_table_name
, myrpt
->p
.phone_functions
, sizeof(function_table_name
));
3555 else if (command_source
== SOURCE_LNK
)
3556 ast_copy_string(function_table_name
, myrpt
->p
.link_functions
, sizeof(function_table_name
));
3558 ast_copy_string(function_table_name
, myrpt
->p
.functions
, sizeof(function_table_name
));
3559 vp
= ast_variable_browse(myrpt
->cfg
, function_table_name
);
3561 if(!strncasecmp(vp
->name
, digits
, strlen(vp
->name
)))
3568 n
= myrpt
->longestfunc
;
3569 if (command_source
== SOURCE_LNK
) n
= myrpt
->link_longestfunc
;
3571 if (command_source
== SOURCE_PHONE
) n
= myrpt
->phone_longestfunc
;
3573 if (command_source
== SOURCE_DPHONE
) n
= myrpt
->dphone_longestfunc
;
3575 if(strlen(digits
) >= n
)
3578 return DC_INDETERMINATE
;
3580 /* Found a match, retrieve value part and parse */
3581 ast_copy_string(workstring
, vp
->value
, sizeof(workstring
));
3582 stringp
= workstring
;
3583 action
= strsep(&stringp
, ",");
3586 printf("@@@@ action: %s, param = %s\n",action
, (param
) ? param
: "(null)");
3587 /* Look up the action */
3588 for(i
= 0 ; i
< (sizeof(function_table
)/sizeof(struct function_table_tag
)); i
++){
3589 if(!strncasecmp(action
, function_table
[i
].action
, strlen(action
)))
3593 printf("@@@@ table index i = %d\n",i
);
3594 if(i
== (sizeof(function_table
)/sizeof(struct function_table_tag
))){
3595 /* Error, action not in table */
3598 if(function_table
[i
].function
== NULL
){
3599 /* Error, function undefined */
3601 printf("@@@@ NULL for action: %s\n",action
);
3604 functiondigits
= digits
+ strlen(vp
->name
);
3605 return (*function_table
[i
].function
)(myrpt
, param
, functiondigits
, command_source
, mylink
);
3609 static void handle_link_data(struct rpt
*myrpt
, struct rpt_link
*mylink
,
3612 char tmp
[300],cmd
[300] = "",dest
[300],src
[300],c
;
3615 struct ast_frame wf
;
3617 wf
.frametype
= AST_FRAME_TEXT
;
3621 wf
.datalen
= strlen(str
) + 1;
3623 /* put string in our buffer */
3624 ast_copy_string(tmp
, str
, sizeof(tmp
));
3626 if (!strcmp(tmp
,discstr
))
3629 mylink
->retries
= MAX_RETRIES
+ 1;
3630 ast_softhangup(mylink
->chan
,AST_SOFTHANGUP_DEV
);
3633 if (sscanf(tmp
,"%s %s %s %d %c",cmd
,dest
,src
,&seq
,&c
) != 5)
3635 ast_log(LOG_WARNING
, "Unable to parse link string %s\n",str
);
3638 if (strcmp(cmd
,"D"))
3640 ast_log(LOG_WARNING
, "Unable to parse link string %s\n",str
);
3646 strcpy(dest
,myrpt
->name
);
3649 /* if not for me, redistribute to all links */
3650 if (strcmp(dest
,myrpt
->name
))
3652 l
= myrpt
->links
.next
;
3653 /* see if this is one in list */
3654 while(l
!= &myrpt
->links
)
3656 if (l
->name
[0] == '0')
3661 /* dont send back from where it came */
3662 if ((l
== mylink
) || (!strcmp(l
->name
,mylink
->name
)))
3667 /* if it is, send it and we're done */
3668 if (!strcmp(l
->name
,dest
))
3670 /* send, but not to src */
3671 if (strcmp(l
->name
,src
)) {
3672 wf
.data
= strdup(str
);
3673 if (l
->chan
) ast_write(l
->chan
,&wf
);
3679 l
= myrpt
->links
.next
;
3680 /* otherwise, send it to all of em */
3681 while(l
!= &myrpt
->links
)
3683 if (l
->name
[0] == '0')
3688 /* dont send back from where it came */
3689 if ((l
== mylink
) || (!strcmp(l
->name
,mylink
->name
)))
3694 /* send, but not to src */
3695 if (strcmp(l
->name
,src
)) {
3696 wf
.data
= strdup(str
);
3697 if (l
->chan
) ast_write(l
->chan
,&wf
);
3703 rpt_mutex_lock(&myrpt
->lock
);
3704 if (c
== myrpt
->p
.endchar
) myrpt
->stopgen
= 1;
3705 if (myrpt
->callmode
== 1)
3707 myrpt
->exten
[myrpt
->cidx
++] = c
;
3708 myrpt
->exten
[myrpt
->cidx
] = 0;
3709 /* if this exists */
3710 if (ast_exists_extension(myrpt
->pchannel
,myrpt
->patchcontext
,myrpt
->exten
,1,NULL
))
3712 myrpt
->callmode
= 2;
3713 if(!myrpt
->patchquiet
){
3714 rpt_mutex_unlock(&myrpt
->lock
);
3715 rpt_telemetry(myrpt
,PROC
,NULL
);
3716 rpt_mutex_lock(&myrpt
->lock
);
3719 /* if can continue, do so */
3720 if (!ast_canmatch_extension(myrpt
->pchannel
,myrpt
->patchcontext
,myrpt
->exten
,1,NULL
))
3722 /* call has failed, inform user */
3723 myrpt
->callmode
= 4;
3726 if ((myrpt
->callmode
== 2) || (myrpt
->callmode
== 3))
3730 if (c
== myrpt
->p
.funcchar
)
3732 myrpt
->rem_dtmfidx
= 0;
3733 myrpt
->rem_dtmfbuf
[myrpt
->rem_dtmfidx
] = 0;
3734 time(&myrpt
->rem_dtmf_time
);
3735 rpt_mutex_unlock(&myrpt
->lock
);
3738 else if ((c
!= myrpt
->p
.endchar
) && (myrpt
->rem_dtmfidx
>= 0))
3740 time(&myrpt
->rem_dtmf_time
);
3741 if (myrpt
->rem_dtmfidx
< MAXDTMF
)
3743 myrpt
->rem_dtmfbuf
[myrpt
->rem_dtmfidx
++] = c
;
3744 myrpt
->rem_dtmfbuf
[myrpt
->rem_dtmfidx
] = 0;
3746 rpt_mutex_unlock(&myrpt
->lock
);
3747 ast_copy_string(cmd
, myrpt
->rem_dtmfbuf
, sizeof(cmd
));
3748 res
= collect_function_digits(myrpt
, cmd
, SOURCE_LNK
, mylink
);
3749 rpt_mutex_lock(&myrpt
->lock
);
3753 case DC_INDETERMINATE
:
3757 myrpt
->rem_dtmfidx
= 0;
3758 myrpt
->rem_dtmfbuf
[0] = 0;
3763 myrpt
->totalexecdcommands
++;
3764 myrpt
->dailyexecdcommands
++;
3765 ast_copy_string(myrpt
->lastdtmfcommand
, cmd
, MAXDTMF
);
3766 myrpt
->lastdtmfcommand
[MAXDTMF
-1] = '\0';
3767 myrpt
->rem_dtmfbuf
[0] = 0;
3768 myrpt
->rem_dtmfidx
= -1;
3769 myrpt
->rem_dtmf_time
= 0;
3774 myrpt
->rem_dtmfbuf
[0] = 0;
3775 myrpt
->rem_dtmfidx
= -1;
3776 myrpt
->rem_dtmf_time
= 0;
3782 rpt_mutex_unlock(&myrpt
->lock
);
3786 static void handle_link_phone_dtmf(struct rpt
*myrpt
, struct rpt_link
*mylink
,
3793 rpt_mutex_lock(&myrpt
->lock
);
3794 if (c
== myrpt
->p
.endchar
)
3799 rpt_mutex_unlock(&myrpt
->lock
);
3803 if (myrpt
->cmdnode
[0])
3805 myrpt
->cmdnode
[0] = 0;
3806 myrpt
->dtmfidx
= -1;
3807 myrpt
->dtmfbuf
[0] = 0;
3808 rpt_mutex_unlock(&myrpt
->lock
);
3809 rpt_telemetry(myrpt
,COMPLETE
,NULL
);
3813 if (myrpt
->cmdnode
[0])
3815 rpt_mutex_unlock(&myrpt
->lock
);
3816 send_link_dtmf(myrpt
,c
);
3819 if (myrpt
->callmode
== 1)
3821 myrpt
->exten
[myrpt
->cidx
++] = c
;
3822 myrpt
->exten
[myrpt
->cidx
] = 0;
3823 /* if this exists */
3824 if (ast_exists_extension(myrpt
->pchannel
,myrpt
->patchcontext
,myrpt
->exten
,1,NULL
))
3826 myrpt
->callmode
= 2;
3827 if(!myrpt
->patchquiet
){
3828 rpt_mutex_unlock(&myrpt
->lock
);
3829 rpt_telemetry(myrpt
,PROC
,NULL
);
3830 rpt_mutex_lock(&myrpt
->lock
);
3833 /* if can continue, do so */
3834 if (!ast_canmatch_extension(myrpt
->pchannel
,myrpt
->patchcontext
,myrpt
->exten
,1,NULL
))
3836 /* call has failed, inform user */
3837 myrpt
->callmode
= 4;
3840 if ((myrpt
->callmode
== 2) || (myrpt
->callmode
== 3))
3844 if (c
== myrpt
->p
.funcchar
)
3846 myrpt
->rem_dtmfidx
= 0;
3847 myrpt
->rem_dtmfbuf
[myrpt
->rem_dtmfidx
] = 0;
3848 time(&myrpt
->rem_dtmf_time
);
3849 rpt_mutex_unlock(&myrpt
->lock
);
3852 else if ((c
!= myrpt
->p
.endchar
) && (myrpt
->rem_dtmfidx
>= 0))
3854 time(&myrpt
->rem_dtmf_time
);
3855 if (myrpt
->rem_dtmfidx
< MAXDTMF
)
3857 myrpt
->rem_dtmfbuf
[myrpt
->rem_dtmfidx
++] = c
;
3858 myrpt
->rem_dtmfbuf
[myrpt
->rem_dtmfidx
] = 0;
3860 rpt_mutex_unlock(&myrpt
->lock
);
3861 ast_copy_string(cmd
, myrpt
->rem_dtmfbuf
, sizeof(cmd
));
3862 switch(mylink
->phonemode
)
3865 res
= collect_function_digits(myrpt
, cmd
,
3866 SOURCE_PHONE
, mylink
);
3869 res
= collect_function_digits(myrpt
, cmd
,
3870 SOURCE_DPHONE
,mylink
);
3873 res
= collect_function_digits(myrpt
, cmd
,
3874 SOURCE_LNK
, mylink
);
3878 rpt_mutex_lock(&myrpt
->lock
);
3882 case DC_INDETERMINATE
:
3890 myrpt
->rem_dtmfidx
= 0;
3891 myrpt
->rem_dtmfbuf
[0] = 0;
3896 myrpt
->totalexecdcommands
++;
3897 myrpt
->dailyexecdcommands
++;
3898 ast_copy_string(myrpt
->lastdtmfcommand
, cmd
, MAXDTMF
);
3899 myrpt
->lastdtmfcommand
[MAXDTMF
-1] = '\0';
3900 myrpt
->rem_dtmfbuf
[0] = 0;
3901 myrpt
->rem_dtmfidx
= -1;
3902 myrpt
->rem_dtmf_time
= 0;
3907 myrpt
->rem_dtmfbuf
[0] = 0;
3908 myrpt
->rem_dtmfidx
= -1;
3909 myrpt
->rem_dtmf_time
= 0;
3915 rpt_mutex_unlock(&myrpt
->lock
);
3919 /* Doug Hall RBI-1 serial data definitions:
3921 * Byte 0: Expansion external outputs
3923 * Bits 0-3 are BAND as follows:
3924 * Bits 4-5 are POWER bits as follows:
3928 * Bits 6-7 are always set
3930 * Bits 0-3 MHZ in BCD format
3931 * Bits 4-5 are offset as follows:
3935 * 03 - minus minus (whatever that is)
3936 * Bit 6 is the 0/5 KHZ bit
3937 * Bit 7 is always set
3939 * Bits 0-3 are 10 KHZ in BCD format
3940 * Bits 4-7 are 100 KHZ in BCD format
3941 * Byte 4: PL Tone code and encode/decode enable bits
3942 * Bits 0-5 are PL tone code (comspec binary codes)
3943 * Bit 6 is encode enable/disable
3944 * Bit 7 is decode enable/disable
3947 /* take the frequency from the 10 mhz digits (and up) and convert it
3950 static int rbi_mhztoband(char *str
)
3954 i
= atoi(str
) / 10; /* get the 10's of mhz */
3985 /* take a PL frequency and turn it into a code */
3986 static int rbi_pltocode(char *str
)
3991 s
= strchr(str
,'.');
3993 if (s
) i
= atoi(s
+ 1);
3994 i
+= atoi(str
) * 10;
4078 * Shift out a formatted serial bit stream
4081 static void rbi_out_parallel(struct rpt
*myrpt
,unsigned char *data
)
4085 static volatile long long delayvar
;
4087 for(i
= 0 ; i
< 5 ; i
++){
4089 for(j
= 0 ; j
< 8 ; j
++){
4091 outb(d
,myrpt
->p
.iobase
);
4093 for(delayvar
= 1; delayvar
< 15000; delayvar
++);
4095 outb(d
| 2,myrpt
->p
.iobase
);
4097 for(delayvar
= 1; delayvar
< 30000; delayvar
++);
4098 outb(d
,myrpt
->p
.iobase
);
4100 for(delayvar
= 1; delayvar
< 10000; delayvar
++);
4104 for(delayvar
= 1; delayvar
< 50000; delayvar
++);
4107 static void rbi_out(struct rpt
*myrpt
,unsigned char *data
)
4109 struct zt_radio_param r
;
4111 memset(&r
,0,sizeof(struct zt_radio_param
));
4112 r
.radpar
= ZT_RADPAR_REMMODE
;
4113 r
.data
= ZT_RADPAR_REM_RBI1
;
4114 /* if setparam ioctl fails, its probably not a pciradio card */
4115 if (ioctl(myrpt
->rxchannel
->fds
[0],ZT_RADIO_SETPARAM
,&r
) == -1)
4117 rbi_out_parallel(myrpt
,data
);
4120 r
.radpar
= ZT_RADPAR_REMCOMMAND
;
4121 memcpy(&r
.data
,data
,5);
4122 if (ioctl(myrpt
->rxchannel
->fds
[0],ZT_RADIO_SETPARAM
,&r
) == -1)
4124 ast_log(LOG_WARNING
,"Cannot send RBI command for channel %s\n",myrpt
->rxchannel
->name
);
4129 static int serial_remote_io(struct rpt
*myrpt
, unsigned char *txbuf
, int txbytes
, char *rxbuf
,
4130 int rxmaxbytes
, int asciiflag
)
4133 struct zt_radio_param prm
;
4136 printf("String output was: ");
4137 for(i
= 0; i
< txbytes
; i
++)
4138 printf("%02X ", (unsigned char ) txbuf
[i
]);
4142 prm
.radpar
= ZT_RADPAR_REMMODE
;
4143 if (asciiflag
) prm
.data
= ZT_RADPAR_REM_SERIAL_ASCII
;
4144 else prm
.data
= ZT_RADPAR_REM_SERIAL
;
4145 if (ioctl(myrpt
->rxchannel
->fds
[0],ZT_RADIO_SETPARAM
,&prm
) == -1) return -1;
4146 prm
.radpar
= ZT_RADPAR_REMCOMMAND
;
4147 prm
.data
= rxmaxbytes
;
4148 memcpy(prm
.buf
,txbuf
,txbytes
);
4149 prm
.index
= txbytes
;
4150 if (ioctl(myrpt
->rxchannel
->fds
[0],ZT_RADIO_SETPARAM
,&prm
) == -1) return -1;
4154 memcpy(rxbuf
,prm
.buf
,prm
.index
);
4159 static int setrbi(struct rpt
*myrpt
)
4161 char tmp
[MAXREMSTR
] = "",*s
;
4162 unsigned char rbicmd
[5];
4163 int band
,txoffset
= 0,txpower
= 0,txpl
;
4165 /* must be a remote system */
4166 if (!myrpt
->remote
) return(0);
4167 /* must have rbi hardware */
4168 if (strncmp(myrpt
->remote
,remote_rig_rbi
,3)) return(0);
4169 ast_copy_string(tmp
, myrpt
->freq
, sizeof(tmp
));
4170 s
= strchr(tmp
,'.');
4171 /* if no decimal, is invalid */
4175 printf("@@@@ Frequency needs a decimal\n");
4180 if (strlen(tmp
) < 2){
4182 printf("@@@@ Bad MHz digits: %s\n", tmp
);
4188 printf("@@@@ Bad KHz digits: %s\n", s
);
4192 if ((s
[2] != '0') && (s
[2] != '5')){
4194 printf("@@@@ KHz must end in 0 or 5: %c\n", s
[2]);
4198 band
= rbi_mhztoband(tmp
);
4201 printf("@@@@ Bad Band: %s\n", tmp
);
4205 txpl
= rbi_pltocode(myrpt
->txpl
);
4209 printf("@@@@ Bad TX PL: %s\n", myrpt
->txpl
);
4214 switch(myrpt
->offset
)
4226 switch(myrpt
->powerlevel
)
4239 rbicmd
[1] = band
| txpower
| 0xc0;
4240 rbicmd
[2] = (*(s
- 2) - '0') | txoffset
| 0x80;
4241 if (s
[2] == '5') rbicmd
[2] |= 0x40;
4242 rbicmd
[3] = ((*s
- '0') << 4) + (s
[1] - '0');
4244 if (myrpt
->txplon
) rbicmd
[4] |= 0x40;
4245 if (myrpt
->rxplon
) rbicmd
[4] |= 0x80;
4246 rbi_out(myrpt
,rbicmd
);
4251 /* Check for valid rbi frequency */
4252 /* Hard coded limits now, configurable later, maybe? */
4254 static int check_freq_rbi(int m
, int d
, int *defmode
)
4256 int dflmd
= REM_MODE_FM
;
4258 if(m
== 50){ /* 6 meters */
4262 else if((m
>= 51) && ( m
< 54)){
4265 else if(m
== 144){ /* 2 meters */
4269 else if((m
>= 145) && (m
< 148)){
4272 else if((m
>= 222) && (m
< 225)){ /* 1.25 meters */
4275 else if((m
>= 430) && (m
< 450)){ /* 70 centimeters */
4278 else if((m
>= 1240) && (m
< 1300)){ /* 23 centimeters */
4292 * Split frequency into mhz and decimals
4295 static int split_freq(char *mhz
, char *decimals
, char *freq
)
4299 freq
= ast_strdupa(freq
);
4300 if ((decp
= strchr(freq
, '.'))) {
4302 ast_copy_string(mhz
, freq
, MAXREMSTR
);
4303 strcpy(decimals
, "00000");
4304 ast_copy_string(decimals
, decp
, 6);
4313 * Split ctcss frequency into hertz and decimal
4316 static int split_ctcss_freq(char *hertz
, char *decimal
, char *freq
)
4320 freq
= ast_strdupa(freq
);
4321 if ((decp
= strchr(freq
, '.'))) {
4323 ast_copy_string(hertz
, freq
, MAXREMSTR
);
4324 ast_copy_string(decimal
, decp
, sizeof(decimal
));
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
;
4350 else if(m
== 3){ /* 80 meters */
4351 dflmd
= REM_MODE_LSB
;
4355 else if(m
== 7){ /* 40 meters */
4356 dflmd
= REM_MODE_LSB
;
4357 if((d
< 15001) || (d
> 29999))
4360 else if(m
== 14){ /* 20 meters */
4361 dflmd
= REM_MODE_USB
;
4362 if((d
< 15001) || (d
> 34999))
4365 else if(m
== 18){ /* 17 meters */
4366 dflmd
= REM_MODE_USB
;
4367 if((d
< 11001) || (d
> 16797))
4370 else if(m
== 21){ /* 15 meters */
4371 dflmd
= REM_MODE_USB
;
4372 if((d
< 20001) || (d
> 44999))
4375 else if(m
== 24){ /* 12 meters */
4376 dflmd
= REM_MODE_USB
;
4377 if((d
< 93001) || (d
> 98999))
4380 else if(m
== 28){ /* 10 meters */
4381 dflmd
= REM_MODE_USB
;
4387 dflmd
= REM_MODE_FM
;
4389 dflmd
= REM_MODE_USB
;
4393 else if(m
== 50){ /* 6 meters */
4397 dflmd
= REM_MODE_FM
;
4399 dflmd
= REM_MODE_USB
;
4402 else if((m
>= 51) && ( m
< 54)){
4403 dflmd
= REM_MODE_FM
;
4405 else if(m
== 144){ /* 2 meters */
4409 dflmd
= REM_MODE_FM
;
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 */
4418 dflmd
= REM_MODE_USB
;
4420 dflmd
= REM_MODE_FM
;
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];
4445 printf("New frequency: %s\n",newfreq
);
4447 if(split_freq(mhz
, decimals
, newfreq
))
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);
4481 static int set_offset_ft897(struct rpt
*myrpt
, char offset
)
4483 unsigned char cmdstr
[5];
4485 memset(cmdstr
, 0, 5);
4506 return serial_remote_io(myrpt
, cmdstr
, 5, NULL
, 0, 0);
4511 static int set_mode_ft897(struct rpt
*myrpt
, char newmode
)
4513 unsigned char cmdstr
[5];
4515 memset(cmdstr
, 0, 5);
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 */
4557 cmdstr
[0] = 0x8A; /* OFF */
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
];
4573 memset(cmdstr
, 0, 5);
4575 if(split_ctcss_freq(hertz
, decimal
, txtone
))
4581 cmdstr
[0] = ((h
/ 100) << 4) + (h
% 100)/ 10;
4582 cmdstr
[1] = ((h
% 10) << 4) + (d
% 10);
4586 if(split_ctcss_freq(hertz
, decimal
, rxtone
))
4592 cmdstr
[2] = ((h
/ 100) << 4) + (h
% 100)/ 10;
4593 cmdstr
[3] = ((h
% 10) << 4) + (d
% 10);
4597 return serial_remote_io(myrpt
, cmdstr
, 5, NULL
, 0, 0);
4602 static int set_ft897(struct rpt
*myrpt
)
4607 printf("@@@@ lock on\n");
4609 res
= simple_command_ft897(myrpt
, 0x00); /* LOCK on */
4612 printf("@@@@ ptt off\n");
4615 res
= simple_command_ft897(myrpt
, 0x88); /* PTT off */
4618 printf("Modulation mode\n");
4621 res
= set_mode_ft897(myrpt
, myrpt
->remmode
); /* Modulation mode */
4624 printf("Split off\n");
4627 simple_command_ft897(myrpt
, 0x82); /* Split off */
4630 printf("Frequency\n");
4633 res
= set_freq_ft897(myrpt
, myrpt
->freq
); /* Frequency */
4634 if((myrpt
->remmode
== REM_MODE_FM
)){
4638 res
= set_offset_ft897(myrpt
, myrpt
->offset
); /* Offset if FM */
4639 if((!res
)&&(myrpt
->rxplon
|| myrpt
->txplon
)){
4641 printf("CTCSS tone freqs.\n");
4642 res
= set_ctcss_freq_ft897(myrpt
, myrpt
->txpl
, myrpt
->rxpl
); /* CTCSS freqs if CTCSS is enabled */
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
)){
4652 printf("Clarifier off\n");
4653 simple_command_ft897(myrpt
, 0x85); /* Clarifier off if LSB or USB */
4658 static int closerem_ft897(struct rpt
*myrpt
)
4660 simple_command_ft897(myrpt
, 0x88); /* PTT off */
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
)
4673 char mhz
[MAXREMSTR
], decimals
[MAXREMSTR
];
4676 printf("Before bump: %s\n", myrpt
->freq
);
4678 if(split_freq(mhz
, decimals
, myrpt
->freq
))
4684 d
+= (interval
/ 10); /* 10Hz resolution */
4689 else if(d
>= 100000){
4694 if(check_freq_ft897(m
, d
, NULL
)){
4696 printf("Bump freq invalid\n");
4700 snprintf(myrpt
->freq
, MAXREMSTR
, "%d.%05d", m
, d
);
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
);
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
);
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
);
4749 * Return 1 if rig is multimode capable
4752 static int multimode_capable(struct rpt
*myrpt
)
4754 if(!strcmp(myrpt
->remote
, remote_rig_ft897
))
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
);
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
)
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 */
4798 case HF_SCAN_DOWN_QUICK
:
4799 interval
= -50; /* 500Hz /sec */
4802 case HF_SCAN_DOWN_FAST
:
4803 interval
= -200; /* 2KHz /sec */
4806 case HF_SCAN_UP_SLOW
:
4807 interval
= 10; /* 100Hz /sec */
4810 case HF_SCAN_UP_QUICK
:
4811 interval
= 50; /* 500 Hz/sec */
4814 case HF_SCAN_UP_FAST
:
4815 interval
= 200; /* 2KHz /sec */
4819 myrpt
->hfscanmode
= 0; /* Huh? */
4823 res
= split_freq(mhz
, decimals
, myrpt
->freq
);
4828 res
= multimode_bump_freq(myrpt
, interval
);
4832 res
= split_freq(mhz
, decimals
, myrpt
->freq
);
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;
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)
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)
4873 if (!par
.rxisoffhook
)
4875 ast_indicate(myrpt
->remchannel
,AST_CONTROL_RADIO_UNKEY
);
4876 myrpt
->remoterx
= 0;
4880 myrpt
->remoterx
= 1;
4886 static int rmt_sayfile(struct rpt
*myrpt
, struct ast_channel
*chan
, int delay
, char *filename
)
4890 res
= rmt_telem_start(myrpt
, chan
, delay
);
4893 res
= sayfile(chan
, filename
);
4896 res
= rmt_telem_finish(myrpt
, chan
);
4900 static int rmt_saycharstr(struct rpt
*myrpt
, struct ast_channel
*chan
, int delay
, char *charstr
)
4904 res
= rmt_telem_start(myrpt
, chan
, delay
);
4907 res
= saycharstr(chan
, charstr
);
4910 res
= rmt_telem_finish(myrpt
, chan
);
4917 * Remote base function
4920 static int function_remote(struct rpt
*myrpt
, char *param
, char *digitbuf
, int command_source
, struct rpt_link
*mylink
)
4924 int i
,j
,ht
,k
,l
,ls2
,m
,d
,res
,offset
,offsave
, modesave
, defmode
;
4927 char tmp
[20], freq
[20] = "", savestr
[20] = "";
4928 char mhz
[MAXREMSTR
], decimals
[MAXREMSTR
];
4929 struct ast_channel
*mychannel
;
4931 if((!param
) || (command_source
== SOURCE_RPT
) || (command_source
== SOURCE_LNK
))
4934 multimode
= multimode_capable(myrpt
);
4936 mychannel
= myrpt
->remchannel
;
4939 switch(myatoi(param
)){
4941 case 1: /* retrieve memory */
4942 if(strlen(digitbuf
) < 2) /* needs 2 digits */
4945 for(i
= 0 ; i
< 2 ; i
++){
4946 if((digitbuf
[i
] < '0') || (digitbuf
[i
] > '9'))
4950 val
= ast_variable_retrieve(myrpt
->cfg
, myrpt
->p
.memory
, digitbuf
);
4952 if (ast_safe_sleep(mychannel
,1000) == -1)
4954 sayfile(mychannel
,"rpt/memory_notfound");
4957 ast_copy_string(tmp
, val
, sizeof(tmp
));
4958 s
= strchr(tmp
,',');
4966 ast_copy_string(myrpt
->freq
, tmp
, sizeof(myrpt
->freq
));
4967 ast_copy_string(myrpt
->rxpl
, s
, sizeof(myrpt
->rxpl
));
4968 ast_copy_string(myrpt
->txpl
, s
, sizeof(myrpt
->rxpl
));
4969 myrpt
->remmode
= REM_MODE_FM
;
4970 myrpt
->offset
= REM_SIMPLEX
;
4971 myrpt
->powerlevel
= REM_MEDPWR
;
4972 myrpt
->txplon
= myrpt
->rxplon
= 0;
4978 strcpy(myrpt
->rxpl
, "100.0");
4979 strcpy(myrpt
->txpl
, "100.0");
4980 myrpt
->remmode
= REM_MODE_AM
;
4985 strcpy(myrpt
->rxpl
, "100.0");
4986 strcpy(myrpt
->txpl
, "100.0");
4987 myrpt
->remmode
= REM_MODE_LSB
;
4991 myrpt
->remmode
= REM_MODE_FM
;
4996 myrpt
->powerlevel
= REM_LOWPWR
;
5000 myrpt
->powerlevel
= REM_HIPWR
;
5005 myrpt
->powerlevel
= REM_MEDPWR
;
5009 myrpt
->offset
= REM_MINUS
;
5013 myrpt
->offset
= REM_PLUS
;
5018 myrpt
->offset
= REM_SIMPLEX
;
5033 strcpy(myrpt
->rxpl
, "100.0");
5034 strcpy(myrpt
->txpl
, "100.0");
5035 myrpt
->remmode
= REM_MODE_USB
;
5041 if (setrem(myrpt
) == -1)
5047 case 2: /* set freq and offset */
5050 for(i
= 0, j
= 0, k
= 0, l
= 0 ; digitbuf
[i
] ; i
++){ /* look for M+*K+*O or M+*H+* depending on mode */
5051 if(digitbuf
[i
] == '*'){
5055 if((digitbuf
[i
] < '0') || (digitbuf
[i
] > '9'))
5059 l
++; /* # of digits before first * */
5061 k
++; /* # of digits after first * */
5065 i
= strlen(digitbuf
) - 1;
5067 if((j
> 2) || (l
> 3) || (k
> 6))
5068 goto invalid_freq
; /* &^@#! */
5071 if((j
> 2) || (l
> 4) || (k
> 3))
5072 goto invalid_freq
; /* &^@#! */
5075 /* Wait for M+*K+* */
5078 break; /* Not yet */
5080 /* We have a frequency */
5082 ast_copy_string(tmp
, digitbuf
,sizeof(tmp
));
5085 s1
= strsep(&s
, "*"); /* Pick off MHz */
5086 s2
= strsep(&s
,"*"); /* Pick off KHz and Hz */
5089 switch(ls2
){ /* Allow partial entry of khz and hz digits for laziness support */
5102 if((s2
[2] != '0')&&(s2
[2] != '5'))
5110 ht
= 10 * (atoi(s2
+(ls2
-1)));
5115 ht
= (atoi(s2
+(ls2
-2)));
5122 /* Check frequency for validity and establish a default mode */
5124 snprintf(freq
, sizeof(freq
), "%s.%03d%02d",s1
, k
, ht
);
5127 printf("New frequency: %s\n", freq
);
5129 split_freq(mhz
, decimals
, freq
);
5133 if(check_freq(myrpt
, m
, d
, &defmode
)) /* Check to see if frequency entered is legit */
5137 if((defmode
== REM_MODE_FM
) && (digitbuf
[i
] == '*')) /* If FM, user must enter and additional offset digit */
5138 break; /* Not yet */
5141 offset
= REM_SIMPLEX
; /* Assume simplex */
5143 if(defmode
== REM_MODE_FM
){
5144 oc
= *s
; /* Pick off offset */
5153 offset
= REM_SIMPLEX
;
5165 offsave
= myrpt
->offset
;
5166 modesave
= myrpt
->remmode
;
5167 ast_copy_string(savestr
, myrpt
->freq
, sizeof(savestr
));
5168 ast_copy_string(myrpt
->freq
, freq
, sizeof(myrpt
->freq
));
5169 myrpt
->offset
= offset
;
5170 myrpt
->remmode
= defmode
;
5172 if (setrem(myrpt
) == -1){
5173 myrpt
->offset
= offsave
;
5174 myrpt
->remmode
= modesave
;
5175 ast_copy_string(myrpt
->freq
, savestr
, sizeof(myrpt
->freq
));
5184 rmt_sayfile(myrpt
, mychannel
, 1000, "rpt/invalid-freq");
5188 case 3: /* set rx PL tone */
5190 for(i
= 0, j
= 0, k
= 0, l
= 0 ; digitbuf
[i
] ; i
++){ /* look for N+*N */
5191 if(digitbuf
[i
] == '*'){
5195 if((digitbuf
[i
] < '0') || (digitbuf
[i
] > '9'))
5204 if((j
> 1) || (k
> 3) || (l
> 1))
5205 return DC_ERROR
; /* &$@^! */
5206 i
= strlen(digitbuf
) - 1;
5207 if((j
!= 1) || (k
< 2)|| (l
!= 1))
5208 break; /* Not yet */
5210 printf("PL digits entered %s\n", digitbuf
);
5212 ast_copy_string(tmp
, digitbuf
, sizeof(tmp
));
5213 /* see if we have at least 1 */
5214 s
= strchr(tmp
,'*');
5217 ast_copy_string(savestr
, myrpt
->rxpl
, sizeof(savestr
));
5218 ast_copy_string(myrpt
->rxpl
, tmp
, sizeof(myrpt
->rxpl
));
5220 if (setrem(myrpt
) == -1){
5221 ast_copy_string(myrpt
->rxpl
, savestr
, sizeof(myrpt
->rxpl
));
5228 case 4: /* set tx PL tone */
5230 for(i
= 0, j
= 0, k
= 0, l
= 0 ; digitbuf
[i
] ; i
++){ /* look for N+*N */
5231 if(digitbuf
[i
] == '*'){
5235 if((digitbuf
[i
] < '0') || (digitbuf
[i
] > '9'))
5244 if((j
> 1) || (k
> 3) || (l
> 1))
5245 return DC_ERROR
; /* &$@^! */
5246 i
= strlen(digitbuf
) - 1;
5247 if((j
!= 1) || (k
< 2)|| (l
!= 1))
5248 break; /* Not yet */
5250 printf("PL digits entered %s\n", digitbuf
);
5252 ast_copy_string(tmp
, digitbuf
, sizeof(tmp
));
5253 /* see if we have at least 1 */
5254 s
= strchr(tmp
,'*');
5257 ast_copy_string(savestr
, myrpt
->txpl
, sizeof(savestr
));
5258 ast_copy_string(myrpt
->txpl
, tmp
, sizeof(myrpt
->txpl
));
5260 if (setrem(myrpt
) == -1){
5261 ast_copy_string(myrpt
->txpl
, savestr
, sizeof(myrpt
->txpl
) - 1);
5269 case 6: /* MODE (FM,USB,LSB,AM) */
5270 if(strlen(digitbuf
) < 1)
5274 return DC_ERROR
; /* Multimode radios only */
5278 split_freq(mhz
, decimals
, myrpt
->freq
);
5280 if(m
< 29) /* No FM allowed below 29MHz! */
5282 myrpt
->remmode
= REM_MODE_FM
;
5283 res
= rmt_saycharstr(myrpt
, mychannel
, 1000,"FM");
5287 myrpt
->remmode
= REM_MODE_USB
;
5288 res
= rmt_saycharstr(myrpt
, mychannel
, 1000,"USB");
5292 myrpt
->remmode
= REM_MODE_LSB
;
5293 res
= rmt_saycharstr(myrpt
, mychannel
, 1000,"LSB");
5297 myrpt
->remmode
= REM_MODE_AM
;
5298 res
= rmt_saycharstr(myrpt
, mychannel
, 1000,"AM");
5311 case 100: /* other stuff */
5318 res
= rmt_telem_start(myrpt
, mychannel
, 1000);
5319 switch(myatoi(param
)){ /* Quick commands requiring a setrem call */
5320 case 100: /* RX PL Off */
5323 res
= sayfile(mychannel
, "rpt/rxpl");
5325 sayfile(mychannel
, "rpt/off");
5328 case 101: /* RX PL On */
5331 res
= sayfile(mychannel
, "rpt/rxpl");
5333 sayfile(mychannel
, "rpt/on");
5337 case 102: /* TX PL Off */
5340 res
= sayfile(mychannel
, "rpt/txpl");
5342 sayfile(mychannel
, "rpt/off");
5345 case 103: /* TX PL On */
5348 res
= sayfile(mychannel
, "rpt/txpl");
5350 sayfile(mychannel
, "rpt/on");
5353 case 104: /* Low Power */
5354 myrpt
->powerlevel
= REM_LOWPWR
;
5356 res
= sayfile(mychannel
, "rpt/lopwr");
5359 case 105: /* Medium Power */
5360 myrpt
->powerlevel
= REM_MEDPWR
;
5362 res
= sayfile(mychannel
, "rpt/medpwr");
5365 case 106: /* Hi Power */
5366 myrpt
->powerlevel
= REM_HIPWR
;
5368 res
= sayfile(mychannel
, "rpt/hipwr");
5373 rmt_telem_finish(myrpt
, mychannel
);
5377 res
= rmt_telem_finish(myrpt
, mychannel
);
5381 if (setrem(myrpt
) == -1)
5385 case 107: /* Bump down 20Hz */
5386 multimode_bump_freq(myrpt
, -20);
5389 case 108: /* Bump down 100Hz */
5390 multimode_bump_freq(myrpt
, -100);
5393 case 109: /* Bump down 500Hz */
5394 multimode_bump_freq(myrpt
, -500);
5397 case 110: /* Bump up 20Hz */
5398 multimode_bump_freq(myrpt
, 20);
5401 case 111: /* Bump up 100Hz */
5402 multimode_bump_freq(myrpt
, 100);
5405 case 112: /* Bump up 500Hz */
5406 multimode_bump_freq(myrpt
, 500);
5416 myrpt
->remotetx
= 0;
5417 ast_indicate(myrpt
->txchannel
,AST_CONTROL_RADIO_UNKEY
);
5418 if (!myrpt
->remoterx
)
5419 ast_indicate(mychannel
,AST_CONTROL_RADIO_KEY
);
5420 if (ast_safe_sleep(mychannel
,1000) == -1)
5423 switch(myatoi(param
)){
5425 case 113: /* Scan down slow */
5426 res
= sayfile(mychannel
,"rpt/down");
5428 res
= sayfile(mychannel
, "rpt/slow");
5430 myrpt
->scantimer
= REM_SCANTIME
;
5431 myrpt
->hfscanmode
= HF_SCAN_DOWN_SLOW
;
5435 case 114: /* Scan down quick */
5436 res
= sayfile(mychannel
,"rpt/down");
5438 res
= sayfile(mychannel
, "rpt/quick");
5440 myrpt
->scantimer
= REM_SCANTIME
;
5441 myrpt
->hfscanmode
= HF_SCAN_DOWN_QUICK
;
5445 case 115: /* Scan down fast */
5446 res
= sayfile(mychannel
,"rpt/down");
5448 res
= sayfile(mychannel
, "rpt/fast");
5450 myrpt
->scantimer
= REM_SCANTIME
;
5451 myrpt
->hfscanmode
= HF_SCAN_DOWN_FAST
;
5455 case 116: /* Scan up slow */
5456 res
= sayfile(mychannel
,"rpt/up");
5458 res
= sayfile(mychannel
, "rpt/slow");
5460 myrpt
->scantimer
= REM_SCANTIME
;
5461 myrpt
->hfscanmode
= HF_SCAN_UP_SLOW
;
5465 case 117: /* Scan up quick */
5466 res
= sayfile(mychannel
,"rpt/up");
5468 res
= sayfile(mychannel
, "rpt/quick");
5470 myrpt
->scantimer
= REM_SCANTIME
;
5471 myrpt
->hfscanmode
= HF_SCAN_UP_QUICK
;
5475 case 118: /* Scan up fast */
5476 res
= sayfile(mychannel
,"rpt/up");
5478 res
= sayfile(mychannel
, "rpt/fast");
5480 myrpt
->scantimer
= REM_SCANTIME
;
5481 myrpt
->hfscanmode
= HF_SCAN_UP_FAST
;
5485 rmt_telem_finish(myrpt
,mychannel
);
5489 case 119: /* Tune Request */
5490 myrpt
->tunerequest
= 1;
5493 case 5: /* Long Status */
5494 case 140: /* Short Status */
5495 res
= rmt_telem_start(myrpt
, mychannel
, 1000);
5497 res
= sayfile(mychannel
,"rpt/node");
5499 res
= saycharstr(mychannel
, myrpt
->name
);
5501 res
= sayfile(mychannel
,"rpt/frequency");
5503 res
= split_freq(mhz
, decimals
, myrpt
->freq
);
5507 res
= saynum(mychannel
, m
);
5509 res
= saycharstr(mychannel
, mhz
);
5512 res
= sayfile(mychannel
, "letters/dot");
5514 res
= saycharstr(mychannel
, decimals
);
5517 rmt_telem_finish(myrpt
,mychannel
);
5520 if(myrpt
->remmode
== REM_MODE_FM
){ /* Mode FM? */
5521 switch(myrpt
->offset
){
5524 res
= sayfile(mychannel
,"rpt/minus");
5528 res
= sayfile(mychannel
,"rpt/simplex");
5532 res
= sayfile(mychannel
,"rpt/plus");
5540 else{ /* Must be USB, LSB, or AM */
5541 switch(myrpt
->remmode
){
5544 res
= saycharstr(mychannel
, "USB");
5548 res
= saycharstr(mychannel
, "LSB");
5552 res
= saycharstr(mychannel
, "AM");
5562 rmt_telem_finish(myrpt
,mychannel
);
5566 if(myatoi(param
) == 140){ /* Short status? */
5568 res
= rmt_telem_finish(myrpt
, mychannel
);
5574 switch(myrpt
->powerlevel
){
5577 res
= sayfile(mychannel
,"rpt/lopwr") ;
5581 res
= sayfile(mychannel
,"rpt/medpwr");
5584 res
= sayfile(mychannel
,"rpt/hipwr");
5587 if (res
|| (sayfile(mychannel
,"rpt/rxpl") == -1) ||
5588 (sayfile(mychannel
,"rpt/frequency") == -1) ||
5589 (saycharstr(mychannel
,myrpt
->rxpl
) == -1) ||
5590 (sayfile(mychannel
,"rpt/txpl") == -1) ||
5591 (sayfile(mychannel
,"rpt/frequency") == -1) ||
5592 (saycharstr(mychannel
,myrpt
->txpl
) == -1) ||
5593 (sayfile(mychannel
,"rpt/txpl") == -1) ||
5594 (sayfile(mychannel
,((myrpt
->txplon
) ? "rpt/on" : "rpt/off")) == -1) ||
5595 (sayfile(mychannel
,"rpt/rxpl") == -1) ||
5596 (sayfile(mychannel
,((myrpt
->rxplon
) ? "rpt/on" : "rpt/off")) == -1))
5598 rmt_telem_finish(myrpt
,mychannel
);
5602 res
= rmt_telem_finish(myrpt
,mychannel
);
5611 return DC_INDETERMINATE
;
5614 static int handle_remote_dtmf_digit(struct rpt
*myrpt
,char c
, char *keyed
, int phonemode
)
5617 int ret
,res
= 0,src
;
5619 /* Stop scan mode if in scan mode */
5620 if(myrpt
->hfscanmode
){
5627 if ((myrpt
->dtmf_time_rem
+ DTMF_TIMEOUT
) < now
)
5629 myrpt
->dtmfidx
= -1;
5630 myrpt
->dtmfbuf
[0] = 0;
5631 myrpt
->dtmf_time_rem
= 0;
5633 /* if decode not active */
5634 if (myrpt
->dtmfidx
== -1)
5636 /* if not lead-in digit, dont worry */
5637 if (c
!= myrpt
->p
.funcchar
) return 0;
5639 myrpt
->dtmfbuf
[0] = 0;
5640 myrpt
->dtmf_time_rem
= now
;
5643 /* if too many in buffer, start over */
5644 if (myrpt
->dtmfidx
>= MAXDTMF
)
5647 myrpt
->dtmfbuf
[0] = 0;
5648 myrpt
->dtmf_time_rem
= now
;
5650 if (c
== myrpt
->p
.funcchar
)
5652 /* if star at beginning, or 2 together, erase buffer */
5653 if ((myrpt
->dtmfidx
< 1) ||
5654 (myrpt
->dtmfbuf
[myrpt
->dtmfidx
- 1] == myrpt
->p
.funcchar
))
5657 myrpt
->dtmfbuf
[0] = 0;
5658 myrpt
->dtmf_time_rem
= now
;
5662 myrpt
->dtmfbuf
[myrpt
->dtmfidx
++] = c
;
5663 myrpt
->dtmfbuf
[myrpt
->dtmfidx
] = 0;
5664 myrpt
->dtmf_time_rem
= now
;
5668 if (phonemode
> 1) src
= SOURCE_DPHONE
;
5669 else if (phonemode
) src
= SOURCE_PHONE
;
5670 ret
= collect_function_digits(myrpt
, myrpt
->dtmfbuf
, src
, NULL
);
5674 case DC_INDETERMINATE
:
5679 if (keyed
) *keyed
= 1;
5685 myrpt
->dtmfbuf
[0] = 0;
5691 myrpt
->totalexecdcommands
++;
5692 myrpt
->dailyexecdcommands
++;
5693 ast_copy_string(myrpt
->lastdtmfcommand
, myrpt
->dtmfbuf
, MAXDTMF
);
5694 myrpt
->dtmfbuf
[0] = 0;
5695 myrpt
->dtmfidx
= -1;
5696 myrpt
->dtmf_time_rem
= 0;
5702 myrpt
->dtmfbuf
[0] = 0;
5703 myrpt
->dtmfidx
= -1;
5704 myrpt
->dtmf_time_rem
= 0;
5712 static int handle_remote_data(struct rpt
*myrpt
, char *str
)
5714 char tmp
[300],cmd
[300],dest
[300],src
[300],c
;
5717 /* put string in our buffer */
5718 ast_copy_string(tmp
,str
,sizeof(tmp
));
5719 if (!strcmp(tmp
,discstr
)) return 0;
5720 if (sscanf(tmp
,"%s %s %s %d %c",cmd
,dest
,src
,&seq
,&c
) != 5)
5722 ast_log(LOG_WARNING
, "Unable to parse link string %s\n",str
);
5725 if (strcmp(cmd
,"D"))
5727 ast_log(LOG_WARNING
, "Unable to parse link string %s\n",str
);
5730 /* if not for me, ignore */
5731 if (strcmp(dest
,myrpt
->name
)) return 0;
5732 res
= handle_remote_dtmf_digit(myrpt
,c
, NULL
, 0);
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
);
5747 static int handle_remote_phone_dtmf(struct rpt
*myrpt
, char c
, char *keyed
, int phonemode
)
5752 if (keyed
&& *keyed
&& (c
== myrpt
->p
.endchar
))
5755 return DC_INDETERMINATE
;
5758 res
= handle_remote_dtmf_digit(myrpt
,c
,keyed
, phonemode
);
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
);
5773 static int attempt_reconnect(struct rpt
*myrpt
, struct rpt_link
*l
)
5776 char *s
, *s1
, *s2
, *tele
;
5777 char tmp
[300], deststr
[300] = "";
5779 val
= ast_variable_retrieve(myrpt
->cfg
, myrpt
->p
.nodes
, l
->name
);
5782 fprintf(stderr
,"attempt_reconnect: cannot find node %s\n",l
->name
);
5786 rpt_mutex_lock(&myrpt
->lock
);
5787 /* remove from queue */
5788 remque((struct qelem
*) l
);
5789 rpt_mutex_unlock(&myrpt
->lock
);
5790 ast_copy_string(tmp
,val
,sizeof(tmp
));
5792 s1
= strsep(&s
,",");
5793 s2
= strsep(&s
,",");
5794 snprintf(deststr
, sizeof(deststr
), "IAX2/%s", s1
);
5795 tele
= strchr(deststr
, '/');
5797 fprintf(stderr
,"attempt_reconnect:Dial number (%s) must be in format tech/number\n",deststr
);
5803 l
->chan
= ast_request(deststr
, AST_FORMAT_SLINEAR
, tele
,NULL
);
5805 ast_set_read_format(l
->chan
, AST_FORMAT_SLINEAR
);
5806 ast_set_write_format(l
->chan
, AST_FORMAT_SLINEAR
);
5807 l
->chan
->whentohangup
= 0;
5808 l
->chan
->appl
= "Apprpt";
5809 l
->chan
->data
= "(Remote Rx)";
5810 if (option_verbose
> 2)
5811 ast_verbose(VERBOSE_PREFIX_3
"rpt (attempt_reconnect) initiating call to %s/%s on %s\n",
5812 deststr
, tele
, l
->chan
->name
);
5813 if(l
->chan
->cid
.cid_num
)
5814 free(l
->chan
->cid
.cid_num
);
5815 l
->chan
->cid
.cid_num
= strdup(myrpt
->name
);
5816 ast_call(l
->chan
,tele
,999);
5821 if (option_verbose
> 2)
5822 ast_verbose(VERBOSE_PREFIX_3
"Unable to place call to %s/%s on %s\n",
5823 deststr
,tele
,l
->chan
->name
);
5826 rpt_mutex_lock(&myrpt
->lock
);
5827 /* put back in queue */
5828 insque((struct qelem
*)l
,(struct qelem
*)myrpt
->links
.next
);
5829 rpt_mutex_unlock(&myrpt
->lock
);
5830 ast_log(LOG_NOTICE
,"Reconnect Attempt to %s in process\n",l
->name
);
5834 /* 0 return=continue, 1 return = break, -1 return = error */
5835 static void local_dtmf_helper(struct rpt
*myrpt
,char c
)
5838 pthread_attr_t attr
;
5839 char cmd
[MAXDTMF
+1] = "";
5841 if (c
== myrpt
->p
.endchar
)
5843 /* if in simple mode, kill autopatch */
5844 if (myrpt
->p
.simple
&& myrpt
->callmode
)
5846 rpt_mutex_lock(&myrpt
->lock
);
5847 myrpt
->callmode
= 0;
5848 rpt_mutex_unlock(&myrpt
->lock
);
5849 rpt_telemetry(myrpt
,TERM
,NULL
);
5852 rpt_mutex_lock(&myrpt
->lock
);
5854 if (myrpt
->cmdnode
[0])
5856 myrpt
->cmdnode
[0] = 0;
5857 myrpt
->dtmfidx
= -1;
5858 myrpt
->dtmfbuf
[0] = 0;
5859 rpt_mutex_unlock(&myrpt
->lock
);
5860 rpt_telemetry(myrpt
,COMPLETE
,NULL
);
5861 } else rpt_mutex_unlock(&myrpt
->lock
);
5864 rpt_mutex_lock(&myrpt
->lock
);
5865 if (myrpt
->cmdnode
[0])
5867 rpt_mutex_unlock(&myrpt
->lock
);
5868 send_link_dtmf(myrpt
,c
);
5871 if (!myrpt
->p
.simple
)
5873 if (c
== myrpt
->p
.funcchar
)
5876 myrpt
->dtmfbuf
[myrpt
->dtmfidx
] = 0;
5877 rpt_mutex_unlock(&myrpt
->lock
);
5878 time(&myrpt
->dtmf_time
);
5881 else if ((c
!= myrpt
->p
.endchar
) && (myrpt
->dtmfidx
>= 0))
5883 time(&myrpt
->dtmf_time
);
5885 if (myrpt
->dtmfidx
< MAXDTMF
)
5887 myrpt
->dtmfbuf
[myrpt
->dtmfidx
++] = c
;
5888 myrpt
->dtmfbuf
[myrpt
->dtmfidx
] = 0;
5890 ast_copy_string(cmd
, myrpt
->dtmfbuf
, sizeof(cmd
));
5892 rpt_mutex_unlock(&myrpt
->lock
);
5893 res
= collect_function_digits(myrpt
, cmd
, SOURCE_RPT
, NULL
);
5894 rpt_mutex_lock(&myrpt
->lock
);
5896 case DC_INDETERMINATE
:
5900 myrpt
->dtmfbuf
[0] = 0;
5903 myrpt
->totalexecdcommands
++;
5904 myrpt
->dailyexecdcommands
++;
5905 ast_copy_string(myrpt
->lastdtmfcommand
, cmd
, MAXDTMF
);
5906 myrpt
->dtmfbuf
[0] = 0;
5907 myrpt
->dtmfidx
= -1;
5908 myrpt
->dtmf_time
= 0;
5913 myrpt
->dtmfbuf
[0] = 0;
5914 myrpt
->dtmfidx
= -1;
5915 myrpt
->dtmf_time
= 0;
5918 if(res
!= DC_INDETERMINATE
) {
5919 rpt_mutex_unlock(&myrpt
->lock
);
5925 else /* if simple */
5927 if ((!myrpt
->callmode
) && (c
== myrpt
->p
.funcchar
))
5929 myrpt
->callmode
= 1;
5930 myrpt
->patchnoct
= 0;
5931 myrpt
->patchquiet
= 0;
5932 myrpt
->patchfarenddisconnect
= 0;
5933 myrpt
->patchdialtime
= 0;
5934 ast_copy_string(myrpt
->patchcontext
, myrpt
->p
.ourcontext
, MAXPATCHCONTEXT
);
5936 myrpt
->exten
[myrpt
->cidx
] = 0;
5937 rpt_mutex_unlock(&myrpt
->lock
);
5938 pthread_attr_init(&attr
);
5939 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
5940 ast_pthread_create(&myrpt
->rpt_call_thread
,&attr
,rpt_call
,(void *)myrpt
);
5941 pthread_attr_destroy(&attr
);
5945 if (myrpt
->callmode
== 1)
5947 myrpt
->exten
[myrpt
->cidx
++] = c
;
5948 myrpt
->exten
[myrpt
->cidx
] = 0;
5949 /* if this exists */
5950 if (ast_exists_extension(myrpt
->pchannel
,myrpt
->patchcontext
,myrpt
->exten
,1,NULL
))
5952 myrpt
->callmode
= 2;
5953 rpt_mutex_unlock(&myrpt
->lock
);
5954 if(!myrpt
->patchquiet
)
5955 rpt_telemetry(myrpt
,PROC
,NULL
);
5958 /* if can continue, do so */
5959 if (!ast_canmatch_extension(myrpt
->pchannel
,myrpt
->patchcontext
,myrpt
->exten
,1,NULL
))
5961 /* call has failed, inform user */
5962 myrpt
->callmode
= 4;
5964 rpt_mutex_unlock(&myrpt
->lock
);
5967 if ((myrpt
->callmode
== 2) || (myrpt
->callmode
== 3))
5971 rpt_mutex_unlock(&myrpt
->lock
);
5976 /* place an ID event in the telemetry queue */
5978 static void queue_id(struct rpt
*myrpt
)
5980 myrpt
->mustid
= myrpt
->tailid
= 0;
5981 myrpt
->idtimer
= myrpt
->p
.idtime
; /* Reset our ID timer */
5982 rpt_mutex_unlock(&myrpt
->lock
);
5983 rpt_telemetry(myrpt
,ID
,NULL
);
5984 rpt_mutex_lock(&myrpt
->lock
);
5989 static void do_scheduler(struct rpt
*myrpt
)
5994 memcpy(&myrpt
->lasttv
, &myrpt
->curtv
, sizeof(struct timeval
));
5996 if( (res
= gettimeofday(&myrpt
->curtv
, NULL
)) < 0)
5997 ast_log(LOG_NOTICE
, "Scheduler gettime of day returned: %s\n", strerror(res
));
5999 /* Try to get close to a 1 second resolution */
6001 if(myrpt
->lasttv
.tv_sec
== myrpt
->curtv
.tv_sec
)
6004 ast_localtime(&myrpt
->curtv
.tv_sec
, &tmnow
, NULL
);
6006 /* If midnight, then reset all daily statistics */
6008 if((tmnow
.tm_hour
== 0)&&(tmnow
.tm_min
== 0)&&(tmnow
.tm_sec
== 0)){
6009 myrpt
->dailykeyups
= 0;
6010 myrpt
->dailytxtime
= 0;
6011 myrpt
->dailykerchunks
= 0;
6012 myrpt
->dailyexecdcommands
= 0;
6017 /* single thread with one file (request) to dial */
6018 static void *rpt(void *this)
6020 struct rpt
*myrpt
= (struct rpt
*)this;
6022 const char *idtalkover
;
6023 int ms
= MSWAIT
,i
,lasttx
=0,val
,remrx
=0,identqueued
,othertelemqueued
,tailmessagequeued
,ctqueued
;
6024 struct ast_channel
*who
;
6025 ZT_CONFINFO ci
; /* conference info */
6027 struct rpt_link
*l
,*m
;
6028 struct rpt_tele
*telem
;
6031 rpt_mutex_lock(&myrpt
->lock
);
6033 telem
= myrpt
->tele
.next
;
6034 while(telem
!= &myrpt
->tele
)
6036 ast_softhangup(telem
->chan
,AST_SOFTHANGUP_DEV
);
6037 telem
= telem
->next
;
6039 rpt_mutex_unlock(&myrpt
->lock
);
6040 /* find our index, and load the vars initially */
6041 for(i
= 0; i
< nrpts
; i
++)
6043 if (&rpt_vars
[i
] == myrpt
)
6049 rpt_mutex_lock(&myrpt
->lock
);
6050 ast_copy_string(tmpstr
,myrpt
->rxchanname
,sizeof(tmpstr
));
6051 tele
= strchr(tmpstr
,'/');
6054 fprintf(stderr
,"rpt:Rxchannel Dial number (%s) must be in format tech/number\n",myrpt
->rxchanname
);
6055 rpt_mutex_unlock(&myrpt
->lock
);
6056 myrpt
->rpt_thread
= AST_PTHREADT_STOP
;
6060 myrpt
->rxchannel
= ast_request(tmpstr
,AST_FORMAT_SLINEAR
,tele
,NULL
);
6061 if (myrpt
->rxchannel
)
6063 if (myrpt
->rxchannel
->_state
== AST_STATE_BUSY
)
6065 fprintf(stderr
,"rpt:Sorry unable to obtain Rx channel\n");
6066 rpt_mutex_unlock(&myrpt
->lock
);
6067 ast_hangup(myrpt
->rxchannel
);
6068 myrpt
->rpt_thread
= AST_PTHREADT_STOP
;
6071 ast_set_read_format(myrpt
->rxchannel
,AST_FORMAT_SLINEAR
);
6072 ast_set_write_format(myrpt
->rxchannel
,AST_FORMAT_SLINEAR
);
6073 myrpt
->rxchannel
->whentohangup
= 0;
6074 myrpt
->rxchannel
->appl
= "Apprpt";
6075 myrpt
->rxchannel
->data
= "(Repeater Rx)";
6076 if (option_verbose
> 2)
6077 ast_verbose(VERBOSE_PREFIX_3
"rpt (Rx) initiating call to %s/%s on %s\n",
6078 tmpstr
,tele
,myrpt
->rxchannel
->name
);
6079 ast_call(myrpt
->rxchannel
,tele
,999);
6080 if (myrpt
->rxchannel
->_state
!= AST_STATE_UP
)
6082 rpt_mutex_unlock(&myrpt
->lock
);
6083 ast_hangup(myrpt
->rxchannel
);
6084 myrpt
->rpt_thread
= AST_PTHREADT_STOP
;
6090 fprintf(stderr
,"rpt:Sorry unable to obtain Rx channel\n");
6091 rpt_mutex_unlock(&myrpt
->lock
);
6092 myrpt
->rpt_thread
= AST_PTHREADT_STOP
;
6095 if (myrpt
->txchanname
)
6097 ast_copy_string(tmpstr
,myrpt
->txchanname
,sizeof(tmpstr
));
6098 tele
= strchr(tmpstr
,'/');
6101 fprintf(stderr
,"rpt:Txchannel Dial number (%s) must be in format tech/number\n",myrpt
->txchanname
);
6102 rpt_mutex_unlock(&myrpt
->lock
);
6103 ast_hangup(myrpt
->rxchannel
);
6104 myrpt
->rpt_thread
= AST_PTHREADT_STOP
;
6108 myrpt
->txchannel
= ast_request(tmpstr
,AST_FORMAT_SLINEAR
,tele
,NULL
);
6109 if (myrpt
->txchannel
)
6111 if (myrpt
->txchannel
->_state
== AST_STATE_BUSY
)
6113 fprintf(stderr
,"rpt:Sorry unable to obtain Tx channel\n");
6114 rpt_mutex_unlock(&myrpt
->lock
);
6115 ast_hangup(myrpt
->txchannel
);
6116 ast_hangup(myrpt
->rxchannel
);
6117 myrpt
->rpt_thread
= AST_PTHREADT_STOP
;
6120 ast_set_read_format(myrpt
->txchannel
,AST_FORMAT_SLINEAR
);
6121 ast_set_write_format(myrpt
->txchannel
,AST_FORMAT_SLINEAR
);
6122 myrpt
->txchannel
->whentohangup
= 0;
6123 myrpt
->txchannel
->appl
= "Apprpt";
6124 myrpt
->txchannel
->data
= "(Repeater Tx)";
6125 if (option_verbose
> 2)
6126 ast_verbose(VERBOSE_PREFIX_3
"rpt (Tx) initiating call to %s/%s on %s\n",
6127 tmpstr
,tele
,myrpt
->txchannel
->name
);
6128 ast_call(myrpt
->txchannel
,tele
,999);
6129 if (myrpt
->rxchannel
->_state
!= AST_STATE_UP
)
6131 rpt_mutex_unlock(&myrpt
->lock
);
6132 ast_hangup(myrpt
->rxchannel
);
6133 ast_hangup(myrpt
->txchannel
);
6134 myrpt
->rpt_thread
= AST_PTHREADT_STOP
;
6140 fprintf(stderr
,"rpt:Sorry unable to obtain Tx channel\n");
6141 rpt_mutex_unlock(&myrpt
->lock
);
6142 ast_hangup(myrpt
->rxchannel
);
6143 myrpt
->rpt_thread
= AST_PTHREADT_STOP
;
6149 myrpt
->txchannel
= myrpt
->rxchannel
;
6151 ast_indicate(myrpt
->txchannel
,AST_CONTROL_RADIO_KEY
);
6152 ast_indicate(myrpt
->txchannel
,AST_CONTROL_RADIO_UNKEY
);
6153 /* allocate a pseudo-channel thru asterisk */
6154 myrpt
->pchannel
= ast_request("zap",AST_FORMAT_SLINEAR
,"pseudo",NULL
);
6155 if (!myrpt
->pchannel
)
6157 fprintf(stderr
,"rpt:Sorry unable to obtain pseudo channel\n");
6158 rpt_mutex_unlock(&myrpt
->lock
);
6159 if (myrpt
->txchannel
!= myrpt
->rxchannel
)
6160 ast_hangup(myrpt
->txchannel
);
6161 ast_hangup(myrpt
->rxchannel
);
6162 myrpt
->rpt_thread
= AST_PTHREADT_STOP
;
6165 /* make a conference for the tx */
6167 ci
.confno
= -1; /* make a new conf */
6168 ci
.confmode
= ZT_CONF_CONF
| ZT_CONF_LISTENER
;
6169 /* first put the channel on the conference in proper mode */
6170 if (ioctl(myrpt
->txchannel
->fds
[0],ZT_SETCONF
,&ci
) == -1)
6172 ast_log(LOG_WARNING
, "Unable to set conference mode to Announce\n");
6173 rpt_mutex_unlock(&myrpt
->lock
);
6174 ast_hangup(myrpt
->pchannel
);
6175 if (myrpt
->txchannel
!= myrpt
->rxchannel
)
6176 ast_hangup(myrpt
->txchannel
);
6177 ast_hangup(myrpt
->rxchannel
);
6178 myrpt
->rpt_thread
= AST_PTHREADT_STOP
;
6181 /* save tx conference number */
6182 myrpt
->txconf
= ci
.confno
;
6183 /* make a conference for the pseudo */
6185 ci
.confno
= -1; /* make a new conf */
6186 ci
.confmode
= ((myrpt
->p
.duplex
== 2) || (myrpt
->p
.duplex
== 4)) ? ZT_CONF_CONFANNMON
:
6187 (ZT_CONF_CONF
| ZT_CONF_LISTENER
| ZT_CONF_TALKER
);
6188 /* first put the channel on the conference in announce mode */
6189 if (ioctl(myrpt
->pchannel
->fds
[0],ZT_SETCONF
,&ci
) == -1)
6191 ast_log(LOG_WARNING
, "Unable to set conference mode to Announce\n");
6192 rpt_mutex_unlock(&myrpt
->lock
);
6193 ast_hangup(myrpt
->pchannel
);
6194 if (myrpt
->txchannel
!= myrpt
->rxchannel
)
6195 ast_hangup(myrpt
->txchannel
);
6196 ast_hangup(myrpt
->rxchannel
);
6197 myrpt
->rpt_thread
= AST_PTHREADT_STOP
;
6200 /* save pseudo channel conference number */
6201 myrpt
->conf
= ci
.confno
;
6202 /* allocate a pseudo-channel thru asterisk */
6203 myrpt
->txpchannel
= ast_request("zap",AST_FORMAT_SLINEAR
,"pseudo",NULL
);
6204 if (!myrpt
->txpchannel
)
6206 fprintf(stderr
,"rpt:Sorry unable to obtain pseudo channel\n");
6207 rpt_mutex_unlock(&myrpt
->lock
);
6208 ast_hangup(myrpt
->pchannel
);
6209 if (myrpt
->txchannel
!= myrpt
->rxchannel
)
6210 ast_hangup(myrpt
->txchannel
);
6211 ast_hangup(myrpt
->rxchannel
);
6212 myrpt
->rpt_thread
= AST_PTHREADT_STOP
;
6215 /* make a conference for the tx */
6217 ci
.confno
= myrpt
->txconf
;
6218 ci
.confmode
= ZT_CONF_CONF
| ZT_CONF_TALKER
;
6219 /* first put the channel on the conference in proper mode */
6220 if (ioctl(myrpt
->txpchannel
->fds
[0],ZT_SETCONF
,&ci
) == -1)
6222 ast_log(LOG_WARNING
, "Unable to set conference mode to Announce\n");
6223 rpt_mutex_unlock(&myrpt
->lock
);
6224 ast_hangup(myrpt
->txpchannel
);
6225 ast_hangup(myrpt
->pchannel
);
6226 if (myrpt
->txchannel
!= myrpt
->rxchannel
)
6227 ast_hangup(myrpt
->txchannel
);
6228 ast_hangup(myrpt
->rxchannel
);
6229 myrpt
->rpt_thread
= AST_PTHREADT_STOP
;
6232 /* Now, the idea here is to copy from the physical rx channel buffer
6233 into the pseudo tx buffer, and from the pseudo rx buffer into the
6234 tx channel buffer */
6235 myrpt
->links
.next
= &myrpt
->links
;
6236 myrpt
->links
.prev
= &myrpt
->links
;
6237 myrpt
->tailtimer
= 0;
6239 myrpt
->tmsgtimer
= myrpt
->p
.tailmessagetime
;
6240 myrpt
->idtimer
= myrpt
->p
.politeid
;
6241 myrpt
->mustid
= myrpt
->tailid
= 0;
6242 myrpt
->callmode
= 0;
6243 myrpt
->tounkeyed
= 0;
6244 myrpt
->tonotify
= 0;
6245 myrpt
->retxtimer
= 0;
6246 myrpt
->skedtimer
= 0;
6247 myrpt
->tailevent
= 0;
6250 idtalkover
= ast_variable_retrieve(myrpt
->cfg
, myrpt
->name
, "idtalkover");
6251 myrpt
->dtmfidx
= -1;
6252 myrpt
->dtmfbuf
[0] = 0;
6253 myrpt
->rem_dtmfidx
= -1;
6254 myrpt
->rem_dtmfbuf
[0] = 0;
6255 myrpt
->dtmf_time
= 0;
6256 myrpt
->rem_dtmf_time
= 0;
6258 myrpt
->disgorgetime
= 0;
6259 myrpt
->lastnodewhichkeyedusup
[0] = '\0';
6260 myrpt
->dailytxtime
= 0;
6261 myrpt
->totaltxtime
= 0;
6262 myrpt
->dailykeyups
= 0;
6263 myrpt
->totalkeyups
= 0;
6264 myrpt
->dailykerchunks
= 0;
6265 myrpt
->totalkerchunks
= 0;
6266 myrpt
->dailyexecdcommands
= 0;
6267 myrpt
->totalexecdcommands
= 0;
6268 myrpt
->timeouts
= 0;
6269 myrpt
->exten
[0] = '\0';
6270 myrpt
->lastdtmfcommand
[0] = '\0';
6271 if (myrpt
->p
.startupmacro
)
6273 snprintf(myrpt
->macrobuf
,MAXMACRO
- 1,"PPPP%s",myrpt
->p
.startupmacro
);
6275 rpt_mutex_unlock(&myrpt
->lock
);
6277 ast_channel_setoption(myrpt
->rxchannel
,AST_OPTION_TONE_VERIFY
,&val
,sizeof(char),0);
6279 ast_channel_setoption(myrpt
->rxchannel
,AST_OPTION_RELAXDTMF
,&val
,sizeof(char),0);
6282 struct ast_frame
*f
;
6283 struct ast_channel
*cs
[300];
6284 int totx
=0,elap
=0,n
,toexit
=0;
6287 if((myrpt
->disgorgetime
) && (time(NULL
) >= myrpt
->disgorgetime
)){
6288 struct rpt_link
*zl
;
6289 struct rpt_tele
*zt
;
6291 myrpt
->disgorgetime
= 0;
6292 ast_log(LOG_NOTICE
,"********** Variable Dump Start (app_rpt) **********\n");
6293 ast_log(LOG_NOTICE
,"totx = %d\n",totx
);
6294 ast_log(LOG_NOTICE
,"remrx = %d\n",remrx
);
6295 ast_log(LOG_NOTICE
,"lasttx = %d\n",lasttx
);
6296 ast_log(LOG_NOTICE
,"elap = %d\n",elap
);
6297 ast_log(LOG_NOTICE
,"toexit = %d\n",toexit
);
6299 ast_log(LOG_NOTICE
,"myrpt->keyed = %d\n",myrpt
->keyed
);
6300 ast_log(LOG_NOTICE
,"myrpt->localtx = %d\n",myrpt
->localtx
);
6301 ast_log(LOG_NOTICE
,"myrpt->callmode = %d\n",myrpt
->callmode
);
6302 ast_log(LOG_NOTICE
,"myrpt->enable = %d\n",myrpt
->enable
);
6303 ast_log(LOG_NOTICE
,"myrpt->mustid = %d\n",myrpt
->mustid
);
6304 ast_log(LOG_NOTICE
,"myrpt->tounkeyed = %d\n",myrpt
->tounkeyed
);
6305 ast_log(LOG_NOTICE
,"myrpt->tonotify = %d\n",myrpt
->tonotify
);
6306 ast_log(LOG_NOTICE
,"myrpt->retxtimer = %ld\n",myrpt
->retxtimer
);
6307 ast_log(LOG_NOTICE
,"myrpt->totimer = %d\n",myrpt
->totimer
);
6308 ast_log(LOG_NOTICE
,"myrpt->tailtimer = %d\n",myrpt
->tailtimer
);
6309 ast_log(LOG_NOTICE
,"myrpt->tailevent = %d\n",myrpt
->tailevent
);
6311 zl
= myrpt
->links
.next
;
6312 while(zl
!= &myrpt
->links
){
6313 ast_log(LOG_NOTICE
,"*** Link Name: %s ***\n",zl
->name
);
6314 ast_log(LOG_NOTICE
," link->lasttx %d\n",zl
->lasttx
);
6315 ast_log(LOG_NOTICE
," link->lastrx %d\n",zl
->lastrx
);
6316 ast_log(LOG_NOTICE
," link->connected %d\n",zl
->connected
);
6317 ast_log(LOG_NOTICE
," link->hasconnected %d\n",zl
->hasconnected
);
6318 ast_log(LOG_NOTICE
," link->outbound %d\n",zl
->outbound
);
6319 ast_log(LOG_NOTICE
," link->disced %d\n",zl
->disced
);
6320 ast_log(LOG_NOTICE
," link->killme %d\n",zl
->killme
);
6321 ast_log(LOG_NOTICE
," link->disctime %ld\n",zl
->disctime
);
6322 ast_log(LOG_NOTICE
," link->retrytimer %ld\n",zl
->retrytimer
);
6323 ast_log(LOG_NOTICE
," link->retries = %d\n",zl
->retries
);
6324 ast_log(LOG_NOTICE
," link->reconnects = %d\n",zl
->reconnects
);
6328 zt
= myrpt
->tele
.next
;
6329 if(zt
!= &myrpt
->tele
)
6330 ast_log(LOG_NOTICE
,"*** Telemetry Queue ***\n");
6331 while(zt
!= &myrpt
->tele
){
6332 ast_log(LOG_NOTICE
," Telemetry mode: %d\n",zt
->mode
);
6335 ast_log(LOG_NOTICE
,"******* Variable Dump End (app_rpt) *******\n");
6342 struct rpt_tele
*telem
;
6344 rpt_mutex_lock(&myrpt
->lock
);
6345 telem
= myrpt
->tele
.next
;
6346 while(telem
!= &myrpt
->tele
)
6348 ast_softhangup(telem
->chan
,AST_SOFTHANGUP_DEV
);
6349 telem
= telem
->next
;
6352 rpt_mutex_unlock(&myrpt
->lock
);
6354 /* find our index, and load the vars */
6355 for(i
= 0; i
< nrpts
; i
++)
6357 if (&rpt_vars
[i
] == myrpt
)
6365 rpt_mutex_lock(&myrpt
->lock
);
6366 if (ast_check_hangup(myrpt
->rxchannel
)) break;
6367 if (ast_check_hangup(myrpt
->txchannel
)) break;
6368 if (ast_check_hangup(myrpt
->pchannel
)) break;
6369 if (ast_check_hangup(myrpt
->txpchannel
)) break;
6371 /* Update local tx with keyed if not parsing a command */
6372 myrpt
->localtx
= myrpt
->keyed
&& (myrpt
->dtmfidx
== -1) && (!myrpt
->cmdnode
[0]);
6373 /* If someone's connected, and they're transmitting from their end to us, set remrx true */
6374 l
= myrpt
->links
.next
;
6376 while(l
!= &myrpt
->links
)
6380 if(l
->name
[0] != '0') /* Ignore '0' nodes */
6381 strcpy(myrpt
->lastnodewhichkeyedusup
, l
->name
); /* Note the node which is doing the key up */
6385 /* Create a "must_id" flag for the cleanup ID */
6386 myrpt
->mustid
|= (myrpt
->idtimer
) && (myrpt
->keyed
|| remrx
) ;
6387 /* Build a fresh totx from myrpt->keyed and autopatch activated */
6388 totx
= myrpt
->callmode
;
6389 /* If full duplex, add local tx to totx */
6390 if (myrpt
->p
.duplex
> 1) totx
= totx
|| myrpt
->localtx
;
6391 /* Traverse the telemetry list to see what's queued */
6393 othertelemqueued
= 0;
6394 tailmessagequeued
= 0;
6396 telem
= myrpt
->tele
.next
;
6397 while(telem
!= &myrpt
->tele
)
6399 if((telem
->mode
== ID
) || (telem
->mode
== IDTALKOVER
)){
6400 identqueued
= 1; /* Identification telemetry */
6402 else if(telem
->mode
== TAILMSG
)
6404 tailmessagequeued
= 1; /* Tail message telemetry */
6408 if (telem
->mode
!= UNKEY
)
6409 othertelemqueued
= 1; /* Other telemetry */
6411 ctqueued
= 1; /* Courtesy tone telemetry */
6413 telem
= telem
->next
;
6416 /* Add in any "other" telemetry, if 3/4 or full duplex */
6417 if (myrpt
->p
.duplex
> 0) totx
= totx
|| othertelemqueued
;
6418 /* Update external (to links) transmitter PTT state with everything but ID, CT, and tailmessage telemetry */
6419 myrpt
->exttx
= totx
;
6420 /* If half or 3/4 duplex, add localtx to external link tx */
6421 if (myrpt
->p
.duplex
< 2) myrpt
->exttx
= myrpt
->exttx
|| myrpt
->localtx
;
6422 /* Add in ID telemetry to local transmitter */
6423 totx
= totx
|| remrx
;
6424 /* If 3/4 or full duplex, add in ident and CT telemetry */
6425 if (myrpt
->p
.duplex
> 0)
6426 totx
= totx
|| identqueued
|| ctqueued
;
6427 /* Reset time out timer variables if there is no activity */
6430 myrpt
->totimer
= myrpt
->p
.totime
;
6431 myrpt
->tounkeyed
= 0;
6432 myrpt
->tonotify
= 0;
6435 myrpt
->tailtimer
= myrpt
->p
.hangtime
; /* Initialize tail timer */
6436 /* Disable the local transmitter if we are timed out */
6437 totx
= totx
&& myrpt
->totimer
;
6438 /* if timed-out and not said already, say it */
6439 if ((!myrpt
->totimer
) && (!myrpt
->tonotify
))
6441 myrpt
->tonotify
= 1;
6443 rpt_mutex_unlock(&myrpt
->lock
);
6444 rpt_telemetry(myrpt
,TIMEOUT
,NULL
);
6445 rpt_mutex_lock(&myrpt
->lock
);
6448 /* If unkey and re-key, reset time out timer */
6449 if ((!totx
) && (!myrpt
->totimer
) && (!myrpt
->tounkeyed
) && (!myrpt
->keyed
))
6451 myrpt
->tounkeyed
= 1;
6453 if ((!totx
) && (!myrpt
->totimer
) && myrpt
->tounkeyed
&& myrpt
->keyed
)
6455 myrpt
->totimer
= myrpt
->p
.totime
;
6456 myrpt
->tounkeyed
= 0;
6457 myrpt
->tonotify
= 0;
6458 rpt_mutex_unlock(&myrpt
->lock
);
6461 /* if timed-out and in circuit busy after call */
6462 if ((!totx
) && (!myrpt
->totimer
) && (myrpt
->callmode
== 4))
6464 myrpt
->callmode
= 0;
6466 /* get rid of tail if timed out */
6467 if (!myrpt
->totimer
) myrpt
->tailtimer
= 0;
6468 /* if not timed-out, add in tail */
6469 if (myrpt
->totimer
) totx
= totx
|| myrpt
->tailtimer
;
6470 /* If user or links key up or are keyed up over standard ID, switch to talkover ID, if one is defined */
6471 /* If tail message, kill the message if someone keys up over it */
6472 if ((myrpt
->keyed
|| remrx
) && ((identqueued
&& idtalkover
) || (tailmessagequeued
))) {
6473 int hasid
= 0,hastalkover
= 0;
6475 telem
= myrpt
->tele
.next
;
6476 while(telem
!= &myrpt
->tele
){
6477 if(telem
->mode
== ID
){
6478 if (telem
->chan
) ast_softhangup(telem
->chan
, AST_SOFTHANGUP_DEV
); /* Whoosh! */
6481 if(telem
->mode
== TAILMSG
){
6482 if (telem
->chan
) ast_softhangup(telem
->chan
, AST_SOFTHANGUP_DEV
); /* Whoosh! */
6484 if (telem
->mode
== IDTALKOVER
) hastalkover
= 1;
6485 telem
= telem
->next
;
6487 rpt_mutex_unlock(&myrpt
->lock
);
6488 if (hasid
&& (!hastalkover
)) rpt_telemetry(myrpt
, IDTALKOVER
, NULL
); /* Start Talkover ID */
6489 rpt_mutex_lock(&myrpt
->lock
);
6491 /* Try to be polite */
6492 /* If the repeater has been inactive for longer than the ID time, do an initial ID in the tail*/
6493 /* If within 30 seconds of the time to ID, try do it in the tail */
6494 /* else if at ID time limit, do it right over the top of them */
6495 /* Lastly, if the repeater has been keyed, and the ID timer is expired, do a clean up ID */
6496 if(myrpt
->mustid
&& (!myrpt
->idtimer
))
6499 if ((totx
&& (!myrpt
->exttx
) &&
6500 (myrpt
->idtimer
<= myrpt
->p
.politeid
) && myrpt
->tailtimer
))
6505 /* If tail timer expires, then check for tail messages */
6507 if(myrpt
->tailevent
){
6508 myrpt
->tailevent
= 0;
6513 else if ((myrpt
->p
.tailmessages
[0]) &&
6514 (myrpt
->p
.tailmessagetime
) && (myrpt
->tmsgtimer
== 0)){
6516 myrpt
->tmsgtimer
= myrpt
->p
.tailmessagetime
;
6517 rpt_mutex_unlock(&myrpt
->lock
);
6518 rpt_telemetry(myrpt
, TAILMSG
, NULL
);
6519 rpt_mutex_lock(&myrpt
->lock
);
6523 /* Main TX control */
6525 /* let telemetry transmit anyway (regardless of timeout) */
6526 if (myrpt
->p
.duplex
> 0) totx
= totx
|| (myrpt
->tele
.next
!= &myrpt
->tele
);
6527 if (totx
&& (!lasttx
))
6530 myrpt
->dailykeyups
++;
6531 myrpt
->totalkeyups
++;
6532 rpt_mutex_unlock(&myrpt
->lock
);
6533 ast_indicate(myrpt
->txchannel
,AST_CONTROL_RADIO_KEY
);
6534 rpt_mutex_lock(&myrpt
->lock
);
6536 totx
= totx
&& myrpt
->enable
;
6537 if ((!totx
) && lasttx
)
6540 rpt_mutex_unlock(&myrpt
->lock
);
6541 ast_indicate(myrpt
->txchannel
,AST_CONTROL_RADIO_UNKEY
);
6542 rpt_mutex_lock(&myrpt
->lock
);
6545 /* if DTMF timeout */
6546 if ((!myrpt
->cmdnode
[0]) && (myrpt
->dtmfidx
>= 0) && ((myrpt
->dtmf_time
+ DTMF_TIMEOUT
) < t
))
6548 myrpt
->dtmfidx
= -1;
6549 myrpt
->dtmfbuf
[0] = 0;
6551 /* if remote DTMF timeout */
6552 if ((myrpt
->rem_dtmfidx
>= 0) && ((myrpt
->rem_dtmf_time
+ DTMF_TIMEOUT
) < t
))
6554 myrpt
->rem_dtmfidx
= -1;
6555 myrpt
->rem_dtmfbuf
[0] = 0;
6560 l
= myrpt
->links
.next
;
6561 while(l
!= &myrpt
->links
)
6565 /* remove from queue */
6566 remque((struct qelem
*) l
);
6567 if (!strcmp(myrpt
->cmdnode
,l
->name
))
6568 myrpt
->cmdnode
[0] = 0;
6569 rpt_mutex_unlock(&myrpt
->lock
);
6570 /* hang-up on call to device */
6571 if (l
->chan
) ast_hangup(l
->chan
);
6572 ast_hangup(l
->pchan
);
6574 rpt_mutex_lock(&myrpt
->lock
);
6575 /* re-start link traversal */
6576 l
= myrpt
->links
.next
;
6582 cs
[n
++] = myrpt
->rxchannel
;
6583 cs
[n
++] = myrpt
->pchannel
;
6584 cs
[n
++] = myrpt
->txpchannel
;
6585 if (myrpt
->txchannel
!= myrpt
->rxchannel
) cs
[n
++] = myrpt
->txchannel
;
6586 l
= myrpt
->links
.next
;
6587 while(l
!= &myrpt
->links
)
6589 if ((!l
->killme
) && (!l
->disctime
) && l
->chan
)
6596 rpt_mutex_unlock(&myrpt
->lock
);
6598 who
= ast_waitfor_n(cs
,n
,&ms
);
6599 if (who
== NULL
) ms
= 0;
6601 rpt_mutex_lock(&myrpt
->lock
);
6602 l
= myrpt
->links
.next
;
6603 while(l
!= &myrpt
->links
)
6607 if ((l
->retxtimer
+= elap
) >= REDUNDANT_TX_TIME
)
6610 if (l
->chan
) ast_indicate(l
->chan
,AST_CONTROL_RADIO_UNKEY
);
6612 } else l
->retxtimer
= 0;
6613 if (l
->disctime
) /* Disconnect timer active on a channel ? */
6615 l
->disctime
-= elap
;
6616 if (l
->disctime
<= 0) /* Disconnect timer expired on inbound channel ? */
6617 l
->disctime
= 0; /* Yep */
6622 l
->retrytimer
-= elap
;
6623 if (l
->retrytimer
< 0) l
->retrytimer
= 0;
6626 /* Tally connect time */
6627 l
->connecttime
+= elap
;
6629 /* ignore non-timing channels */
6630 if (l
->elaptime
< 0)
6635 l
->elaptime
+= elap
;
6636 /* if connection has taken too long */
6637 if ((l
->elaptime
> MAXCONNECTTIME
) &&
6638 ((!l
->chan
) || (l
->chan
->_state
!= AST_STATE_UP
)))
6641 rpt_mutex_unlock(&myrpt
->lock
);
6642 if (l
->chan
) ast_softhangup(l
->chan
,AST_SOFTHANGUP_DEV
);
6643 rpt_mutex_lock(&myrpt
->lock
);
6646 if ((!l
->chan
) && (!l
->retrytimer
) && l
->outbound
&&
6647 (l
->retries
++ < MAX_RETRIES
) && (l
->hasconnected
))
6649 if (l
->chan
) ast_hangup(l
->chan
);
6650 rpt_mutex_unlock(&myrpt
->lock
);
6651 if ((l
->name
[0] != '0') && (!l
->isremote
))
6653 l
->retrytimer
= MAX_RETRIES
+ 1;
6657 if (attempt_reconnect(myrpt
,l
) == -1)
6659 l
->retrytimer
= RETRY_TIMER_MS
;
6662 rpt_mutex_lock(&myrpt
->lock
);
6665 if ((!l
->chan
) && (!l
->retrytimer
) && l
->outbound
&&
6666 (l
->retries
>= MAX_RETRIES
))
6668 /* remove from queue */
6669 remque((struct qelem
*) l
);
6670 if (!strcmp(myrpt
->cmdnode
,l
->name
))
6671 myrpt
->cmdnode
[0] = 0;
6672 rpt_mutex_unlock(&myrpt
->lock
);
6673 if (l
->name
[0] != '0')
6675 if (!l
->hasconnected
)
6676 rpt_telemetry(myrpt
,CONNFAIL
,l
);
6677 else rpt_telemetry(myrpt
,REMDISC
,l
);
6679 /* hang-up on call to device */
6680 ast_hangup(l
->pchan
);
6682 rpt_mutex_lock(&myrpt
->lock
);
6685 if ((!l
->chan
) && (!l
->disctime
) && (!l
->outbound
))
6687 /* remove from queue */
6688 remque((struct qelem
*) l
);
6689 if (!strcmp(myrpt
->cmdnode
,l
->name
))
6690 myrpt
->cmdnode
[0] = 0;
6691 rpt_mutex_unlock(&myrpt
->lock
);
6692 if (l
->name
[0] != '0')
6694 rpt_telemetry(myrpt
,REMDISC
,l
);
6696 /* hang-up on call to device */
6697 ast_hangup(l
->pchan
);
6699 rpt_mutex_lock(&myrpt
->lock
);
6705 myrpt
->dailytxtime
+= elap
;
6706 myrpt
->totaltxtime
+= elap
;
6708 i
= myrpt
->tailtimer
;
6709 if (myrpt
->tailtimer
) myrpt
->tailtimer
-= elap
;
6710 if (myrpt
->tailtimer
< 0) myrpt
->tailtimer
= 0;
6711 if((i
) && (myrpt
->tailtimer
== 0))
6712 myrpt
->tailevent
= 1;
6713 if (myrpt
->totimer
) myrpt
->totimer
-= elap
;
6714 if (myrpt
->totimer
< 0) myrpt
->totimer
= 0;
6715 if (myrpt
->idtimer
) myrpt
->idtimer
-= elap
;
6716 if (myrpt
->idtimer
< 0) myrpt
->idtimer
= 0;
6717 if (myrpt
->tmsgtimer
) myrpt
->tmsgtimer
-= elap
;
6718 if (myrpt
->tmsgtimer
< 0) myrpt
->tmsgtimer
= 0;
6719 /* do macro timers */
6720 if (myrpt
->macrotimer
) myrpt
->macrotimer
-= elap
;
6721 if (myrpt
->macrotimer
< 0) myrpt
->macrotimer
= 0;
6722 /* Execute scheduler appx. every 2 tenths of a second */
6723 if (myrpt
->skedtimer
<= 0){
6724 myrpt
->skedtimer
= 200;
6725 do_scheduler(myrpt
);
6728 myrpt
->skedtimer
-=elap
;
6731 rpt_mutex_unlock(&myrpt
->lock
);
6734 c
= myrpt
->macrobuf
[0];
6735 if (c
&& (!myrpt
->macrotimer
))
6737 myrpt
->macrotimer
= MACROTIME
;
6738 memmove(myrpt
->macrobuf
,myrpt
->macrobuf
+ 1,MAXMACRO
- 1);
6739 if ((c
== 'p') || (c
== 'P'))
6740 myrpt
->macrotimer
= MACROPTIME
;
6741 rpt_mutex_unlock(&myrpt
->lock
);
6742 local_dtmf_helper(myrpt
,c
);
6743 } else rpt_mutex_unlock(&myrpt
->lock
);
6744 if (who
== myrpt
->rxchannel
) /* if it was a read from rx */
6746 f
= ast_read(myrpt
->rxchannel
);
6749 if (debug
) printf("@@@@ rpt:Hung Up\n");
6752 if (f
->frametype
== AST_FRAME_VOICE
)
6754 #ifdef _MDC_DECODE_H_
6755 unsigned char ubuf
[2560];
6760 if (!myrpt
->localtx
) {
6761 memset(f
->data
,0,f
->datalen
);
6764 #ifdef _MDC_DECODE_H_
6765 sp
= (short *) f
->data
;
6766 /* convert block to unsigned char */
6767 for(n
= 0; n
< f
->datalen
/ 2; n
++)
6769 ubuf
[n
] = (*sp
++ >> 8) + 128;
6771 n
= mdc_decoder_process_samples(myrpt
->mdc
,ubuf
,f
->datalen
/ 2);
6774 unsigned char op
,arg
;
6775 unsigned short unitID
;
6777 mdc_decoder_get_packet(myrpt
->mdc
,&op
,&arg
,&unitID
);
6780 ast_log(LOG_NOTICE
,"Got (single-length) packet:\n");
6781 ast_log(LOG_NOTICE
,"op: %02x, arg: %02x, UnitID: %04x\n",
6782 op
& 255,arg
& 255,unitID
);
6784 if ((op
== 1) && (arg
== 0))
6786 myrpt
->lastunit
= unitID
;
6789 if ((debug
> 2) && (i
== 2))
6791 unsigned char op
,arg
,ex1
,ex2
,ex3
,ex4
;
6792 unsigned short unitID
;
6794 mdc_decoder_get_double_packet(myrpt
->mdc
,&op
,&arg
,&unitID
,
6795 &ex1
,&ex2
,&ex3
,&ex4
);
6796 ast_log(LOG_NOTICE
,"Got (double-length) packet:\n");
6797 ast_log(LOG_NOTICE
,"op: %02x, arg: %02x, UnitID: %04x\n",
6798 op
& 255,arg
& 255,unitID
);
6799 ast_log(LOG_NOTICE
,"ex1: %02x, ex2: %02x, ex3: %02x, ex4: %02x\n",
6800 ex1
& 255, ex2
& 255, ex3
& 255, ex4
& 255);
6804 /* apply inbound filters, if any */
6805 rpt_filter(myrpt
,f
->data
,f
->datalen
/ 2);
6807 ast_write(myrpt
->pchannel
,f
);
6809 else if (f
->frametype
== AST_FRAME_DTMF
)
6811 c
= (char) f
->subclass
; /* get DTMF char */
6813 if (!myrpt
->keyed
) continue;
6814 local_dtmf_helper(myrpt
,c
);
6817 else if (f
->frametype
== AST_FRAME_CONTROL
)
6819 if (f
->subclass
== AST_CONTROL_HANGUP
)
6821 if (debug
) printf("@@@@ rpt:Hung Up\n");
6826 if (f
->subclass
== AST_CONTROL_RADIO_KEY
)
6828 if ((!lasttx
) || (myrpt
->p
.duplex
> 1))
6830 if (debug
== 7) printf("@@@@ rx key\n");
6835 if (f
->subclass
== AST_CONTROL_RADIO_UNKEY
)
6837 if ((!lasttx
) || (myrpt
->p
.duplex
> 1))
6839 if (debug
== 7) printf("@@@@ rx un-key\n");
6841 rpt_telemetry(myrpt
,UNKEY
,NULL
);
6850 if (who
== myrpt
->pchannel
) /* if it was a read from pseudo */
6852 f
= ast_read(myrpt
->pchannel
);
6855 if (debug
) printf("@@@@ rpt:Hung Up\n");
6858 if (f
->frametype
== AST_FRAME_VOICE
)
6860 ast_write(myrpt
->txpchannel
,f
);
6862 if (f
->frametype
== AST_FRAME_CONTROL
)
6864 if (f
->subclass
== AST_CONTROL_HANGUP
)
6866 if (debug
) printf("@@@@ rpt:Hung Up\n");
6874 if (who
== myrpt
->txchannel
) /* if it was a read from tx */
6876 f
= ast_read(myrpt
->txchannel
);
6879 if (debug
) printf("@@@@ rpt:Hung Up\n");
6882 if (f
->frametype
== AST_FRAME_CONTROL
)
6884 if (f
->subclass
== AST_CONTROL_HANGUP
)
6886 if (debug
) printf("@@@@ rpt:Hung Up\n");
6895 rpt_mutex_lock(&myrpt
->lock
);
6896 l
= myrpt
->links
.next
;
6897 while(l
!= &myrpt
->links
)
6904 if (who
== l
->chan
) /* if it was a read from rx */
6907 /* see if any other links are receiving */
6908 m
= myrpt
->links
.next
;
6909 while(m
!= &myrpt
->links
)
6911 /* if not us, count it */
6912 if ((m
!= l
) && (m
->lastrx
)) remrx
= 1;
6915 rpt_mutex_unlock(&myrpt
->lock
);
6916 totx
= (((l
->isremote
) ? myrpt
->localtx
:
6917 myrpt
->exttx
) || remrx
) && l
->mode
;
6918 if (l
->chan
&& (l
->lasttx
!= totx
))
6922 ast_indicate(l
->chan
,AST_CONTROL_RADIO_KEY
);
6926 ast_indicate(l
->chan
,AST_CONTROL_RADIO_UNKEY
);
6930 f
= ast_read(l
->chan
);
6933 if ((!l
->disced
) && (!l
->outbound
))
6935 if ((l
->name
[0] == '0') || l
->isremote
)
6938 l
->disctime
= DISC_TIME
;
6939 rpt_mutex_lock(&myrpt
->lock
);
6940 ast_hangup(l
->chan
);
6947 rpt_mutex_lock(&myrpt
->lock
);
6950 if (l
->outbound
&& (l
->retries
++ < MAX_RETRIES
) && (l
->hasconnected
))
6952 rpt_mutex_lock(&myrpt
->lock
);
6953 ast_hangup(l
->chan
);
6955 rpt_mutex_unlock(&myrpt
->lock
);
6956 if (attempt_reconnect(myrpt
,l
) == -1)
6958 l
->retrytimer
= RETRY_TIMER_MS
;
6960 rpt_mutex_lock(&myrpt
->lock
);
6963 rpt_mutex_lock(&myrpt
->lock
);
6964 /* remove from queue */
6965 remque((struct qelem
*) l
);
6966 if (!strcmp(myrpt
->cmdnode
,l
->name
))
6967 myrpt
->cmdnode
[0] = 0;
6968 rpt_mutex_unlock(&myrpt
->lock
);
6969 if (!l
->hasconnected
)
6970 rpt_telemetry(myrpt
,CONNFAIL
,l
);
6971 else if (l
->disced
!= 2) rpt_telemetry(myrpt
,REMDISC
,l
);
6972 /* hang-up on call to device */
6973 ast_hangup(l
->chan
);
6974 ast_hangup(l
->pchan
);
6976 rpt_mutex_lock(&myrpt
->lock
);
6979 if (f
->frametype
== AST_FRAME_VOICE
)
6983 memset(f
->data
,0,f
->datalen
);
6985 ast_write(l
->pchan
,f
);
6987 if (f
->frametype
== AST_FRAME_TEXT
)
6989 handle_link_data(myrpt
,l
,f
->data
);
6991 if (f
->frametype
== AST_FRAME_DTMF
)
6993 handle_link_phone_dtmf(myrpt
,l
,f
->subclass
);
6995 if (f
->frametype
== AST_FRAME_CONTROL
)
6997 if (f
->subclass
== AST_CONTROL_ANSWER
)
6999 char lconnected
= l
->connected
;
7001 l
->hasconnected
= 1;
7005 rpt_telemetry(myrpt
,CONNECTED
,l
);
7010 if (f
->subclass
== AST_CONTROL_RADIO_KEY
)
7012 if (debug
== 7 ) printf("@@@@ rx key\n");
7016 if (f
->subclass
== AST_CONTROL_RADIO_UNKEY
)
7018 if (debug
== 7) printf("@@@@ rx un-key\n");
7021 if (f
->subclass
== AST_CONTROL_HANGUP
)
7024 if ((!l
->outbound
) && (!l
->disced
))
7026 if ((l
->name
[0] == '0') || l
->isremote
)
7029 l
->disctime
= DISC_TIME
;
7030 rpt_mutex_lock(&myrpt
->lock
);
7031 ast_hangup(l
->chan
);
7037 rpt_mutex_lock(&myrpt
->lock
);
7040 if (l
->outbound
&& (l
->retries
++ < MAX_RETRIES
) && (l
->hasconnected
))
7042 rpt_mutex_lock(&myrpt
->lock
);
7043 ast_hangup(l
->chan
);
7045 rpt_mutex_unlock(&myrpt
->lock
);
7046 if (attempt_reconnect(myrpt
,l
) == -1)
7048 l
->retrytimer
= RETRY_TIMER_MS
;
7050 rpt_mutex_lock(&myrpt
->lock
);
7053 rpt_mutex_lock(&myrpt
->lock
);
7054 /* remove from queue */
7055 remque((struct qelem
*) l
);
7056 if (!strcmp(myrpt
->cmdnode
,l
->name
))
7057 myrpt
->cmdnode
[0] = 0;
7058 rpt_mutex_unlock(&myrpt
->lock
);
7059 if (!l
->hasconnected
)
7060 rpt_telemetry(myrpt
,CONNFAIL
,l
);
7061 else if (l
->disced
!= 2) rpt_telemetry(myrpt
,REMDISC
,l
);
7062 /* hang-up on call to device */
7063 ast_hangup(l
->chan
);
7064 ast_hangup(l
->pchan
);
7066 rpt_mutex_lock(&myrpt
->lock
);
7071 rpt_mutex_lock(&myrpt
->lock
);
7074 if (who
== l
->pchan
)
7076 rpt_mutex_unlock(&myrpt
->lock
);
7077 f
= ast_read(l
->pchan
);
7080 if (debug
) printf("@@@@ rpt:Hung Up\n");
7082 rpt_mutex_lock(&myrpt
->lock
);
7085 if (f
->frametype
== AST_FRAME_VOICE
)
7087 if (l
->chan
) ast_write(l
->chan
,f
);
7089 if (f
->frametype
== AST_FRAME_CONTROL
)
7091 if (f
->subclass
== AST_CONTROL_HANGUP
)
7093 if (debug
) printf("@@@@ rpt:Hung Up\n");
7096 rpt_mutex_lock(&myrpt
->lock
);
7101 rpt_mutex_lock(&myrpt
->lock
);
7106 rpt_mutex_unlock(&myrpt
->lock
);
7108 if (who
== myrpt
->txpchannel
) /* if it was a read from remote tx */
7110 f
= ast_read(myrpt
->txpchannel
);
7113 if (debug
) printf("@@@@ rpt:Hung Up\n");
7116 if (f
->frametype
== AST_FRAME_CONTROL
)
7118 if (f
->subclass
== AST_CONTROL_HANGUP
)
7120 if (debug
) printf("@@@@ rpt:Hung Up\n");
7130 ast_hangup(myrpt
->pchannel
);
7131 ast_hangup(myrpt
->txpchannel
);
7132 if (myrpt
->txchannel
!= myrpt
->rxchannel
) ast_hangup(myrpt
->txchannel
);
7133 ast_hangup(myrpt
->rxchannel
);
7134 rpt_mutex_lock(&myrpt
->lock
);
7135 l
= myrpt
->links
.next
;
7136 while(l
!= &myrpt
->links
)
7138 struct rpt_link
*ll
= l
;
7139 /* remove from queue */
7140 remque((struct qelem
*) l
);
7141 /* hang-up on call to device */
7142 if (l
->chan
) ast_hangup(l
->chan
);
7143 ast_hangup(l
->pchan
);
7147 rpt_mutex_unlock(&myrpt
->lock
);
7148 if (debug
) printf("@@@@ rpt:Hung up channel\n");
7149 myrpt
->rpt_thread
= AST_PTHREADT_STOP
;
7155 static void *rpt_master(void *config
)
7158 pthread_attr_t attr
;
7159 struct ast_config
*cfg
;
7163 /* go thru all the specified repeaters */
7166 rpt_vars
[n
].cfg
= config
;
7167 cfg
= rpt_vars
[n
].cfg
;
7169 ast_log(LOG_NOTICE
, "Unable to open radio repeater configuration rpt.conf. Radio Repeater disabled.\n");
7172 while((this = ast_category_browse(cfg
,this)) != NULL
)
7174 for(i
= 0 ; i
< strlen(this) ; i
++){
7175 if((this[i
] < '0') || (this[i
] > '9'))
7178 if(i
!= strlen(this)) continue; /* Not a node defn */
7179 memset(&rpt_vars
[n
],0,sizeof(rpt_vars
[n
]));
7180 rpt_vars
[n
].name
= strdup(this);
7181 val
= ast_variable_retrieve(cfg
,this,"rxchannel");
7182 if (val
) rpt_vars
[n
].rxchanname
= strdup(val
);
7183 val
= ast_variable_retrieve(cfg
,this,"txchannel");
7184 if (val
) rpt_vars
[n
].txchanname
= strdup(val
);
7185 val
= ast_variable_retrieve(cfg
,this,"remote");
7186 if (val
) rpt_vars
[n
].remote
= strdup(val
);
7187 ast_mutex_init(&rpt_vars
[n
].lock
);
7188 rpt_vars
[n
].tele
.next
= &rpt_vars
[n
].tele
;
7189 rpt_vars
[n
].tele
.prev
= &rpt_vars
[n
].tele
;
7190 rpt_vars
[n
].rpt_thread
= AST_PTHREADT_NULL
;
7191 rpt_vars
[n
].tailmessagen
= 0;
7192 #ifdef _MDC_DECODE_H_
7193 rpt_vars
[n
].mdc
= mdc_decoder_new(8000);
7198 ast_config_destroy(cfg
);
7201 for(i
= 0; i
< n
; i
++)
7205 /* if is a remote, dont start one for it */
7206 if (rpt_vars
[i
].remote
)
7208 strcpy(rpt_vars
[i
].freq
, "146.580");
7209 strcpy(rpt_vars
[i
].rxpl
, "100.0");
7210 strcpy(rpt_vars
[i
].txpl
, "100.0");
7211 rpt_vars
[i
].remmode
= REM_MODE_FM
;
7212 rpt_vars
[i
].offset
= REM_SIMPLEX
;
7213 rpt_vars
[i
].powerlevel
= REM_MEDPWR
;
7216 if (!rpt_vars
[i
].p
.ident
)
7218 ast_log(LOG_WARNING
,"Did not specify ident for node %s\n",rpt_vars
[i
].name
);
7219 ast_config_destroy(cfg
);
7222 pthread_attr_init(&attr
);
7223 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
7224 ast_pthread_create(&rpt_vars
[i
].rpt_thread
,&attr
,rpt
,(void *) &rpt_vars
[i
]);
7225 pthread_attr_destroy(&attr
);
7230 /* Now monitor each thread, and restart it if necessary */
7231 for(i
= 0; i
< n
; i
++)
7234 if (rpt_vars
[i
].remote
) continue;
7235 if (rpt_vars
[i
].rpt_thread
== AST_PTHREADT_STOP
)
7238 rv
= pthread_kill(rpt_vars
[i
].rpt_thread
,0);
7241 if(time(NULL
) - rpt_vars
[i
].lastthreadrestarttime
<= 15)
7243 if(rpt_vars
[i
].threadrestarts
>= 5)
7245 ast_log(LOG_ERROR
,"Continual RPT thread restarts, killing Asterisk\n");
7246 exit(1); /* Stuck in a restart loop, kill Asterisk and start over */
7250 ast_log(LOG_NOTICE
,"RPT thread restarted on %s\n",rpt_vars
[i
].name
);
7251 rpt_vars
[i
].threadrestarts
++;
7255 rpt_vars
[i
].threadrestarts
= 0;
7257 rpt_vars
[i
].lastthreadrestarttime
= time(NULL
);
7258 pthread_attr_init(&attr
);
7259 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
7260 ast_pthread_create(&rpt_vars
[i
].rpt_thread
,&attr
,rpt
,(void *) &rpt_vars
[i
]);
7261 pthread_attr_destroy(&attr
);
7262 ast_log(LOG_WARNING
, "rpt_thread restarted on node %s\n", rpt_vars
[i
].name
);
7268 ast_config_destroy(cfg
);
7272 static int rpt_exec(struct ast_channel
*chan
, void *data
)
7274 int res
=-1,i
,rem_totx
,n
,phone_mode
= 0;
7275 struct ast_module_user
*u
;
7276 char tmp
[256], keyed
= 0;
7277 char *options
,*stringp
,*tele
,c
;
7279 struct ast_frame
*f
;
7280 struct ast_channel
*who
;
7281 struct ast_channel
*cs
[20];
7283 ZT_CONFINFO ci
; /* conference info */
7287 if (ast_strlen_zero(data
)) {
7288 ast_log(LOG_WARNING
, "Rpt requires an argument (system node)\n");
7291 ast_copy_string(tmp
, (char *)data
, sizeof(tmp
));
7293 strsep(&stringp
, "|");
7296 /* see if we can find our specified one */
7297 for(i
= 0; i
< nrpts
; i
++)
7299 /* if name matches, assign it and exit loop */
7300 if (!strcmp(tmp
,rpt_vars
[i
].name
))
7302 myrpt
= &rpt_vars
[i
];
7308 ast_log(LOG_WARNING
, "Cannot find specified system node %s\n",tmp
);
7312 /* if not phone access, must be an IAX connection */
7313 if (options
&& ((*options
== 'P') || (*options
== 'D') || (*options
== 'R')))
7316 if (*options
== 'D') phone_mode
= 2;
7317 ast_set_callerid(chan
,"0","app_rpt user","0");
7321 if (strncmp(chan
->name
,"IAX2",4))
7323 ast_log(LOG_WARNING
, "We only accept links via IAX2!!\n");
7327 if (options
&& (*options
== 'R'))
7330 /* Parts of this section taken from app_parkandannounce */
7331 char *return_context
;
7332 int l
, m
, lot
, timeout
= 0;
7333 char tmp
[256],*template;
7334 char *working
, *context
, *exten
, *priority
;
7338 rpt_mutex_lock(&myrpt
->lock
);
7339 m
= myrpt
->callmode
;
7340 rpt_mutex_unlock(&myrpt
->lock
);
7342 if ((!myrpt
->p
.nobusyout
) && m
)
7344 if (chan
->_state
!= AST_STATE_UP
)
7346 ast_indicate(chan
,AST_CONTROL_BUSY
);
7348 while(ast_safe_sleep(chan
,10000) != -1);
7352 if (chan
->_state
!= AST_STATE_UP
)
7357 l
=strlen(options
)+2;
7360 ast_log(LOG_WARNING
, "Out of memory\n");
7364 ast_copy_string(s
,options
,l
);
7366 template=strsep(&s
,"|");
7368 ast_log(LOG_WARNING
, "An announce template must be defined\n");
7374 timeout
= atoi(strsep(&s
, "|"));
7380 if(return_context
!= NULL
) {
7381 /* set the return context. Code borrowed from the Goto builtin */
7383 working
= return_context
;
7384 context
= strsep(&working
, "|");
7385 exten
= strsep(&working
, "|");
7387 /* Only a priority in this one */
7392 priority
= strsep(&working
, "|");
7394 /* Only an extension and priority in this one */
7400 if(atoi(priority
) < 0) {
7401 ast_log(LOG_WARNING
, "Priority '%s' must be a number > 0\n", priority
);
7405 /* At this point we have a priority and maybe an extension and a context */
7406 chan
->priority
= atoi(priority
);
7408 if(exten
&& strcasecmp(exten
, "BYEXTENSION"))
7412 ast_copy_string(chan
->exten
, exten
, sizeof(chan
->exten
));
7414 ast_copy_string(chan
->context
, context
, sizeof(chan
->context
));
7415 } else { /* increment the priority by default*/
7419 if(option_verbose
> 2) {
7420 ast_verbose( VERBOSE_PREFIX_3
"Return Context: (%s,%s,%d) ID: %s\n", chan
->context
,chan
->exten
, chan
->priority
, chan
->cid
.cid_num
);
7421 if(!ast_exists_extension(chan
, chan
->context
, chan
->exten
, chan
->priority
, chan
->cid
.cid_num
)) {
7422 ast_verbose( VERBOSE_PREFIX_3
"Warning: Return Context Invalid, call will return to default|s\n");
7426 /* we are using masq_park here to protect * from touching the channel once we park it. If the channel comes out of timeout
7427 before we are done announcing and the channel is messed with, Kablooeee. So we use Masq to prevent this. */
7429 ast_masq_park_call(chan
, NULL
, timeout
, &lot
);
7431 if (option_verbose
> 2) ast_verbose( VERBOSE_PREFIX_3
"Call Parking Called, lot: %d, timeout: %d, context: %s\n", lot
, timeout
, return_context
);
7433 snprintf(tmp
,sizeof(tmp
) - 1,"%d,%s",lot
,template + 1);
7435 rpt_telemetry(myrpt
,REV_PATCH
,tmp
);
7445 struct ast_hostent ahp
;
7448 char hisip
[100],nodeip
[100];
7450 char *s
, *s1
, *s2
, *b
,*b1
;
7452 /* look at callerid to see what node this comes from */
7453 if (!chan
->cid
.cid_num
) /* if doesn't have caller id */
7455 ast_log(LOG_WARNING
, "Doesnt have callerid on %s\n",tmp
);
7459 /* get his IP from IAX2 module */
7460 memset(hisip
,0,sizeof(hisip
));
7461 pbx_substitute_variables_helper(chan
,"${IAXPEER(CURRENTCHANNEL)}",hisip
,sizeof(hisip
) - 1);
7464 ast_log(LOG_WARNING
, "Link IP address cannot be determined!!\n");
7468 ast_callerid_parse(chan
->cid
.cid_num
,&b
,&b1
);
7469 ast_shrink_phone_number(b1
);
7470 if (!strcmp(myrpt
->name
,b1
))
7472 ast_log(LOG_WARNING
, "Trying to link to self!!\n");
7478 ast_log(LOG_WARNING
, "Node %s Invalid for connection here!!\n",b1
);
7483 /* look for his reported node string */
7484 val
= ast_variable_retrieve(myrpt
->cfg
, myrpt
->p
.nodes
, b1
);
7487 ast_log(LOG_WARNING
, "Reported node %s cannot be found!!\n",b1
);
7490 ast_copy_string(tmp
,val
,sizeof(tmp
));
7492 s1
= strsep(&s
,",");
7493 s2
= strsep(&s
,",");
7496 ast_log(LOG_WARNING
, "Reported node %s not in correct format!!\n",b1
);
7499 if (strcmp(s2
,"NONE")) {
7500 hp
= ast_gethostbyname(s2
, &ahp
);
7503 ast_log(LOG_WARNING
, "Reported node %s, name %s cannot be found!!\n",b1
,s2
);
7506 memcpy(&ia
,hp
->h_addr
,sizeof(in_addr_t
));
7507 ast_copy_string(nodeip
, ast_inet_ntoa(ia
), sizeof(nodeip
));
7508 if (strcmp(hisip
,nodeip
))
7510 char *s3
= strchr(s1
,'@');
7511 if (s3
) s1
= s3
+ 1;
7512 s3
= strchr(s1
,'/');
7514 hp
= ast_gethostbyname(s1
, &ahp
);
7517 ast_log(LOG_WARNING
, "Reported node %s, name %s cannot be found!!\n",b1
,s1
);
7520 memcpy(&ia
,hp
->h_addr
,sizeof(in_addr_t
));
7521 ast_copy_string(nodeip
, ast_inet_ntoa(ia
), sizeof(nodeip
));
7522 if (strcmp(hisip
,nodeip
))
7524 ast_log(LOG_WARNING
, "Node %s IP %s does not match link IP %s!!\n",b1
,nodeip
,hisip
);
7531 /* if is not a remote */
7538 /* look at callerid to see what node this comes from */
7539 if (!chan
->cid
.cid_num
) /* if doesn't have caller id */
7541 ast_log(LOG_WARNING
, "Doesnt have callerid on %s\n",tmp
);
7545 ast_callerid_parse(chan
->cid
.cid_num
,&b
,&b1
);
7546 ast_shrink_phone_number(b1
);
7547 if (!strcmp(myrpt
->name
,b1
))
7549 ast_log(LOG_WARNING
, "Trying to link to self!!\n");
7552 rpt_mutex_lock(&myrpt
->lock
);
7553 l
= myrpt
->links
.next
;
7554 /* try to find this one in queue */
7555 while(l
!= &myrpt
->links
)
7557 if (l
->name
[0] == '0')
7562 /* if found matching string */
7563 if (!strcmp(l
->name
,b1
)) break;
7567 if (l
!= &myrpt
->links
)
7570 l
->retries
= MAX_RETRIES
+ 1;
7572 reconnects
= l
->reconnects
;
7574 rpt_mutex_unlock(&myrpt
->lock
);
7577 rpt_mutex_unlock(&myrpt
->lock
);
7578 /* establish call in tranceive mode */
7579 l
= malloc(sizeof(struct rpt_link
));
7582 ast_log(LOG_WARNING
, "Unable to malloc\n");
7585 /* zero the silly thing */
7586 memset((char *)l
,0,sizeof(struct rpt_link
));
7588 ast_copy_string(l
->name
,b1
,MAXNODESTR
);
7592 l
->hasconnected
= 1;
7593 l
->reconnects
= reconnects
;
7594 l
->phonemode
= phone_mode
;
7595 ast_set_read_format(l
->chan
,AST_FORMAT_SLINEAR
);
7596 ast_set_write_format(l
->chan
,AST_FORMAT_SLINEAR
);
7597 /* allocate a pseudo-channel thru asterisk */
7598 l
->pchan
= ast_request("zap",AST_FORMAT_SLINEAR
,"pseudo",NULL
);
7601 fprintf(stderr
,"rpt:Sorry unable to obtain pseudo channel\n");
7604 ast_set_read_format(l
->pchan
,AST_FORMAT_SLINEAR
);
7605 ast_set_write_format(l
->pchan
,AST_FORMAT_SLINEAR
);
7606 /* make a conference for the tx */
7608 ci
.confno
= myrpt
->conf
;
7609 ci
.confmode
= ZT_CONF_CONF
| ZT_CONF_LISTENER
| ZT_CONF_TALKER
;
7610 /* first put the channel on the conference in proper mode */
7611 if (ioctl(l
->pchan
->fds
[0],ZT_SETCONF
,&ci
) == -1)
7613 ast_log(LOG_WARNING
, "Unable to set conference mode to Announce\n");
7616 rpt_mutex_lock(&myrpt
->lock
);
7617 if (phone_mode
> 1) l
->lastrx
= 1;
7618 /* insert at end of queue */
7619 insque((struct qelem
*)l
,(struct qelem
*)myrpt
->links
.next
);
7620 rpt_mutex_unlock(&myrpt
->lock
);
7621 if (chan
->_state
!= AST_STATE_UP
) {
7624 return AST_PBX_KEEPALIVE
;
7626 rpt_mutex_lock(&myrpt
->lock
);
7627 /* if remote, error if anyone else already linked */
7628 if (myrpt
->remoteon
)
7630 rpt_mutex_unlock(&myrpt
->lock
);
7632 if (myrpt
->remoteon
)
7634 ast_log(LOG_WARNING
, "Trying to use busy link on %s\n",tmp
);
7637 rpt_mutex_lock(&myrpt
->lock
);
7639 myrpt
->remoteon
= 1;
7640 if (ioperm(myrpt
->p
.iobase
,1,1) == -1)
7642 rpt_mutex_unlock(&myrpt
->lock
);
7643 ast_log(LOG_WARNING
, "Cant get io permission on IO port %x hex\n",myrpt
->p
.iobase
);
7646 u
= ast_module_user_add(chan
);
7647 rpt_mutex_unlock(&myrpt
->lock
);
7648 /* find our index, and load the vars initially */
7649 for(i
= 0; i
< nrpts
; i
++)
7651 if (&rpt_vars
[i
] == myrpt
)
7657 rpt_mutex_lock(&myrpt
->lock
);
7658 tele
= strchr(myrpt
->rxchanname
,'/');
7661 fprintf(stderr
,"rpt:Dial number must be in format tech/number\n");
7662 rpt_mutex_unlock(&myrpt
->lock
);
7666 myrpt
->rxchannel
= ast_request(myrpt
->rxchanname
,AST_FORMAT_SLINEAR
,tele
,NULL
);
7667 if (myrpt
->rxchannel
)
7669 ast_set_read_format(myrpt
->rxchannel
,AST_FORMAT_SLINEAR
);
7670 ast_set_write_format(myrpt
->rxchannel
,AST_FORMAT_SLINEAR
);
7671 myrpt
->rxchannel
->whentohangup
= 0;
7672 myrpt
->rxchannel
->appl
= "Apprpt";
7673 myrpt
->rxchannel
->data
= "(Link Rx)";
7674 if (option_verbose
> 2)
7675 ast_verbose(VERBOSE_PREFIX_3
"rpt (Rx) initiating call to %s/%s on %s\n",
7676 myrpt
->rxchanname
,tele
,myrpt
->rxchannel
->name
);
7677 rpt_mutex_unlock(&myrpt
->lock
);
7678 ast_call(myrpt
->rxchannel
,tele
,999);
7679 rpt_mutex_lock(&myrpt
->lock
);
7683 fprintf(stderr
,"rpt:Sorry unable to obtain Rx channel\n");
7684 rpt_mutex_unlock(&myrpt
->lock
);
7688 if (myrpt
->txchanname
)
7690 tele
= strchr(myrpt
->txchanname
,'/');
7693 fprintf(stderr
,"rpt:Dial number must be in format tech/number\n");
7694 rpt_mutex_unlock(&myrpt
->lock
);
7695 ast_hangup(myrpt
->rxchannel
);
7699 myrpt
->txchannel
= ast_request(myrpt
->txchanname
,AST_FORMAT_SLINEAR
,tele
,NULL
);
7700 if (myrpt
->txchannel
)
7702 ast_set_read_format(myrpt
->txchannel
,AST_FORMAT_SLINEAR
);
7703 ast_set_write_format(myrpt
->txchannel
,AST_FORMAT_SLINEAR
);
7704 myrpt
->txchannel
->whentohangup
= 0;
7705 myrpt
->txchannel
->appl
= "Apprpt";
7706 myrpt
->txchannel
->data
= "(Link Tx)";
7707 if (option_verbose
> 2)
7708 ast_verbose(VERBOSE_PREFIX_3
"rpt (Tx) initiating call to %s/%s on %s\n",
7709 myrpt
->txchanname
,tele
,myrpt
->txchannel
->name
);
7710 rpt_mutex_unlock(&myrpt
->lock
);
7711 ast_call(myrpt
->txchannel
,tele
,999);
7712 rpt_mutex_lock(&myrpt
->lock
);
7716 fprintf(stderr
,"rpt:Sorry unable to obtain Tx channel\n");
7717 rpt_mutex_unlock(&myrpt
->lock
);
7718 ast_hangup(myrpt
->rxchannel
);
7725 myrpt
->txchannel
= myrpt
->rxchannel
;
7727 myrpt
->remoterx
= 0;
7728 myrpt
->remotetx
= 0;
7729 myrpt
->retxtimer
= 0;
7730 myrpt
->remoteon
= 1;
7731 myrpt
->dtmfidx
= -1;
7732 myrpt
->dtmfbuf
[0] = 0;
7733 myrpt
->dtmf_time_rem
= 0;
7734 myrpt
->hfscanmode
= 0;
7735 myrpt
->hfscanstatus
= 0;
7736 if (myrpt
->p
.startupmacro
)
7738 myrpt
->remchannel
= chan
; /* Save copy of channel */
7739 snprintf(myrpt
->macrobuf
,MAXMACRO
- 1,"PPPP%s",myrpt
->p
.startupmacro
);
7742 rpt_mutex_unlock(&myrpt
->lock
);
7744 ast_set_write_format(chan
, AST_FORMAT_SLINEAR
);
7745 ast_set_read_format(chan
, AST_FORMAT_SLINEAR
);
7746 /* if we are on 2w loop and are a remote, turn EC on */
7747 if (myrpt
->remote
&& (myrpt
->rxchannel
== myrpt
->txchannel
))
7750 ioctl(myrpt
->rxchannel
->fds
[0],ZT_ECHOCANCEL
,&i
);
7752 if (chan
->_state
!= AST_STATE_UP
) {
7756 if (ioctl(myrpt
->txchannel
->fds
[0],ZT_GET_PARAMS
,&par
) != -1)
7758 if (par
.rxisoffhook
)
7760 ast_indicate(chan
,AST_CONTROL_RADIO_KEY
);
7761 myrpt
->remoterx
= 1;
7766 cs
[n
++] = myrpt
->rxchannel
;
7767 if (myrpt
->rxchannel
!= myrpt
->txchannel
)
7768 cs
[n
++] = myrpt
->txchannel
;
7771 if (ast_check_hangup(chan
)) break;
7772 if (ast_check_hangup(myrpt
->rxchannel
)) break;
7776 rpt_mutex_unlock(&myrpt
->lock
);
7777 /* find our index, and load the vars */
7778 for(i
= 0; i
< nrpts
; i
++)
7780 if (&rpt_vars
[i
] == myrpt
)
7786 rpt_mutex_lock(&myrpt
->lock
);
7789 who
= ast_waitfor_n(cs
,n
,&ms
);
7790 if (who
== NULL
) ms
= 0;
7792 if (myrpt
->macrotimer
) myrpt
->macrotimer
-= elap
;
7793 if (myrpt
->macrotimer
< 0) myrpt
->macrotimer
= 0;
7794 rpt_mutex_unlock(&myrpt
->lock
);
7799 if ((!myrpt
->remoterx
) && (!myrpt
->remotetx
))
7801 if ((myrpt
->retxtimer
+= elap
) >= REDUNDANT_TX_TIME
)
7803 myrpt
->retxtimer
= 0;
7804 ast_indicate(chan
,AST_CONTROL_RADIO_UNKEY
);
7806 } else myrpt
->retxtimer
= 0;
7807 if (rem_totx
&& (!myrpt
->remotetx
)) /* Remote base radio TX key */
7809 myrpt
->remotetx
= 1;
7810 ast_indicate(myrpt
->txchannel
,AST_CONTROL_RADIO_KEY
);
7812 if ((!rem_totx
) && myrpt
->remotetx
) /* Remote base radio TX unkey */
7814 myrpt
->remotetx
= 0;
7815 ast_indicate(myrpt
->txchannel
,AST_CONTROL_RADIO_UNKEY
);
7818 if(myrpt
->tunerequest
&& (!strcmp(myrpt
->remote
, remote_rig_ft897
))){ /* ft-897 specific for now... */
7819 myrpt
->tunerequest
= 0;
7820 set_mode_ft897(myrpt
, REM_MODE_AM
);
7821 simple_command_ft897(myrpt
, 8);
7822 myrpt
->remotetx
= 0;
7823 ast_indicate(myrpt
->txchannel
,AST_CONTROL_RADIO_UNKEY
);
7824 if (!myrpt
->remoterx
)
7825 ast_indicate(chan
, AST_CONTROL_RADIO_KEY
);
7826 if(play_tone(chan
, 800, 6000, 8192) == -1)
7829 rmt_telem_finish(myrpt
,chan
);
7830 set_mode_ft897(myrpt
, 0x88);
7834 if (myrpt
->hfscanmode
){
7835 myrpt
->scantimer
-= elap
;
7836 if(myrpt
->scantimer
<= 0){
7837 myrpt
->scantimer
= REM_SCANTIME
;
7838 service_scan(myrpt
);
7841 if (who
== chan
) /* if it was a read from incomming */
7846 if (debug
) printf("@@@@ link:Hung Up\n");
7849 if (f
->frametype
== AST_FRAME_VOICE
)
7851 /* if not transmitting, zero-out audio */
7852 if (!myrpt
->remotetx
)
7853 memset(f
->data
,0,f
->datalen
);
7854 ast_write(myrpt
->txchannel
,f
);
7856 if (f
->frametype
== AST_FRAME_DTMF
)
7858 myrpt
->remchannel
= chan
; /* Save copy of channel */
7859 if (handle_remote_phone_dtmf(myrpt
,f
->subclass
,&keyed
,phone_mode
) == -1)
7861 if (debug
) printf("@@@@ rpt:Hung Up\n");
7866 if (f
->frametype
== AST_FRAME_TEXT
)
7868 myrpt
->remchannel
= chan
; /* Save copy of channel */
7869 if (handle_remote_data(myrpt
,f
->data
) == -1)
7871 if (debug
) printf("@@@@ rpt:Hung Up\n");
7876 if (f
->frametype
== AST_FRAME_CONTROL
)
7878 if (f
->subclass
== AST_CONTROL_HANGUP
)
7880 if (debug
) printf("@@@@ rpt:Hung Up\n");
7885 if (f
->subclass
== AST_CONTROL_RADIO_KEY
)
7887 if (debug
== 7) printf("@@@@ rx key\n");
7891 if (f
->subclass
== AST_CONTROL_RADIO_UNKEY
)
7893 if (debug
== 7) printf("@@@@ rx un-key\n");
7897 if (myrpt
->hfscanstatus
){
7898 myrpt
->remchannel
= chan
; /* Save copy of channel */
7899 myrpt
->remotetx
= 0;
7900 ast_indicate(myrpt
->txchannel
,AST_CONTROL_RADIO_UNKEY
);
7901 if (!myrpt
->remoterx
)
7903 ast_indicate(myrpt
->remchannel
,AST_CONTROL_RADIO_KEY
);
7905 if(myrpt
->hfscanstatus
< 0) {
7906 if (myrpt
->hfscanstatus
== -1) {
7907 if (ast_safe_sleep(myrpt
->remchannel
,1000) == -1) break;
7909 sayfile(myrpt
->remchannel
, "rpt/stop");
7913 saynum(myrpt
->remchannel
, myrpt
->hfscanstatus
);
7915 rmt_telem_finish(myrpt
,myrpt
->remchannel
);
7916 myrpt
->hfscanstatus
= 0;
7919 rpt_mutex_lock(&myrpt
->lock
);
7920 c
= myrpt
->macrobuf
[0];
7921 if (c
&& (!myrpt
->macrotimer
))
7923 myrpt
->macrotimer
= MACROTIME
;
7924 memmove(myrpt
->macrobuf
,myrpt
->macrobuf
+ 1,MAXMACRO
- 1);
7925 if ((c
== 'p') || (c
== 'P'))
7926 myrpt
->macrotimer
= MACROPTIME
;
7927 rpt_mutex_unlock(&myrpt
->lock
);
7928 if (handle_remote_dtmf_digit(myrpt
,c
,&keyed
,0) == -1) break;
7931 rpt_mutex_unlock(&myrpt
->lock
);
7934 if (who
== myrpt
->rxchannel
) /* if it was a read from radio */
7936 f
= ast_read(myrpt
->rxchannel
);
7939 if (debug
) printf("@@@@ link:Hung Up\n");
7942 if (f
->frametype
== AST_FRAME_VOICE
)
7944 if ((myrpt
->remote
) && (myrpt
->remotetx
))
7945 memset(f
->data
,0,f
->datalen
);
7948 else if (f
->frametype
== AST_FRAME_CONTROL
)
7950 if (f
->subclass
== AST_CONTROL_HANGUP
)
7952 if (debug
) printf("@@@@ rpt:Hung Up\n");
7957 if (f
->subclass
== AST_CONTROL_RADIO_KEY
)
7959 if (debug
== 7) printf("@@@@ remote rx key\n");
7960 if (!myrpt
->remotetx
)
7962 ast_indicate(chan
,AST_CONTROL_RADIO_KEY
);
7963 myrpt
->remoterx
= 1;
7967 if (f
->subclass
== AST_CONTROL_RADIO_UNKEY
)
7969 if (debug
== 7) printf("@@@@ remote rx un-key\n");
7970 if (!myrpt
->remotetx
)
7972 ast_indicate(chan
,AST_CONTROL_RADIO_UNKEY
);
7973 myrpt
->remoterx
= 0;
7980 if ((myrpt
->rxchannel
!= myrpt
->txchannel
) &&
7981 (who
== myrpt
->txchannel
)) /* do this cuz you have to */
7983 f
= ast_read(myrpt
->txchannel
);
7986 if (debug
) printf("@@@@ link:Hung Up\n");
7989 if (f
->frametype
== AST_FRAME_CONTROL
)
7991 if (f
->subclass
== AST_CONTROL_HANGUP
)
7993 if (debug
) printf("@@@@ rpt:Hung Up\n");
8003 rpt_mutex_lock(&myrpt
->lock
);
8004 if (myrpt
->rxchannel
!= myrpt
->txchannel
) ast_hangup(myrpt
->txchannel
);
8005 ast_hangup(myrpt
->rxchannel
);
8006 myrpt
->hfscanmode
= 0;
8007 myrpt
->hfscanstatus
= 0;
8008 myrpt
->remoteon
= 0;
8009 rpt_mutex_unlock(&myrpt
->lock
);
8011 ast_module_user_remove(u
);
8015 static int unload_module(void)
8019 ast_module_user_hangup_all();
8020 for(i
= 0; i
< nrpts
; i
++) {
8021 if (!strcmp(rpt_vars
[i
].name
,rpt_vars
[i
].p
.nodes
)) continue;
8022 ast_mutex_destroy(&rpt_vars
[i
].lock
);
8024 i
= ast_unregister_application(app
);
8026 /* Unregister cli extensions */
8027 ast_cli_unregister_multiple(cli_rpt
, sizeof(cli_rpt
) / sizeof(struct ast_cli_entry
));
8032 static int load_module(void)
8034 struct ast_config
*cfg
= ast_config_load("rpt.conf");
8036 ast_log(LOG_WARNING
, "No such configuration file rpt.conf\n");
8037 return AST_MODULE_LOAD_DECLINE
;
8039 ast_pthread_create(&rpt_master_thread
,NULL
,rpt_master
,cfg
);
8041 /* Register cli extensions */
8042 ast_cli_register_multiple(cli_rpt
, sizeof(cli_rpt
) / sizeof(struct ast_cli_entry
));
8044 return ast_register_application(app
, rpt_exec
, synopsis
, descrip
);
8047 static int reload(void)
8051 for(n
= 0; n
< nrpts
; n
++) rpt_vars
[n
].reload
= 1;
8055 AST_MODULE_INFO(ASTERISK_GPL_KEY
, AST_MODFLAG_DEFAULT
, "Radio Repeater / Remote Base",
8056 .load
= load_module
,
8057 .unload
= unload_module
,