Added support for signalling system no. 5.
More infos will follow on the isdn4linux mailing list. modified: Makefile.am modified: Makefile.in modified: README modified: apppbx.cpp modified: configure modified: configure.ac modified: default/options.conf modified: dss1.cpp modified: ie.cpp modified: interface.c modified: interface.h modified: lcradmin.c modified: lcrsocket.h modified: mISDN.cpp modified: mISDN.h modified: main.c modified: main.h modified: port.h modified: socket_server.c new file: ss5.cpp new file: ss5.h new file: ss5_decode.c new file: ss5_decode.h new file: ss5_encode.c new file: ss5_encode.h
This commit is contained in:
parent
96124cb106
commit
323cbc387b
12
Makefile.am
12
Makefile.am
|
@ -56,6 +56,14 @@ GSM_LIB = /usr/lib/libgsm.a ./openbsc/src/libbsc.a ./openbsc/src/libmsc.a ./open
|
|||
|
||||
endif
|
||||
|
||||
if ENABLE_SS5
|
||||
|
||||
SS5_INCLUDE = -DWITH_SS5
|
||||
|
||||
SS5_SOURCE = ss5.cpp ss5_encode.c ss5_decode.c
|
||||
|
||||
endif
|
||||
|
||||
bin_PROGRAMS = lcradmin gentones genwave
|
||||
|
||||
sbin_PROGRAMS = lcr genrc genextension
|
||||
|
@ -84,9 +92,9 @@ install-exec-hook:
|
|||
$(INSTALL) chan_lcr.so $(astmoddir)
|
||||
endif
|
||||
|
||||
INCLUDES = $(all_includes) $(GSM_INCLUDE) -Wall -I/usr/include/mISDNuser $(INSTALLATION_DEFINES)
|
||||
INCLUDES = $(all_includes) $(GSM_INCLUDE) $(SS5_INCLUDE) -Wall -I/usr/include/mISDNuser $(INSTALLATION_DEFINES)
|
||||
|
||||
lcr_SOURCES = $(GSM_SOURCE) action.cpp mISDN.cpp tones.c \
|
||||
lcr_SOURCES = $(GSM_SOURCE) $(SS5_SOURCE) action.cpp mISDN.cpp tones.c \
|
||||
action_efi.cpp crypt.cpp mail.c trace.c \
|
||||
action_vbox.cpp dss1.cpp main.c \
|
||||
vbox.cpp alawulaw.c endpoint.cpp interface.c message.c \
|
||||
|
|
49
Makefile.in
49
Makefile.in
|
@ -77,26 +77,29 @@ genwave_OBJECTS = genwave.$(OBJEXT)
|
|||
genwave_LDADD = $(LDADD)
|
||||
am__lcr_SOURCES_DIST = gsm_audio.c gsm.cpp gsm_conf.c \
|
||||
openbsc/src/bsc_init.c openbsc/src/vty_interface.c \
|
||||
openbsc/src/vty_interface_layer3.c action.cpp mISDN.cpp \
|
||||
tones.c action_efi.cpp crypt.cpp mail.c trace.c \
|
||||
action_vbox.cpp dss1.cpp main.c vbox.cpp alawulaw.c \
|
||||
endpoint.cpp interface.c message.c apppbx.cpp endpointapp.cpp \
|
||||
join.cpp options.c extension.c joinpbx.cpp port.cpp callerid.c \
|
||||
joinremote.cpp route.c cause.c socket_server.c
|
||||
openbsc/src/vty_interface_layer3.c ss5.cpp ss5_encode.c \
|
||||
ss5_decode.c action.cpp mISDN.cpp tones.c action_efi.cpp \
|
||||
crypt.cpp mail.c trace.c action_vbox.cpp dss1.cpp main.c \
|
||||
vbox.cpp alawulaw.c endpoint.cpp interface.c message.c \
|
||||
apppbx.cpp endpointapp.cpp join.cpp options.c extension.c \
|
||||
joinpbx.cpp port.cpp callerid.c joinremote.cpp route.c cause.c \
|
||||
socket_server.c
|
||||
@ENABLE_GSM_TRUE@am__objects_1 = gsm_audio.$(OBJEXT) gsm.$(OBJEXT) \
|
||||
@ENABLE_GSM_TRUE@ gsm_conf.$(OBJEXT) bsc_init.$(OBJEXT) \
|
||||
@ENABLE_GSM_TRUE@ vty_interface.$(OBJEXT) \
|
||||
@ENABLE_GSM_TRUE@ vty_interface_layer3.$(OBJEXT)
|
||||
am_lcr_OBJECTS = $(am__objects_1) action.$(OBJEXT) mISDN.$(OBJEXT) \
|
||||
tones.$(OBJEXT) action_efi.$(OBJEXT) crypt.$(OBJEXT) \
|
||||
mail.$(OBJEXT) trace.$(OBJEXT) action_vbox.$(OBJEXT) \
|
||||
dss1.$(OBJEXT) main.$(OBJEXT) vbox.$(OBJEXT) \
|
||||
alawulaw.$(OBJEXT) endpoint.$(OBJEXT) interface.$(OBJEXT) \
|
||||
message.$(OBJEXT) apppbx.$(OBJEXT) endpointapp.$(OBJEXT) \
|
||||
join.$(OBJEXT) options.$(OBJEXT) extension.$(OBJEXT) \
|
||||
joinpbx.$(OBJEXT) port.$(OBJEXT) callerid.$(OBJEXT) \
|
||||
joinremote.$(OBJEXT) route.$(OBJEXT) cause.$(OBJEXT) \
|
||||
socket_server.$(OBJEXT)
|
||||
@ENABLE_SS5_TRUE@am__objects_2 = ss5.$(OBJEXT) ss5_encode.$(OBJEXT) \
|
||||
@ENABLE_SS5_TRUE@ ss5_decode.$(OBJEXT)
|
||||
am_lcr_OBJECTS = $(am__objects_1) $(am__objects_2) action.$(OBJEXT) \
|
||||
mISDN.$(OBJEXT) tones.$(OBJEXT) action_efi.$(OBJEXT) \
|
||||
crypt.$(OBJEXT) mail.$(OBJEXT) trace.$(OBJEXT) \
|
||||
action_vbox.$(OBJEXT) dss1.$(OBJEXT) main.$(OBJEXT) \
|
||||
vbox.$(OBJEXT) alawulaw.$(OBJEXT) endpoint.$(OBJEXT) \
|
||||
interface.$(OBJEXT) message.$(OBJEXT) apppbx.$(OBJEXT) \
|
||||
endpointapp.$(OBJEXT) join.$(OBJEXT) options.$(OBJEXT) \
|
||||
extension.$(OBJEXT) joinpbx.$(OBJEXT) port.$(OBJEXT) \
|
||||
callerid.$(OBJEXT) joinremote.$(OBJEXT) route.$(OBJEXT) \
|
||||
cause.$(OBJEXT) socket_server.$(OBJEXT)
|
||||
lcr_OBJECTS = $(am_lcr_OBJECTS)
|
||||
am__DEPENDENCIES_1 =
|
||||
@ENABLE_GSM_TRUE@am__DEPENDENCIES_2 = /usr/lib/libgsm.a \
|
||||
|
@ -161,6 +164,8 @@ ENABLE_ASTERISK_CHANNEL_DRIVER_FALSE = @ENABLE_ASTERISK_CHANNEL_DRIVER_FALSE@
|
|||
ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE = @ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@
|
||||
ENABLE_GSM_FALSE = @ENABLE_GSM_FALSE@
|
||||
ENABLE_GSM_TRUE = @ENABLE_GSM_TRUE@
|
||||
ENABLE_SS5_FALSE = @ENABLE_SS5_FALSE@
|
||||
ENABLE_SS5_TRUE = @ENABLE_SS5_TRUE@
|
||||
EXEEXT = @EXEEXT@
|
||||
GREP = @GREP@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
|
@ -246,11 +251,16 @@ INSTALLATION_DEFINES = \
|
|||
@ENABLE_GSM_TRUE@GSM_INCLUDE = -DWITH_GSM -I./openbsc/include
|
||||
@ENABLE_GSM_TRUE@GSM_SOURCE = gsm_audio.c gsm.cpp gsm_conf.c openbsc/src/bsc_init.c openbsc/src/vty_interface.c openbsc/src/vty_interface_layer3.c
|
||||
@ENABLE_GSM_TRUE@GSM_LIB = /usr/lib/libgsm.a ./openbsc/src/libbsc.a ./openbsc/src/libmsc.a ./openbsc/src/libvty.a -ldbi -lcrypt
|
||||
|
||||
#gsm_audio.po: gsm_audio.c gsm_audio.h
|
||||
# $(CC) -D_GNU_SOURCE -fPIC -c gsm_audio.c -o gsm_audio.po
|
||||
@ENABLE_SS5_TRUE@SS5_INCLUDE = -DWITH_SS5
|
||||
@ENABLE_SS5_TRUE@SS5_SOURCE = ss5.cpp ss5_encode.c ss5_decode.c
|
||||
@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@chan_lcr_so_SOURCES =
|
||||
@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@chan_lcr_so_LDFLAGS = -shared
|
||||
@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@chan_lcr_so_LDADD = chan_lcr.po bchannel.po options.po callerid.po
|
||||
INCLUDES = $(all_includes) $(GSM_INCLUDE) -Wall -I/usr/include/mISDNuser $(INSTALLATION_DEFINES)
|
||||
lcr_SOURCES = $(GSM_SOURCE) action.cpp mISDN.cpp tones.c \
|
||||
INCLUDES = $(all_includes) $(GSM_INCLUDE) $(SS5_INCLUDE) -Wall -I/usr/include/mISDNuser $(INSTALLATION_DEFINES)
|
||||
lcr_SOURCES = $(GSM_SOURCE) $(SS5_SOURCE) action.cpp mISDN.cpp tones.c \
|
||||
action_efi.cpp crypt.cpp mail.c trace.c \
|
||||
action_vbox.cpp dss1.cpp main.c \
|
||||
vbox.cpp alawulaw.c endpoint.cpp interface.c message.c \
|
||||
|
@ -437,6 +447,9 @@ distclean-compile:
|
|||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/port.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/route.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket_server.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss5.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss5_decode.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss5_encode.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tones.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trace.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vbox.Po@am__quote@
|
||||
|
|
3
README
3
README
|
@ -517,8 +517,9 @@ Changes after Version 1.6
|
|||
- Fixed bad call/conference bug in joinpbx.c
|
||||
- External interfaces must now be specified using 'extern' keyword.
|
||||
-> This prevents from selecting other interfaces when dialing out.
|
||||
-> Just add 'extern' right below your external interface, or define
|
||||
-> Just add 'extern' right below your external interface definition, or give
|
||||
external interface name in routing.conf: ": extern interfaces=XXXXX"
|
||||
- Added experimental CCITT No. 5 signalling system. (for educational purpose)
|
||||
|
||||
|
||||
|
||||
|
|
185
apppbx.cpp
185
apppbx.cpp
|
@ -136,7 +136,7 @@ void EndpointAppPBX::trace_header(const char *name, int direction)
|
|||
SCPY(msgtext, name);
|
||||
|
||||
/* init trace with given values */
|
||||
start_trace(0,
|
||||
start_trace(-1,
|
||||
NULL,
|
||||
numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype, options.national, options.international),
|
||||
e_dialinginfo.id,
|
||||
|
@ -648,92 +648,108 @@ foundif:
|
|||
|
||||
/* check for channel form selection list */
|
||||
*channel = 0;
|
||||
selchannel = ifport->out_channel;
|
||||
while(selchannel) {
|
||||
switch(selchannel->channel) {
|
||||
case CHANNEL_FREE: /* free channel */
|
||||
if (mISDNport->b_reserved >= mISDNport->b_num)
|
||||
break; /* all channel in use or reserverd */
|
||||
/* find channel */
|
||||
i = 0;
|
||||
while(i < mISDNport->b_num) {
|
||||
#ifdef WITH_SS5
|
||||
if (mISDNport->ss5) {
|
||||
class Pss5 *port;
|
||||
port = ss5_hunt_line(mISDNport);
|
||||
if (port) {
|
||||
*channel = port->p_m_b_channel;
|
||||
trace_header("CHANNEL SELECTION (selecting SS5 channel)", DIRECTION_NONE);
|
||||
add_trace("port", NULL, "%d", ifport->portnum);
|
||||
add_trace("position", NULL, "%d", index);
|
||||
add_trace("channel", NULL, "%d", *channel);
|
||||
end_trace();
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
selchannel = ifport->out_channel;
|
||||
while(selchannel) {
|
||||
switch(selchannel->channel) {
|
||||
case CHANNEL_FREE: /* free channel */
|
||||
if (mISDNport->b_reserved >= mISDNport->b_num)
|
||||
break; /* all channel in use or reserverd */
|
||||
/* find channel */
|
||||
i = 0;
|
||||
while(i < mISDNport->b_num) {
|
||||
if (mISDNport->b_port[i] == NULL) {
|
||||
*channel = i+1+(i>=15);
|
||||
trace_header("CHANNEL SELECTION (selecting free channel)", DIRECTION_NONE);
|
||||
add_trace("port", NULL, "%d", ifport->portnum);
|
||||
add_trace("position", NULL, "%d", index);
|
||||
add_trace("channel", NULL, "%d", *channel);
|
||||
end_trace();
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (*channel)
|
||||
break;
|
||||
trace_header("CHANNEL SELECTION (no channel is 'free')", DIRECTION_NONE);
|
||||
add_trace("port", NULL, "%d", ifport->portnum);
|
||||
add_trace("position", NULL, "%d", index);
|
||||
end_trace();
|
||||
break;
|
||||
|
||||
case CHANNEL_ANY: /* don't ask for channel */
|
||||
if (mISDNport->b_reserved >= mISDNport->b_num) {
|
||||
trace_header("CHANNEL SELECTION (cannot ask for 'any' channel, all reserved)", DIRECTION_NONE);
|
||||
add_trace("port", NULL, "%d", ifport->portnum);
|
||||
add_trace("position", NULL, "%d", index);
|
||||
add_trace("total", NULL, "%d", mISDNport->b_num);
|
||||
add_trace("reserved", NULL, "%d", mISDNport->b_reserved);
|
||||
end_trace();
|
||||
break; /* all channel in use or reserverd */
|
||||
}
|
||||
trace_header("CHANNEL SELECTION (using 'any' channel)", DIRECTION_NONE);
|
||||
add_trace("port", NULL, "%d", ifport->portnum);
|
||||
add_trace("position", NULL, "%d", index);
|
||||
end_trace();
|
||||
*channel = CHANNEL_ANY;
|
||||
break;
|
||||
|
||||
case CHANNEL_NO: /* call waiting */
|
||||
trace_header("CHANNEL SELECTION (using 'no' channel, call-waiting)", DIRECTION_NONE);
|
||||
add_trace("port", NULL, "%d", ifport->portnum);
|
||||
add_trace("position", NULL, "%d", index);
|
||||
end_trace();
|
||||
*channel = CHANNEL_NO;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (selchannel->channel<1 || selchannel->channel==16) {
|
||||
trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
|
||||
add_trace("port", NULL, "%d", ifport->portnum);
|
||||
add_trace("position", NULL, "%d", index);
|
||||
add_trace("channel", NULL, "%d", selchannel->channel);
|
||||
end_trace();
|
||||
break; /* invalid channels */
|
||||
}
|
||||
i = selchannel->channel-1-(selchannel->channel>=17);
|
||||
if (i >= mISDNport->b_num) {
|
||||
trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
|
||||
add_trace("port", NULL, "%d", ifport->portnum);
|
||||
add_trace("position", NULL, "%d", index);
|
||||
add_trace("channel", NULL, "%d", selchannel->channel);
|
||||
add_trace("channels", NULL, "%d", mISDNport->b_num);
|
||||
end_trace();
|
||||
break; /* channel not in port */
|
||||
}
|
||||
if (mISDNport->b_port[i] == NULL) {
|
||||
*channel = i+1+(i>=15);
|
||||
trace_header("CHANNEL SELECTION (selecting free channel)", DIRECTION_NONE);
|
||||
*channel = selchannel->channel;
|
||||
trace_header("CHANNEL SELECTION (selecting given channel)", DIRECTION_NONE);
|
||||
add_trace("port", NULL, "%d", ifport->portnum);
|
||||
add_trace("position", NULL, "%d", index);
|
||||
add_trace("channel", NULL, "%d", *channel);
|
||||
end_trace();
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
if (*channel)
|
||||
break;
|
||||
trace_header("CHANNEL SELECTION (no channel is 'free')", DIRECTION_NONE);
|
||||
add_trace("port", NULL, "%d", ifport->portnum);
|
||||
add_trace("position", NULL, "%d", index);
|
||||
end_trace();
|
||||
break;
|
||||
|
||||
case CHANNEL_ANY: /* don't ask for channel */
|
||||
if (mISDNport->b_reserved >= mISDNport->b_num) {
|
||||
trace_header("CHANNEL SELECTION (cannot ask for 'any' channel, all reserved)", DIRECTION_NONE);
|
||||
add_trace("port", NULL, "%d", ifport->portnum);
|
||||
add_trace("position", NULL, "%d", index);
|
||||
add_trace("total", NULL, "%d", mISDNport->b_num);
|
||||
add_trace("reserved", NULL, "%d", mISDNport->b_reserved);
|
||||
end_trace();
|
||||
break; /* all channel in use or reserverd */
|
||||
}
|
||||
trace_header("CHANNEL SELECTION (using 'any' channel)", DIRECTION_NONE);
|
||||
add_trace("port", NULL, "%d", ifport->portnum);
|
||||
add_trace("position", NULL, "%d", index);
|
||||
end_trace();
|
||||
*channel = CHANNEL_ANY;
|
||||
break;
|
||||
|
||||
case CHANNEL_NO: /* call waiting */
|
||||
trace_header("CHANNEL SELECTION (using 'no' channel, call-waiting)", DIRECTION_NONE);
|
||||
add_trace("port", NULL, "%d", ifport->portnum);
|
||||
add_trace("position", NULL, "%d", index);
|
||||
end_trace();
|
||||
*channel = CHANNEL_NO;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (selchannel->channel<1 || selchannel->channel==16) {
|
||||
trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
|
||||
add_trace("port", NULL, "%d", ifport->portnum);
|
||||
add_trace("position", NULL, "%d", index);
|
||||
add_trace("channel", NULL, "%d", selchannel->channel);
|
||||
end_trace();
|
||||
break; /* invalid channels */
|
||||
}
|
||||
i = selchannel->channel-1-(selchannel->channel>=17);
|
||||
if (i >= mISDNport->b_num) {
|
||||
trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
|
||||
add_trace("port", NULL, "%d", ifport->portnum);
|
||||
add_trace("position", NULL, "%d", index);
|
||||
add_trace("channel", NULL, "%d", selchannel->channel);
|
||||
add_trace("channels", NULL, "%d", mISDNport->b_num);
|
||||
end_trace();
|
||||
break; /* channel not in port */
|
||||
}
|
||||
if (mISDNport->b_port[i] == NULL) {
|
||||
*channel = selchannel->channel;
|
||||
trace_header("CHANNEL SELECTION (selecting given channel)", DIRECTION_NONE);
|
||||
add_trace("port", NULL, "%d", ifport->portnum);
|
||||
add_trace("position", NULL, "%d", index);
|
||||
add_trace("channel", NULL, "%d", *channel);
|
||||
end_trace();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
break; /* found channel */
|
||||
selchannel = selchannel->next;
|
||||
}
|
||||
if (*channel)
|
||||
break; /* found channel */
|
||||
selchannel = selchannel->next;
|
||||
}
|
||||
|
||||
/* if channel was found, return mISDNport and channel */
|
||||
|
@ -921,6 +937,11 @@ void EndpointAppPBX::out_setup(void)
|
|||
}
|
||||
/* creating INTERNAL port */
|
||||
SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
|
||||
#ifdef WITH_SS5
|
||||
if (mISDNport->ss5)
|
||||
port = ss5_hunt_line(mISDNport);
|
||||
else
|
||||
#endif
|
||||
if (!mISDNport->gsm)
|
||||
port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
|
||||
else
|
||||
|
@ -1034,6 +1055,11 @@ void EndpointAppPBX::out_setup(void)
|
|||
if (mISDNport) {
|
||||
/* creating EXTERNAL port*/
|
||||
SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
|
||||
#ifdef WITH_SS5
|
||||
if (mISDNport->ss5)
|
||||
port = ss5_hunt_line(mISDNport);
|
||||
else
|
||||
#endif
|
||||
port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
|
||||
if (!port)
|
||||
FATAL("No memory for Port instance\n");
|
||||
|
@ -1124,6 +1150,11 @@ void EndpointAppPBX::out_setup(void)
|
|||
}
|
||||
/* creating EXTERNAL port*/
|
||||
SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
|
||||
#ifdef WITH_SS5
|
||||
if (mISDNport->ss5)
|
||||
port = ss5_hunt_line(mISDNport);
|
||||
else
|
||||
#endif
|
||||
if (!mISDNport->gsm)
|
||||
port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
|
||||
else
|
||||
|
|
|
@ -640,6 +640,8 @@ ac_includes_default="\
|
|||
ac_subst_vars='LTLIBOBJS
|
||||
POW_LIB
|
||||
LIBOBJS
|
||||
ENABLE_SS5_FALSE
|
||||
ENABLE_SS5_TRUE
|
||||
ENABLE_GSM_FALSE
|
||||
ENABLE_GSM_TRUE
|
||||
LIBCRYPTO
|
||||
|
@ -735,6 +737,7 @@ enable_dependency_tracking
|
|||
with_asterisk
|
||||
with_ssl
|
||||
with_gsm
|
||||
with_ss5
|
||||
'
|
||||
ac_precious_vars='build_alias
|
||||
host_alias
|
||||
|
@ -1385,7 +1388,9 @@ Optional Packages:
|
|||
|
||||
--with-ssl compile with ssl support (libcrypto) [default=check]
|
||||
|
||||
--with-gsm compile with OpenBSC support [default=no]
|
||||
--with-gsm compile with OpenBSC support [default=check]
|
||||
|
||||
--with-ss5 compile with CCITT No. 5 support [default=no]
|
||||
|
||||
|
||||
Some influential environment variables:
|
||||
|
@ -6316,6 +6321,27 @@ else
|
|||
fi
|
||||
|
||||
|
||||
# check for ss5
|
||||
|
||||
# Check whether --with-ss5 was given.
|
||||
if test "${with_ss5+set}" = set; then
|
||||
withval=$with_ss5;
|
||||
else
|
||||
with_ss5="check"
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
if test "x$with_ss5" == "xyes" ; then
|
||||
ENABLE_SS5_TRUE=
|
||||
ENABLE_SS5_FALSE='#'
|
||||
else
|
||||
ENABLE_SS5_TRUE='#'
|
||||
ENABLE_SS5_FALSE=
|
||||
fi
|
||||
|
||||
|
||||
# Checks for libraries.
|
||||
|
||||
{ $as_echo "$as_me:$LINENO: checking for main in -lm" >&5
|
||||
|
@ -9826,6 +9852,13 @@ $as_echo "$as_me: error: conditional \"ENABLE_GSM\" was never defined.
|
|||
Usually this means the macro was only invoked conditionally." >&2;}
|
||||
{ (exit 1); exit 1; }; }
|
||||
fi
|
||||
if test -z "${ENABLE_SS5_TRUE}" && test -z "${ENABLE_SS5_FALSE}"; then
|
||||
{ { $as_echo "$as_me:$LINENO: error: conditional \"ENABLE_SS5\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." >&5
|
||||
$as_echo "$as_me: error: conditional \"ENABLE_SS5\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." >&2;}
|
||||
{ (exit 1); exit 1; }; }
|
||||
fi
|
||||
|
||||
: ${CONFIG_STATUS=./config.status}
|
||||
ac_write_fail=0
|
||||
|
|
12
configure.ac
12
configure.ac
|
@ -98,7 +98,7 @@ AS_IF([test "x$with_ssl" != xno],
|
|||
# check for gsm
|
||||
AC_ARG_WITH([gsm],
|
||||
[AS_HELP_STRING([--with-gsm],
|
||||
[compile with OpenBSC support @<:@default=no@:>@])
|
||||
[compile with OpenBSC support @<:@default=check@:>@])
|
||||
],
|
||||
[],
|
||||
[with_gsm="check"])
|
||||
|
@ -115,6 +115,16 @@ AS_IF([test "x$with_gsm" != xno],
|
|||
|
||||
AM_CONDITIONAL(ENABLE_GSM, test "x$with_gsm" == "xyes" )
|
||||
|
||||
# check for ss5
|
||||
AC_ARG_WITH([ss5],
|
||||
[AS_HELP_STRING([--with-ss5],
|
||||
[compile with CCITT No. 5 support @<:@default=no@:>@])
|
||||
],
|
||||
[],
|
||||
[with_ss5="check"])
|
||||
|
||||
AM_CONDITIONAL(ENABLE_SS5, test "x$with_ss5" == "xyes" )
|
||||
|
||||
# Checks for libraries.
|
||||
AC_CHECK_LIB([m], [main])
|
||||
AC_CHECK_LIB([ncurses], [main])
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#define DEBUG_PORT 0x0100
|
||||
#define DEBUG_ISDN 0x0110
|
||||
#define DEBUG_GSM 0x0120
|
||||
#define DEBUG_SS5 0x0130
|
||||
#define DEBUG_VBOX 0x0180
|
||||
#define DEBUG_EPOINT 0x0200
|
||||
#define DEBUG_JOIN 0x0400
|
||||
|
|
2
dss1.cpp
2
dss1.cpp
|
@ -1900,8 +1900,6 @@ void Pdss1::message_information(unsigned int epoint_id, int message_id, union pa
|
|||
}
|
||||
|
||||
|
||||
int newteid = 0;
|
||||
|
||||
/* MESSAGE_SETUP */
|
||||
void Pdss1::message_setup(unsigned int epoint_id, int message_id, union parameter *param)
|
||||
{
|
||||
|
|
2
ie.cpp
2
ie.cpp
|
@ -616,7 +616,7 @@ void Pdss1::enc_ie_cause(struct l3_msg *l3m, int location, int cause)
|
|||
unsigned char p[256];
|
||||
int l;
|
||||
|
||||
if (location<0 || location>7) {
|
||||
if (location<0 || location>10) {
|
||||
PERROR("location(%d) is out of range.\n", location);
|
||||
return;
|
||||
}
|
||||
|
|
74
interface.c
74
interface.c
|
@ -916,6 +916,56 @@ static int inter_gsm(struct interface *interface, char *filename, int line, char
|
|||
return(0);
|
||||
#endif
|
||||
}
|
||||
#ifdef WITH_SS5
|
||||
static int inter_ss5(struct interface *interface, char *filename, int line, char *parameter, char *value)
|
||||
{
|
||||
struct interface_port *ifport;
|
||||
char *element;
|
||||
|
||||
/* port in chain ? */
|
||||
if (!interface->ifport) {
|
||||
SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
|
||||
return(-1);
|
||||
}
|
||||
/* goto end of chain */
|
||||
ifport = interface->ifport;
|
||||
while(ifport->next)
|
||||
ifport = ifport->next;
|
||||
ifport->ss5 |= SS5_ENABLE;
|
||||
while((element = strsep(&value, " "))) {
|
||||
if (element[0] == '\0')
|
||||
continue;
|
||||
if (!strcasecmp(element, "connect"))
|
||||
ifport->ss5 |= SS5_FEATURE_CONNECT;
|
||||
else
|
||||
if (!strcasecmp(element, "nodisconnect"))
|
||||
ifport->ss5 |= SS5_FEATURE_NODISCONNECT;
|
||||
else
|
||||
if (!strcasecmp(element, "releaseguardtimer"))
|
||||
ifport->ss5 |= SS5_FEATURE_RELEASEGUARDTIMER;
|
||||
else
|
||||
if (!strcasecmp(element, "bell"))
|
||||
ifport->ss5 |= SS5_FEATURE_BELL;
|
||||
else
|
||||
if (!strcasecmp(element, "pulsedialing"))
|
||||
ifport->ss5 |= SS5_FEATURE_PULSEDIALING;
|
||||
else
|
||||
if (!strcasecmp(element, "delay"))
|
||||
ifport->ss5 |= SS5_FEATURE_DELAY;
|
||||
else
|
||||
if (!strcasecmp(element, "starrelease"))
|
||||
ifport->ss5 |= SS5_FEATURE_STAR_RELEASE;
|
||||
else
|
||||
if (!strcasecmp(element, "suppress"))
|
||||
ifport->ss5 |= SS5_FEATURE_SUPPRESS;
|
||||
else {
|
||||
SPRINT(interface_error, "Error in %s (line %d): parameter '%s' does not allow value element '%s'.\n", filename, line, parameter, element);
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
|
@ -1049,6 +1099,22 @@ struct interface_param interface_param[] = {
|
|||
"This interface must be a loopback interface. The second loopback interface\n"
|
||||
"must be assigned to OpenBSC"},
|
||||
|
||||
#ifdef WITH_SS5
|
||||
{"ccitt5", &inter_ss5, "[<feature> [feature ...]]",
|
||||
"Interface uses CCITT No. 5 inband signalling rather than D-channel.\n"
|
||||
"This feature causes CPU load to rise and has no practical intend.\n"
|
||||
"If you don't know what it is, you don't need it.\n"
|
||||
"Features apply to protocol behaviour and blueboxing specials, they are:\n"
|
||||
" connect - Connect incomming call to throughconnect audio, if required.\n"
|
||||
" nodisconnect - Don't disconnect if incomming exchange disconnects.\n"
|
||||
" releaseguardtimer - Tries to prevent Blueboxing by a longer release-guard.\n"
|
||||
" bell - Allow releasing and pulse-dialing via 2600 Hz like old Bell systems.\n"
|
||||
" pulsedialing - Use pulse dialing on outgoing exchange. (takes long!)\n"
|
||||
" delay - Use on incomming exchange, to make you feel a delay when blueboxing.\n"
|
||||
" starrelease - Pulse dialing a star (11 pulses per digit) clears current call.\n"
|
||||
" suppress - Suppress received tones, as they will be recognized."},
|
||||
#endif
|
||||
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
@ -1275,12 +1341,12 @@ static void set_defaults(struct interface_port *ifport)
|
|||
if (ifport->interface->is_tones)
|
||||
ifport->mISDNport->tones = (ifport->interface->is_tones==IS_YES);
|
||||
else
|
||||
ifport->mISDNport->tones = (ifport->mISDNport->ntmode)?1:0;
|
||||
ifport->mISDNport->tones = (ifport->mISDNport->ntmode || ifport->mISDNport->ss5)?1:0;
|
||||
/* default is_earlyb */
|
||||
if (ifport->interface->is_earlyb)
|
||||
ifport->mISDNport->earlyb = (ifport->interface->is_earlyb==IS_YES);
|
||||
else
|
||||
ifport->mISDNport->earlyb = (ifport->mISDNport->ntmode)?0:1;
|
||||
ifport->mISDNport->earlyb = (ifport->mISDNport->ntmode && !ifport->mISDNport->ss5)?0:1;
|
||||
/* set locally flag */
|
||||
if (ifport->interface->extension)
|
||||
ifport->mISDNport->locally = 1;
|
||||
|
@ -1366,7 +1432,7 @@ void load_port(struct interface_port *ifport)
|
|||
struct mISDNport *mISDNport;
|
||||
|
||||
/* open new port */
|
||||
mISDNport = mISDNport_open(ifport->portnum, ifport->portname, ifport->ptp, ifport->nt, ifport->tespecial, ifport->l1hold, ifport->l2hold, ifport->interface, ifport->gsm);
|
||||
mISDNport = mISDNport_open(ifport->portnum, ifport->portname, ifport->ptp, ifport->nt, ifport->tespecial, ifport->l1hold, ifport->l2hold, ifport->interface, ifport->gsm, ifport->ss5);
|
||||
if (mISDNport) {
|
||||
/* link port */
|
||||
ifport->mISDNport = mISDNport;
|
||||
|
@ -1376,6 +1442,8 @@ void load_port(struct interface_port *ifport)
|
|||
SCPY(ifport->portname, mISDNport->name);
|
||||
/* set defaults */
|
||||
set_defaults(ifport);
|
||||
/* load static port instances */
|
||||
mISDNport_static(mISDNport);
|
||||
} else {
|
||||
ifport->block = 2; /* not available */
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ struct interface_port {
|
|||
int l1hold; /* hold layer 1 (1=on, 0=off) */
|
||||
int l2hold; /* hold layer 2 (1=force, -1=disable, 0=default) */
|
||||
int gsm; /* interface is an GSM interface */
|
||||
unsigned int ss5; /* set, if SS5 signalling enabled, also holds feature bits */
|
||||
int channel_force; /* forces channel by protocol */
|
||||
int nodtmf; /* disables DTMF */
|
||||
struct select_channel *out_channel; /* list of channels to select */
|
||||
|
|
|
@ -179,6 +179,10 @@ int debug_port(struct admin_message *msg, struct admin_message *m, int line, int
|
|||
color(blue);
|
||||
addstr("'out >> disc'");
|
||||
break;
|
||||
case ADMIN_STATE_RELEASE:
|
||||
color(blue);
|
||||
addstr("'release'");
|
||||
break;
|
||||
default:
|
||||
color(blue);
|
||||
addstr("'--NONE--'");
|
||||
|
@ -729,7 +733,7 @@ const char *admin_state(int sock, char *argv[])
|
|||
break;
|
||||
case B_STATE_ACTIVE:
|
||||
color(green);
|
||||
addstr("busy ");
|
||||
addstr("active ");
|
||||
break;
|
||||
case B_STATE_DEACTIVATING:
|
||||
color(yellow);
|
||||
|
|
|
@ -188,4 +188,5 @@ enum {
|
|||
ADMIN_STATE_CONNECT,
|
||||
ADMIN_STATE_IN_DISCONNECT,
|
||||
ADMIN_STATE_OUT_DISCONNECT,
|
||||
ADMIN_STATE_RELEASE,
|
||||
};
|
||||
|
|
152
mISDN.cpp
152
mISDN.cpp
|
@ -108,12 +108,15 @@ PmISDN::PmISDN(int type, mISDNport *mISDNport, char *portname, struct port_setti
|
|||
p_m_tx_gain = mISDNport->ifport->interface->tx_gain;
|
||||
p_m_rx_gain = mISDNport->ifport->interface->rx_gain;
|
||||
p_m_conf = 0;
|
||||
p_m_mute = 0;
|
||||
p_m_txdata = 0;
|
||||
p_m_delay = 0;
|
||||
p_m_echo = 0;
|
||||
p_m_tone = 0;
|
||||
p_m_rxoff = 0;
|
||||
p_m_joindata = 0;
|
||||
p_m_inband_send_on = 0;
|
||||
p_m_inband_receive_on = 0;
|
||||
p_m_dtmf = !mISDNport->ifport->nodtmf;
|
||||
p_m_timeout = 0;
|
||||
p_m_timer = 0;
|
||||
|
@ -159,6 +162,7 @@ PmISDN::PmISDN(int type, mISDNport *mISDNport, char *portname, struct port_setti
|
|||
/* we increase the number of objects: */
|
||||
mISDNport->use++;
|
||||
PDEBUG(DEBUG_ISDN, "Created new mISDNPort(%s). Currently %d objects use, port #%d\n", portname, mISDNport->use, p_m_portnum);
|
||||
//inband_receive_on();
|
||||
}
|
||||
|
||||
|
||||
|
@ -464,7 +468,7 @@ static void _bchannel_configure(struct mISDNport *mISDNport, int i)
|
|||
ph_control(mISDNport, port, handle, DSP_VOL_CHANGE_RX, port->p_m_rx_gain, "DSP-RX_GAIN", port->p_m_rx_gain);
|
||||
if (port->p_m_pipeline[0] && mode == B_MODE_TRANSPARENT)
|
||||
ph_control_block(mISDNport, port, handle, DSP_PIPELINE_CFG, port->p_m_pipeline, strlen(port->p_m_pipeline)+1, "DSP-PIPELINE", 0);
|
||||
if (port->p_m_conf)
|
||||
if (port->p_m_conf && !port->p_m_mute)
|
||||
ph_control(mISDNport, port, handle, DSP_CONF_JOIN, port->p_m_conf, "DSP-CONF", port->p_m_conf);
|
||||
if (port->p_m_echo)
|
||||
ph_control(mISDNport, port, handle, DSP_ECHO_ON, 0, "DSP-ECHO", 1);
|
||||
|
@ -480,6 +484,19 @@ static void _bchannel_configure(struct mISDNport *mISDNport, int i)
|
|||
ph_control_block(mISDNport, port, handle, DSP_BF_ENABLE_KEY, port->p_m_crypt_key, port->p_m_crypt_key_len, "DSP-CRYPT", port->p_m_crypt_key_len);
|
||||
}
|
||||
|
||||
|
||||
void PmISDN::set_conf(int oldconf, int newconf)
|
||||
{
|
||||
if (oldconf != newconf) {
|
||||
PDEBUG(DEBUG_BCHANNEL, "we change conference from conf=%d to conf=%d.\n", oldconf, newconf);
|
||||
if (p_m_b_index > -1)
|
||||
if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
|
||||
ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], (newconf)?DSP_CONF_JOIN:DSP_CONF_SPLIT, newconf, "DSP-CONF", newconf);
|
||||
} else
|
||||
PDEBUG(DEBUG_BCHANNEL, "we already have conf=%d.\n", newconf);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* subfunction for bchannel_event
|
||||
* destroy stack
|
||||
|
@ -1218,15 +1235,20 @@ int PmISDN::handler(void)
|
|||
else
|
||||
p_m_load = 0;
|
||||
|
||||
/* to send data, tone must be active OR crypt messages must be on */
|
||||
if ((p_tone_name[0] || p_m_crypt_msg_loops)
|
||||
&& (p_m_load < ISDN_LOAD)
|
||||
&& (p_state==PORT_STATE_CONNECT || p_m_mISDNport->tones)) {
|
||||
/* to send data, tone must be on */
|
||||
if ((p_tone_name[0] || p_m_crypt_msg_loops || p_m_inband_send_on) /* what tones? */
|
||||
&& (p_m_load < ISDN_LOAD) /* enough load? */
|
||||
&& (p_state==PORT_STATE_CONNECT || p_m_mISDNport->tones || p_m_inband_send_on)) { /* connected or inband-tones? */
|
||||
int tosend = ISDN_LOAD - p_m_load, length;
|
||||
unsigned char buf[MISDN_HEADER_LEN+tosend];
|
||||
struct mISDNhead *frm = (struct mISDNhead *)buf;
|
||||
unsigned char *p = buf+MISDN_HEADER_LEN;
|
||||
|
||||
/* copy inband signalling (e.g. used by ss5) */
|
||||
if (p_m_inband_send_on && tosend) {
|
||||
tosend -= inband_send(p, tosend);
|
||||
}
|
||||
|
||||
/* copy crypto loops */
|
||||
while (p_m_crypt_msg_loops && tosend) {
|
||||
/* how much do we have to send */
|
||||
|
@ -1372,6 +1394,10 @@ void PmISDN::bchannel_receive(struct mISDNhead *hh, unsigned char *data, int len
|
|||
return;
|
||||
}
|
||||
|
||||
/* inband is processed */
|
||||
if (p_m_inband_receive_on)
|
||||
inband_receive(data, len);
|
||||
|
||||
/* calls will not process any audio data unless
|
||||
* the call is connected OR tones feature is enabled.
|
||||
*/
|
||||
|
@ -1566,6 +1592,7 @@ void PmISDN::set_tone(const char *dir, const char *tone)
|
|||
//extern struct lcr_msg *dddebug;
|
||||
void PmISDN::message_mISDNsignal(unsigned int epoint_id, int message_id, union parameter *param)
|
||||
{
|
||||
int oldconf, newconf;
|
||||
switch(param->mISDNsignal.message) {
|
||||
case mISDNSIGNAL_VOLUME:
|
||||
if (p_m_tx_gain != param->mISDNsignal.tx_gain) {
|
||||
|
@ -1587,19 +1614,10 @@ void PmISDN::message_mISDNsignal(unsigned int epoint_id, int message_id, union p
|
|||
break;
|
||||
|
||||
case mISDNSIGNAL_CONF:
|
||||
//if (dddebug) PDEBUG(DEBUG_ISDN, "dddebug = %d\n", dddebug->type);
|
||||
//tone if (!p_m_tone && p_m_conf!=param->mISDNsignal.conf)
|
||||
if (p_m_conf != param->mISDNsignal.conf) {
|
||||
p_m_conf = param->mISDNsignal.conf;
|
||||
PDEBUG(DEBUG_BCHANNEL, "we change conference to conf=%d.\n", p_m_conf);
|
||||
if (p_m_b_index > -1)
|
||||
if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
|
||||
ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], (p_m_conf)?DSP_CONF_JOIN:DSP_CONF_SPLIT, p_m_conf, "DSP-CONF", p_m_conf);
|
||||
} else
|
||||
PDEBUG(DEBUG_BCHANNEL, "we already have conf=%d.\n", p_m_conf);
|
||||
/* we must set, even if currently tone forbids conf */
|
||||
oldconf = p_m_mute?0:p_m_conf;
|
||||
p_m_conf = param->mISDNsignal.conf;
|
||||
//if (dddebug) PDEBUG(DEBUG_ISDN, "dddebug = %d\n", dddebug->type);
|
||||
newconf = p_m_mute?0:p_m_conf;
|
||||
set_conf(oldconf, newconf);
|
||||
break;
|
||||
|
||||
case mISDNSIGNAL_JOINDATA:
|
||||
|
@ -1744,7 +1762,7 @@ int mISDN_handler(void)
|
|||
isdnport=mISDNport->b_port[i];
|
||||
if (isdnport) {
|
||||
/* call bridges in user space OR crypto OR recording */
|
||||
if (isdnport->p_m_joindata || isdnport->p_m_crypt_msg_loops || isdnport->p_m_crypt_listen || isdnport->p_record) {
|
||||
if (isdnport->p_m_joindata || isdnport->p_m_crypt_msg_loops || isdnport->p_m_crypt_listen || isdnport->p_record || isdnport->p_m_inband_receive_on) {
|
||||
/* rx IS required */
|
||||
if (isdnport->p_m_rxoff) {
|
||||
/* turn on RX */
|
||||
|
@ -1947,7 +1965,7 @@ int mISDN_handler(void)
|
|||
mISDNport->l2establish = 0;
|
||||
if (!mISDNport->gsm && mISDNport->l2hold && (mISDNport->ptp || !mISDNport->ntmode)) {
|
||||
|
||||
PDEBUG(DEBUG_ISDN, "the L2 establish timer expired, we try to establish the link portnum=%d.\n", mISDNport->portnum);
|
||||
// PDEBUG(DEBUG_ISDN, "the L2 establish timer expired, we try to establish the link portnum=%d.\n", mISDNport->portnum);
|
||||
mISDNport->ml3->to_layer3(mISDNport->ml3, MT_L2ESTABLISH, 0, NULL);
|
||||
time(&mISDNport->l2establish);
|
||||
return(1);
|
||||
|
@ -2027,7 +2045,7 @@ int mISDN_getportbyname(int sock, int cnt, char *portname)
|
|||
/*
|
||||
* global function to add a new card (port)
|
||||
*/
|
||||
struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt, int te_special, int l1hold, int l2hold, struct interface *interface, int gsm)
|
||||
struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt, int te_special, int l1hold, int l2hold, struct interface *interface, int gsm, unsigned int ss5)
|
||||
{
|
||||
int ret;
|
||||
struct mISDNport *mISDNport, **mISDNportp;
|
||||
|
@ -2168,8 +2186,8 @@ struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt
|
|||
while(*mISDNportp)
|
||||
mISDNportp = &((*mISDNportp)->next);
|
||||
mISDNport = (struct mISDNport *)MALLOC(sizeof(struct mISDNport));
|
||||
if (gsm) {
|
||||
/* gsm audio is always active */
|
||||
if (gsm | ss5) {
|
||||
/* gsm/ss5 link is always active */
|
||||
mISDNport->l1link = 1;
|
||||
mISDNport->l2link = 1;
|
||||
} else {
|
||||
|
@ -2183,7 +2201,13 @@ struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt
|
|||
/* if pri, must set PTP */
|
||||
if (pri)
|
||||
ptp = 1;
|
||||
|
||||
|
||||
/* set ss5 params */
|
||||
if (ss5) {
|
||||
/* try to keep interface enabled */
|
||||
l1hold = 1;
|
||||
l2hold = 1;
|
||||
}
|
||||
/* set l2hold */
|
||||
switch (l2hold) {
|
||||
case -1: // off
|
||||
|
@ -2273,6 +2297,7 @@ struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt
|
|||
mISDNport->ptp = ptp;
|
||||
mISDNport->l1hold = l1hold;
|
||||
mISDNport->l2hold = l2hold;
|
||||
mISDNport->ss5 = ss5;
|
||||
PDEBUG(DEBUG_ISDN, "Port has %d b-channels.\n", mISDNport->b_num);
|
||||
i = 0;
|
||||
while(i < mISDNport->b_num) {
|
||||
|
@ -2306,11 +2331,32 @@ struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt
|
|||
"PORT (open)");
|
||||
add_trace("mode", NULL, (mISDNport->ntmode)?"network":"terminal");
|
||||
add_trace("channels", NULL, "%d", mISDNport->b_num);
|
||||
if (mISDNport->ss5)
|
||||
add_trace("ccitt#5", NULL, "enabled");
|
||||
end_trace();
|
||||
|
||||
return(mISDNport);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* load static port instances, if required by mISDNport
|
||||
*/
|
||||
void mISDNport_static(struct mISDNport *mISDNport)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
while(i < mISDNport->b_num) {
|
||||
#ifdef WITH_SS5
|
||||
if (mISDNport->ss5)
|
||||
ss5_create_channel(mISDNport, i);
|
||||
#endif
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* function to free ALL cards (ports)
|
||||
*/
|
||||
|
@ -2418,7 +2464,7 @@ void PmISDN::txfromup(unsigned char *data, int length)
|
|||
/* check if high priority tones exist
|
||||
* ignore data in this case
|
||||
*/
|
||||
if (p_tone_name[0] || p_m_crypt_msg_loops)
|
||||
if (p_tone_name[0] || p_m_crypt_msg_loops || p_m_inband_send_on)
|
||||
return;
|
||||
|
||||
/* preload procedure
|
||||
|
@ -2451,3 +2497,61 @@ void PmISDN::txfromup(unsigned char *data, int length)
|
|||
p_m_load += length;
|
||||
}
|
||||
|
||||
int PmISDN::inband_send(unsigned char *buffer, int len)
|
||||
{
|
||||
PERROR("this function must be derived to function!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PmISDN::inband_send_on(void)
|
||||
{
|
||||
PDEBUG(DEBUG_PORT, "turning inband signalling send on.\n");
|
||||
p_m_inband_send_on = 1;
|
||||
}
|
||||
|
||||
void PmISDN::inband_send_off(void)
|
||||
{
|
||||
PDEBUG(DEBUG_PORT, "turning inband signalling send off.\n");
|
||||
p_m_inband_send_on = 0;
|
||||
}
|
||||
|
||||
void PmISDN::inband_receive(unsigned char *buffer, int len)
|
||||
{
|
||||
//
|
||||
// if (len >= SS5_DECODER_NPOINTS)
|
||||
// ss5_decode(buffer, SS5_DECODER_NPOINTS);
|
||||
PERROR("this function must be derived to function!\n");
|
||||
}
|
||||
|
||||
void PmISDN::inband_receive_on(void)
|
||||
{
|
||||
/* this must work during constructor, see ss5.cpp */
|
||||
PDEBUG(DEBUG_PORT, "turning inband signalling receive on.\n");
|
||||
p_m_inband_receive_on = 1;
|
||||
}
|
||||
|
||||
void PmISDN::inband_receive_off(void)
|
||||
{
|
||||
PDEBUG(DEBUG_PORT, "turning inband signalling receive off.\n");
|
||||
p_m_inband_receive_on = 0;
|
||||
}
|
||||
|
||||
void PmISDN::mute_on(void)
|
||||
{
|
||||
if (p_m_mute)
|
||||
return;
|
||||
PDEBUG(DEBUG_PORT, "turning mute on.\n");
|
||||
p_m_mute = 1;
|
||||
set_conf(p_m_conf, 0);
|
||||
}
|
||||
|
||||
void PmISDN::mute_off(void)
|
||||
{
|
||||
if (!p_m_mute)
|
||||
return;
|
||||
PDEBUG(DEBUG_PORT, "turning mute off.\n");
|
||||
p_m_mute = 0;
|
||||
set_conf(0, p_m_conf);
|
||||
}
|
||||
|
||||
|
||||
|
|
20
mISDN.h
20
mISDN.h
|
@ -67,6 +67,9 @@ struct mISDNport {
|
|||
/* gsm */
|
||||
int gsm; /* this is the (only) GSM interface */
|
||||
int lcr_sock; /* socket of loopback on LCR side */
|
||||
|
||||
/* ss5 */
|
||||
unsigned int ss5; /* set, if SS5 signalling enabled, also holds feature bits */
|
||||
};
|
||||
extern mISDNport *mISDNport_first;
|
||||
|
||||
|
@ -89,7 +92,8 @@ calls with no bchannel (call waiting, call on hold).
|
|||
int mISDN_initialize(void);
|
||||
void mISDN_deinitialize(void);
|
||||
int mISDN_getportbyname(int sock, int cnt, char *portname);
|
||||
struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt, int te_special, int l1hold, int l2hold, struct interface *interface, int gsm);
|
||||
struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt, int te_special, int l1hold, int l2hold, struct interface *interface, int gsm, unsigned int ss5);
|
||||
void mISDNport_static(struct mISDNport *mISDNport);
|
||||
void mISDNport_close_all(void);
|
||||
void mISDNport_close(struct mISDNport *mISDNport);
|
||||
void mISDN_port_reorder(void);
|
||||
|
@ -121,6 +125,7 @@ class PmISDN : public Port
|
|||
int p_m_tx_gain, p_m_rx_gain; /* volume shift (0 = no change) */
|
||||
char p_m_pipeline[256]; /* filter pipeline */
|
||||
int p_m_echo, p_m_conf; /* remote echo, conference number */
|
||||
int p_m_mute; /* if set, conf is disconnected */
|
||||
int p_m_tone; /* current kernel space tone */
|
||||
int p_m_rxoff; /* rx from driver is disabled */
|
||||
// int p_m_nodata; /* all parties within a conf are isdn ports, so pure bridging is possible */
|
||||
|
@ -152,6 +157,7 @@ class PmISDN : public Port
|
|||
|
||||
void set_tone(const char *dir, const char *name);
|
||||
void set_echotest(int echotest);
|
||||
void set_conf(int oldconf, int newconf);
|
||||
|
||||
int p_m_portnum; /* used port number (1...n) */
|
||||
int p_m_b_index; /* index 0,1 0..29 */
|
||||
|
@ -168,6 +174,18 @@ class PmISDN : public Port
|
|||
unsigned int p_m_remote_ref; /* join to export bchannel to */
|
||||
int p_m_remote_id; /* sock to export bchannel to */
|
||||
|
||||
int p_m_inband_send_on; /* triggers optional send function */
|
||||
int p_m_inband_receive_on; /* triggers optional receive function */
|
||||
int p_m_mute_on; /* if mute is on, bridge is removed */
|
||||
virtual int inband_send(unsigned char *buffer, int len);
|
||||
void inband_send_on(void);
|
||||
void inband_send_off(void);
|
||||
virtual void inband_receive(unsigned char *buffer, int len);
|
||||
void inband_receive_on(void);
|
||||
void inband_receive_off(void);
|
||||
void mute_on(void);
|
||||
void mute_off(void);
|
||||
|
||||
int seize_bchannel(int channel, int exclusive); /* requests / reserves / links bchannels, but does not open it! */
|
||||
void drop_bchannel(void);
|
||||
};
|
||||
|
|
6
main.c
6
main.c
|
@ -360,6 +360,12 @@ int main(int argc, char *argv[])
|
|||
/* generate alaw / ulaw tables */
|
||||
generate_tables(options.law);
|
||||
|
||||
#ifdef WITH_SS5
|
||||
/* init ss5 sine tables */
|
||||
ss5_sine_generate();
|
||||
ss5_test_decode();
|
||||
#endif
|
||||
|
||||
/* load tones (if requested) */
|
||||
if (fetch_tones() == 0) {
|
||||
fprintf(stderr, "Unable to fetch tones into memory.\n");
|
||||
|
|
6
main.h
6
main.h
|
@ -68,6 +68,7 @@ void debug(const char *function, int line, const char *prefix, char *buffer);
|
|||
#define DEBUG_PORT 0x0100
|
||||
#define DEBUG_ISDN 0x0110
|
||||
#define DEBUG_GSM 0x0120
|
||||
#define DEBUG_SS5 0x0130
|
||||
//#define DEBUG_KNOCK 0x0140
|
||||
#define DEBUG_VBOX 0x0180
|
||||
#define DEBUG_EPOINT 0x0200
|
||||
|
@ -151,6 +152,11 @@ extern "C" {
|
|||
#ifdef WITH_GSM
|
||||
#include "gsm.h"
|
||||
#endif
|
||||
#ifdef WITH_SS5
|
||||
#include "ss5_encode.h"
|
||||
#include "ss5_decode.h"
|
||||
#include "ss5.h"
|
||||
#endif
|
||||
#include "vbox.h"
|
||||
#include "join.h"
|
||||
#include "joinpbx.h"
|
||||
|
|
5
port.h
5
port.h
|
@ -18,6 +18,7 @@
|
|||
#define PORT_CLASS_MASK 0xff00
|
||||
#define PORT_CLASS_mISDN_DSS1 0x0110
|
||||
#define PORT_CLASS_mISDN_GSM 0x0120
|
||||
#define PORT_CLASS_mISDN_SS5 0x0130
|
||||
#define PORT_CLASS_mISDN_MASK 0xfff0
|
||||
/* nt-mode */
|
||||
#define PORT_TYPE_DSS1_NT_IN 0x0111
|
||||
|
@ -28,6 +29,10 @@
|
|||
/* gsm */
|
||||
#define PORT_TYPE_GSM_IN 0x0121
|
||||
#define PORT_TYPE_GSM_OUT 0x0122
|
||||
/* ss5 */
|
||||
#define PORT_TYPE_SS5_IN 0x0131
|
||||
#define PORT_TYPE_SS5_OUT 0x0132
|
||||
#define PORT_TYPE_SS5_IDLE 0x0133
|
||||
/* answering machine */
|
||||
#define PORT_TYPE_VBOX_OUT 0x0311
|
||||
|
||||
|
|
|
@ -1035,6 +1035,9 @@ int admin_state(struct admin_queue **responsep)
|
|||
case PORT_STATE_OUT_DISCONNECT:
|
||||
response->am[num].u.p.state = ADMIN_STATE_OUT_DISCONNECT;
|
||||
break;
|
||||
case PORT_STATE_RELEASE:
|
||||
response->am[num].u.p.state = ADMIN_STATE_RELEASE;
|
||||
break;
|
||||
default:
|
||||
response->am[num].u.p.state = ADMIN_STATE_IDLE;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
/*****************************************************************************\
|
||||
** **
|
||||
** LCR **
|
||||
** **
|
||||
**---------------------------------------------------------------------------**
|
||||
** Copyright: Andreas Eversberg **
|
||||
** **
|
||||
** ss5-port header file **
|
||||
** **
|
||||
\*****************************************************************************/
|
||||
|
||||
#define SS5_ENABLE 0x00000001
|
||||
#define SS5_FEATURE_CONNECT 0x00000002
|
||||
#define SS5_FEATURE_NODISCONNECT 0x00000004
|
||||
#define SS5_FEATURE_RELEASEGUARDTIMER 0x00000008
|
||||
#define SS5_FEATURE_BELL 0x00000010
|
||||
#define SS5_FEATURE_PULSEDIALING 0x00000020
|
||||
#define SS5_FEATURE_DELAY 0x00000040
|
||||
#define SS5_FEATURE_STAR_RELEASE 0x00000080
|
||||
#define SS5_FEATURE_SUPPRESS 0x00000100
|
||||
|
||||
/* SS5 port classes */
|
||||
class Pss5 : public PmISDN
|
||||
{
|
||||
public:
|
||||
Pss5(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode);
|
||||
~Pss5();
|
||||
int handler(void);
|
||||
int message_epoint(unsigned int epoint_id, int message, union parameter *param);
|
||||
void set_tone(const char *dir, const char *name);
|
||||
|
||||
int p_m_s_state; /* current signalling state */
|
||||
int p_m_s_signal; /* current state of current signal */
|
||||
char p_m_s_dial[64]; /* current dialing register */
|
||||
int p_m_s_digit_i; /* current digit of register counter */
|
||||
int p_m_s_pulsecount; /* counts pule dialing half cycles */
|
||||
char p_m_s_last_digit; /* stores last digit to fill short signal losses */
|
||||
int p_m_s_signal_loss; /* sample counter for loss of signal check */
|
||||
int p_m_s_decoder_count; /* samples currently decoded */
|
||||
unsigned char p_m_s_decoder_buffer[SS5_DECODER_NPOINTS]; /* buffer for storing one goertzel window */
|
||||
unsigned char p_m_s_delay_digits[3000/SS5_DECODER_NPOINTS]; /* delay buffer for received digits */
|
||||
unsigned char p_m_s_delay_mute[400/SS5_DECODER_NPOINTS]; /* 40 ms delay on mute, so a 'chirp' can be heared */
|
||||
int p_m_s_sample_nr; /* decoder's sample number, counter */
|
||||
int p_m_s_recog; /* sample counter to wait for signal recognition time */
|
||||
double p_m_s_timer;
|
||||
void (Pss5::*p_m_s_timer_fn)(void);
|
||||
int p_m_s_answer; /* queued signal */
|
||||
int p_m_s_busy_flash; /* queued signal */
|
||||
int p_m_s_clear_back; /* queued signal */
|
||||
|
||||
void _new_ss5_state(int state, const char *func, int line);
|
||||
void _new_ss5_signal(int signal, const char *func, int line);
|
||||
void inband_receive(unsigned char *buffer, int len);
|
||||
int inband_send(unsigned char *buffer, int len);
|
||||
int inband_dial_mf(unsigned char *buffer, int len, int count);
|
||||
int inband_dial_pulse(unsigned char *buffer, int len, int count);
|
||||
void start_signal(int);
|
||||
void start_outgoing(void);
|
||||
void do_release(int cause, int location);
|
||||
void do_setup(char *digit);
|
||||
|
||||
void seizing_ind(void);
|
||||
void digit_ind(char digit);
|
||||
void pulse_ind(int on);
|
||||
void proceed_to_send_ind(void);
|
||||
void busy_flash_ind(void);
|
||||
void answer_ind(void);
|
||||
void forward_ind(void);
|
||||
void clear_back_ind(void);
|
||||
void clear_forward_ind(void);
|
||||
void release_guard_ind(void);
|
||||
void double_seizure_ind(void);
|
||||
void forward_transfer_ind(void);
|
||||
void message_setup(unsigned int epoint_id, int message_id, union parameter *param);
|
||||
void message_connect(unsigned int epoint_id, int message_id, union parameter *param);
|
||||
void message_disconnect(unsigned int epoint_id, int message_id, union parameter *param);
|
||||
void message_release(unsigned int epoint_id, int message_id, union parameter *param);
|
||||
|
||||
};
|
||||
|
||||
#define new_ss5_state(a) _new_ss5_state(a, __FUNCTION__, __LINE__)
|
||||
#define new_ss5_signal(a) _new_ss5_signal(a, __FUNCTION__, __LINE__)
|
||||
|
||||
void ss5_create_channel(struct mISDNport *mISDNport, int i);
|
||||
class Pss5 *ss5_hunt_line(struct mISDNport *mISDNport);
|
||||
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* SS5 signal decoder.
|
||||
*
|
||||
* Copyright by Andreas Eversberg (jolly@eversberg.eu)
|
||||
* based on different decoders such as ISDN4Linux
|
||||
* copyright by Karsten Keil
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
#include "ss5_decode.h"
|
||||
|
||||
/* enable level debugging */
|
||||
//#define DEBUG_LEVELS
|
||||
|
||||
#define NCOEFF 8 /* number of frequencies to be analyzed */
|
||||
|
||||
#define MIN_DB 0.01995262 /* -17 db */
|
||||
#define DIFF_DB 0.31622777 /* -5 db */
|
||||
#define SNR 1.3 /* noise may not exceed signal by that factor */
|
||||
|
||||
/* For DTMF recognition:
|
||||
* 2 * cos(2 * PI * k / N) precalculated for all k
|
||||
*/
|
||||
static signed long long cos2pik[NCOEFF] =
|
||||
{
|
||||
/* k = 2*cos(2*PI*f/8000), k << 15
|
||||
* 700, 900, 1100, 1300, 1500, 1700, 2400, 2600 */
|
||||
55879, 49834, 42562, 34242, 25080, 15299, -20252, -29753
|
||||
};
|
||||
|
||||
/* detection matrix for two frequencies */
|
||||
static char decode_two[8][8] =
|
||||
{
|
||||
{' ', '1', '2', '4', '7', '*', ' ', ' '}, /* * = code 11 */
|
||||
{'1', ' ', '3', '5', '8', '#', ' ', ' '}, /* # = code 12 */
|
||||
{'2', '3', ' ', '6', '9', 'a', ' ', ' '}, /* a = KP1 */
|
||||
{'4', '5', '6', ' ', '0', 'b', ' ', ' '}, /* b = KP2 */
|
||||
{'7', '8', '9', '0', ' ', 'c', ' ', ' '}, /* c = ST */
|
||||
{'*', '#', 'a', 'b', 'c', ' ', ' ', ' '},
|
||||
{' ', ' ', ' ', ' ', ' ', ' ', ' ', 'C'}, /* C = 2600+2400 */
|
||||
{' ', ' ', ' ', ' ', ' ', ' ', 'C', ' '}
|
||||
};
|
||||
|
||||
static char decode_one[8] =
|
||||
{' ', ' ', ' ', ' ', ' ', ' ', 'A', 'B'}; /* A = 2400, B = 2600 */
|
||||
/*
|
||||
* calculate the coefficients of the given sample and decode
|
||||
*/
|
||||
|
||||
char ss5_decode(unsigned char *data, int len)
|
||||
{
|
||||
signed short buf[len];
|
||||
signed long sk, sk1, sk2, low, high;
|
||||
int k, n, i;
|
||||
int f1 = 0, f2 = 0, f3 = 0;
|
||||
double result[NCOEFF], power, noise, snr;
|
||||
signed long long cos2pik_;
|
||||
char digit = ' ';
|
||||
|
||||
/* convert samples */
|
||||
for (i = 0; i < len; i++)
|
||||
buf[i] = audio_law_to_s32[*data++];
|
||||
|
||||
/* now we have a full buffer of signed long samples - we do goertzel */
|
||||
for (k = 0; k < NCOEFF; k++) {
|
||||
sk = 0;
|
||||
sk1 = 0;
|
||||
sk2 = 0;
|
||||
cos2pik_ = cos2pik[k];
|
||||
for (n = 0; n < len; n++) {
|
||||
sk = ((cos2pik_*sk1)>>15) - sk2 + buf[n];
|
||||
sk2 = sk1;
|
||||
sk1 = sk;
|
||||
}
|
||||
sk >>= 8;
|
||||
sk2 >>= 8;
|
||||
if (sk > 32767 || sk < -32767 || sk2 > 32767 || sk2 < -32767)
|
||||
PERROR("Tone-Detection overflow\n");
|
||||
/* compute |X(k)|**2 */
|
||||
result[k] = sqrt (
|
||||
(sk * sk) -
|
||||
(((cos2pik[k] * sk) >> 15) * sk2) +
|
||||
(sk2 * sk2)
|
||||
) / len / 62; /* level of 1 is 0 db*/
|
||||
}
|
||||
|
||||
/* now we do noise level calculation */
|
||||
low = 32767;
|
||||
high = -32768;
|
||||
for (n = 0; n < len; n++) {
|
||||
sk = buf[n];
|
||||
if (sk < low)
|
||||
low = sk;
|
||||
if (sk > high)
|
||||
high = sk;
|
||||
}
|
||||
noise = ((double)(high-low) / 65536.0);
|
||||
|
||||
/* find the two loudest frequencies + one less lower frequency to detect noise */
|
||||
power = 0.0;
|
||||
for (i = 0; i < NCOEFF; i++) {
|
||||
if (result[i] > power) {
|
||||
power = result[i];
|
||||
f1 = i;
|
||||
}
|
||||
}
|
||||
power = 0.0;
|
||||
for (i = 0; i < NCOEFF; i++) {
|
||||
if (i != f1 && result[i] > power) {
|
||||
power = result[i];
|
||||
f2 = i;
|
||||
}
|
||||
}
|
||||
power = 0.0;
|
||||
for (i = 0; i < NCOEFF; i++) {
|
||||
if (i != f1 && i != f2 && result[i] > power) {
|
||||
power = result[i];
|
||||
f3 = i;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* check one frequency */
|
||||
if (result[f1] > MIN_DB /* must be at least -17 db */
|
||||
&& result[f1]*DIFF_DB > result[f2]) /* must be 5 db above other tones */
|
||||
digit = decode_one[f1];
|
||||
/* check two frequencies */
|
||||
if (result[f1] > MIN_DB && result[f2] > MIN_DB /* must be at lease -17 db */
|
||||
&& result[f1]*DIFF_DB <= result[f2] /* f2 must be not less than 5 db below f1 */
|
||||
&& result[f1]*DIFF_DB > result[f3]) /* f1 must be 5 db above other tones */
|
||||
digit = decode_two[f1][f2];
|
||||
#endif
|
||||
snr = 0;
|
||||
/* check one frequency */
|
||||
if (result[f1] > MIN_DB /* must be at least -17 db */
|
||||
&& result[f1]*SNR > noise) { /* */
|
||||
digit = decode_one[f1];
|
||||
snr = result[f1] / noise;
|
||||
}
|
||||
/* check two frequencies */
|
||||
if (result[f1] > MIN_DB && result[f2] > MIN_DB /* must be at lease -17 db */
|
||||
&& result[f1]*DIFF_DB <= result[f2] /* f2 must be not less than 5 db below f1 */
|
||||
&& (result[f1]+result[f2])*SNR > noise) { /* */
|
||||
digit = decode_two[f1][f2];
|
||||
snr = (result[f1]+result[f2]) / noise;
|
||||
}
|
||||
|
||||
/* debug powers */
|
||||
#ifdef DEBUG_LEVELS
|
||||
for (i = 0; i < NCOEFF; i++)
|
||||
printf("%d:%3d %c ", i, (int)(result[i]*100), (f1==i || f2==i)?'*':' ');
|
||||
printf("N:%3d digit:%c snr=%3d\n", (int)(noise*100), digit, (int)(snr*100));
|
||||
#endif
|
||||
|
||||
return digit;
|
||||
}
|
||||
|
||||
void ss5_test_decode(void)
|
||||
{
|
||||
#ifdef DEBUG_LEVELS
|
||||
double phase;
|
||||
int i, j;
|
||||
signed short sample;
|
||||
|
||||
unsigned char buffer[SS5_DECODER_NPOINTS];
|
||||
for (i = 0; i < 4000; i += 10) {
|
||||
phase = 2.0 * 3.14159265 * i / 8000.0;
|
||||
for (j = 0; j < SS5_DECODER_NPOINTS; j++) {
|
||||
sample = sin(phase * j) * 1000;
|
||||
buffer[j] = audio_s16_to_law[sample & 0xffff];
|
||||
}
|
||||
printf("FRQ:%04d:", i);
|
||||
ss5_decode(buffer, SS5_DECODER_NPOINTS);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* SS5 signal decoder header file
|
||||
*
|
||||
*/
|
||||
|
||||
#define SS5_DECODER_NPOINTS 80 /* size of goertzel window */
|
||||
|
||||
char ss5_decode(unsigned char *data, int len);
|
||||
void ss5_test_decode(void);
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* SS5 signal coder.
|
||||
*
|
||||
* Copyright by Andreas Eversberg (jolly@eversberg.eu)
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
#include "ss5_encode.h"
|
||||
|
||||
/* 2*PI*f/8000 */
|
||||
static double ss5_freq[9][2] = {
|
||||
{0.0, 0}, /* 0: 0 */
|
||||
{700, 0.19952623}, /* 1: 700, -7db */
|
||||
{900, 0.19952623}, /* 2: 900, -7db */
|
||||
{1100, 0.19952623}, /* 3: 1100, -7db */
|
||||
{1300, 0.19952623}, /* 4: 1300, -7db */
|
||||
{1500, 0.19952623}, /* 5: 1500, -7db */
|
||||
{1700, 0.19952623}, /* 6: 1700, -7db */
|
||||
{2400, 0.12589254}, /* 7: 2400, -9db */
|
||||
{2600, 0.12589254}, /* 8: 2600, -9db */
|
||||
};
|
||||
|
||||
static char ss5_digits[][3] = {
|
||||
{'1', 1, 2},
|
||||
{'2', 1, 3},
|
||||
{'3', 2, 3},
|
||||
{'4', 1, 4},
|
||||
{'5', 2, 4},
|
||||
{'6', 3, 4},
|
||||
{'7', 1, 5},
|
||||
{'8', 2, 5},
|
||||
{'9', 3, 5},
|
||||
{'0', 4, 5},
|
||||
{'*', 1, 6}, /* code 11 */
|
||||
{'#', 2, 6}, /* code 12 */
|
||||
{'a', 3, 6}, /* KP1 */
|
||||
{'b', 4, 6}, /* KP2 */
|
||||
{'c', 5, 6}, /* ST */
|
||||
{'A', 7, 0}, /* 2400 answer, acknowledge */
|
||||
{'B', 8, 0}, /* 2600 busy */
|
||||
{'C', 7, 8}, /* 2600+2400 clear forward */
|
||||
{0 , 0, 0},
|
||||
};
|
||||
|
||||
static unsigned char sintab[15+3][8192]; /* sine tables of about one second sound (error <1Hz) */
|
||||
|
||||
/* generate sine tables */
|
||||
void ss5_sine_generate(void)
|
||||
{
|
||||
int i, j;
|
||||
int cycles1, cycles2;
|
||||
double vol1, vol2, phase1, phase2;
|
||||
signed short sample;
|
||||
|
||||
for (i = 0; i < 15+3; i++) {
|
||||
/* how many cycles are within 8192 samples (rounded!) */
|
||||
cycles1 = (int)(ss5_freq[(int)ss5_digits[i][1]][0] / 8000.0 * 8192.0 + 0.5);
|
||||
cycles2 = (int)(ss5_freq[(int)ss5_digits[i][2]][0] / 8000.0 * 8192.0 + 0.5);
|
||||
/* how much phase shift within one cycle */
|
||||
phase1 = 2.0 * 3.14159265 * cycles1 / 8192.0;
|
||||
phase2 = 2.0 * 3.14159265 * cycles2 / 8192.0;
|
||||
/* volume */
|
||||
vol1 = ss5_freq[(int)ss5_digits[i][1]][1] * 32768.0;
|
||||
vol2 = ss5_freq[(int)ss5_digits[i][2]][1] * 32768.0;
|
||||
for (j = 0; j < 8192; j++) {
|
||||
sample = (int)(sin(phase1 * j) * vol1);
|
||||
sample += (int)(sin(phase2 * j) * vol2);
|
||||
sintab[i][j] = audio_s16_to_law[sample & 0xffff];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* encode digit at given sample_nr with given lengt and return law-encoded audio */
|
||||
unsigned char *ss5_encode(unsigned char *buffer, int len, char digit, int sample_nr)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
/* get frequency from digit */
|
||||
i = 0;
|
||||
while(ss5_digits[i][0]) {
|
||||
if (digit == ss5_digits[i][0])
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
if (!ss5_digits[i][0]) {
|
||||
PERROR("Digit '%c' does not exist.\n", digit);
|
||||
memset(buffer, audio_s16_to_law[0], sizeof(buffer));
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/* copy tones */
|
||||
for (j = 0; j < len; j++)
|
||||
*buffer++ = sintab[i][sample_nr++ & 8191];
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* SS5 signal coder header file
|
||||
*/
|
||||
|
||||
void ss5_sine_generate(void);
|
||||
unsigned char *ss5_encode(unsigned char *buffer, int len, char digit, int sample_nr);
|
||||
|
Loading…
Reference in New Issue