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
;
404 char *link_functions
;
405 char *phone_functions
;
406 char *dphone_functions
;
412 int tailsquashedtime
;
415 char *tailmessages
[500];
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_debug
=
730 { { "rpt", "debug", "level" }, rpt_do_debug
,
731 "Enable app_rpt debugging", debug_usage
};
733 static struct ast_cli_entry cli_dump
=
734 { { "rpt", "dump" }, rpt_do_dump
,
735 "Dump app_rpt structs for debugging", dump_usage
};
737 static struct ast_cli_entry cli_stats
=
738 { { "rpt", "stats" }, rpt_do_stats
,
739 "Dump node statistics", dump_stats
};
741 static struct ast_cli_entry cli_lstats
=
742 { { "rpt", "lstats" }, rpt_do_lstats
,
743 "Dump link statistics", dump_lstats
};
745 static struct ast_cli_entry cli_reload
=
746 { { "rpt", "reload" }, rpt_do_reload
,
747 "Reload app_rpt config", reload_usage
};
749 static struct ast_cli_entry cli_restart
=
750 { { "rpt", "restart" }, rpt_do_restart
,
751 "Restart app_rpt", restart_usage
};
758 static struct telem_defaults tele_defs
[] = {
759 {"ct1","|t(350,0,100,3072)(500,0,100,3072)(660,0,100,3072)"},
760 {"ct2","|t(660,880,150,3072)"},
761 {"ct3","|t(440,0,150,3072)"},
762 {"ct4","|t(550,0,150,3072)"},
763 {"ct5","|t(660,0,150,3072)"},
764 {"ct6","|t(880,0,150,3072)"},
765 {"ct7","|t(660,440,150,3072)"},
766 {"ct8","|t(700,1100,150,3072)"},
767 {"remotemon","|t(1600,0,75,2048)"},
768 {"remotetx","|t(2000,0,75,2048)(0,0,75,0)(1600,0,75,2048)"},
769 {"cmdmode","|t(900,904,200,2048)"},
770 {"functcomplete","|t(1000,0,100,2048)(0,0,100,0)(1000,0,100,2048)"}
774 * Forward decl's - these suppress compiler warnings when funcs coded further down the file than thier invokation
777 static int setrbi(struct rpt
*myrpt
);
782 * Define function protos for function table here
785 static int function_ilink(struct rpt
*myrpt
, char *param
, char *digitbuf
, int command_source
, struct rpt_link
*mylink
);
786 static int function_autopatchup(struct rpt
*myrpt
, char *param
, char *digitbuf
, int command_source
, struct rpt_link
*mylink
);
787 static int function_autopatchdn(struct rpt
*myrpt
, char *param
, char *digitbuf
, int command_source
, struct rpt_link
*mylink
);
788 static int function_status(struct rpt
*myrpt
, char *param
, char *digitbuf
, int command_source
, struct rpt_link
*mylink
);
789 static int function_cop(struct rpt
*myrpt
, char *param
, char *digitbuf
, int command_source
, struct rpt_link
*mylink
);
790 static int function_remote(struct rpt
*myrpt
, char *param
, char *digitbuf
, int command_source
, struct rpt_link
*mylink
);
791 static int function_macro(struct rpt
*myrpt
, char *param
, char *digitbuf
, int command_source
, struct rpt_link
*mylink
);
796 static struct function_table_tag function_table
[] = {
797 {"cop", function_cop
},
798 {"autopatchup", function_autopatchup
},
799 {"autopatchdn", function_autopatchdn
},
800 {"ilink", function_ilink
},
801 {"status", function_status
},
802 {"remote", function_remote
},
803 {"macro", function_macro
}
807 * Break up a delimited string into a table of substrings
809 * str - delimited string ( will be modified )
810 * strp- list of pointers to substrings (this is built by this function), NULL will be placed at end of list
811 * limit- maximum number of substrings to process
816 static int finddelim(char *str
, char *strp
[], int limit
)
828 for(l
= 0; *str
&& (l
< limit
) ; str
++)
830 if (*str
== QUOTECHR
)
839 strp
[i
- 1] = str
+ 1;
843 if ((*str
== DELIMCHR
) && (!inquo
))
856 * Match a keyword in a list, and return index of string plus 1 if there was a match,
857 * else return 0. If param is passed in non-null, then it will be set to the first character past the match
860 static int matchkeyword(char *string
, char **param
, char *keywords
[])
863 for( i
= 0 ; keywords
[i
] ; i
++){
864 ls
= strlen(keywords
[i
]);
869 if(!strncmp(string
, keywords
[i
], ls
)){
871 *param
= string
+ ls
;
880 * Skip characters in string which are in charlist, and return a pointer to the
881 * first non-matching character
884 static char *skipchars(char *string
, char *charlist
)
888 for(i
= 0; charlist
[i
] ; i
++){
889 if(*string
== charlist
[i
]){
902 static int myatoi(char *str
)
906 if (str
== NULL
) return -1;
907 /* leave this %i alone, non-base-10 input is useful here */
908 if (sscanf(str
,"%i",&ret
) != 1) return -1;
915 /* rpt filter routine */
916 static void rpt_filter(struct rpt
*myrpt
, volatile short *buf
, int len
)
921 for(i
= 0; i
< len
; i
++)
923 for(j
= 0; j
< MAXFILTERS
; j
++)
925 f
= &myrpt
->filters
[j
];
926 if (!*f
->desc
) continue;
927 f
->x0
= f
->x1
; f
->x1
= f
->x2
;
928 f
->x2
= ((float)buf
[i
]) / f
->gain
;
929 f
->y0
= f
->y1
; f
->y1
= f
->y2
;
930 f
->y2
= (f
->x0
+ f
->x2
) + f
->const0
* f
->x1
931 + (f
->const1
* f
->y0
) + (f
->const2
* f
->y1
);
932 buf
[i
] = (short)f
->y2
;
939 /* Retrieve an int from a config file */
941 static int retrieve_astcfgint(struct rpt
*myrpt
,char *category
, char *name
, int min
, int max
, int defl
)
946 var
= ast_variable_retrieve(myrpt
->cfg
, category
, name
);
960 static void load_rpt_vars(int n
,int init
)
964 struct ast_variable
*vp
;
965 struct ast_config
*cfg
;
971 if (option_verbose
> 2)
972 ast_verbose(VERBOSE_PREFIX_3
"%s config for repeater %s\n",
973 (init
) ? "Loading initial" : "Re-Loading",rpt_vars
[n
].name
);
974 ast_mutex_lock(&rpt_vars
[n
].lock
);
975 if (rpt_vars
[n
].cfg
) ast_config_destroy(rpt_vars
[n
].cfg
);
976 cfg
= ast_config_load("rpt.conf");
978 ast_mutex_unlock(&rpt_vars
[n
].lock
);
979 ast_log(LOG_NOTICE
, "Unable to open radio repeater configuration rpt.conf. Radio Repeater disabled.\n");
982 rpt_vars
[n
].cfg
= cfg
;
983 this = rpt_vars
[n
].name
;
984 memset(&rpt_vars
[n
].p
,0,sizeof(rpt_vars
[n
].p
));
988 int savearea
= (char *)&rpt_vars
[n
].p
- (char *)&rpt_vars
[n
];
990 cp
= (char *) &rpt_vars
[n
].p
;
991 memset(cp
+ sizeof(rpt_vars
[n
].p
),0,
992 sizeof(rpt_vars
[n
]) - (sizeof(rpt_vars
[n
].p
) + savearea
));
993 rpt_vars
[n
].tele
.next
= &rpt_vars
[n
].tele
;
994 rpt_vars
[n
].tele
.prev
= &rpt_vars
[n
].tele
;
995 rpt_vars
[n
].rpt_thread
= AST_PTHREADT_NULL
;
996 rpt_vars
[n
].tailmessagen
= 0;
999 /* zot out filters stuff */
1000 memset(&rpt_vars
[n
].filters
,0,sizeof(rpt_vars
[n
].filters
));
1002 val
= ast_variable_retrieve(cfg
,this,"context");
1003 if (val
) rpt_vars
[n
].p
.ourcontext
= val
;
1004 else rpt_vars
[n
].p
.ourcontext
= this;
1005 val
= ast_variable_retrieve(cfg
,this,"callerid");
1006 if (val
) rpt_vars
[n
].p
.ourcallerid
= val
;
1007 val
= ast_variable_retrieve(cfg
,this,"accountcode");
1008 if (val
) rpt_vars
[n
].p
.acctcode
= val
;
1009 val
= ast_variable_retrieve(cfg
,this,"idrecording");
1010 if (val
) rpt_vars
[n
].p
.ident
= val
;
1011 val
= ast_variable_retrieve(cfg
,this,"hangtime");
1012 if (val
) rpt_vars
[n
].p
.hangtime
= atoi(val
);
1013 else rpt_vars
[n
].p
.hangtime
= HANGTIME
;
1014 val
= ast_variable_retrieve(cfg
,this,"totime");
1015 if (val
) rpt_vars
[n
].p
.totime
= atoi(val
);
1016 else rpt_vars
[n
].p
.totime
= TOTIME
;
1017 rpt_vars
[n
].p
.tailmessagetime
= retrieve_astcfgint(&rpt_vars
[n
],this, "tailmessagetime", 0, 2400000, 0);
1018 rpt_vars
[n
].p
.tailsquashedtime
= retrieve_astcfgint(&rpt_vars
[n
],this, "tailsquashedtime", 0, 2400000, 0);
1019 rpt_vars
[n
].p
.duplex
= retrieve_astcfgint(&rpt_vars
[n
],this,"duplex",0,4,2);
1020 rpt_vars
[n
].p
.idtime
= retrieve_astcfgint(&rpt_vars
[n
],this, "idtime", 60000, 2400000, IDTIME
); /* Enforce a min max */
1021 rpt_vars
[n
].p
.politeid
= retrieve_astcfgint(&rpt_vars
[n
],this, "politeid", 30000, 300000, POLITEID
); /* Enforce a min max */
1022 val
= ast_variable_retrieve(cfg
,this,"tonezone");
1023 if (val
) rpt_vars
[n
].p
.tonezone
= val
;
1024 rpt_vars
[n
].p
.tailmessages
[0] = 0;
1025 rpt_vars
[n
].p
.tailmessagemax
= 0;
1026 val
= ast_variable_retrieve(cfg
,this,"tailmessagelist");
1027 if (val
) rpt_vars
[n
].p
.tailmessagemax
= finddelim(val
, rpt_vars
[n
].p
.tailmessages
, 500);
1028 val
= ast_variable_retrieve(cfg
,this,"memory");
1029 if (!val
) val
= MEMORY
;
1030 rpt_vars
[n
].p
.memory
= val
;
1031 val
= ast_variable_retrieve(cfg
,this,"macro");
1032 if (!val
) val
= MACRO
;
1033 rpt_vars
[n
].p
.macro
= val
;
1034 val
= ast_variable_retrieve(cfg
,this,"startup_macro");
1035 if (val
) rpt_vars
[n
].p
.startupmacro
= val
;
1036 val
= ast_variable_retrieve(cfg
,this,"iobase");
1037 /* do not use atoi() here, we need to be able to have
1038 the input specified in hex or decimal so we use
1040 if ((!val
) || (sscanf(val
,"%i",&rpt_vars
[n
].p
.iobase
) != 1))
1041 rpt_vars
[n
].p
.iobase
= DEFAULT_IOBASE
;
1042 val
= ast_variable_retrieve(cfg
,this,"functions");
1046 rpt_vars
[n
].p
.simple
= 1;
1048 rpt_vars
[n
].p
.functions
= val
;
1049 val
= ast_variable_retrieve(cfg
,this,"link_functions");
1050 if (val
) rpt_vars
[n
].p
.link_functions
= val
;
1052 rpt_vars
[n
].p
.link_functions
= rpt_vars
[n
].p
.functions
;
1053 val
= ast_variable_retrieve(cfg
,this,"phone_functions");
1054 if (val
) rpt_vars
[n
].p
.phone_functions
= val
;
1055 val
= ast_variable_retrieve(cfg
,this,"dphone_functions");
1056 if (val
) rpt_vars
[n
].p
.dphone_functions
= val
;
1057 val
= ast_variable_retrieve(cfg
,this,"funcchar");
1058 if (!val
) rpt_vars
[n
].p
.funcchar
= FUNCCHAR
; else
1059 rpt_vars
[n
].p
.funcchar
= *val
;
1060 val
= ast_variable_retrieve(cfg
,this,"endchar");
1061 if (!val
) rpt_vars
[n
].p
.endchar
= ENDCHAR
; else
1062 rpt_vars
[n
].p
.endchar
= *val
;
1063 val
= ast_variable_retrieve(cfg
,this,"nobusyout");
1064 if (val
) rpt_vars
[n
].p
.nobusyout
= ast_true(val
);
1065 val
= ast_variable_retrieve(cfg
,this,"nodes");
1066 if (!val
) val
= NODES
;
1067 rpt_vars
[n
].p
.nodes
= val
;
1069 val
= ast_variable_retrieve(cfg
,this,"rxnotch");
1071 i
= finddelim(val
,strs
,MAXFILTERS
* 2);
1072 i
&= ~1; /* force an even number, rounded down */
1073 if (i
>= 2) for(j
= 0; j
< i
; j
+= 2)
1075 rpt_mknotch(atof(strs
[j
]),atof(strs
[j
+ 1]),
1076 &rpt_vars
[n
].filters
[j
>> 1].gain
,
1077 &rpt_vars
[n
].filters
[j
>> 1].const0
,
1078 &rpt_vars
[n
].filters
[j
>> 1].const1
,
1079 &rpt_vars
[n
].filters
[j
>> 1].const2
);
1080 sprintf(rpt_vars
[n
].filters
[j
>> 1].desc
,"%s Hz, BW = %s",
1081 strs
[j
],strs
[j
+ 1]);
1088 vp
= ast_variable_browse(cfg
, rpt_vars
[n
].p
.nodes
);
1091 j
= strlen(vp
->name
);
1092 if (j
> longestnode
)
1097 rpt_vars
[n
].longestnode
= longestnode
;
1100 * For this repeater, Determine the length of the longest function
1102 rpt_vars
[n
].longestfunc
= 0;
1103 vp
= ast_variable_browse(cfg
, rpt_vars
[n
].p
.functions
);
1105 j
= strlen(vp
->name
);
1106 if (j
> rpt_vars
[n
].longestfunc
)
1107 rpt_vars
[n
].longestfunc
= j
;
1111 * For this repeater, Determine the length of the longest function
1113 rpt_vars
[n
].link_longestfunc
= 0;
1114 vp
= ast_variable_browse(cfg
, rpt_vars
[n
].p
.link_functions
);
1116 j
= strlen(vp
->name
);
1117 if (j
> rpt_vars
[n
].link_longestfunc
)
1118 rpt_vars
[n
].link_longestfunc
= j
;
1121 rpt_vars
[n
].phone_longestfunc
= 0;
1122 if (rpt_vars
[n
].p
.phone_functions
)
1124 vp
= ast_variable_browse(cfg
, rpt_vars
[n
].p
.phone_functions
);
1126 j
= strlen(vp
->name
);
1127 if (j
> rpt_vars
[n
].phone_longestfunc
)
1128 rpt_vars
[n
].phone_longestfunc
= j
;
1132 rpt_vars
[n
].dphone_longestfunc
= 0;
1133 if (rpt_vars
[n
].p
.dphone_functions
)
1135 vp
= ast_variable_browse(cfg
, rpt_vars
[n
].p
.dphone_functions
);
1137 j
= strlen(vp
->name
);
1138 if (j
> rpt_vars
[n
].dphone_longestfunc
)
1139 rpt_vars
[n
].dphone_longestfunc
= j
;
1143 rpt_vars
[n
].macro_longest
= 1;
1144 vp
= ast_variable_browse(cfg
, rpt_vars
[n
].p
.macro
);
1146 j
= strlen(vp
->name
);
1147 if (j
> rpt_vars
[n
].macro_longest
)
1148 rpt_vars
[n
].macro_longest
= j
;
1151 ast_mutex_unlock(&rpt_vars
[n
].lock
);
1155 * Enable or disable debug output at a given level at the console
1158 static int rpt_do_debug(int fd
, int argc
, char *argv
[])
1163 return RESULT_SHOWUSAGE
;
1164 newlevel
= myatoi(argv
[3]);
1165 if((newlevel
< 0) || (newlevel
> 7))
1166 return RESULT_SHOWUSAGE
;
1168 ast_cli(fd
, "app_rpt Debugging enabled, previous level: %d, new level: %d\n", debug
, newlevel
);
1170 ast_cli(fd
, "app_rpt Debugging disabled\n");
1173 return RESULT_SUCCESS
;
1177 * Dump rpt struct debugging onto console
1180 static int rpt_do_dump(int fd
, int argc
, char *argv
[])
1185 return RESULT_SHOWUSAGE
;
1187 for(i
= 0; i
< nrpts
; i
++)
1189 if (!strcmp(argv
[2],rpt_vars
[i
].name
))
1191 rpt_vars
[i
].disgorgetime
= time(NULL
) + 10; /* Do it 10 seconds later */
1192 ast_cli(fd
, "app_rpt struct dump requested for node %s\n",argv
[2]);
1193 return RESULT_SUCCESS
;
1196 return RESULT_FAILURE
;
1200 * Dump statistics onto console
1203 static int rpt_do_stats(int fd
, int argc
, char *argv
[])
1206 int dailytxtime
, dailykerchunks
;
1207 int totalkerchunks
, dailykeyups
, totalkeyups
, timeouts
;
1208 int totalexecdcommands
, dailyexecdcommands
, hours
, minutes
, seconds
;
1209 long long totaltxtime
;
1211 char *listoflinks
[MAX_STAT_LINKS
];
1212 char *lastnodewhichkeyedusup
, *lastdtmfcommand
;
1213 char *tot_state
, *ider_state
, *patch_state
;
1214 char *reverse_patch_state
, *enable_state
, *input_signal
, *called_number
;
1217 static char *not_applicable
= "N/A";
1220 return RESULT_SHOWUSAGE
;
1222 for(i
= 0 ; i
<= MAX_STAT_LINKS
; i
++)
1223 listoflinks
[i
] = NULL
;
1225 tot_state
= ider_state
=
1226 patch_state
= reverse_patch_state
=
1227 input_signal
= called_number
=
1228 lastdtmfcommand
= not_applicable
;
1230 for(i
= 0; i
< nrpts
; i
++)
1232 if (!strcmp(argv
[2],rpt_vars
[i
].name
)){
1233 /* Make a copy of all stat variables while locked */
1234 myrpt
= &rpt_vars
[i
];
1235 rpt_mutex_lock(&myrpt
->lock
); /* LOCK */
1237 dailytxtime
= myrpt
->dailytxtime
;
1238 totaltxtime
= myrpt
->totaltxtime
;
1239 dailykeyups
= myrpt
->dailykeyups
;
1240 totalkeyups
= myrpt
->totalkeyups
;
1241 dailykerchunks
= myrpt
->dailykerchunks
;
1242 totalkerchunks
= myrpt
->totalkerchunks
;
1243 dailyexecdcommands
= myrpt
->dailyexecdcommands
;
1244 totalexecdcommands
= myrpt
->totalexecdcommands
;
1245 timeouts
= myrpt
->timeouts
;
1247 /* Traverse the list of connected nodes */
1248 reverse_patch_state
= "DOWN";
1250 l
= myrpt
->links
.next
;
1251 while(l
!= &myrpt
->links
){
1252 if (l
->name
[0] == '0'){ /* Skip '0' nodes */
1253 reverse_patch_state
= "UP";
1257 listoflinks
[j
] = ast_strdupa(l
->name
);
1263 lastnodewhichkeyedusup
= ast_strdupa(myrpt
->lastnodewhichkeyedusup
);
1264 if((!lastnodewhichkeyedusup
) || (!strlen(lastnodewhichkeyedusup
)))
1265 lastnodewhichkeyedusup
= not_applicable
;
1268 input_signal
= "YES";
1270 input_signal
= "NO";
1273 enable_state
= "YES";
1275 enable_state
= "NO";
1278 tot_state
= "TIMED OUT!";
1279 else if(myrpt
->totimer
!= myrpt
->p
.totime
)
1280 tot_state
= "ARMED";
1282 tot_state
= "RESET";
1285 ider_state
= "QUEUED IN TAIL";
1286 else if(myrpt
->mustid
)
1287 ider_state
= "QUEUED FOR CLEANUP";
1289 ider_state
= "CLEAN";
1291 switch(myrpt
->callmode
){
1293 patch_state
= "DIALING";
1296 patch_state
= "CONNECTING";
1303 patch_state
= "CALL FAILED";
1307 patch_state
= "DOWN";
1310 if(strlen(myrpt
->exten
)){
1311 called_number
= ast_strdupa(myrpt
->exten
);
1313 called_number
= not_applicable
;
1316 if(strlen(myrpt
->lastdtmfcommand
)){
1317 lastdtmfcommand
= ast_strdupa(myrpt
->lastdtmfcommand
);
1318 if(!lastdtmfcommand
)
1319 lastdtmfcommand
= not_applicable
;
1322 rpt_mutex_unlock(&myrpt
->lock
); /* UNLOCK */
1324 ast_cli(fd
, "************************ NODE %s STATISTICS *************************\n\n", myrpt
->name
);
1325 ast_cli(fd
, "Signal on input..................................: %s\n", input_signal
);
1326 ast_cli(fd
, "Transmitter enabled..............................: %s\n", enable_state
);
1327 ast_cli(fd
, "Time out timer state.............................: %s\n", tot_state
);
1328 ast_cli(fd
, "Time outs since system initialization............: %d\n", timeouts
);
1329 ast_cli(fd
, "Identifier state.................................: %s\n", ider_state
);
1330 ast_cli(fd
, "Kerchunks today..................................: %d\n", dailykerchunks
);
1331 ast_cli(fd
, "Kerchunks since system initialization............: %d\n", totalkerchunks
);
1332 ast_cli(fd
, "Keyups today.....................................: %d\n", dailykeyups
);
1333 ast_cli(fd
, "Keyups since system initialization...............: %d\n", totalkeyups
);
1334 ast_cli(fd
, "DTMF commands today..............................: %d\n", dailyexecdcommands
);
1335 ast_cli(fd
, "DTMF commands since system initialization........: %d\n", totalexecdcommands
);
1336 ast_cli(fd
, "Last DTMF command executed.......................: %s\n", lastdtmfcommand
);
1338 hours
= dailytxtime
/3600000;
1339 dailytxtime
%= 3600000;
1340 minutes
= dailytxtime
/60000;
1341 dailytxtime
%= 60000;
1342 seconds
= dailytxtime
/1000;
1343 dailytxtime
%= 1000;
1345 ast_cli(fd
, "TX time today ...................................: %02d:%02d:%02d.%d\n",
1346 hours
, minutes
, seconds
, dailytxtime
);
1348 hours
= (int) totaltxtime
/3600000;
1349 totaltxtime
%= 3600000;
1350 minutes
= (int) totaltxtime
/60000;
1351 totaltxtime
%= 60000;
1352 seconds
= (int) totaltxtime
/1000;
1353 totaltxtime
%= 1000;
1355 ast_cli(fd
, "TX time since system initialization..............: %02d:%02d:%02d.%d\n",
1356 hours
, minutes
, seconds
, (int) totaltxtime
);
1357 ast_cli(fd
, "Nodes currently connected to us..................: ");
1359 if(!listoflinks
[j
]){
1361 ast_cli(fd
,"<NONE>");
1365 ast_cli(fd
, "%s", listoflinks
[j
]);
1371 if(listoflinks
[j
+ 1])
1377 ast_cli(fd
, "Last node which transmitted to us................: %s\n", lastnodewhichkeyedusup
);
1378 ast_cli(fd
, "Autopatch state..................................: %s\n", patch_state
);
1379 ast_cli(fd
, "Autopatch called number..........................: %s\n", called_number
);
1380 ast_cli(fd
, "Reverse patch/IAXRPT connected...................: %s\n\n", reverse_patch_state
);
1382 return RESULT_SUCCESS
;
1385 return RESULT_FAILURE
;
1389 * Link stats function
1392 static int rpt_do_lstats(int fd
, int argc
, char *argv
[])
1397 struct rpt_lstat
*s
,*t
;
1398 struct rpt_lstat s_head
;
1400 return RESULT_SHOWUSAGE
;
1403 s_head
.next
= &s_head
;
1404 s_head
.prev
= &s_head
;
1406 for(i
= 0; i
< nrpts
; i
++)
1408 if (!strcmp(argv
[2],rpt_vars
[i
].name
)){
1409 /* Make a copy of all stat variables while locked */
1410 myrpt
= &rpt_vars
[i
];
1411 rpt_mutex_lock(&myrpt
->lock
); /* LOCK */
1412 /* Traverse the list of connected nodes */
1414 l
= myrpt
->links
.next
;
1415 while(l
!= &myrpt
->links
){
1416 if (l
->name
[0] == '0'){ /* Skip '0' nodes */
1420 if((s
= (struct rpt_lstat
*) malloc(sizeof(struct rpt_lstat
))) == NULL
){
1421 ast_log(LOG_ERROR
, "Malloc failed in rpt_do_lstats\n");
1422 rpt_mutex_unlock(&myrpt
->lock
); /* UNLOCK */
1423 return RESULT_FAILURE
;
1425 memset(s
, 0, sizeof(struct rpt_lstat
));
1426 strncpy(s
->name
, l
->name
, MAXREMSTR
- 1);
1427 pbx_substitute_variables_helper(l
->chan
, "${IAXPEER(CURRENTCHANNEL)}", s
->peer
, MAXPEERSTR
- 1);
1429 s
->outbound
= l
->outbound
;
1430 s
->reconnects
= l
->reconnects
;
1431 s
->connecttime
= l
->connecttime
;
1432 insque((struct qelem
*) s
, (struct qelem
*) s_head
.next
);
1435 rpt_mutex_unlock(&myrpt
->lock
); /* UNLOCK */
1436 ast_cli(fd
, "NODE PEER RECONNECTS DIRECTION CONNECT TIME\n");
1437 ast_cli(fd
, "---- ---- ---------- --------- ------------\n");
1439 for(s
= s_head
.next
; s
!= &s_head
; s
= s
->next
){
1440 int hours
, minutes
, seconds
;
1441 long long connecttime
= s
->connecttime
;
1443 hours
= (int) connecttime
/3600000;
1444 connecttime
%= 3600000;
1445 minutes
= (int) connecttime
/60000;
1446 connecttime
%= 60000;
1447 seconds
= (int) connecttime
/1000;
1448 connecttime
%= 1000;
1449 snprintf(conntime
, 30, "%02d:%02d:%02d.%d",
1450 hours
, minutes
, seconds
, (int) connecttime
);
1452 ast_cli(fd
, "%-10s%-20s%-12d%-11s%-30s\n",
1453 s
->name
, s
->peer
, s
->reconnects
, (s
->outbound
)? "OUT":"IN", conntime
);
1455 /* destroy our local link queue */
1457 while(s
!= &s_head
){
1460 remque((struct qelem
*)t
);
1463 return RESULT_SUCCESS
;
1466 return RESULT_FAILURE
;
1473 static int rpt_do_reload(int fd
, int argc
, char *argv
[])
1477 if (argc
> 2) return RESULT_SHOWUSAGE
;
1479 for(n
= 0; n
< nrpts
; n
++) rpt_vars
[n
].reload
= 1;
1481 return RESULT_FAILURE
;
1488 static int rpt_do_restart(int fd
, int argc
, char *argv
[])
1492 if (argc
> 2) return RESULT_SHOWUSAGE
;
1493 for(i
= 0; i
< nrpts
; i
++)
1495 if (rpt_vars
[i
].rxchannel
) ast_softhangup(rpt_vars
[i
].rxchannel
,AST_SOFTHANGUP_DEV
);
1497 return RESULT_FAILURE
;
1500 static int play_tone_pair(struct ast_channel
*chan
, int f1
, int f2
, int duration
, int amplitude
)
1504 if ((res
= ast_tonepair_start(chan
, f1
, f2
, duration
, amplitude
)))
1507 while(chan
->generatordata
) {
1508 if (ast_safe_sleep(chan
,1)) return -1;
1514 static int play_tone(struct ast_channel
*chan
, int freq
, int duration
, int amplitude
)
1516 return play_tone_pair(chan
, freq
, 0, duration
, amplitude
);
1519 static int play_silence(struct ast_channel
*chan
, int duration
)
1521 return play_tone_pair(chan
, 0, 0, duration
, 0);
1525 static int send_morse(struct ast_channel
*chan
, char *string
, int speed
, int freq
, int amplitude
)
1528 static struct morse_bits mbits
[] = {
1593 int intralettertime
;
1594 int interlettertime
;
1604 /* Approximate the dot time from the speed arg. */
1606 dottime
= 900/speed
;
1608 /* Establish timing releationships */
1610 dashtime
= 3 * dottime
;
1611 intralettertime
= dottime
;
1612 interlettertime
= dottime
* 4 ;
1613 interwordtime
= dottime
* 7;
1615 for(;(*string
) && (!res
); string
++){
1619 /* Convert lower case to upper case */
1621 if((c
>= 'a') && (c
<= 'z'))
1624 /* Can't deal with any char code greater than Z, skip it */
1629 /* If space char, wait the inter word time */
1633 res
= play_silence(chan
, interwordtime
);
1637 /* Subtract out control char offset to match our table */
1641 /* Get the character data */
1644 ddcomb
= mbits
[c
].ddcomb
;
1646 /* Send the character */
1650 res
= play_tone(chan
, freq
, (ddcomb
& 1) ? dashtime
: dottime
, amplitude
);
1652 res
= play_silence(chan
, intralettertime
);
1656 /* Wait the interletter time */
1659 res
= play_silence(chan
, interlettertime
- intralettertime
);
1662 /* Wait for all the frames to be sent */
1665 res
= ast_waitstream(chan
, "");
1666 ast_stopstream(chan
);
1669 * Wait for the zaptel driver to physically write the tone blocks to the hardware
1672 for(i
= 0; i
< 20 ; i
++){
1673 flags
= ZT_IOMUX_WRITEEMPTY
| ZT_IOMUX_NOWAIT
;
1674 res
= ioctl(chan
->fds
[0], ZT_IOMUX
, &flags
);
1675 if(flags
& ZT_IOMUX_WRITEEMPTY
)
1677 if( ast_safe_sleep(chan
, 50)){
1687 static int send_tone_telemetry(struct ast_channel
*chan
, char *tonestring
)
1700 stringp
= ast_strdupa(tonestring
);
1703 tonesubset
= strsep(&stringp
,")");
1706 if(sscanf(tonesubset
,"(%d,%d,%d,%d", &f1
, &f2
, &duration
, &litude
) != 4)
1708 res
= play_tone_pair(chan
, f1
, f2
, duration
, amplitude
);
1713 res
= play_tone_pair(chan
, 0, 0, 100, 0); /* This is needed to ensure the last tone segment is timed correctly */
1716 res
= ast_waitstream(chan
, "");
1717 ast_stopstream(chan
);
1720 * Wait for the zaptel driver to physically write the tone blocks to the hardware
1723 for(i
= 0; i
< 20 ; i
++){
1724 flags
= ZT_IOMUX_WRITEEMPTY
| ZT_IOMUX_NOWAIT
;
1725 res
= ioctl(chan
->fds
[0], ZT_IOMUX
, &flags
);
1726 if(flags
& ZT_IOMUX_WRITEEMPTY
)
1728 if( ast_safe_sleep(chan
, 50)){
1739 static int sayfile(struct ast_channel
*mychannel
,char *fname
)
1743 res
= ast_streamfile(mychannel
, fname
, mychannel
->language
);
1745 res
= ast_waitstream(mychannel
, "");
1747 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
1748 ast_stopstream(mychannel
);
1752 static int saycharstr(struct ast_channel
*mychannel
,char *str
)
1756 res
= ast_say_character_str(mychannel
,str
,NULL
,mychannel
->language
);
1758 res
= ast_waitstream(mychannel
, "");
1760 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
1761 ast_stopstream(mychannel
);
1765 static int saynum(struct ast_channel
*mychannel
, int num
)
1768 res
= ast_say_number(mychannel
, num
, NULL
, mychannel
->language
, NULL
);
1770 res
= ast_waitstream(mychannel
, "");
1772 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
1773 ast_stopstream(mychannel
);
1778 static int telem_any(struct rpt
*myrpt
,struct ast_channel
*chan
, char *entry
)
1783 static int morsespeed
;
1784 static int morsefreq
;
1785 static int morseampl
;
1786 static int morseidfreq
= 0;
1787 static int morseidampl
;
1788 static char mcat
[] = MORSE
;
1792 if(!morseidfreq
){ /* Get the morse parameters if not already loaded */
1793 morsespeed
= retrieve_astcfgint(myrpt
, mcat
, "speed", 5, 20, 20);
1794 morsefreq
= retrieve_astcfgint(myrpt
, mcat
, "frequency", 300, 3000, 800);
1795 morseampl
= retrieve_astcfgint(myrpt
, mcat
, "amplitude", 200, 8192, 4096);
1796 morseidampl
= retrieve_astcfgint(myrpt
, mcat
, "idamplitude", 200, 8192, 2048);
1797 morseidfreq
= retrieve_astcfgint(myrpt
, mcat
, "idfrequency", 300, 3000, 330);
1800 /* Is it a file, or a tone sequence? */
1802 if(entry
[0] == '|'){
1804 if((c
>= 'a')&&(c
<= 'z'))
1808 case 'I': /* Morse ID */
1809 res
= send_morse(chan
, entry
+ 2, morsespeed
, morseidfreq
, morseidampl
);
1812 case 'M': /* Morse Message */
1813 res
= send_morse(chan
, entry
+ 2, morsespeed
, morsefreq
, morseampl
);
1816 case 'T': /* Tone sequence */
1817 res
= send_tone_telemetry(chan
, entry
+ 2);
1824 res
= sayfile(chan
, entry
); /* File */
1829 * This function looks up a telemetry name in the config file, and does a telemetry response as configured.
1831 * 4 types of telemtry are handled: Morse ID, Morse Message, Tone Sequence, and a File containing a recording.
1834 static int telem_lookup(struct rpt
*myrpt
,struct ast_channel
*chan
, char *node
, char *name
)
1841 char *telemetry_save
;
1844 telemetry_save
= NULL
;
1847 /* Retrieve the section name for telemetry from the node section */
1848 telemetry
= ast_variable_retrieve(myrpt
->cfg
, node
, TELEMETRY
);
1850 telemetry_save
= ast_strdupa(telemetry
);
1851 if(!telemetry_save
){
1852 ast_log(LOG_WARNING
,"ast_strdupa() failed in telem_lookup()\n");
1855 entry
= ast_variable_retrieve(myrpt
->cfg
, telemetry_save
, name
);
1858 /* Try to look up the telemetry name */
1861 /* Telemetry name wasn't found in the config file, use the default */
1862 for(i
= 0; i
< sizeof(tele_defs
)/sizeof(struct telem_defaults
) ; i
++){
1863 if(!strcasecmp(tele_defs
[i
].name
, name
))
1864 entry
= tele_defs
[i
].value
;
1869 telem_any(myrpt
,chan
, entry
);
1878 * Retrieve a wait interval
1881 static int get_wait_interval(struct rpt
*myrpt
, int type
)
1885 char *wait_times_save
;
1887 wait_times_save
= NULL
;
1888 wait_times
= ast_variable_retrieve(myrpt
->cfg
, myrpt
->name
, "wait_times");
1891 wait_times_save
= ast_strdupa(wait_times
);
1892 if(!wait_times_save
){
1893 ast_log(LOG_WARNING
, "Out of memory in wait_interval()\n");
1901 interval
= retrieve_astcfgint(myrpt
,wait_times_save
, "telemwait", 500, 5000, 1000);
1908 interval
= retrieve_astcfgint(myrpt
,wait_times_save
, "idwait",250,5000,500);
1915 interval
= retrieve_astcfgint(myrpt
,wait_times_save
, "unkeywait",500,5000,1000);
1922 interval
= retrieve_astcfgint(myrpt
,wait_times_save
, "calltermwait",500,5000,1500);
1935 * Wait a configurable interval of time
1939 static void wait_interval(struct rpt
*myrpt
, int type
, struct ast_channel
*chan
)
1942 interval
= get_wait_interval(myrpt
, type
);
1944 ast_log(LOG_NOTICE
," Delay interval = %d\n", interval
);
1946 ast_safe_sleep(chan
,interval
);
1948 ast_log(LOG_NOTICE
,"Delay complete\n");
1953 static void *rpt_tele_thread(void *this)
1955 ZT_CONFINFO ci
; /* conference info */
1956 int res
= 0,haslink
,hastx
,hasremote
,imdone
= 0, unkeys_queued
, x
;
1957 struct rpt_tele
*mytele
= (struct rpt_tele
*)this;
1958 struct rpt_tele
*tlist
;
1960 struct rpt_link
*l
,*m
,linkbase
;
1961 struct ast_channel
*mychannel
;
1962 char *p
,*ct
,*ct_copy
,*ident
, *nodename
;
1966 /* get a pointer to myrpt */
1967 myrpt
= mytele
->rpt
;
1969 /* Snag copies of a few key myrpt variables */
1970 rpt_mutex_lock(&myrpt
->lock
);
1971 nodename
= ast_strdupa(myrpt
->name
);
1972 ident
= ast_strdupa(myrpt
->p
.ident
);
1973 rpt_mutex_unlock(&myrpt
->lock
);
1975 /* allocate a pseudo-channel thru asterisk */
1976 mychannel
= ast_request("zap",AST_FORMAT_SLINEAR
,"pseudo",NULL
);
1979 fprintf(stderr
,"rpt:Sorry unable to obtain pseudo channel\n");
1980 rpt_mutex_lock(&myrpt
->lock
);
1981 remque((struct qelem
*)mytele
);
1982 ast_log(LOG_NOTICE
,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__
, mytele
->mode
); /*@@@@@@@@@@@*/
1983 rpt_mutex_unlock(&myrpt
->lock
);
1987 rpt_mutex_lock(&myrpt
->lock
);
1988 mytele
->chan
= mychannel
; /* Save a copy of the channel so we can access it externally if need be */
1989 rpt_mutex_unlock(&myrpt
->lock
);
1991 /* make a conference for the tx */
1993 /* If there's an ID queued, or tail message queued, */
1994 /* only connect the ID audio to the local tx conference so */
1995 /* linked systems can't hear it */
1996 ci
.confno
= (((mytele
->mode
== ID
) || (mytele
->mode
== IDTALKOVER
) || (mytele
->mode
== UNKEY
) ||
1997 (mytele
->mode
== TAILMSG
)) ?
1998 myrpt
->txconf
: myrpt
->conf
);
1999 ci
.confmode
= ZT_CONF_CONFANN
;
2000 /* first put the channel on the conference in announce mode */
2001 if (ioctl(mychannel
->fds
[0],ZT_SETCONF
,&ci
) == -1)
2003 ast_log(LOG_WARNING
, "Unable to set conference mode to Announce\n");
2004 rpt_mutex_lock(&myrpt
->lock
);
2005 remque((struct qelem
*)mytele
);
2006 rpt_mutex_unlock(&myrpt
->lock
);
2007 ast_log(LOG_NOTICE
,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__
, mytele
->mode
); /*@@@@@@@@@@@*/
2009 ast_hangup(mychannel
);
2012 ast_stopstream(mychannel
);
2013 switch(mytele
->mode
)
2019 wait_interval(myrpt
, (mytele
->mode
== ID
) ? DLY_ID
: DLY_TELEM
,mychannel
);
2020 res
= telem_any(myrpt
,mychannel
, ident
);
2025 res
= ast_streamfile(mychannel
, myrpt
->p
.tailmessages
[myrpt
->tailmessagen
], mychannel
->language
);
2029 p
= ast_variable_retrieve(myrpt
->cfg
, nodename
, "idtalkover");
2031 res
= telem_any(myrpt
,mychannel
, p
);
2036 /* wait a little bit longer */
2037 wait_interval(myrpt
, DLY_TELEM
, mychannel
);
2038 res
= telem_lookup(myrpt
, mychannel
, myrpt
->name
, "patchup");
2039 if(res
< 0){ /* Then default message */
2040 res
= ast_streamfile(mychannel
, "rpt/callproceeding", mychannel
->language
);
2044 /* wait a little bit longer */
2045 wait_interval(myrpt
, DLY_CALLTERM
, mychannel
);
2046 res
= telem_lookup(myrpt
, mychannel
, myrpt
->name
, "patchdown");
2047 if(res
< 0){ /* Then default message */
2048 res
= ast_streamfile(mychannel
, "rpt/callterminated", mychannel
->language
);
2052 /* wait a little bit */
2053 wait_interval(myrpt
, DLY_TELEM
, mychannel
);
2054 res
= telem_lookup(myrpt
,mychannel
, myrpt
->name
, "functcomplete");
2056 case MACRO_NOTFOUND
:
2057 /* wait a little bit */
2058 wait_interval(myrpt
, DLY_TELEM
, mychannel
);
2059 res
= ast_streamfile(mychannel
, "rpt/macro_notfound", mychannel
->language
);
2062 /* wait a little bit */
2063 wait_interval(myrpt
, DLY_TELEM
, mychannel
);
2064 res
= ast_streamfile(mychannel
, "rpt/macro_busy", mychannel
->language
);
2067 if(myrpt
->patchnoct
&& myrpt
->callmode
){ /* If no CT during patch configured, then don't send one */
2073 * Reset the Unkey to CT timer
2076 x
= get_wait_interval(myrpt
, DLY_UNKEY
);
2077 rpt_mutex_lock(&myrpt
->lock
);
2078 myrpt
->unkeytocttimer
= x
; /* Must be protected as it is changed below */
2079 rpt_mutex_unlock(&myrpt
->lock
);
2082 * If there's one already queued, don't do another
2085 tlist
= myrpt
->tele
.next
;
2087 if (tlist
!= &myrpt
->tele
)
2089 rpt_mutex_lock(&myrpt
->lock
);
2090 while(tlist
!= &myrpt
->tele
){
2091 if (tlist
->mode
== UNKEY
) unkeys_queued
++;
2092 tlist
= tlist
->next
;
2094 rpt_mutex_unlock(&myrpt
->lock
);
2096 if( unkeys_queued
> 1){
2101 /* Wait for the telemetry timer to expire */
2102 /* Periodically check the timer since it can be re-initialized above */
2103 while(myrpt
->unkeytocttimer
)
2106 if(myrpt
->unkeytocttimer
> 100)
2109 ctint
= myrpt
->unkeytocttimer
;
2110 ast_safe_sleep(mychannel
, ctint
);
2111 rpt_mutex_lock(&myrpt
->lock
);
2112 if(myrpt
->unkeytocttimer
< ctint
)
2113 myrpt
->unkeytocttimer
= 0;
2115 myrpt
->unkeytocttimer
-= ctint
;
2116 rpt_mutex_unlock(&myrpt
->lock
);
2120 * Now, the carrier on the rptr rx should be gone.
2121 * If it re-appeared, then forget about sending the CT
2128 rpt_mutex_lock(&myrpt
->lock
); /* Update the kerchunk counters */
2129 myrpt
->dailykerchunks
++;
2130 myrpt
->totalkerchunks
++;
2131 rpt_mutex_unlock(&myrpt
->lock
);
2136 l
= myrpt
->links
.next
;
2137 if (l
!= &myrpt
->links
)
2139 rpt_mutex_lock(&myrpt
->lock
);
2140 while(l
!= &myrpt
->links
)
2142 if (l
->name
[0] == '0')
2150 if (l
->isremote
) hasremote
++;
2154 rpt_mutex_unlock(&myrpt
->lock
);
2159 res
= telem_lookup(myrpt
,mychannel
, myrpt
->name
, (!hastx
) ? "remotemon" : "remotetx");
2161 ast_log(LOG_WARNING
, "telem_lookup:remotexx failed on %s\n", mychannel
->name
);
2164 /* if in remote cmd mode, indicate it */
2165 if (myrpt
->cmdnode
[0])
2167 ast_safe_sleep(mychannel
,200);
2168 res
= telem_lookup(myrpt
,mychannel
, myrpt
->name
, "cmdmode");
2170 ast_log(LOG_WARNING
, "telem_lookup:cmdmode failed on %s\n", mychannel
->name
);
2171 ast_stopstream(mychannel
);
2174 else if((ct
= ast_variable_retrieve(myrpt
->cfg
, nodename
, "unlinkedct"))){ /* Unlinked Courtesy Tone */
2175 ct_copy
= ast_strdupa(ct
);
2176 res
= telem_lookup(myrpt
,mychannel
, myrpt
->name
, ct_copy
);
2178 ast_log(LOG_WARNING
, "telem_lookup:ctx failed on %s\n", mychannel
->name
);
2180 if (hasremote
&& (!myrpt
->cmdnode
[0]))
2182 /* set for all to hear */
2184 ci
.confno
= myrpt
->conf
;
2185 ci
.confmode
= ZT_CONF_CONFANN
;
2186 /* first put the channel on the conference in announce mode */
2187 if (ioctl(mychannel
->fds
[0],ZT_SETCONF
,&ci
) == -1)
2189 ast_log(LOG_WARNING
, "Unable to set conference mode to Announce\n");
2190 rpt_mutex_lock(&myrpt
->lock
);
2191 remque((struct qelem
*)mytele
);
2192 rpt_mutex_unlock(&myrpt
->lock
);
2193 ast_log(LOG_NOTICE
,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__
, mytele
->mode
); /*@@@@@@@@@@@*/
2195 ast_hangup(mychannel
);
2198 if((ct
= ast_variable_retrieve(myrpt
->cfg
, nodename
, "remotect"))){ /* Unlinked Courtesy Tone */
2199 ast_safe_sleep(mychannel
,200);
2200 ct_copy
= ast_strdupa(ct
);
2201 res
= telem_lookup(myrpt
,mychannel
, myrpt
->name
, ct_copy
);
2203 ast_log(LOG_WARNING
, "telem_lookup:ctx failed on %s\n", mychannel
->name
);
2206 #ifdef _MDC_DECODE_H_
2207 if (myrpt
->lastunit
)
2211 ast_safe_sleep(mychannel
,200);
2212 /* set for all to hear */
2214 ci
.confno
= myrpt
->txconf
;
2215 ci
.confmode
= ZT_CONF_CONFANN
;
2216 /* first put the channel on the conference in announce mode */
2217 if (ioctl(mychannel
->fds
[0],ZT_SETCONF
,&ci
) == -1)
2219 ast_log(LOG_WARNING
, "Unable to set conference mode to Announce\n");
2220 rpt_mutex_lock(&myrpt
->lock
);
2221 remque((struct qelem
*)mytele
);
2222 rpt_mutex_unlock(&myrpt
->lock
);
2223 ast_log(LOG_NOTICE
,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__
, mytele
->mode
); /*@@@@@@@@@@@*/
2225 ast_hangup(mychannel
);
2228 sprintf(mystr
,"%04x",myrpt
->lastunit
);
2229 myrpt
->lastunit
= 0;
2230 ast_say_character_str(mychannel
,mystr
,NULL
,mychannel
->language
);
2237 /* wait a little bit */
2238 wait_interval(myrpt
, DLY_TELEM
, mychannel
);
2239 res
= ast_streamfile(mychannel
, "rpt/node", mychannel
->language
);
2241 res
= ast_waitstream(mychannel
, "");
2243 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
2244 ast_stopstream(mychannel
);
2245 ast_say_character_str(mychannel
,mytele
->mylink
.name
,NULL
,mychannel
->language
);
2246 res
= ast_streamfile(mychannel
, ((mytele
->mylink
.connected
) ?
2247 "rpt/remote_disc" : "rpt/remote_busy"), mychannel
->language
);
2250 /* wait a little bit */
2251 wait_interval(myrpt
, DLY_TELEM
, mychannel
);
2252 res
= ast_streamfile(mychannel
, "rpt/remote_already", mychannel
->language
);
2255 /* wait a little bit */
2256 wait_interval(myrpt
, DLY_TELEM
, mychannel
);
2257 res
= ast_streamfile(mychannel
, "rpt/remote_notfound", mychannel
->language
);
2260 /* wait a little bit */
2261 wait_interval(myrpt
, DLY_TELEM
, mychannel
);
2262 res
= ast_streamfile(mychannel
, "rpt/remote_go", mychannel
->language
);
2265 /* wait a little bit */
2266 wait_interval(myrpt
, DLY_TELEM
, mychannel
);
2267 res
= ast_streamfile(mychannel
, "rpt/node", mychannel
->language
);
2269 res
= ast_waitstream(mychannel
, "");
2271 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
2272 ast_stopstream(mychannel
);
2273 ast_say_character_str(mychannel
,mytele
->mylink
.name
,NULL
,mychannel
->language
);
2274 res
= ast_streamfile(mychannel
, "rpt/connected", mychannel
->language
);
2277 res
= ast_streamfile(mychannel
, "rpt/node", mychannel
->language
);
2279 res
= ast_waitstream(mychannel
, "");
2281 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
2282 ast_stopstream(mychannel
);
2283 ast_say_character_str(mychannel
,mytele
->mylink
.name
,NULL
,mychannel
->language
);
2284 res
= ast_streamfile(mychannel
, "rpt/connection_failed", mychannel
->language
);
2287 /* wait a little bit */
2288 wait_interval(myrpt
, DLY_TELEM
, mychannel
);
2290 linkbase
.next
= &linkbase
;
2291 linkbase
.prev
= &linkbase
;
2292 rpt_mutex_lock(&myrpt
->lock
);
2293 /* make our own list of links */
2294 l
= myrpt
->links
.next
;
2295 while(l
!= &myrpt
->links
)
2297 if (l
->name
[0] == '0')
2302 m
= malloc(sizeof(struct rpt_link
));
2305 ast_log(LOG_WARNING
, "Cannot alloc memory on %s\n", mychannel
->name
);
2306 remque((struct qelem
*)mytele
);
2307 rpt_mutex_unlock(&myrpt
->lock
);
2308 ast_log(LOG_NOTICE
,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__
, mytele
->mode
); /*@@@@@@@@@@@*/
2310 ast_hangup(mychannel
);
2313 memcpy(m
,l
,sizeof(struct rpt_link
));
2314 m
->next
= m
->prev
= NULL
;
2315 insque((struct qelem
*)m
,(struct qelem
*)linkbase
.next
);
2318 rpt_mutex_unlock(&myrpt
->lock
);
2319 res
= ast_streamfile(mychannel
, "rpt/node", mychannel
->language
);
2321 res
= ast_waitstream(mychannel
, "");
2323 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
2324 ast_stopstream(mychannel
);
2325 ast_say_character_str(mychannel
,myrpt
->name
,NULL
,mychannel
->language
);
2327 res
= ast_waitstream(mychannel
, "");
2329 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
2330 ast_stopstream(mychannel
);
2331 if (myrpt
->callmode
)
2334 res
= ast_streamfile(mychannel
, "rpt/autopatch_on", mychannel
->language
);
2336 res
= ast_waitstream(mychannel
, "");
2338 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
2339 ast_stopstream(mychannel
);
2342 while(l
!= &linkbase
)
2345 res
= ast_streamfile(mychannel
, "rpt/node", mychannel
->language
);
2347 res
= ast_waitstream(mychannel
, "");
2349 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
2350 ast_stopstream(mychannel
);
2351 ast_say_character_str(mychannel
,l
->name
,NULL
,mychannel
->language
);
2353 res
= ast_waitstream(mychannel
, "");
2355 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
2356 ast_stopstream(mychannel
);
2357 res
= ast_streamfile(mychannel
, ((l
->mode
) ?
2358 "rpt/tranceive" : "rpt/monitor"), mychannel
->language
);
2360 res
= ast_waitstream(mychannel
, "");
2362 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
2363 ast_stopstream(mychannel
);
2368 res
= ast_streamfile(mychannel
, "rpt/repeat_only", mychannel
->language
);
2370 res
= ast_waitstream(mychannel
, "");
2372 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
2373 ast_stopstream(mychannel
);
2375 /* destroy our local link queue */
2377 while(l
!= &linkbase
)
2381 remque((struct qelem
*)m
);
2387 case LASTNODEKEY
: /* Identify last node which keyed us up */
2388 rpt_mutex_lock(&myrpt
->lock
);
2389 if(myrpt
->lastnodewhichkeyedusup
)
2390 p
= ast_strdupa(myrpt
->lastnodewhichkeyedusup
); /* Make a local copy of the node name */
2393 rpt_mutex_unlock(&myrpt
->lock
);
2395 imdone
= 1; /* no node previously keyed us up, or the node which did has been disconnected */
2398 wait_interval(myrpt
, DLY_TELEM
, mychannel
);
2399 res
= ast_streamfile(mychannel
, "rpt/node", mychannel
->language
);
2401 res
= ast_waitstream(mychannel
, "");
2403 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
2404 ast_stopstream(mychannel
);
2405 ast_say_character_str(mychannel
, p
, NULL
, mychannel
->language
);
2407 res
= ast_waitstream(mychannel
, "");
2409 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
2410 ast_stopstream(mychannel
);
2415 res
= ast_streamfile(mychannel
, "rpt/node", mychannel
->language
);
2417 res
= ast_waitstream(mychannel
, "");
2419 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
2420 ast_stopstream(mychannel
);
2421 ast_say_character_str(mychannel
,myrpt
->name
,NULL
,mychannel
->language
);
2422 res
= ast_streamfile(mychannel
, "rpt/timeout", mychannel
->language
);
2426 wait_interval(myrpt
, DLY_TELEM
, mychannel
); /* Wait a little bit */
2428 localtime_r(&t
, &localtm
);
2429 /* Say the phase of the day is before the time */
2430 if((localtm
.tm_hour
>= 0) && (localtm
.tm_hour
< 12))
2431 p
= "rpt/goodmorning";
2432 else if((localtm
.tm_hour
>= 12) && (localtm
.tm_hour
< 18))
2433 p
= "rpt/goodafternoon";
2435 p
= "rpt/goodevening";
2436 if (sayfile(mychannel
,p
) == -1)
2441 /* Say the time is ... */
2442 if (sayfile(mychannel
,"rpt/thetimeis") == -1)
2448 res
= ast_say_time(mychannel
, t
, "", mychannel
->language
);
2450 res
= ast_waitstream(mychannel
, "");
2451 ast_stopstream(mychannel
);
2455 wait_interval(myrpt
, DLY_TELEM
, mychannel
); /* Wait a little bit */
2457 if (sayfile(mychannel
,"rpt/version") == -1)
2462 if(!res
) /* Say "X" */
2463 ast_say_number(mychannel
, vmajor
, "", mychannel
->language
, (char *) NULL
);
2465 res
= ast_waitstream(mychannel
, "");
2466 ast_stopstream(mychannel
);
2467 if (saycharstr(mychannel
,".") == -1)
2472 if(!res
) /* Say "Y" */
2473 ast_say_number(mychannel
, vminor
, "", mychannel
->language
, (char *) NULL
);
2475 res
= ast_waitstream(mychannel
, "");
2476 ast_stopstream(mychannel
);
2479 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
2483 wait_interval(myrpt
, DLY_TELEM
, mychannel
); /* Wait a little bit */
2485 saycharstr(mychannel
, mytele
->param
);
2489 wait_interval(myrpt
, DLY_TELEM
, mychannel
); /* Wait a little bit */
2492 /* Parts of this section taken from app_parkandannounce */
2493 char *tpl_working
, *tpl_current
;
2494 char *tmp
[100], *myparm
;
2495 int looptemp
=0,i
=0, dres
= 0;
2498 tpl_working
= strdupa(mytele
->param
);
2499 myparm
= strsep(&tpl_working
,",");
2500 tpl_current
=strsep(&tpl_working
, ":");
2502 while(tpl_current
&& looptemp
< sizeof(tmp
)) {
2503 tmp
[looptemp
]=tpl_current
;
2505 tpl_current
=strsep(&tpl_working
,":");
2508 for(i
=0; i
<looptemp
; i
++) {
2509 if(!strcmp(tmp
[i
], "PARKED")) {
2510 ast_say_digits(mychannel
, atoi(myparm
), "", mychannel
->language
);
2511 } else if(!strcmp(tmp
[i
], "NODE")) {
2512 ast_say_digits(mychannel
, atoi(myrpt
->name
), "", mychannel
->language
);
2514 dres
= ast_streamfile(mychannel
, tmp
[i
], mychannel
->language
);
2516 dres
= ast_waitstream(mychannel
, "");
2518 ast_log(LOG_WARNING
, "ast_streamfile of %s failed on %s\n", tmp
[i
], mychannel
->name
);
2529 if ((res
= ast_tonepair_start(mychannel
, 1004.0, 0, 99999999, 7200.0)))
2531 while(mychannel
->generatordata
&& (!myrpt
->stopgen
)) {
2532 if (ast_safe_sleep(mychannel
,1)) break;
2543 res
= ast_waitstream(mychannel
, "");
2545 ast_log(LOG_WARNING
, "ast_streamfile failed on %s\n", mychannel
->name
);
2549 ast_stopstream(mychannel
);
2550 rpt_mutex_lock(&myrpt
->lock
);
2551 if (mytele
->mode
== TAILMSG
)
2555 myrpt
->tailmessagen
++;
2556 if(myrpt
->tailmessagen
>= myrpt
->p
.tailmessagemax
) myrpt
->tailmessagen
= 0;
2560 myrpt
->tmsgtimer
= myrpt
->p
.tailsquashedtime
;
2563 remque((struct qelem
*)mytele
);
2564 rpt_mutex_unlock(&myrpt
->lock
);
2566 ast_hangup(mychannel
);
2567 #ifdef APP_RPT_LOCK_DEBUG
2569 struct lockthread
*t
;
2572 ast_mutex_lock(&locklock
);
2573 t
= get_lockthread(pthread_self());
2574 if (t
) memset(t
,0,sizeof(struct lockthread
));
2575 ast_mutex_unlock(&locklock
);
2581 static void rpt_telemetry(struct rpt
*myrpt
,int mode
, void *data
)
2583 struct rpt_tele
*tele
;
2584 struct rpt_link
*mylink
= (struct rpt_link
*) data
;
2586 pthread_attr_t attr
;
2588 tele
= malloc(sizeof(struct rpt_tele
));
2591 ast_log(LOG_WARNING
, "Unable to allocate memory\n");
2596 memset((char *)tele
,0,sizeof(struct rpt_tele
));
2599 rpt_mutex_lock(&myrpt
->lock
);
2600 if((mode
== CONNFAIL
) || (mode
== REMDISC
) || (mode
== CONNECTED
)){
2601 memset(&tele
->mylink
,0,sizeof(struct rpt_link
));
2603 memcpy(&tele
->mylink
,mylink
,sizeof(struct rpt_link
));
2606 else if ((mode
== ARB_ALPHA
) || (mode
== REV_PATCH
)) {
2607 strncpy(tele
->param
, (char *) data
, TELEPARAMSIZE
- 1);
2608 tele
->param
[TELEPARAMSIZE
- 1] = 0;
2610 insque((struct qelem
*)tele
, (struct qelem
*)myrpt
->tele
.next
);
2611 rpt_mutex_unlock(&myrpt
->lock
);
2612 pthread_attr_init(&attr
);
2613 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
2614 res
= ast_pthread_create(&tele
->threadid
,&attr
,rpt_tele_thread
,(void *) tele
);
2616 rpt_mutex_lock(&myrpt
->lock
);
2617 remque((struct qlem
*) tele
); /* We don't like stuck transmitters, remove it from the queue */
2618 rpt_mutex_unlock(&myrpt
->lock
);
2619 ast_log(LOG_WARNING
, "Could not create telemetry thread: %s",strerror(res
));
2624 static void *rpt_call(void *this)
2626 ZT_CONFINFO ci
; /* conference info */
2627 struct rpt
*myrpt
= (struct rpt
*)this;
2629 struct ast_frame wf
;
2630 int stopped
,congstarted
,dialtimer
,lastcidx
,aborted
;
2631 struct ast_channel
*mychannel
,*genchannel
;
2635 /* allocate a pseudo-channel thru asterisk */
2636 mychannel
= ast_request("zap",AST_FORMAT_SLINEAR
,"pseudo",NULL
);
2639 fprintf(stderr
,"rpt:Sorry unable to obtain pseudo channel\n");
2643 ci
.confno
= myrpt
->conf
; /* use the pseudo conference */
2644 ci
.confmode
= ZT_CONF_REALANDPSEUDO
| ZT_CONF_TALKER
| ZT_CONF_LISTENER
2645 | ZT_CONF_PSEUDO_TALKER
| ZT_CONF_PSEUDO_LISTENER
;
2646 /* first put the channel on the conference */
2647 if (ioctl(mychannel
->fds
[0],ZT_SETCONF
,&ci
) == -1)
2649 ast_log(LOG_WARNING
, "Unable to set conference mode to Announce\n");
2650 ast_hangup(mychannel
);
2651 myrpt
->callmode
= 0;
2654 /* allocate a pseudo-channel thru asterisk */
2655 genchannel
= ast_request("zap",AST_FORMAT_SLINEAR
,"pseudo",NULL
);
2658 fprintf(stderr
,"rpt:Sorry unable to obtain pseudo channel\n");
2659 ast_hangup(mychannel
);
2663 ci
.confno
= myrpt
->conf
;
2664 ci
.confmode
= ZT_CONF_REALANDPSEUDO
| ZT_CONF_TALKER
| ZT_CONF_LISTENER
2665 | ZT_CONF_PSEUDO_TALKER
| ZT_CONF_PSEUDO_LISTENER
;
2666 /* first put the channel on the conference */
2667 if (ioctl(genchannel
->fds
[0],ZT_SETCONF
,&ci
) == -1)
2669 ast_log(LOG_WARNING
, "Unable to set conference mode to Announce\n");
2670 ast_hangup(mychannel
);
2671 ast_hangup(genchannel
);
2672 myrpt
->callmode
= 0;
2675 if (myrpt
->p
.tonezone
&& (tone_zone_set_zone(mychannel
->fds
[0],myrpt
->p
.tonezone
) == -1))
2677 ast_log(LOG_WARNING
, "Unable to set tone zone %s\n",myrpt
->p
.tonezone
);
2678 ast_hangup(mychannel
);
2679 ast_hangup(genchannel
);
2680 myrpt
->callmode
= 0;
2683 if (myrpt
->p
.tonezone
&& (tone_zone_set_zone(genchannel
->fds
[0],myrpt
->p
.tonezone
) == -1))
2685 ast_log(LOG_WARNING
, "Unable to set tone zone %s\n",myrpt
->p
.tonezone
);
2686 ast_hangup(mychannel
);
2687 ast_hangup(genchannel
);
2688 myrpt
->callmode
= 0;
2691 /* start dialtone if patchquiet is 0. Special patch modes don't send dial tone */
2692 if ((!myrpt
->patchquiet
) && (tone_zone_play_tone(mychannel
->fds
[0],ZT_TONE_DIALTONE
) < 0))
2694 ast_log(LOG_WARNING
, "Cannot start dialtone\n");
2695 ast_hangup(mychannel
);
2696 ast_hangup(genchannel
);
2697 myrpt
->callmode
= 0;
2707 while ((myrpt
->callmode
== 1) || (myrpt
->callmode
== 4))
2710 if((myrpt
->patchdialtime
)&&(myrpt
->callmode
== 1)&&(myrpt
->cidx
!= lastcidx
)){
2712 lastcidx
= myrpt
->cidx
;
2715 if((myrpt
->patchdialtime
)&&(dialtimer
>= myrpt
->patchdialtime
)){
2716 rpt_mutex_lock(&myrpt
->lock
);
2718 myrpt
->callmode
= 0;
2719 rpt_mutex_unlock(&myrpt
->lock
);
2723 if ((!myrpt
->patchquiet
) && (!stopped
) && (myrpt
->callmode
== 1) && (myrpt
->cidx
> 0))
2726 /* stop dial tone */
2727 tone_zone_play_tone(mychannel
->fds
[0],-1);
2729 if (myrpt
->callmode
== 4)
2733 /* start congestion tone */
2734 tone_zone_play_tone(mychannel
->fds
[0],ZT_TONE_CONGESTION
);
2737 res
= ast_safe_sleep(mychannel
, MSWAIT
);
2740 ast_hangup(mychannel
);
2741 ast_hangup(genchannel
);
2742 rpt_mutex_lock(&myrpt
->lock
);
2743 myrpt
->callmode
= 0;
2744 rpt_mutex_unlock(&myrpt
->lock
);
2747 dialtimer
+= MSWAIT
;
2749 /* stop any tone generation */
2750 tone_zone_play_tone(mychannel
->fds
[0],-1);
2752 if (!myrpt
->callmode
)
2754 ast_hangup(mychannel
);
2755 ast_hangup(genchannel
);
2756 rpt_mutex_lock(&myrpt
->lock
);
2757 myrpt
->callmode
= 0;
2758 rpt_mutex_unlock(&myrpt
->lock
);
2759 if((!myrpt
->patchquiet
) && aborted
)
2760 rpt_telemetry(myrpt
, TERM
, NULL
);
2764 if (myrpt
->p
.ourcallerid
&& *myrpt
->p
.ourcallerid
){
2765 char *name
, *loc
, *instr
;
2766 instr
= strdup(myrpt
->p
.ourcallerid
);
2768 ast_callerid_parse(instr
, &name
, &loc
);
2770 if(mychannel
->cid
.cid_num
)
2771 free(mychannel
->cid
.cid_num
);
2772 mychannel
->cid
.cid_num
= strdup(loc
);
2775 if(mychannel
->cid
.cid_name
)
2776 free(mychannel
->cid
.cid_name
);
2777 mychannel
->cid
.cid_name
= strdup(name
);
2783 strncpy(mychannel
->exten
, myrpt
->exten
, sizeof(mychannel
->exten
) - 1);
2784 strncpy(mychannel
->context
, myrpt
->patchcontext
, sizeof(mychannel
->context
) - 1);
2786 if (myrpt
->p
.acctcode
)
2787 strncpy((char *)mychannel
->accountcode
, myrpt
->p
.acctcode
, sizeof(mychannel
->accountcode
) - 1);
2788 mychannel
->priority
= 1;
2789 ast_channel_undefer_dtmf(mychannel
);
2790 if (ast_pbx_start(mychannel
) < 0)
2792 ast_log(LOG_WARNING
, "Unable to start PBX!!\n");
2793 ast_hangup(mychannel
);
2794 ast_hangup(genchannel
);
2795 rpt_mutex_lock(&myrpt
->lock
);
2796 myrpt
->callmode
= 0;
2797 rpt_mutex_unlock(&myrpt
->lock
);
2801 rpt_mutex_lock(&myrpt
->lock
);
2802 myrpt
->callmode
= 3;
2803 /* set appropriate conference for the pseudo */
2805 ci
.confno
= myrpt
->conf
;
2806 ci
.confmode
= (myrpt
->p
.duplex
== 2) ? ZT_CONF_CONFANNMON
:
2807 (ZT_CONF_CONF
| ZT_CONF_LISTENER
| ZT_CONF_TALKER
);
2808 /* first put the channel on the conference in announce mode */
2809 if (ioctl(myrpt
->pchannel
->fds
[0],ZT_SETCONF
,&ci
) == -1)
2811 ast_log(LOG_WARNING
, "Unable to set conference mode to Announce\n");
2812 ast_hangup(mychannel
);
2813 ast_hangup(genchannel
);
2814 myrpt
->callmode
= 0;
2817 while(myrpt
->callmode
)
2819 if ((!mychannel
->pbx
) && (myrpt
->callmode
!= 4))
2821 if(myrpt
->patchfarenddisconnect
){ /* If patch is setup for far end disconnect */
2822 myrpt
->callmode
= 0;
2823 if(!myrpt
->patchquiet
){
2824 rpt_mutex_unlock(&myrpt
->lock
);
2825 rpt_telemetry(myrpt
, TERM
, NULL
);
2826 rpt_mutex_lock(&myrpt
->lock
);
2829 else{ /* Send congestion until patch is downed by command */
2830 myrpt
->callmode
= 4;
2831 rpt_mutex_unlock(&myrpt
->lock
);
2832 /* start congestion tone */
2833 tone_zone_play_tone(genchannel
->fds
[0],ZT_TONE_CONGESTION
);
2834 rpt_mutex_lock(&myrpt
->lock
);
2839 wf
.frametype
= AST_FRAME_DTMF
;
2840 wf
.subclass
= myrpt
->mydtmf
;
2846 rpt_mutex_unlock(&myrpt
->lock
);
2847 ast_write(genchannel
,&wf
);
2848 rpt_mutex_lock(&myrpt
->lock
);
2851 rpt_mutex_unlock(&myrpt
->lock
);
2852 usleep(MSWAIT
* 1000);
2853 rpt_mutex_lock(&myrpt
->lock
);
2855 rpt_mutex_unlock(&myrpt
->lock
);
2856 tone_zone_play_tone(genchannel
->fds
[0],-1);
2857 if (mychannel
->pbx
) ast_softhangup(mychannel
,AST_SOFTHANGUP_DEV
);
2858 ast_hangup(genchannel
);
2859 rpt_mutex_lock(&myrpt
->lock
);
2860 myrpt
->callmode
= 0;
2861 rpt_mutex_unlock(&myrpt
->lock
);
2862 /* set appropriate conference for the pseudo */
2864 ci
.confno
= myrpt
->conf
;
2865 ci
.confmode
= ((myrpt
->p
.duplex
== 2) || (myrpt
->p
.duplex
== 4)) ? ZT_CONF_CONFANNMON
:
2866 (ZT_CONF_CONF
| ZT_CONF_LISTENER
| ZT_CONF_TALKER
);
2867 /* first put the channel on the conference in announce mode */
2868 if (ioctl(myrpt
->pchannel
->fds
[0],ZT_SETCONF
,&ci
) == -1)
2870 ast_log(LOG_WARNING
, "Unable to set conference mode to Announce\n");
2875 static void send_link_dtmf(struct rpt
*myrpt
,char c
)
2878 struct ast_frame wf
;
2881 snprintf(str
, sizeof(str
), "D %s %s %d %c", myrpt
->cmdnode
, myrpt
->name
, ++(myrpt
->dtmfidx
), c
);
2882 wf
.frametype
= AST_FRAME_TEXT
;
2886 wf
.datalen
= strlen(str
) + 1;
2888 l
= myrpt
->links
.next
;
2889 /* first, see if our dude is there */
2890 while(l
!= &myrpt
->links
)
2892 if (l
->name
[0] == '0')
2897 /* if we found it, write it and were done */
2898 if (!strcmp(l
->name
,myrpt
->cmdnode
))
2900 wf
.data
= strdup(str
);
2901 if (l
->chan
) ast_write(l
->chan
,&wf
);
2906 l
= myrpt
->links
.next
;
2907 /* if not, give it to everyone */
2908 while(l
!= &myrpt
->links
)
2910 wf
.data
= strdup(str
);
2911 if (l
->chan
) ast_write(l
->chan
,&wf
);
2918 * Internet linking function
2921 static int function_ilink(struct rpt
*myrpt
, char *param
, char *digits
, int command_source
, struct rpt_link
*mylink
)
2924 char *val
, *s
, *s1
, *s2
, *tele
;
2925 char tmp
[300], deststr
[300] = "",modechange
= 0;
2926 char digitbuf
[MAXNODESTR
];
2929 ZT_CONFINFO ci
; /* conference info */
2938 strncpy(digitbuf
,digits
,MAXNODESTR
- 1);
2941 printf("@@@@ ilink param = %s, digitbuf = %s\n", (param
)? param
: "(null)", digitbuf
);
2943 switch(myatoi(param
)){
2944 case 1: /* Link off */
2945 if ((digitbuf
[0] == '0') && (myrpt
->lastlinknode
[0]))
2946 strcpy(digitbuf
,myrpt
->lastlinknode
);
2947 val
= ast_variable_retrieve(myrpt
->cfg
, myrpt
->p
.nodes
, digitbuf
);
2949 if(strlen(digitbuf
) >= myrpt
->longestnode
)
2953 strncpy(tmp
,val
,sizeof(tmp
) - 1);
2955 s1
= strsep(&s
,",");
2956 s2
= strsep(&s
,",");
2957 rpt_mutex_lock(&myrpt
->lock
);
2958 l
= myrpt
->links
.next
;
2959 /* try to find this one in queue */
2960 while(l
!= &myrpt
->links
){
2961 if (l
->name
[0] == '0')
2966 /* if found matching string */
2967 if (!strcmp(l
->name
, digitbuf
))
2971 if (l
!= &myrpt
->links
){ /* if found */
2972 struct ast_frame wf
;
2973 strncpy(myrpt
->lastlinknode
,digitbuf
,MAXNODESTR
- 1);
2974 l
->retries
= MAX_RETRIES
+ 1;
2976 rpt_mutex_unlock(&myrpt
->lock
);
2977 wf
.frametype
= AST_FRAME_TEXT
;
2981 wf
.datalen
= strlen(discstr
) + 1;
2983 wf
.data
= strdup(discstr
);
2986 ast_write(l
->chan
,&wf
);
2987 if (ast_safe_sleep(l
->chan
,250) == -1) return DC_ERROR
;
2988 ast_softhangup(l
->chan
,AST_SOFTHANGUP_DEV
);
2990 rpt_telemetry(myrpt
, COMPLETE
, NULL
);
2993 rpt_mutex_unlock(&myrpt
->lock
);
2995 case 2: /* Link Monitor */
2996 if ((digitbuf
[0] == '0') && (myrpt
->lastlinknode
[0]))
2997 strcpy(digitbuf
,myrpt
->lastlinknode
);
2998 val
= ast_variable_retrieve(myrpt
->cfg
, myrpt
->p
.nodes
, digitbuf
);
3000 if(strlen(digitbuf
) >= myrpt
->longestnode
)
3004 strncpy(tmp
,val
,sizeof(tmp
) - 1);
3006 s1
= strsep(&s
,",");
3007 s2
= strsep(&s
,",");
3008 rpt_mutex_lock(&myrpt
->lock
);
3009 l
= myrpt
->links
.next
;
3010 /* try to find this one in queue */
3011 while(l
!= &myrpt
->links
){
3012 if (l
->name
[0] == '0')
3017 /* if found matching string */
3018 if (!strcmp(l
->name
, digitbuf
))
3023 if (l
!= &myrpt
->links
)
3025 /* if already in this mode, just ignore */
3026 if ((!l
->mode
) || (!l
->chan
)) {
3027 rpt_mutex_unlock(&myrpt
->lock
);
3028 rpt_telemetry(myrpt
,REMALREADY
,NULL
);
3032 reconnects
= l
->reconnects
;
3033 rpt_mutex_unlock(&myrpt
->lock
);
3034 if (l
->chan
) ast_softhangup(l
->chan
,AST_SOFTHANGUP_DEV
);
3035 l
->retries
= MAX_RETRIES
+ 1;
3039 rpt_mutex_unlock(&myrpt
->lock
);
3040 strncpy(myrpt
->lastlinknode
,digitbuf
,MAXNODESTR
- 1);
3041 /* establish call in monitor mode */
3042 l
= malloc(sizeof(struct rpt_link
));
3044 ast_log(LOG_WARNING
, "Unable to malloc\n");
3047 /* zero the silly thing */
3048 memset((char *)l
,0,sizeof(struct rpt_link
));
3049 snprintf(deststr
, sizeof(deststr
), "IAX2/%s", s1
);
3050 tele
= strchr(deststr
,'/');
3052 fprintf(stderr
,"link2:Dial number (%s) must be in format tech/number\n",deststr
);
3056 l
->isremote
= (s
&& ast_true(s
));
3057 strncpy(l
->name
, digitbuf
, MAXNODESTR
- 1);
3058 l
->chan
= ast_request(deststr
,AST_FORMAT_SLINEAR
,tele
,NULL
);
3059 if (modechange
) l
->connected
= 1;
3061 ast_set_read_format(l
->chan
,AST_FORMAT_SLINEAR
);
3062 ast_set_write_format(l
->chan
,AST_FORMAT_SLINEAR
);
3063 l
->chan
->whentohangup
= 0;
3064 l
->chan
->appl
= "Apprpt";
3065 l
->chan
->data
= "(Remote Rx)";
3066 if (option_verbose
> 2)
3067 ast_verbose(VERBOSE_PREFIX_3
"rpt (remote) initiating call to %s/%s on %s\n",
3068 deststr
,tele
,l
->chan
->name
);
3069 if(l
->chan
->cid
.cid_num
)
3070 free(l
->chan
->cid
.cid_num
);
3071 l
->chan
->cid
.cid_num
= strdup(myrpt
->name
);
3072 ast_call(l
->chan
,tele
,0);
3076 rpt_telemetry(myrpt
,CONNFAIL
,l
);
3078 if (option_verbose
> 2)
3079 ast_verbose(VERBOSE_PREFIX_3
"Unable to place call to %s/%s on %s\n",
3080 deststr
,tele
,l
->chan
->name
);
3083 /* allocate a pseudo-channel thru asterisk */
3084 l
->pchan
= ast_request("zap",AST_FORMAT_SLINEAR
,"pseudo",NULL
);
3086 fprintf(stderr
,"rpt:Sorry unable to obtain pseudo channel\n");
3087 ast_hangup(l
->chan
);
3091 ast_set_read_format(l
->pchan
,AST_FORMAT_SLINEAR
);
3092 ast_set_write_format(l
->pchan
,AST_FORMAT_SLINEAR
);
3093 /* make a conference for the pseudo-one */
3095 ci
.confno
= myrpt
->conf
;
3096 ci
.confmode
= ZT_CONF_CONF
| ZT_CONF_LISTENER
| ZT_CONF_TALKER
;
3097 /* first put the channel on the conference in proper mode */
3098 if (ioctl(l
->pchan
->fds
[0],ZT_SETCONF
,&ci
) == -1)
3100 ast_log(LOG_WARNING
, "Unable to set conference mode to Announce\n");
3101 ast_hangup(l
->chan
);
3102 ast_hangup(l
->pchan
);
3106 rpt_mutex_lock(&myrpt
->lock
);
3107 l
->reconnects
= reconnects
;
3108 /* insert at end of queue */
3109 insque((struct qelem
*)l
,(struct qelem
*)myrpt
->links
.next
);
3110 rpt_mutex_unlock(&myrpt
->lock
);
3111 rpt_telemetry(myrpt
,COMPLETE
,NULL
);
3113 case 3: /* Link transceive */
3114 if ((digitbuf
[0] == '0') && (myrpt
->lastlinknode
[0]))
3115 strcpy(digitbuf
,myrpt
->lastlinknode
);
3116 val
= ast_variable_retrieve(myrpt
->cfg
, myrpt
->p
.nodes
, digitbuf
);
3118 if(strlen(digitbuf
) >= myrpt
->longestnode
)
3122 strncpy(tmp
,val
,sizeof(tmp
) - 1);
3124 s1
= strsep(&s
,",");
3125 s2
= strsep(&s
,",");
3126 rpt_mutex_lock(&myrpt
->lock
);
3127 l
= myrpt
->links
.next
;
3128 /* try to find this one in queue */
3129 while(l
!= &myrpt
->links
){
3130 if (l
->name
[0] == '0')
3135 /* if found matching string */
3136 if (!strcmp(l
->name
, digitbuf
))
3141 if (l
!= &myrpt
->links
){
3142 /* if already in this mode, just ignore */
3143 if ((l
->mode
) || (!l
->chan
)) {
3144 rpt_mutex_unlock(&myrpt
->lock
);
3145 rpt_telemetry(myrpt
, REMALREADY
, NULL
);
3148 reconnects
= l
->reconnects
;
3149 rpt_mutex_unlock(&myrpt
->lock
);
3150 if (l
->chan
) ast_softhangup(l
->chan
, AST_SOFTHANGUP_DEV
);
3151 l
->retries
= MAX_RETRIES
+ 1;
3155 rpt_mutex_unlock(&myrpt
->lock
);
3156 strncpy(myrpt
->lastlinknode
,digitbuf
,MAXNODESTR
- 1);
3157 /* establish call in tranceive mode */
3158 l
= malloc(sizeof(struct rpt_link
));
3160 ast_log(LOG_WARNING
, "Unable to malloc\n");
3163 /* zero the silly thing */
3164 memset((char *)l
,0,sizeof(struct rpt_link
));
3167 strncpy(l
->name
, digitbuf
, MAXNODESTR
- 1);
3168 l
->isremote
= (s
&& ast_true(s
));
3169 if (modechange
) l
->connected
= 1;
3170 snprintf(deststr
, sizeof(deststr
), "IAX2/%s", s1
);
3171 tele
= strchr(deststr
, '/');
3173 fprintf(stderr
,"link3:Dial number (%s) must be in format tech/number\n",deststr
);
3178 l
->chan
= ast_request(deststr
, AST_FORMAT_SLINEAR
, tele
,NULL
);
3180 ast_set_read_format(l
->chan
, AST_FORMAT_SLINEAR
);
3181 ast_set_write_format(l
->chan
, AST_FORMAT_SLINEAR
);
3182 l
->chan
->whentohangup
= 0;
3183 l
->chan
->appl
= "Apprpt";
3184 l
->chan
->data
= "(Remote Rx)";
3185 if (option_verbose
> 2)
3186 ast_verbose(VERBOSE_PREFIX_3
"rpt (remote) initiating call to %s/%s on %s\n",
3187 deststr
, tele
, l
->chan
->name
);
3188 if(l
->chan
->cid
.cid_num
)
3189 free(l
->chan
->cid
.cid_num
);
3190 l
->chan
->cid
.cid_num
= strdup(myrpt
->name
);
3191 ast_call(l
->chan
,tele
,999);
3194 rpt_telemetry(myrpt
,CONNFAIL
,l
);
3196 if (option_verbose
> 2)
3197 ast_verbose(VERBOSE_PREFIX_3
"Unable to place call to %s/%s on %s\n",
3198 deststr
,tele
,l
->chan
->name
);
3201 /* allocate a pseudo-channel thru asterisk */
3202 l
->pchan
= ast_request("zap",AST_FORMAT_SLINEAR
,"pseudo",NULL
);
3204 fprintf(stderr
,"rpt:Sorry unable to obtain pseudo channel\n");
3205 ast_hangup(l
->chan
);
3209 ast_set_read_format(l
->pchan
, AST_FORMAT_SLINEAR
);
3210 ast_set_write_format(l
->pchan
, AST_FORMAT_SLINEAR
);
3211 /* make a conference for the tx */
3213 ci
.confno
= myrpt
->conf
;
3214 ci
.confmode
= ZT_CONF_CONF
| ZT_CONF_LISTENER
| ZT_CONF_TALKER
;
3215 /* first put the channel on the conference in proper mode */
3216 if (ioctl(l
->pchan
->fds
[0], ZT_SETCONF
, &ci
) == -1)
3218 ast_log(LOG_WARNING
, "Unable to set conference mode to Announce\n");
3219 ast_hangup(l
->chan
);
3220 ast_hangup(l
->pchan
);
3224 rpt_mutex_lock(&myrpt
->lock
);
3225 l
->reconnects
= reconnects
;
3226 /* insert at end of queue */
3227 insque((struct qelem
*)l
,(struct qelem
*)myrpt
->links
.next
);
3228 rpt_mutex_unlock(&myrpt
->lock
);
3229 rpt_telemetry(myrpt
,COMPLETE
,NULL
);
3231 case 4: /* Enter Command Mode */
3233 /* if doesnt allow link cmd, or no links active, return */
3234 if (((command_source
!= SOURCE_RPT
) && (command_source
!= SOURCE_PHONE
) && (command_source
!= SOURCE_DPHONE
)) || (myrpt
->links
.next
== &myrpt
->links
))
3237 /* if already in cmd mode, or selected self, fughetabahtit */
3238 if ((myrpt
->cmdnode
[0]) || (!strcmp(myrpt
->name
, digitbuf
))){
3240 rpt_telemetry(myrpt
, REMALREADY
, NULL
);
3243 if ((digitbuf
[0] == '0') && (myrpt
->lastlinknode
[0]))
3244 strcpy(digitbuf
,myrpt
->lastlinknode
);
3245 /* node must at least exist in list */
3246 val
= ast_variable_retrieve(myrpt
->cfg
, myrpt
->p
.nodes
, digitbuf
);
3248 if(strlen(digitbuf
) >= myrpt
->longestnode
)
3253 rpt_mutex_lock(&myrpt
->lock
);
3254 strcpy(myrpt
->lastlinknode
,digitbuf
);
3255 strncpy(myrpt
->cmdnode
, digitbuf
, sizeof(myrpt
->cmdnode
) - 1);
3256 rpt_mutex_unlock(&myrpt
->lock
);
3257 rpt_telemetry(myrpt
, REMGO
, NULL
);
3260 case 5: /* Status */
3261 rpt_telemetry(myrpt
, STATUS
, NULL
);
3265 case 6: /* All Links Off */
3266 l
= myrpt
->links
.next
;
3268 while(l
!= &myrpt
->links
){ /* This code is broke and needs to be changed to work with the reconnect kludge */
3269 if (l
->chan
) ast_softhangup(l
->chan
, AST_SOFTHANGUP_DEV
); /* Hang 'em up */
3272 rpt_telemetry(myrpt
, COMPLETE
, NULL
);
3275 case 7: /* Identify last node which keyed us up */
3276 rpt_telemetry(myrpt
, LASTNODEKEY
, NULL
);
3284 return DC_INDETERMINATE
;
3291 static int function_autopatchup(struct rpt
*myrpt
, char *param
, char *digitbuf
, int command_source
, struct rpt_link
*mylink
)
3293 pthread_attr_t attr
;
3294 int i
, index
, paramlength
;
3297 char *paramlist
[20];
3299 static char *keywords
[] = {
3312 printf("@@@@ Autopatch up\n");
3314 if(!myrpt
->callmode
){
3316 myrpt
->patchnoct
= 0;
3317 myrpt
->patchdialtime
= 0;
3318 myrpt
->patchfarenddisconnect
= 0;
3319 myrpt
->patchquiet
= 0;
3320 strncpy(myrpt
->patchcontext
, myrpt
->p
.ourcontext
, MAXPATCHCONTEXT
);
3323 /* Process parameter list */
3324 lparam
= ast_strdupa(param
);
3326 ast_log(LOG_ERROR
,"App_rpt out of memory on line %d\n",__LINE__
);
3329 paramlength
= finddelim(lparam
, paramlist
, 20);
3330 for(i
= 0; i
< paramlength
; i
++){
3331 index
= matchkeyword(paramlist
[i
], &value
, keywords
);
3333 value
= skipchars(value
, "= ");
3336 case 1: /* context */
3337 strncpy(myrpt
->patchcontext
, value
, MAXPATCHCONTEXT
- 1) ;
3340 case 2: /* dialtime */
3341 myrpt
->patchdialtime
= atoi(value
);
3344 case 3: /* farenddisconnect */
3345 myrpt
->patchfarenddisconnect
= atoi(value
);
3349 myrpt
->patchnoct
= atoi(value
);
3353 myrpt
->patchquiet
= atoi(value
);
3363 rpt_mutex_lock(&myrpt
->lock
);
3365 /* if on call, force * into current audio stream */
3367 if ((myrpt
->callmode
== 2) || (myrpt
->callmode
== 3)){
3368 myrpt
->mydtmf
= myrpt
->p
.funcchar
;
3370 if (myrpt
->callmode
){
3371 rpt_mutex_unlock(&myrpt
->lock
);
3374 myrpt
->callmode
= 1;
3376 myrpt
->exten
[myrpt
->cidx
] = 0;
3377 rpt_mutex_unlock(&myrpt
->lock
);
3378 pthread_attr_init(&attr
);
3379 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
3380 ast_pthread_create(&myrpt
->rpt_call_thread
,&attr
,rpt_call
,(void *) myrpt
);
3388 static int function_autopatchdn(struct rpt
*myrpt
, char *param
, char *digitbuf
, int command_source
, struct rpt_link
*mylink
)
3394 printf("@@@@ Autopatch down\n");
3396 rpt_mutex_lock(&myrpt
->lock
);
3398 if (!myrpt
->callmode
){
3399 rpt_mutex_unlock(&myrpt
->lock
);
3403 myrpt
->callmode
= 0;
3404 rpt_mutex_unlock(&myrpt
->lock
);
3405 rpt_telemetry(myrpt
, TERM
, NULL
);
3413 static int function_status(struct rpt
*myrpt
, char *param
, char *digitbuf
, int command_source
, struct rpt_link
*mylink
)
3423 printf("@@@@ status param = %s, digitbuf = %s\n", (param
)? param
: "(null)", digitbuf
);
3425 switch(myatoi(param
)){
3426 case 1: /* System ID */
3427 rpt_telemetry(myrpt
, ID1
, NULL
);
3429 case 2: /* System Time */
3430 rpt_telemetry(myrpt
, STATS_TIME
, NULL
);
3432 case 3: /* app_rpt.c version */
3433 rpt_telemetry(myrpt
, STATS_VERSION
, NULL
);
3437 return DC_INDETERMINATE
;
3441 * Macro-oni (without Salami)
3444 static int function_macro(struct rpt
*myrpt
, char *param
, char *digitbuf
, int command_source
, struct rpt_link
*mylink
)
3449 struct ast_channel
*mychannel
;
3451 if ((!myrpt
->remote
) && (!myrpt
->enable
))
3455 printf("@@@@ macro-oni param = %s, digitbuf = %s\n", (param
)? param
: "(null)", digitbuf
);
3457 mychannel
= myrpt
->remchannel
;
3459 if(strlen(digitbuf
) < 1) /* needs 1 digit */
3460 return DC_INDETERMINATE
;
3462 for(i
= 0 ; i
< digitbuf
[i
] ; i
++) {
3463 if((digitbuf
[i
] < '0') || (digitbuf
[i
] > '9'))
3467 if (*digitbuf
== '0') val
= myrpt
->p
.startupmacro
;
3468 else val
= ast_variable_retrieve(myrpt
->cfg
, myrpt
->p
.macro
, digitbuf
);
3469 /* param was 1 for local buf */
3471 rpt_telemetry(myrpt
, MACRO_NOTFOUND
, NULL
);
3474 rpt_mutex_lock(&myrpt
->lock
);
3475 if ((MAXMACRO
- strlen(myrpt
->macrobuf
)) < strlen(val
))
3477 rpt_mutex_unlock(&myrpt
->lock
);
3478 rpt_telemetry(myrpt
, MACRO_BUSY
, NULL
);
3481 myrpt
->macrotimer
= MACROTIME
;
3482 strncat(myrpt
->macrobuf
,val
,MAXMACRO
- 1);
3483 rpt_mutex_unlock(&myrpt
->lock
);
3488 * COP - Control operator
3491 static int function_cop(struct rpt
*myrpt
, char *param
, char *digitbuf
, int command_source
, struct rpt_link
*mylink
)
3496 switch(myatoi(param
)){
3497 case 1: /* System reset */
3498 system("killall -9 asterisk"); /* FIXME to drastic? */
3503 rpt_telemetry(myrpt
, ARB_ALPHA
, (void *) "RPTENA");
3510 case 4: /* test tone on */
3511 rpt_telemetry(myrpt
, TEST_TONE
, NULL
);
3514 case 5: /* Disgorge variables to log for debug purposes */
3515 myrpt
->disgorgetime
= time(NULL
) + 10; /* Do it 10 seconds later */
3518 case 6: /* Simulate COR being activated (phone only) */
3519 if (command_source
!= SOURCE_PHONE
) return DC_INDETERMINATE
;
3523 return DC_INDETERMINATE
;
3527 * Collect digits one by one until something matches
3530 static int collect_function_digits(struct rpt
*myrpt
, char *digits
,
3531 int command_source
, struct rpt_link
*mylink
)
3534 char *stringp
,*action
,*param
,*functiondigits
;
3535 char function_table_name
[30] = "";
3536 char workstring
[200];
3538 struct ast_variable
*vp
;
3541 printf("@@@@ Digits collected: %s, source: %d\n", digits
, command_source
);
3543 if (command_source
== SOURCE_DPHONE
) {
3544 if (!myrpt
->p
.dphone_functions
) return DC_INDETERMINATE
;
3545 strncpy(function_table_name
, myrpt
->p
.dphone_functions
, sizeof(function_table_name
) - 1);
3547 else if (command_source
== SOURCE_PHONE
) {
3548 if (!myrpt
->p
.phone_functions
) return DC_INDETERMINATE
;
3549 strncpy(function_table_name
, myrpt
->p
.phone_functions
, sizeof(function_table_name
) - 1);
3551 else if (command_source
== SOURCE_LNK
)
3552 strncpy(function_table_name
, myrpt
->p
.link_functions
, sizeof(function_table_name
) - 1);
3554 strncpy(function_table_name
, myrpt
->p
.functions
, sizeof(function_table_name
) - 1);
3555 vp
= ast_variable_browse(myrpt
->cfg
, function_table_name
);
3557 if(!strncasecmp(vp
->name
, digits
, strlen(vp
->name
)))
3564 n
= myrpt
->longestfunc
;
3565 if (command_source
== SOURCE_LNK
) n
= myrpt
->link_longestfunc
;
3567 if (command_source
== SOURCE_PHONE
) n
= myrpt
->phone_longestfunc
;
3569 if (command_source
== SOURCE_DPHONE
) n
= myrpt
->dphone_longestfunc
;
3571 if(strlen(digits
) >= n
)
3574 return DC_INDETERMINATE
;
3576 /* Found a match, retrieve value part and parse */
3577 strncpy(workstring
, vp
->value
, sizeof(workstring
) - 1 );
3578 stringp
= workstring
;
3579 action
= strsep(&stringp
, ",");
3582 printf("@@@@ action: %s, param = %s\n",action
, (param
) ? param
: "(null)");
3583 /* Look up the action */
3584 for(i
= 0 ; i
< (sizeof(function_table
)/sizeof(struct function_table_tag
)); i
++){
3585 if(!strncasecmp(action
, function_table
[i
].action
, strlen(action
)))
3589 printf("@@@@ table index i = %d\n",i
);
3590 if(i
== (sizeof(function_table
)/sizeof(struct function_table_tag
))){
3591 /* Error, action not in table */
3594 if(function_table
[i
].function
== NULL
){
3595 /* Error, function undefined */
3597 printf("@@@@ NULL for action: %s\n",action
);
3600 functiondigits
= digits
+ strlen(vp
->name
);
3601 return (*function_table
[i
].function
)(myrpt
, param
, functiondigits
, command_source
, mylink
);
3605 static void handle_link_data(struct rpt
*myrpt
, struct rpt_link
*mylink
,
3608 char tmp
[300],cmd
[300] = "",dest
[300],src
[300],c
;
3611 struct ast_frame wf
;
3613 wf
.frametype
= AST_FRAME_TEXT
;
3617 wf
.datalen
= strlen(str
) + 1;
3619 /* put string in our buffer */
3620 strncpy(tmp
,str
,sizeof(tmp
) - 1);
3622 if (!strcmp(tmp
,discstr
))
3625 mylink
->retries
= MAX_RETRIES
+ 1;
3626 ast_softhangup(mylink
->chan
,AST_SOFTHANGUP_DEV
);
3629 if (sscanf(tmp
,"%s %s %s %d %c",cmd
,dest
,src
,&seq
,&c
) != 5)
3631 ast_log(LOG_WARNING
, "Unable to parse link string %s\n",str
);
3634 if (strcmp(cmd
,"D"))
3636 ast_log(LOG_WARNING
, "Unable to parse link string %s\n",str
);
3642 strcpy(dest
,myrpt
->name
);
3645 /* if not for me, redistribute to all links */
3646 if (strcmp(dest
,myrpt
->name
))
3648 l
= myrpt
->links
.next
;
3649 /* see if this is one in list */
3650 while(l
!= &myrpt
->links
)
3652 if (l
->name
[0] == '0')
3657 /* dont send back from where it came */
3658 if ((l
== mylink
) || (!strcmp(l
->name
,mylink
->name
)))
3663 /* if it is, send it and we're done */
3664 if (!strcmp(l
->name
,dest
))
3666 /* send, but not to src */
3667 if (strcmp(l
->name
,src
)) {
3668 wf
.data
= strdup(str
);
3669 if (l
->chan
) ast_write(l
->chan
,&wf
);
3675 l
= myrpt
->links
.next
;
3676 /* otherwise, send it to all of em */
3677 while(l
!= &myrpt
->links
)
3679 if (l
->name
[0] == '0')
3684 /* dont send back from where it came */
3685 if ((l
== mylink
) || (!strcmp(l
->name
,mylink
->name
)))
3690 /* send, but not to src */
3691 if (strcmp(l
->name
,src
)) {
3692 wf
.data
= strdup(str
);
3693 if (l
->chan
) ast_write(l
->chan
,&wf
);
3699 rpt_mutex_lock(&myrpt
->lock
);
3700 if (c
== myrpt
->p
.endchar
) myrpt
->stopgen
= 1;
3701 if (myrpt
->callmode
== 1)
3703 myrpt
->exten
[myrpt
->cidx
++] = c
;
3704 myrpt
->exten
[myrpt
->cidx
] = 0;
3705 /* if this exists */
3706 if (ast_exists_extension(myrpt
->pchannel
,myrpt
->patchcontext
,myrpt
->exten
,1,NULL
))
3708 myrpt
->callmode
= 2;
3709 if(!myrpt
->patchquiet
){
3710 rpt_mutex_unlock(&myrpt
->lock
);
3711 rpt_telemetry(myrpt
,PROC
,NULL
);
3712 rpt_mutex_lock(&myrpt
->lock
);
3715 /* if can continue, do so */
3716 if (!ast_canmatch_extension(myrpt
->pchannel
,myrpt
->patchcontext
,myrpt
->exten
,1,NULL
))
3718 /* call has failed, inform user */
3719 myrpt
->callmode
= 4;
3722 if ((myrpt
->callmode
== 2) || (myrpt
->callmode
== 3))
3726 if (c
== myrpt
->p
.funcchar
)
3728 myrpt
->rem_dtmfidx
= 0;
3729 myrpt
->rem_dtmfbuf
[myrpt
->rem_dtmfidx
] = 0;
3730 time(&myrpt
->rem_dtmf_time
);
3731 rpt_mutex_unlock(&myrpt
->lock
);
3734 else if ((c
!= myrpt
->p
.endchar
) && (myrpt
->rem_dtmfidx
>= 0))
3736 time(&myrpt
->rem_dtmf_time
);
3737 if (myrpt
->rem_dtmfidx
< MAXDTMF
)
3739 myrpt
->rem_dtmfbuf
[myrpt
->rem_dtmfidx
++] = c
;
3740 myrpt
->rem_dtmfbuf
[myrpt
->rem_dtmfidx
] = 0;
3742 rpt_mutex_unlock(&myrpt
->lock
);
3743 strncpy(cmd
, myrpt
->rem_dtmfbuf
, sizeof(cmd
) - 1);
3744 res
= collect_function_digits(myrpt
, cmd
, SOURCE_LNK
, mylink
);
3745 rpt_mutex_lock(&myrpt
->lock
);
3749 case DC_INDETERMINATE
:
3753 myrpt
->rem_dtmfidx
= 0;
3754 myrpt
->rem_dtmfbuf
[0] = 0;
3759 myrpt
->totalexecdcommands
++;
3760 myrpt
->dailyexecdcommands
++;
3761 strncpy(myrpt
->lastdtmfcommand
, cmd
, MAXDTMF
-1);
3762 myrpt
->lastdtmfcommand
[MAXDTMF
-1] = '\0';
3763 myrpt
->rem_dtmfbuf
[0] = 0;
3764 myrpt
->rem_dtmfidx
= -1;
3765 myrpt
->rem_dtmf_time
= 0;
3770 myrpt
->rem_dtmfbuf
[0] = 0;
3771 myrpt
->rem_dtmfidx
= -1;
3772 myrpt
->rem_dtmf_time
= 0;
3778 rpt_mutex_unlock(&myrpt
->lock
);
3782 static void handle_link_phone_dtmf(struct rpt
*myrpt
, struct rpt_link
*mylink
,
3789 rpt_mutex_lock(&myrpt
->lock
);
3790 if (c
== myrpt
->p
.endchar
)
3795 rpt_mutex_unlock(&myrpt
->lock
);
3799 if (myrpt
->cmdnode
[0])
3801 myrpt
->cmdnode
[0] = 0;
3802 myrpt
->dtmfidx
= -1;
3803 myrpt
->dtmfbuf
[0] = 0;
3804 rpt_mutex_unlock(&myrpt
->lock
);
3805 rpt_telemetry(myrpt
,COMPLETE
,NULL
);
3809 if (myrpt
->cmdnode
[0])
3811 rpt_mutex_unlock(&myrpt
->lock
);
3812 send_link_dtmf(myrpt
,c
);
3815 if (myrpt
->callmode
== 1)
3817 myrpt
->exten
[myrpt
->cidx
++] = c
;
3818 myrpt
->exten
[myrpt
->cidx
] = 0;
3819 /* if this exists */
3820 if (ast_exists_extension(myrpt
->pchannel
,myrpt
->patchcontext
,myrpt
->exten
,1,NULL
))
3822 myrpt
->callmode
= 2;
3823 if(!myrpt
->patchquiet
){
3824 rpt_mutex_unlock(&myrpt
->lock
);
3825 rpt_telemetry(myrpt
,PROC
,NULL
);
3826 rpt_mutex_lock(&myrpt
->lock
);
3829 /* if can continue, do so */
3830 if (!ast_canmatch_extension(myrpt
->pchannel
,myrpt
->patchcontext
,myrpt
->exten
,1,NULL
))
3832 /* call has failed, inform user */
3833 myrpt
->callmode
= 4;
3836 if ((myrpt
->callmode
== 2) || (myrpt
->callmode
== 3))
3840 if (c
== myrpt
->p
.funcchar
)
3842 myrpt
->rem_dtmfidx
= 0;
3843 myrpt
->rem_dtmfbuf
[myrpt
->rem_dtmfidx
] = 0;
3844 time(&myrpt
->rem_dtmf_time
);
3845 rpt_mutex_unlock(&myrpt
->lock
);
3848 else if ((c
!= myrpt
->p
.endchar
) && (myrpt
->rem_dtmfidx
>= 0))
3850 time(&myrpt
->rem_dtmf_time
);
3851 if (myrpt
->rem_dtmfidx
< MAXDTMF
)
3853 myrpt
->rem_dtmfbuf
[myrpt
->rem_dtmfidx
++] = c
;
3854 myrpt
->rem_dtmfbuf
[myrpt
->rem_dtmfidx
] = 0;
3856 rpt_mutex_unlock(&myrpt
->lock
);
3857 strncpy(cmd
, myrpt
->rem_dtmfbuf
, sizeof(cmd
) - 1);
3858 switch(mylink
->phonemode
)
3861 res
= collect_function_digits(myrpt
, cmd
,
3862 SOURCE_PHONE
, mylink
);
3865 res
= collect_function_digits(myrpt
, cmd
,
3866 SOURCE_DPHONE
,mylink
);
3869 res
= collect_function_digits(myrpt
, cmd
,
3870 SOURCE_LNK
, mylink
);
3874 rpt_mutex_lock(&myrpt
->lock
);
3878 case DC_INDETERMINATE
:
3886 myrpt
->rem_dtmfidx
= 0;
3887 myrpt
->rem_dtmfbuf
[0] = 0;
3892 myrpt
->totalexecdcommands
++;
3893 myrpt
->dailyexecdcommands
++;
3894 strncpy(myrpt
->lastdtmfcommand
, cmd
, MAXDTMF
-1);
3895 myrpt
->lastdtmfcommand
[MAXDTMF
-1] = '\0';
3896 myrpt
->rem_dtmfbuf
[0] = 0;
3897 myrpt
->rem_dtmfidx
= -1;
3898 myrpt
->rem_dtmf_time
= 0;
3903 myrpt
->rem_dtmfbuf
[0] = 0;
3904 myrpt
->rem_dtmfidx
= -1;
3905 myrpt
->rem_dtmf_time
= 0;
3911 rpt_mutex_unlock(&myrpt
->lock
);
3915 /* Doug Hall RBI-1 serial data definitions:
3917 * Byte 0: Expansion external outputs
3919 * Bits 0-3 are BAND as follows:
3920 * Bits 4-5 are POWER bits as follows:
3924 * Bits 6-7 are always set
3926 * Bits 0-3 MHZ in BCD format
3927 * Bits 4-5 are offset as follows:
3931 * 03 - minus minus (whatever that is)
3932 * Bit 6 is the 0/5 KHZ bit
3933 * Bit 7 is always set
3935 * Bits 0-3 are 10 KHZ in BCD format
3936 * Bits 4-7 are 100 KHZ in BCD format
3937 * Byte 4: PL Tone code and encode/decode enable bits
3938 * Bits 0-5 are PL tone code (comspec binary codes)
3939 * Bit 6 is encode enable/disable
3940 * Bit 7 is decode enable/disable
3943 /* take the frequency from the 10 mhz digits (and up) and convert it
3946 static int rbi_mhztoband(char *str
)
3950 i
= atoi(str
) / 10; /* get the 10's of mhz */
3981 /* take a PL frequency and turn it into a code */
3982 static int rbi_pltocode(char *str
)
3987 s
= strchr(str
,'.');
3989 if (s
) i
= atoi(s
+ 1);
3990 i
+= atoi(str
) * 10;
4074 * Shift out a formatted serial bit stream
4077 static void rbi_out_parallel(struct rpt
*myrpt
,unsigned char *data
)
4081 static volatile long long delayvar
;
4083 for(i
= 0 ; i
< 5 ; i
++){
4085 for(j
= 0 ; j
< 8 ; j
++){
4087 outb(d
,myrpt
->p
.iobase
);
4089 for(delayvar
= 1; delayvar
< 15000; delayvar
++);
4091 outb(d
| 2,myrpt
->p
.iobase
);
4093 for(delayvar
= 1; delayvar
< 30000; delayvar
++);
4094 outb(d
,myrpt
->p
.iobase
);
4096 for(delayvar
= 1; delayvar
< 10000; delayvar
++);
4100 for(delayvar
= 1; delayvar
< 50000; delayvar
++);
4103 static void rbi_out(struct rpt
*myrpt
,unsigned char *data
)
4105 struct zt_radio_param r
;
4107 memset(&r
,0,sizeof(struct zt_radio_param
));
4108 r
.radpar
= ZT_RADPAR_REMMODE
;
4109 r
.data
= ZT_RADPAR_REM_RBI1
;
4110 /* if setparam ioctl fails, its probably not a pciradio card */
4111 if (ioctl(myrpt
->rxchannel
->fds
[0],ZT_RADIO_SETPARAM
,&r
) == -1)
4113 rbi_out_parallel(myrpt
,data
);
4116 r
.radpar
= ZT_RADPAR_REMCOMMAND
;
4117 memcpy(&r
.data
,data
,5);
4118 if (ioctl(myrpt
->rxchannel
->fds
[0],ZT_RADIO_SETPARAM
,&r
) == -1)
4120 ast_log(LOG_WARNING
,"Cannot send RBI command for channel %s\n",myrpt
->rxchannel
->name
);
4125 static int serial_remote_io(struct rpt
*myrpt
, unsigned char *txbuf
, int txbytes
, char *rxbuf
,
4126 int rxmaxbytes
, int asciiflag
)
4129 struct zt_radio_param prm
;
4132 printf("String output was: ");
4133 for(i
= 0; i
< txbytes
; i
++)
4134 printf("%02X ", (unsigned char ) txbuf
[i
]);
4138 prm
.radpar
= ZT_RADPAR_REMMODE
;
4139 if (asciiflag
) prm
.data
= ZT_RADPAR_REM_SERIAL_ASCII
;
4140 else prm
.data
= ZT_RADPAR_REM_SERIAL
;
4141 if (ioctl(myrpt
->rxchannel
->fds
[0],ZT_RADIO_SETPARAM
,&prm
) == -1) return -1;
4142 prm
.radpar
= ZT_RADPAR_REMCOMMAND
;
4143 prm
.data
= rxmaxbytes
;
4144 memcpy(prm
.buf
,txbuf
,txbytes
);
4145 prm
.index
= txbytes
;
4146 if (ioctl(myrpt
->rxchannel
->fds
[0],ZT_RADIO_SETPARAM
,&prm
) == -1) return -1;
4150 memcpy(rxbuf
,prm
.buf
,prm
.index
);
4155 static int setrbi(struct rpt
*myrpt
)
4157 char tmp
[MAXREMSTR
] = "",*s
;
4158 unsigned char rbicmd
[5];
4159 int band
,txoffset
= 0,txpower
= 0,txpl
;
4161 /* must be a remote system */
4162 if (!myrpt
->remote
) return(0);
4163 /* must have rbi hardware */
4164 if (strncmp(myrpt
->remote
,remote_rig_rbi
,3)) return(0);
4165 strncpy(tmp
, myrpt
->freq
, sizeof(tmp
) - 1);
4166 s
= strchr(tmp
,'.');
4167 /* if no decimal, is invalid */
4171 printf("@@@@ Frequency needs a decimal\n");
4176 if (strlen(tmp
) < 2){
4178 printf("@@@@ Bad MHz digits: %s\n", tmp
);
4184 printf("@@@@ Bad KHz digits: %s\n", s
);
4188 if ((s
[2] != '0') && (s
[2] != '5')){
4190 printf("@@@@ KHz must end in 0 or 5: %c\n", s
[2]);
4194 band
= rbi_mhztoband(tmp
);
4197 printf("@@@@ Bad Band: %s\n", tmp
);
4201 txpl
= rbi_pltocode(myrpt
->txpl
);
4205 printf("@@@@ Bad TX PL: %s\n", myrpt
->txpl
);
4210 switch(myrpt
->offset
)
4222 switch(myrpt
->powerlevel
)
4235 rbicmd
[1] = band
| txpower
| 0xc0;
4236 rbicmd
[2] = (*(s
- 2) - '0') | txoffset
| 0x80;
4237 if (s
[2] == '5') rbicmd
[2] |= 0x40;
4238 rbicmd
[3] = ((*s
- '0') << 4) + (s
[1] - '0');
4240 if (myrpt
->txplon
) rbicmd
[4] |= 0x40;
4241 if (myrpt
->rxplon
) rbicmd
[4] |= 0x80;
4242 rbi_out(myrpt
,rbicmd
);
4247 /* Check for valid rbi frequency */
4248 /* Hard coded limits now, configurable later, maybe? */
4250 static int check_freq_rbi(int m
, int d
, int *defmode
)
4252 int dflmd
= REM_MODE_FM
;
4254 if(m
== 50){ /* 6 meters */
4258 else if((m
>= 51) && ( m
< 54)){
4261 else if(m
== 144){ /* 2 meters */
4265 else if((m
>= 145) && (m
< 148)){
4268 else if((m
>= 222) && (m
< 225)){ /* 1.25 meters */
4271 else if((m
>= 430) && (m
< 450)){ /* 70 centimeters */
4274 else if((m
>= 1240) && (m
< 1300)){ /* 23 centimeters */
4288 * Split frequency into mhz and decimals
4291 static int split_freq(char *mhz
, char *decimals
, char *freq
)
4293 char freq_copy
[MAXREMSTR
];
4296 decp
= strchr(strncpy(freq_copy
, freq
, MAXREMSTR
),'.');
4299 strncpy(mhz
, freq_copy
, MAXREMSTR
);
4300 strcpy(decimals
, "00000");
4301 strncpy(decimals
, decp
, strlen(decp
));
4311 * Split ctcss frequency into hertz and decimal
4314 static int split_ctcss_freq(char *hertz
, char *decimal
, char *freq
)
4316 char freq_copy
[MAXREMSTR
];
4319 decp
= strchr(strncpy(freq_copy
, freq
, MAXREMSTR
),'.');
4322 strncpy(hertz
, freq_copy
, MAXREMSTR
);
4323 strncpy(decimal
, decp
, strlen(decp
));
4324 decimal
[strlen(decp
)] = '\0';
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
)
4922 char *s
,*s1
,*s2
,*val
;
4923 int i
,j
,ht
,k
,l
,ls2
,m
,d
,res
,offset
,offsave
, modesave
, defmode
;
4926 char tmp
[20], freq
[20] = "", savestr
[20] = "";
4927 char mhz
[MAXREMSTR
], decimals
[MAXREMSTR
];
4928 struct ast_channel
*mychannel
;
4930 if((!param
) || (command_source
== SOURCE_RPT
) || (command_source
== SOURCE_LNK
))
4933 multimode
= multimode_capable(myrpt
);
4935 mychannel
= myrpt
->remchannel
;
4938 switch(myatoi(param
)){
4940 case 1: /* retrieve memory */
4941 if(strlen(digitbuf
) < 2) /* needs 2 digits */
4944 for(i
= 0 ; i
< 2 ; i
++){
4945 if((digitbuf
[i
] < '0') || (digitbuf
[i
] > '9'))
4949 val
= ast_variable_retrieve(myrpt
->cfg
, myrpt
->p
.memory
, digitbuf
);
4951 if (ast_safe_sleep(mychannel
,1000) == -1)
4953 sayfile(mychannel
,"rpt/memory_notfound");
4956 strncpy(tmp
,val
,sizeof(tmp
) - 1);
4957 s
= strchr(tmp
,',');
4965 strncpy(myrpt
->freq
, tmp
, sizeof(myrpt
->freq
) - 1);
4966 strncpy(myrpt
->rxpl
, s
, sizeof(myrpt
->rxpl
) - 1);
4967 strncpy(myrpt
->txpl
, s
, sizeof(myrpt
->rxpl
) - 1);
4968 myrpt
->remmode
= REM_MODE_FM
;
4969 myrpt
->offset
= REM_SIMPLEX
;
4970 myrpt
->powerlevel
= REM_MEDPWR
;
4971 myrpt
->txplon
= myrpt
->rxplon
= 0;
4977 strcpy(myrpt
->rxpl
, "100.0");
4978 strcpy(myrpt
->txpl
, "100.0");
4979 myrpt
->remmode
= REM_MODE_AM
;
4984 strcpy(myrpt
->rxpl
, "100.0");
4985 strcpy(myrpt
->txpl
, "100.0");
4986 myrpt
->remmode
= REM_MODE_LSB
;
4990 myrpt
->remmode
= REM_MODE_FM
;
4995 myrpt
->powerlevel
= REM_LOWPWR
;
4999 myrpt
->powerlevel
= REM_HIPWR
;
5004 myrpt
->powerlevel
= REM_MEDPWR
;
5008 myrpt
->offset
= REM_MINUS
;
5012 myrpt
->offset
= REM_PLUS
;
5017 myrpt
->offset
= REM_SIMPLEX
;
5032 strcpy(myrpt
->rxpl
, "100.0");
5033 strcpy(myrpt
->txpl
, "100.0");
5034 myrpt
->remmode
= REM_MODE_USB
;
5040 if (setrem(myrpt
) == -1)
5046 case 2: /* set freq and offset */
5049 for(i
= 0, j
= 0, k
= 0, l
= 0 ; digitbuf
[i
] ; i
++){ /* look for M+*K+*O or M+*H+* depending on mode */
5050 if(digitbuf
[i
] == '*'){
5054 if((digitbuf
[i
] < '0') || (digitbuf
[i
] > '9'))
5058 l
++; /* # of digits before first * */
5060 k
++; /* # of digits after first * */
5064 i
= strlen(digitbuf
) - 1;
5066 if((j
> 2) || (l
> 3) || (k
> 6))
5067 goto invalid_freq
; /* &^@#! */
5070 if((j
> 2) || (l
> 4) || (k
> 3))
5071 goto invalid_freq
; /* &^@#! */
5074 /* Wait for M+*K+* */
5077 break; /* Not yet */
5079 /* We have a frequency */
5081 strncpy(tmp
, digitbuf
,sizeof(tmp
) - 1);
5084 s1
= strsep(&s
, "*"); /* Pick off MHz */
5085 s2
= strsep(&s
,"*"); /* Pick off KHz and Hz */
5088 switch(ls2
){ /* Allow partial entry of khz and hz digits for laziness support */
5101 if((s2
[2] != '0')&&(s2
[2] != '5'))
5109 ht
= 10 * (atoi(s2
+(ls2
-1)));
5114 ht
= (atoi(s2
+(ls2
-2)));
5121 /* Check frequency for validity and establish a default mode */
5123 snprintf(freq
, sizeof(freq
), "%s.%03d%02d",s1
, k
, ht
);
5126 printf("New frequency: %s\n", freq
);
5128 split_freq(mhz
, decimals
, freq
);
5132 if(check_freq(myrpt
, m
, d
, &defmode
)) /* Check to see if frequency entered is legit */
5136 if((defmode
== REM_MODE_FM
) && (digitbuf
[i
] == '*')) /* If FM, user must enter and additional offset digit */
5137 break; /* Not yet */
5140 offset
= REM_SIMPLEX
; /* Assume simplex */
5142 if(defmode
== REM_MODE_FM
){
5143 oc
= *s
; /* Pick off offset */
5152 offset
= REM_SIMPLEX
;
5164 offsave
= myrpt
->offset
;
5165 modesave
= myrpt
->remmode
;
5166 strncpy(savestr
, myrpt
->freq
, sizeof(savestr
) - 1);
5167 strncpy(myrpt
->freq
, freq
, sizeof(myrpt
->freq
) - 1);
5168 myrpt
->offset
= offset
;
5169 myrpt
->remmode
= defmode
;
5171 if (setrem(myrpt
) == -1){
5172 myrpt
->offset
= offsave
;
5173 myrpt
->remmode
= modesave
;
5174 strncpy(myrpt
->freq
, savestr
, sizeof(myrpt
->freq
) - 1);
5183 rmt_sayfile(myrpt
, mychannel
, 1000, "rpt/invalid-freq");
5187 case 3: /* set rx PL tone */
5189 for(i
= 0, j
= 0, k
= 0, l
= 0 ; digitbuf
[i
] ; i
++){ /* look for N+*N */
5190 if(digitbuf
[i
] == '*'){
5194 if((digitbuf
[i
] < '0') || (digitbuf
[i
] > '9'))
5203 if((j
> 1) || (k
> 3) || (l
> 1))
5204 return DC_ERROR
; /* &$@^! */
5205 i
= strlen(digitbuf
) - 1;
5206 if((j
!= 1) || (k
< 2)|| (l
!= 1))
5207 break; /* Not yet */
5209 printf("PL digits entered %s\n", digitbuf
);
5211 strncpy(tmp
, digitbuf
, sizeof(tmp
) - 1);
5212 /* see if we have at least 1 */
5213 s
= strchr(tmp
,'*');
5216 strncpy(savestr
, myrpt
->rxpl
, sizeof(savestr
) - 1);
5217 strncpy(myrpt
->rxpl
, tmp
, sizeof(myrpt
->rxpl
) - 1);
5219 if (setrem(myrpt
) == -1){
5220 strncpy(myrpt
->rxpl
, savestr
, sizeof(myrpt
->rxpl
) - 1);
5227 case 4: /* set tx PL tone */
5229 for(i
= 0, j
= 0, k
= 0, l
= 0 ; digitbuf
[i
] ; i
++){ /* look for N+*N */
5230 if(digitbuf
[i
] == '*'){
5234 if((digitbuf
[i
] < '0') || (digitbuf
[i
] > '9'))
5243 if((j
> 1) || (k
> 3) || (l
> 1))
5244 return DC_ERROR
; /* &$@^! */
5245 i
= strlen(digitbuf
) - 1;
5246 if((j
!= 1) || (k
< 2)|| (l
!= 1))
5247 break; /* Not yet */
5249 printf("PL digits entered %s\n", digitbuf
);
5251 strncpy(tmp
, digitbuf
, sizeof(tmp
) - 1);
5252 /* see if we have at least 1 */
5253 s
= strchr(tmp
,'*');
5256 strncpy(savestr
, myrpt
->txpl
, sizeof(savestr
) - 1);
5257 strncpy(myrpt
->txpl
, tmp
, sizeof(myrpt
->txpl
) - 1);
5259 if (setrem(myrpt
) == -1){
5260 strncpy(myrpt
->txpl
, savestr
, sizeof(myrpt
->txpl
) - 1);
5268 case 6: /* MODE (FM,USB,LSB,AM) */
5269 if(strlen(digitbuf
) < 1)
5273 return DC_ERROR
; /* Multimode radios only */
5277 split_freq(mhz
, decimals
, myrpt
->freq
);
5279 if(m
< 29) /* No FM allowed below 29MHz! */
5281 myrpt
->remmode
= REM_MODE_FM
;
5282 res
= rmt_saycharstr(myrpt
, mychannel
, 1000,"FM");
5286 myrpt
->remmode
= REM_MODE_USB
;
5287 res
= rmt_saycharstr(myrpt
, mychannel
, 1000,"USB");
5291 myrpt
->remmode
= REM_MODE_LSB
;
5292 res
= rmt_saycharstr(myrpt
, mychannel
, 1000,"LSB");
5296 myrpt
->remmode
= REM_MODE_AM
;
5297 res
= rmt_saycharstr(myrpt
, mychannel
, 1000,"AM");
5310 case 100: /* other stuff */
5317 res
= rmt_telem_start(myrpt
, mychannel
, 1000);
5318 switch(myatoi(param
)){ /* Quick commands requiring a setrem call */
5319 case 100: /* RX PL Off */
5322 res
= sayfile(mychannel
, "rpt/rxpl");
5324 sayfile(mychannel
, "rpt/off");
5327 case 101: /* RX PL On */
5330 res
= sayfile(mychannel
, "rpt/rxpl");
5332 sayfile(mychannel
, "rpt/on");
5336 case 102: /* TX PL Off */
5339 res
= sayfile(mychannel
, "rpt/txpl");
5341 sayfile(mychannel
, "rpt/off");
5344 case 103: /* TX PL On */
5347 res
= sayfile(mychannel
, "rpt/txpl");
5349 sayfile(mychannel
, "rpt/on");
5352 case 104: /* Low Power */
5353 myrpt
->powerlevel
= REM_LOWPWR
;
5355 res
= sayfile(mychannel
, "rpt/lopwr");
5358 case 105: /* Medium Power */
5359 myrpt
->powerlevel
= REM_MEDPWR
;
5361 res
= sayfile(mychannel
, "rpt/medpwr");
5364 case 106: /* Hi Power */
5365 myrpt
->powerlevel
= REM_HIPWR
;
5367 res
= sayfile(mychannel
, "rpt/hipwr");
5372 rmt_telem_finish(myrpt
, mychannel
);
5376 res
= rmt_telem_finish(myrpt
, mychannel
);
5380 if (setrem(myrpt
) == -1)
5384 case 107: /* Bump down 20Hz */
5385 multimode_bump_freq(myrpt
, -20);
5388 case 108: /* Bump down 100Hz */
5389 multimode_bump_freq(myrpt
, -100);
5392 case 109: /* Bump down 500Hz */
5393 multimode_bump_freq(myrpt
, -500);
5396 case 110: /* Bump up 20Hz */
5397 multimode_bump_freq(myrpt
, 20);
5400 case 111: /* Bump up 100Hz */
5401 multimode_bump_freq(myrpt
, 100);
5404 case 112: /* Bump up 500Hz */
5405 multimode_bump_freq(myrpt
, 500);
5415 myrpt
->remotetx
= 0;
5416 ast_indicate(myrpt
->txchannel
,AST_CONTROL_RADIO_UNKEY
);
5417 if (!myrpt
->remoterx
)
5418 ast_indicate(mychannel
,AST_CONTROL_RADIO_KEY
);
5419 if (ast_safe_sleep(mychannel
,1000) == -1)
5422 switch(myatoi(param
)){
5424 case 113: /* Scan down slow */
5425 res
= sayfile(mychannel
,"rpt/down");
5427 res
= sayfile(mychannel
, "rpt/slow");
5429 myrpt
->scantimer
= REM_SCANTIME
;
5430 myrpt
->hfscanmode
= HF_SCAN_DOWN_SLOW
;
5434 case 114: /* Scan down quick */
5435 res
= sayfile(mychannel
,"rpt/down");
5437 res
= sayfile(mychannel
, "rpt/quick");
5439 myrpt
->scantimer
= REM_SCANTIME
;
5440 myrpt
->hfscanmode
= HF_SCAN_DOWN_QUICK
;
5444 case 115: /* Scan down fast */
5445 res
= sayfile(mychannel
,"rpt/down");
5447 res
= sayfile(mychannel
, "rpt/fast");
5449 myrpt
->scantimer
= REM_SCANTIME
;
5450 myrpt
->hfscanmode
= HF_SCAN_DOWN_FAST
;
5454 case 116: /* Scan up slow */
5455 res
= sayfile(mychannel
,"rpt/up");
5457 res
= sayfile(mychannel
, "rpt/slow");
5459 myrpt
->scantimer
= REM_SCANTIME
;
5460 myrpt
->hfscanmode
= HF_SCAN_UP_SLOW
;
5464 case 117: /* Scan up quick */
5465 res
= sayfile(mychannel
,"rpt/up");
5467 res
= sayfile(mychannel
, "rpt/quick");
5469 myrpt
->scantimer
= REM_SCANTIME
;
5470 myrpt
->hfscanmode
= HF_SCAN_UP_QUICK
;
5474 case 118: /* Scan up fast */
5475 res
= sayfile(mychannel
,"rpt/up");
5477 res
= sayfile(mychannel
, "rpt/fast");
5479 myrpt
->scantimer
= REM_SCANTIME
;
5480 myrpt
->hfscanmode
= HF_SCAN_UP_FAST
;
5484 rmt_telem_finish(myrpt
,mychannel
);
5488 case 119: /* Tune Request */
5489 myrpt
->tunerequest
= 1;
5492 case 5: /* Long Status */
5493 case 140: /* Short Status */
5494 res
= rmt_telem_start(myrpt
, mychannel
, 1000);
5496 res
= sayfile(mychannel
,"rpt/node");
5498 res
= saycharstr(mychannel
, myrpt
->name
);
5500 res
= sayfile(mychannel
,"rpt/frequency");
5502 res
= split_freq(mhz
, decimals
, myrpt
->freq
);
5506 res
= saynum(mychannel
, m
);
5508 res
= saycharstr(mychannel
, mhz
);
5511 res
= sayfile(mychannel
, "letters/dot");
5513 res
= saycharstr(mychannel
, decimals
);
5516 rmt_telem_finish(myrpt
,mychannel
);
5519 if(myrpt
->remmode
== REM_MODE_FM
){ /* Mode FM? */
5520 switch(myrpt
->offset
){
5523 res
= sayfile(mychannel
,"rpt/minus");
5527 res
= sayfile(mychannel
,"rpt/simplex");
5531 res
= sayfile(mychannel
,"rpt/plus");
5539 else{ /* Must be USB, LSB, or AM */
5540 switch(myrpt
->remmode
){
5543 res
= saycharstr(mychannel
, "USB");
5547 res
= saycharstr(mychannel
, "LSB");
5551 res
= saycharstr(mychannel
, "AM");
5561 rmt_telem_finish(myrpt
,mychannel
);
5565 if(myatoi(param
) == 140){ /* Short status? */
5567 res
= rmt_telem_finish(myrpt
, mychannel
);
5573 switch(myrpt
->powerlevel
){
5576 res
= sayfile(mychannel
,"rpt/lopwr") ;
5580 res
= sayfile(mychannel
,"rpt/medpwr");
5583 res
= sayfile(mychannel
,"rpt/hipwr");
5586 if (res
|| (sayfile(mychannel
,"rpt/rxpl") == -1) ||
5587 (sayfile(mychannel
,"rpt/frequency") == -1) ||
5588 (saycharstr(mychannel
,myrpt
->rxpl
) == -1) ||
5589 (sayfile(mychannel
,"rpt/txpl") == -1) ||
5590 (sayfile(mychannel
,"rpt/frequency") == -1) ||
5591 (saycharstr(mychannel
,myrpt
->txpl
) == -1) ||
5592 (sayfile(mychannel
,"rpt/txpl") == -1) ||
5593 (sayfile(mychannel
,((myrpt
->txplon
) ? "rpt/on" : "rpt/off")) == -1) ||
5594 (sayfile(mychannel
,"rpt/rxpl") == -1) ||
5595 (sayfile(mychannel
,((myrpt
->rxplon
) ? "rpt/on" : "rpt/off")) == -1))
5597 rmt_telem_finish(myrpt
,mychannel
);
5601 res
= rmt_telem_finish(myrpt
,mychannel
);
5610 return DC_INDETERMINATE
;
5613 static int handle_remote_dtmf_digit(struct rpt
*myrpt
,char c
, char *keyed
, int phonemode
)
5616 int ret
,res
= 0,src
;
5618 /* Stop scan mode if in scan mode */
5619 if(myrpt
->hfscanmode
){
5626 if ((myrpt
->dtmf_time_rem
+ DTMF_TIMEOUT
) < now
)
5628 myrpt
->dtmfidx
= -1;
5629 myrpt
->dtmfbuf
[0] = 0;
5630 myrpt
->dtmf_time_rem
= 0;
5632 /* if decode not active */
5633 if (myrpt
->dtmfidx
== -1)
5635 /* if not lead-in digit, dont worry */
5636 if (c
!= myrpt
->p
.funcchar
) return 0;
5638 myrpt
->dtmfbuf
[0] = 0;
5639 myrpt
->dtmf_time_rem
= now
;
5642 /* if too many in buffer, start over */
5643 if (myrpt
->dtmfidx
>= MAXDTMF
)
5646 myrpt
->dtmfbuf
[0] = 0;
5647 myrpt
->dtmf_time_rem
= now
;
5649 if (c
== myrpt
->p
.funcchar
)
5651 /* if star at beginning, or 2 together, erase buffer */
5652 if ((myrpt
->dtmfidx
< 1) ||
5653 (myrpt
->dtmfbuf
[myrpt
->dtmfidx
- 1] == myrpt
->p
.funcchar
))
5656 myrpt
->dtmfbuf
[0] = 0;
5657 myrpt
->dtmf_time_rem
= now
;
5661 myrpt
->dtmfbuf
[myrpt
->dtmfidx
++] = c
;
5662 myrpt
->dtmfbuf
[myrpt
->dtmfidx
] = 0;
5663 myrpt
->dtmf_time_rem
= now
;
5667 if (phonemode
> 1) src
= SOURCE_DPHONE
;
5668 else if (phonemode
) src
= SOURCE_PHONE
;
5669 ret
= collect_function_digits(myrpt
, myrpt
->dtmfbuf
, src
, NULL
);
5673 case DC_INDETERMINATE
:
5678 if (keyed
) *keyed
= 1;
5684 myrpt
->dtmfbuf
[0] = 0;
5690 myrpt
->totalexecdcommands
++;
5691 myrpt
->dailyexecdcommands
++;
5692 strncpy(myrpt
->lastdtmfcommand
, myrpt
->dtmfbuf
, MAXDTMF
-1);
5693 myrpt
->lastdtmfcommand
[MAXDTMF
-1] = '\0';
5694 myrpt
->dtmfbuf
[0] = 0;
5695 myrpt
->dtmfidx
= -1;
5696 myrpt
->dtmf_time_rem
= 0;
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 strncpy(tmp
,str
,sizeof(tmp
) - 1);
5719 if (!strcmp(tmp
,discstr
)) return 0;
5720 if (sscanf(tmp
,"%s %s %s %d %c",cmd
,dest
,src
,&seq
,&c
) != 5)
5722 ast_log(LOG_WARNING
, "Unable to parse link string %s\n",str
);
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
)
5775 char *val
, *s
, *s1
, *s2
, *tele
;
5776 char tmp
[300], deststr
[300] = "";
5778 val
= ast_variable_retrieve(myrpt
->cfg
, myrpt
->p
.nodes
, l
->name
);
5781 fprintf(stderr
,"attempt_reconnect: cannot find node %s\n",l
->name
);
5785 rpt_mutex_lock(&myrpt
->lock
);
5786 /* remove from queue */
5787 remque((struct qelem
*) l
);
5788 rpt_mutex_unlock(&myrpt
->lock
);
5789 strncpy(tmp
,val
,sizeof(tmp
) - 1);
5791 s1
= strsep(&s
,",");
5792 s2
= strsep(&s
,",");
5793 snprintf(deststr
, sizeof(deststr
), "IAX2/%s", s1
);
5794 tele
= strchr(deststr
, '/');
5796 fprintf(stderr
,"attempt_reconnect:Dial number (%s) must be in format tech/number\n",deststr
);
5802 l
->chan
= ast_request(deststr
, AST_FORMAT_SLINEAR
, tele
,NULL
);
5804 ast_set_read_format(l
->chan
, AST_FORMAT_SLINEAR
);
5805 ast_set_write_format(l
->chan
, AST_FORMAT_SLINEAR
);
5806 l
->chan
->whentohangup
= 0;
5807 l
->chan
->appl
= "Apprpt";
5808 l
->chan
->data
= "(Remote Rx)";
5809 if (option_verbose
> 2)
5810 ast_verbose(VERBOSE_PREFIX_3
"rpt (attempt_reconnect) initiating call to %s/%s on %s\n",
5811 deststr
, tele
, l
->chan
->name
);
5812 if(l
->chan
->cid
.cid_num
)
5813 free(l
->chan
->cid
.cid_num
);
5814 l
->chan
->cid
.cid_num
= strdup(myrpt
->name
);
5815 ast_call(l
->chan
,tele
,999);
5820 if (option_verbose
> 2)
5821 ast_verbose(VERBOSE_PREFIX_3
"Unable to place call to %s/%s on %s\n",
5822 deststr
,tele
,l
->chan
->name
);
5825 rpt_mutex_lock(&myrpt
->lock
);
5826 /* put back in queue */
5827 insque((struct qelem
*)l
,(struct qelem
*)myrpt
->links
.next
);
5828 rpt_mutex_unlock(&myrpt
->lock
);
5829 ast_log(LOG_NOTICE
,"Reconnect Attempt to %s in process\n",l
->name
);
5833 /* 0 return=continue, 1 return = break, -1 return = error */
5834 static void local_dtmf_helper(struct rpt
*myrpt
,char c
)
5837 pthread_attr_t attr
;
5838 char cmd
[MAXDTMF
+1] = "";
5840 if (c
== myrpt
->p
.endchar
)
5842 /* if in simple mode, kill autopatch */
5843 if (myrpt
->p
.simple
&& myrpt
->callmode
)
5845 rpt_mutex_lock(&myrpt
->lock
);
5846 myrpt
->callmode
= 0;
5847 rpt_mutex_unlock(&myrpt
->lock
);
5848 rpt_telemetry(myrpt
,TERM
,NULL
);
5851 rpt_mutex_lock(&myrpt
->lock
);
5853 if (myrpt
->cmdnode
[0])
5855 myrpt
->cmdnode
[0] = 0;
5856 myrpt
->dtmfidx
= -1;
5857 myrpt
->dtmfbuf
[0] = 0;
5858 rpt_mutex_unlock(&myrpt
->lock
);
5859 rpt_telemetry(myrpt
,COMPLETE
,NULL
);
5860 } else rpt_mutex_unlock(&myrpt
->lock
);
5863 rpt_mutex_lock(&myrpt
->lock
);
5864 if (myrpt
->cmdnode
[0])
5866 rpt_mutex_unlock(&myrpt
->lock
);
5867 send_link_dtmf(myrpt
,c
);
5870 if (!myrpt
->p
.simple
)
5872 if (c
== myrpt
->p
.funcchar
)
5875 myrpt
->dtmfbuf
[myrpt
->dtmfidx
] = 0;
5876 rpt_mutex_unlock(&myrpt
->lock
);
5877 time(&myrpt
->dtmf_time
);
5880 else if ((c
!= myrpt
->p
.endchar
) && (myrpt
->dtmfidx
>= 0))
5882 time(&myrpt
->dtmf_time
);
5884 if (myrpt
->dtmfidx
< MAXDTMF
)
5886 myrpt
->dtmfbuf
[myrpt
->dtmfidx
++] = c
;
5887 myrpt
->dtmfbuf
[myrpt
->dtmfidx
] = 0;
5889 strncpy(cmd
, myrpt
->dtmfbuf
, sizeof(cmd
) - 1);
5891 rpt_mutex_unlock(&myrpt
->lock
);
5892 res
= collect_function_digits(myrpt
, cmd
, SOURCE_RPT
, NULL
);
5893 rpt_mutex_lock(&myrpt
->lock
);
5895 case DC_INDETERMINATE
:
5899 myrpt
->dtmfbuf
[0] = 0;
5902 myrpt
->totalexecdcommands
++;
5903 myrpt
->dailyexecdcommands
++;
5904 strncpy(myrpt
->lastdtmfcommand
, cmd
, MAXDTMF
-1);
5905 myrpt
->lastdtmfcommand
[MAXDTMF
-1] = '\0';
5906 myrpt
->dtmfbuf
[0] = 0;
5907 myrpt
->dtmfidx
= -1;
5908 myrpt
->dtmf_time
= 0;
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 strncpy(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
);
5944 if (myrpt
->callmode
== 1)
5946 myrpt
->exten
[myrpt
->cidx
++] = c
;
5947 myrpt
->exten
[myrpt
->cidx
] = 0;
5948 /* if this exists */
5949 if (ast_exists_extension(myrpt
->pchannel
,myrpt
->patchcontext
,myrpt
->exten
,1,NULL
))
5951 myrpt
->callmode
= 2;
5952 rpt_mutex_unlock(&myrpt
->lock
);
5953 if(!myrpt
->patchquiet
)
5954 rpt_telemetry(myrpt
,PROC
,NULL
);
5957 /* if can continue, do so */
5958 if (!ast_canmatch_extension(myrpt
->pchannel
,myrpt
->patchcontext
,myrpt
->exten
,1,NULL
))
5960 /* call has failed, inform user */
5961 myrpt
->callmode
= 4;
5963 rpt_mutex_unlock(&myrpt
->lock
);
5966 if ((myrpt
->callmode
== 2) || (myrpt
->callmode
== 3))
5970 rpt_mutex_unlock(&myrpt
->lock
);
5975 /* place an ID event in the telemetry queue */
5977 static void queue_id(struct rpt
*myrpt
)
5979 myrpt
->mustid
= myrpt
->tailid
= 0;
5980 myrpt
->idtimer
= myrpt
->p
.idtime
; /* Reset our ID timer */
5981 rpt_mutex_unlock(&myrpt
->lock
);
5982 rpt_telemetry(myrpt
,ID
,NULL
);
5983 rpt_mutex_lock(&myrpt
->lock
);
5988 static void do_scheduler(struct rpt
*myrpt
)
5993 memcpy(&myrpt
->lasttv
, &myrpt
->curtv
, sizeof(struct timeval
));
5995 if( (res
= gettimeofday(&myrpt
->curtv
, NULL
)) < 0)
5996 ast_log(LOG_NOTICE
, "Scheduler gettime of day returned: %s\n", strerror(res
));
5998 /* Try to get close to a 1 second resolution */
6000 if(myrpt
->lasttv
.tv_sec
== myrpt
->curtv
.tv_sec
)
6003 ast_localtime(&myrpt
->curtv
.tv_sec
, &tmnow
, NULL
);
6005 /* If midnight, then reset all daily statistics */
6007 if((tmnow
.tm_hour
== 0)&&(tmnow
.tm_min
== 0)&&(tmnow
.tm_sec
== 0)){
6008 myrpt
->dailykeyups
= 0;
6009 myrpt
->dailytxtime
= 0;
6010 myrpt
->dailykerchunks
= 0;
6011 myrpt
->dailyexecdcommands
= 0;
6016 /* single thread with one file (request) to dial */
6017 static void *rpt(void *this)
6019 struct rpt
*myrpt
= (struct rpt
*)this;
6020 char *tele
,*idtalkover
,c
;
6021 int ms
= MSWAIT
,i
,lasttx
=0,val
,remrx
=0,identqueued
,othertelemqueued
,tailmessagequeued
,ctqueued
;
6022 struct ast_channel
*who
;
6023 ZT_CONFINFO ci
; /* conference info */
6025 struct rpt_link
*l
,*m
;
6026 struct rpt_tele
*telem
;
6029 rpt_mutex_lock(&myrpt
->lock
);
6031 telem
= myrpt
->tele
.next
;
6032 while(telem
!= &myrpt
->tele
)
6034 ast_softhangup(telem
->chan
,AST_SOFTHANGUP_DEV
);
6035 telem
= telem
->next
;
6037 rpt_mutex_unlock(&myrpt
->lock
);
6038 /* find our index, and load the vars initially */
6039 for(i
= 0; i
< nrpts
; i
++)
6041 if (&rpt_vars
[i
] == myrpt
)
6047 rpt_mutex_lock(&myrpt
->lock
);
6048 strncpy(tmpstr
,myrpt
->rxchanname
,sizeof(tmpstr
) - 1);
6049 tele
= strchr(tmpstr
,'/');
6052 fprintf(stderr
,"rpt:Rxchannel Dial number (%s) must be in format tech/number\n",myrpt
->rxchanname
);
6053 rpt_mutex_unlock(&myrpt
->lock
);
6054 myrpt
->rpt_thread
= AST_PTHREADT_STOP
;
6058 myrpt
->rxchannel
= ast_request(tmpstr
,AST_FORMAT_SLINEAR
,tele
,NULL
);
6059 if (myrpt
->rxchannel
)
6061 if (myrpt
->rxchannel
->_state
== AST_STATE_BUSY
)
6063 fprintf(stderr
,"rpt:Sorry unable to obtain Rx channel\n");
6064 rpt_mutex_unlock(&myrpt
->lock
);
6065 ast_hangup(myrpt
->rxchannel
);
6066 myrpt
->rpt_thread
= AST_PTHREADT_STOP
;
6069 ast_set_read_format(myrpt
->rxchannel
,AST_FORMAT_SLINEAR
);
6070 ast_set_write_format(myrpt
->rxchannel
,AST_FORMAT_SLINEAR
);
6071 myrpt
->rxchannel
->whentohangup
= 0;
6072 myrpt
->rxchannel
->appl
= "Apprpt";
6073 myrpt
->rxchannel
->data
= "(Repeater Rx)";
6074 if (option_verbose
> 2)
6075 ast_verbose(VERBOSE_PREFIX_3
"rpt (Rx) initiating call to %s/%s on %s\n",
6076 tmpstr
,tele
,myrpt
->rxchannel
->name
);
6077 ast_call(myrpt
->rxchannel
,tele
,999);
6078 if (myrpt
->rxchannel
->_state
!= AST_STATE_UP
)
6080 rpt_mutex_unlock(&myrpt
->lock
);
6081 ast_hangup(myrpt
->rxchannel
);
6082 myrpt
->rpt_thread
= AST_PTHREADT_STOP
;
6088 fprintf(stderr
,"rpt:Sorry unable to obtain Rx channel\n");
6089 rpt_mutex_unlock(&myrpt
->lock
);
6090 myrpt
->rpt_thread
= AST_PTHREADT_STOP
;
6093 if (myrpt
->txchanname
)
6095 strncpy(tmpstr
,myrpt
->txchanname
,sizeof(tmpstr
) - 1);
6096 tele
= strchr(tmpstr
,'/');
6099 fprintf(stderr
,"rpt:Txchannel Dial number (%s) must be in format tech/number\n",myrpt
->txchanname
);
6100 rpt_mutex_unlock(&myrpt
->lock
);
6101 ast_hangup(myrpt
->rxchannel
);
6102 myrpt
->rpt_thread
= AST_PTHREADT_STOP
;
6106 myrpt
->txchannel
= ast_request(tmpstr
,AST_FORMAT_SLINEAR
,tele
,NULL
);
6107 if (myrpt
->txchannel
)
6109 if (myrpt
->txchannel
->_state
== AST_STATE_BUSY
)
6111 fprintf(stderr
,"rpt:Sorry unable to obtain Tx channel\n");
6112 rpt_mutex_unlock(&myrpt
->lock
);
6113 ast_hangup(myrpt
->txchannel
);
6114 ast_hangup(myrpt
->rxchannel
);
6115 myrpt
->rpt_thread
= AST_PTHREADT_STOP
;
6118 ast_set_read_format(myrpt
->txchannel
,AST_FORMAT_SLINEAR
);
6119 ast_set_write_format(myrpt
->txchannel
,AST_FORMAT_SLINEAR
);
6120 myrpt
->txchannel
->whentohangup
= 0;
6121 myrpt
->txchannel
->appl
= "Apprpt";
6122 myrpt
->txchannel
->data
= "(Repeater Tx)";
6123 if (option_verbose
> 2)
6124 ast_verbose(VERBOSE_PREFIX_3
"rpt (Tx) initiating call to %s/%s on %s\n",
6125 tmpstr
,tele
,myrpt
->txchannel
->name
);
6126 ast_call(myrpt
->txchannel
,tele
,999);
6127 if (myrpt
->rxchannel
->_state
!= AST_STATE_UP
)
6129 rpt_mutex_unlock(&myrpt
->lock
);
6130 ast_hangup(myrpt
->rxchannel
);
6131 ast_hangup(myrpt
->txchannel
);
6132 myrpt
->rpt_thread
= AST_PTHREADT_STOP
;
6138 fprintf(stderr
,"rpt:Sorry unable to obtain Tx channel\n");
6139 rpt_mutex_unlock(&myrpt
->lock
);
6140 ast_hangup(myrpt
->rxchannel
);
6141 myrpt
->rpt_thread
= AST_PTHREADT_STOP
;
6147 myrpt
->txchannel
= myrpt
->rxchannel
;
6149 ast_indicate(myrpt
->txchannel
,AST_CONTROL_RADIO_KEY
);
6150 ast_indicate(myrpt
->txchannel
,AST_CONTROL_RADIO_UNKEY
);
6151 /* allocate a pseudo-channel thru asterisk */
6152 myrpt
->pchannel
= ast_request("zap",AST_FORMAT_SLINEAR
,"pseudo",NULL
);
6153 if (!myrpt
->pchannel
)
6155 fprintf(stderr
,"rpt:Sorry unable to obtain pseudo channel\n");
6156 rpt_mutex_unlock(&myrpt
->lock
);
6157 if (myrpt
->txchannel
!= myrpt
->rxchannel
)
6158 ast_hangup(myrpt
->txchannel
);
6159 ast_hangup(myrpt
->rxchannel
);
6160 myrpt
->rpt_thread
= AST_PTHREADT_STOP
;
6163 /* make a conference for the tx */
6165 ci
.confno
= -1; /* make a new conf */
6166 ci
.confmode
= ZT_CONF_CONF
| ZT_CONF_LISTENER
;
6167 /* first put the channel on the conference in proper mode */
6168 if (ioctl(myrpt
->txchannel
->fds
[0],ZT_SETCONF
,&ci
) == -1)
6170 ast_log(LOG_WARNING
, "Unable to set conference mode to Announce\n");
6171 rpt_mutex_unlock(&myrpt
->lock
);
6172 ast_hangup(myrpt
->pchannel
);
6173 if (myrpt
->txchannel
!= myrpt
->rxchannel
)
6174 ast_hangup(myrpt
->txchannel
);
6175 ast_hangup(myrpt
->rxchannel
);
6176 myrpt
->rpt_thread
= AST_PTHREADT_STOP
;
6179 /* save tx conference number */
6180 myrpt
->txconf
= ci
.confno
;
6181 /* make a conference for the pseudo */
6183 ci
.confno
= -1; /* make a new conf */
6184 ci
.confmode
= ((myrpt
->p
.duplex
== 2) || (myrpt
->p
.duplex
== 4)) ? ZT_CONF_CONFANNMON
:
6185 (ZT_CONF_CONF
| ZT_CONF_LISTENER
| ZT_CONF_TALKER
);
6186 /* first put the channel on the conference in announce mode */
6187 if (ioctl(myrpt
->pchannel
->fds
[0],ZT_SETCONF
,&ci
) == -1)
6189 ast_log(LOG_WARNING
, "Unable to set conference mode to Announce\n");
6190 rpt_mutex_unlock(&myrpt
->lock
);
6191 ast_hangup(myrpt
->pchannel
);
6192 if (myrpt
->txchannel
!= myrpt
->rxchannel
)
6193 ast_hangup(myrpt
->txchannel
);
6194 ast_hangup(myrpt
->rxchannel
);
6195 myrpt
->rpt_thread
= AST_PTHREADT_STOP
;
6198 /* save pseudo channel conference number */
6199 myrpt
->conf
= ci
.confno
;
6200 /* allocate a pseudo-channel thru asterisk */
6201 myrpt
->txpchannel
= ast_request("zap",AST_FORMAT_SLINEAR
,"pseudo",NULL
);
6202 if (!myrpt
->txpchannel
)
6204 fprintf(stderr
,"rpt:Sorry unable to obtain pseudo channel\n");
6205 rpt_mutex_unlock(&myrpt
->lock
);
6206 ast_hangup(myrpt
->pchannel
);
6207 if (myrpt
->txchannel
!= myrpt
->rxchannel
)
6208 ast_hangup(myrpt
->txchannel
);
6209 ast_hangup(myrpt
->rxchannel
);
6210 myrpt
->rpt_thread
= AST_PTHREADT_STOP
;
6213 /* make a conference for the tx */
6215 ci
.confno
= myrpt
->txconf
;
6216 ci
.confmode
= ZT_CONF_CONF
| ZT_CONF_TALKER
;
6217 /* first put the channel on the conference in proper mode */
6218 if (ioctl(myrpt
->txpchannel
->fds
[0],ZT_SETCONF
,&ci
) == -1)
6220 ast_log(LOG_WARNING
, "Unable to set conference mode to Announce\n");
6221 rpt_mutex_unlock(&myrpt
->lock
);
6222 ast_hangup(myrpt
->txpchannel
);
6223 ast_hangup(myrpt
->pchannel
);
6224 if (myrpt
->txchannel
!= myrpt
->rxchannel
)
6225 ast_hangup(myrpt
->txchannel
);
6226 ast_hangup(myrpt
->rxchannel
);
6227 myrpt
->rpt_thread
= AST_PTHREADT_STOP
;
6230 /* Now, the idea here is to copy from the physical rx channel buffer
6231 into the pseudo tx buffer, and from the pseudo rx buffer into the
6232 tx channel buffer */
6233 myrpt
->links
.next
= &myrpt
->links
;
6234 myrpt
->links
.prev
= &myrpt
->links
;
6235 myrpt
->tailtimer
= 0;
6237 myrpt
->tmsgtimer
= myrpt
->p
.tailmessagetime
;
6238 myrpt
->idtimer
= myrpt
->p
.politeid
;
6239 myrpt
->mustid
= myrpt
->tailid
= 0;
6240 myrpt
->callmode
= 0;
6241 myrpt
->tounkeyed
= 0;
6242 myrpt
->tonotify
= 0;
6243 myrpt
->retxtimer
= 0;
6244 myrpt
->skedtimer
= 0;
6245 myrpt
->tailevent
= 0;
6248 idtalkover
= ast_variable_retrieve(myrpt
->cfg
, myrpt
->name
, "idtalkover");
6249 myrpt
->dtmfidx
= -1;
6250 myrpt
->dtmfbuf
[0] = 0;
6251 myrpt
->rem_dtmfidx
= -1;
6252 myrpt
->rem_dtmfbuf
[0] = 0;
6253 myrpt
->dtmf_time
= 0;
6254 myrpt
->rem_dtmf_time
= 0;
6256 myrpt
->disgorgetime
= 0;
6257 myrpt
->lastnodewhichkeyedusup
[0] = '\0';
6258 myrpt
->dailytxtime
= 0;
6259 myrpt
->totaltxtime
= 0;
6260 myrpt
->dailykeyups
= 0;
6261 myrpt
->totalkeyups
= 0;
6262 myrpt
->dailykerchunks
= 0;
6263 myrpt
->totalkerchunks
= 0;
6264 myrpt
->dailyexecdcommands
= 0;
6265 myrpt
->totalexecdcommands
= 0;
6266 myrpt
->timeouts
= 0;
6267 myrpt
->exten
[0] = '\0';
6268 myrpt
->lastdtmfcommand
[0] = '\0';
6269 if (myrpt
->p
.startupmacro
)
6271 snprintf(myrpt
->macrobuf
,MAXMACRO
- 1,"PPPP%s",myrpt
->p
.startupmacro
);
6273 rpt_mutex_unlock(&myrpt
->lock
);
6275 ast_channel_setoption(myrpt
->rxchannel
,AST_OPTION_TONE_VERIFY
,&val
,sizeof(char),0);
6277 ast_channel_setoption(myrpt
->rxchannel
,AST_OPTION_RELAXDTMF
,&val
,sizeof(char),0);
6280 struct ast_frame
*f
;
6281 struct ast_channel
*cs
[300];
6282 int totx
=0,elap
=0,n
,toexit
=0;
6285 if((myrpt
->disgorgetime
) && (time(NULL
) >= myrpt
->disgorgetime
)){
6286 struct rpt_link
*zl
;
6287 struct rpt_tele
*zt
;
6289 myrpt
->disgorgetime
= 0;
6290 ast_log(LOG_NOTICE
,"********** Variable Dump Start (app_rpt) **********\n");
6291 ast_log(LOG_NOTICE
,"totx = %d\n",totx
);
6292 ast_log(LOG_NOTICE
,"remrx = %d\n",remrx
);
6293 ast_log(LOG_NOTICE
,"lasttx = %d\n",lasttx
);
6294 ast_log(LOG_NOTICE
,"elap = %d\n",elap
);
6295 ast_log(LOG_NOTICE
,"toexit = %d\n",toexit
);
6297 ast_log(LOG_NOTICE
,"myrpt->keyed = %d\n",myrpt
->keyed
);
6298 ast_log(LOG_NOTICE
,"myrpt->localtx = %d\n",myrpt
->localtx
);
6299 ast_log(LOG_NOTICE
,"myrpt->callmode = %d\n",myrpt
->callmode
);
6300 ast_log(LOG_NOTICE
,"myrpt->enable = %d\n",myrpt
->enable
);
6301 ast_log(LOG_NOTICE
,"myrpt->mustid = %d\n",myrpt
->mustid
);
6302 ast_log(LOG_NOTICE
,"myrpt->tounkeyed = %d\n",myrpt
->tounkeyed
);
6303 ast_log(LOG_NOTICE
,"myrpt->tonotify = %d\n",myrpt
->tonotify
);
6304 ast_log(LOG_NOTICE
,"myrpt->retxtimer = %ld\n",myrpt
->retxtimer
);
6305 ast_log(LOG_NOTICE
,"myrpt->totimer = %d\n",myrpt
->totimer
);
6306 ast_log(LOG_NOTICE
,"myrpt->tailtimer = %d\n",myrpt
->tailtimer
);
6307 ast_log(LOG_NOTICE
,"myrpt->tailevent = %d\n",myrpt
->tailevent
);
6309 zl
= myrpt
->links
.next
;
6310 while(zl
!= &myrpt
->links
){
6311 ast_log(LOG_NOTICE
,"*** Link Name: %s ***\n",zl
->name
);
6312 ast_log(LOG_NOTICE
," link->lasttx %d\n",zl
->lasttx
);
6313 ast_log(LOG_NOTICE
," link->lastrx %d\n",zl
->lastrx
);
6314 ast_log(LOG_NOTICE
," link->connected %d\n",zl
->connected
);
6315 ast_log(LOG_NOTICE
," link->hasconnected %d\n",zl
->hasconnected
);
6316 ast_log(LOG_NOTICE
," link->outbound %d\n",zl
->outbound
);
6317 ast_log(LOG_NOTICE
," link->disced %d\n",zl
->disced
);
6318 ast_log(LOG_NOTICE
," link->killme %d\n",zl
->killme
);
6319 ast_log(LOG_NOTICE
," link->disctime %ld\n",zl
->disctime
);
6320 ast_log(LOG_NOTICE
," link->retrytimer %ld\n",zl
->retrytimer
);
6321 ast_log(LOG_NOTICE
," link->retries = %d\n",zl
->retries
);
6322 ast_log(LOG_NOTICE
," link->reconnects = %d\n",zl
->reconnects
);
6326 zt
= myrpt
->tele
.next
;
6327 if(zt
!= &myrpt
->tele
)
6328 ast_log(LOG_NOTICE
,"*** Telemetry Queue ***\n");
6329 while(zt
!= &myrpt
->tele
){
6330 ast_log(LOG_NOTICE
," Telemetry mode: %d\n",zt
->mode
);
6333 ast_log(LOG_NOTICE
,"******* Variable Dump End (app_rpt) *******\n");
6340 struct rpt_tele
*telem
;
6342 rpt_mutex_lock(&myrpt
->lock
);
6343 telem
= myrpt
->tele
.next
;
6344 while(telem
!= &myrpt
->tele
)
6346 ast_softhangup(telem
->chan
,AST_SOFTHANGUP_DEV
);
6347 telem
= telem
->next
;
6350 rpt_mutex_unlock(&myrpt
->lock
);
6352 /* find our index, and load the vars */
6353 for(i
= 0; i
< nrpts
; i
++)
6355 if (&rpt_vars
[i
] == myrpt
)
6363 rpt_mutex_lock(&myrpt
->lock
);
6364 if (ast_check_hangup(myrpt
->rxchannel
)) break;
6365 if (ast_check_hangup(myrpt
->txchannel
)) break;
6366 if (ast_check_hangup(myrpt
->pchannel
)) break;
6367 if (ast_check_hangup(myrpt
->txpchannel
)) break;
6369 /* Update local tx with keyed if not parsing a command */
6370 myrpt
->localtx
= myrpt
->keyed
&& (myrpt
->dtmfidx
== -1) && (!myrpt
->cmdnode
[0]);
6371 /* If someone's connected, and they're transmitting from their end to us, set remrx true */
6372 l
= myrpt
->links
.next
;
6374 while(l
!= &myrpt
->links
)
6378 if(l
->name
[0] != '0') /* Ignore '0' nodes */
6379 strcpy(myrpt
->lastnodewhichkeyedusup
, l
->name
); /* Note the node which is doing the key up */
6383 /* Create a "must_id" flag for the cleanup ID */
6384 myrpt
->mustid
|= (myrpt
->idtimer
) && (myrpt
->keyed
|| remrx
) ;
6385 /* Build a fresh totx from myrpt->keyed and autopatch activated */
6386 totx
= myrpt
->callmode
;
6387 /* If full duplex, add local tx to totx */
6388 if (myrpt
->p
.duplex
> 1) totx
= totx
|| myrpt
->localtx
;
6389 /* Traverse the telemetry list to see what's queued */
6391 othertelemqueued
= 0;
6392 tailmessagequeued
= 0;
6394 telem
= myrpt
->tele
.next
;
6395 while(telem
!= &myrpt
->tele
)
6397 if((telem
->mode
== ID
) || (telem
->mode
== IDTALKOVER
)){
6398 identqueued
= 1; /* Identification telemetry */
6400 else if(telem
->mode
== TAILMSG
)
6402 tailmessagequeued
= 1; /* Tail message telemetry */
6406 if (telem
->mode
!= UNKEY
)
6407 othertelemqueued
= 1; /* Other telemetry */
6409 ctqueued
= 1; /* Courtesy tone telemetry */
6411 telem
= telem
->next
;
6414 /* Add in any "other" telemetry, if 3/4 or full duplex */
6415 if (myrpt
->p
.duplex
> 0) totx
= totx
|| othertelemqueued
;
6416 /* Update external (to links) transmitter PTT state with everything but ID, CT, and tailmessage telemetry */
6417 myrpt
->exttx
= totx
;
6418 /* If half or 3/4 duplex, add localtx to external link tx */
6419 if (myrpt
->p
.duplex
< 2) myrpt
->exttx
= myrpt
->exttx
|| myrpt
->localtx
;
6420 /* Add in ID telemetry to local transmitter */
6421 totx
= totx
|| remrx
;
6422 /* If 3/4 or full duplex, add in ident and CT telemetry */
6423 if (myrpt
->p
.duplex
> 0)
6424 totx
= totx
|| identqueued
|| ctqueued
;
6425 /* Reset time out timer variables if there is no activity */
6428 myrpt
->totimer
= myrpt
->p
.totime
;
6429 myrpt
->tounkeyed
= 0;
6430 myrpt
->tonotify
= 0;
6433 myrpt
->tailtimer
= myrpt
->p
.hangtime
; /* Initialize tail timer */
6434 /* Disable the local transmitter if we are timed out */
6435 totx
= totx
&& myrpt
->totimer
;
6436 /* if timed-out and not said already, say it */
6437 if ((!myrpt
->totimer
) && (!myrpt
->tonotify
))
6439 myrpt
->tonotify
= 1;
6441 rpt_mutex_unlock(&myrpt
->lock
);
6442 rpt_telemetry(myrpt
,TIMEOUT
,NULL
);
6443 rpt_mutex_lock(&myrpt
->lock
);
6446 /* If unkey and re-key, reset time out timer */
6447 if ((!totx
) && (!myrpt
->totimer
) && (!myrpt
->tounkeyed
) && (!myrpt
->keyed
))
6449 myrpt
->tounkeyed
= 1;
6451 if ((!totx
) && (!myrpt
->totimer
) && myrpt
->tounkeyed
&& myrpt
->keyed
)
6453 myrpt
->totimer
= myrpt
->p
.totime
;
6454 myrpt
->tounkeyed
= 0;
6455 myrpt
->tonotify
= 0;
6456 rpt_mutex_unlock(&myrpt
->lock
);
6459 /* if timed-out and in circuit busy after call */
6460 if ((!totx
) && (!myrpt
->totimer
) && (myrpt
->callmode
== 4))
6462 myrpt
->callmode
= 0;
6464 /* get rid of tail if timed out */
6465 if (!myrpt
->totimer
) myrpt
->tailtimer
= 0;
6466 /* if not timed-out, add in tail */
6467 if (myrpt
->totimer
) totx
= totx
|| myrpt
->tailtimer
;
6468 /* If user or links key up or are keyed up over standard ID, switch to talkover ID, if one is defined */
6469 /* If tail message, kill the message if someone keys up over it */
6470 if ((myrpt
->keyed
|| remrx
) && ((identqueued
&& idtalkover
) || (tailmessagequeued
))) {
6471 int hasid
= 0,hastalkover
= 0;
6473 telem
= myrpt
->tele
.next
;
6474 while(telem
!= &myrpt
->tele
){
6475 if(telem
->mode
== ID
){
6476 if (telem
->chan
) ast_softhangup(telem
->chan
, AST_SOFTHANGUP_DEV
); /* Whoosh! */
6479 if(telem
->mode
== TAILMSG
){
6480 if (telem
->chan
) ast_softhangup(telem
->chan
, AST_SOFTHANGUP_DEV
); /* Whoosh! */
6482 if (telem
->mode
== IDTALKOVER
) hastalkover
= 1;
6483 telem
= telem
->next
;
6485 rpt_mutex_unlock(&myrpt
->lock
);
6486 if (hasid
&& (!hastalkover
)) rpt_telemetry(myrpt
, IDTALKOVER
, NULL
); /* Start Talkover ID */
6487 rpt_mutex_lock(&myrpt
->lock
);
6489 /* Try to be polite */
6490 /* If the repeater has been inactive for longer than the ID time, do an initial ID in the tail*/
6491 /* If within 30 seconds of the time to ID, try do it in the tail */
6492 /* else if at ID time limit, do it right over the top of them */
6493 /* Lastly, if the repeater has been keyed, and the ID timer is expired, do a clean up ID */
6494 if(myrpt
->mustid
&& (!myrpt
->idtimer
))
6497 if ((totx
&& (!myrpt
->exttx
) &&
6498 (myrpt
->idtimer
<= myrpt
->p
.politeid
) && myrpt
->tailtimer
))
6503 /* If tail timer expires, then check for tail messages */
6505 if(myrpt
->tailevent
){
6506 myrpt
->tailevent
= 0;
6511 else if ((myrpt
->p
.tailmessages
[0]) &&
6512 (myrpt
->p
.tailmessagetime
) && (myrpt
->tmsgtimer
== 0)){
6514 myrpt
->tmsgtimer
= myrpt
->p
.tailmessagetime
;
6515 rpt_mutex_unlock(&myrpt
->lock
);
6516 rpt_telemetry(myrpt
, TAILMSG
, NULL
);
6517 rpt_mutex_lock(&myrpt
->lock
);
6521 /* Main TX control */
6523 /* let telemetry transmit anyway (regardless of timeout) */
6524 if (myrpt
->p
.duplex
> 0) totx
= totx
|| (myrpt
->tele
.next
!= &myrpt
->tele
);
6525 if (totx
&& (!lasttx
))
6528 myrpt
->dailykeyups
++;
6529 myrpt
->totalkeyups
++;
6530 rpt_mutex_unlock(&myrpt
->lock
);
6531 ast_indicate(myrpt
->txchannel
,AST_CONTROL_RADIO_KEY
);
6532 rpt_mutex_lock(&myrpt
->lock
);
6534 totx
= totx
&& myrpt
->enable
;
6535 if ((!totx
) && lasttx
)
6538 rpt_mutex_unlock(&myrpt
->lock
);
6539 ast_indicate(myrpt
->txchannel
,AST_CONTROL_RADIO_UNKEY
);
6540 rpt_mutex_lock(&myrpt
->lock
);
6543 /* if DTMF timeout */
6544 if ((!myrpt
->cmdnode
[0]) && (myrpt
->dtmfidx
>= 0) && ((myrpt
->dtmf_time
+ DTMF_TIMEOUT
) < t
))
6546 myrpt
->dtmfidx
= -1;
6547 myrpt
->dtmfbuf
[0] = 0;
6549 /* if remote DTMF timeout */
6550 if ((myrpt
->rem_dtmfidx
>= 0) && ((myrpt
->rem_dtmf_time
+ DTMF_TIMEOUT
) < t
))
6552 myrpt
->rem_dtmfidx
= -1;
6553 myrpt
->rem_dtmfbuf
[0] = 0;
6558 l
= myrpt
->links
.next
;
6559 while(l
!= &myrpt
->links
)
6563 /* remove from queue */
6564 remque((struct qelem
*) l
);
6565 if (!strcmp(myrpt
->cmdnode
,l
->name
))
6566 myrpt
->cmdnode
[0] = 0;
6567 rpt_mutex_unlock(&myrpt
->lock
);
6568 /* hang-up on call to device */
6569 if (l
->chan
) ast_hangup(l
->chan
);
6570 ast_hangup(l
->pchan
);
6572 rpt_mutex_lock(&myrpt
->lock
);
6573 /* re-start link traversal */
6574 l
= myrpt
->links
.next
;
6580 cs
[n
++] = myrpt
->rxchannel
;
6581 cs
[n
++] = myrpt
->pchannel
;
6582 cs
[n
++] = myrpt
->txpchannel
;
6583 if (myrpt
->txchannel
!= myrpt
->rxchannel
) cs
[n
++] = myrpt
->txchannel
;
6584 l
= myrpt
->links
.next
;
6585 while(l
!= &myrpt
->links
)
6587 if ((!l
->killme
) && (!l
->disctime
) && l
->chan
)
6594 rpt_mutex_unlock(&myrpt
->lock
);
6596 who
= ast_waitfor_n(cs
,n
,&ms
);
6597 if (who
== NULL
) ms
= 0;
6599 rpt_mutex_lock(&myrpt
->lock
);
6600 l
= myrpt
->links
.next
;
6601 while(l
!= &myrpt
->links
)
6605 if ((l
->retxtimer
+= elap
) >= REDUNDANT_TX_TIME
)
6608 if (l
->chan
) ast_indicate(l
->chan
,AST_CONTROL_RADIO_UNKEY
);
6610 } else l
->retxtimer
= 0;
6611 if (l
->disctime
) /* Disconnect timer active on a channel ? */
6613 l
->disctime
-= elap
;
6614 if (l
->disctime
<= 0) /* Disconnect timer expired on inbound channel ? */
6615 l
->disctime
= 0; /* Yep */
6620 l
->retrytimer
-= elap
;
6621 if (l
->retrytimer
< 0) l
->retrytimer
= 0;
6624 /* Tally connect time */
6625 l
->connecttime
+= elap
;
6627 /* ignore non-timing channels */
6628 if (l
->elaptime
< 0)
6633 l
->elaptime
+= elap
;
6634 /* if connection has taken too long */
6635 if ((l
->elaptime
> MAXCONNECTTIME
) &&
6636 ((!l
->chan
) || (l
->chan
->_state
!= AST_STATE_UP
)))
6639 rpt_mutex_unlock(&myrpt
->lock
);
6640 if (l
->chan
) ast_softhangup(l
->chan
,AST_SOFTHANGUP_DEV
);
6641 rpt_mutex_lock(&myrpt
->lock
);
6644 if ((!l
->chan
) && (!l
->retrytimer
) && l
->outbound
&&
6645 (l
->retries
++ < MAX_RETRIES
) && (l
->hasconnected
))
6647 if (l
->chan
) ast_hangup(l
->chan
);
6648 rpt_mutex_unlock(&myrpt
->lock
);
6649 if ((l
->name
[0] != '0') && (!l
->isremote
))
6651 l
->retrytimer
= MAX_RETRIES
+ 1;
6655 if (attempt_reconnect(myrpt
,l
) == -1)
6657 l
->retrytimer
= RETRY_TIMER_MS
;
6660 rpt_mutex_lock(&myrpt
->lock
);
6663 if ((!l
->chan
) && (!l
->retrytimer
) && l
->outbound
&&
6664 (l
->retries
>= MAX_RETRIES
))
6666 /* remove from queue */
6667 remque((struct qelem
*) l
);
6668 if (!strcmp(myrpt
->cmdnode
,l
->name
))
6669 myrpt
->cmdnode
[0] = 0;
6670 rpt_mutex_unlock(&myrpt
->lock
);
6671 if (l
->name
[0] != '0')
6673 if (!l
->hasconnected
)
6674 rpt_telemetry(myrpt
,CONNFAIL
,l
);
6675 else rpt_telemetry(myrpt
,REMDISC
,l
);
6677 /* hang-up on call to device */
6678 ast_hangup(l
->pchan
);
6680 rpt_mutex_lock(&myrpt
->lock
);
6683 if ((!l
->chan
) && (!l
->disctime
) && (!l
->outbound
))
6685 /* remove from queue */
6686 remque((struct qelem
*) l
);
6687 if (!strcmp(myrpt
->cmdnode
,l
->name
))
6688 myrpt
->cmdnode
[0] = 0;
6689 rpt_mutex_unlock(&myrpt
->lock
);
6690 if (l
->name
[0] != '0')
6692 rpt_telemetry(myrpt
,REMDISC
,l
);
6694 /* hang-up on call to device */
6695 ast_hangup(l
->pchan
);
6697 rpt_mutex_lock(&myrpt
->lock
);
6703 myrpt
->dailytxtime
+= elap
;
6704 myrpt
->totaltxtime
+= elap
;
6706 i
= myrpt
->tailtimer
;
6707 if (myrpt
->tailtimer
) myrpt
->tailtimer
-= elap
;
6708 if (myrpt
->tailtimer
< 0) myrpt
->tailtimer
= 0;
6709 if((i
) && (myrpt
->tailtimer
== 0))
6710 myrpt
->tailevent
= 1;
6711 if (myrpt
->totimer
) myrpt
->totimer
-= elap
;
6712 if (myrpt
->totimer
< 0) myrpt
->totimer
= 0;
6713 if (myrpt
->idtimer
) myrpt
->idtimer
-= elap
;
6714 if (myrpt
->idtimer
< 0) myrpt
->idtimer
= 0;
6715 if (myrpt
->tmsgtimer
) myrpt
->tmsgtimer
-= elap
;
6716 if (myrpt
->tmsgtimer
< 0) myrpt
->tmsgtimer
= 0;
6717 /* do macro timers */
6718 if (myrpt
->macrotimer
) myrpt
->macrotimer
-= elap
;
6719 if (myrpt
->macrotimer
< 0) myrpt
->macrotimer
= 0;
6720 /* Execute scheduler appx. every 2 tenths of a second */
6721 if (myrpt
->skedtimer
<= 0){
6722 myrpt
->skedtimer
= 200;
6723 do_scheduler(myrpt
);
6726 myrpt
->skedtimer
-=elap
;
6729 rpt_mutex_unlock(&myrpt
->lock
);
6732 c
= myrpt
->macrobuf
[0];
6733 if (c
&& (!myrpt
->macrotimer
))
6735 myrpt
->macrotimer
= MACROTIME
;
6736 memmove(myrpt
->macrobuf
,myrpt
->macrobuf
+ 1,MAXMACRO
- 1);
6737 if ((c
== 'p') || (c
== 'P'))
6738 myrpt
->macrotimer
= MACROPTIME
;
6739 rpt_mutex_unlock(&myrpt
->lock
);
6740 local_dtmf_helper(myrpt
,c
);
6741 } else rpt_mutex_unlock(&myrpt
->lock
);
6742 if (who
== myrpt
->rxchannel
) /* if it was a read from rx */
6744 f
= ast_read(myrpt
->rxchannel
);
6747 if (debug
) printf("@@@@ rpt:Hung Up\n");
6750 if (f
->frametype
== AST_FRAME_VOICE
)
6752 #ifdef _MDC_DECODE_H_
6753 unsigned char ubuf
[2560];
6758 if (!myrpt
->localtx
) {
6759 memset(f
->data
,0,f
->datalen
);
6762 #ifdef _MDC_DECODE_H_
6763 sp
= (short *) f
->data
;
6764 /* convert block to unsigned char */
6765 for(n
= 0; n
< f
->datalen
/ 2; n
++)
6767 ubuf
[n
] = (*sp
++ >> 8) + 128;
6769 n
= mdc_decoder_process_samples(myrpt
->mdc
,ubuf
,f
->datalen
/ 2);
6772 unsigned char op
,arg
;
6773 unsigned short unitID
;
6775 mdc_decoder_get_packet(myrpt
->mdc
,&op
,&arg
,&unitID
);
6778 ast_log(LOG_NOTICE
,"Got (single-length) packet:\n");
6779 ast_log(LOG_NOTICE
,"op: %02x, arg: %02x, UnitID: %04x\n",
6780 op
& 255,arg
& 255,unitID
);
6782 if ((op
== 1) && (arg
== 0))
6784 myrpt
->lastunit
= unitID
;
6787 if ((debug
> 2) && (i
== 2))
6789 unsigned char op
,arg
,ex1
,ex2
,ex3
,ex4
;
6790 unsigned short unitID
;
6792 mdc_decoder_get_double_packet(myrpt
->mdc
,&op
,&arg
,&unitID
,
6793 &ex1
,&ex2
,&ex3
,&ex4
);
6794 ast_log(LOG_NOTICE
,"Got (double-length) packet:\n");
6795 ast_log(LOG_NOTICE
,"op: %02x, arg: %02x, UnitID: %04x\n",
6796 op
& 255,arg
& 255,unitID
);
6797 ast_log(LOG_NOTICE
,"ex1: %02x, ex2: %02x, ex3: %02x, ex4: %02x\n",
6798 ex1
& 255, ex2
& 255, ex3
& 255, ex4
& 255);
6802 /* apply inbound filters, if any */
6803 rpt_filter(myrpt
,f
->data
,f
->datalen
/ 2);
6805 ast_write(myrpt
->pchannel
,f
);
6807 else if (f
->frametype
== AST_FRAME_DTMF
)
6809 c
= (char) f
->subclass
; /* get DTMF char */
6811 if (!myrpt
->keyed
) continue;
6812 local_dtmf_helper(myrpt
,c
);
6815 else if (f
->frametype
== AST_FRAME_CONTROL
)
6817 if (f
->subclass
== AST_CONTROL_HANGUP
)
6819 if (debug
) printf("@@@@ rpt:Hung Up\n");
6824 if (f
->subclass
== AST_CONTROL_RADIO_KEY
)
6826 if ((!lasttx
) || (myrpt
->p
.duplex
> 1))
6828 if (debug
== 7) printf("@@@@ rx key\n");
6833 if (f
->subclass
== AST_CONTROL_RADIO_UNKEY
)
6835 if ((!lasttx
) || (myrpt
->p
.duplex
> 1))
6837 if (debug
== 7) printf("@@@@ rx un-key\n");
6839 rpt_telemetry(myrpt
,UNKEY
,NULL
);
6848 if (who
== myrpt
->pchannel
) /* if it was a read from pseudo */
6850 f
= ast_read(myrpt
->pchannel
);
6853 if (debug
) printf("@@@@ rpt:Hung Up\n");
6856 if (f
->frametype
== AST_FRAME_VOICE
)
6858 ast_write(myrpt
->txpchannel
,f
);
6860 if (f
->frametype
== AST_FRAME_CONTROL
)
6862 if (f
->subclass
== AST_CONTROL_HANGUP
)
6864 if (debug
) printf("@@@@ rpt:Hung Up\n");
6872 if (who
== myrpt
->txchannel
) /* if it was a read from tx */
6874 f
= ast_read(myrpt
->txchannel
);
6877 if (debug
) printf("@@@@ rpt:Hung Up\n");
6880 if (f
->frametype
== AST_FRAME_CONTROL
)
6882 if (f
->subclass
== AST_CONTROL_HANGUP
)
6884 if (debug
) printf("@@@@ rpt:Hung Up\n");
6893 rpt_mutex_lock(&myrpt
->lock
);
6894 l
= myrpt
->links
.next
;
6895 while(l
!= &myrpt
->links
)
6902 if (who
== l
->chan
) /* if it was a read from rx */
6905 /* see if any other links are receiving */
6906 m
= myrpt
->links
.next
;
6907 while(m
!= &myrpt
->links
)
6909 /* if not us, count it */
6910 if ((m
!= l
) && (m
->lastrx
)) remrx
= 1;
6913 rpt_mutex_unlock(&myrpt
->lock
);
6914 totx
= (((l
->isremote
) ? myrpt
->localtx
:
6915 myrpt
->exttx
) || remrx
) && l
->mode
;
6916 if (l
->chan
&& (l
->lasttx
!= totx
))
6920 ast_indicate(l
->chan
,AST_CONTROL_RADIO_KEY
);
6924 ast_indicate(l
->chan
,AST_CONTROL_RADIO_UNKEY
);
6928 f
= ast_read(l
->chan
);
6931 if ((!l
->disced
) && (!l
->outbound
))
6933 if ((l
->name
[0] == '0') || l
->isremote
)
6936 l
->disctime
= DISC_TIME
;
6937 rpt_mutex_lock(&myrpt
->lock
);
6938 ast_hangup(l
->chan
);
6945 rpt_mutex_lock(&myrpt
->lock
);
6948 if (l
->outbound
&& (l
->retries
++ < MAX_RETRIES
) && (l
->hasconnected
))
6950 rpt_mutex_lock(&myrpt
->lock
);
6951 ast_hangup(l
->chan
);
6953 rpt_mutex_unlock(&myrpt
->lock
);
6954 if (attempt_reconnect(myrpt
,l
) == -1)
6956 l
->retrytimer
= RETRY_TIMER_MS
;
6958 rpt_mutex_lock(&myrpt
->lock
);
6961 rpt_mutex_lock(&myrpt
->lock
);
6962 /* remove from queue */
6963 remque((struct qelem
*) l
);
6964 if (!strcmp(myrpt
->cmdnode
,l
->name
))
6965 myrpt
->cmdnode
[0] = 0;
6966 rpt_mutex_unlock(&myrpt
->lock
);
6967 if (!l
->hasconnected
)
6968 rpt_telemetry(myrpt
,CONNFAIL
,l
);
6969 else if (l
->disced
!= 2) rpt_telemetry(myrpt
,REMDISC
,l
);
6970 /* hang-up on call to device */
6971 ast_hangup(l
->chan
);
6972 ast_hangup(l
->pchan
);
6974 rpt_mutex_lock(&myrpt
->lock
);
6977 if (f
->frametype
== AST_FRAME_VOICE
)
6981 memset(f
->data
,0,f
->datalen
);
6983 ast_write(l
->pchan
,f
);
6985 if (f
->frametype
== AST_FRAME_TEXT
)
6987 handle_link_data(myrpt
,l
,f
->data
);
6989 if (f
->frametype
== AST_FRAME_DTMF
)
6991 handle_link_phone_dtmf(myrpt
,l
,f
->subclass
);
6993 if (f
->frametype
== AST_FRAME_CONTROL
)
6995 if (f
->subclass
== AST_CONTROL_ANSWER
)
6997 char lconnected
= l
->connected
;
6999 l
->hasconnected
= 1;
7003 rpt_telemetry(myrpt
,CONNECTED
,l
);
7008 if (f
->subclass
== AST_CONTROL_RADIO_KEY
)
7010 if (debug
== 7 ) printf("@@@@ rx key\n");
7014 if (f
->subclass
== AST_CONTROL_RADIO_UNKEY
)
7016 if (debug
== 7) printf("@@@@ rx un-key\n");
7019 if (f
->subclass
== AST_CONTROL_HANGUP
)
7022 if ((!l
->outbound
) && (!l
->disced
))
7024 if ((l
->name
[0] == '0') || l
->isremote
)
7027 l
->disctime
= DISC_TIME
;
7028 rpt_mutex_lock(&myrpt
->lock
);
7029 ast_hangup(l
->chan
);
7035 rpt_mutex_lock(&myrpt
->lock
);
7038 if (l
->outbound
&& (l
->retries
++ < MAX_RETRIES
) && (l
->hasconnected
))
7040 rpt_mutex_lock(&myrpt
->lock
);
7041 ast_hangup(l
->chan
);
7043 rpt_mutex_unlock(&myrpt
->lock
);
7044 if (attempt_reconnect(myrpt
,l
) == -1)
7046 l
->retrytimer
= RETRY_TIMER_MS
;
7048 rpt_mutex_lock(&myrpt
->lock
);
7051 rpt_mutex_lock(&myrpt
->lock
);
7052 /* remove from queue */
7053 remque((struct qelem
*) l
);
7054 if (!strcmp(myrpt
->cmdnode
,l
->name
))
7055 myrpt
->cmdnode
[0] = 0;
7056 rpt_mutex_unlock(&myrpt
->lock
);
7057 if (!l
->hasconnected
)
7058 rpt_telemetry(myrpt
,CONNFAIL
,l
);
7059 else if (l
->disced
!= 2) rpt_telemetry(myrpt
,REMDISC
,l
);
7060 /* hang-up on call to device */
7061 ast_hangup(l
->chan
);
7062 ast_hangup(l
->pchan
);
7064 rpt_mutex_lock(&myrpt
->lock
);
7069 rpt_mutex_lock(&myrpt
->lock
);
7072 if (who
== l
->pchan
)
7074 rpt_mutex_unlock(&myrpt
->lock
);
7075 f
= ast_read(l
->pchan
);
7078 if (debug
) printf("@@@@ rpt:Hung Up\n");
7080 rpt_mutex_lock(&myrpt
->lock
);
7083 if (f
->frametype
== AST_FRAME_VOICE
)
7085 if (l
->chan
) ast_write(l
->chan
,f
);
7087 if (f
->frametype
== AST_FRAME_CONTROL
)
7089 if (f
->subclass
== AST_CONTROL_HANGUP
)
7091 if (debug
) printf("@@@@ rpt:Hung Up\n");
7094 rpt_mutex_lock(&myrpt
->lock
);
7099 rpt_mutex_lock(&myrpt
->lock
);
7104 rpt_mutex_unlock(&myrpt
->lock
);
7106 if (who
== myrpt
->txpchannel
) /* if it was a read from remote tx */
7108 f
= ast_read(myrpt
->txpchannel
);
7111 if (debug
) printf("@@@@ rpt:Hung Up\n");
7114 if (f
->frametype
== AST_FRAME_CONTROL
)
7116 if (f
->subclass
== AST_CONTROL_HANGUP
)
7118 if (debug
) printf("@@@@ rpt:Hung Up\n");
7128 ast_hangup(myrpt
->pchannel
);
7129 ast_hangup(myrpt
->txpchannel
);
7130 if (myrpt
->txchannel
!= myrpt
->rxchannel
) ast_hangup(myrpt
->txchannel
);
7131 ast_hangup(myrpt
->rxchannel
);
7132 rpt_mutex_lock(&myrpt
->lock
);
7133 l
= myrpt
->links
.next
;
7134 while(l
!= &myrpt
->links
)
7136 struct rpt_link
*ll
= l
;
7137 /* remove from queue */
7138 remque((struct qelem
*) l
);
7139 /* hang-up on call to device */
7140 if (l
->chan
) ast_hangup(l
->chan
);
7141 ast_hangup(l
->pchan
);
7145 rpt_mutex_unlock(&myrpt
->lock
);
7146 if (debug
) printf("@@@@ rpt:Hung up channel\n");
7147 myrpt
->rpt_thread
= AST_PTHREADT_STOP
;
7153 static void *rpt_master(void *ignore
)
7156 pthread_attr_t attr
;
7157 struct ast_config
*cfg
;
7160 /* go thru all the specified repeaters */
7163 rpt_vars
[n
].cfg
= ast_config_load("rpt.conf");
7164 cfg
= rpt_vars
[n
].cfg
;
7166 ast_log(LOG_NOTICE
, "Unable to open radio repeater configuration rpt.conf. Radio Repeater disabled.\n");
7169 while((this = ast_category_browse(cfg
,this)) != NULL
)
7171 for(i
= 0 ; i
< strlen(this) ; i
++){
7172 if((this[i
] < '0') || (this[i
] > '9'))
7175 if(i
!= strlen(this)) continue; /* Not a node defn */
7176 memset(&rpt_vars
[n
],0,sizeof(rpt_vars
[n
]));
7177 rpt_vars
[n
].name
= strdup(this);
7178 val
= ast_variable_retrieve(cfg
,this,"rxchannel");
7179 if (val
) rpt_vars
[n
].rxchanname
= strdup(val
);
7180 val
= ast_variable_retrieve(cfg
,this,"txchannel");
7181 if (val
) rpt_vars
[n
].txchanname
= strdup(val
);
7182 val
= ast_variable_retrieve(cfg
,this,"remote");
7183 if (val
) rpt_vars
[n
].remote
= strdup(val
);
7184 ast_mutex_init(&rpt_vars
[n
].lock
);
7185 rpt_vars
[n
].tele
.next
= &rpt_vars
[n
].tele
;
7186 rpt_vars
[n
].tele
.prev
= &rpt_vars
[n
].tele
;
7187 rpt_vars
[n
].rpt_thread
= AST_PTHREADT_NULL
;
7188 rpt_vars
[n
].tailmessagen
= 0;
7189 #ifdef _MDC_DECODE_H_
7190 rpt_vars
[n
].mdc
= mdc_decoder_new(8000);
7195 ast_config_destroy(cfg
);
7198 for(i
= 0; i
< n
; i
++)
7202 /* if is a remote, dont start one for it */
7203 if (rpt_vars
[i
].remote
)
7205 strncpy(rpt_vars
[i
].freq
, "146.580", sizeof(rpt_vars
[i
].freq
) - 1);
7206 strncpy(rpt_vars
[i
].rxpl
, "100.0", sizeof(rpt_vars
[i
].rxpl
) - 1);
7208 strncpy(rpt_vars
[i
].txpl
, "100.0", sizeof(rpt_vars
[i
].txpl
) - 1);
7209 rpt_vars
[i
].remmode
= REM_MODE_FM
;
7210 rpt_vars
[i
].offset
= REM_SIMPLEX
;
7211 rpt_vars
[i
].powerlevel
= REM_MEDPWR
;
7214 if (!rpt_vars
[i
].p
.ident
)
7216 ast_log(LOG_WARNING
,"Did not specify ident for node %s\n",rpt_vars
[i
].name
);
7217 ast_config_destroy(cfg
);
7220 pthread_attr_init(&attr
);
7221 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
7222 ast_pthread_create(&rpt_vars
[i
].rpt_thread
,&attr
,rpt
,(void *) &rpt_vars
[i
]);
7227 /* Now monitor each thread, and restart it if necessary */
7228 for(i
= 0; i
< n
; i
++)
7231 if (rpt_vars
[i
].remote
) continue;
7232 if (rpt_vars
[i
].rpt_thread
== AST_PTHREADT_STOP
)
7235 rv
= pthread_kill(rpt_vars
[i
].rpt_thread
,0);
7238 if(time(NULL
) - rpt_vars
[i
].lastthreadrestarttime
<= 15)
7240 if(rpt_vars
[i
].threadrestarts
>= 5)
7242 ast_log(LOG_ERROR
,"Continual RPT thread restarts, killing Asterisk\n");
7243 exit(1); /* Stuck in a restart loop, kill Asterisk and start over */
7247 ast_log(LOG_NOTICE
,"RPT thread restarted on %s\n",rpt_vars
[i
].name
);
7248 rpt_vars
[i
].threadrestarts
++;
7252 rpt_vars
[i
].threadrestarts
= 0;
7254 rpt_vars
[i
].lastthreadrestarttime
= time(NULL
);
7255 pthread_attr_init(&attr
);
7256 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
7257 ast_pthread_create(&rpt_vars
[i
].rpt_thread
,&attr
,rpt
,(void *) &rpt_vars
[i
]);
7258 ast_log(LOG_WARNING
, "rpt_thread restarted on node %s\n", rpt_vars
[i
].name
);
7264 ast_config_destroy(cfg
);
7268 static int rpt_exec(struct ast_channel
*chan
, void *data
)
7270 int res
=-1,i
,rem_totx
,n
,phone_mode
= 0;
7271 struct ast_module_user
*u
;
7272 char tmp
[256], keyed
= 0;
7273 char *options
,*stringp
,*tele
,c
;
7275 struct ast_frame
*f
;
7276 struct ast_channel
*who
;
7277 struct ast_channel
*cs
[20];
7279 ZT_CONFINFO ci
; /* conference info */
7283 if (ast_strlen_zero(data
)) {
7284 ast_log(LOG_WARNING
, "Rpt requires an argument (system node)\n");
7287 strncpy(tmp
, (char *)data
, sizeof(tmp
)-1);
7289 strsep(&stringp
, "|");
7292 /* see if we can find our specified one */
7293 for(i
= 0; i
< nrpts
; i
++)
7295 /* if name matches, assign it and exit loop */
7296 if (!strcmp(tmp
,rpt_vars
[i
].name
))
7298 myrpt
= &rpt_vars
[i
];
7304 ast_log(LOG_WARNING
, "Cannot find specified system node %s\n",tmp
);
7308 /* if not phone access, must be an IAX connection */
7309 if (options
&& ((*options
== 'P') || (*options
== 'D') || (*options
== 'R')))
7312 if (*options
== 'D') phone_mode
= 2;
7313 ast_set_callerid(chan
,"0","app_rpt user","0");
7317 if (strncmp(chan
->name
,"IAX2",4))
7319 ast_log(LOG_WARNING
, "We only accept links via IAX2!!\n");
7323 if (options
&& (*options
== 'R'))
7326 /* Parts of this section taken from app_parkandannounce */
7327 char *return_context
;
7328 int l
, m
, lot
, timeout
= 0;
7329 char tmp
[256],*template;
7330 char *working
, *context
, *exten
, *priority
;
7334 rpt_mutex_lock(&myrpt
->lock
);
7335 m
= myrpt
->callmode
;
7336 rpt_mutex_unlock(&myrpt
->lock
);
7338 if ((!myrpt
->p
.nobusyout
) && m
)
7340 if (chan
->_state
!= AST_STATE_UP
)
7342 ast_indicate(chan
,AST_CONTROL_BUSY
);
7344 while(ast_safe_sleep(chan
,10000) != -1);
7348 if (chan
->_state
!= AST_STATE_UP
)
7353 l
=strlen(options
)+2;
7356 ast_log(LOG_WARNING
, "Out of memory\n");
7360 strncpy(s
,options
,l
);
7362 template=strsep(&s
,"|");
7364 ast_log(LOG_WARNING
, "An announce template must be defined\n");
7370 timeout
= atoi(strsep(&s
, "|"));
7376 if(return_context
!= NULL
) {
7377 /* set the return context. Code borrowed from the Goto builtin */
7379 working
= return_context
;
7380 context
= strsep(&working
, "|");
7381 exten
= strsep(&working
, "|");
7383 /* Only a priority in this one */
7388 priority
= strsep(&working
, "|");
7390 /* Only an extension and priority in this one */
7396 if(atoi(priority
) < 0) {
7397 ast_log(LOG_WARNING
, "Priority '%s' must be a number > 0\n", priority
);
7401 /* At this point we have a priority and maybe an extension and a context */
7402 chan
->priority
= atoi(priority
);
7404 if(exten
&& strcasecmp(exten
, "BYEXTENSION"))
7408 strncpy(chan
->exten
, exten
, sizeof(chan
->exten
)-1);
7410 strncpy(chan
->context
, context
, sizeof(chan
->context
)-1);
7411 } else { /* increment the priority by default*/
7415 if(option_verbose
> 2) {
7416 ast_verbose( VERBOSE_PREFIX_3
"Return Context: (%s,%s,%d) ID: %s\n", chan
->context
,chan
->exten
, chan
->priority
, chan
->cid
.cid_num
);
7417 if(!ast_exists_extension(chan
, chan
->context
, chan
->exten
, chan
->priority
, chan
->cid
.cid_num
)) {
7418 ast_verbose( VERBOSE_PREFIX_3
"Warning: Return Context Invalid, call will return to default|s\n");
7422 /* we are using masq_park here to protect * from touching the channel once we park it. If the channel comes out of timeout
7423 before we are done announcing and the channel is messed with, Kablooeee. So we use Masq to prevent this. */
7425 ast_masq_park_call(chan
, NULL
, timeout
, &lot
);
7427 if (option_verbose
> 2) ast_verbose( VERBOSE_PREFIX_3
"Call Parking Called, lot: %d, timeout: %d, context: %s\n", lot
, timeout
, return_context
);
7429 snprintf(tmp
,sizeof(tmp
) - 1,"%d,%s",lot
,template + 1);
7431 rpt_telemetry(myrpt
,REV_PATCH
,tmp
);
7441 struct ast_hostent ahp
;
7444 char hisip
[100],nodeip
[100],*val
, *s
, *s1
, *s2
, *b
,*b1
;
7446 /* look at callerid to see what node this comes from */
7447 if (!chan
->cid
.cid_num
) /* if doesn't have caller id */
7449 ast_log(LOG_WARNING
, "Doesnt have callerid on %s\n",tmp
);
7453 /* get his IP from IAX2 module */
7454 memset(hisip
,0,sizeof(hisip
));
7455 pbx_substitute_variables_helper(chan
,"${IAXPEER(CURRENTCHANNEL)}",hisip
,sizeof(hisip
) - 1);
7458 ast_log(LOG_WARNING
, "Link IP address cannot be determined!!\n");
7462 ast_callerid_parse(chan
->cid
.cid_num
,&b
,&b1
);
7463 ast_shrink_phone_number(b1
);
7464 if (!strcmp(myrpt
->name
,b1
))
7466 ast_log(LOG_WARNING
, "Trying to link to self!!\n");
7472 ast_log(LOG_WARNING
, "Node %s Invalid for connection here!!\n",b1
);
7477 /* look for his reported node string */
7478 val
= ast_variable_retrieve(myrpt
->cfg
, myrpt
->p
.nodes
, b1
);
7481 ast_log(LOG_WARNING
, "Reported node %s cannot be found!!\n",b1
);
7484 strncpy(tmp
,val
,sizeof(tmp
) - 1);
7486 s1
= strsep(&s
,",");
7487 s2
= strsep(&s
,",");
7490 ast_log(LOG_WARNING
, "Reported node %s not in correct format!!\n",b1
);
7493 if (strcmp(s2
,"NONE")) {
7494 hp
= ast_gethostbyname(s2
, &ahp
);
7497 ast_log(LOG_WARNING
, "Reported node %s, name %s cannot be found!!\n",b1
,s2
);
7500 memcpy(&ia
,hp
->h_addr
,sizeof(in_addr_t
));
7501 ast_copy_string(nodeip
, ast_inet_ntoa(ia
), sizeof(nodeip
));
7502 if (strcmp(hisip
,nodeip
))
7504 char *s3
= strchr(s1
,'@');
7505 if (s3
) s1
= s3
+ 1;
7506 s3
= strchr(s1
,'/');
7508 hp
= ast_gethostbyname(s1
, &ahp
);
7511 ast_log(LOG_WARNING
, "Reported node %s, name %s cannot be found!!\n",b1
,s1
);
7514 memcpy(&ia
,hp
->h_addr
,sizeof(in_addr_t
));
7515 ast_copy_string(nodeip
, ast_inet_ntoa(ia
), sizeof(nodeip
));
7516 if (strcmp(hisip
,nodeip
))
7518 ast_log(LOG_WARNING
, "Node %s IP %s does not match link IP %s!!\n",b1
,nodeip
,hisip
);
7525 /* if is not a remote */
7532 /* look at callerid to see what node this comes from */
7533 if (!chan
->cid
.cid_num
) /* if doesn't have caller id */
7535 ast_log(LOG_WARNING
, "Doesnt have callerid on %s\n",tmp
);
7539 ast_callerid_parse(chan
->cid
.cid_num
,&b
,&b1
);
7540 ast_shrink_phone_number(b1
);
7541 if (!strcmp(myrpt
->name
,b1
))
7543 ast_log(LOG_WARNING
, "Trying to link to self!!\n");
7546 rpt_mutex_lock(&myrpt
->lock
);
7547 l
= myrpt
->links
.next
;
7548 /* try to find this one in queue */
7549 while(l
!= &myrpt
->links
)
7551 if (l
->name
[0] == '0')
7556 /* if found matching string */
7557 if (!strcmp(l
->name
,b1
)) break;
7561 if (l
!= &myrpt
->links
)
7564 l
->retries
= MAX_RETRIES
+ 1;
7566 reconnects
= l
->reconnects
;
7568 rpt_mutex_unlock(&myrpt
->lock
);
7571 rpt_mutex_unlock(&myrpt
->lock
);
7572 /* establish call in tranceive mode */
7573 l
= malloc(sizeof(struct rpt_link
));
7576 ast_log(LOG_WARNING
, "Unable to malloc\n");
7579 /* zero the silly thing */
7580 memset((char *)l
,0,sizeof(struct rpt_link
));
7582 strncpy(l
->name
,b1
,MAXNODESTR
- 1);
7586 l
->hasconnected
= 1;
7587 l
->reconnects
= reconnects
;
7588 l
->phonemode
= phone_mode
;
7589 ast_set_read_format(l
->chan
,AST_FORMAT_SLINEAR
);
7590 ast_set_write_format(l
->chan
,AST_FORMAT_SLINEAR
);
7591 /* allocate a pseudo-channel thru asterisk */
7592 l
->pchan
= ast_request("zap",AST_FORMAT_SLINEAR
,"pseudo",NULL
);
7595 fprintf(stderr
,"rpt:Sorry unable to obtain pseudo channel\n");
7598 ast_set_read_format(l
->pchan
,AST_FORMAT_SLINEAR
);
7599 ast_set_write_format(l
->pchan
,AST_FORMAT_SLINEAR
);
7600 /* make a conference for the tx */
7602 ci
.confno
= myrpt
->conf
;
7603 ci
.confmode
= ZT_CONF_CONF
| ZT_CONF_LISTENER
| ZT_CONF_TALKER
;
7604 /* first put the channel on the conference in proper mode */
7605 if (ioctl(l
->pchan
->fds
[0],ZT_SETCONF
,&ci
) == -1)
7607 ast_log(LOG_WARNING
, "Unable to set conference mode to Announce\n");
7610 rpt_mutex_lock(&myrpt
->lock
);
7611 if (phone_mode
> 1) l
->lastrx
= 1;
7612 /* insert at end of queue */
7613 insque((struct qelem
*)l
,(struct qelem
*)myrpt
->links
.next
);
7614 rpt_mutex_unlock(&myrpt
->lock
);
7615 if (chan
->_state
!= AST_STATE_UP
) {
7618 return AST_PBX_KEEPALIVE
;
7620 rpt_mutex_lock(&myrpt
->lock
);
7621 /* if remote, error if anyone else already linked */
7622 if (myrpt
->remoteon
)
7624 rpt_mutex_unlock(&myrpt
->lock
);
7626 if (myrpt
->remoteon
)
7628 ast_log(LOG_WARNING
, "Trying to use busy link on %s\n",tmp
);
7631 rpt_mutex_lock(&myrpt
->lock
);
7633 myrpt
->remoteon
= 1;
7634 if (ioperm(myrpt
->p
.iobase
,1,1) == -1)
7636 rpt_mutex_unlock(&myrpt
->lock
);
7637 ast_log(LOG_WARNING
, "Cant get io permission on IO port %x hex\n",myrpt
->p
.iobase
);
7640 u
= ast_module_user_add(chan
);
7641 rpt_mutex_unlock(&myrpt
->lock
);
7642 /* find our index, and load the vars initially */
7643 for(i
= 0; i
< nrpts
; i
++)
7645 if (&rpt_vars
[i
] == myrpt
)
7651 rpt_mutex_lock(&myrpt
->lock
);
7652 tele
= strchr(myrpt
->rxchanname
,'/');
7655 fprintf(stderr
,"rpt:Dial number must be in format tech/number\n");
7656 rpt_mutex_unlock(&myrpt
->lock
);
7660 myrpt
->rxchannel
= ast_request(myrpt
->rxchanname
,AST_FORMAT_SLINEAR
,tele
,NULL
);
7661 if (myrpt
->rxchannel
)
7663 ast_set_read_format(myrpt
->rxchannel
,AST_FORMAT_SLINEAR
);
7664 ast_set_write_format(myrpt
->rxchannel
,AST_FORMAT_SLINEAR
);
7665 myrpt
->rxchannel
->whentohangup
= 0;
7666 myrpt
->rxchannel
->appl
= "Apprpt";
7667 myrpt
->rxchannel
->data
= "(Link Rx)";
7668 if (option_verbose
> 2)
7669 ast_verbose(VERBOSE_PREFIX_3
"rpt (Rx) initiating call to %s/%s on %s\n",
7670 myrpt
->rxchanname
,tele
,myrpt
->rxchannel
->name
);
7671 rpt_mutex_unlock(&myrpt
->lock
);
7672 ast_call(myrpt
->rxchannel
,tele
,999);
7673 rpt_mutex_lock(&myrpt
->lock
);
7677 fprintf(stderr
,"rpt:Sorry unable to obtain Rx channel\n");
7678 rpt_mutex_unlock(&myrpt
->lock
);
7682 if (myrpt
->txchanname
)
7684 tele
= strchr(myrpt
->txchanname
,'/');
7687 fprintf(stderr
,"rpt:Dial number must be in format tech/number\n");
7688 rpt_mutex_unlock(&myrpt
->lock
);
7689 ast_hangup(myrpt
->rxchannel
);
7693 myrpt
->txchannel
= ast_request(myrpt
->txchanname
,AST_FORMAT_SLINEAR
,tele
,NULL
);
7694 if (myrpt
->txchannel
)
7696 ast_set_read_format(myrpt
->txchannel
,AST_FORMAT_SLINEAR
);
7697 ast_set_write_format(myrpt
->txchannel
,AST_FORMAT_SLINEAR
);
7698 myrpt
->txchannel
->whentohangup
= 0;
7699 myrpt
->txchannel
->appl
= "Apprpt";
7700 myrpt
->txchannel
->data
= "(Link Tx)";
7701 if (option_verbose
> 2)
7702 ast_verbose(VERBOSE_PREFIX_3
"rpt (Tx) initiating call to %s/%s on %s\n",
7703 myrpt
->txchanname
,tele
,myrpt
->txchannel
->name
);
7704 rpt_mutex_unlock(&myrpt
->lock
);
7705 ast_call(myrpt
->txchannel
,tele
,999);
7706 rpt_mutex_lock(&myrpt
->lock
);
7710 fprintf(stderr
,"rpt:Sorry unable to obtain Tx channel\n");
7711 rpt_mutex_unlock(&myrpt
->lock
);
7712 ast_hangup(myrpt
->rxchannel
);
7719 myrpt
->txchannel
= myrpt
->rxchannel
;
7721 myrpt
->remoterx
= 0;
7722 myrpt
->remotetx
= 0;
7723 myrpt
->retxtimer
= 0;
7724 myrpt
->remoteon
= 1;
7725 myrpt
->dtmfidx
= -1;
7726 myrpt
->dtmfbuf
[0] = 0;
7727 myrpt
->dtmf_time_rem
= 0;
7728 myrpt
->hfscanmode
= 0;
7729 myrpt
->hfscanstatus
= 0;
7730 if (myrpt
->p
.startupmacro
)
7732 myrpt
->remchannel
= chan
; /* Save copy of channel */
7733 snprintf(myrpt
->macrobuf
,MAXMACRO
- 1,"PPPP%s",myrpt
->p
.startupmacro
);
7736 rpt_mutex_unlock(&myrpt
->lock
);
7738 ast_set_write_format(chan
, AST_FORMAT_SLINEAR
);
7739 ast_set_read_format(chan
, AST_FORMAT_SLINEAR
);
7740 /* if we are on 2w loop and are a remote, turn EC on */
7741 if (myrpt
->remote
&& (myrpt
->rxchannel
== myrpt
->txchannel
))
7744 ioctl(myrpt
->rxchannel
->fds
[0],ZT_ECHOCANCEL
,&i
);
7746 if (chan
->_state
!= AST_STATE_UP
) {
7750 if (ioctl(myrpt
->txchannel
->fds
[0],ZT_GET_PARAMS
,&par
) != -1)
7752 if (par
.rxisoffhook
)
7754 ast_indicate(chan
,AST_CONTROL_RADIO_KEY
);
7755 myrpt
->remoterx
= 1;
7760 cs
[n
++] = myrpt
->rxchannel
;
7761 if (myrpt
->rxchannel
!= myrpt
->txchannel
)
7762 cs
[n
++] = myrpt
->txchannel
;
7765 if (ast_check_hangup(chan
)) break;
7766 if (ast_check_hangup(myrpt
->rxchannel
)) break;
7770 rpt_mutex_unlock(&myrpt
->lock
);
7771 /* find our index, and load the vars */
7772 for(i
= 0; i
< nrpts
; i
++)
7774 if (&rpt_vars
[i
] == myrpt
)
7780 rpt_mutex_lock(&myrpt
->lock
);
7783 who
= ast_waitfor_n(cs
,n
,&ms
);
7784 if (who
== NULL
) ms
= 0;
7786 if (myrpt
->macrotimer
) myrpt
->macrotimer
-= elap
;
7787 if (myrpt
->macrotimer
< 0) myrpt
->macrotimer
= 0;
7788 rpt_mutex_unlock(&myrpt
->lock
);
7793 if ((!myrpt
->remoterx
) && (!myrpt
->remotetx
))
7795 if ((myrpt
->retxtimer
+= elap
) >= REDUNDANT_TX_TIME
)
7797 myrpt
->retxtimer
= 0;
7798 ast_indicate(chan
,AST_CONTROL_RADIO_UNKEY
);
7800 } else myrpt
->retxtimer
= 0;
7801 if (rem_totx
&& (!myrpt
->remotetx
)) /* Remote base radio TX key */
7803 myrpt
->remotetx
= 1;
7804 ast_indicate(myrpt
->txchannel
,AST_CONTROL_RADIO_KEY
);
7806 if ((!rem_totx
) && myrpt
->remotetx
) /* Remote base radio TX unkey */
7808 myrpt
->remotetx
= 0;
7809 ast_indicate(myrpt
->txchannel
,AST_CONTROL_RADIO_UNKEY
);
7812 if(myrpt
->tunerequest
&& (!strcmp(myrpt
->remote
, remote_rig_ft897
))){ /* ft-897 specific for now... */
7813 myrpt
->tunerequest
= 0;
7814 set_mode_ft897(myrpt
, REM_MODE_AM
);
7815 simple_command_ft897(myrpt
, 8);
7816 myrpt
->remotetx
= 0;
7817 ast_indicate(myrpt
->txchannel
,AST_CONTROL_RADIO_UNKEY
);
7818 if (!myrpt
->remoterx
)
7819 ast_indicate(chan
, AST_CONTROL_RADIO_KEY
);
7820 if(play_tone(chan
, 800, 6000, 8192) == -1)
7823 rmt_telem_finish(myrpt
,chan
);
7824 set_mode_ft897(myrpt
, 0x88);
7828 if (myrpt
->hfscanmode
){
7829 myrpt
->scantimer
-= elap
;
7830 if(myrpt
->scantimer
<= 0){
7831 myrpt
->scantimer
= REM_SCANTIME
;
7832 service_scan(myrpt
);
7835 if (who
== chan
) /* if it was a read from incomming */
7840 if (debug
) printf("@@@@ link:Hung Up\n");
7843 if (f
->frametype
== AST_FRAME_VOICE
)
7845 /* if not transmitting, zero-out audio */
7846 if (!myrpt
->remotetx
)
7847 memset(f
->data
,0,f
->datalen
);
7848 ast_write(myrpt
->txchannel
,f
);
7850 if (f
->frametype
== AST_FRAME_DTMF
)
7852 myrpt
->remchannel
= chan
; /* Save copy of channel */
7853 if (handle_remote_phone_dtmf(myrpt
,f
->subclass
,&keyed
,phone_mode
) == -1)
7855 if (debug
) printf("@@@@ rpt:Hung Up\n");
7860 if (f
->frametype
== AST_FRAME_TEXT
)
7862 myrpt
->remchannel
= chan
; /* Save copy of channel */
7863 if (handle_remote_data(myrpt
,f
->data
) == -1)
7865 if (debug
) printf("@@@@ rpt:Hung Up\n");
7870 if (f
->frametype
== AST_FRAME_CONTROL
)
7872 if (f
->subclass
== AST_CONTROL_HANGUP
)
7874 if (debug
) printf("@@@@ rpt:Hung Up\n");
7879 if (f
->subclass
== AST_CONTROL_RADIO_KEY
)
7881 if (debug
== 7) printf("@@@@ rx key\n");
7885 if (f
->subclass
== AST_CONTROL_RADIO_UNKEY
)
7887 if (debug
== 7) printf("@@@@ rx un-key\n");
7891 if (myrpt
->hfscanstatus
){
7892 myrpt
->remchannel
= chan
; /* Save copy of channel */
7893 myrpt
->remotetx
= 0;
7894 ast_indicate(myrpt
->txchannel
,AST_CONTROL_RADIO_UNKEY
);
7895 if (!myrpt
->remoterx
)
7897 ast_indicate(myrpt
->remchannel
,AST_CONTROL_RADIO_KEY
);
7899 if(myrpt
->hfscanstatus
< 0) {
7900 if (myrpt
->hfscanstatus
== -1) {
7901 if (ast_safe_sleep(myrpt
->remchannel
,1000) == -1) break;
7903 sayfile(myrpt
->remchannel
, "rpt/stop");
7907 saynum(myrpt
->remchannel
, myrpt
->hfscanstatus
);
7909 rmt_telem_finish(myrpt
,myrpt
->remchannel
);
7910 myrpt
->hfscanstatus
= 0;
7913 rpt_mutex_lock(&myrpt
->lock
);
7914 c
= myrpt
->macrobuf
[0];
7915 if (c
&& (!myrpt
->macrotimer
))
7917 myrpt
->macrotimer
= MACROTIME
;
7918 memmove(myrpt
->macrobuf
,myrpt
->macrobuf
+ 1,MAXMACRO
- 1);
7919 if ((c
== 'p') || (c
== 'P'))
7920 myrpt
->macrotimer
= MACROPTIME
;
7921 rpt_mutex_unlock(&myrpt
->lock
);
7922 if (handle_remote_dtmf_digit(myrpt
,c
,&keyed
,0) == -1) break;
7925 rpt_mutex_unlock(&myrpt
->lock
);
7928 if (who
== myrpt
->rxchannel
) /* if it was a read from radio */
7930 f
= ast_read(myrpt
->rxchannel
);
7933 if (debug
) printf("@@@@ link:Hung Up\n");
7936 if (f
->frametype
== AST_FRAME_VOICE
)
7938 if ((myrpt
->remote
) && (myrpt
->remotetx
))
7939 memset(f
->data
,0,f
->datalen
);
7942 else if (f
->frametype
== AST_FRAME_CONTROL
)
7944 if (f
->subclass
== AST_CONTROL_HANGUP
)
7946 if (debug
) printf("@@@@ rpt:Hung Up\n");
7951 if (f
->subclass
== AST_CONTROL_RADIO_KEY
)
7953 if (debug
== 7) printf("@@@@ remote rx key\n");
7954 if (!myrpt
->remotetx
)
7956 ast_indicate(chan
,AST_CONTROL_RADIO_KEY
);
7957 myrpt
->remoterx
= 1;
7961 if (f
->subclass
== AST_CONTROL_RADIO_UNKEY
)
7963 if (debug
== 7) printf("@@@@ remote rx un-key\n");
7964 if (!myrpt
->remotetx
)
7966 ast_indicate(chan
,AST_CONTROL_RADIO_UNKEY
);
7967 myrpt
->remoterx
= 0;
7974 if ((myrpt
->rxchannel
!= myrpt
->txchannel
) &&
7975 (who
== myrpt
->txchannel
)) /* do this cuz you have to */
7977 f
= ast_read(myrpt
->txchannel
);
7980 if (debug
) printf("@@@@ link:Hung Up\n");
7983 if (f
->frametype
== AST_FRAME_CONTROL
)
7985 if (f
->subclass
== AST_CONTROL_HANGUP
)
7987 if (debug
) printf("@@@@ rpt:Hung Up\n");
7997 rpt_mutex_lock(&myrpt
->lock
);
7998 if (myrpt
->rxchannel
!= myrpt
->txchannel
) ast_hangup(myrpt
->txchannel
);
7999 ast_hangup(myrpt
->rxchannel
);
8000 myrpt
->hfscanmode
= 0;
8001 myrpt
->hfscanstatus
= 0;
8002 myrpt
->remoteon
= 0;
8003 rpt_mutex_unlock(&myrpt
->lock
);
8005 ast_module_user_remove(u
);
8009 static int unload_module(void)
8013 ast_module_user_hangup_all();
8014 for(i
= 0; i
< nrpts
; i
++) {
8015 if (!strcmp(rpt_vars
[i
].name
,rpt_vars
[i
].p
.nodes
)) continue;
8016 ast_mutex_destroy(&rpt_vars
[i
].lock
);
8018 i
= ast_unregister_application(app
);
8020 /* Unregister cli extensions */
8021 ast_cli_unregister(&cli_debug
);
8022 ast_cli_unregister(&cli_dump
);
8023 ast_cli_unregister(&cli_stats
);
8024 ast_cli_unregister(&cli_lstats
);
8025 ast_cli_unregister(&cli_reload
);
8026 ast_cli_unregister(&cli_restart
);
8031 static int load_module(void)
8033 ast_pthread_create(&rpt_master_thread
,NULL
,rpt_master
,NULL
);
8035 /* Register cli extensions */
8036 ast_cli_register(&cli_debug
);
8037 ast_cli_register(&cli_dump
);
8038 ast_cli_register(&cli_stats
);
8039 ast_cli_register(&cli_lstats
);
8040 ast_cli_register(&cli_reload
);
8041 ast_cli_register(&cli_restart
);
8043 return ast_register_application(app
, rpt_exec
, synopsis
, descrip
);
8046 static int reload(void)
8050 for(n
= 0; n
< nrpts
; n
++) rpt_vars
[n
].reload
= 1;
8054 AST_MODULE_INFO(ASTERISK_GPL_KEY
, AST_MODFLAG_DEFAULT
, "Radio Repeater / Remote Base",
8055 .load
= load_module
,
8056 .unload
= unload_module
,