3 * Asterisk -- A telephony toolkit for Linux.
5 * Radio Repeater / Remote Base program
8 * Copyright (C) 2002-2004, Jim Dixon, WB6NIL
10 * Jim Dixon, WB6NIL <jim@lambdatel.com>
12 * This program is free software, distributed under the terms of
13 * the GNU General Public License
15 * Repeater / Remote Functions:
16 * "Simple" Mode: * - autopatch access, # - autopatch hangup
19 * *1XXX - remote link off
20 * *2XXX - remote link monitor
21 * *3XXX - remote link tranceive
22 * *4XXX - remote link command mode
23 * *6 - autopatch access/send (*)
26 * *90 - system disable (and reset)
30 * To send an asterisk (*) while dialing or talking on phone,
31 * use the autopatch acess code.
36 * *0 - Recall Memory MM (*000-*099) (Gets memory from rpt.conf)
37 * *1 - Set VFO MMMMM*KKK*O (Mhz digits, Khz digits, Offset)
38 * *2 - Set Rx PL Tone HHH*D*
39 * *3 - Set Tx PL Tone HHH*D*
40 * *40 - RX PL off (Default)
42 * *42 - TX PL Off (Default)
50 /* number of digits for function after *. Must be at least 1 */
51 #define FUNCTION_LEN 4
52 /* string containing all of the 1 digit functions */
53 #define SHORTFUNCS "05678"
54 /* string containing all of the 2 digit functions */
57 /* maximum digits in DTMF buffer, and seconds after * for DTMF command timeout */
60 #define DTMF_TIMEOUT 3
65 #define MEMORY "memory"
67 #define DEFAULT_IOBASE 0x378
69 #define MAXCONNECTTIME 5000
71 #define MAXNODESTR 300
73 enum {REM_OFF,REM_MONITOR,REM_TX};
75 enum{ID,PROC,TERM,COMPLETE,UNKEY,REMDISC,REMALREADY,REMNOTFOUND,REMGO,
76 CONNECTED,CONNFAIL,STATUS,TIMEOUT};
78 enum {REM_SIMPLEX,REM_MINUS,REM_PLUS};
80 enum {REM_LOWPWR,REM_MEDPWR,REM_HIPWR};
82 #include <asterisk/lock.h>
83 #include <asterisk/file.h>
84 #include <asterisk/logger.h>
85 #include <asterisk/channel.h>
86 #include <asterisk/callerid.h>
87 #include <asterisk/pbx.h>
88 #include <asterisk/module.h>
89 #include <asterisk/translate.h>
90 #include <asterisk/options.h>
91 #include <asterisk/config.h>
92 #include <asterisk/utils.h>
93 #include <asterisk/say.h>
99 #include <sys/types.h>
100 #include <sys/stat.h>
104 #include <sys/stat.h>
105 #include <sys/time.h>
106 #include <sys/file.h>
107 #include <sys/ioctl.h>
110 #include <tonezone.h>
111 #include <linux/zaptel.h>
113 static char *tdesc = "Radio Repeater / Remote Base version 0.8 06/26/2004";
114 static char *app = "Rpt";
116 static char *synopsis = "Radio Repeater/Remote Base Control System";
118 static char *descrip =
119 " Rpt(sysname): Radio Remote Link or Remote Base Link Endpoint Process.\n";
121 static int debug = 0;
122 static int nrpts = 0;
124 struct ast_config *cfg;
130 #define HANGTIME 5000
131 #define TOTIME 180000
132 #define IDTIME 300000
135 static pthread_t rpt_master_thread;
141 struct rpt_link *next;
142 struct rpt_link *prev;
143 char mode; /* 1 if in tx mode */
145 char name[MAXNODESTR]; /* identifier (routing) string */
151 struct ast_channel *chan;
152 struct ast_channel *pchan;
157 struct rpt_tele *next;
158 struct rpt_tele *prev;
161 struct rpt_link mylink;
176 struct rpt_link links;
190 char dtmfbuf[MAXDTMF];
191 char rem_dtmfbuf[MAXDTMF];
193 struct ast_channel *rxchannel,*txchannel;
194 struct ast_channel *pchannel,*txpchannel;
195 struct rpt_tele tele;
196 pthread_t rpt_call_thread,rpt_thread;
197 time_t rem_dtmf_time,dtmf_time_rem;
198 int tailtimer,totimer,idtimer,txconf,conf,callmode,cidx;
199 int dtmfidx,rem_dtmfidx;
202 char exten[AST_MAX_EXTENSION];
203 char freq[MAXREMSTR],rxpl[MAXREMSTR],txpl[MAXREMSTR];
210 static void *rpt_tele_thread(void *this)
212 ZT_CONFINFO ci; /* conference info */
213 int res = 0,hastx,imdone = 0;
214 struct rpt_tele *mytele = (struct rpt_tele *)this;
216 struct rpt_link *l,*m,linkbase;
217 struct ast_channel *mychannel;
219 /* get a pointer to myrpt */
221 /* allocate a pseudo-channel thru asterisk */
222 mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo");
225 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
226 ast_mutex_lock(&myrpt->lock);
227 remque((struct qelem *)mytele);
228 ast_mutex_unlock(&myrpt->lock);
232 /* make a conference for the tx */
234 ci.confno = myrpt->conf; /* use the tx conference */
235 ci.confmode = ZT_CONF_CONFANN;
236 /* first put the channel on the conference in announce mode */
237 if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
239 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
240 ast_mutex_lock(&myrpt->lock);
241 remque((struct qelem *)mytele);
242 ast_mutex_unlock(&myrpt->lock);
244 ast_hangup(mychannel);
247 ast_stopstream(mychannel);
251 res = ast_streamfile(mychannel, myrpt->ident, mychannel->language);
254 /* wait a little bit longer */
256 res = ast_streamfile(mychannel, "rpt/callproceeding", mychannel->language);
259 /* wait a little bit longer */
261 res = ast_streamfile(mychannel, "rpt/callterminated", mychannel->language);
264 /* wait a little bit */
266 res = ast_streamfile(mychannel, "rpt/functioncomplete", mychannel->language);
269 /* wait a little bit */
272 l = myrpt->links.next;
273 if (l != &myrpt->links)
275 ast_mutex_lock(&myrpt->lock);
276 while(l != &myrpt->links)
278 if (l->mode) hastx++;
281 ast_mutex_unlock(&myrpt->lock);
282 res = ast_streamfile(mychannel,
283 ((!hastx) ? "rpt/remote_monitor" : "rpt/remote_tx"),
284 mychannel->language);
286 res = ast_waitstream(mychannel, "");
288 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
289 ast_stopstream(mychannel);
291 /* if in remote cmd mode, indicate it */
292 if (myrpt->cmdnode[0])
294 ast_safe_sleep(mychannel,200);
295 res = ast_streamfile(mychannel, "rpt/remote_cmd", mychannel->language);
297 res = ast_waitstream(mychannel, "");
299 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
300 ast_stopstream(mychannel);
305 /* wait a little bit */
307 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
309 res = ast_waitstream(mychannel, "");
311 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
312 ast_stopstream(mychannel);
313 ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
314 res = ast_streamfile(mychannel, ((mytele->mylink.connected) ?
315 "rpt/remote_disc" : "rpt/remote_busy"), mychannel->language);
318 /* wait a little bit */
320 res = ast_streamfile(mychannel, "rpt/remote_already", mychannel->language);
323 /* wait a little bit */
325 res = ast_streamfile(mychannel, "rpt/remote_notfound", mychannel->language);
328 /* wait a little bit */
330 res = ast_streamfile(mychannel, "rpt/remote_go", mychannel->language);
333 /* wait a little bit */
335 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
337 res = ast_waitstream(mychannel, "");
339 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
340 ast_stopstream(mychannel);
341 ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
342 res = ast_streamfile(mychannel, "rpt/connected", mychannel->language);
345 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
347 res = ast_waitstream(mychannel, "");
349 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
350 ast_stopstream(mychannel);
351 ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
352 res = ast_streamfile(mychannel, "rpt/connection_failed", mychannel->language);
355 /* wait a little bit */
358 linkbase.next = &linkbase;
359 linkbase.prev = &linkbase;
360 ast_mutex_lock(&myrpt->lock);
361 /* make our own list of links */
362 l = myrpt->links.next;
363 while(l != &myrpt->links)
365 m = malloc(sizeof(struct rpt_link));
368 ast_log(LOG_WARNING, "Cannot alloc memory on %s\n", mychannel->name);
371 memcpy(m,l,sizeof(struct rpt_link));
372 m->next = m->prev = NULL;
373 insque((struct qelem *)m,(struct qelem *)linkbase.next);
376 ast_mutex_unlock(&myrpt->lock);
377 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
379 res = ast_waitstream(mychannel, "");
381 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
382 ast_stopstream(mychannel);
383 ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
385 res = ast_waitstream(mychannel, "");
387 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
388 ast_stopstream(mychannel);
392 res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
394 res = ast_waitstream(mychannel, "");
396 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
397 ast_stopstream(mychannel);
400 while(l != &linkbase)
403 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
405 res = ast_waitstream(mychannel, "");
407 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
408 ast_stopstream(mychannel);
409 ast_say_character_str(mychannel,l->name,NULL,mychannel->language);
411 res = ast_waitstream(mychannel, "");
413 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
414 ast_stopstream(mychannel);
415 res = ast_streamfile(mychannel, ((l->mode) ?
416 "rpt/tranceive" : "rpt/monitor"), mychannel->language);
418 res = ast_waitstream(mychannel, "");
420 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
421 ast_stopstream(mychannel);
426 res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
428 res = ast_waitstream(mychannel, "");
430 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
431 ast_stopstream(mychannel);
433 /* destroy our local link queue */
435 while(l != &linkbase)
439 remque((struct qelem *)m);
445 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
447 res = ast_waitstream(mychannel, "");
449 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
450 ast_stopstream(mychannel);
451 ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
452 res = ast_streamfile(mychannel, "rpt/timeout", mychannel->language);
458 res = ast_waitstream(mychannel, "");
460 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
464 ast_stopstream(mychannel);
465 ast_mutex_lock(&myrpt->lock);
466 remque((struct qelem *)mytele);
467 ast_mutex_unlock(&myrpt->lock);
469 ast_hangup(mychannel);
473 static void rpt_telemetry(struct rpt *myrpt,int mode,struct rpt_link *mylink)
475 struct rpt_tele *tele;
478 tele = malloc(sizeof(struct rpt_tele));
481 ast_log(LOG_WARNING, "Unable to allocate memory\n");
486 memset((char *)tele,0,sizeof(struct rpt_tele));
489 ast_mutex_lock(&myrpt->lock);
490 memset(&tele->mylink,0,sizeof(struct rpt_link));
493 memcpy(&tele->mylink,mylink,sizeof(struct rpt_link));
495 insque((struct qelem *)tele,(struct qelem *)myrpt->tele.next);
496 ast_mutex_unlock(&myrpt->lock);
497 pthread_attr_init(&attr);
498 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
499 pthread_create(&tele->threadid,&attr,rpt_tele_thread,(void *) tele);
503 static int sayfile(struct ast_channel *mychannel,char *fname)
507 res = ast_streamfile(mychannel, fname, mychannel->language);
509 res = ast_waitstream(mychannel, "");
511 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
512 ast_stopstream(mychannel);
516 static int saycharstr(struct ast_channel *mychannel,char *str)
520 res = ast_say_character_str(mychannel,str,NULL,mychannel->language);
522 res = ast_waitstream(mychannel, "");
524 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
525 ast_stopstream(mychannel);
529 static void *rpt_call(void *this)
531 ZT_CONFINFO ci; /* conference info */
532 struct rpt *myrpt = (struct rpt *)this;
534 struct ast_frame *f,wf;
535 int stopped,congstarted;
536 struct ast_channel *mychannel,*genchannel;
539 /* allocate a pseudo-channel thru asterisk */
540 mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo");
543 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
547 ci.confno = myrpt->conf; /* use the pseudo conference */
548 ci.confmode = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER
549 | ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER;
550 /* first put the channel on the conference */
551 if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
553 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
554 ast_hangup(mychannel);
558 /* allocate a pseudo-channel thru asterisk */
559 genchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo");
562 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
563 ast_hangup(mychannel);
567 ci.confno = myrpt->conf;
568 ci.confmode = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER
569 | ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER;
570 /* first put the channel on the conference */
571 if (ioctl(genchannel->fds[0],ZT_SETCONF,&ci) == -1)
573 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
574 ast_hangup(mychannel);
575 ast_hangup(genchannel);
579 if (myrpt->tonezone && (tone_zone_set_zone(mychannel->fds[0],myrpt->tonezone) == -1))
581 ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->tonezone);
582 ast_hangup(mychannel);
583 ast_hangup(genchannel);
587 if (myrpt->tonezone && (tone_zone_set_zone(genchannel->fds[0],myrpt->tonezone) == -1))
589 ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->tonezone);
590 ast_hangup(mychannel);
591 ast_hangup(genchannel);
596 if (tone_zone_play_tone(mychannel->fds[0],ZT_TONE_DIALTONE) < 0)
598 ast_log(LOG_WARNING, "Cannot start dialtone\n");
599 ast_hangup(mychannel);
600 ast_hangup(genchannel);
606 while ((myrpt->callmode == 1) || (myrpt->callmode == 4))
609 if ((myrpt->callmode == 1) && (myrpt->cidx > 0) && (!stopped))
613 tone_zone_play_tone(mychannel->fds[0],-1);
615 if ((myrpt->callmode == 4) && (!congstarted))
618 /* start congestion tone */
619 tone_zone_play_tone(mychannel->fds[0],ZT_TONE_CONGESTION);
621 res = ast_waitfor(mychannel, MSWAIT);
624 ast_hangup(mychannel);
625 ast_hangup(genchannel);
626 ast_mutex_lock(&myrpt->lock);
628 ast_mutex_unlock(&myrpt->lock);
631 if (res == 0) continue;
632 f = ast_read(mychannel);
635 ast_hangup(mychannel);
636 ast_hangup(genchannel);
637 ast_mutex_lock(&myrpt->lock);
639 ast_mutex_unlock(&myrpt->lock);
642 if ((f->frametype == AST_FRAME_CONTROL) &&
643 (f->subclass == AST_CONTROL_HANGUP))
646 ast_hangup(mychannel);
647 ast_hangup(genchannel);
648 ast_mutex_lock(&myrpt->lock);
650 ast_mutex_unlock(&myrpt->lock);
655 /* stop any tone generation */
656 tone_zone_play_tone(mychannel->fds[0],-1);
658 if (!myrpt->callmode)
660 ast_hangup(mychannel);
661 ast_hangup(genchannel);
662 ast_mutex_lock(&myrpt->lock);
664 ast_mutex_unlock(&myrpt->lock);
667 if (myrpt->ourcallerid && *myrpt->ourcallerid)
669 if (mychannel->callerid) free(mychannel->callerid);
670 mychannel->callerid = strdup(myrpt->ourcallerid);
672 strcpy(mychannel->exten,myrpt->exten);
673 strcpy(mychannel->context,myrpt->ourcontext);
675 strcpy(mychannel->accountcode,myrpt->acctcode);
676 mychannel->priority = 1;
677 ast_channel_undefer_dtmf(mychannel);
678 if (ast_pbx_start(mychannel) < 0)
680 ast_log(LOG_WARNING, "Unable to start PBX!!\n");
681 ast_hangup(mychannel);
682 ast_hangup(genchannel);
683 ast_mutex_lock(&myrpt->lock);
685 ast_mutex_unlock(&myrpt->lock);
688 ast_mutex_lock(&myrpt->lock);
690 while(myrpt->callmode)
692 if ((!mychannel->pvt) && (myrpt->callmode != 4))
695 ast_mutex_unlock(&myrpt->lock);
696 /* start congestion tone */
697 tone_zone_play_tone(genchannel->fds[0],ZT_TONE_CONGESTION);
698 ast_mutex_lock(&myrpt->lock);
702 wf.frametype = AST_FRAME_DTMF;
703 wf.subclass = myrpt->mydtmf;
709 ast_mutex_unlock(&myrpt->lock);
710 ast_write(genchannel,&wf);
711 ast_mutex_lock(&myrpt->lock);
714 ast_mutex_unlock(&myrpt->lock);
716 ast_mutex_lock(&myrpt->lock);
718 ast_mutex_unlock(&myrpt->lock);
719 tone_zone_play_tone(genchannel->fds[0],-1);
720 if (mychannel->pvt) ast_softhangup(mychannel,AST_SOFTHANGUP_DEV);
721 ast_hangup(genchannel);
722 ast_mutex_lock(&myrpt->lock);
724 ast_mutex_unlock(&myrpt->lock);
728 static void send_link_dtmf(struct rpt *myrpt,char c)
734 sprintf(str,"D %s %s %d %c",myrpt->cmdnode,myrpt->name,++(myrpt->dtmfidx),c);
735 wf.frametype = AST_FRAME_TEXT;
739 wf.datalen = strlen(str) + 1;
741 l = myrpt->links.next;
742 /* first, see if our dude is there */
743 while(l != &myrpt->links)
745 /* if we found it, write it and were done */
746 if (!strcmp(l->name,myrpt->cmdnode))
748 wf.data = strdup(str);
749 ast_write(l->chan,&wf);
754 l = myrpt->links.next;
755 /* if not, give it to everyone */
756 while(l != &myrpt->links)
758 wf.data = strdup(str);
759 ast_write(l->chan,&wf);
765 static void process_dtmf(char *cmd,struct rpt *myrpt, int allow_linkcmd)
768 char *tele,tmp[300],deststr[300],*val,*s,*s1;
770 ZT_CONFINFO ci; /* conference info */
772 switch(atoi(cmd) / 1000)
774 case 6: /* autopatch on / send asterisk (*) */
775 if (!myrpt->enable) return;
776 ast_mutex_lock(&myrpt->lock);
777 /* if on call, force * into current audio stream */
778 if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
781 ast_mutex_unlock(&myrpt->lock);
786 ast_mutex_unlock(&myrpt->lock);
791 myrpt->exten[myrpt->cidx] = 0;
792 ast_mutex_unlock(&myrpt->lock);
793 pthread_attr_init(&attr);
794 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
795 pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *) myrpt);
797 case 0: /* autopatch off */
798 if (!myrpt->enable) return;
799 ast_mutex_lock(&myrpt->lock);
800 if (!myrpt->callmode)
802 ast_mutex_unlock(&myrpt->lock);
806 ast_mutex_unlock(&myrpt->lock);
807 rpt_telemetry(myrpt,TERM,NULL);
809 case 9: /* system control group */
810 /* if invalid, just ignore */
811 if ((cmd[1] >= '2') && (cmd[1] <= '8')) return;
812 ast_mutex_lock(&myrpt->lock);
813 if (cmd[1] == '1') /* system enable */
817 if (cmd[1] == '0') /* system disable */
823 ast_mutex_unlock(&myrpt->lock);
824 l = myrpt->links.next;
825 /* disconnect all of the remote stuff */
826 while(l != &myrpt->links)
828 ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
832 case 1: /* remote base off */
833 if (!myrpt->enable) return;
834 val = ast_variable_retrieve(cfg,NODES,cmd + 1);
837 rpt_telemetry(myrpt,REMNOTFOUND,NULL);
840 strncpy(tmp,val,sizeof(tmp) - 1);
843 ast_mutex_lock(&myrpt->lock);
844 l = myrpt->links.next;
845 /* try to find this one in queue */
846 while(l != &myrpt->links)
848 /* if found matching string */
849 if (!strcmp(l->name,cmd + 1)) break;
852 if (l != &myrpt->links) /* if found */
854 ast_mutex_unlock(&myrpt->lock);
855 ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
858 ast_mutex_unlock(&myrpt->lock);
860 case 2: /* remote base monitor */
861 if (!myrpt->enable) return;
862 val = ast_variable_retrieve(cfg,NODES,cmd + 1);
865 rpt_telemetry(myrpt,REMNOTFOUND,NULL);
868 strncpy(tmp,val,sizeof(tmp) - 1);
871 ast_mutex_lock(&myrpt->lock);
872 l = myrpt->links.next;
873 /* try to find this one in queue */
874 while(l != &myrpt->links)
876 /* if found matching string */
877 if (!strcmp(l->name,cmd + 1)) break;
881 if (l != &myrpt->links)
883 /* if already in this mode, just ignore */
885 ast_mutex_unlock(&myrpt->lock);
886 rpt_telemetry(myrpt,REMALREADY,NULL);
889 ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
892 ast_mutex_unlock(&myrpt->lock);
893 /* establish call in monitor mode */
894 l = malloc(sizeof(struct rpt_link));
897 ast_log(LOG_WARNING, "Unable to malloc\n");
900 /* zero the silly thing */
901 memset((char *)l,0,sizeof(struct rpt_link));
902 sprintf(deststr,"IAX2/%s",s1);
903 tele = strchr(deststr,'/');
906 fprintf(stderr,"rpt:Dial number (%s) must be in format tech/number\n",deststr);
910 l->isremote = (s && ast_true(s));
911 strncpy(l->name,cmd + 1,MAXNODESTR - 1);
912 l->chan = ast_request(deststr,AST_FORMAT_SLINEAR,tele);
915 ast_set_read_format(l->chan,AST_FORMAT_SLINEAR);
916 ast_set_write_format(l->chan,AST_FORMAT_SLINEAR);
917 l->chan->whentohangup = 0;
918 l->chan->appl = "Apprpt";
919 l->chan->data = "(Remote Rx)";
920 if (option_verbose > 2)
921 ast_verbose(VERBOSE_PREFIX_3 "rpt (remote) initiating call to %s/%s on %s\n",
922 deststr,tele,l->chan->name);
923 l->chan->callerid = strdup(myrpt->name);
924 ast_call(l->chan,tele,0);
929 if (option_verbose > 2)
930 ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
931 deststr,tele,l->chan->name);
934 /* allocate a pseudo-channel thru asterisk */
935 l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo");
938 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
941 ast_set_read_format(l->pchan,AST_FORMAT_SLINEAR);
942 ast_set_write_format(l->pchan,AST_FORMAT_SLINEAR);
943 /* make a conference for the pseudo-one */
945 ci.confno = myrpt->conf;
946 ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER;
947 /* first put the channel on the conference in proper mode */
948 if (ioctl(l->pchan->fds[0],ZT_SETCONF,&ci) == -1)
950 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
953 ast_mutex_lock(&myrpt->lock);
954 /* insert at end of queue */
955 insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
956 ast_mutex_unlock(&myrpt->lock);
958 case 3: /* remote base tranceieve */
959 if (!myrpt->enable) return;
960 val = ast_variable_retrieve(cfg,NODES,cmd + 1);
963 rpt_telemetry(myrpt,REMNOTFOUND,NULL);
966 strncpy(tmp,val,sizeof(tmp) - 1);
969 ast_mutex_lock(&myrpt->lock);
970 l = myrpt->links.next;
971 /* try to find this one in queue */
972 while(l != &myrpt->links)
974 /* if found matching string */
975 if (!strcmp(l->name,cmd + 1)) break;
979 if (l != &myrpt->links)
981 /* if already in this mode, just ignore */
984 ast_mutex_unlock(&myrpt->lock);
985 rpt_telemetry(myrpt,REMALREADY,NULL);
988 ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
991 ast_mutex_unlock(&myrpt->lock);
992 /* establish call in tranceive mode */
993 l = malloc(sizeof(struct rpt_link));
996 ast_log(LOG_WARNING, "Unable to malloc\n");
999 /* zero the silly thing */
1000 memset((char *)l,0,sizeof(struct rpt_link));
1002 strncpy(l->name,cmd + 1,MAXNODESTR - 1);
1003 l->isremote = (s && ast_true(s));
1004 sprintf(deststr,"IAX2/%s",s1);
1005 tele = strchr(deststr,'/');
1008 fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
1012 l->chan = ast_request(deststr,AST_FORMAT_SLINEAR,tele);
1015 ast_set_read_format(l->chan,AST_FORMAT_SLINEAR);
1016 ast_set_write_format(l->chan,AST_FORMAT_SLINEAR);
1017 l->chan->whentohangup = 0;
1018 l->chan->appl = "Apprpt";
1019 l->chan->data = "(Remote Rx)";
1020 if (option_verbose > 2)
1021 ast_verbose(VERBOSE_PREFIX_3 "rpt (remote) initiating call to %s/%s on %s\n",
1022 deststr,tele,l->chan->name);
1023 l->chan->callerid = strdup(myrpt->name);
1024 ast_call(l->chan,tele,999);
1029 if (option_verbose > 2)
1030 ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
1031 deststr,tele,l->chan->name);
1034 /* allocate a pseudo-channel thru asterisk */
1035 l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo");
1038 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
1041 ast_set_read_format(l->pchan,AST_FORMAT_SLINEAR);
1042 ast_set_write_format(l->pchan,AST_FORMAT_SLINEAR);
1043 /* make a conference for the tx */
1045 ci.confno = myrpt->conf;
1046 ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER;
1047 /* first put the channel on the conference in proper mode */
1048 if (ioctl(l->pchan->fds[0],ZT_SETCONF,&ci) == -1)
1050 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
1053 ast_mutex_lock(&myrpt->lock);
1054 /* insert at end of queue */
1055 insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
1056 ast_mutex_unlock(&myrpt->lock);
1058 case 4: /* remote cmd mode */
1059 if (!myrpt->enable) return;
1060 /* if doesnt allow link cmd, return */
1061 if ((!allow_linkcmd) || (myrpt->links.next == &myrpt->links)) return;
1062 /* if already in cmd mode, or selected self, forget it */
1063 if ((myrpt->cmdnode[0]) || (!strcmp(myrpt->name,cmd + 1)))
1065 rpt_telemetry(myrpt,REMALREADY,NULL);
1068 /* node must at least exist in list */
1069 val = ast_variable_retrieve(cfg,NODES,cmd + 1);
1072 rpt_telemetry(myrpt,REMNOTFOUND,NULL);
1075 ast_mutex_lock(&myrpt->lock);
1076 myrpt->dtmfidx = -1;
1077 myrpt->dtmfbuf[0] = 0;
1078 myrpt->rem_dtmfidx = -1;
1079 myrpt->rem_dtmfbuf[0] = 0;
1080 strcpy(myrpt->cmdnode,cmd + 1);
1081 ast_mutex_unlock(&myrpt->lock);
1082 rpt_telemetry(myrpt,REMGO,NULL);
1084 case 7: /* system status */
1085 if (!myrpt->enable) return;
1086 rpt_telemetry(myrpt,STATUS,NULL);
1088 case 8: /* force ID */
1089 if (!myrpt->enable) return;
1095 if (!myrpt->enable) return;
1096 rpt_telemetry(myrpt,COMPLETE,NULL);
1099 static void handle_link_data(struct rpt *myrpt, struct rpt_link *mylink,
1102 char tmp[300],cmd[300],dest[300],src[300],c;
1105 struct ast_frame wf;
1107 /* if we are a remote, we dont want to do this */
1108 if (myrpt->remote) return;
1109 wf.frametype = AST_FRAME_TEXT;
1113 wf.datalen = strlen(str) + 1;
1115 /* put string in our buffer */
1116 strncpy(tmp,str,sizeof(tmp) - 1);
1117 if (sscanf(tmp,"%s %s %s %d %c",cmd,dest,src,&seq,&c) != 5)
1119 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
1122 if (strcmp(cmd,"D"))
1124 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
1127 /* if not for me, redistribute to all links */
1128 if (strcmp(dest,myrpt->name))
1130 l = myrpt->links.next;
1131 /* see if this is one in list */
1132 while(l != &myrpt->links)
1134 /* dont send back from where it came */
1135 if ((l == mylink) || (!strcmp(l->name,mylink->name)))
1140 /* if it is, send it and we're done */
1141 if (!strcmp(l->name,dest))
1143 /* send, but not to src */
1144 if (strcmp(l->name,src)) {
1145 wf.data = strdup(str);
1146 ast_write(l->chan,&wf);
1152 l = myrpt->links.next;
1153 /* otherwise, send it to all of em */
1154 while(l != &myrpt->links)
1156 /* dont send back from where it came */
1157 if ((l == mylink) || (!strcmp(l->name,mylink->name)))
1162 /* send, but not to src */
1163 if (strcmp(l->name,src)) {
1164 wf.data = strdup(str);
1165 ast_write(l->chan,&wf);
1171 ast_mutex_lock(&myrpt->lock);
1174 myrpt->rem_dtmfidx = 0;
1175 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
1176 time(&myrpt->rem_dtmf_time);
1177 ast_mutex_unlock(&myrpt->lock);
1180 else if ((c != '#') && (myrpt->rem_dtmfidx >= 0))
1182 time(&myrpt->rem_dtmf_time);
1183 if (myrpt->rem_dtmfidx < MAXDTMF)
1185 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
1186 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
1187 /* if to terminate function now */
1188 if ((myrpt->rem_dtmfidx == 1) && strchr(SHORTFUNCS,c))
1190 while(myrpt->rem_dtmfidx < FUNCTION_LEN)
1191 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = '0';
1192 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
1194 /* if to terminate function now */
1195 if ((myrpt->rem_dtmfidx == 2) && strchr(MEDFUNCS,myrpt->rem_dtmfbuf[0]))
1197 while(myrpt->rem_dtmfidx < FUNCTION_LEN)
1198 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = '0';
1199 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
1202 if (myrpt->rem_dtmfidx == FUNCTION_LEN)
1204 strcpy(cmd,myrpt->rem_dtmfbuf);
1205 myrpt->rem_dtmfbuf[0] = 0;
1206 myrpt->rem_dtmfidx = -1;
1207 ast_mutex_unlock(&myrpt->lock);
1208 process_dtmf(cmd,myrpt,0);
1212 ast_mutex_unlock(&myrpt->lock);
1216 /* Doug Hall RBI-1 serial data definitions:
1218 * Byte 0: Expansion external outputs
1220 * Bits 0-3 are BAND as follows:
1221 * Bits 4-5 are POWER bits as follows:
1225 * Bits 6-7 are always set
1227 * Bits 0-3 MHZ in BCD format
1228 * Bits 4-5 are offset as follows:
1232 * 03 - minus minus (whatever that is)
1233 * Bit 6 is the 0/5 KHZ bit
1234 * Bit 7 is always set
1236 * Bits 0-3 are 10 KHZ in BCD format
1237 * Bits 4-7 are 100 KHZ in BCD format
1238 * Byte 4: PL Tone code and encode/decode enable bits
1239 * Bits 0-5 are PL tone code (comspec binary codes)
1240 * Bit 6 is encode enable/disable
1241 * Bit 7 is decode enable/disable
1244 /* take the frequency from the 10 mhz digits (and up) and convert it
1247 static int rbi_mhztoband(char *str)
1251 i = atoi(str) / 10; /* get the 10's of mhz */
1282 /* take a PL frequency and turn it into a code */
1283 static int rbi_pltocode(char *str)
1288 s = strchr(str,'.');
1290 if (s) i = atoi(s + 1);
1291 i += atoi(str) * 10;
1375 * Shift out a formatted serial bit stream
1378 static void rbi_out(struct rpt *myrpt,unsigned char *data)
1382 static volatile long long delayvar;
1384 for(i = 0 ; i < 5 ; i++){
1386 for(j = 0 ; j < 8 ; j++){
1388 outb(d,myrpt->iobase);
1390 for(delayvar = 1; delayvar < 15000; delayvar++);
1392 outb(d | 2,myrpt->iobase);
1394 for(delayvar = 1; delayvar < 30000; delayvar++);
1395 outb(d,myrpt->iobase);
1397 for(delayvar = 1; delayvar < 10000; delayvar++);
1401 for(delayvar = 1; delayvar < 50000; delayvar++);
1404 static int setrbi(struct rpt *myrpt)
1406 char tmp[MAXREMSTR],rbicmd[5],*s;
1407 int band,txoffset = 0,txpower = 0,rxpl;
1410 strcpy(tmp,myrpt->freq);
1411 s = strchr(tmp,'.');
1412 /* if no decimal, is invalid */
1413 if (s == NULL) return -1;
1415 if (strlen(tmp) < 2) return -1;
1416 if (strlen(s) < 3) return -1;
1417 if ((s[2] != '0') && (s[2] != '5')) return -1;
1418 band = rbi_mhztoband(tmp);
1419 if (band == -1) return -1;
1420 rxpl = rbi_pltocode(myrpt->rxpl);
1421 if (rxpl == -1) return -1;
1422 switch(myrpt->offset)
1434 switch(myrpt->powerlevel)
1447 rbicmd[1] = band | txpower | 0xc0;
1448 rbicmd[2] = (*(s - 2) - '0') | txoffset | 0x80;
1449 if (s[2] == '5') rbicmd[2] |= 0x40;
1450 rbicmd[3] = ((*s - '0') << 4) + (s[1] - '0');
1452 if (myrpt->txplon) rbicmd[4] |= 0x40;
1453 if (myrpt->rxplon) rbicmd[4] |= 0x80;
1454 rbi_out(myrpt,rbicmd);
1458 static int remote_function(struct rpt *myrpt,char *cmd, struct ast_channel *mychannel)
1460 char *s,*s1,tmp[300],oc,savestr[MAXREMSTR],*val;
1464 case '0': /* retrieve memory */
1465 val = ast_variable_retrieve(cfg,MEMORY,cmd + 1);
1468 if (ast_safe_sleep(mychannel,1000) == -1) return -1;
1469 return(sayfile(mychannel,"rpt/memory_notfound"));
1471 strncpy(tmp,val,sizeof(tmp) - 1);
1472 s = strchr(tmp,',');
1478 strcpy(myrpt->freq,tmp);
1479 strcpy(myrpt->rxpl,s);
1480 myrpt->offset = REM_SIMPLEX;
1481 myrpt->powerlevel = REM_MEDPWR;
1490 myrpt->powerlevel = REM_LOWPWR;
1494 myrpt->powerlevel = REM_HIPWR;
1498 myrpt->powerlevel = REM_MEDPWR;
1501 myrpt->offset = REM_MINUS;
1504 myrpt->offset = REM_PLUS;
1508 myrpt->offset = REM_SIMPLEX;
1520 if (setrbi(myrpt) == -1) return 0;
1522 case '1': /* set freq + offset */
1523 strncpy(tmp,cmd,sizeof(tmp) - 1);
1526 /* see if we have at least 1 */
1527 s = strchr(tmp,'*');
1537 if (strlen(s) > 3) return 0;
1538 if (strlen(s) < 3) memset(s + strlen(s),'0',3 - strlen(s));
1540 } else strcat(tmp,".000");
1546 myrpt->offset = REM_MINUS;
1549 myrpt->offset = REM_SIMPLEX;
1552 myrpt->offset = REM_PLUS;
1557 } else myrpt->offset = REM_SIMPLEX;
1559 strcpy(savestr,myrpt->freq);
1560 strcpy(myrpt->freq,tmp + 1);
1561 if (setrbi(myrpt) == -1)
1563 strcpy(myrpt->freq,savestr);
1567 case '2': /* set rx PL tone */
1568 strncpy(tmp,cmd,sizeof(tmp) - 1);
1569 /* see if we have at least 1 */
1570 s = strchr(tmp,'*');
1574 if (strlen(s + 1) > 1) return 0;
1575 } else strcat(tmp,".0");
1576 strcpy(savestr,myrpt->rxpl);
1577 strcpy(myrpt->rxpl,tmp + 1);
1578 if (setrbi(myrpt) == -1)
1580 strcpy(myrpt->rxpl,savestr);
1584 case '4': /* other stuff */
1585 if (strlen(cmd) > 2) return 0;
1588 case '0': /* RX PL Off */
1591 case '1': /* RX PL On */
1594 case '2': /* TX PL Off */
1597 case '3': /* TX PL On */
1600 case '4': /* Low Power */
1601 myrpt->powerlevel = REM_LOWPWR;
1603 case '5': /* Medium Power */
1604 myrpt->powerlevel = REM_MEDPWR;
1606 case '6': /* Hi Power */
1607 myrpt->powerlevel = REM_HIPWR;
1612 if (setrbi(myrpt) == -1) return 0;
1620 static int handle_dtmf_digit(struct rpt *myrpt,char c, struct ast_channel *mychannel)
1622 char str[MAXDTMF],*s,*s1;
1627 if ((myrpt->dtmf_time_rem + DTMF_TIMEOUT) < now)
1629 strcpy(str,myrpt->dtmfbuf);
1630 myrpt->dtmfidx = -1;
1631 myrpt->dtmfbuf[0] = 0;
1632 myrpt->dtmf_time_rem = 0;
1634 /* if decode not active */
1635 if (myrpt->dtmfidx == -1)
1637 /* if not lead-in digit, dont worry */
1638 if (c != '*') return 0;
1640 myrpt->dtmfbuf[0] = 0;
1641 myrpt->dtmf_time_rem = now;
1644 /* if too many in buffer, start over */
1645 if (myrpt->dtmfidx >= MAXDTMF)
1648 myrpt->dtmfbuf[0] = 0;
1649 myrpt->dtmf_time_rem = now;
1653 /* if star at beginning, or 2 together, erase buffer */
1654 if ((myrpt->dtmfidx < 1) ||
1655 (myrpt->dtmfbuf[myrpt->dtmfidx - 1] == '*'))
1658 myrpt->dtmfbuf[0] = 0;
1659 myrpt->dtmf_time_rem = now;
1663 myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
1664 myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
1665 myrpt->dtmf_time_rem = now;
1666 switch(myrpt->dtmfbuf[0])
1668 case '4': /* wait for 1 more digit */
1669 /* if we are at end, process it */
1670 if (myrpt->dtmfidx >= 2) break;
1672 case '0': /* wait for 2 more digits */
1673 /* if we are at end, process it */
1674 if (myrpt->dtmfidx >= 3) break;
1677 case '3': /* go until 1 digit after * */
1678 s = strchr(myrpt->dtmfbuf,'*');
1679 /* if we dont have a star, dont worry yet */
1680 if (s == NULL) return 0;
1681 /* if nothing after star yet */
1682 if (!s[1]) return 0;
1683 /* okay, we got it */
1685 case '1': /* go until 1 digit after second * */
1686 s = strchr(myrpt->dtmfbuf,'*');
1687 /* if we dont have a star, dont worry yet */
1688 if (s == NULL) return 0;
1689 /* if nothing after star yet */
1690 if (!s[1]) return 0;
1691 s1 = strchr(s + 1,'*');
1692 /* if we dont have a 2nd star, dont worry yet */
1693 if (s1 == NULL) return 0;
1694 /* if nothing after 2nd * yet */
1695 if (!s1[1]) return 0;
1696 /* okay, we got it */
1698 case '5': /* status, just deux it here */
1699 if (sayfile(mychannel,"rpt/node") == -1) return -1;
1700 if (saycharstr(mychannel,myrpt->name) == -1) return -1;
1701 if (sayfile(mychannel,"rpt/frequency") == -1) return -1;
1702 if (saycharstr(mychannel,myrpt->freq) == -1) return -1;
1703 switch(myrpt->offset)
1706 if (sayfile(mychannel,"rpt/minus") == -1) return -1;
1709 if (sayfile(mychannel,"rpt/simplex") == -1) return -1;
1712 if (sayfile(mychannel,"rpt/plus") == -1) return -1;
1715 switch(myrpt->powerlevel)
1718 if (sayfile(mychannel,"rpt/lopwr") == -1) return -1;
1721 if (sayfile(mychannel,"rpt/medpwr") == -1) return -1;
1724 if (sayfile(mychannel,"rpt/hipwr") == -1) return -1;
1727 if (sayfile(mychannel,"rpt/rxpl") == -1) return -1;
1728 if (sayfile(mychannel,"rpt/frequency") == -1) return -1;
1729 if (saycharstr(mychannel,myrpt->rxpl) == -1) return -1;
1730 if (sayfile(mychannel,"rpt/txpl") == -1) return -1;
1731 if (sayfile(mychannel,((myrpt->txplon) ? "rpt/on" : "rpt/off")) == -1) return -1;
1732 if (sayfile(mychannel,"rpt/rxpl") == -1) return -1;
1733 if (sayfile(mychannel,((myrpt->rxplon) ? "rpt/on" : "rpt/off")) == -1) return -1;
1734 myrpt->dtmfidx = -1;
1735 myrpt->dtmfbuf[0] = 0;
1736 myrpt->dtmf_time_rem = 0;
1739 myrpt->dtmfidx = -1;
1740 myrpt->dtmfbuf[0] = 0;
1741 myrpt->dtmf_time_rem = 0;
1744 strcpy(str,myrpt->dtmfbuf);
1745 myrpt->dtmfidx = -1;
1746 myrpt->dtmfbuf[0] = 0;
1747 myrpt->dtmf_time_rem = 0;
1748 return(remote_function(myrpt,str,mychannel));
1751 static int handle_remote_data(struct rpt *myrpt, char *str, struct ast_channel *mychannel)
1753 char tmp[300],cmd[300],dest[300],src[300],c;
1756 /* put string in our buffer */
1757 strncpy(tmp,str,sizeof(tmp) - 1);
1758 if (sscanf(tmp,"%s %s %s %d %c",cmd,dest,src,&seq,&c) != 5)
1760 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
1763 if (strcmp(cmd,"D"))
1765 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
1768 /* if not for me, ignore */
1769 if (strcmp(dest,myrpt->name)) return 0;
1770 res = handle_dtmf_digit(myrpt,c,mychannel);
1771 if (res != 1) return res;
1772 if (ast_safe_sleep(mychannel,1000) == -1) return -1;
1773 return(sayfile(mychannel,"rpt/functioncomplete"));
1776 /* single thread with one file (request) to dial */
1777 static void *rpt(void *this)
1779 struct rpt *myrpt = (struct rpt *)this;
1781 int ms = MSWAIT,lasttx,keyed,val,remrx;
1782 struct ast_channel *who;
1783 ZT_CONFINFO ci; /* conference info */
1785 struct rpt_link *l,*m;
1786 pthread_attr_t attr;
1788 ast_mutex_lock(&myrpt->lock);
1789 tele = strchr(myrpt->rxchanname,'/');
1792 fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
1793 ast_mutex_unlock(&myrpt->lock);
1797 myrpt->rxchannel = ast_request(myrpt->rxchanname,AST_FORMAT_SLINEAR,tele);
1798 if (myrpt->rxchannel)
1800 ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
1801 ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
1802 myrpt->rxchannel->whentohangup = 0;
1803 myrpt->rxchannel->appl = "Apprpt";
1804 myrpt->rxchannel->data = "(Repeater Rx)";
1805 if (option_verbose > 2)
1806 ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
1807 myrpt->rxchanname,tele,myrpt->rxchannel->name);
1808 ast_call(myrpt->rxchannel,tele,999);
1812 fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
1813 ast_mutex_unlock(&myrpt->lock);
1816 if (myrpt->txchanname)
1818 tele = strchr(myrpt->txchanname,'/');
1821 fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
1822 ast_mutex_unlock(&myrpt->lock);
1826 myrpt->txchannel = ast_request(myrpt->txchanname,AST_FORMAT_SLINEAR,tele);
1827 if (myrpt->txchannel)
1829 ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
1830 ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
1831 myrpt->txchannel->whentohangup = 0;
1832 myrpt->txchannel->appl = "Apprpt";
1833 myrpt->txchannel->data = "(Repeater Rx)";
1834 if (option_verbose > 2)
1835 ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
1836 myrpt->txchanname,tele,myrpt->txchannel->name);
1837 ast_call(myrpt->txchannel,tele,999);
1841 fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
1842 ast_mutex_unlock(&myrpt->lock);
1848 myrpt->txchannel = myrpt->rxchannel;
1850 /* allocate a pseudo-channel thru asterisk */
1851 myrpt->pchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo");
1852 if (!myrpt->pchannel)
1854 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
1855 ast_mutex_unlock(&myrpt->lock);
1858 /* make a conference for the tx */
1860 ci.confno = -1; /* make a new conf */
1861 ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER;
1862 /* first put the channel on the conference in proper mode */
1863 if (ioctl(myrpt->txchannel->fds[0],ZT_SETCONF,&ci) == -1)
1865 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
1866 ast_mutex_unlock(&myrpt->lock);
1869 /* save tx conference number */
1870 myrpt->txconf = ci.confno;
1871 /* make a conference for the pseudo */
1873 ci.confno = -1; /* make a new conf */
1874 ci.confmode = ZT_CONF_CONFANNMON;
1875 /* first put the channel on the conference in announce mode */
1876 if (ioctl(myrpt->pchannel->fds[0],ZT_SETCONF,&ci) == -1)
1878 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
1879 ast_mutex_unlock(&myrpt->lock);
1882 /* save pseudo channel conference number */
1883 myrpt->conf = ci.confno;
1884 /* allocate a pseudo-channel thru asterisk */
1885 myrpt->txpchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo");
1886 if (!myrpt->txpchannel)
1888 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
1889 ast_mutex_unlock(&myrpt->lock);
1892 /* make a conference for the tx */
1894 ci.confno = myrpt->txconf;
1895 ci.confmode = ZT_CONF_CONF | ZT_CONF_TALKER ;
1896 /* first put the channel on the conference in proper mode */
1897 if (ioctl(myrpt->txpchannel->fds[0],ZT_SETCONF,&ci) == -1)
1899 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
1900 ast_mutex_unlock(&myrpt->lock);
1903 /* Now, the idea here is to copy from the physical rx channel buffer
1904 into the pseudo tx buffer, and from the pseudo rx buffer into the
1905 tx channel buffer */
1906 myrpt->links.next = &myrpt->links;
1907 myrpt->links.prev = &myrpt->links;
1908 myrpt->tailtimer = 0;
1911 myrpt->callmode = 0;
1912 myrpt->tounkeyed = 0;
1913 myrpt->tonotify = 0;
1916 myrpt->dtmfidx = -1;
1917 myrpt->dtmfbuf[0] = 0;
1918 myrpt->rem_dtmfidx = -1;
1919 myrpt->rem_dtmfbuf[0] = 0;
1921 myrpt->rem_dtmf_time = 0;
1923 ast_mutex_unlock(&myrpt->lock);
1925 ast_channel_setoption(myrpt->rxchannel,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0);
1927 ast_channel_setoption(myrpt->rxchannel,AST_OPTION_RELAXDTMF,&val,sizeof(char),0);
1930 struct ast_frame *f;
1931 struct ast_channel *cs[300];
1932 int totx,elap,n,toexit;
1934 if (ast_check_hangup(myrpt->rxchannel)) break;
1935 if (ast_check_hangup(myrpt->txchannel)) break;
1936 if (ast_check_hangup(myrpt->pchannel)) break;
1937 if (ast_check_hangup(myrpt->txpchannel)) break;
1938 ast_mutex_lock(&myrpt->lock);
1939 myrpt->localtx = keyed;
1940 l = myrpt->links.next;
1942 while(l != &myrpt->links)
1944 if (l->lastrx) remrx = 1;
1947 totx = (keyed || myrpt->callmode ||
1948 (myrpt->tele.next != &myrpt->tele));
1949 myrpt->exttx = totx;
1950 totx = totx || remrx;
1953 myrpt->totimer = myrpt->totime;
1954 myrpt->tounkeyed = 0;
1955 myrpt->tonotify = 0;
1957 else myrpt->tailtimer = myrpt->hangtime;
1958 totx = totx && myrpt->totimer;
1959 /* if timed-out and not said already, say it */
1960 if ((!myrpt->totimer) && (!myrpt->tonotify))
1962 myrpt->tonotify = 1;
1963 rpt_telemetry(myrpt,TIMEOUT,NULL);
1965 /* if wants to transmit and in phone call, but timed out,
1966 reset time-out timer if keyed */
1967 if ((!totx) && (!myrpt->totimer) && (!myrpt->tounkeyed) && (!keyed))
1969 myrpt->tounkeyed = 1;
1971 if ((!totx) && (!myrpt->totimer) && myrpt->tounkeyed && keyed)
1973 myrpt->totimer = myrpt->totime;
1974 myrpt->tounkeyed = 0;
1975 myrpt->tonotify = 0;
1976 ast_mutex_unlock(&myrpt->lock);
1979 /* if timed-out and in circuit busy after call */
1980 if ((!totx) && (!myrpt->totimer) && (myrpt->callmode == 4))
1982 myrpt->callmode = 0;
1984 /* get rid of tail if timed out */
1985 if (!myrpt->totimer) myrpt->tailtimer = 0;
1986 /* if not timed-out, add in tail */
1987 if (myrpt->totimer) totx = totx || myrpt->tailtimer;
1989 if (totx && (!myrpt->idtimer))
1991 myrpt->idtimer = myrpt->idtime;
1992 ast_mutex_unlock(&myrpt->lock);
1993 rpt_telemetry(myrpt,ID,NULL);
1994 ast_mutex_lock(&myrpt->lock);
1996 /* let telemetry transmit anyway (regardless of timeout) */
1997 totx = totx || (myrpt->tele.next != &myrpt->tele);
1998 if (totx && (!lasttx))
2001 ast_mutex_unlock(&myrpt->lock);
2002 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
2003 ast_mutex_lock(&myrpt->lock);
2005 totx = totx && myrpt->enable;
2006 if ((!totx) && lasttx)
2009 ast_mutex_unlock(&myrpt->lock);
2010 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
2011 ast_mutex_lock(&myrpt->lock);
2014 /* if DTMF timeout */
2015 if ((!myrpt->cmdnode[0]) && (myrpt->dtmfidx >= 0) && ((dtmf_time + DTMF_TIMEOUT) < t))
2017 myrpt->dtmfidx = -1;
2018 myrpt->dtmfbuf[0] = 0;
2020 /* if remote DTMF timeout */
2021 if ((myrpt->rem_dtmfidx >= 0) && ((myrpt->rem_dtmf_time + DTMF_TIMEOUT) < t))
2023 myrpt->rem_dtmfidx = -1;
2024 myrpt->rem_dtmfbuf[0] = 0;
2027 cs[n++] = myrpt->rxchannel;
2028 cs[n++] = myrpt->pchannel;
2029 cs[n++] = myrpt->txpchannel;
2030 if (myrpt->txchannel != myrpt->rxchannel) cs[n++] = myrpt->txchannel;
2031 l = myrpt->links.next;
2032 while(l != &myrpt->links)
2038 ast_mutex_unlock(&myrpt->lock);
2040 who = ast_waitfor_n(cs,n,&ms);
2041 if (who == NULL) ms = 0;
2043 ast_mutex_lock(&myrpt->lock);
2044 l = myrpt->links.next;
2045 while(l != &myrpt->links)
2047 /* ignore non-timing channels */
2048 if (l->elaptime < 0)
2053 l->elaptime += elap;
2054 /* if connection has taken too long */
2055 if ((l->elaptime > MAXCONNECTTIME) &&
2056 (l->chan->_state != AST_STATE_UP))
2058 ast_mutex_unlock(&myrpt->lock);
2059 ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
2060 rpt_telemetry(myrpt,CONNFAIL,l);
2061 ast_mutex_lock(&myrpt->lock);
2065 if (myrpt->tailtimer) myrpt->tailtimer -= elap;
2066 if (myrpt->tailtimer < 0) myrpt->tailtimer = 0;
2067 if (myrpt->totimer) myrpt->totimer -= elap;
2068 if (myrpt->totimer < 0) myrpt->totimer = 0;
2069 if (myrpt->idtimer) myrpt->idtimer -= elap;
2070 if (myrpt->idtimer < 0) myrpt->idtimer = 0;
2071 ast_mutex_unlock(&myrpt->lock);
2073 if (who == myrpt->rxchannel) /* if it was a read from rx */
2075 f = ast_read(myrpt->rxchannel);
2078 if (debug) printf("@@@@ rpt:Hung Up\n");
2081 if (f->frametype == AST_FRAME_VOICE)
2083 ast_write(myrpt->pchannel,f);
2085 else if (f->frametype == AST_FRAME_DTMF)
2089 c = (char) f->subclass; /* get DTMF char */
2092 /* if in simple mode, kill autopatch */
2093 if (myrpt->simple && myrpt->callmode)
2095 myrpt->callmode = 0;
2096 rpt_telemetry(myrpt,TERM,NULL);
2099 ast_mutex_lock(&myrpt->lock);
2100 if (myrpt->cmdnode[0])
2102 myrpt->cmdnode[0] = 0;
2103 myrpt->dtmfidx = -1;
2104 myrpt->dtmfbuf[0] = 0;
2105 ast_mutex_unlock(&myrpt->lock);
2106 rpt_telemetry(myrpt,COMPLETE,NULL);
2107 } else ast_mutex_unlock(&myrpt->lock);
2110 if (myrpt->cmdnode[0])
2112 send_link_dtmf(myrpt,c);
2120 myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
2124 else if ((c != '#') && (myrpt->dtmfidx >= 0))
2127 if (myrpt->dtmfidx < MAXDTMF)
2129 myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
2130 myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
2131 /* if to terminate function now */
2132 if ((myrpt->dtmfidx == 1) && strchr(SHORTFUNCS,c))
2134 while(myrpt->dtmfidx < FUNCTION_LEN)
2135 myrpt->dtmfbuf[myrpt->dtmfidx++] = '0';
2136 myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
2138 /* if to terminate function now */
2139 if ((myrpt->dtmfidx == 2) && strchr(MEDFUNCS,myrpt->dtmfbuf[0]))
2141 while(myrpt->dtmfidx < FUNCTION_LEN)
2142 myrpt->dtmfbuf[myrpt->dtmfidx++] = '0';
2143 myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
2146 if (myrpt->dtmfidx == FUNCTION_LEN)
2148 process_dtmf(myrpt->dtmfbuf,myrpt,1);
2149 myrpt->dtmfbuf[0] = 0;
2150 myrpt->dtmfidx = -1;
2157 if ((!myrpt->callmode) && (c == '*'))
2159 myrpt->callmode = 1;
2161 myrpt->exten[myrpt->cidx] = 0;
2162 pthread_attr_init(&attr);
2163 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2164 pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *)myrpt);
2168 if (myrpt->callmode == 1)
2170 myrpt->exten[myrpt->cidx++] = c;
2171 myrpt->exten[myrpt->cidx] = 0;
2172 /* if this exists */
2173 if (ast_exists_extension(myrpt->pchannel,myrpt->ourcontext,myrpt->exten,1,NULL))
2175 myrpt->callmode = 2;
2176 rpt_telemetry(myrpt,PROC,NULL);
2178 /* if can continue, do so */
2179 if (ast_canmatch_extension(myrpt->pchannel,myrpt->ourcontext,myrpt->exten,1,NULL)) continue;
2180 /* call has failed, inform user */
2181 myrpt->callmode = 4;
2184 if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
2186 myrpt->mydtmf = f->subclass;
2189 else if (f->frametype == AST_FRAME_CONTROL)
2191 if (f->subclass == AST_CONTROL_HANGUP)
2193 if (debug) printf("@@@@ rpt:Hung Up\n");
2198 if (f->subclass == AST_CONTROL_RADIO_KEY)
2200 if (debug) printf("@@@@ rx key\n");
2204 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
2206 if (debug) printf("@@@@ rx un-key\n");
2208 /* if we have remotes, twiddle */
2209 if (myrpt->cmdnode[0] || (myrpt->links.next != &myrpt->links))
2211 rpt_telemetry(myrpt,UNKEY,NULL);
2218 if (who == myrpt->pchannel) /* if it was a read from pseudo */
2220 f = ast_read(myrpt->pchannel);
2223 if (debug) printf("@@@@ rpt:Hung Up\n");
2226 if (f->frametype == AST_FRAME_VOICE)
2228 ast_write(myrpt->txpchannel,f);
2230 if (f->frametype == AST_FRAME_CONTROL)
2232 if (f->subclass == AST_CONTROL_HANGUP)
2234 if (debug) printf("@@@@ rpt:Hung Up\n");
2242 if (who == myrpt->txchannel) /* if it was a read from tx */
2244 f = ast_read(myrpt->txchannel);
2247 if (debug) printf("@@@@ rpt:Hung Up\n");
2250 if (f->frametype == AST_FRAME_CONTROL)
2252 if (f->subclass == AST_CONTROL_HANGUP)
2254 if (debug) printf("@@@@ rpt:Hung Up\n");
2263 l = myrpt->links.next;
2264 while(l != &myrpt->links)
2266 if (who == l->chan) /* if it was a read from rx */
2268 ast_mutex_lock(&myrpt->lock);
2270 /* see if any other links are receiving */
2271 m = myrpt->links.next;
2272 while(m != &myrpt->links)
2274 /* if not us, count it */
2275 if ((m != l) && (m->lastrx)) remrx = 1;
2278 ast_mutex_unlock(&myrpt->lock);
2279 totx = (((l->isremote) ? myrpt->localtx :
2280 myrpt->exttx) || remrx) && l->mode;
2281 if (l->lasttx != totx)
2285 ast_indicate(l->chan,AST_CONTROL_RADIO_KEY);
2289 ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
2293 f = ast_read(l->chan);
2296 ast_mutex_lock(&myrpt->lock);
2297 /* remove from queue */
2298 remque((struct qelem *) l);
2299 ast_mutex_unlock(&myrpt->lock);
2300 rpt_telemetry(myrpt,REMDISC,l);
2301 /* hang-up on call to device */
2302 ast_hangup(l->chan);
2303 ast_hangup(l->pchan);
2307 if (f->frametype == AST_FRAME_VOICE)
2309 ast_write(l->pchan,f);
2311 if (f->frametype == AST_FRAME_TEXT)
2313 handle_link_data(myrpt,l,f->data);
2315 if (f->frametype == AST_FRAME_CONTROL)
2317 if (f->subclass == AST_CONTROL_ANSWER)
2321 rpt_telemetry(myrpt,CONNECTED,l);
2324 if (f->subclass == AST_CONTROL_RADIO_KEY)
2326 if (debug) printf("@@@@ rx key\n");
2330 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
2332 if (debug) printf("@@@@ rx un-key\n");
2335 if (f->subclass == AST_CONTROL_HANGUP)
2338 ast_mutex_lock(&myrpt->lock);
2339 /* remove from queue */
2340 remque((struct qelem *) l);
2341 ast_mutex_unlock(&myrpt->lock);
2342 rpt_telemetry(myrpt,REMDISC,l);
2343 /* hang-up on call to device */
2344 ast_hangup(l->chan);
2345 ast_hangup(l->pchan);
2353 if (who == l->pchan)
2355 f = ast_read(l->pchan);
2358 if (debug) printf("@@@@ rpt:Hung Up\n");
2362 if (f->frametype == AST_FRAME_VOICE)
2364 ast_write(l->chan,f);
2366 if (f->frametype == AST_FRAME_CONTROL)
2368 if (f->subclass == AST_CONTROL_HANGUP)
2370 if (debug) printf("@@@@ rpt:Hung Up\n");
2382 if (who == myrpt->txpchannel) /* if it was a read from remote tx */
2384 f = ast_read(myrpt->txpchannel);
2387 if (debug) printf("@@@@ rpt:Hung Up\n");
2390 if (f->frametype == AST_FRAME_CONTROL)
2392 if (f->subclass == AST_CONTROL_HANGUP)
2394 if (debug) printf("@@@@ rpt:Hung Up\n");
2403 ast_mutex_lock(&myrpt->lock);
2404 ast_hangup(myrpt->pchannel);
2405 ast_hangup(myrpt->txpchannel);
2406 ast_hangup(myrpt->rxchannel);
2407 if (myrpt->txchannel != myrpt->rxchannel) ast_hangup(myrpt->txchannel);
2408 l = myrpt->links.next;
2409 while(l != &myrpt->links)
2411 struct rpt_link *ll = l;
2412 /* remove from queue */
2413 remque((struct qelem *) l);
2414 /* hang-up on call to device */
2415 ast_hangup(l->chan);
2416 ast_hangup(l->pchan);
2420 ast_mutex_unlock(&myrpt->lock);
2421 if (debug) printf("@@@@ rpt:Hung up channel\n");
2426 static void *rpt_master(void *ignore)
2431 /* start with blank config */
2432 memset(&rpt_vars,0,sizeof(rpt_vars));
2434 cfg = ast_load("rpt.conf");
2436 ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf. Radio Repeater disabled.\n");
2440 /* go thru all the specified repeaters */
2443 while((this = ast_category_browse(cfg,this)) != NULL)
2445 if (!strcmp(this,NODES)) continue;
2446 if (!strcmp(this,MEMORY)) continue;
2447 ast_log(LOG_DEBUG,"Loading config for repeater %s\n",this);
2448 ast_mutex_init(&rpt_vars[n].lock);
2449 rpt_vars[n].tele.next = &rpt_vars[n].tele;
2450 rpt_vars[n].tele.prev = &rpt_vars[n].tele;
2451 rpt_vars[n].name = this;
2452 rpt_vars[n].rxchanname = ast_variable_retrieve(cfg,this,"rxchannel");
2453 rpt_vars[n].txchanname = ast_variable_retrieve(cfg,this,"txchannel");
2454 rpt_vars[n].ourcontext = ast_variable_retrieve(cfg,this,"context");
2455 if (!rpt_vars[n].ourcontext) rpt_vars[n].ourcontext = this;
2456 rpt_vars[n].ourcallerid = ast_variable_retrieve(cfg,this,"callerid");
2457 rpt_vars[n].acctcode = ast_variable_retrieve(cfg,this,"accountcode");
2458 rpt_vars[n].ident = ast_variable_retrieve(cfg,this,"idrecording");
2459 val = ast_variable_retrieve(cfg,this,"hangtime");
2460 if (val) rpt_vars[n].hangtime = atoi(val);
2461 else rpt_vars[n].hangtime = HANGTIME;
2462 val = ast_variable_retrieve(cfg,this,"totime");
2463 if (val) rpt_vars[n].totime = atoi(val);
2464 else rpt_vars[n].totime = TOTIME;
2465 val = ast_variable_retrieve(cfg,this,"idtime");
2466 if (val) rpt_vars[n].idtime = atoi(val);
2467 else rpt_vars[n].idtime = IDTIME;
2468 val = ast_variable_retrieve(cfg,this,"simple");
2469 if (val) rpt_vars[n].simple = ast_true(val);
2470 else rpt_vars[n].simple = 0;
2471 val = ast_variable_retrieve(cfg,this,"remote");
2472 if (val) rpt_vars[n].remote = ast_true(val);
2473 else rpt_vars[n].remote = 0;
2474 rpt_vars[n].tonezone = ast_variable_retrieve(cfg,this,"tonezone");
2475 val = ast_variable_retrieve(cfg,this,"iobase");
2476 if (val) rpt_vars[n].iobase = atoi(val);
2477 else rpt_vars[n].iobase = DEFAULT_IOBASE;
2481 ast_log(LOG_DEBUG, "Total of %d repeaters configured.\n",n);
2483 for(i = 0; i < n; i++)
2485 if (!rpt_vars[i].rxchanname)
2487 ast_log(LOG_WARNING,"Did not specify rxchanname for node %s\n",rpt_vars[i].name);
2490 /* if is a remote, dont start one for it */
2491 if (rpt_vars[i].remote)
2493 strcpy(rpt_vars[i].freq,"146.460");
2494 strcpy(rpt_vars[i].rxpl,"100.0");
2495 rpt_vars[i].offset = REM_SIMPLEX;
2496 rpt_vars[i].powerlevel = REM_MEDPWR;
2499 if (!rpt_vars[i].ident)
2501 ast_log(LOG_WARNING,"Did not specify ident for node %s\n",rpt_vars[i].name);
2504 pthread_create(&rpt_vars[i].rpt_thread,NULL,rpt,(void *) &rpt_vars[i]);
2506 /* wait for first one to die (should be never) */
2507 pthread_join(rpt_vars[0].rpt_thread,NULL);
2511 static int rpt_exec(struct ast_channel *chan, void *data)
2513 int res=-1,i,keyed = 0,rem_totx;
2514 struct localuser *u;
2516 char *options,*stringp,*tele;
2518 struct ast_frame *f;
2519 struct ast_channel *who;
2520 struct ast_channel *cs[20];
2522 ZT_CONFINFO ci; /* conference info */
2525 if (!data || ast_strlen_zero((char *)data)) {
2526 ast_log(LOG_WARNING, "Rpt requires an argument (system node)\n");
2529 strncpy(tmp, (char *)data, sizeof(tmp)-1);
2531 strsep(&stringp, "|");
2532 options = strsep(&stringp, "|");
2534 /* see if we can find our specified one */
2535 for(i = 0; i < nrpts; i++)
2537 /* if name matches, assign it and exit loop */
2538 if (!strcmp(tmp,rpt_vars[i].name))
2540 myrpt = &rpt_vars[i];
2546 ast_log(LOG_WARNING, "Cannot find specified system node %s\n",tmp);
2549 /* if is not a remote */
2554 /* look at callerid to see what node this comes from */
2555 if (!chan->callerid) /* if doesnt have callerid */
2557 ast_log(LOG_WARNING, "Trying to use busy link on %s\n",tmp);
2560 ast_callerid_parse(chan->callerid,&b,&b1);
2561 ast_shrink_phone_number(b1);
2562 if (!strcmp(myrpt->name,b1))
2564 ast_log(LOG_WARNING, "Trying to link to self!!\n");
2567 ast_mutex_lock(&myrpt->lock);
2568 l = myrpt->links.next;
2569 /* try to find this one in queue */
2570 while(l != &myrpt->links)
2572 /* if found matching string */
2573 if (!strcmp(l->name,b1)) break;
2577 if (l != &myrpt->links)
2579 /* remove from queue */
2580 remque((struct qelem *) l);
2581 ast_mutex_unlock(&myrpt->lock);
2582 /* hang-up on call to device */
2583 ast_hangup(l->chan);
2584 ast_hangup(l->pchan);
2588 ast_mutex_unlock(&myrpt->lock);
2589 /* establish call in tranceive mode */
2590 l = malloc(sizeof(struct rpt_link));
2593 ast_log(LOG_WARNING, "Unable to malloc\n");
2596 /* zero the silly thing */
2597 memset((char *)l,0,sizeof(struct rpt_link));
2599 strncpy(l->name,b1,MAXNODESTR - 1);
2603 ast_set_read_format(l->chan,AST_FORMAT_SLINEAR);
2604 ast_set_write_format(l->chan,AST_FORMAT_SLINEAR);
2605 /* allocate a pseudo-channel thru asterisk */
2606 l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo");
2609 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
2612 ast_set_read_format(l->pchan,AST_FORMAT_SLINEAR);
2613 ast_set_write_format(l->pchan,AST_FORMAT_SLINEAR);
2614 /* make a conference for the tx */
2616 ci.confno = myrpt->conf;
2617 ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER;
2618 /* first put the channel on the conference in proper mode */
2619 if (ioctl(l->pchan->fds[0],ZT_SETCONF,&ci) == -1)
2621 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2624 ast_mutex_lock(&myrpt->lock);
2625 /* insert at end of queue */
2626 insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
2627 ast_mutex_unlock(&myrpt->lock);
2628 if (chan->_state != AST_STATE_UP) {
2631 return AST_PBX_KEEPALIVE;
2633 /* if remote, error if anyone else already linked */
2634 if (myrpt->remoteon)
2636 ast_mutex_unlock(&myrpt->lock);
2637 ast_log(LOG_WARNING, "Trying to use busy link on %s\n",tmp);
2640 if (ioperm(myrpt->iobase,1,1) == -1)
2642 ast_mutex_unlock(&myrpt->lock);
2643 ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->iobase);
2647 tele = strchr(myrpt->rxchanname,'/');
2650 fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
2651 ast_mutex_unlock(&myrpt->lock);
2655 ast_mutex_lock(&myrpt->lock);
2656 myrpt->rxchannel = ast_request(myrpt->rxchanname,AST_FORMAT_SLINEAR,tele);
2657 if (myrpt->rxchannel)
2659 ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
2660 ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
2661 myrpt->rxchannel->whentohangup = 0;
2662 myrpt->rxchannel->appl = "Apprpt";
2663 myrpt->rxchannel->data = "(Repeater Rx)";
2664 if (option_verbose > 2)
2665 ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
2666 myrpt->rxchanname,tele,myrpt->rxchannel->name);
2667 ast_mutex_unlock(&myrpt->lock);
2668 ast_call(myrpt->rxchannel,tele,999);
2669 ast_mutex_lock(&myrpt->lock);
2673 fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
2674 ast_mutex_unlock(&myrpt->lock);
2678 if (myrpt->txchanname)
2680 tele = strchr(myrpt->txchanname,'/');
2683 fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
2684 ast_mutex_unlock(&myrpt->lock);
2688 myrpt->txchannel = ast_request(myrpt->txchanname,AST_FORMAT_SLINEAR,tele);
2689 if (myrpt->txchannel)
2691 ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
2692 ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
2693 myrpt->txchannel->whentohangup = 0;
2694 myrpt->txchannel->appl = "Apprpt";
2695 myrpt->txchannel->data = "(Repeater Rx)";
2696 if (option_verbose > 2)
2697 ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
2698 myrpt->txchanname,tele,myrpt->txchannel->name);
2699 ast_mutex_unlock(&myrpt->lock);
2700 ast_call(myrpt->txchannel,tele,999);
2701 ast_mutex_lock(&myrpt->lock);
2705 fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
2706 ast_mutex_unlock(&myrpt->lock);
2713 myrpt->txchannel = myrpt->rxchannel;
2715 myrpt->remoterx = 0;
2716 myrpt->remotetx = 0;
2717 myrpt->remoteon = 1;
2718 myrpt->dtmfidx = -1;
2719 myrpt->dtmfbuf[0] = 0;
2720 myrpt->dtmf_time_rem = 0;
2721 ast_mutex_unlock(&myrpt->lock);
2723 ast_set_write_format(chan, AST_FORMAT_SLINEAR);
2724 ast_set_read_format(chan, AST_FORMAT_SLINEAR);
2725 /* if we are on 2w loop and are a remote, turn EC on */
2726 if (myrpt->remote && (myrpt->rxchannel == myrpt->txchannel))
2729 ioctl(myrpt->rxchannel->fds[0],ZT_ECHOCANCEL,&i);
2731 if (chan->_state != AST_STATE_UP) {
2735 cs[1] = myrpt->rxchannel;
2738 if (ast_check_hangup(chan)) break;
2739 if (ast_check_hangup(myrpt->rxchannel)) break;
2741 who = ast_waitfor_n(cs,2,&ms);
2742 if (who == NULL) ms = 0;
2746 if (rem_totx && (!myrpt->remotetx))
2748 myrpt->remotetx = 1;
2749 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
2751 if ((!rem_totx) && myrpt->remotetx)
2753 myrpt->remotetx = 0;
2754 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
2756 if (who == chan) /* if it was a read from incomming */
2761 if (debug) printf("@@@@ link:Hung Up\n");
2764 if (f->frametype == AST_FRAME_VOICE)
2766 /* if not transmitting, zero-out audio */
2767 if (!myrpt->remotetx)
2768 memset(f->data,0,f->datalen);
2769 ast_write(myrpt->txchannel,f);
2771 else if (f->frametype == AST_FRAME_TEXT)
2773 if (handle_remote_data(myrpt,f->data,chan) == -1)
2775 if (debug) printf("@@@@ rpt:Hung Up\n");
2780 else if (f->frametype == AST_FRAME_CONTROL)
2782 if (f->subclass == AST_CONTROL_HANGUP)
2784 if (debug) printf("@@@@ rpt:Hung Up\n");
2789 if (f->subclass == AST_CONTROL_RADIO_KEY)
2791 if (debug) printf("@@@@ rx key\n");
2795 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
2797 if (debug) printf("@@@@ rx un-key\n");
2804 if (who == myrpt->rxchannel) /* if it was a read from radio */
2806 f = ast_read(myrpt->rxchannel);
2809 if (debug) printf("@@@@ link:Hung Up\n");
2812 if (f->frametype == AST_FRAME_VOICE)
2814 if ((myrpt->remote) && (myrpt->remotetx))
2815 memset(f->data,0,f->datalen);
2818 else if (f->frametype == AST_FRAME_CONTROL)
2820 if (f->subclass == AST_CONTROL_HANGUP)
2822 if (debug) printf("@@@@ rpt:Hung Up\n");
2827 if (f->subclass == AST_CONTROL_RADIO_KEY)
2829 if (debug) printf("@@@@ remote rx key\n");
2830 if (!myrpt->remotetx)
2832 ast_indicate(chan,AST_CONTROL_RADIO_KEY);
2833 myrpt->remoterx = 1;
2837 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
2839 if (debug) printf("@@@@ remote rx un-key\n");
2840 if (!myrpt->remotetx)
2842 ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
2843 myrpt->remoterx = 0;
2852 ast_mutex_lock(&myrpt->lock);
2853 if (myrpt->rxchannel != myrpt->txchannel) ast_hangup(myrpt->txchannel);
2854 ast_hangup(myrpt->rxchannel);
2855 myrpt->remoteon = 0;
2856 ast_mutex_unlock(&myrpt->lock);
2857 LOCAL_USER_REMOVE(u);
2861 int unload_module(void)
2865 STANDARD_HANGUP_LOCALUSERS;
2866 for(i = 0; i < nrpts; i++) {
2867 if (!strcmp(rpt_vars[i].name,NODES)) continue;
2868 ast_mutex_destroy(&rpt_vars[i].lock);
2870 return ast_unregister_application(app);
2874 int load_module(void)
2876 pthread_create(&rpt_master_thread,NULL,rpt_master,NULL);
2877 return ast_register_application(app, rpt_exec, synopsis, descrip);
2880 char *description(void)
2888 STANDARD_USECOUNT(res);
2894 return ASTERISK_GPL_KEY;