summaryrefslogtreecommitdiff
path: root/gsmsp/gsm/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'gsmsp/gsm/src/lib')
-rw-r--r--gsmsp/gsm/src/lib/Makefile.am77
-rw-r--r--gsmsp/gsm/src/lib/Makefile.in754
-rw-r--r--gsmsp/gsm/src/lib/burst_types.h203
-rw-r--r--gsmsp/gsm/src/lib/cch.cc485
-rw-r--r--gsmsp/gsm/src/lib/cch.h41
-rw-r--r--gsmsp/gsm/src/lib/common.cc87
-rw-r--r--gsmsp/gsm/src/lib/common.h51
-rw-r--r--gsmsp/gsm/src/lib/data_out.c2289
-rw-r--r--gsmsp/gsm/src/lib/data_out.h11
-rw-r--r--gsmsp/gsm/src/lib/fire_crc.cc168
-rw-r--r--gsmsp/gsm/src/lib/fire_crc.h54
-rw-r--r--gsmsp/gsm/src/lib/gsm.i32
-rw-r--r--gsmsp/gsm/src/lib/gsm_constants.h12
-rw-r--r--gsmsp/gsm/src/lib/gsm_desc.h158
-rw-r--r--gsmsp/gsm/src/lib/gsm_run_bb.cc420
-rw-r--r--gsmsp/gsm/src/lib/gsm_run_bb.h87
-rw-r--r--gsmsp/gsm/src/lib/id_list.c18
-rw-r--r--gsmsp/gsm/src/lib/id_list.h23
-rw-r--r--gsmsp/gsm/src/lib/interleave.cc48
-rw-r--r--gsmsp/gsm/src/lib/interleave.h18
-rw-r--r--gsmsp/gsm/src/lib/sch.cc325
-rw-r--r--gsmsp/gsm/src/lib/sch.h3
22 files changed, 5364 insertions, 0 deletions
diff --git a/gsmsp/gsm/src/lib/Makefile.am b/gsmsp/gsm/src/lib/Makefile.am
new file mode 100644
index 0000000..84cf81d
--- /dev/null
+++ b/gsmsp/gsm/src/lib/Makefile.am
@@ -0,0 +1,77 @@
+include $(top_srcdir)/Makefile.common
+
+# Install this stuff so that it ends up as the gnuradio.gsm module
+# This usually ends up at:
+# ${prefix}/lib/python${python_version}/site-packages/gnuradio
+
+ourpythondir = $(grpythondir)
+ourlibdir = $(grpyexecdir)
+
+INCLUDES = $(STD_DEFINES_AND_INCLUDES) $(PYTHON_CPPFLAGS)
+
+SWIGPYTHONARGS = $(SWIGPYTHONFLAGS) $(SWIGGRFLAGS)
+
+ALL_IFILES = \
+ $(LOCAL_IFILES) \
+ $(NON_LOCAL_IFILES)
+
+NON_LOCAL_IFILES = \
+ $(GNURADIO_CORE_INCLUDEDIR)/swig/gnuradio.i
+
+
+LOCAL_IFILES = \
+ $(top_srcdir)/src/lib/gsm.i
+
+# These files are built by SWIG. The first is the C++ glue.
+# The second is the python wrapper that loads the _gsm shared library
+# and knows how to call our extensions.
+
+BUILT_SOURCES = \
+ gsm.cc \
+ gsm.py
+
+# This gets gsm.py installed in the right place
+ourpython_PYTHON = \
+ gsm.py
+
+ourlib_LTLIBRARIES = _gsm.la
+
+# These are the source files that go into the shared library
+_gsm_la_SOURCES = \
+ gsm.cc \
+ common.cc \
+ sch.cc \
+ cch.cc \
+ data_out.c \
+ id_list.c \
+ fire_crc.cc \
+ interleave.cc \
+ gsm_run_bb.cc
+
+# magic flags
+_gsm_la_LDFLAGS = $(NO_UNDEFINED) -module -avoid-version
+
+# link the library against some comon swig runtime code and the
+# c++ standard library
+_gsm_la_LIBADD = \
+ $(PYTHON_LDFLAGS) \
+ -lstdc++
+
+gsm.cc gsm.py: $(LOCAL_IFILES) $(ALL_IFILES)
+ $(SWIG) $(SWIGPYTHONARGS) -module gsm -o gsm.cc $(LOCAL_IFILES)
+
+# These headers get installed in ${prefix}/include/gnuradio
+grinclude_HEADERS = \
+ gsm_run_bb.h common.h sch.h fire_crc.h cch.h common.h burst_types.h gsm_constants.h interleave.h id_list.h gsm_desc.h data_out.h
+
+# These swig headers get installed in ${prefix}/include/gnuradio/swig
+swiginclude_HEADERS = \
+ $(LOCAL_IFILES)
+
+
+MOSTLYCLEANFILES = $(BUILT_SOURCES) *.pyc
+
+# Don't distribute output of swig
+dist-hook:
+ @for file in $(BUILT_SOURCES); do echo $(RM) $(distdir)/$$file; done
+ @for file in $(BUILT_SOURCES); do $(RM) $(distdir)/$$file; done
diff --git a/gsmsp/gsm/src/lib/Makefile.in b/gsmsp/gsm/src/lib/Makefile.in
new file mode 100644
index 0000000..7bb69e9
--- /dev/null
+++ b/gsmsp/gsm/src/lib/Makefile.in
@@ -0,0 +1,754 @@
+# Makefile.in generated by automake 1.10 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# -*- Makefile -*-
+#
+# Copyright 2004,2006 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+DIST_COMMON = $(grinclude_HEADERS) $(ourpython_PYTHON) \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ $(swiginclude_HEADERS) $(top_srcdir)/Makefile.common
+subdir = src/lib
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/config/acx_pthread.m4 \
+ $(top_srcdir)/config/gr_boost.m4 \
+ $(top_srcdir)/config/gr_gprof.m4 \
+ $(top_srcdir)/config/gr_no_undefined.m4 \
+ $(top_srcdir)/config/gr_omnithread.m4 \
+ $(top_srcdir)/config/gr_pwin32.m4 \
+ $(top_srcdir)/config/gr_python.m4 \
+ $(top_srcdir)/config/gr_scripting.m4 \
+ $(top_srcdir)/config/gr_swig.m4 \
+ $(top_srcdir)/config/gr_x86_64.m4 \
+ $(top_srcdir)/config/lf_cxx.m4 \
+ $(top_srcdir)/config/lf_warnings.m4 \
+ $(top_srcdir)/config/pkg.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(ourlibdir)" "$(DESTDIR)$(ourpythondir)" \
+ "$(DESTDIR)$(grincludedir)" "$(DESTDIR)$(swigincludedir)"
+ourlibLTLIBRARIES_INSTALL = $(INSTALL)
+LTLIBRARIES = $(ourlib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+_gsm_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am__gsm_la_OBJECTS = gsm.lo common.lo sch.lo cch.lo data_out.lo \
+ id_list.lo fire_crc.lo interleave.lo gsm_run_bb.lo
+_gsm_la_OBJECTS = $(am__gsm_la_OBJECTS)
+_gsm_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(_gsm_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(_gsm_la_SOURCES)
+DIST_SOURCES = $(_gsm_la_SOURCES)
+ourpythonPYTHON_INSTALL = $(INSTALL_DATA)
+py_compile = $(top_srcdir)/py-compile
+grincludeHEADERS_INSTALL = $(INSTALL_HEADER)
+swigincludeHEADERS_INSTALL = $(INSTALL_HEADER)
+HEADERS = $(grinclude_HEADERS) $(swiginclude_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CFLAGS = @BOOST_CFLAGS@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CXX_FOR_BUILD = @CXX_FOR_BUILD@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GNURADIO_CORE_CFLAGS = @GNURADIO_CORE_CFLAGS@
+GNURADIO_CORE_INCLUDEDIR = @GNURADIO_CORE_INCLUDEDIR@
+GNURADIO_CORE_LIBS = @GNURADIO_CORE_LIBS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NO_UNDEFINED = @NO_UNDEFINED@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+PYTHON = @PYTHON@
+PYTHON_CPPFLAGS = @PYTHON_CPPFLAGS@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_LDFLAGS = @PYTHON_LDFLAGS@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RM_PROG = @RM_PROG@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STD_DEFINES_AND_INCLUDES = @STD_DEFINES_AND_INCLUDES@
+STRIP = @STRIP@
+SWIG = @SWIG@
+SWIG_PYTHON_CPPFLAGS = @SWIG_PYTHON_CPPFLAGS@
+SWIG_PYTHON_LIB = @SWIG_PYTHON_LIB@
+SWIG_PYTHON_OPT = @SWIG_PYTHON_OPT@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+
+# includes
+grincludedir = $(includedir)/gnuradio
+
+# swig includes
+swigincludedir = $(grincludedir)/swig
+
+# Install this stuff in the appropriate subdirectory
+# This usually ends up at:
+# ${prefix}/lib/python${python_version}/site-packages/gnuradio
+grpythondir = $(pythondir)/gnuradio
+grpyexecdir = $(pyexecdir)/gnuradio
+
+# swig flags
+SWIGPYTHONFLAGS = -fvirtual -python -modern
+SWIGGRFLAGS = -I$(GNURADIO_CORE_INCLUDEDIR)/swig -I$(GNURADIO_CORE_INCLUDEDIR)
+
+# Don't assume that make predefines $(RM), because BSD make does
+# not. We define it now in configure.ac using AM_PATH_PROG, but now
+# here have to add a -f to be like GNU make.
+RM = $(RM_PROG) -f
+
+# Install this stuff so that it ends up as the gnuradio.gsm module
+# This usually ends up at:
+# ${prefix}/lib/python${python_version}/site-packages/gnuradio
+ourpythondir = $(grpythondir)
+ourlibdir = $(grpyexecdir)
+INCLUDES = $(STD_DEFINES_AND_INCLUDES) $(PYTHON_CPPFLAGS)
+SWIGPYTHONARGS = $(SWIGPYTHONFLAGS) $(SWIGGRFLAGS)
+ALL_IFILES = \
+ $(LOCAL_IFILES) \
+ $(NON_LOCAL_IFILES)
+
+NON_LOCAL_IFILES = \
+ $(GNURADIO_CORE_INCLUDEDIR)/swig/gnuradio.i
+
+LOCAL_IFILES = \
+ $(top_srcdir)/src/lib/gsm.i
+
+
+# These files are built by SWIG. The first is the C++ glue.
+# The second is the python wrapper that loads the _gsm shared library
+# and knows how to call our extensions.
+BUILT_SOURCES = \
+ gsm.cc \
+ gsm.py
+
+
+# This gets gsm.py installed in the right place
+ourpython_PYTHON = \
+ gsm.py
+
+ourlib_LTLIBRARIES = _gsm.la
+
+# These are the source files that go into the shared library
+_gsm_la_SOURCES = \
+ gsm.cc \
+ common.cc \
+ sch.cc \
+ cch.cc \
+ data_out.c \
+ id_list.c \
+ fire_crc.cc \
+ interleave.cc \
+ gsm_run_bb.cc
+
+
+# magic flags
+_gsm_la_LDFLAGS = $(NO_UNDEFINED) -module -avoid-version
+
+# link the library against some comon swig runtime code and the
+# c++ standard library
+_gsm_la_LIBADD = \
+ $(PYTHON_LDFLAGS) \
+ -lstdc++
+
+
+# These headers get installed in ${prefix}/include/gnuradio
+grinclude_HEADERS = \
+ gsm_run_bb.h common.h sch.h fire_crc.h cch.h common.h burst_types.h gsm_constants.h interleave.h id_list.h gsm_desc.h data_out.h
+
+
+# These swig headers get installed in ${prefix}/include/gnuradio/swig
+swiginclude_HEADERS = \
+ $(LOCAL_IFILES)
+
+MOSTLYCLEANFILES = $(BUILT_SOURCES) *.pyc
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .cc .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(top_srcdir)/Makefile.common $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-ourlibLTLIBRARIES: $(ourlib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(ourlibdir)" || $(MKDIR_P) "$(DESTDIR)$(ourlibdir)"
+ @list='$(ourlib_LTLIBRARIES)'; for p in $$list; do \
+ if test -f $$p; then \
+ f=$(am__strip_dir) \
+ echo " $(LIBTOOL) --mode=install $(ourlibLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(ourlibdir)/$$f'"; \
+ $(LIBTOOL) --mode=install $(ourlibLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(ourlibdir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-ourlibLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(ourlib_LTLIBRARIES)'; for p in $$list; do \
+ p=$(am__strip_dir) \
+ echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(ourlibdir)/$$p'"; \
+ $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(ourlibdir)/$$p"; \
+ done
+
+clean-ourlibLTLIBRARIES:
+ -test -z "$(ourlib_LTLIBRARIES)" || rm -f $(ourlib_LTLIBRARIES)
+ @list='$(ourlib_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+_gsm.la: $(_gsm_la_OBJECTS) $(_gsm_la_DEPENDENCIES)
+ $(_gsm_la_LINK) -rpath $(ourlibdir) $(_gsm_la_OBJECTS) $(_gsm_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cch.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/data_out.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fire_crc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gsm.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gsm_run_bb.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/id_list.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interleave.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sch.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+.cc.o:
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-ourpythonPYTHON: $(ourpython_PYTHON)
+ @$(NORMAL_INSTALL)
+ test -z "$(ourpythondir)" || $(MKDIR_P) "$(DESTDIR)$(ourpythondir)"
+ @list='$(ourpython_PYTHON)'; dlist=''; for p in $$list; do\
+ if test -f "$$p"; then b=; else b="$(srcdir)/"; fi; \
+ if test -f $$b$$p; then \
+ f=$(am__strip_dir) \
+ dlist="$$dlist $$f"; \
+ echo " $(ourpythonPYTHON_INSTALL) '$$b$$p' '$(DESTDIR)$(ourpythondir)/$$f'"; \
+ $(ourpythonPYTHON_INSTALL) "$$b$$p" "$(DESTDIR)$(ourpythondir)/$$f"; \
+ else :; fi; \
+ done; \
+ if test -n "$$dlist"; then \
+ if test -z "$(DESTDIR)"; then \
+ PYTHON=$(PYTHON) $(py_compile) --basedir "$(ourpythondir)" $$dlist; \
+ else \
+ PYTHON=$(PYTHON) $(py_compile) --destdir "$(DESTDIR)" --basedir "$(ourpythondir)" $$dlist; \
+ fi; \
+ else :; fi
+
+uninstall-ourpythonPYTHON:
+ @$(NORMAL_UNINSTALL)
+ @list='$(ourpython_PYTHON)'; dlist=''; for p in $$list; do\
+ f=$(am__strip_dir) \
+ rm -f "$(DESTDIR)$(ourpythondir)/$$f"; \
+ rm -f "$(DESTDIR)$(ourpythondir)/$${f}c"; \
+ rm -f "$(DESTDIR)$(ourpythondir)/$${f}o"; \
+ done
+install-grincludeHEADERS: $(grinclude_HEADERS)
+ @$(NORMAL_INSTALL)
+ test -z "$(grincludedir)" || $(MKDIR_P) "$(DESTDIR)$(grincludedir)"
+ @list='$(grinclude_HEADERS)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(am__strip_dir) \
+ echo " $(grincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(grincludedir)/$$f'"; \
+ $(grincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(grincludedir)/$$f"; \
+ done
+
+uninstall-grincludeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(grinclude_HEADERS)'; for p in $$list; do \
+ f=$(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(grincludedir)/$$f'"; \
+ rm -f "$(DESTDIR)$(grincludedir)/$$f"; \
+ done
+install-swigincludeHEADERS: $(swiginclude_HEADERS)
+ @$(NORMAL_INSTALL)
+ test -z "$(swigincludedir)" || $(MKDIR_P) "$(DESTDIR)$(swigincludedir)"
+ @list='$(swiginclude_HEADERS)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(am__strip_dir) \
+ echo " $(swigincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(swigincludedir)/$$f'"; \
+ $(swigincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(swigincludedir)/$$f"; \
+ done
+
+uninstall-swigincludeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(swiginclude_HEADERS)'; for p in $$list; do \
+ f=$(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(swigincludedir)/$$f'"; \
+ rm -f "$(DESTDIR)$(swigincludedir)/$$f"; \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$(top_distdir)" distdir="$(distdir)" \
+ dist-hook
+check-am: all-am
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(ourlibdir)" "$(DESTDIR)$(ourpythondir)" "$(DESTDIR)$(grincludedir)" "$(DESTDIR)$(swigincludedir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+ -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-ourlibLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-grincludeHEADERS install-ourlibLTLIBRARIES \
+ install-ourpythonPYTHON install-swigincludeHEADERS
+
+install-dvi: install-dvi-am
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-grincludeHEADERS uninstall-ourlibLTLIBRARIES \
+ uninstall-ourpythonPYTHON uninstall-swigincludeHEADERS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-ourlibLTLIBRARIES ctags dist-hook \
+ distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-grincludeHEADERS install-html \
+ install-html-am install-info install-info-am install-man \
+ install-ourlibLTLIBRARIES install-ourpythonPYTHON install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ install-swigincludeHEADERS installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
+ uninstall-am uninstall-grincludeHEADERS \
+ uninstall-ourlibLTLIBRARIES uninstall-ourpythonPYTHON \
+ uninstall-swigincludeHEADERS
+
+
+gsm.cc gsm.py: $(LOCAL_IFILES) $(ALL_IFILES)
+ $(SWIG) $(SWIGPYTHONARGS) -module gsm -o gsm.cc $(LOCAL_IFILES)
+
+# Don't distribute output of swig
+dist-hook:
+ @for file in $(BUILT_SOURCES); do echo $(RM) $(distdir)/$$file; done
+ @for file in $(BUILT_SOURCES); do $(RM) $(distdir)/$$file; done
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/gsmsp/gsm/src/lib/burst_types.h b/gsmsp/gsm/src/lib/burst_types.h
new file mode 100644
index 0000000..377ef6d
--- /dev/null
+++ b/gsmsp/gsm/src/lib/burst_types.h
@@ -0,0 +1,203 @@
+// $Id: burst_types.h,v 1.5 2007/03/14 05:44:53 jl Exp $
+
+#pragma once
+
+#include "gsm_constants.h"
+
+static const int TB_LEN = 3;
+static const int TB_OS1 = 0;
+static const int TB_OS2 = 145;
+static const unsigned char tail_bits[TB_LEN] = {0, 0, 0};
+
+/*
+ * The normal burst is used to carry information on traffic and control
+ * channels.
+ */
+static const int N_TSC_NUM = 8; // number of training sequence codes
+static const int N_TSC_CODE_LEN = 26; // length of tsc
+static const int N_TSC_OS = 61; // tsc offset
+static const int N_EDATA_LEN_1 = 58; // length of first data section
+static const int N_EDATA_OS_1 = 3; // offset of first data section
+static const int N_EDATA_LEN_2 = 58; // length of second data section
+static const int N_EDATA_OS_2 = 87; // offset of second data section
+static const unsigned char n_tsc[N_TSC_NUM][N_TSC_CODE_LEN] = {
+/* 0 */ {
+ 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1
+ },
+/* 1 */ {
+ 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1,
+ 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1
+ },
+/* 2 */ {
+ 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1,
+ 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0
+ },
+/* 3 */ {
+ 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0,
+ 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0
+ },
+/* 4 */ {
+ 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1
+ },
+/* 5 */ {
+ 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0
+ },
+/* 6 */ {
+ 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1,
+ 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1
+ },
+/* 7 */ {
+ 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0,
+ 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0
+ }
+};
+
+
+/*
+ * The frequency correction burst is used for frequency synchronization
+ * of the mobile. This is broadcast in TS0 together with the SCH and
+ * BCCH.
+ *
+ * Modulating the bits below causes a spike at 62.5kHz above (below for
+ * COMPACT) the center frequency. One can use this spike with a narrow
+ * band filter to accurately determine the center of the channel.
+ */
+static const int FC_CODE_LEN = 142;
+static const int FC_OS = 3;
+static const unsigned char fc_fb[FC_CODE_LEN] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static const unsigned char fc_compact_fb[FC_CODE_LEN] = {
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0
+};
+
+
+/*
+ * The synchronization burst is used for time synchronization of the
+ * mobile. The bits given below were chosen for their correlation
+ * properties. The synchronization channel (SCH) contains a long
+ * training sequence (given below) and carries the TDMA frame number and
+ * base station identity code. It is broadcast in TS0 in the frame
+ * following the frequency correction burst.
+ */
+static const int SB_CODE_LEN = 64;
+static const int SB_ETS_OS = 42;
+static const int SB_EDATA_LEN_1 = 39;
+static const int SB_EDATA_OS_1 = 3;
+static const int SB_EDATA_LEN_2 = 39;
+static const int SB_EDATA_OS_2 = 106;
+static const unsigned char sb_etsc[SB_CODE_LEN] = {
+ 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
+ 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1,
+ 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1
+};
+
+static const unsigned char sb_cts_etsc[SB_CODE_LEN] = {
+ 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1,
+ 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0,
+ 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0,
+ 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1
+};
+
+static const unsigned char sb_compact_etsc[SB_CODE_LEN] = {
+ 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
+ 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0,
+ 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0
+};
+
+
+/*
+ * A base tranceiver station must transmit a burst in every timeslot of
+ * every TDMA frame in channel C0. The dummy burst will be transmitted
+ * on all timeslots of all TDMA frames for which no other channel
+ * requires a burst to be transmitted.
+ */
+static const int D_CODE_LEN = 142;
+static const int D_MB_OS = 3;
+static const unsigned char d_mb[D_CODE_LEN] = {
+ 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0,
+ 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0,
+ 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0,
+ 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0,
+ 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1,
+ 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1,
+ 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0
+};
+
+
+/*
+ * The access burst is used for random access from a mobile.
+ */
+static const int AB_ETB_CODE_LEN = 8;
+static const int AB_ETB_OS = 0;
+static const unsigned char ab_etb[AB_ETB_CODE_LEN] = {
+ 0, 0, 1, 1, 1, 0, 1, 0
+};
+
+static const int AB_SSB_CODE_LEN = 41;
+static const int AB_SSB_OS = 8;
+static const unsigned char ab_ssb[AB_SSB_CODE_LEN] = {
+ 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1,
+ 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0,
+ 0, 0, 1, 1, 1, 1, 0, 0, 0
+};
+
+static const unsigned char ab_ts1_ssb[AB_SSB_CODE_LEN] = {
+ 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,
+ 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1,
+ 0, 0, 1, 0, 0, 1, 1, 0, 1
+};
+
+static const unsigned char ab_ts2_ssb[AB_SSB_CODE_LEN] = {
+ 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1,
+ 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1,
+ 1, 0, 1, 1, 1, 0, 1, 1, 1
+};
+
+
+typedef enum {
+ burst_n_0,
+ burst_n_1,
+ burst_n_2,
+ burst_n_3,
+ burst_n_4,
+ burst_n_5,
+ burst_n_6,
+ burst_n_7,
+ burst_fc,
+ burst_fc_c,
+ burst_s,
+ burst_s_cts,
+ burst_s_c,
+ burst_d,
+ burst_a,
+ burst_a_ts1,
+ burst_a_ts2,
+ burst_not_a_burst
+} burst_t;
+
+static const int N_BURST_TYPES = ((int)(burst_not_a_burst) + 1);
diff --git a/gsmsp/gsm/src/lib/cch.cc b/gsmsp/gsm/src/lib/cch.cc
new file mode 100644
index 0000000..c43fe8c
--- /dev/null
+++ b/gsmsp/gsm/src/lib/cch.cc
@@ -0,0 +1,485 @@
+
+#include "common.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <exception>
+#include <stdexcept>
+#include <math.h>
+
+#include "burst_types.h"
+#include "cch.h"
+#include "fire_crc.h"
+
+extern struct _opt opt;
+
+/*
+ * GSM SACCH -- Slow Associated Control Channel
+ *
+ * These messages are encoded exactly the same as on the BCCH.
+ * (Broadcast Control Channel.)
+ *
+ * Input: 184 bits
+ *
+ * 1. Add parity and flushing bits. (Output 184 + 40 + 4 = 228 bit)
+ * 2. Convolutional encode. (Output 228 * 2 = 456 bit)
+ * 3. Interleave. (Output 456 bit)
+ * 4. Map on bursts. (4 x 156 bit bursts with each 2x57 bit content data)
+ */
+
+
+/*
+ * Parity (FIRE) for the GSM SACCH channel.
+ *
+ * g(x) = (x^23 + 1)(x^17 + x^3 + 1)
+ * = x^40 + x^26 + x^23 + x^17 + x^3 + 1
+ */
+
+static const unsigned char parity_polynomial[PARITY_SIZE + 1] = {
+ 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 0,
+ 0, 1, 0, 0, 0, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0,
+ 1
+};
+
+// remainder after dividing data polynomial by g(x)
+static const unsigned char parity_remainder[PARITY_SIZE] = {
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1
+};
+
+
+/*
+static void parity_encode(unsigned char *d, unsigned char *p) {
+
+ int i;
+ unsigned char buf[DATA_BLOCK_SIZE + PARITY_SIZE], *q;
+
+ memcpy(buf, d, DATA_BLOCK_SIZE);
+ memset(buf + DATA_BLOCK_SIZE, 0, PARITY_SIZE);
+
+ for(q = buf; q < buf + DATA_BLOCK_SIZE; q++)
+ if(*q)
+ for(i = 0; i < PARITY_SIZE + 1; i++)
+ q[i] ^= parity_polynomial[i];
+ for(i = 0; i < PARITY_SIZE; i++)
+ p[i] = !buf[DATA_BLOCK_SIZE + i];
+}
+ */
+
+
+static int parity_check(unsigned char *d) {
+
+ unsigned int i;
+ unsigned char buf[DATA_BLOCK_SIZE + PARITY_SIZE], *q;
+
+ memcpy(buf, d, DATA_BLOCK_SIZE + PARITY_SIZE);
+
+ for(q = buf; q < buf + DATA_BLOCK_SIZE; q++)
+ if(*q)
+ for(i = 0; i < PARITY_SIZE + 1; i++)
+ q[i] ^= parity_polynomial[i];
+ return memcmp(buf + DATA_BLOCK_SIZE, parity_remainder, PARITY_SIZE);
+}
+
+
+/*
+ * Convolutional encoding and Viterbi decoding for the GSM SACCH channel.
+ */
+
+/*
+ * Convolutional encoding:
+ *
+ * G_0 = 1 + x^3 + x^4
+ * G_1 = 1 + x + x^3 + x^4
+ *
+ * i.e.,
+ *
+ * c_{2k} = u_k + u_{k - 3} + u_{k - 4}
+ * c_{2k + 1} = u_k + u_{k - 1} + u_{k - 3} + u_{k - 4}
+ */
+#define K 5
+#define MAX_ERROR (2 * CONV_INPUT_SIZE + 1)
+
+
+/*
+ * Given the current state and input bit, what are the output bits?
+ *
+ * encode[current_state][input_bit]
+ */
+static const unsigned int encode[1 << (K - 1)][2] = {
+ {0, 3}, {3, 0}, {3, 0}, {0, 3},
+ {0, 3}, {3, 0}, {3, 0}, {0, 3},
+ {1, 2}, {2, 1}, {2, 1}, {1, 2},
+ {1, 2}, {2, 1}, {2, 1}, {1, 2}
+};
+
+
+/*
+ * Given the current state and input bit, what is the next state?
+ *
+ * next_state[current_state][input_bit]
+ */
+static const unsigned int next_state[1 << (K - 1)][2] = {
+ {0, 8}, {0, 8}, {1, 9}, {1, 9},
+ {2, 10}, {2, 10}, {3, 11}, {3, 11},
+ {4, 12}, {4, 12}, {5, 13}, {5, 13},
+ {6, 14}, {6, 14}, {7, 15}, {7, 15}
+};
+
+
+/*
+ * Given the previous state and the current state, what input bit caused
+ * the transition? If it is impossible to transition between the two
+ * states, the value is 2.
+ *
+ * prev_next_state[previous_state][current_state]
+ */
+static const unsigned int prev_next_state[1 << (K - 1)][1 << (K - 1)] = {
+ { 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2},
+ { 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2},
+ { 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2},
+ { 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2},
+ { 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2},
+ { 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2},
+ { 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2},
+ { 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2},
+ { 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2},
+ { 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2},
+ { 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2},
+ { 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2},
+ { 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2},
+ { 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2},
+ { 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1},
+ { 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1}
+};
+
+
+static inline unsigned int hamming_distance2(unsigned int w) {
+
+ return (w & 1) + !!(w & 2);
+}
+
+
+/*
+static void conv_encode(unsigned char *data, unsigned char *output) {
+
+ unsigned int i, state = 0, o;
+
+ // encode data
+ for(i = 0; i < CONV_INPUT_SIZE; i++) {
+ o = encode[state][data[i]];
+ state = next_state[state][data[i]];
+ *output++ = !!(o & 2);
+ *output++ = o & 1;
+ }
+}
+ */
+
+
+static int conv_decode(unsigned char *output, unsigned char *data) {
+
+ int i, t;
+ unsigned int rdata, state, nstate, b, o, distance, accumulated_error,
+ min_state, min_error, cur_state;
+
+ unsigned int ae[1 << (K - 1)];
+ unsigned int nae[1 << (K - 1)]; // next accumulated error
+ unsigned int state_history[1 << (K - 1)][CONV_INPUT_SIZE + 1];
+
+ // initialize accumulated error, assume starting state is 0
+ for(i = 0; i < (1 << (K - 1)); i++)
+ ae[i] = nae[i] = MAX_ERROR;
+ ae[0] = 0;
+
+ // build trellis
+ for(t = 0; t < CONV_INPUT_SIZE; t++) {
+
+ // get received data symbol
+ rdata = (data[2 * t] << 1) | data[2 * t + 1];
+
+ // for each state
+ for(state = 0; state < (1 << (K - 1)); state++) {
+
+ // make sure this state is possible
+ if(ae[state] >= MAX_ERROR)
+ continue;
+
+ // find all states we lead to
+ for(b = 0; b < 2; b++) {
+
+ // get next state given input bit b
+ nstate = next_state[state][b];
+
+ // find output for this transition
+ o = encode[state][b];
+
+ // calculate distance from received data
+ distance = hamming_distance2(rdata ^ o);
+
+ // choose surviving path
+ accumulated_error = ae[state] + distance;
+ if(accumulated_error < nae[nstate]) {
+
+ // save error for surviving state
+ nae[nstate] = accumulated_error;
+
+ // update state history
+ state_history[nstate][t + 1] = state;
+ }
+ }
+ }
+
+ // get accumulated error ready for next time slice
+ for(i = 0; i < (1 << (K - 1)); i++) {
+ ae[i] = nae[i];
+ nae[i] = MAX_ERROR;
+ }
+ }
+
+ // the final state is the state with the fewest errors
+ min_state = (unsigned int)-1;
+ min_error = MAX_ERROR;
+ for(i = 0; i < (1 << (K - 1)); i++) {
+ if(ae[i] < min_error) {
+ min_state = i;
+ min_error = ae[i];
+ }
+ }
+
+ // trace the path
+ cur_state = min_state;
+ for(t = CONV_INPUT_SIZE; t >= 1; t--) {
+ min_state = cur_state;
+ cur_state = state_history[cur_state][t]; // get previous
+ output[t - 1] = prev_next_state[cur_state][min_state];
+ }
+
+ // return the number of errors detected (hard-decision)
+ return min_error;
+}
+
+
+/*
+ * GSM SACCH interleaving and burst mapping
+ *
+ * Interleaving:
+ *
+ * Given 456 coded input bits, form 4 blocks of 114 bits:
+ *
+ * i(B, j) = c(n, k) k = 0, ..., 455
+ * n = 0, ..., N, N + 1, ...
+ * B = B_0 + 4n + (k mod 4)
+ * j = 2(49k mod 57) + ((k mod 8) div 4)
+ *
+ * Mapping on Burst:
+ *
+ * e(B, j) = i(B, j)
+ * e(B, 59 + j) = i(B, 57 + j) j = 0, ..., 56
+ * e(B, 57) = h_l(B)
+ * e(B, 58) = h_n(B)
+ *
+ * Where h_l(B) and h_n(B) are bits in burst B indicating flags.
+ */
+
+/*
+static void interleave(unsigned char *data, unsigned char *iBLOCK) {
+
+ int j, k, B;
+
+ // for each bit in input data
+ for(k = 0; k < CONV_SIZE; k++) {
+ B = k % 4;
+ j = 2 * ((49 * k) % 57) + ((k % 8) / 4);
+ iBLOCK[B * iBLOCK_SIZE + j] = data[k];
+ }
+}
+ */
+
+
+#if 0
+static void decode_interleave(unsigned char *data, unsigned char *iBLOCK) {
+
+ int j, k, B;
+
+ for(k = 0; k < CONV_SIZE; k++) {
+ B = k % 4;
+ j = 2 * ((49 * k) % 57) + ((k % 8) / 4);
+ data[k] = iBLOCK[B * iBLOCK_SIZE + j];
+ }
+}
+
+#endif
+
+/*
+static void burstmap(unsigned char *iBLOCK, unsigned char *eBLOCK,
+ unsigned char hl, unsigned char hn) {
+
+ int j;
+
+ for(j = 0; j < 57; j++) {
+ eBLOCK[j] = iBLOCK[j];
+ eBLOCK[j + 59] = iBLOCK[j + 57];
+ }
+ eBLOCK[57] = hl;
+ eBLOCK[58] = hn;
+}
+ */
+
+
+static void decode_burstmap(unsigned char *iBLOCK, unsigned char *eBLOCK,
+ unsigned char *hl, unsigned char *hn) {
+
+ int j;
+
+ for(j = 0; j < 57; j++) {
+ iBLOCK[j] = eBLOCK[j];
+ iBLOCK[j + 57] = eBLOCK[j + 59];
+ }
+ *hl = eBLOCK[57];
+ *hn = eBLOCK[58];
+}
+
+
+/*
+ * Transmitted bits are sent least-significant first.
+ */
+static int compress_bits(unsigned char *dbuf, unsigned int dbuf_len,
+ unsigned char *sbuf, unsigned int sbuf_len) {
+
+ unsigned int i, j, c, pos = 0;
+
+ if(dbuf_len < ((sbuf_len + 7) >> 3))
+ return -1;
+
+ for(i = 0; i < sbuf_len; i += 8) {
+ for(j = 0, c = 0; (j < 8) && (i + j < sbuf_len); j++)
+ c |= (!!sbuf[i + j]) << j;
+ dbuf[pos++] = c & 0xff;
+ }
+ return pos;
+}
+
+
+#if 0
+int get_ns_l3_len(unsigned char *data, unsigned int datalen) {
+
+ if((data[0] & 3) != 1) {
+ fprintf(stderr, "error: get_ns_l3_len: pseudo-length reserved "
+ "bits bad (%2.2x)\n", data[0] & 3);
+ return -1;
+ }
+ return (data[0] >> 2);
+}
+
+#endif
+
+static unsigned char *decode_sacch(unsigned char *e0, unsigned char *e1,
+ unsigned char *e2, unsigned char *e3, unsigned int *datalen) {
+
+ int errors, len, data_size = (DATA_BLOCK_SIZE + 7) >> 3;
+ unsigned char conv_data[CONV_SIZE], iBLOCK[BLOCKS][iBLOCK_SIZE],
+ hl, hn, decoded_data[PARITY_OUTPUT_SIZE], *data;
+
+ if(!(data = (unsigned char *)malloc(data_size))) {
+ throw std::runtime_error("error: decode_cch: malloc");
+ }
+
+ if(datalen)
+ *datalen = 0;
+
+ // unmap the bursts
+ decode_burstmap(iBLOCK[0], e0, &hl, &hn); // XXX ignore stealing bits
+ decode_burstmap(iBLOCK[1], e1, &hl, &hn);
+ decode_burstmap(iBLOCK[2], e2, &hl, &hn);
+ decode_burstmap(iBLOCK[3], e3, &hl, &hn);
+
+ // remove interleave
+ interleave_decode(&opt.ictx, conv_data, (unsigned char *)iBLOCK);
+ //decode_interleave(conv_data, (unsigned char *)iBLOCK);
+
+ // Viterbi decode
+ errors = conv_decode(decoded_data, conv_data);
+ DEBUGF("conv_decode: %d\n", errors);
+ if (errors)
+ return NULL;
+
+ // check parity
+ // If parity check error detected try to fix it.
+ if (parity_check(decoded_data))
+ {
+ fire_crc crc(40, 184);
+ // fprintf(stderr, "error: sacch: parity error (%d)\n", errors);
+ unsigned char crc_result[224];
+ if (crc.check_crc(decoded_data, crc_result) == 0)
+ {
+ errors = -1;
+ DEBUGF("error: sacch: parity error (%d)\n", errors);
+ return NULL;
+ } else {
+ memcpy(decoded_data, crc_result, sizeof crc_result);
+ errors = 0;
+ }
+ }
+
+ if((len = compress_bits(data, data_size, decoded_data,
+ DATA_BLOCK_SIZE)) < 0) {
+ fprintf(stderr, "error: compress_bits\n");
+ return 0;
+ }
+ if(len < data_size) {
+ fprintf(stderr, "error: buf too small (%d < %d)\n",
+ sizeof(data), len);
+ return 0;
+ }
+
+ if(datalen)
+ *datalen = (unsigned int)len;
+ return data;
+}
+
+
+/*
+ * decode_cch
+ *
+ * Decode a "common" control channel. Most control channels use
+ * the same burst, interleave, Viterbi and parity configuration.
+ * The documentation for the control channels defines SACCH first
+ * and then just keeps referring to that.
+ *
+ * The current (investigated) list is as follows:
+ *
+ * BCCH Norm
+ * BCCH Ext
+ * PCH
+ * AGCH
+ * CBCH (SDCCH/4)
+ * CBCH (SDCCH/8)
+ * SDCCH/4
+ * SACCH/C4
+ * SDCCH/8
+ * SACCH/C8
+ *
+ * We provide two functions, one for where all four bursts are
+ * contiguous, and one where they aren't.
+ */
+unsigned char *decode_cch(unsigned char *e0, unsigned char *e1,
+ unsigned char *e2, unsigned char *e3, unsigned int *datalen) {
+
+ return decode_sacch(e0, e1, e2, e3, datalen);
+}
+
+
+unsigned char *decode_cch(unsigned char *e, unsigned int *datalen) {
+
+ return decode_sacch(e, e + eBLOCK_SIZE, e + 2 * eBLOCK_SIZE,
+ e + 3 * eBLOCK_SIZE, datalen);
+}
diff --git a/gsmsp/gsm/src/lib/cch.h b/gsmsp/gsm/src/lib/cch.h
new file mode 100644
index 0000000..e4429a0
--- /dev/null
+++ b/gsmsp/gsm/src/lib/cch.h
@@ -0,0 +1,41 @@
+
+/*
+ * decode_cch
+ *
+ * Decode a "common" control channel. Most control channels use
+ * the same burst, interleave, Viterbi and parity configuration.
+ * The documentation for the control channels defines SACCH first
+ * and then just keeps referring to that.
+ *
+ * The current (investigated) list is as follows:
+ *
+ * BCCH Norm
+ * BCCH Ext
+ * PCH
+ * AGCH
+ * CBCH (SDCCH/4)
+ * CBCH (SDCCH/8)
+ * SDCCH/4
+ * SACCH/C4
+ * SDCCH/8
+ * SACCH/C8
+ *
+ * We provide two functions, one for where all four bursts are
+ * contiguous, and one where they aren't.
+ */
+
+#define DATA_BLOCK_SIZE 184
+#define PARITY_SIZE 40
+#define FLUSH_BITS_SIZE 4
+#define PARITY_OUTPUT_SIZE (DATA_BLOCK_SIZE + PARITY_SIZE + FLUSH_BITS_SIZE)
+
+#define CONV_INPUT_SIZE PARITY_OUTPUT_SIZE
+#define CONV_SIZE (2 * CONV_INPUT_SIZE)
+
+#define BLOCKS 4
+#define iBLOCK_SIZE (CONV_SIZE / BLOCKS)
+#define eBLOCK_SIZE (iBLOCK_SIZE + 2)
+
+unsigned char *decode_cch(unsigned char *, unsigned char *, unsigned char *,
+ unsigned char *, unsigned int *);
+unsigned char *decode_cch(unsigned char *, unsigned int *);
diff --git a/gsmsp/gsm/src/lib/common.cc b/gsmsp/gsm/src/lib/common.cc
new file mode 100644
index 0000000..1666c24
--- /dev/null
+++ b/gsmsp/gsm/src/lib/common.cc
@@ -0,0 +1,87 @@
+/*
+ * $Id: system.c,v 1.1 2003/05/15 12:13:49 skyper Exp $
+ */
+
+#include "common.h"
+#include <stdio.h>
+#include <string.h>
+
+void
+hexdump(const unsigned char *data, size_t len)
+{
+ size_t n = 0;
+ int line = 0;
+
+ if (!len)
+ return;
+
+ printf("%03x: ", line++);
+ while (1)
+ {
+ printf("%2.2x ", data[n++]);
+ if (n >= len)
+ break;
+ if ((n % 8 == 0) && (n % 16 != 0))
+ printf(" - ");
+ if (n % 16 == 0)
+ printf("\n%03x: ", line++);
+ }
+ printf("\n");
+}
+
+#ifndef HAVE_STRLCPY
+/*
+ * bsd'sh strlcpy().
+ * The strlcpy() function copies up to size-1 characters from the
+ * NUL-terminated string src to dst, NUL-terminating the result.
+ * Return: total length of the string tried to create.
+ */
+size_t
+strlcpy(char *dst, const char *src, size_t size)
+{
+ size_t len = strlen(src);
+ size_t ret = len;
+
+ if (size <= 0)
+ return 0;
+ if (len >= size)
+ len = size - 1;
+ memcpy(dst, src, len);
+ dst[len] = 0;
+
+ return ret;
+}
+#endif
+
+/*
+ * Debuggging...
+ * Convert an interger to a bit string and output it.
+ * Most significatn bit first.
+ */
+char *
+int2bit(unsigned int val)
+{
+ static char buf[33 + 3];
+ char *ptr = buf;
+ unsigned int i = 0x1 << 31;
+ int round = 0;
+
+ while (i > 0)
+ {
+
+ if (val & i)
+ *ptr++ = '1';
+ else
+ *ptr++ = '0';
+
+ i = i >> 1;
+
+ if ((++round % 8 == 0) && (i > 0))
+ *ptr++ = '.';
+ }
+
+ *ptr = '\0';
+
+ return buf;
+}
+
diff --git a/gsmsp/gsm/src/lib/common.h b/gsmsp/gsm/src/lib/common.h
new file mode 100644
index 0000000..5ea56ce
--- /dev/null
+++ b/gsmsp/gsm/src/lib/common.h
@@ -0,0 +1,51 @@
+#ifndef __GSMSP_COMMON_H__
+#define __GSMSP_COMMON_H__ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <unistd.h>
+
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#define MAX(a,b) ((a)>(b)?(a):(b))
+
+/* DISABLE me for release build. Otherwise with debug output. */
+//#define GSMSP_DEBUG 1
+
+#ifdef GSMSP_DEBUG
+# define DEBUGF(a...) do { \
+ fprintf(stderr, "DEBUG %s:%d ", __func__, __LINE__); \
+ fprintf(stderr, a); \
+} while (0)
+#else
+# define DEBUGF(a...)
+#endif
+
+# define HEXDUMPF(data, len, a...) do { \
+ printf("HEX %s:%d ", __func__, __LINE__); \
+ printf(a); \
+ hexdump(data, len); \
+} while (0)
+
+void hexdump(const unsigned char *data, size_t len);
+
+#ifndef GSMDECODE
+#include "interleave.h"
+struct _opt
+{
+ INTERLEAVE_CTX ictx;
+};
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !__GSMSP_COMMON_H__ */
+
+
diff --git a/gsmsp/gsm/src/lib/data_out.c b/gsmsp/gsm/src/lib/data_out.c
new file mode 100644
index 0000000..b74b886
--- /dev/null
+++ b/gsmsp/gsm/src/lib/data_out.c
@@ -0,0 +1,2289 @@
+#include "common.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "id_list.h"
+#include "gsm_desc.h"
+
+#define OUTF(a...) do { \
+ printf(" %3d: %02x ", (int)(data - start), data[0]); \
+ printf(a); \
+} while (0)
+
+#define OUT(a...) do { \
+ printf(a); \
+} while (0)
+
+#define RETTRUNK() do { \
+ printf("%s:%d TRUNKATED (0x%p - 0x%p)\n", __func__, __LINE__, data, end); \
+ return; \
+} while (0)
+
+static void l2_rrm();
+static void l2_sms();
+static void l2_cc();
+static void l2_RRsystemInfo1();
+static void l2_MccMncLac();
+static void l2_RRsystemInfo2();
+//static void l2_RRsystemInfo2ter();
+static void l2_RRsystemInfo3C();
+static void l2_RRsystemInfo4C();
+static void l2_RRsystemInfo6();
+static void l2_RRsystemInfo13C();
+static void l2_RRimmediateAssTBFC();
+static void l2_RRassignCommand();
+static void l2_RRassignComplete();
+static void l2_RRpagingrequest1();
+static void l2_RRpagingrequest2();
+static void l2_RRpagingrequest3();
+static void l2_RRimmediateAssignment();
+static void l2_RRimmAssTBFDirEncHoChaC();
+static void l2_MobId();
+static void l2_mmm();
+static void l2_HoppingChannel();
+static void l2_SingleChannel();
+static void l2_HoppingChannelAssCom();
+static void l2_SingleChannelAssCom();
+static void l2_MobileAllocation();
+static void l2_BcchAllocation();
+static void l2_TmsiReallocCommand();
+static void l2_RachControlParameters();
+static void l2_bcc();
+static void l2_Bbis();
+static void l2_ChannelRelease();
+static void l2_MMcmServiceRequest();
+static void l2_RRciphModCmd();
+static void l2_RRciphModCompl();
+static void l2_RRpagingresponse();
+static void l2_RRclassmarkChange();
+
+static void l2_ChannelNeeded(char *str, unsigned char ch);
+static void l2_MNCC(const char *str, unsigned char a, unsigned char b, unsigned char c);
+
+static char *BitRow(unsigned char c, int pos);
+static char *PageMode(unsigned char mode);
+static char *BitRowFill(unsigned char c, unsigned char mask);
+
+static void dcch_address();
+static void dcch_control();
+static void ControlChannelDescription();
+static void CellOptionsBcch();
+static void CellSelectionParameters();
+static void RequestReference();
+static void TimingAdvance();
+static void StartingTime();
+static void l2_NeighbourCellDescription();
+static void CellIdentity();
+static void MSClassMarkTwo();
+static void cpData();
+static void Address(const char *str);
+static void ChannelDescriptionTwo();
+static void CCalerting();
+static void CCsetup();
+static void ProgressIndicator();
+static void Cause();
+static void SmsProtocolDataValidity();
+static void BearerCap();
+static void AuthenticationRequest();
+static void AuthenticationResponse();
+
+static const unsigned char *start;
+static const unsigned char *data;
+static const unsigned char *end;
+
+/*
+ * B-format (and also A-Format)
+ */
+void
+l2_data_out_B(int fn, const unsigned char *input_data, int len)
+{
+ data = input_data;
+ start = data;
+ end = data + len;
+ HEXDUMPF(data, 23 /*len*/, "Format B DATA\n");
+ /* Need at least 3 octets */
+ if (data + 2 >= end)
+ RETTRUNK();
+
+ dcch_address();
+ data++;
+ dcch_control();
+ data++;
+ /* FIXME: Why is extended length always set to 1? */
+ OUTF("%s EL, Extended Length: %s\n", BitRow(data[0], 0), (data[0] & 1)?"y":"n");
+ OUTF("%s M, segmentation: %c\n", BitRow(data[0], 1), ((data[0] >> 1) & 1)?'Y':'N');
+ OUTF("%s Length: %u\n", BitRowFill(data[0], 0xfc), data[0] >> 2);
+ if (data + (data[0] >> 2) < end)
+ end = data + (data[0] >> 2) + 1;
+ data++;
+ if (data >= end)
+ return;
+ l2_Bbis();
+}
+
+static void
+dcch_control()
+{
+ if ((data[0] & 0x03) != 3)
+ {
+ if ((data[0] & 1) == 0)
+ {
+ OUTF("-------0 Information Frame\n");
+ OUTF("%s N(S), Sequence counter: %u\n", BitRowFill(data[0], 0x0e), (data[0] >> 1) & 0x07);
+ OUTF("%s P\n", BitRow(data[0], 4));
+ } else if ((data[0] & 0x03) == 1) {
+ OUTF("------01 Supvervisory Frame\n");
+ if (((data[0] >> 2) & 0x03) == 0)
+ OUTF("----00-- RR Frame (Receive ready)\n");
+ else if (((data[0] >> 2) & 0x03) == 1)
+ OUTF("----01-- RNR Frame (Receive not ready)\n");
+ else if (((data[0] >> 2) & 0x03) == 2)
+ OUTF("----10-- REJ Frame (REJect)\n");
+ else
+ OUTF("----11-- UNKNOWN\n");
+ OUTF("%s Poll/Final bit (P/F)\n", BitRow(data[0], 4));
+ }
+ OUTF("%s N(R), Retransmission counter: %u\n", BitRowFill(data[0], 0xe0), (data[0] >> 5) & 0x07);
+ return;
+ }
+ OUTF("------11 Unnumbered Frame\n");
+ switch (data[0] & 0xec) /* 11101100 */
+ {
+ case 0x6c: /* 011-11-- */
+ OUTF("%s P\n", BitRow(data[0], 4));
+ OUTF("011-11-- SABM frame (Set asynchonous balance mode)\n");
+ break;
+ case 0x0c: /* 000-11-- */
+ OUTF("%s F\n", BitRow(data[0], 4));
+ OUTF("000-11-- DM frame (Disconnected mode)\n");
+ break;
+ case 0x00:
+ OUTF("%s P\n", BitRow(data[0], 4));
+ OUTF("000-00-- UI frame (Unnumbered information)\n");
+ break;
+ case 0x40:
+ OUTF("%s P\n", BitRow(data[0], 4));
+ OUTF("010-00-- DISC frame (DISConnect)\n");
+ break;
+ case 0x60:
+ OUTF("%s P\n", BitRow(data[0], 4));
+ OUTF("011-00-- UA frame (Unnumbered achknowledgement)\n");
+ break;
+ default:
+ OUTF("%s P/F\n", BitRow(data[0], 4));
+ OUTF("%s UNKNOWN\n", BitRowFill(data[0], 0xec));
+ break;
+ }
+}
+
+static void
+dcch_address()
+{
+ if (data[0] & 1)
+ OUTF("-------1 Extended Address: 1 octet long\n");
+ else
+ OUTF("-------0 Extended Address: more octets follow\n");
+
+ if ((data[0] >> 1) & 1)
+ OUTF("------1- C/R: Command\n");
+ else
+ OUTF("------0- C/R: Response\n");
+
+ if (data[0] & 1)
+ {
+ /* SAPI */
+ switch ((data[0] >> 2) & 0x07)
+ {
+ case 0x03:
+ OUTF("---011-- SAPI: SMS and SS\n");
+ break;
+ case 0x00:
+ OUTF("---000-- SAPI: RR, MM and CC\n");
+ break;
+ default:
+ OUTF("%s SAPI: UNKNWON\n", BitRowFill(data[0], 0x1c));
+ break;
+ }
+
+ switch ((data[0] >> 4 ) & 0x03)
+ {
+ case 0x00:
+ OUTF("%s Link Protocol Disciminator: GSM (not Cell Broadcasting)\n", BitRowFill(data[0], 0x60));
+ break;
+ case 0x01:
+ OUTF("%s Link Protocol Disciminator: Cell Broadcasting (CBS)\n", BitRowFill(data[0], 0x60));
+ break;
+ default:
+ OUTF("%s Link Protocol Disciminator: UNKNOWN %u\n", BitRowFill(data[0], 0x60), (data[0] >> 5) & 0x03);
+ }
+ } else {
+ switch ((data[0] >> 2))
+ {
+ case 0x03:
+ OUTF("000011-- SAPI: SMS and SS\n");
+ break;
+ case 0x00:
+ OUTF("000000-- SAPI: RR, MM and CC\n");
+ break;
+ default:
+ OUTF("%s SAPI: UNKNOWN\n", BitRowFill(data[0], 0xfc));
+ break;
+ }
+ data++;
+ if (data >= end)
+ RETTRUNK();
+ if (data[0] & 1)
+ OUTF("-------1 Extended Address: 1 octet long\n");
+ else
+ OUTF("-------0 Extended Address: more octets follow [ERROR]\n");
+ OUTF("%s Terminal Endpoint Identifier (TEI): %u\n", BitRowFill(data[0], 0xfe), data[0] >> 1);
+ }
+}
+
+void
+l2_data_out_Bbis(int fn, const unsigned char *input_data, int len)
+{
+ int i;
+
+
+ if (len <= 0)
+ return;
+
+ data = input_data;
+ start = data;
+
+ i = data[0] >> 2;
+ if (len - 1 < i)
+ OUTF("WARN: packet to short\n");
+ len = MIN(len - 1, i);
+ /* len = number of octets following the length field */
+ end = data + len + 1;
+
+ HEXDUMPF(data, 23 /*len*/, "Format Bbis DATA\n");
+ if (len <= 0)
+ return;
+
+ OUTF("%s Pseudo Length: %d\n", BitRowFill(data[0], 0xfc), data[0] >> 2);
+ data++;
+ l2_Bbis();
+}
+
+static void
+l2_Bbis()
+{
+ if (data >= end)
+ RETTRUNK();
+
+ switch (data[0] >> 7)
+ {
+ case 1:
+ OUTF("1------- Direction: To originating site\n");
+ break;
+ default:
+ OUTF("0------- Direction: From originating site\n");
+ }
+
+ OUTF("%s %d TransactionID\n", BitRowFill(data[0], 0x70), (data[0] >> 4) & 7);
+
+ switch (data[0] & 0x0f)
+ {
+ case 0:
+ OUTF("----0000 Group Call Control [FIXME]\n");
+ break;
+ case 1:
+ OUTF("----0001 Broadcast call control [FIXME]\n");
+ data++;
+ l2_bcc();
+ /* TS GSM 04.69 */
+ break;
+ case 2:
+ OUTF("----0010 PDSS1 [FIXME]\n");
+ break;
+ case 3:
+ OUTF("----0011 Call control. call related SS messages\n");
+ data++;
+ l2_cc();
+ /* TS 24.008 */
+ break;
+ case 4:
+ OUTF("----01-- PDSS2 [FIXME]\n");
+ break;
+ case 5:
+ OUTF("----0101 Mobile Management Message (non GPRS)\n");
+ data++;
+ /* TS 24.008 */
+ l2_mmm();
+ break;
+ case 6:
+ OUTF("----0110 Radio Resouce Management\n");
+ data++;
+ l2_rrm();
+ break;
+ case 7:
+ OUTF("----0111 RFU [FIXME]\n");
+ break;
+ case 8:
+ OUTF("----1000 GPRS Mobile Management\n");
+ /* in GMMattachAccept */
+ /* in GMMidentityRequest */
+ OUTF("FIXME: possible IMEI in here\n");
+ break;
+ case 9:
+ OUTF("----1001 SMS messages\n");
+ data++;
+ l2_sms();
+ /* TS 04.11 */
+ break;
+ case 0x0a:
+ OUTF("----1011 GRPS session management messages [FIXME]\n");
+ break;
+ case 0x0b:
+ OUTF("----1011 Non-call related SS messages [FIXME]\n");
+ /* GSM 04.80 */
+ break;
+ case 0x0c:
+ OUTF("----1100 Location services [FIXME]\n");
+ break;
+ case 0x0d:
+ OUTF("----1101 RFU [FIXME]\n");
+ break;
+ case 0x0e:
+ OUTF("----1110 Extension of the PD to one octet length [FIXME]\n");
+ break;
+ case 0x0f:
+ OUTF("----1111 Tests procedures describe in TS GSM 11.10 [FIXME]\n");
+ break;
+ default:
+ OUTF("%s 0x%02x UNKNOWN\n", BitRowFill(data[0], 0x0f), data[0] & 0x0f);
+ }
+
+}
+
+/*
+ * Broadcast Call Control (04.69)
+ */
+static void
+l2_bcc()
+{
+ if (data >= end)
+ RETTRUNK();
+
+ /* Message type 04.69:9.3*/
+ switch (data[0] & 0x3f)
+ {
+ case 0x06: /* 0-000110 */
+ OUTF("--000110 ???\n");
+ break;
+ default:
+ OUTF("--?????? UNKNOWN [FIXME]\n");
+ return;
+ }
+
+ /* Call reference 04.69:9.4.1*/
+
+ /* Orig indication 04.69:9.5.5*/
+ /* Spare half octet 04.69:9.4.5*/
+
+}
+
+/*
+ * ProtDisc3
+ */
+static void
+l2_cc()
+{
+ if (data >= end)
+ RETTRUNK();
+ OUTF("%s Send Sequence Number: %u\n", BitRowFill(data[0], 0xc0), data[0] >> 6);
+
+ if ((data[0] & 0x3f) == 0x01)
+ {
+ OUTF("--000001 Call Alerting\n");
+ data++;
+ CCalerting();
+ } else if ((data[0] & 0x3f) == 0x02) {
+ OUTF("--000010 Call Proceesing\n");
+ if (++data >= end)
+ return;
+ OUTF("FIXME %s\n", __func__);
+ } else if ((data[0] & 0x3f) == 0x07) {
+ OUTF("--000111 Call Connect\n");
+ if (++data >= end)
+ return;
+ OUTF("FIXME %s\n", __func__);
+ } else if ((data[0] & 0x3f) == 0x08) {
+ OUTF("--001000 Call Confirmed\n");
+ if (++data >= end)
+ return;
+ if (data[0] != 0x04)
+ return;
+ OUTF("--000010 Bearer Capability\n");
+ data++;
+ BearerCap();
+ } else if ((data[0] & 0x3f) == 0x05) {
+ OUTF("--000101 Call Setup\n");
+ data++;
+ CCsetup();
+ } else if ((data[0] & 0x3f) == 0x03) {
+ OUTF("--000011 Call Progress\n");
+ data++;
+ ProgressIndicator();
+ } else if ((data[0] & 0x3f) == 0x0f) {
+ OUTF("--001111 Connect Acknowledge\n");
+ } else if ((data[0] & 0x3f) == 0x25) {
+ OUTF("--100101 Disconnect\n");
+ data++;
+ Cause();
+ } else if ((data[0] & 0x3f) == 0x2d) {
+ OUTF("--101101 CC Release\n");
+ if (++data >= end)
+ RETTRUNK();
+ if (data[0] == 0x08)
+ {
+ data++;
+ Cause();
+ }
+ } else if ((data[0] & 0x3f) == 0x2a) {
+ OUTF("--101010 CC Release Complete\n");
+ if (++data >= end)
+ RETTRUNK();
+ if (data[0] == 0x08)
+ {
+ data++;
+ Cause();
+ }
+ if (data >= end)
+ RETTRUNK();
+ if (data[0] == 0x1c)
+ {
+ /* facility */
+ OUTF("FIXME\n");
+ }
+ } else {
+ OUTF("%s FIXME %s\n", BitRowFill(data[0], 0xff), __func__);
+ }
+}
+
+/*
+ * ----0101
+ * ProtDisc5 - Mobile Management message (non GPRS)
+ */
+static void
+l2_mmm()
+{
+ if (data >= end)
+ return;
+ OUTF("%s SendSequenceNumber: %d\n", BitRowFill(data[0], 0xc0), data[0] >> 6);
+ switch (data[0] & 0x3f)
+ {
+ case 1:
+ //l2_MMimsiDetIndication(data + 1, end);
+ OUTF("--000001 Imsi Det Indication\n"); /* FIXME */
+ OUTF("FIXME: Possible IMSI in here\n");
+ OUTF("FIXME: Possible cipher mode here\n");
+ break;
+ case 2:
+ OUTF("--000010 Location Update Accept\n"); /* FIXME */
+ break;
+ case 4:
+ OUTF("--000100 Message Type: Locatoin Updating Reject\n");
+ break;
+ case 8:
+ OUTF("--001000 MM Location Update Request\n"); /* FIXME */
+ OUTF("FIXME: Possible IMSI in here\n");
+ OUTF("FIXME: Possible cipher mode here\n");
+ break;
+ case 0x12:
+ OUTF("--010010 Authentication Request\n");
+ data++;
+ AuthenticationRequest();
+ break;
+ case 0x14:
+ OUTF("--010100 Authentication Response\n");
+ data++;
+ AuthenticationResponse();
+ break;
+ case 0x19:
+ OUTF("--011001 MMidentityResponse\n");
+ OUTF("FIXME: Possible IMSI in here\n");
+ break;
+ case 0x1a:
+ OUTF("--011010 TMSI Realloc Command\n");
+ data++;
+ l2_TmsiReallocCommand();
+ break;
+ case 0x24: /* --100100 */
+ OUTF("--100100 MMcmServiceRequest\n");
+ data++;
+ l2_MMcmServiceRequest();
+ /* in multisupport2 and others! */
+ break;
+ default:
+ OUTF("UNKNWON\n");
+ }
+}
+
+/*
+ * ProtDisc6 - Radio Resource Management Messages
+ */
+static void
+l2_rrm()
+{
+ if (data >= end)
+ return;
+
+ switch (data[0] & 0x3f)
+ {
+ case 0x00:
+ OUTF("00000000 System Information Type 13\n");
+ data++;
+ l2_RRsystemInfo13C();
+ break;
+ case 0x06:
+ OUTF("00000110 System Information Type 5ter\n");
+ data++;
+ l2_BcchAllocation();
+ break;
+ case 0x0d:
+ OUTF("00001101 Channel Release\n");
+ data++;
+ l2_ChannelRelease();
+ break;
+ case 0x15:
+ OUTF("00010101 RR Measurement Report C [FIXME]\n");
+ break;
+ case 0x16:
+ OUTF("00010110 RRclassmarkChange\n");
+ data++;
+ l2_RRclassmarkChange();
+ break;
+ case 0x19:
+ OUTF("00011001 RRsystemInfo1\n");
+ data++;
+ l2_RRsystemInfo1();
+ break;
+ case 0x1a:
+ OUTF("00011010 RRsystemInfo2\n");
+ data++;
+ l2_RRsystemInfo2();
+ break;
+ case 0x1B: /* 0001 1011 */
+ OUTF("00011011 RRsystemInfo3C\n");
+ data++;
+ l2_RRsystemInfo3C();
+ break;
+ case 0x1c:
+ OUTF("00011100 RRsystemInfo4-C\n");
+ data++;
+ l2_RRsystemInfo4C();
+ break;
+ case 0x1d:
+ /* From SDCCH */
+ OUTF("00011101 Neighbour Cells Description\n");
+ data++;
+ l2_NeighbourCellDescription();
+ break;
+ case 0x1e:
+ /* From SDCCH */
+ OUTF("00011110 System Information Type 6\n");
+ data++;
+ l2_RRsystemInfo6();
+ break;
+ case 0x21:
+ OUTF("00100001 Paging Request Type 1\n");
+ data++;
+ l2_RRpagingrequest1();
+ break;
+ case 0x22:
+ OUTF("00100010 Paging Request Type 2\n");
+ data++;
+ l2_RRpagingrequest2();
+ break;
+ case 0x24:
+ OUTF("00100100 Paging Request Type 3\n");
+ data++;
+ l2_RRpagingrequest3();
+ break;
+ case 0x27:
+ OUTF("0-100111 RRpagingResponse\n");
+ OUTF("-x------ Send sequence number: %d\n", (data[0] >> 7) & 0x01);
+ data++;
+ l2_RRpagingresponse();
+ break;
+ case 0x29:
+ OUTF("0-101001 RR Assign Complete\n");
+ data++;
+ l2_RRassignComplete();
+ break;
+ case 0x2e:
+ OUTF("00101110 RR Assign Command\n");
+ data++;
+ l2_RRassignCommand();
+ break;
+ case 0x32:
+ OUTF("00110010 RR Cipher Mode Complete\n");
+ data++;
+ l2_RRciphModCompl();
+ break;
+ case 0x35:
+ OUTF("00110101 RR Cipher Mode Command\n");
+ data++;
+ l2_RRciphModCmd();
+ break;
+ case 0x3f:
+ OUTF("0-111111 RRimmediateAssignment\n");
+ OUTF("-x------ Send sequence number: %d\n", (data[0] >> 7) & 0x01);
+ data++;
+ l2_RRimmediateAssignment();
+ break;
+ default:
+ OUTF("???????? UNKNOWN. FIXME\n");
+ }
+}
+static void
+l2_RRsystemInfo13C()
+{
+ if (data >= end);
+ return;
+ if (data[0] >> 7)
+ OUTF("1------- SI 13 Restoctet present\n");
+ else
+ OUTF("0------- SI 13 Restoctet NOT present\n");
+ OUTF("%s BCCH_CHANGE_MARK : %d\n", BitRowFill(data[0], 0x70), (data[0] >> 4) & 0x07);
+ switch (data[0] & 0x0f)
+ {
+ case 0x00:
+ OUTF("----0000 SI_CHANGE_FIELD : Update of unspecified SI messages\n");
+ break;
+ case 0x01:
+ OUTF("----00001 SI_CHANGE_FIELD : Update of unspecified SI1 messages\n");
+ break;
+ case 0x02:
+ OUTF("----0010 SI_CHANGE_FIELD : Update of unspecified SI2 messages\n");
+ break;
+ case 0x03:
+ OUTF("----0011 SI_CHANGE_FIELD : Update of unspecified SI3,4,7,8 messages\n");
+ break;
+ case 0x04:
+ OUTF("----0100 SI_CHANGE_FIELD : Update of unspecified SI9 messages\n");
+ break;
+ default:
+ OUTF("----???? Unknown %d\n", data[0] & 0x0f);
+ break;
+ }
+ OUTF("FIXME: implement me\n");
+
+}
+
+static void
+l2_RRimmediateAssignment()
+{
+ if (data >= end)
+ return;
+
+ /* Octect 4, 0x79 */
+ OUTF("%s\n", PageMode(data[0] & 0x03));
+
+ if ((data[0] >> 6) & 0x01)
+ OUTF("-1------ Two messages assign.: 1. message of..(continue)\n");
+ else
+ OUTF("-0------ No meaning\n");
+ if ((data[0] >> 5) & 0x01)
+ OUTF("--1----- Assigns a resource identified in the IA rest octets.\n");
+ else
+ OUTF("--0----- Downlink assig to MS: No meaning\n");
+ if ((data[0] >> 4) & 0x01)
+ {
+ OUTF("---1---- Temporary Block Flow (TBF)\n");
+ data++;
+ l2_RRimmediateAssTBFC();
+ return;
+ }
+ else
+ OUTF("---0---- This messages assigns a dedicated mode resource\n");
+ data++;
+ if (data >= end)
+ return;
+
+ /* Channel Description */
+ ChannelDescriptionTwo();
+
+ if (data >= end)
+ return;
+ if (((data[0] >> 2) & 0x07) == 0)
+ l2_SingleChannel();
+ else if (((data[0] >> 4) & 0x01) == 1)
+ {
+ l2_HoppingChannel();
+ } else {
+ OUTF("xxx0??xxx UNKNOWN %d\n", (data[0] >> 3) & 0x3);
+ }
+}
+
+static void
+l2_SingleChannel()
+{
+ int freq;
+ OUTF("%s Training seq. code: %d\n", BitRowFill(data[0], 0xe0), data[0] >> 5);
+ OUTF("---000-- Single channel\n");
+ freq = (data[0] & 0x03) << 8;
+ data++;
+ if (data >= end)
+ RETTRUNK();
+ freq |= data[0];
+ OUTF("........ Absolute RF channel number: %u\n", freq);
+ data++;
+ RequestReference();
+ TimingAdvance();
+ l2_MobileAllocation();
+ if (data >= end)
+ return;
+}
+
+static void
+l2_HoppingChannel()
+{
+ unsigned char maio = 0;
+ OUTF("%s Training seq. code : %d\n", BitRowFill(data[0], 0xe0), data[0] >> 5);
+ OUTF("---1---- HoppingChannel\n");
+ maio = (data[0] & 0x0f) << 2;
+ data++;
+ if (data >= end)
+ RETTRUNK();
+ maio |= (data[0] >> 6);
+ OUTF("........ MAIO %d\n", maio);
+ OUTF("%s Hopping Seq. Number: %d\n", BitRowFill(data[0], 0x3f), data[0] & 0x3f);
+
+ data++;
+ RequestReference();
+ TimingAdvance();
+ l2_MobileAllocation();
+ if (data >= end)
+ return; /* finished. not truncated! */
+
+ OUTF("FIXME, more data left here???\n");
+}
+
+static void
+l2_MobileAllocation()
+{
+ int c = 64, pos;
+ char *str = "Mobile allocation RF chann.";
+ const unsigned char *thisend;
+
+ if (data >= end)
+ RETTRUNK();
+ OUTF("%s Length of Mobile Allocation: %d\n", BitRowFill(data[0], 0xff), data[0]);
+ thisend = data + data[0] + 1;
+ if (thisend > end)
+ {
+ OUTF("xxxxxxxx ERROR: Packet to short or length to long\n");
+ thisend = end;
+ }
+
+ data++;
+ /* If mobile allocation has length 0 */
+ if (data >= thisend)
+ return;
+
+ while (data < thisend)
+ {
+ pos = 7;
+ while (pos >= 0)
+ {
+ if ((data[0] >> pos) & 1)
+ OUTF("%s %s%d\n", BitRow(data[0], pos), str, c - (7 - pos));
+ pos--;
+
+ }
+
+ c -= 8;
+ data++;
+ if (c <= 0)
+ break;
+ }
+}
+
+/*
+ * From RRsystemInfo2
+ */
+static void
+l2_BcchAllocation()
+{
+ int c, pos;
+ char *str = "BCCH alloc. RF chan.: ";
+
+#if 0
+ /* goeller script for Info2 outputs channels 128 + 127
+ * but opengpa outputs bitmap format for info2.
+ * We do what opengpa does. (correct?)
+ */
+ if ((data[0] >> 7))
+ OUTF("1------- %s%d\n", str, 128);
+ if ((data[0] >> 6) & 1)
+ OUTF("-1------ %s%d\n", str, 127);
+#endif
+ if ((data[0] >> 6) == 0x00)
+ OUTF("00------ Bitmap format: 0\n");
+ else {
+ OUTF("%s Bitmap format: UNKNOWN [FIXME]\n", BitRowFill(data[0], 0xc0));
+ RETTRUNK();
+ }
+
+ if ((data[0] & 0x8e) == 0x8e)
+ {
+ /* From System Information Type 5ter */
+ OUTF("1---111- Variable Bitmap SI5ter [FIXME]\n");
+ return;
+ }
+
+ if ((data[0] >> 5) & 1)
+ OUTF("--1----- Extension Indicator: The IE carries only a part of the BA\n");
+ else
+ OUTF("--0----- Extension Indicator: The IE carries the complete BA\n");
+ OUTF("---x---- BCCH alloc. seq. num: %d\n", (data[0] >> 4) & 1);
+ if ((data[0] >> 3) & 1)
+ OUTF("----1--- %s%d\n", str, 124);
+ if ((data[0] >> 2) & 1)
+ OUTF("-----1-- %s%d\n", str, 123);
+ if ((data[0] >> 1) & 1)
+ OUTF("------1- %s%d\n", str, 122);
+ if (data[0] & 1)
+ OUTF("-------1 %s%d\n", str, 121);
+
+ data++;
+ c = 120;
+ while (data < end)
+ {
+ pos = 7;
+ while (pos >= 0)
+ {
+ if ((data[0] >> pos) & 1)
+ OUTF("%s %s%d\n", BitRow(data[0], pos), str, c - (7 - pos));
+ pos--;
+
+ }
+
+ c -= 8;
+ data++;
+ if (c <= 0)
+ break;
+ }
+}
+
+static void
+l2_RRimmediateAssTBFC()
+{
+ if (data >= end)
+ return;
+
+ /* GPRS Packet Channel Description */
+ OUTF("%s Channel Type : %d\n", BitRowFill(data[0], 0xf8), data[0] >> 3);
+ OUTF("%s Time Slot Number : %d\n", BitRowFill(data[0], 0x07), data[0] & 0x07);
+ data++;
+ if (data >= end)
+ return;
+
+ OUTF("%s Tranining Sequence Code: %d\n", BitRowFill(data[0], 0xe0), data[0] >> 5);
+ if ((data[0] >> 4) & 0x01)
+ {
+ OUTF("---1---- Direct Encoding of Hopping Channels\n");
+ l2_RRimmAssTBFDirEncHoChaC();
+ return;
+ } else {
+ OUTF("---0---- non-hopping RF channel config or indirect encoding of hopping RFCC\n");
+ }
+
+ if ((data[0] >> 3) & 0x01)
+ {
+ OUTF("----1--- indirect encoding of hopping RF channel config\n");
+ } else {
+ OUTF("----0--- RRimmAssTBFaRFCN-C FIXME\n");
+ return;
+ }
+
+ data++;
+ if (data >= end)
+ RETTRUNK();
+ OUTF("xxxxxxxx MAIO [FIXME]\n");
+
+ data++;
+ RequestReference();
+ TimingAdvance();
+ l2_MobileAllocation();
+ if (data >= end)
+ RETTRUNK();
+ OUTF("FIXME: implenet\n");
+}
+
+static void
+l2_RRsystemInfo1()
+{
+ int ca;
+
+ if (data + 1 >= end)
+ return;
+ switch (data[0] >> 6)
+ {
+ case 0x00:
+ OUTF("00------ Bitmap 0 format\n");
+ break;
+ case 0x01:
+ OUTF("10------ Bitmap format: (FIXME)\n");
+ break;
+ default:
+ OUTF("%s Bitmap %d format (FIXME)\n", BitRowFill(data[0], 0xc0), data[0] >> 6);
+ }
+ if ((data[0] >> 3) & 1)
+ OUTF("----1--- Cell Allocation : ARFCN 124\n");
+ if ((data[0] >> 2) & 1)
+ OUTF("-----1-- Cell Allocation : ARFCN 123\n");
+ if ((data[0] >> 1) & 1)
+ OUTF("------1- Cell Allocation : ARFCN 122\n");
+ if (data[0] & 1)
+ OUTF("-------1 Cell Allocation : ARFCN 121\n");
+
+ ca = 120;
+ while (ca > 0)
+ {
+ data++;
+ if (data >= end)
+ return;
+ if ((data[0] >> 7) & 1)
+ OUTF("1------- Cell Allocation : ARFCN %d\n", ca);
+ if ((data[0] >> 6) & 1)
+ OUTF("-1------ Cell Allocation : ARFCN %d\n", ca - 1);
+ if ((data[0] >> 5) & 1)
+ OUTF("--1----- Cell Allocation : ARFCN %d\n", ca - 2);
+ if ((data[0] >> 4) & 1)
+ OUTF("---1---- Cell Allocation : ARFCN %d\n", ca - 3);
+ if ((data[0] >> 3) & 1)
+ OUTF("----1--- Cell Allocation : ARFCN %d\n", ca - 4);
+ if ((data[0] >> 2) & 1)
+ OUTF("-----1-- Cell Allocation : ARFCN %d\n", ca - 5);
+ if ((data[0] >> 1) & 1)
+ OUTF("------1- Cell Allocation : ARFCN %d\n", ca - 6);
+ if (data[0] & 1)
+ OUTF("-------1 Cell Allocation : ARFCN %d\n", ca - 7);
+
+ ca -= 8;
+ }
+
+ data++;
+
+ l2_RachControlParameters();
+ OUTF("FIXME: NCH Position\n");
+ if (data >= end)
+ return;
+}
+
+static void
+l2_RachControlParameters()
+{
+ int ca = -1;
+
+ if (data >= end)
+ return;
+
+ if (((data[0] >> 6) & 0x03) == 0)
+ ca = 1;
+ else if (((data[0] >> 6) & 0x03) == 0x01)
+ ca = 2;
+ else if (((data[0] >> 6) & 0x03) == 0x02)
+ ca = 4;
+ else if (((data[0] >> 6) & 0x03) == 0x03)
+ ca = 7;
+ OUTF("%s Max. of retransmiss : %u\n", BitRowFill(data[0], 0xc0), ca);
+ if (((data[0] >> 2) & 0x0f) <= 9)
+ {
+ ca = ((data[0] >> 2) & 0x0f) + 3;
+ } else {
+ switch ((data[0] >> 2) & 0x0f)
+ {
+ case 10: /* --1010-- */
+ ca = 14;
+ break;
+ case 11:
+ ca = 16;
+ break;
+ case 12:
+ ca = 20;
+ break;
+ case 13:
+ ca = 25;
+ break;
+ case 14:
+ ca = 32;
+ break;
+ case 15:
+ ca = 50;
+ break;
+ default:
+ ca = -1;
+ break;
+ }
+ }
+ OUTF("%s slots to spread TX : %u\n", BitRowFill(data[0], 0x3c), ca);
+ switch ((data[0] >> 1) & 0x01)
+ {
+ case 0:
+ OUTF("------0- The cell is barred : no\n");
+ break;
+ case 1:
+ OUTF("------1- The cell is barred : yes\n");
+ break;
+ }
+
+ switch (data[0] & 0x01)
+ {
+ case 0:
+ OUTF("-------0 Call reestabl.i.cell: allowed\n");
+ break;
+ case 1:
+ OUTF("-------1 Cell reestabl.i.cell: not allowed\n");
+ }
+
+ data++;
+ if (data >= end)
+ return;
+ switch ((data[0] >> 2) & 0x01)
+ {
+ case 0:
+ OUTF("-----0-- Emergency call EC 10: allowed\n");
+ break;
+ case 1:
+ OUTF("-----1-- Emergency call EC 10: not allowed\n");
+ break;
+ }
+ OUTF("%s Acc ctrl cl 11-15: 0 = permitted, 1 = forbidden\n", BitRowFill(data[0], 0xf8));
+ OUTF("%s Acc ctrl cl 8- 9: 0 = permitted, 1 = forbidden\n", BitRowFill(data[0], 0x03));
+ OUTF("%s Ordinary subscribers (8)\n", BitRowFill(data[0], 0x01));
+ OUTF("%s Ordinary subscribers (9)\n", BitRowFill(data[0], 0x02));
+ OUTF("%s Emergency call (10): %s\n", BitRowFill(data[0], 0x04), ((data[0] >> 4) & 1)?"Class 11-15 only":"Everyone");
+ OUTF("%s Operator Specific (11)\n", BitRowFill(data[0], 0x08));
+ OUTF("%s Security service (12)\n", BitRowFill(data[0], 0x10));
+ OUTF("%s Public service (13)\n", BitRowFill(data[0], 0x20));
+ OUTF("%s Emergency service (14)\n", BitRowFill(data[0], 0x40));
+ OUTF("%s Network Operator (15)\n", BitRowFill(data[0], 0x80));
+ data++;
+ if (data >= end)
+ RETTRUNK();
+ OUTF("%s Acc ctrl cl 0- 7: 0 = permitted, 1 = forbidden\n", BitRowFill(data[0], 0xff));
+ OUTF("%s Ordinary subscribers (0-7)\n", BitRowFill(data[0], 0xff));
+ data++;
+}
+
+static char *
+BitRow(unsigned char c, int pos)
+{
+ unsigned char bit = 0;
+ static char buf[9];
+
+ if ((c >> pos) & 1)
+ bit = 1;
+
+ if (pos == 0)
+ snprintf(buf, sizeof buf, "-------%d", bit);
+ else if (pos == 1)
+ snprintf(buf, sizeof buf, "------%d-", bit);
+ else if (pos == 2)
+ snprintf(buf, sizeof buf, "-----%d--", bit);
+ else if (pos == 3)
+ snprintf(buf, sizeof buf, "----%d---", bit);
+ else if (pos == 4)
+ snprintf(buf, sizeof buf, "---%d----", bit);
+ else if (pos == 5)
+ snprintf(buf, sizeof buf, "--%d-----", bit);
+ else if (pos == 6)
+ snprintf(buf, sizeof buf, "-%d------", bit);
+ else if (pos == 7)
+ snprintf(buf, sizeof buf, "%d-------", bit);
+
+ return buf;
+}
+
+static char *
+BitRowFill(unsigned char c, unsigned char mask)
+{
+ static char buf[9];
+
+ memset(buf, '-', sizeof buf);
+ buf[sizeof buf - 1] = '\0';
+ int i = 0;
+ while (i < 8)
+ {
+ if ((mask >> i) & 1)
+ {
+ if ((c >> i) & 1)
+ buf[7 - i] = '1';
+ else
+ buf[7 - i] = '0';
+ }
+ i++;
+ }
+
+ return buf;
+}
+
+static void
+l2_RRsystemInfo2()
+{
+ if (data >= end)
+ RETTRUNK();
+
+ l2_BcchAllocation();
+ if (data >= end)
+ RETTRUNK();
+
+ int c = 7;
+ while (c >= 0)
+ {
+ if ((data[0] >> c) & 1)
+ OUTF("%s BCCH carrier with NCC = %d is permitted for monitoring\n", BitRow(data[0], c), c);
+ c--;
+ }
+ data++;
+ if (data >= end)
+ RETTRUNK();
+
+ l2_RachControlParameters();
+
+ if (data > end) /* Note: not >= */
+ RETTRUNK();
+}
+
+#if 0
+static void
+l2_RRsystemInfo2ter()
+{
+ if (data >= end)
+ return;
+ if ((data[0] >> 7) == 0)
+ OUTF("%s Bitmap 0 format\n", BitRowFill(data[0], 0x8e));
+ else {
+ /* 0x8e = 10001110 */
+ if (((data[0] >> 1) & 0x07) == 0x04)
+ OUTF("1---100- 1024 range\nFIXME\n");
+ else if (((data[0] >> 1) & 0x07) == 0x05)
+ OUTF("1---101- 512 range\nFIXME\n");
+ else if (((data[0] >> 1) & 0x07) == 0x06)
+ OUTF("1---110- 128 range\nFIXME\n");
+ else if (((data[0] >> 1) & 0x07) == 0x07)
+ OUTF("1---111- variable Bitmap\nFIXME\n");
+ else
+ OUTF("1---xxx- UNKNOWN 0x%08x\n", data[0]);
+ }
+ OUTF("FIXME\n");
+}
+#endif
+
+
+/*
+ * RRsystemInfo4-C
+ */
+static void
+l2_RRsystemInfo4C()
+{
+ if (data + 2 >= end)
+ RETTRUNK();
+ l2_MccMncLac();
+ CellSelectionParameters();
+ l2_RachControlParameters();
+ if (data >= end)
+ RETTRUNK();
+ OUTF("FIXME\n");
+}
+
+/*
+ * Output MCC, MNC and LAC. consume 5 bytes.
+ */
+static void
+l2_MccMncLac()
+{
+ if (data + 2 >= end)
+ return;
+ unsigned short lac;
+
+ l2_MNCC("Mobile Country Code", data[0] & 0x0f, (data[0] >> 4) & 0x0f, data[1] & 0x0f);
+ data++;
+ l2_MNCC("Mobile Network Code", data[1] & 0x0f, (data[1] >> 4) & 0x0f, (data[0] >> 4) & 0x0f);
+ data += 2;
+
+ if (data + 1 >= end)
+ return;
+
+ lac = data[0];
+ lac = (lac << 8) | data[1];
+ OUTF("%-8u [0x%02x%02x] Local Area Code\n", lac, data[0], data[1]);
+ data += 2;
+}
+/*
+ * RRsystemINfo3-C
+ */
+static void
+l2_RRsystemInfo3C()
+{
+ CellIdentity();
+ l2_MccMncLac();
+
+ ControlChannelDescription();
+ CellOptionsBcch();
+ CellSelectionParameters();
+ l2_RachControlParameters();
+
+ /* FIXME: complete here */
+}
+
+static void
+l2_RRsystemInfo6()
+{
+ CellIdentity();
+ l2_MccMncLac();
+ CellOptionsBcch();
+ if (data >= end)
+ RETTRUNK();
+ OUTF("%s Network Colour Code: %u\n", BitRowFill(data[0], 0xff), data[0]);
+}
+
+static void
+CellIdentity()
+{
+ unsigned short id;
+
+ if (data + 1 >= end)
+ return;
+
+ id = data[0];
+ id = (id << 8) | data[1];
+ OUTF("%-8u [0x%02x%02x] Cell identity\n", id, data[0], data[1]);
+ data += 2;
+}
+
+static void
+ControlChannelDescription()
+{
+ if (data >= end)
+ RETTRUNK();
+ OUTF("%s Spare bit (should be 0)\n", BitRow(data[0], 7));
+ if ((data[0] >> 6) & 1)
+ OUTF("-1------ MSs in the cell shall apply IMSI attach/detach procedure\n");
+ else
+ OUTF("-0------ MSs in cell are not allowed attach/detach procedure\n");
+ OUTF("%s Number of blocks: %u\n", BitRowFill(data[0], 0x38), (data[0] >> 3) & 0x07);
+
+ switch (data[0] & 0x07)
+ {
+ case 0x00:
+ OUTF("-----000 1 basic physical channel for CCCH, not combined with SDCCHs\n");
+ break;
+ case 0x01:
+ OUTF("-----001 1 basic physical channel for CCCH, combined with SDCCHs\n");
+ break;
+ case 0x02:
+ OUTF("-----010 2 basic physical channel for CCCH, not combined with SDCCHs\n");
+ break;
+ case 0x04:
+ OUTF("-----100 3 basic physical channel for CCCH, not combined with SDCCHs\n");
+ break;
+ case 0x06:
+ OUTF("-----110 4 basic physical channel for CCCH, not combined with SDCCHs\n");
+ break;
+ default:
+ OUTF("%s Unknown CCCH config (ERROR)\n", BitRowFill(data[0], 0x07));
+ break;
+ }
+
+ data++;
+ if (data >= end)
+ RETTRUNK();
+
+ OUTF("%s spare bits (should be 0)\n", BitRowFill(data[0], 0xf8));
+ OUTF("%s %u multi frames period for paging request\n", BitRowFill(data[0], 0x07), (data[0] & 0x07) + 2);
+
+ data++;
+ if (data >= end)
+ RETTRUNK();
+ OUTF("%s T3212 TimeOut value: %u\n", BitRowFill(data[0], 0xff), data[0]);
+ data++;
+}
+
+static void
+CellOptionsBcch()
+{
+ if (data >= end)
+ RETTRUNK();
+ OUTF("%s spare bit (should be 0)\n", BitRowFill(data[0], 0x80));
+ if ((data[0] >> 6) & 1)
+ OUTF("-1------ Power control indicator is set\n");
+ else
+ OUTF("-0------ Power control indicator is not set\n");
+
+ if (((data[0] >> 4) & 0x03) == 0x00)
+ OUTF("--00---- MSs may use uplink DTX\n");
+ else if (((data[0] >> 4) & 0x03) == 0x01)
+ OUTF("--01---- MSs shall use uplink DTX\n");
+ else if (((data[0] >> 4) & 0x03) == 0x02)
+ OUTF("--10---- MSs shall not use uplink DTX\n");
+ else
+ OUTF("%s DTX UNKNOWN [ERROR]\n", BitRowFill(data[0], 0x30));
+
+ OUTF("%s Radio Link Timeout: %u\n", BitRowFill(data[0], 0x0f), ((data[0] & 0x0f) + 1 ) * 4);
+ data++;
+}
+
+static void
+l2_MNCC(const char *str, unsigned char a, unsigned char b, unsigned char c)
+{
+ char buf[128];
+ char f[12];
+
+ snprintf(f, sizeof f, "%x%x%x", a, b, c);
+ /* Nokia netmonitor shows NC's like '30F' and '10F' */
+ snprintf(buf, sizeof buf, "%-8s %s\n", f, str);
+
+#if 0
+ buf[0] = '\0';
+ if (a != 0x0f)
+ {
+ snprintf(buf, sizeof buf, "%x", a);
+ if (b != 0x0f)
+ {
+ snprintf(buf + 1, sizeof buf - 1, "%x", b);
+ if (c != 0x0f)
+ snprintf(buf + 2, sizeof buf - 2, "%x", c);
+ }
+ }
+ snprintf(buf + strlen(buf), sizeof buf - strlen(buf), " - %s\n", str);
+#endif
+
+ OUTF(buf);
+}
+
+static char *
+PageMode(unsigned char mode)
+{
+ switch (mode)
+ {
+ case 0:
+ return "------00 Page Mode: Normal paging";
+ case 1:
+ return "------01 Page Mode: Extended paging";
+ case 2:
+ return "------10 Page Mode: Paging reorganisation";
+ case 3:
+ return "------11 Page Mode: reserved / same as before";
+ }
+
+ return "------?? UNKNOWN\n";
+}
+
+static void
+l2_RRpagingrequest1()
+{
+ if (data >= end)
+ return;
+
+ OUTF("%s\n", PageMode(data[0] & 0x3));
+
+ /* FIXME complete here */
+
+ data++;
+ if (data >= end)
+ return;
+
+ l2_MobId();
+ if (data >= end)
+ return; /* sometimes it's end here */
+ if (data[0] == 0x17)
+ {
+ data++;
+ l2_MobId();
+ return;
+ }
+ OUTF("ERR: wrong data\n");
+}
+
+static void
+l2_ChannelNeeded(char *str, unsigned char ch)
+{
+ switch (ch)
+ {
+ case 0x00:
+ OUTF("%s Channel Needed: Any channel\n", str);
+ break;
+ case 0x01:
+ OUTF("%s Channel Needed: SDCCH\n", str);
+ break;
+ case 0x02:
+ OUTF("%s Channel Needed: TCH/F (Full rate)\n", str);
+ break;
+ case 0x03:
+ OUTF("%s Channel Needed: TCH/H or TCH/F (Dual rate)\n", str);
+ break;
+ }
+
+}
+
+static void
+l2_RRpagingrequest2()
+{
+ if (data >= end)
+ return;
+ OUTF("%s\n", PageMode(data[0] & 0x03));
+
+ l2_ChannelNeeded("--xx---- (first)", (data[0] >> 4) & 0x03);
+ l2_ChannelNeeded("xx------ (second)", data[0] >> 6);
+
+ data++;
+ if (data + 3 >= end)
+ RETTRUNK();
+ OUTF("........ Mob. Ident 1 (P)TMSI: %02X%02X%02X%02X\n", data[0], data[1], data[2], data[3]);
+ data += 4;
+ if (data + 3 >= end)
+ RETTRUNK();
+ OUTF("........ Mob. Ident 2 (P)TMSI: %02X%02X%02X%02X\n", data[0], data[1], data[2], data[3]);
+ data += 4;
+ if (data >= end)
+ RETTRUNK();
+
+ if (data[0] == 0x17)
+ {
+ data++;
+ l2_MobId();
+ return;
+ }
+
+ OUTF("FIXME, unknown\n");
+}
+
+static void
+l2_RRpagingrequest3()
+{
+ if (data >= end)
+ RETTRUNK();
+ OUTF("%s\n", PageMode(data[0] & 0x03));
+ l2_ChannelNeeded("--xx---- (first)", (data[0] >> 4) & 0x03);
+ l2_ChannelNeeded("xx------ (second)", data[0] >> 6);
+ data++;
+
+ int c = 0;
+ while (c++ < 4)
+ {
+ if (data + 3 >= end)
+ RETTRUNK();
+ OUTF("........ Mob. Ident %u (P)TMSI: %02X%02X%02X%02X\n", c, data[0], data[1], data[2], data[3]);
+ data += 4;
+ }
+}
+
+static void
+l2_MobId()
+{
+ const unsigned char *thisend = end;
+ unsigned char len = data[0];
+ char odd = 0;
+ int bcd = 0;
+
+ data++;
+ if (data >= end)
+ return;
+
+ if ((data[0] >> 3) & 1)
+ odd = 1;
+
+ switch (data[0] & 0x07)
+ {
+ case 0:
+ OUTF("-----000 Type of identity: No Identity\n");
+ break;
+ case 1:
+ OUTF("-----001 Type of identity: IMSI\n");
+ bcd = 1;
+ break;
+ case 2:
+ OUTF("-----010 Type of identity: IMEI\n");
+ bcd = 1;
+ break;
+ case 3:
+ OUTF("-----011 Type of identity: IMEISV\n");
+ bcd = 1;
+ break;
+ case 4:
+ OUTF("-----100 Type of identity: TMSI/P-TMSI\n");
+ break;
+ default:
+ OUTF("-----000 Type of identity: UNKNOWN\n");
+ return;
+ }
+ if (len <= 0)
+ return;
+
+ /* Nokia Netmonitor never outputs the first value */
+ //OUTF("%x", data[0] >> 4);
+ unsigned char c;
+ c = data[0] >> 4;
+ len--;
+ data++;
+ if (len <= 0)
+ return;
+
+ OUTF("-------- ID(%d/%s): ", len, odd?"odd":"even");
+
+ if (data + len < thisend)
+ thisend = data + len;
+ if (bcd)
+ {
+ OUT("%X", c);
+ while (data < thisend)
+ {
+ if ((data + 1 == thisend) && (!odd))
+ OUT("%X", data[0] & 0x0f);
+ else
+ OUT("%X%X", data[0] & 0x0f, (data[0] >> 4) & 0x0f);
+ data++;
+ }
+ } else {
+ while (data < thisend)
+ {
+ if ((data + 1 == thisend) && (odd))
+ OUT("%X", (data[0] >> 4 ) & 0x0f);
+ else
+ OUT("%X%X", (data[0] >> 4) & 0x0f, data[0] & 0x0f);
+ data++;
+ }
+ }
+ OUT("\n");
+}
+
+
+static void CellSelectionParameters()
+{
+ if (data >= end)
+ RETTRUNK();
+
+ switch (data[0] >> 5)
+ {
+ case 0:
+ OUTF("000----- Cell Reselect Hyst. : 0 db RXLEV\n");
+ break;
+ case 1:
+ OUTF("001----- Cell Reselect Hyst. : 2 db RXLEV\n");
+ break;
+ case 2:
+ OUTF("010----- Cell Reselect Hyst. : 4 db RXLEV\n");
+ break;
+ case 3:
+ OUTF("011----- Cell Reselect Hyst. : 6 db RXLEV\n");
+ break;
+ case 4:
+ OUTF("100----- Cell Reselect Hyst. : 8 db RXLEV\n");
+ break;
+ case 5:
+ OUTF("101----- Cell Reselect Hyst. : 10 db RXLEV\n");
+ break;
+ case 6:
+ OUTF("110----- Cell Reselect Hyst. : 12 db RXLEV\n");
+ break;
+ case 7:
+ OUTF("111----- Cell Reselect Hyst. : 14 db RXLEV\n");
+ break;
+ }
+ OUTF("---xxxxx Max Tx power level: %d\n", data[0] & 0x1f);
+ data++;
+ if (data >= end)
+ RETTRUNK();
+
+ if (data[0] >> 7)
+ OUTF("1------- Additional cells in SysInfo 16,17\n");
+ else
+ OUTF("0------- No additional cells in SysInfo 7-8\n");
+ if ((data[0] >> 6) & 1)
+ OUTF("-1------ New establishm cause: supported\n");
+ else
+ OUTF("-0------ New establishm cause: not supported\n");
+ OUTF("--xxxxxx RXLEV Access Min permitted = -110 + %ddB\n", data[0] & 0x3f);
+ data++;
+}
+
+static void
+l2_RRimmAssTBFDirEncHoChaC()
+{
+ unsigned char maio = (data[0] & 0x0f) << 4;
+
+ data++;
+ if (data >= end)
+ RETTRUNK();
+ maio |= (data[0] >> 6);
+ OUTF("xxxxxxxx MAIO: %u\n", maio);
+ OUTF("%s HSN: %u\n", BitRowFill(data[0], 0x3f), data[0] & 0x3f);
+ data++;
+
+ RequestReference();
+
+ TimingAdvance();
+ l2_MobileAllocation();
+
+ if (data >= end)
+ RETTRUNK();
+ if (data[0] == 0x7c)
+ {
+ StartingTime();
+ return;
+ }
+ OUTF("FIXME: implement me\n");
+}
+
+static void
+RequestReference()
+{
+ if (data >= end)
+ RETTRUNK();
+
+ /* Request Reference */
+ if ((data[0] >> 5) == 0)
+ OUTF("000----- Establishing Cause : All other cases\n");
+ else if ((data[0] >> 5) == 0x01)
+ OUTF("001----- Establishing Cause : All other cases\n");
+ else if ((data[0] >> 5) == 0x02)
+ OUTF("010----- Establishing Cause : All other cases\n");
+ else if ((data[0] >> 5) == 0x03)
+ OUTF("011----- Establishing Cause : All other cases\n");
+ else if ((data[0] >> 5) == 0x04)
+ OUTF("100----- Establishing Cause: Answer to paging\n");
+ else if ((data[0] >> 5) == 0x05)
+ OUTF("101----- Establishing Cause: Emergency call\n");
+ else if ((data[0] >> 5) == 0x07)
+ OUTF("111----- Establishing Cause: Other services req. by user\n");
+/* Random refernce must be 5 bit long ?! */
+// else if ((data[0] >> 4) == 0x05)
+// OUTF("0101---- Establishing Cause: Originating data call from dual rate mobile station\n");
+// else if ((data[0] >> 4) == 0x02)
+// OUTF("0010---- Establishing Cause: Answer to paging\n");
+ else
+ OUTF("%s Establishing Cause: UNKNOWN [FIXME}\n", BitRowFill(data[0], 0xe0));
+
+ OUTF("---xxxxx Random Reference : %d\n", data[0] & 0x1f);
+
+ data++;
+ if (data + 1>= end)
+ RETTRUNK();
+
+ OUTF("xxxxxxxx T1/T2/T3\n");
+ data++;
+ OUTF("xxxxxxxx T1/T2/T3\n");
+ data++;
+ /* END Request Reference */
+}
+
+static void
+TimingAdvance()
+{
+ if (data >= end)
+ RETTRUNK();
+ OUTF("--xxxxxx Timing advance value: %d\n", data[0] & 0x3f);
+ data++;
+}
+
+static void
+StartingTime()
+{
+ if (data >= end)
+ RETTRUNK();
+ OUTF("01111100 Starting Time block\n");
+ data++;
+ if (data >= end)
+ RETTRUNK();
+ unsigned char t3;
+ OUTF("%s T1 Frame Number: %u\n", BitRowFill(data[0], 0xf8), data[0] >> 3);
+ t3 = (data[0] & 0x07) << 5;
+ data++;
+ if (data >= end)
+ RETTRUNK();
+ t3 |= (data[0] >> 5);
+ OUTF("%s T2 Frame Number: %u\n", BitRowFill(data[0], 0x1f), data[0] & 0x1f);
+ OUTF("........ T3 Frame Number: %u\n", t3);
+}
+
+/*
+ * RRsystemInfo5
+ */
+static void
+l2_NeighbourCellDescription()
+{
+ if (data >= end)
+ RETTRUNK();
+ l2_BcchAllocation();
+}
+
+
+static void
+l2_ChannelRelease()
+{
+ if (data >= end)
+ RETTRUNK();
+ OUTF("%s\n", id_list_get(list_ChannelRelease, data[0]));
+ data++;
+}
+
+static void
+l2_MMcmServiceRequest()
+{
+ if (data >= end)
+ RETTRUNK();
+
+ OUTF("%s Ciphering key sequence: %u\n", BitRowFill(data[0], 0x70), (data[0] >> 4) & 0x07);
+ OUTF("%s\n", id_list_get(list_RequestServiceType, data[0] & 0x0f));
+ data++;
+ MSClassMarkTwo();
+ if (data >= end)
+ RETTRUNK();
+
+ if (data[0] == 0x20)
+ {
+ OUTF("FIXME: classmark3\n");
+ return;
+ }
+
+ l2_MobId();
+}
+
+static void
+MSClassMarkTwo()
+{
+ if (data >= end)
+ RETTRUNK();
+
+ OUTF("%s MS Classmark 2 length: %u\n", BitRowFill(data[0], 0xff), data[0]);
+ data++;
+ if (data >= end)
+ RETTRUNK();
+
+ if (((data[0] >> 5) & 0x03) == 0)
+ OUTF("-00----- Revision Level: Phase 1\n");
+ else if (((data[0] >> 5) & 0x03) == 1)
+ OUTF("-01----- Revision Level: Phase 2\n");
+ else
+ OUTF("-xx----- Revision Level: Unknown\n");
+ if (((data[0] >> 4) & 1) == 0)
+ OUTF("---0---- Controlled early classmark sending: Not implemented\n");
+ else
+ OUTF("---1---- Controlled early classmark sending: Implemented\n");
+ if ((data[0] >> 3) & 1)
+ OUTF("----1--- A5/1 not available\n");
+ else
+ OUTF("----0--- A5/1 available\n");
+
+ OUTF("%s RF power class capability: Class %u\n", BitRowFill(data[0], 0x07), (data[0] & 0x07) + 1);
+
+ data++;
+
+ if ((data[0] >> 6) & 1)
+ OUTF("-1------ Pseudo Sync Capability: present\n");
+ else
+ OUTF("-1------ Pseudo Sync Capability: not present\n");
+
+ if (((data[0] >> 4) & 0x03) == 0)
+ OUTF("--00---- SS Screening: Phase 1 default value\n");
+ else if (((data[0] >> 4) & 0x03) == 1)
+ OUTF("--01---- SS Screening: Phase 2 error handling\n");
+ else
+ OUTF("--xx---- SS Screening: UNKNOWN\n");
+
+ if ((data[0] >> 3) & 1)
+ OUTF("----1--- Mobile Terminated Point to Point SMS: supported\n");
+ else
+ OUTF("----0--- Mobile Terminated Point to Point SMS: not supported\n");
+
+ if ((data[0] >> 2) & 1)
+ OUTF("-----1-- VoiceBroadcastService: supported\n");
+ else
+ OUTF("-----0-- VoiceBroadcastService: not supported\n");
+
+ if ((data[0] >> 1) & 1)
+ OUTF("------1- VoiceGroupCallService: supported\n");
+ else
+ OUTF("------0- VoiceGroupCallService: not supported\n");
+
+ if (data[0] & 1)
+ OUTF("-------1 MS supports E-GSM or R-GSM: supported\n");
+ else
+ OUTF("-------0 MS supports E-GSM or R-GSM: not supported\n");
+
+ data++;
+ if (data >= end)
+ RETTRUNK();
+
+
+ if ((data[0] >> 7) & 1)
+ OUTF("1------- CM3 option: supported\n");
+ else
+ OUTF("0------- CM3 option: not supported\n");
+
+ if ((data[0] >> 5) & 1)
+ OUTF("--1----- LocationServiceValueAdded Capability: supported\n");
+ else
+ OUTF("--0----- LocationServiceValueAdded Capability: not supported\n");
+
+ if ((data[0] >> 3) & 1)
+ OUTF("----1--- SoLSA Capability: supported\n");
+ else
+ OUTF("----0--- SoLSA Capability: not supported\n");
+
+ if ((data[0] >> 1) & 1)
+ OUTF("------1- A5/3 available\n");
+ else
+ OUTF("------0- A5/3 not available\n");
+
+ if (data[0] & 1)
+ OUTF("-------1 A5/2: available\n");
+ else
+ OUTF("-------0 A5/2: not available\n");
+ data++;
+}
+
+static void
+l2_RRciphModCmd()
+{
+ if (data >= end)
+ RETTRUNK();
+ if (((data[0] >> 1) & 0x07) == 0x07)
+ OUTF("----111- Cipher: reserved [UNKNOWN]\n");
+ else
+ OUTF("%s Cipher: A5/%u\n", BitRowFill(data[0], 0x0e), ((data[0] >> 1) & 0x07) + 1);
+
+
+ if (data[0] & 1)
+ OUTF("-------1 Start ciphering\n");
+ else
+ OUTF("-------0 No ciphering\n");
+
+ if ((data[0] >> 4) & 1)
+ OUTF("---1---- Cipher Response: IMEISV shall be included\n");
+ else
+ OUTF("---0---- Cipher Response: IMEISV shall not be included\n");
+ data++;
+}
+
+static void
+l2_RRciphModCompl()
+{
+ if (data >= end)
+ RETTRUNK();
+
+ if (data[0] != 0x17)
+ return;
+ if (++data >= end)
+ RETTRUNK();
+ l2_MobId();
+}
+
+static void
+l2_TmsiReallocCommand()
+{
+ if (data >= end)
+ RETTRUNK();
+
+ l2_MccMncLac();
+ l2_MobId();
+}
+
+static void
+l2_sms()
+{
+ if (data >= end)
+ RETTRUNK();
+
+ if ((data[0] == 0x04))
+ OUTF("00000100 Type: CP-ACK\n");
+ else if (data[0] == 0x10)
+ OUTF("00010000 Type: CP-ERROR\n");
+ else if (data[0] == 1) {
+ OUTF("00000001 Type: CP-DATA\n");
+ data++;
+ cpData();
+ } else
+ OUTF("%s UNKNOWN\n", BitRowFill(data[0], 0xff));
+}
+
+static void
+cpDataUp()
+{
+ if (data >= end)
+ RETTRUNK();
+ OUTF("%s Parameter %u\n", BitRowFill(data[0], 0xff), data[0]);
+ if (++data >= end)
+ RETTRUNK();
+ OUTF("%s Parameter %u\n", BitRowFill(data[0], 0xff), data[0]);
+ if (++data >= end)
+ RETTRUNK();
+ OUTF("%s Parameter %u\n", BitRowFill(data[0], 0xff), data[0]);
+ data++;
+ Address("SMSC");
+ if (data >= end)
+ RETTRUNK();
+
+ /* FIXME: Be more detailed here about message flags */
+ OUTF("%s Message Flags: %u\n", BitRowFill(data[0], 0xff), data[0]);
+ if (++data + 1 >= end)
+ RETTRUNK();
+ int num = data[0] << 8;
+ OUTF("%s Reference Number [continue]\n", BitRowFill(data[0], 0xff));
+ data++;
+ num |= data[0];
+ OUTF("%s Reference Number: %u\n", BitRowFill(data[0], 0xff), num);
+ data++;
+
+ /* Destination address */
+ Address("Destination");
+ SmsProtocolDataValidity();
+ if (data >= end)
+ RETTRUNK();
+}
+
+static void
+cpData()
+{
+ if (data >= end)
+ RETTRUNK();
+ OUTF("%s Length: %u\n", BitRowFill(data[0], 0xff), data[0]);
+ data++;
+ if (data >= end)
+ RETTRUNK();
+ if ((data[0] & 1) == 0)
+ {
+ //OUTF("xxxxxxx0 cpDataUp FIXME\n");
+ //data++;
+ cpDataUp();
+ return;
+ }
+ OUTF("%s Parameter\n", BitRowFill(data[0], 0xff));
+ if (++data >= end)
+ RETTRUNK();
+ OUTF("%s Parameter\n", BitRowFill(data[0], 0xff));
+ if (++data >= end)
+ return; /* Can happen that msg terminated here... */
+
+ Address("SMSC");
+ if (data >= end)
+ RETTRUNK();
+
+ OUTF("%s TP-MTI, TP-MMS, TP-SRI, TP-UDIH, TP-RP: %u\n", BitRowFill(data[0], 0xff), data[0]);
+ if (++data >= end)
+ RETTRUNK();
+ OUTF("%s Reference number: %u\n", BitRowFill(data[0], 0xff), data[0]);
+ if ((data[0]) == 0x44)
+ {
+ OUTF("FIXME: ems_type\n");
+ return;
+ }
+ if (++data >= end)
+ RETTRUNK();
+
+ OUTF("%s Parameter\n", BitRowFill(data[0], 0xff));
+ data++;
+
+ Address("Destination");
+ SmsProtocolDataValidity();
+
+ int c = 0;
+ while (c++ < 7)
+ {
+ OUTF("%s Parameter%u\n", BitRowFill(data[0], 0xff), c);
+ if (++data >= end)
+ RETTRUNK();
+ }
+ OUTF("FIXME %p < %p\n", data, end);
+}
+
+static void
+Address(const char *str)
+{
+ int len;
+
+ if (data >= end)
+ RETTRUNK();
+ len = data[0];
+ OUTF("%s %s Address Length: %u\n", BitRowFill(data[0], 0xff), str, data[0]);
+ data++;
+ if (len <= 0)
+ return;
+ if (data >= end)
+ RETTRUNK();
+ if (data[0] >> 7)
+ OUTF("1------- Extension\n");
+
+ OUTF("%s\n", id_list_get(list_SMSCAddressType, (data[0] >> 4) & 0x07));
+ OUTF("%s\n", id_list_get(list_SMSCAddressNumberingPlan, data[0] & 0x0f));
+ len--;
+ data++;
+ if (len <= 0)
+ return;
+ const unsigned char *thisend = data + len;
+ if (thisend > end)
+ thisend = end;
+
+ OUTF("-------- Number(%d): ", len);
+ while (data < thisend)
+ {
+ if ((data[0] >> 4) == 0x0f)
+ OUT("%X", data[0] & 0x0f);
+ else
+ OUT("%X%X", data[0] & 0x0f, data[0] >> 4);
+ data++;
+ }
+ OUT("\n");
+}
+
+
+static void
+l2_RRpagingresponse()
+{
+ if (data >= end)
+ RETTRUNK();
+
+ if ((data[0] & 0x07) == 0x07)
+ OUTF("-----111 Cipher key sequence: Key not available!\n");
+ else
+ OUTF("%s Ciphering key sequence: %u\n", BitRowFill(data[0], 0x07), data[0] & 0x07);
+
+ OUTF("%s Ciphering key sequence: %u\n", BitRowFill(data[0], 0x70), (data[0] >> 4) & 0x07);
+
+ data++;
+ MSClassMarkTwo();
+ if (data >= end)
+ RETTRUNK();
+ l2_MobId();
+}
+
+static void
+l2_RRassignCommand()
+{
+ ChannelDescriptionTwo();
+ if (data >= end)
+ RETTRUNK();
+
+ OUTF("%s Training seq. code: %d\n", BitRowFill(data[0], 0xe0), data[0] >> 5);
+ if (((data[0] >> 2) & 0x07) == 0x00)
+ l2_SingleChannelAssCom();
+ else if (((data[0] >> 4) & 1) == 0x01)
+ l2_HoppingChannelAssCom();
+ else
+ OUTF("xxx0??xxx UNKNOWN %d\n", (data[0] >> 3) & 0x3);
+}
+
+static void
+l2_RRassignComplete()
+{
+ if (data >= end)
+ RETTRUNK();
+
+ OUTF("%s\n", id_list_get(list_ChannelRelease, data[0]));
+ data++;
+}
+
+static void
+ChannelDescriptionTwo()
+{
+ if (data >= end)
+ RETTRUNK();
+ OUTF("%s Timeslot number: %d\n", BitRowFill(data[0], 0x07), data[0] & 0x07);
+ OUTF("%s Channel Description: %s\n", BitRowFill(data[0], 0xf8), id_list_get(list_ChannelDescriptionTwo, data[0] >> 3));
+
+ data++;
+}
+
+static void
+l2_SingleChannelAssCom()
+{
+ int freq = (data[0] & 0x03) << 8;
+
+ data++;
+ if (data >= end)
+ RETTRUNK();
+ freq |= data[0];
+ OUTF("........ Absolute RF channel number: %u\n", freq);
+ if (++data >= end)
+ RETTRUNK();
+ OUTF("%s Power Level: %u\n", BitRowFill(data[0], 0x1f), data[0] & 0x1f);
+ if (++data >= end)
+ RETTRUNK();
+ if (data[0] != 0x63)
+ return;
+ if (++data >= end)
+ RETTRUNK();
+ OUTF("%s\n", id_list_get(list_ChannelMode, data[0]));
+}
+
+static void
+l2_HoppingChannelAssCom()
+{
+ OUTF("FIXME %s\n", __func__);
+}
+
+static void
+CCalerting()
+{
+ if (data >= end)
+ RETTRUNK();
+ if (data[0] != 0x1e)
+ return;
+
+ data++;
+ ProgressIndicator();
+}
+
+static void
+ProgressIndicator()
+{
+ if (data >= end)
+ RETTRUNK();
+
+ OUTF("%s Length of IE Progress Indicator: %u\n", BitRowFill(data[0], 0xff), data[0]);
+ if (++data >= end)
+ RETTRUNK();
+ OUTF("%s Coding: %s\n", BitRowFill(data[0], 0x60), id_list_get(list_CodingStandard, (data[0] >> 5) & 0x03));
+ OUTF("%s Location: %s\n", BitRowFill(data[0], 0x0f), id_list_get(list_Location, data[0] & 0x0f));
+ if (++data >= end)
+ RETTRUNK();
+ OUTF("%s\n", id_list_get(list_Progress, data[0] & 0x7f));
+ data++;
+}
+
+static void
+CCsetup()
+{
+ if (data >= end)
+ RETTRUNK();
+
+ if (data[0] == 0x04)
+ {
+ OUTF("00000100 Bearer Capability\n");
+ data++;
+ BearerCap();
+ } else if (data[0] == 0x1e) {
+ OUTF("00011110 Progress Indicator\n");
+ ProgressIndicator();
+ return;
+ } else {
+ OUTF("%s FIXME\n", BitRowFill(data[0], 0xff));
+ }
+
+ data++;
+}
+
+static void
+Cause()
+{
+ if (data >= end)
+ RETTRUNK();
+
+ OUTF("%s Length of Cause: %u\n", BitRowFill(data[0], 0xff), data[0]);
+ if (++data >= end)
+ RETTRUNK();
+
+ OUTF("%s Coding: %s\n", BitRowFill(data[0], 0x60), id_list_get(list_CodingStandard, (data[0] >> 5) & 0x03));
+ OUTF("%s Location: %s\n", BitRowFill(data[0], 0x0f), id_list_get(list_Location, data[0] & 0x0f));
+ if (++data >= end)
+ RETTRUNK();
+
+ OUTF("%s Cause: %s\n", BitRowFill(data[0], 0x7f), id_list_get(list_Cause, data[0] & 0x7f));
+ data++;
+}
+
+static void
+l2_RRclassmarkChange()
+{
+ if (data >= end)
+ RETTRUNK();
+ MSClassMarkTwo();
+ if (data >= end)
+ RETTRUNK();
+ if (data[0] == 0x20)
+ {
+ OUTF("00100000 Class Mark 3 [FIXME]\n");
+ data++;
+ }
+}
+
+static void
+SmsProtocolDataValidity()
+{
+ if (data >= end)
+ RETTRUNK();
+ OUTF("%s Protocol Identifier: %u\n", BitRowFill(data[0], 0xff), data[0]);
+ if (++data >= end)
+ RETTRUNK();
+ OUTF("%s Data Coding Sheme: %u\n", BitRowFill(data[0], 0xff), data[0]);
+ data++;
+}
+
+static void
+BearerCap()
+{
+ int len;
+
+ if (data >= end)
+ RETTRUNK();
+
+ len = data[0];
+ OUTF("%s Length: %u\n", BitRowFill(data[0], 0xff), data[0]);
+ if (data + len > end)
+ len = end - data;
+ if (++data >= end)
+ RETTRUNK();
+
+ OUTF("%s Radio Channel: %s\n", BitRowFill(data[0], 0x60), id_list_get(list_RadioChannelReq, (data[0] >> 5) & 0x03));
+ if ((data[0] >> 4) & 1)
+ OUTF("---1---- Coding Standard: reserved\n");
+ else
+ OUTF("---0---- Coding Standard: GSM\n");
+ if ((data[0] >> 3) & 1)
+ OUTF("----1--- Transfer Mode: Packet\n");
+ else
+ OUTF("----0--- Transfer Mode: Circuit\n");
+
+ OUTF("%s Transfer Capability: %s\n", BitRowFill(data[0], 0x07), id_list_get(list_TransferCap, data[0] & 0x07));
+ //len--;
+ OUTF("FIXME: Stuff missing here\n");
+#if 0
+ if (++data >= end)
+ RETTRUNK();
+ if ((data[0] >> 6) & 1)
+ OUTF("-1------ Coding: octet 3 extended [FIXME]\n");
+ else
+ OUTF("-0------ Coding: octet 3 extended for inf. trans. cap\n");
+
+ /* FIXME: Stuff missing here */
+#endif
+}
+
+static void
+AuthenticationRequest()
+{
+ char rand[16 * 2 + 1];
+
+ if (data >= end)
+ RETTRUNK();
+
+ OUTF("%s Cipher Key Sequence Number: %u\n", BitRowFill(data[0], 0x07), data[0] & 0x07);
+ data++;
+ if (data + 16 > end)
+ RETTRUNK();
+
+ snprintf(rand, sizeof rand, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15]);
+ OUTF("-------- RAND: %s\n", rand);
+ data += 16;
+}
+
+static void
+AuthenticationResponse()
+{
+ char sres[4 * 2 + 1];
+
+ if (data + 4 > end)
+ RETTRUNK();
+ snprintf(sres, sizeof sres, "%02x%02x%02x%02x", data[0], data[1], data[2], data[3]);
+ OUTF("-------- SRES: %s\n", sres);
+ data += 4;
+}
+
diff --git a/gsmsp/gsm/src/lib/data_out.h b/gsmsp/gsm/src/lib/data_out.h
new file mode 100644
index 0000000..d920136
--- /dev/null
+++ b/gsmsp/gsm/src/lib/data_out.h
@@ -0,0 +1,11 @@
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void l2_data_out_Bbis(int fn, const unsigned char *data, int len);
+void l2_data_out_B(int fn, const unsigned char *data, int len);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/gsmsp/gsm/src/lib/fire_crc.cc b/gsmsp/gsm/src/lib/fire_crc.cc
new file mode 100644
index 0000000..9037ee5
--- /dev/null
+++ b/gsmsp/gsm/src/lib/fire_crc.cc
@@ -0,0 +1,168 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2005 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "fire_crc.h"
+#include <math.h>
+#include <iostream>
+
+fire_crc::fire_crc (unsigned int crc_size, unsigned int data_size)
+ : d_crc_size(crc_size),
+ d_data_size(data_size),
+ d_syn_start(0),
+ d_syndrome_reg()
+{
+ // Initialise syndrome
+}
+
+fire_crc::~fire_crc()
+{
+}
+
+int
+fire_crc::rem(const int x, const int y)
+{
+ return (x % y);
+}
+
+int
+fire_crc::check_crc(const unsigned char *input_bits,
+ unsigned char *control_data)
+{
+ int j,error_count = 0, error_index = 0, success_flag = 0, syn_index = 0;
+ d_syn_start = 0;
+ // reset the syndrome register
+ d_syndrome_reg.clear();
+ d_syndrome_reg.insert(d_syndrome_reg.begin(),40,0);
+
+ // shift in the data bits
+ for (unsigned int i=0; i < d_data_size; i++) {
+ error_count = syndrome_shift(input_bits[i]);
+ control_data[i] = input_bits[i];
+ }
+
+ // shift in the crc bits
+ for (unsigned int i=0; i < d_crc_size; i++) {
+ error_count = syndrome_shift(1-input_bits[i+d_data_size]);
+ }
+
+ // Find position of error burst
+ if (error_count == 0) {
+ error_index = 0;
+ }
+ else {
+ error_index = 1;
+ error_count = syndrome_shift(0);
+ error_index += 1;
+ while (error_index < (d_data_size + d_crc_size) ) {
+ error_count = syndrome_shift(0);
+ error_index += 1;
+ if ( error_count == 0 ) break;
+ }
+ }
+
+ // Test for correctable errors
+ //printf("error_index %d\n",error_index);
+ if (error_index == 224) success_flag = 0;
+ else {
+
+ // correct index depending on the position of the error
+ if (error_index == 0) syn_index = error_index;
+ else syn_index = error_index - 1;
+
+ // error burst lies within data bits
+ if (error_index < 184) {
+ //printf("error < bit 184,%d\n",error_index);
+ j = error_index;
+ while ( j < (error_index+12) ) {
+ if (j < 184) {
+ control_data[j] = control_data[j] ^
+ d_syndrome_reg[rem(d_syn_start+39-j+syn_index,40)];
+ }
+ else break;
+ j = j + 1;
+ }
+ }
+ else if ( error_index > 212 ) {
+ //printf("error > bit 212,%d\n",error_index);
+ j = 0;
+ while ( j < (error_index - 212) ) {
+ control_data[j] = control_data[j] ^
+ d_syndrome_reg[rem(d_syn_start+39-j-224+syn_index,40)];
+ j = j + 1;
+ }
+ }
+ // for 183 < error_index < 213 error in parity alone so ignore
+ success_flag = 1;
+ }
+ return success_flag;
+}
+
+int
+fire_crc::syndrome_shift(unsigned int bit)
+{
+ int error_count = 0;
+ if (d_syn_start == 0) d_syn_start = 39;
+ else d_syn_start -= 1;
+
+ std::vector<int> temp_syndrome_reg = d_syndrome_reg;
+
+ temp_syndrome_reg[rem(d_syn_start+3,40)] =
+ d_syndrome_reg[rem(d_syn_start+3,40)] ^
+ d_syndrome_reg[d_syn_start];
+ temp_syndrome_reg[rem(d_syn_start+17,40)] =
+ d_syndrome_reg[rem(d_syn_start+17,40)] ^
+ d_syndrome_reg[d_syn_start];
+ temp_syndrome_reg[rem(d_syn_start+23,40)] =
+ d_syndrome_reg[rem(d_syn_start+23,40)] ^
+ d_syndrome_reg[d_syn_start];
+ temp_syndrome_reg[rem(d_syn_start+26,40)] =
+ d_syndrome_reg[rem(d_syn_start+26,40)] ^
+ d_syndrome_reg[d_syn_start];
+
+ temp_syndrome_reg[rem(d_syn_start+4,40)] =
+ d_syndrome_reg[rem(d_syn_start+4,40)] ^ bit;
+ temp_syndrome_reg[rem(d_syn_start+6,40)] =
+ d_syndrome_reg[rem(d_syn_start+6,40)] ^ bit;
+ temp_syndrome_reg[rem(d_syn_start+10,40)] =
+ d_syndrome_reg[rem(d_syn_start+10,40)] ^ bit;
+ temp_syndrome_reg[rem(d_syn_start+16,40)] =
+ d_syndrome_reg[rem(d_syn_start+16,40)] ^ bit;
+ temp_syndrome_reg[rem(d_syn_start+27,40)] =
+ d_syndrome_reg[rem(d_syn_start+27,40)] ^ bit;
+ temp_syndrome_reg[rem(d_syn_start+29,40)] =
+ d_syndrome_reg[rem(d_syn_start+29,40)] ^ bit;
+ temp_syndrome_reg[rem(d_syn_start+33,40)] =
+ d_syndrome_reg[rem(d_syn_start+33,40)] ^ bit;
+ temp_syndrome_reg[rem(d_syn_start+39,40)] =
+ d_syndrome_reg[rem(d_syn_start+39,40)] ^ bit;
+
+ temp_syndrome_reg[d_syn_start] = d_syndrome_reg[d_syn_start] ^ bit;
+
+ d_syndrome_reg = temp_syndrome_reg;
+
+ for (unsigned int i = 0; i < 28; i++) {
+ error_count = error_count + d_syndrome_reg[rem(d_syn_start+i,40)];
+ }
+ return error_count;
+}
+
+
diff --git a/gsmsp/gsm/src/lib/fire_crc.h b/gsmsp/gsm/src/lib/fire_crc.h
new file mode 100644
index 0000000..bd231c4
--- /dev/null
+++ b/gsmsp/gsm/src/lib/fire_crc.h
@@ -0,0 +1,54 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2005 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <vector>
+#include <math.h>
+
+#ifndef INCLUDED_FIRE_CRC_H
+#define INCLUDED_FIRE_CRC_H
+
+/*!
+ * \brief
+ * \ingroup
+ */
+
+class fire_crc
+{
+protected:
+
+ unsigned int d_crc_size;
+ unsigned int d_data_size;
+ unsigned int d_syn_start;
+ std::vector<int> d_syndrome_reg;
+
+public:
+
+ fire_crc (unsigned int crc_size, unsigned int data_size);
+ ~fire_crc ();
+ int check_crc (const unsigned char *input_bits,
+ unsigned char *control_bits);
+ int syndrome_shift (unsigned int bit);
+ int rem (const int x, const int y);
+
+};
+
+#endif
diff --git a/gsmsp/gsm/src/lib/gsm.i b/gsmsp/gsm/src/lib/gsm.i
new file mode 100644
index 0000000..dc3b5d4
--- /dev/null
+++ b/gsmsp/gsm/src/lib/gsm.i
@@ -0,0 +1,32 @@
+/* -*- c++ -*- */
+
+%feature("autodoc", "1"); // generate python docstrings
+
+%include "exception.i"
+%import "gnuradio.i" // the common stuff
+
+%{
+#include "gnuradio_swig_bug_workaround.h" // mandatory bug fix
+#include "gsm_run_bb.h"
+#include <stdexcept>
+%}
+
+// ----------------------------------------------------------------
+
+/*
+ * First arg is the package prefix.
+ * Second arg is the name of the class minus the prefix.
+ *
+ * This does some behind-the-scenes magic so we can
+ * access gsm_ruN_bb from python as gsm.run_bb
+ */
+GR_SWIG_BLOCK_MAGIC(gsm,run_bb);
+
+gsm_run_bb_sptr gsm_make_run_bb ();
+
+class gsm_run_bb : public gr_block
+{
+private:
+ gsm_run_bb ();
+};
+
diff --git a/gsmsp/gsm/src/lib/gsm_constants.h b/gsmsp/gsm/src/lib/gsm_constants.h
new file mode 100644
index 0000000..779cd0f
--- /dev/null
+++ b/gsmsp/gsm/src/lib/gsm_constants.h
@@ -0,0 +1,12 @@
+// $Id: gsm_constants.h,v 1.3 2007/03/14 05:44:53 jl Exp $
+
+#pragma once
+
+static const double QN_TIME = 12.0l / 13.0l / 1000000.0l;
+static const double BN_TIME = 4.0l * QN_TIME;
+static const double TN_TIME = 156.25l * BN_TIME;
+static const double FN_TIME = 8.0l * TN_TIME;
+
+static const double GSM_RATE = 812500.0l / 3.0l;
+static const int MAX_FN = 26 * 51 * 2048;
+static const int BURST_LENGTH = 156;
diff --git a/gsmsp/gsm/src/lib/gsm_desc.h b/gsmsp/gsm/src/lib/gsm_desc.h
new file mode 100644
index 0000000..e9f59ba
--- /dev/null
+++ b/gsmsp/gsm/src/lib/gsm_desc.h
@@ -0,0 +1,158 @@
+
+
+struct _id_list list_ChannelRelease[] = {
+{0, "00000000 RR-Cause (reason of event) = Normal event"},
+{1, "00000001 RR-Cause (reason of event) = Abnormal release, unspecified"},
+{2, "00000010 RR-Cause (reason of event) = Abnormal release, channel unacceptable"},
+{3, "00000011 RR-Cause (reason of event) = Abnormal release, timer expired"},
+{4, "00000100 RR-Cause (reason of event) = Abnormal release, no activity on the radio path"},
+{5, "00000101 RR-Cause (reason of event) = Preemptive release"},
+{8, "00001000 RR-Cause (reason of event) = Handover impossible, timing advance out of range"},
+{9, "00001001 RR-Cause (reason of event) = Channel mode unacceptable"},
+{10, "00001010 RR-Cause (reason of event) = Frequency not implemented"},
+{0x81, "01000001 RR-Cause (reason of event) = Call already cleared"},
+{0x5f, "01011111 RR-Cause (reason of event) = Semantically incorrect message"},
+{0x60, "01100000 RR-Cause (reason of event) = Invalid mandatory information"},
+{0x61, "01100001 RR-Cause (reason of event) = Message type non-existent or not implemented"},
+{0x62, "01100010 RR-Cause (reason of event) = Message type not compatible with protocol state"},
+{0x64, "01100100 RR-Cause (reason of event) = Conditional IE error"},
+{0x65, "01100101 RR-Cause (reason of event) = Nocell allocation available"},
+{0x6f, "01101111 RR-Cause (reason of event) = Protocol error unspecified"},
+{-1, NULL}
+};
+
+struct _id_list list_RequestServiceType[] = {
+{1, "----0001 Request Service Type: MS originated call"},
+{2, "----0010 Request Service Type: Emergency call"},
+{4, "----0100 Request Service Type: SMS"},
+{8, "----1000 Request Service Type: Supplementary Service Activation"},
+{9, "----1001 Request Service Type: Voice Group call"},
+{10, "----1010 Request Service Type: Voice Broadcast call"},
+{11, "----1011 Request Service Type: Location Services"},
+{-1, NULL}
+};
+
+struct _id_list list_SMSCAddressType[] = {
+{0, "-000---- Unknown Number Type"},
+{1, "-001---- International Number"},
+{2, "-010---- National Number"},
+{3, "-011---- Network specific number"},
+{4, "-100---- Subscriber number"},
+{5, "-101---- Alphanumeric number"},
+{6, "-110---- Abbreviated number"},
+{-1, NULL}
+};
+
+struct _id_list list_SMSCAddressNumberingPlan[] = {
+{0, "----0000 Numbering plan: Unknown"},
+{1, "----0001 Numbering plan: ISDN/telephone (E164/E.163)"},
+{3, "----0011 Numbering plan: Data(X.121)"},
+{4, "----0100 Numbering plan: Telex"},
+{8, "----1000 Numbering plan: National"},
+{9, "----1001 Numbering plan: Private"},
+{10, "----1010 Numbering plan: ERMES (ESTI DE/PS3 01-3)"},
+{-1, NULL}
+};
+
+struct _id_list list_ChannelDescriptionTwo[] = {
+{0x01, "TCH/F + ACCHs"},
+{0x02, "TCH/H + ACCHs, subchannel 0"},
+{0x03, "TCH/H + ACCHs, subchannel 1"},
+{0x04, "SDCCH/4 + SACCH/C4 or CBCH (SDCCH/4), SC0"},
+{0x05, "SDCCH/4 + SACCH/C4 or CBCH (SDCCH/4), SC1"},
+{0x06, "SDCCH/4 + SACCH/C4 or CBCH (SDCCH/4), SC2"},
+{0x07, "SDCCH/4 + SACCH/C4 or CBCH (SDCCH/4), SC3"},
+{0x08, "SDCCH/8 + SACCH/C8 or CBCH (SDCCH/8), SC0"},
+{0x09, "SDCCH/8 + SACCH/C8 or CBCH (SDCCH/8), SC1"},
+{0x0a, "SDCCH/8 + SACCH/C8 or CBCH (SDCCH/8), SC2"},
+{0x0b, "SDCCH/8 + SACCH/C8 or CBCH (SDCCH/8), SC3"},
+{0x0c, "SDCCH/8 + SACCH/C8 or CBCH (SDCCH/8), SC4"},
+{0x0d, "SDCCH/8 + SACCH/C8 or CBCH (SDCCH/8), SC5"},
+{0x0e, "SDCCH/8 + SACCH/C8 or CBCH (SDCCH/8), SC6"},
+{0x0f, "SDCCH/8 + SACCH/C8 or CBCH (SDCCH/8), SC7"},
+{-1, NULL}
+};
+
+struct _id_list list_ChannelMode[] = {
+{0x00, "00000000 Channel Mode: signaling only"},
+{0x01, "00000001 Channel Mode: TCH/F or TCH/H rev 1"},
+{0x21, "00100001 Channel Mode: TCH/F or TCH/H rev 2"},
+{0x41, "01000001 Channel Mode: TCH/F or TCH/H rev 3"},
+{0x0f, "00001111 Channel Mode: Data, 14.5 kbit/s"},
+{0x03, "00000011 Channel Mode: Data, 12.0 kbit/s"},
+{0x0b, "00001011 Channel Mode: Data, 6.0 kbit/s"},
+{0x13, "00010011 Channel Mode: Data, 3.6 kbit/s"},
+{-1, NULL}
+};
+
+struct _id_list list_CodingStandard[] = {
+{0x00, "CCITT"},
+{0x01, "Reserved for international standards"},
+{0x02, "National standard"},
+{0x03, "GSM-PLMNS"},
+{-1, NULL}
+};
+
+
+struct _id_list list_Location[] = {
+{0x00, "User"},
+{0x01, "Private network serving local user"},
+{0x02, "Public network serving local user"},
+{0x04, "Public network serving remote user"},
+{0x05, "Private network serving remote user"},
+{0x0a, "Network beyong interworking point"},
+{-1, NULL}
+};
+
+struct _id_list list_Progress[] = {
+{0x01, "-0000001 Progress: Call is not end-to-end PLMN/ISDN"},
+{0x02, "-0000010 Progress: Destination address in non-PLMN/ISDN"},
+{0x03, "-0000011 Progress: Origination address in non-PLMN/ISDN"},
+{0x04, "-0000100 Progress: Call has returned to the PLMN/ISDN"},
+{0x08, "-0001000 Progress: In-band information or appr. pattern available"},
+{0x20, "-0100000 Progress: Call is end-to-end PLMN/ISDN"},
+{0x40, "-1000000 Progress: Queueing"},
+{-1, NULL}
+};
+
+struct _id_list list_Cause[] = {
+{0x01, "Unassigned number"},
+{0x03, "No route to destination"},
+{0x06, "Channel unacceptable"},
+{0x08, "Operator determined barring"},
+{0x10, "Normal call clearing"},
+{0x11, "User busy"},
+{0x12, "No user responding"},
+{0x13, "User alerting, no answer"},
+{0x15, "Call rejected"},
+{0x16, "Number changed, New destination"},
+{0x19, "Pre-emption"},
+{0x1a, "Non selected user clearing"},
+{0x1b, "Destination out of order"},
+{0x1c, "Invalid number format (incomplete number)"},
+{0x1d, "Fascility rejected"},
+{0x1e, "Response to Status Enquiry"},
+{0x1f, "Normal"},
+{0x22, "No channel available"},
+{0x26, "Network out of order"},
+/* FIXME: fill in others.. */
+{-1, NULL}
+};
+
+struct _id_list list_RadioChannelReq[] = {
+{0x00, "reserved"},
+{0x01, "full rate MS"},
+{0x02, "dual rate MS/half rate preferred"},
+{0x03, "dual rate MS/full rate preferred"},
+{-1, NULL}
+};
+
+struct _id_list list_TransferCap[] = {
+{0x00, "speech"},
+{0x01, "unrestricted digital information"},
+{0x02, "3.1 kHz audio, exx PLMN"},
+{0x03, "facsimile group 3"},
+{0x05, "Other ITC"},
+{-1, NULL}
+};
+
diff --git a/gsmsp/gsm/src/lib/gsm_run_bb.cc b/gsmsp/gsm/src/lib/gsm_run_bb.cc
new file mode 100644
index 0000000..0db1bbf
--- /dev/null
+++ b/gsmsp/gsm/src/lib/gsm_run_bb.cc
@@ -0,0 +1,420 @@
+/* -*- c++ -*- */
+/*
+ * config.h is generated by configure. It contains the results
+ * of probing for features, options etc. It should be the first
+ * file included in your .cc file.
+ */
+#include "common.h"
+#include <gsm_run_bb.h>
+#include <gr_io_signature.h>
+#include "sch.h"
+#include "cch.h"
+#include "data_out.h"
+
+struct _opt opt;
+
+/* Estiamted earliest SCH start after FCH 142 bit's 0 */
+#define GSMSP_EST_SCH_START_AFTER_FCH (3 + 8 + 156 * 7)
+
+/* SCH training sequence */
+#if 1
+const unsigned char syncbits[] = {
+0x01, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01,
+0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
+0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
+0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01 };
+#endif
+
+static unsigned char syncbitsdiffencoded[sizeof syncbits];
+
+static ssize_t g_req_size;
+
+static void diff_encode(unsigned char *out, const unsigned char *in, size_t len);
+static void diff_decode(unsigned char *out, const unsigned char *in, size_t len);
+static int memdiff(const unsigned char *s1, const unsigned char *s2, size_t n);
+/*
+ * Create a new instance of howto_square2_ff and return
+ * a boost shared_ptr. This is effectively the public constructor.
+ */
+gsm_run_bb_sptr
+gsm_make_run_bb ()
+{
+ return gsm_run_bb_sptr (new gsm_run_bb ());
+}
+
+/*
+ * The private constructor
+ */
+gsm_run_bb::gsm_run_bb ()
+ : gr_sync_block ("run_bb",
+ gr_make_io_signature (1, 1, sizeof (unsigned char)),
+ gr_make_io_signature (0, 0, 0))
+{
+ set_output_multiple(156);
+ bits_processed = 0;
+ iPhase = 1;
+ ChangeSearchMode(EModeFindFCCH);
+ diff_encode(syncbitsdiffencoded, syncbits, sizeof syncbits);
+ //HEXDUMPF(syncbitsdiffencoded, sizeof syncbitsdiffencoded, "syncbitsdiffencoded:\n");
+ interleave_init(&opt.ictx, 456, 114);
+}
+
+/*
+ * Our virtual destructor.
+ */
+gsm_run_bb::~gsm_run_bb ()
+{
+ // nothing else required in this example
+ interleave_deinit(&opt.ictx);
+}
+
+void
+gsm_run_bb::forecast(int noutput_items, gr_vector_int &ninput_items_required)
+{
+ unsigned ninputs = ninput_items_required.size();
+ for (unsigned int i = 0; i < ninputs; i++)
+ ninput_items_required[i] = noutput_items;
+}
+
+/*
+ * Find SCH in inbuf[]. Return the offset of the SCH *start*.
+ */
+int
+gsm_run_bb::find_sch()
+{
+ int ret;
+ const unsigned char *end;
+
+ end = iPtr + 3 + 39 + sizeof syncbitsdiffencoded + 39 + 8;
+
+ DEBUGF("earliest SCH can start: %d\n", bits_processed + iPtr - iStart);
+
+ while (iPtr + 39 + 3 + sizeof syncbitsdiffencoded < end)
+ {
+ ret = memdiff(iPtr + 39 + 3, syncbitsdiffencoded, sizeof (syncbitsdiffencoded));
+ //DEBUGF("memdiff start: %d, ret = %d\n", bits_processed + iPtr - iStart + 39 + 3, ret);
+ if (ret <= 5)
+ {
+ DEBUGF("Possible SCH start: %d (bit error %d)\n", bits_processed + iPtr - iStart, ret);
+ //iPtr = iPtr - 39 - 3;
+ return 0;
+ }
+ iPtr++;
+ }
+
+ return -1; /* SCH not found */
+}
+
+int
+gsm_run_bb::process_sch()
+{
+ int fn = 0, bsic = 0;
+ int ret;
+ unsigned char burst[156];
+
+ //DEBUGF("process_sch at %d\n", bits_processed + iPtr - iStart);
+ diff_decode(burst, iPtr, 156);
+ ret = decode_sch(burst, &fn, &bsic);
+ DEBUGF("SCH ret %d, fn %d, bsic %d\n", ret, fn, bsic);
+ if (ret == 0)
+ iFN = fn;
+
+ return ret;
+}
+
+/*
+ * Search for an exact match!
+ * FIXME: later on accepts FCH burst with a few bit errors.
+ */
+int
+gsm_run_bb::find_fch()
+{
+ while (iPtr < iEnd)
+ {
+ // DEBUGF("zero count %d\n", fcch_zero_count);
+ if (*iPtr == iFchLastBit)
+ {
+
+ fcch_zero_count++;
+ if (fcch_zero_count >= 142)
+ {
+ iPtr++;
+ return 0;
+ }
+ } else {
+ fcch_zero_count = 0;
+ iFchLastBit = *iPtr;
+ }
+ iPtr++;
+ }
+
+ return -1; /* Need more data */
+}
+
+void
+gsm_run_bb::ChangeSearchMode(TMode new_mode)
+{
+ switch (new_mode)
+ {
+ case EModeFindFCCH:
+ ts_n = 0;
+ g_req_size = 1;
+ iFchLastBit = 0;
+ fcch_zero_count = 0;
+ break;
+ case EModeProcessL2:
+ memset(timeslots, 0, sizeof timeslots);
+ // memset(timeslots[0].data, 0x41, sizeof timeslots[0].data);
+ timeslots[0].n_max_frames = 51;
+ timeslots[0].config = TS_CONFIG_CCH;
+ for (int i = 1; i < 2; i++)
+ {
+ timeslots[i].n_max_frames = 51;
+ timeslots[i].config = TS_CONFIG_SDCCH8;
+ }
+ case EModeProcessSCH:
+ case EModeFindSCH:
+ ts_n = 0;
+ default:
+ g_req_size = 156;
+ }
+
+ mode = new_mode;
+}
+
+/*
+ * encode:
+ * - last = 1
+ * - *out = !(in[0] ^ last)
+ * decode:
+ * - last = 1
+ * => ret 0 seen 16 times. all FCCH with Phase: 1
+ * decode:
+ * - last = 0
+ * => ret 0 seen 2 times. all FCCH with Phase: 1
+ */
+static void
+diff_decode(unsigned char *out, const unsigned char *in, size_t len)
+{
+ const unsigned char *end = in + len;
+ unsigned char last; /* = 1; */
+
+ /*
+ * The first 3 decoded bits must be 0 because they are the tail bits.
+ * If one of these bits is wrong then the error is propagated.
+ * To prevent this we just always set the first 3 bits to 0.
+ */
+#if 0
+ int ret;
+ ret = memdiff(in, (const unsigned char *)"\x00\x01\x01", 3);
+ if (ret != 0)
+ {
+ HEXDUMPF(in, 3, "BIT ERROR in TAIL BITS (%d)\n", ret);
+ }
+#endif
+#if 1
+ in += 3;
+ last = 0;
+ memset(out, 0, 3);
+ out += 3;
+#endif
+
+ while (in < end)
+ {
+ *out = !*in ^ last;
+ last = *out;
+ in++;
+ out++;
+ }
+}
+
+/*
+ * Init value is always 1. (after GSM 05.04?)
+ */
+static void
+diff_encode(unsigned char *out, const unsigned char *in, size_t len)
+{
+ const unsigned char *end = in + len;
+ unsigned char last = 1;
+
+ while (in < end)
+ {
+ *out = !(in[0] ^ last);
+ last = in[0];
+ in++;
+ out++;
+ }
+}
+
+int
+gsm_run_bb::work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &/*output_items*/)
+{
+ int ret;
+
+ iStart = (const unsigned char *)input_items[0];
+ iPtr = iStart;
+ iEnd = iStart + noutput_items;
+
+ while (iEnd - iPtr >= g_req_size)
+ {
+ ts_n = (ts_n + 1) % 8;
+ if (ts_n == 0)
+ iFN++;
+ switch (mode)
+ {
+ case EModeFindFCCH:
+ ret = find_fch();
+ if (ret != 0)
+ break;
+ DEBUGF("ts %d: Found FCH start at %d (Phase: %d)\n", ts_n, bits_processed + (iPtr - iStart) - 142, iFchLastBit);
+ iPtr += 3 + 8; /* Tail + guard */
+ iPhase = iFchLastBit;
+ ChangeSearchMode(EModeFindSCH);
+ break;
+ case EModeFindSCH:
+ if (ts_n != 0)
+ {
+ iPtr += g_req_size;
+ break;
+ }
+ ret = find_sch();
+ if (ret != 0)
+ ChangeSearchMode(EModeFindFCCH);
+ else
+ ChangeSearchMode(EModeProcessSCH);
+ break;
+ case EModeProcessSCH:
+ if (process_sch() != 0)
+ {
+ ChangeSearchMode(EModeFindFCCH);
+ } else {
+ iPtr += g_req_size;
+ ChangeSearchMode(EModeProcessL2);
+ }
+ //ChangeSearchMode(EModeFindFCCH);
+ break;
+ default:
+ /* Check if handling this timeslot...*/
+ /* At the moment only handle cch channel */
+ if (timeslots[ts_n].config == TS_CONFIG_UNKNOWN)
+ {
+ iPtr += g_req_size;
+ break;
+ }
+#if 1
+ /* 1, 11, 21, 31, 41 but not 0, 10, 20, 30, 40, 50, . */
+ if ((timeslots[ts_n].config == TS_CONFIG_CCH) && ((iFN % 51 != 0) && ((iFN % 51 + 9) % 10 == 0)))
+ {
+ ret = memdiff(iPtr + 39 + 3, syncbitsdiffencoded, sizeof (syncbitsdiffencoded));
+ if (ret >= 5)
+ {
+ HEXDUMPF(iPtr + 39 + 3, sizeof syncbitsdiffencoded, "ERR: Out of sync!\n");
+ ChangeSearchMode(EModeFindFCCH);
+ break;
+ }
+ ChangeSearchMode(EModeProcessSCH);
+ break;
+ }
+#endif
+
+ burst_ptr = timeslots[ts_n].data[iFN % timeslots[ts_n].n_max_frames];
+ diff_decode(burst_ptr, iPtr, 156);
+ if (handle_l2() != 0)
+ {
+ ChangeSearchMode(EModeFindFCCH);
+ break;
+ }
+ iPtr += g_req_size;
+ break;
+ }
+
+ /* NOTHING HERE */
+ }
+
+ bits_processed += iPtr - iStart;
+ return iPtr - iStart;
+}
+
+int
+gsm_run_bb::handle_l2()
+{
+ unsigned char *data;
+ unsigned int len;
+ unsigned char b[4][58 * 2];
+ unsigned char ready = 0;
+ //DEBUGF("(ts %d, iFN %% %d = %d\n", ts_n, timeslots[ts_n].n_max_frames, iFN % 51);
+
+ /* FIXME: if ts_n == 0 then check if burst 1, 11, 21, 31, ... etc
+ * are still same bsic and if frame number matches...
+ */
+ if (timeslots[ts_n].config == TS_CONFIG_CCH)
+ {
+ /* 2..5, 12..15, 22..25, 23..35, 42..45 */
+ /* 6..9, 16..19, 26..29, 36..39, 46..49 */
+ /* But not 0, 1, 50, ... */
+ if ((iFN % 51 != 0) && ( (((iFN % 51) + 5) % 10 == 0) || (((iFN % 51) + 1) % 10 == 0) ) )
+ ready = 1;
+ //ready = 0; /* TESTING */
+ } else if (timeslots[ts_n].config == TS_CONFIG_SDCCH8) {
+ /* 0..3, 4..7, 8..11, 12..15, .. but not 48..50 */
+ if (((iFN % 51) <= 47) && (((iFN % 51) + 1) % 4 == 0))
+ ready = 1;
+ }
+
+ if (ready == 0)
+ return 0;
+
+ int tdma_n = (iFN % 51) - 3;
+ for (int i = 0; i < 4; i++)
+ {
+ memcpy(b[i], timeslots[ts_n].data[tdma_n + i] + 3, 58);
+ memcpy(b[i] + 58, timeslots[ts_n].data[tdma_n + i] + 3 + 58 + 26, 58);
+ }
+ data = decode_cch(b[0], b[1], b[2], b[3], &len);
+ if (data == NULL)
+ {
+ //DEBUGF("ERR TS %d decoding at %d\n", ts_n, bits_processed + iPtr - iStart);
+ return 0;
+ }
+ DEBUGF("OK TS %d decoding at %d, len %d\n", ts_n, bits_processed + iPtr - iStart, len);
+ //HEXDUMPF(data, len, "DATA (%d)\n", len);
+#if 0
+ if (1)
+ {
+ unsigned char data[]={0x17, 0x06, 0x00, 0xe0, 0xa7, 0x80, 0xe0 ,0x0e ,0x12 ,0x04 ,0xd2 ,0x49 ,0xd2 ,0xda ,0x2b ,0x2b ,0x2b ,0x2b ,0x2b ,0x2b ,0x2b ,0x2b ,0x2b};
+ l2_data_out(1, 0, data, 23);
+ exit(0);
+ }
+#endif
+ if (timeslots[ts_n].config == TS_CONFIG_SDCCH8)
+ {
+ l2_data_out_B(iFN, data, len);
+ } else {
+ l2_data_out_Bbis(iFN, data, len);
+ }
+
+ return 0;
+}
+
+/*
+ * Return number of bytes s1 differes from s2.
+ * Return 0 if s1 and s2 are equal.
+ */
+static int
+memdiff(const unsigned char *s1, const unsigned char *s2, size_t n)
+{
+ int diff = 0;
+
+ for (size_t i = 0; i < n; i++)
+ if (s1[i] != s2[i])
+ diff++;
+
+ return diff;
+}
+
diff --git a/gsmsp/gsm/src/lib/gsm_run_bb.h b/gsmsp/gsm/src/lib/gsm_run_bb.h
new file mode 100644
index 0000000..23cef35
--- /dev/null
+++ b/gsmsp/gsm/src/lib/gsm_run_bb.h
@@ -0,0 +1,87 @@
+/* -*- c++ -*- */
+#ifndef INCLUDED_GR_EXAMPLE_B_SQUARE_BB_H
+#define INCLUDED_GR_EXAMPLE_B_SQUARE_BB_H
+
+#include <gr_sync_block.h>
+
+class gsm_run_bb;
+
+/*
+ * We use boost::shared_ptr's instead of raw pointers for all access
+ * to gr_blocks (and many other data structures). The shared_ptr gets
+ * us transparent reference counting, which greatly simplifies storage
+ * management issues. This is especially helpful in our hybrid
+ * C++ / Python system.
+ *
+ * See http://www.boost.org/libs/smart_ptr/smart_ptr.htm
+ *
+ * As a convention, the _sptr suffix indicates a boost::shared_ptr
+ */
+typedef boost::shared_ptr<gsm_run_bb> gsm_run_bb_sptr;
+
+/*!
+ * \brief Return a shared_ptr to a new instance of howto_square2_ff.
+ *
+ * To avoid accidental use of raw pointers, howto_square2_ff's
+ * constructor is private. howto_make_square2_ff is the public
+ * interface for creating new instances.
+ */
+gsm_run_bb_sptr gsm_make_run_bb ();
+
+enum TimeslotConfig { TS_CONFIG_UNKNOWN, TS_CONFIG_CCH, TS_CONFIG_SDCCH8 };
+struct timeslot_st
+{
+ unsigned char data[102][156];
+ unsigned char n_max_frames;
+ TimeslotConfig config;
+};
+
+/*!
+ * \brief square2 a stream of floats.
+ * \ingroup block
+ *
+ * This uses the preferred technique: subclassing gr_sync_block.
+ */
+class gsm_run_bb : public gr_sync_block
+{
+ private:
+ enum TMode { EModeFindFCCH, EModeFindSCH, EModeProcessSCH, EModeProcessL2 };
+ // The friend declaration allows howto_make_square2_ff to
+ // access the private constructor.
+
+ friend gsm_run_bb_sptr gsm_make_run_bb ();
+
+ gsm_run_bb (); // private constructor
+ int find_sch();
+ int process_sch();
+ int find_fch();
+ int handle_l2();
+ //int find_fch(const unsigned char *start, const unsigned char *end);
+ //int FillWorkingBuffer(const unsigned char *start, const unsigned char *end);
+ void ChangeSearchMode(TMode new_mode);
+ public:
+ ~gsm_run_bb (); // public destructor
+
+ void forecast(int noutput_items, gr_vector_int &ninput_items_required);
+ // Where all the action really happens
+
+ int work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+ private:
+ int ts_n;
+ unsigned char syncbits_match[64];
+ int bits_processed;
+ int fcch_zero_count;
+ unsigned char *burst_ptr;
+// unsigned char burst[156];
+ struct timeslot_st timeslots[8];
+ TMode mode;
+ //unsigned char mode;
+ const unsigned char *iStart, *iPtr, *iEnd;
+ unsigned char iFchLastBit;
+ unsigned char iPhase;
+ int iFN;
+};
+
+#endif /* INCLUDED_HOWTO_SQUARE2_FF_H */
diff --git a/gsmsp/gsm/src/lib/id_list.c b/gsmsp/gsm/src/lib/id_list.c
new file mode 100644
index 0000000..571c3a0
--- /dev/null
+++ b/gsmsp/gsm/src/lib/id_list.c
@@ -0,0 +1,18 @@
+#include "common.h"
+#include "id_list.h"
+
+const char *
+id_list_get(struct _id_list *id_list, int id)
+{
+ struct _id_list *idptr = id_list;
+
+ while (idptr->string != NULL)
+ {
+ if (idptr->id == id)
+ return idptr->string;
+ idptr++;
+ }
+
+ return "UNKNOWN";
+}
+
diff --git a/gsmsp/gsm/src/lib/id_list.h b/gsmsp/gsm/src/lib/id_list.h
new file mode 100644
index 0000000..6ee12cc
--- /dev/null
+++ b/gsmsp/gsm/src/lib/id_list.h
@@ -0,0 +1,23 @@
+
+#ifndef __GSMSP_ID_LIST_H__
+#define __GSMSP_ID_LIST_H__ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _id_list
+{
+ int id;
+ const char *string;
+};
+
+const char *id_list_get(struct _id_list *id_list, int id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !__GSMSP_COMMON_H__ */
+
+
diff --git a/gsmsp/gsm/src/lib/interleave.cc b/gsmsp/gsm/src/lib/interleave.cc
new file mode 100644
index 0000000..879d64d
--- /dev/null
+++ b/gsmsp/gsm/src/lib/interleave.cc
@@ -0,0 +1,48 @@
+
+#include "common.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include "interleave.h"
+
+int
+interleave_init(INTERLEAVE_CTX *ictx, int size, int block_size)
+{
+ ictx->trans_size = size;
+ ictx->trans = (unsigned short *)malloc(size * sizeof *ictx->trans);
+
+// DEBUGF("size: %d\n", size);
+// DEBUGF("Block size: %d\n", block_size);
+ int j, k, B;
+ for (k = 0; k < size; k++)
+ {
+ B = k % 4;
+ j = 2 * ((49 * k) % 57) + ((k % 8) / 4);
+ ictx->trans[k] = B * block_size + j;
+ /* Mapping: pos1 goes to pos2: pos1 -> pos2 */
+// DEBUGF("%d -> %d\n", ictx->trans[k], k);
+ }
+// exit(0);
+ return 0;
+}
+
+int
+interleave_deinit(INTERLEAVE_CTX *ictx)
+{
+ if (ictx->trans != NULL)
+ {
+ free(ictx->trans);
+ ictx->trans = NULL;
+ }
+
+ return 0;
+}
+
+void
+interleave_decode(INTERLEAVE_CTX *ictx, unsigned char *dst, unsigned char *src)
+{
+
+ int k;
+ for (k = 0; k < ictx->trans_size; k++)
+ dst[k] = src[ictx->trans[k]];
+}
+
diff --git a/gsmsp/gsm/src/lib/interleave.h b/gsmsp/gsm/src/lib/interleave.h
new file mode 100644
index 0000000..b1abf81
--- /dev/null
+++ b/gsmsp/gsm/src/lib/interleave.h
@@ -0,0 +1,18 @@
+/*
+ * $Id:$
+ */
+
+#ifndef __GSMSP_INTERLEAVE_H__
+#define __GSMSP_INTERLEAVE_H__ 1
+
+typedef struct _interleave_ctx
+{
+ unsigned short *trans;
+ int trans_size;
+} INTERLEAVE_CTX;
+
+int interleave_init(INTERLEAVE_CTX *ictx, int size, int block_size);
+int interleave_deinit(INTERLEAVE_CTX *ictx);
+void interleave_decode(INTERLEAVE_CTX *ictx, unsigned char *dst, unsigned char *src);
+
+#endif
diff --git a/gsmsp/gsm/src/lib/sch.cc b/gsmsp/gsm/src/lib/sch.cc
new file mode 100644
index 0000000..7bfebc6
--- /dev/null
+++ b/gsmsp/gsm/src/lib/sch.cc
@@ -0,0 +1,325 @@
+// $Id: sch.cc,v 1.11 2007/03/14 05:44:53 jl Exp $
+
+#include "common.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "burst_types.h"
+
+/*
+ * Synchronization channel.
+ *
+ * Timeslot Repeat length Frame Number (mod repeat length)
+ * 0 51 1, 11, 21, 31, 41
+ */
+
+/*
+ * Parity (FIRE) for the GSM SCH.
+ *
+ * g(x) = x^10 + x^8 + x^6 + x^5 + x^4 + x^2 + 1
+ */
+#define DATA_BLOCK_SIZE 25
+#define PARITY_SIZE 10
+#define TAIL_BITS_SIZE 4
+#define PARITY_OUTPUT_SIZE (DATA_BLOCK_SIZE + PARITY_SIZE + TAIL_BITS_SIZE)
+
+static const unsigned char parity_polynomial[PARITY_SIZE + 1] = {
+ 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1
+};
+
+static const unsigned char parity_remainder[PARITY_SIZE] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
+};
+
+
+static void parity_encode(unsigned char *d, unsigned char *p) {
+
+ unsigned int i;
+ unsigned char buf[DATA_BLOCK_SIZE + PARITY_SIZE], *q;
+
+ memcpy(buf, d, DATA_BLOCK_SIZE);
+ memset(buf + DATA_BLOCK_SIZE, 0, PARITY_SIZE);
+
+ for(q = buf; q < buf + DATA_BLOCK_SIZE; q++)
+ if(*q)
+ for(i = 0; i < PARITY_SIZE + 1; i++)
+ q[i] ^= parity_polynomial[i];
+ for(i = 0; i < PARITY_SIZE; i++)
+ p[i] = !buf[DATA_BLOCK_SIZE + i];
+}
+
+
+static int parity_check(unsigned char *d) {
+
+ unsigned int i;
+ unsigned char buf[DATA_BLOCK_SIZE + PARITY_SIZE], *q;
+
+ memcpy(buf, d, DATA_BLOCK_SIZE + PARITY_SIZE);
+
+ for(q = buf; q < buf + DATA_BLOCK_SIZE; q++)
+ if(*q)
+ for(i = 0; i < PARITY_SIZE + 1; i++)
+ q[i] ^= parity_polynomial[i];
+ return memcmp(buf + DATA_BLOCK_SIZE, parity_remainder, PARITY_SIZE);
+}
+
+
+/*
+ * Convolutional encoding and Viterbi decoding for the GSM SCH.
+ * (Equivalent to the GSM SACCH.)
+ *
+ * G_0 = 1 + x^3 + x^4
+ * G_1 = 1 + x + x^3 + x^4
+ *
+ * i.e.,
+ *
+ * c_{2k} = u_k + u_{k - 3} + u_{k - 4}
+ * c_{2k + 1} = u_k + u_{k - 1} + u_{k - 3} + u_{k - 4}
+ */
+#define CONV_INPUT_SIZE PARITY_OUTPUT_SIZE
+#define CONV_SIZE (2 * CONV_INPUT_SIZE)
+#define K 5
+#define MAX_ERROR (2 * CONV_INPUT_SIZE + 1)
+
+
+/*
+ * Given the current state and input bit, what are the output bits?
+ *
+ * encode[current_state][input_bit]
+ */
+static const unsigned int encode[1 << (K - 1)][2] = {
+ {0, 3}, {3, 0}, {3, 0}, {0, 3},
+ {0, 3}, {3, 0}, {3, 0}, {0, 3},
+ {1, 2}, {2, 1}, {2, 1}, {1, 2},
+ {1, 2}, {2, 1}, {2, 1}, {1, 2}
+};
+
+
+/*
+ * Given the current state and input bit, what is the next state?
+ *
+ * next_state[current_state][input_bit]
+ */
+static const unsigned int next_state[1 << (K - 1)][2] = {
+ {0, 8}, {0, 8}, {1, 9}, {1, 9},
+ {2, 10}, {2, 10}, {3, 11}, {3, 11},
+ {4, 12}, {4, 12}, {5, 13}, {5, 13},
+ {6, 14}, {6, 14}, {7, 15}, {7, 15}
+};
+
+
+/*
+ * Given the previous state and the current state, what input bit caused
+ * the transition? If it is impossible to transition between the two
+ * states, the value is 2.
+ *
+ * prev_next_state[previous_state][current_state]
+ */
+static const unsigned int prev_next_state[1 << (K - 1)][1 << (K - 1)] = {
+ { 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2},
+ { 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2},
+ { 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2},
+ { 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2},
+ { 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2},
+ { 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2},
+ { 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2},
+ { 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2},
+ { 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2},
+ { 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2},
+ { 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2},
+ { 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2},
+ { 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2},
+ { 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2},
+ { 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1},
+ { 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1}
+};
+
+
+static inline unsigned int hamming_distance2(unsigned int w) {
+
+ return (w & 1) + !!(w & 2);
+}
+
+
+static void conv_encode(unsigned char *data, unsigned char *output) {
+
+ unsigned int i, state = 0, o;
+
+ // encode data
+ for(i = 0; i < CONV_INPUT_SIZE; i++) {
+ o = encode[state][data[i]];
+ state = next_state[state][data[i]];
+ *output++ = !!(o & 2);
+ *output++ = o & 1;
+ }
+}
+
+
+static int conv_decode(unsigned char *data, unsigned char *output) {
+
+ int i, t;
+ unsigned int rdata, state, nstate, b, o, distance, accumulated_error,
+ min_state, min_error, cur_state;
+
+ unsigned int ae[1 << (K - 1)];
+ unsigned int nae[1 << (K - 1)]; // next accumulated error
+ unsigned int state_history[1 << (K - 1)][CONV_INPUT_SIZE + 1];
+
+ // initialize accumulated error, assume starting state is 0
+ for(i = 0; i < (1 << (K - 1)); i++)
+ ae[i] = nae[i] = MAX_ERROR;
+ ae[0] = 0;
+
+ // build trellis
+ for(t = 0; t < CONV_INPUT_SIZE; t++) {
+
+ // get received data symbol
+ rdata = (data[2 * t] << 1) | data[2 * t + 1];
+
+ // for each state
+ for(state = 0; state < (1 << (K - 1)); state++) {
+
+ // make sure this state is possible
+ if(ae[state] >= MAX_ERROR)
+ continue;
+
+ // find all states we lead to
+ for(b = 0; b < 2; b++) {
+
+ // get next state given input bit b
+ nstate = next_state[state][b];
+
+ // find output for this transition
+ o = encode[state][b];
+
+ // calculate distance from received data
+ distance = hamming_distance2(rdata ^ o);
+
+ // choose surviving path
+ accumulated_error = ae[state] + distance;
+ if(accumulated_error < nae[nstate]) {
+
+ // save error for surviving state
+ nae[nstate] = accumulated_error;
+
+ // update state history
+ state_history[nstate][t + 1] = state;
+ }
+ }
+ }
+
+ // get accumulated error ready for next time slice
+ for(i = 0; i < (1 << (K - 1)); i++) {
+ ae[i] = nae[i];
+ nae[i] = MAX_ERROR;
+ }
+ }
+
+ // the final state is the state with the fewest errors
+ min_state = (unsigned int)-1;
+ min_error = MAX_ERROR;
+ for(i = 0; i < (1 << (K - 1)); i++) {
+ if(ae[i] < min_error) {
+ min_state = i;
+ min_error = ae[i];
+ }
+ }
+
+ // trace the path
+ cur_state = min_state;
+ for(t = CONV_INPUT_SIZE; t >= 1; t--) {
+ min_state = cur_state;
+ cur_state = state_history[cur_state][t]; // get previous
+ output[t - 1] = prev_next_state[cur_state][min_state];
+ }
+
+ // return the number of errors detected (hard-decision)
+ return min_error;
+}
+
+
+int decode_sch(const unsigned char *buf, int *fn_o, int *bsic_o) {
+
+ int errors, bsic, t1, t2, t3p, t3, fn, tt;
+ unsigned char data[CONV_SIZE], decoded_data[PARITY_OUTPUT_SIZE];
+
+ // extract encoded data from synchronization burst
+ /* buf + 3, 39 bit */
+ /* buf + 3 + 39 + 64 = 106, 39 */
+ memcpy(data, buf + SB_EDATA_OS_1, SB_EDATA_LEN_1);
+ memcpy(data + SB_EDATA_LEN_1, buf + SB_EDATA_OS_2, SB_EDATA_LEN_2);
+
+ // Viterbi decode
+ if(errors = conv_decode(data, decoded_data)) {
+ // fprintf(stderr, "error: sch: conv_decode (%d)\n", errors);
+ DEBUGF("ERR: conv_decode %d\n", errors);
+ return errors;
+ }
+
+ // check parity
+ if(parity_check(decoded_data)) {
+ // fprintf(stderr, "error: sch: parity failed\n");
+ DEBUGF("ERR: parity_check failed\n");
+ return 1;
+ }
+
+ // Synchronization channel information, 44.018 page 171. (V7.2.0)
+ bsic =
+ (decoded_data[ 7] << 5) |
+ (decoded_data[ 6] << 4) |
+ (decoded_data[ 5] << 3) |
+ (decoded_data[ 4] << 2) |
+ (decoded_data[ 3] << 1) |
+ (decoded_data[ 2] << 0);
+ t1 =
+ (decoded_data[ 1] << 10) |
+ (decoded_data[ 0] << 9) |
+ (decoded_data[15] << 8) |
+ (decoded_data[14] << 7) |
+ (decoded_data[13] << 6) |
+ (decoded_data[12] << 5) |
+ (decoded_data[11] << 4) |
+ (decoded_data[10] << 3) |
+ (decoded_data[ 9] << 2) |
+ (decoded_data[ 8] << 1) |
+ (decoded_data[23] << 0);
+ t2 =
+ (decoded_data[22] << 4) |
+ (decoded_data[21] << 3) |
+ (decoded_data[20] << 2) |
+ (decoded_data[19] << 1) |
+ (decoded_data[18] << 0);
+ t3p =
+ (decoded_data[17] << 2) |
+ (decoded_data[16] << 1) |
+ (decoded_data[24] << 0);
+
+ t3 = 10 * t3p + 1;
+
+ // modulo arithmetic
+ if(t3 < t2)
+ tt = (t3 + 26) - t2;
+ else
+ tt = (t3 - t2) % 26;
+ fn = (51 * 26 * t1) + (51 * tt) + t3;
+
+ /*
+ * BSIC: Base Station Identification Code
+ * BCC: Base station Color Code
+ * NCC: Network Color Code
+ *
+ * FN: Frame Number
+ */
+ /*
+ printf("bsic: %x (bcc: %u; ncc: %u)\tFN: %u\n", bsic, bsic & 7,
+ (bsic >> 3) & 7, fn);
+ */
+
+ if(fn_o)
+ *fn_o = fn;
+ if(bsic_o)
+ *bsic_o = bsic;
+
+ return 0;
+}
diff --git a/gsmsp/gsm/src/lib/sch.h b/gsmsp/gsm/src/lib/sch.h
new file mode 100644
index 0000000..2858954
--- /dev/null
+++ b/gsmsp/gsm/src/lib/sch.h
@@ -0,0 +1,3 @@
+// $Id: sch.h,v 1.3 2007/03/14 05:44:53 jl Exp $
+
+int decode_sch(const unsigned char *, int *, int *);
personal git repositories of Harald Welte. Your mileage may vary