initial checkin of Osmocom E1TS (E1 timeslot) test port for TITAN
Change-Id: Ib03a6a5b3d7e4864bf797e4a69b87a64515dd953
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1bba67a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+*.o
+*.d
+*.so
+compile
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..3534f2f
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,277 @@
+Eclipse Public License - v 2.0
+
+ THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE
+ PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION
+ OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+
+1. DEFINITIONS
+
+"Contribution" means:
+
+ a) in the case of the initial Contributor, the initial content
+ Distributed under this Agreement, and
+
+ b) in the case of each subsequent Contributor:
+ i) changes to the Program, and
+ ii) additions to the Program;
+ where such changes and/or additions to the Program originate from
+ and are Distributed by that particular Contributor. A Contribution
+ "originates" from a Contributor if it was added to the Program by
+ such Contributor itself or anyone acting on such Contributor's behalf.
+ Contributions do not include changes or additions to the Program that
+ are not Modified Works.
+
+"Contributor" means any person or entity that Distributes the Program.
+
+"Licensed Patents" mean patent claims licensable by a Contributor which
+are necessarily infringed by the use or sale of its Contribution alone
+or when combined with the Program.
+
+"Program" means the Contributions Distributed in accordance with this
+Agreement.
+
+"Recipient" means anyone who receives the Program under this Agreement
+or any Secondary License (as applicable), including Contributors.
+
+"Derivative Works" shall mean any work, whether in Source Code or other
+form, that is based on (or derived from) the Program and for which the
+editorial revisions, annotations, elaborations, or other modifications
+represent, as a whole, an original work of authorship.
+
+"Modified Works" shall mean any work in Source Code or other form that
+results from an addition to, deletion from, or modification of the
+contents of the Program, including, for purposes of clarity any new file
+in Source Code form that contains any contents of the Program. Modified
+Works shall not include works that contain only declarations,
+interfaces, types, classes, structures, or files of the Program solely
+in each case in order to link to, bind by name, or subclass the Program
+or Modified Works thereof.
+
+"Distribute" means the acts of a) distributing or b) making available
+in any manner that enables the transfer of a copy.
+
+"Source Code" means the form of a Program preferred for making
+modifications, including but not limited to software source code,
+documentation source, and configuration files.
+
+"Secondary License" means either the GNU General Public License,
+Version 2.0, or any later versions of that license, including any
+exceptions or additional permissions as identified by the initial
+Contributor.
+
+2. GRANT OF RIGHTS
+
+ a) Subject to the terms of this Agreement, each Contributor hereby
+ grants Recipient a non-exclusive, worldwide, royalty-free copyright
+ license to reproduce, prepare Derivative Works of, publicly display,
+ publicly perform, Distribute and sublicense the Contribution of such
+ Contributor, if any, and such Derivative Works.
+
+ b) Subject to the terms of this Agreement, each Contributor hereby
+ grants Recipient a non-exclusive, worldwide, royalty-free patent
+ license under Licensed Patents to make, use, sell, offer to sell,
+ import and otherwise transfer the Contribution of such Contributor,
+ if any, in Source Code or other form. This patent license shall
+ apply to the combination of the Contribution and the Program if, at
+ the time the Contribution is added by the Contributor, such addition
+ of the Contribution causes such combination to be covered by the
+ Licensed Patents. The patent license shall not apply to any other
+ combinations which include the Contribution. No hardware per se is
+ licensed hereunder.
+
+ c) Recipient understands that although each Contributor grants the
+ licenses to its Contributions set forth herein, no assurances are
+ provided by any Contributor that the Program does not infringe the
+ patent or other intellectual property rights of any other entity.
+ Each Contributor disclaims any liability to Recipient for claims
+ brought by any other entity based on infringement of intellectual
+ property rights or otherwise. As a condition to exercising the
+ rights and licenses granted hereunder, each Recipient hereby
+ assumes sole responsibility to secure any other intellectual
+ property rights needed, if any. For example, if a third party
+ patent license is required to allow Recipient to Distribute the
+ Program, it is Recipient's responsibility to acquire that license
+ before distributing the Program.
+
+ d) Each Contributor represents that to its knowledge it has
+ sufficient copyright rights in its Contribution, if any, to grant
+ the copyright license set forth in this Agreement.
+
+ e) Notwithstanding the terms of any Secondary License, no
+ Contributor makes additional grants to any Recipient (other than
+ those set forth in this Agreement) as a result of such Recipient's
+ receipt of the Program under the terms of a Secondary License
+ (if permitted under the terms of Section 3).
+
+3. REQUIREMENTS
+
+3.1 If a Contributor Distributes the Program in any form, then:
+
+ a) the Program must also be made available as Source Code, in
+ accordance with section 3.2, and the Contributor must accompany
+ the Program with a statement that the Source Code for the Program
+ is available under this Agreement, and informs Recipients how to
+ obtain it in a reasonable manner on or through a medium customarily
+ used for software exchange; and
+
+ b) the Contributor may Distribute the Program under a license
+ different than this Agreement, provided that such license:
+ i) effectively disclaims on behalf of all other Contributors all
+ warranties and conditions, express and implied, including
+ warranties or conditions of title and non-infringement, and
+ implied warranties or conditions of merchantability and fitness
+ for a particular purpose;
+
+ ii) effectively excludes on behalf of all other Contributors all
+ liability for damages, including direct, indirect, special,
+ incidental and consequential damages, such as lost profits;
+
+ iii) does not attempt to limit or alter the recipients' rights
+ in the Source Code under section 3.2; and
+
+ iv) requires any subsequent distribution of the Program by any
+ party to be under a license that satisfies the requirements
+ of this section 3.
+
+3.2 When the Program is Distributed as Source Code:
+
+ a) it must be made available under this Agreement, or if the
+ Program (i) is combined with other material in a separate file or
+ files made available under a Secondary License, and (ii) the initial
+ Contributor attached to the Source Code the notice described in
+ Exhibit A of this Agreement, then the Program may be made available
+ under the terms of such Secondary Licenses, and
+
+ b) a copy of this Agreement must be included with each copy of
+ the Program.
+
+3.3 Contributors may not remove or alter any copyright, patent,
+trademark, attribution notices, disclaimers of warranty, or limitations
+of liability ("notices") contained within the Program from any copy of
+the Program which they Distribute, provided that Contributors may add
+their own appropriate notices.
+
+4. COMMERCIAL DISTRIBUTION
+
+Commercial distributors of software may accept certain responsibilities
+with respect to end users, business partners and the like. While this
+license is intended to facilitate the commercial use of the Program,
+the Contributor who includes the Program in a commercial product
+offering should do so in a manner which does not create potential
+liability for other Contributors. Therefore, if a Contributor includes
+the Program in a commercial product offering, such Contributor
+("Commercial Contributor") hereby agrees to defend and indemnify every
+other Contributor ("Indemnified Contributor") against any losses,
+damages and costs (collectively "Losses") arising from claims, lawsuits
+and other legal actions brought by a third party against the Indemnified
+Contributor to the extent caused by the acts or omissions of such
+Commercial Contributor in connection with its distribution of the Program
+in a commercial product offering. The obligations in this section do not
+apply to any claims or Losses relating to any actual or alleged
+intellectual property infringement. In order to qualify, an Indemnified
+Contributor must: a) promptly notify the Commercial Contributor in
+writing of such claim, and b) allow the Commercial Contributor to control,
+and cooperate with the Commercial Contributor in, the defense and any
+related settlement negotiations. The Indemnified Contributor may
+participate in any such claim at its own expense.
+
+For example, a Contributor might include the Program in a commercial
+product offering, Product X. That Contributor is then a Commercial
+Contributor. If that Commercial Contributor then makes performance
+claims, or offers warranties related to Product X, those performance
+claims and warranties are such Commercial Contributor's responsibility
+alone. Under this section, the Commercial Contributor would have to
+defend claims against the other Contributors related to those performance
+claims and warranties, and if a court requires any other Contributor to
+pay any damages as a result, the Commercial Contributor must pay
+those damages.
+
+5. NO WARRANTY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT
+PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS"
+BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
+IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF
+TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR
+PURPOSE. Each Recipient is solely responsible for determining the
+appropriateness of using and distributing the Program and assumes all
+risks associated with its exercise of rights under this Agreement,
+including but not limited to the risks and costs of program errors,
+compliance with applicable laws, damage to or loss of data, programs
+or equipment, and unavailability or interruption of operations.
+
+6. DISCLAIMER OF LIABILITY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT
+PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS
+SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST
+PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
+EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+7. GENERAL
+
+If any provision of this Agreement is invalid or unenforceable under
+applicable law, it shall not affect the validity or enforceability of
+the remainder of the terms of this Agreement, and without further
+action by the parties hereto, such provision shall be reformed to the
+minimum extent necessary to make such provision valid and enforceable.
+
+If Recipient institutes patent litigation against any entity
+(including a cross-claim or counterclaim in a lawsuit) alleging that the
+Program itself (excluding combinations of the Program with other software
+or hardware) infringes such Recipient's patent(s), then such Recipient's
+rights granted under Section 2(b) shall terminate as of the date such
+litigation is filed.
+
+All Recipient's rights under this Agreement shall terminate if it
+fails to comply with any of the material terms or conditions of this
+Agreement and does not cure such failure in a reasonable period of
+time after becoming aware of such noncompliance. If all Recipient's
+rights under this Agreement terminate, Recipient agrees to cease use
+and distribution of the Program as soon as reasonably practicable.
+However, Recipient's obligations under this Agreement and any licenses
+granted by Recipient relating to the Program shall continue and survive.
+
+Everyone is permitted to copy and distribute copies of this Agreement,
+but in order to avoid inconsistency the Agreement is copyrighted and
+may only be modified in the following manner. The Agreement Steward
+reserves the right to publish new versions (including revisions) of
+this Agreement from time to time. No one other than the Agreement
+Steward has the right to modify this Agreement. The Eclipse Foundation
+is the initial Agreement Steward. The Eclipse Foundation may assign the
+responsibility to serve as the Agreement Steward to a suitable separate
+entity. Each new version of the Agreement will be given a distinguishing
+version number. The Program (including Contributions) may always be
+Distributed subject to the version of the Agreement under which it was
+received. In addition, after a new version of the Agreement is published,
+Contributor may elect to Distribute the Program (including its
+Contributions) under the new version.
+
+Except as expressly stated in Sections 2(a) and 2(b) above, Recipient
+receives no rights or licenses to the intellectual property of any
+Contributor under this Agreement, whether expressly, by implication,
+estoppel or otherwise. All rights in the Program not expressly granted
+under this Agreement are reserved. Nothing in this Agreement is intended
+to be enforceable by any entity that is not a Contributor or Recipient.
+No third-party beneficiary rights are created under this Agreement.
+
+Exhibit A - Form of Secondary Licenses Notice
+
+"This Source Code may also be made available under the following
+Secondary Licenses when the conditions for such availability set forth
+in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),
+version(s), and exceptions or additional permissions here}."
+
+ Simply including a copy of this Agreement, including this Exhibit A
+ is not sufficient to license the Source Code under Secondary Licenses.
+
+ If it is not possible or desirable to put the notice in a particular
+ file, then You may include the notice in a location (such as a LICENSE
+ file in a relevant directory) where a recipient would be likely to
+ look for such a notice.
+
+ You may add additional accurate notices of copyright ownership.
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..111e0da
--- /dev/null
+++ b/README.md
@@ -0,0 +1,34 @@
+titan.TestPorts.E1TS
+====================
+
+This implements a TTCN-3 E1 Timeslot test port for Eclipse TITAN. Running on a (Linux) computer,
+it allows you to write TTCN-3 tests sending and receiving data on 64kBps E1 timeslots.
+
+In order to interface both physical and virtual E1 lines, this port currently relies on
+osmo-e1d, the Osmocom E1 daemon [1]. Adding back-ends for other drivers such as DAHDI should
+not be hard, if needed at a later point.
+
+The timeslots can either be opened in RAW (transparent) 64kBps mode, or with a HDLC controller.
+
+The idea of this module is to be able to write abstract test suites in TTCN-3 which interface
+IUT (Implementations under Test) over E1.
+
+
+GIT repository
+--------------
+
+You can clone from the official titan.TestPorts.E1TS repository using
+
+ git clone https://git.osmocom.org/titan.TestPorts.E1TS
+
+There's a cgit interface at <https://cgit.osmocom.org/titan.TestPorts.E1TS/>
+
+Documentation
+-------------
+
+This is still very much a Work-In-Progress, and hence there's no documentation yet, sorry.
+
+References
+----------
+
+[1] osmo-e1d homepage at https://osmocom.org/projects/osmo-e1d/wiki
diff --git a/example/E1TS_PT.cc b/example/E1TS_PT.cc
new file mode 120000
index 0000000..6db7ab4
--- /dev/null
+++ b/example/E1TS_PT.cc
@@ -0,0 +1 @@
+../src/E1TS_PT.cc
\ No newline at end of file
diff --git a/example/E1TS_PT.hh b/example/E1TS_PT.hh
new file mode 120000
index 0000000..7a5df55
--- /dev/null
+++ b/example/E1TS_PT.hh
@@ -0,0 +1 @@
+../src/E1TS_PT.hh
\ No newline at end of file
diff --git a/example/E1TS_PortType.ttcn b/example/E1TS_PortType.ttcn
new file mode 120000
index 0000000..b30bdda
--- /dev/null
+++ b/example/E1TS_PortType.ttcn
@@ -0,0 +1 @@
+../src/E1TS_PortType.ttcn
\ No newline at end of file
diff --git a/example/E1TS_PortTypes.ttcn b/example/E1TS_PortTypes.ttcn
new file mode 120000
index 0000000..049f24c
--- /dev/null
+++ b/example/E1TS_PortTypes.ttcn
@@ -0,0 +1 @@
+../src/E1TS_PortTypes.ttcn
\ No newline at end of file
diff --git a/example/E1TS_Test.ttcn b/example/E1TS_Test.ttcn
new file mode 100644
index 0000000..5bed3e4
--- /dev/null
+++ b/example/E1TS_Test.ttcn
@@ -0,0 +1,42 @@
+module E1TS_Test {
+
+import from E1TS_PortType all;
+import from E1TS_PortTypes all;
+
+type component test_CT {
+ port E1TS_PT E1;
+}
+
+testcase TC_selftest() runs on test_CT {
+ map(self:E1, system:E1);
+ var template (value) E1TS_identity ts_id := ts_E1TS_ID(0,0,2);
+
+ E1.send(ts_E1TS_open(23, ts_id, E1TS_MODE_RAW, "e1d"));
+ E1.receive(tr_E1TS_result(23, 0));
+
+ var integer rx_count := 0, rx_bytes := 0;
+ var E1TS_unitdata rx_ud;
+ timer T := 5.0;
+ T.start;
+ while (true) {
+ alt {
+ [] E1.receive(tr_E1TS_unitdata(ts_id,?)) -> value rx_ud {
+ rx_bytes := rx_bytes + lengthof(rx_ud.data);
+ rx_count := rx_count + 1;
+ repeat;
+ }
+ [] T.timeout {
+ log(rx_count, " messages received, total bytes ", rx_bytes);
+ mtc.stop
+ };
+ }
+ }
+}
+
+control {
+ execute( TC_selftest() );
+}
+
+
+
+}
diff --git a/example/Makefile b/example/Makefile
new file mode 100644
index 0000000..8028ef2
--- /dev/null
+++ b/example/Makefile
@@ -0,0 +1,241 @@
+# This Makefile was generated by the Makefile Generator
+# of the TTCN-3 Test Executor version CRL 113 200/6 R6B
+# for Harald Welte (laforge@nataraja) on Thu Jul 2 18:32:11 2020
+
+# Copyright (c) 2000-2019 Ericsson Telecom AB
+
+# The following make commands are available:
+# - make, make all Builds the executable test suite.
+# - make archive Archives all source files.
+# - make check Checks the semantics of TTCN-3 and ASN.1modules.
+# - make port Generates port skeletons.
+# - make clean Removes all generated files.
+# - make compile Translates TTCN-3 and ASN.1 modules to C++.
+# - make dep Creates/updates dependency list.
+# - make executable Builds the executable test suite.
+# - make library Builds the library archive.
+# - make objects Builds the object files without linking the executable.
+# - make shared_objects Builds the shared object files without linking the executable.
+# - make preprocess Preprocess TTCN-3 files.
+# WARNING! This Makefile can be used with GNU make only.
+# Other versions of make may report syntax errors in it.
+
+#
+# Do NOT touch this line...
+#
+.PHONY: all shared_objects executable library objects check port clean dep archive preprocess
+
+.SUFFIXES: .d
+
+#
+# Set these variables...
+#
+
+ifndef TTCN3_DIR
+ifneq (,$(wildcard /usr/include/titan/))
+TTCN3_DIR = /usr
+TTCN3_SUBDIR = /titan
+else
+TTCN3_DIR = /usr
+TTCN3_SUBDIR =
+endif
+endif
+
+# Your platform: (SOLARIS, SOLARIS8, LINUX, FREEBSD or WIN32)
+PLATFORM = LINUX
+
+# Your C++ compiler:
+# (if you change the platform, you may need to change the compiler)
+CXX = env CCACHE_SLOPPINESS=time_macros ccache g++
+
+# C preprocessor used for TTCN-3 files:
+CPP = cpp
+
+# Flags for the C++ preprocessor (and makedepend as well):
+CPPFLAGS = -D$(PLATFORM) -DMAKEDEPEND_RUN -DUSE_SCTP -I$(TTCN3_DIR)/include$(TTCN3_SUBDIR) $(shell pkg-config --cflags libosmo-e1d libosmocore)
+
+# Flags for dependency generation
+CXXDEPFLAGS = -MM
+
+# Flags for preprocessing TTCN-3 files:
+CPPFLAGS_TTCN3 = $(shell pkg-config --cflags libosmo-e1d libosmocore)
+
+# Flags for the C++ compiler:
+CXXFLAGS = -fPIC
+
+# Flags for the linker:
+LDFLAGS = -L /usr/lib/titan -fPIC
+
+ifeq ($(PLATFORM), WIN32)
+# Silence linker warnings.
+LDFLAGS += -Wl,--enable-auto-import,--enable-runtime-pseudo-reloc
+endif
+
+# Utility to create library files
+AR = ar
+ARFLAGS =
+
+# Flags for the TTCN-3 and ASN.1 compiler:
+COMPILER_FLAGS = -L -U 5 -D
+
+# Execution mode: (either ttcn3 or ttcn3-parallel)
+TTCN3_LIB = ttcn3-parallel-dynamic
+
+# The path of your libxml2 installation:
+# If you do not have your own one, leave it unchanged.
+XMLDIR = $(TTCN3_DIR)
+
+# Directory to store the archived source files:
+ARCHIVE_DIR = backup
+
+#
+# You may change these variables. Add your files if necessary...
+#
+
+# TTCN-3 modules of this project:
+TTCN3_MODULES = E1TS_Test.ttcn E1TS_PortType.ttcn E1TS_PortTypes.ttcn
+
+# TTCN-3 modules to preprocess:
+TTCN3_PP_MODULES =
+
+# Files to include in TTCN-3 preprocessed modules:
+TTCN3_INCLUDES =
+
+# ASN.1 modules of this project:
+ASN1_MODULES =
+
+# TTCN-3 source files generated by the C preprocessor:
+PREPROCESSED_TTCN3_MODULES =
+
+# C++ source & header files generated from the TTCN-3 & ASN.1 modules of
+# this project:
+GENERATED_SOURCES = $(TTCN3_MODULES:.ttcn=.cc) E1TS_Test_part_1.cc E1TS_Test_part_2.cc E1TS_Test_part_3.cc E1TS_Test_part_4.cc E1TS_PortType_part_1.cc E1TS_PortType_part_2.cc E1TS_PortType_part_3.cc E1TS_PortType_part_4.cc E1TS_PortTypes_part_1.cc E1TS_PortTypes_part_2.cc E1TS_PortTypes_part_3.cc E1TS_PortTypes_part_4.cc $(TTCN3_PP_MODULES:.ttcnpp=.cc) $(ASN1_MODULES:.asn=.cc)
+GENERATED_HEADERS = $(TTCN3_MODULES:.ttcn=.hh) $(TTCN3_PP_MODULES:.ttcnpp=.hh) $(ASN1_MODULES:.asn=.hh)
+
+# C/C++ Source & header files of Test Ports, external functions and
+# other modules:
+USER_SOURCES = E1TS_PT.cc
+USER_HEADERS = $(USER_SOURCES:.cc=.hh)
+
+# Shared object files of this project:
+SHARED_OBJECTS = $(GENERATED_SOURCES:.cc=.so) $(USER_SOURCES:.cc=.so)
+
+# Object files of this project that are needed for the executable test suite:
+OBJECTS = $(GENERATED_OBJECTS) $(USER_OBJECTS)
+
+GENERATED_OBJECTS = $(GENERATED_SOURCES:.cc=.o)
+
+USER_OBJECTS = $(USER_SOURCES:.cc=.o)
+
+DEPFILES = $(USER_OBJECTS:.o=.d) $(GENERATED_OBJECTS:.o=.d)
+
+# Other files of the project (Makefile, configuration files, etc.)
+# that will be added to the archived source files:
+OTHER_FILES = Makefile
+
+# The name of the executable test suite:
+EXECUTABLE = E1TS_Test
+
+
+
+LIBRARY = lib$(EXECUTABLE).so
+
+TARGET = $(EXECUTABLE)
+
+#
+# Do not modify these unless you know what you are doing...
+# Platform specific additional libraries:
+#
+SOLARIS_LIBS = -lsocket -lnsl -lxml2
+SOLARIS8_LIBS = -lsocket -lnsl -lxml2
+LINUX_LIBS = -lxml2 $(shell pkg-config --libs libosmo-e1d libosmocore)
+FREEBSD_LIBS = -lxml2
+WIN32_LIBS = -lxml2
+
+#
+# Rules for building the executable...
+#
+
+all: $(TARGET) ;
+
+shared_objects: $(SHARED_OBJECTS) ;
+
+executable: $(EXECUTABLE) ;
+
+library: $(LIBRARY) ;
+
+objects: $(OBJECTS) compile;
+
+$(EXECUTABLE): $(SHARED_OBJECTS)
+ if $(CXX) $(LDFLAGS) -o $@ -Wl,--no-as-needed $^ \
+ -L$(TTCN3_DIR)/lib$(TTCN3_SUBDIR) -l$(TTCN3_LIB) \
+ -L$(OPENSSL_DIR)/lib -lcrypto \
+ -L$(XMLDIR)/lib $($(PLATFORM)_LIBS); \
+ then : ; else $(TTCN3_DIR)/bin/titanver $(OBJECTS); exit 1; fi
+
+$(LIBRARY): $(OBJECTS)
+ $(CXX) -shared -o $@ $(OBJECTS)
+
+.cc.o .c.o:
+ $(CXX) -c $(CPPFLAGS) $(CXXFLAGS) -o $@ $<
+
+.cc.d .c.d:
+ @echo Creating dependency file for '$<'; set -e; \
+ $(CXX) $(CXXDEPFLAGS) $(CPPFLAGS) $(CXXFLAGS) $< \
+ | sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@; \
+ [ -s $@ ] || rm -f $@
+
+%.so: %.o
+ $(CXX) -shared -o $@ $<
+
+%.ttcn: %.ttcnpp $(TTCN3_INCLUDES)
+ $(CPP) -x c -nostdinc $(CPPFLAGS_TTCN3) $< $@
+
+preprocess: $(PREPROCESSED_TTCN3_MODULES) ;
+
+$(GENERATED_SOURCES) $(GENERATED_HEADERS): compile
+ @if [ ! -f $@ ]; then $(RM) compile; $(MAKE) compile; fi
+
+check: $(TTCN3_MODULES) $(PREPROCESSED_TTCN3_MODULES) $(ASN1_MODULES)
+ $(TTCN3_DIR)/bin/ttcn3_compiler -s $(COMPILER_FLAGS) $^
+
+port: $(TTCN3_MODULES) $(PREPROCESSED_TTCN3_MODULES) $(ASN1_MODULES)
+ $(TTCN3_DIR)/bin/ttcn3_compiler -t $(COMPILER_FLAGS) $^
+
+compile: $(TTCN3_MODULES) $(PREPROCESSED_TTCN3_MODULES) $(ASN1_MODULES)
+ $(TTCN3_DIR)/bin/ttcn3_compiler $(COMPILER_FLAGS) $^ - $?
+ touch $@
+
+clean:
+ -$(RM) $(EXECUTABLE) $(LIBRARY) $(OBJECTS) $(GENERATED_HEADERS) \
+ $(GENERATED_SOURCES) $(SHARED_OBJECTS) $(PREPROCESSED_TTCN3_MODULES) compile $(DEPFILES) \
+ tags *.log
+
+dep: $(GENERATED_SOURCES) $(USER_SOURCES) ;
+
+ifeq ($(findstring n,$(MAKEFLAGS)),)
+ifeq ($(filter clean check port compile archive diag preprocess,$(MAKECMDGOALS)),)
+-include $(DEPFILES)
+endif
+endif
+
+archive:
+ mkdir -p $(ARCHIVE_DIR)
+ tar -cvhf - $(TTCN3_MODULES) $(TTCN3_PP_MODULES) \
+ $(TTCN3_INCLUDES) $(ASN1_MODULES) \
+ $(USER_HEADERS) $(USER_SOURCES) $(OTHER_FILES) \
+ | gzip >$(ARCHIVE_DIR)/`basename $(TARGET) .exe`-`date '+%y%m%d-%H%M'`.tgz
+
+diag:
+ $(TTCN3_DIR)/bin/ttcn3_compiler -v 2>&1
+ $(TTCN3_DIR)/bin/mctr_cli -v 2>&1
+ $(CXX) -v 2>&1
+ @echo TTCN3_DIR=$(TTCN3_DIR)
+ @echo OPENSSL_DIR=$(OPENSSL_DIR)
+ @echo XMLDIR=$(XMLDIR)
+ @echo PLATFORM=$(PLATFORM)
+
+#
+# Add your rules here if necessary...
+#
+
diff --git a/src/E1TS_PT.cc b/src/E1TS_PT.cc
new file mode 100644
index 0000000..9bb7dc4
--- /dev/null
+++ b/src/E1TS_PT.cc
@@ -0,0 +1,285 @@
+/* Copyright (c) 2020 Harald Welte <laforge@osmocom.org> */
+
+#include <iterator>
+
+#include "E1TS_PT.hh"
+#include "E1TS_PortType.hh"
+
+extern "C" {
+#include <osmocom/core/application.h>
+}
+
+#include <poll.h>
+#include <unistd.h>
+
+using namespace E1TS__PortTypes;
+
+namespace E1TS__PortType {
+
+/* somehow std::map() won't work wit E1TS_identity as key */
+DerivedId::DerivedId(const E1TS__identity &id)
+{
+ interface_nr = id.interface__nr();
+ line_nr = id.line__nr();
+ ts_nr = id.ts__nr();
+}
+
+bool operator<(const DerivedId &fk, const DerivedId &lk) {
+ if (fk.interface_nr < lk.interface_nr)
+ return true;
+ else if (fk.interface_nr == lk.interface_nr) {
+ if (fk.line_nr < lk.line_nr)
+ return true;
+ else if (fk.line_nr == lk.line_nr) {
+ if (fk.ts_nr < lk.line_nr)
+ return true;
+ }
+ }
+ return false;
+}
+
+
+QueueEntry::QueueEntry(const uint8_t *pdata, unsigned int plen):
+ len(plen)
+{
+ data = (uint8_t *) malloc(len);
+ memcpy(data, pdata, len);
+}
+
+QueueEntry::~QueueEntry()
+{
+ free(data);
+}
+
+E1_Timeslot::E1_Timeslot(E1TS__PT_PROVIDER &pt, E1TS__identity id, E1TS__mode mode, int fd)
+ : m_pt(pt), m_id(id), m_mode(mode), m_fd(fd)
+{
+ m_pt.log("creating %d:%d:%d fd=%d",
+ (int)m_id.interface__nr(), (int)m_id.line__nr(), (int)m_id.ts__nr(), m_fd);
+}
+
+E1_Timeslot::~E1_Timeslot()
+{
+ m_pt.log("destroying %d:%d:%d fd=%d",
+ (int)m_id.interface__nr(), (int)m_id.line__nr(), (int)m_id.ts__nr(), m_fd);
+
+ close(m_fd);
+
+ /* iterate over tx-queue and free all elements */
+ while (!m_tx_queue.empty()) {
+ struct QueueEntry *qe = m_tx_queue.front();
+ printf("qe=%p\n", qe);
+ m_tx_queue.pop();
+ delete qe;
+ }
+}
+
+/* enqueue to-be-transmitted data */
+int E1_Timeslot::enqueue_tx(const uint8_t *data, unsigned int len)
+{
+ struct QueueEntry *qe = new QueueEntry(data, len);
+ if (!qe)
+ return 0;
+ m_tx_queue.push(qe);
+
+ return 1;
+}
+
+/* dequeue + write next-to-be-transmitted data from queue */
+int E1_Timeslot::dequeue_tx(void)
+{
+ struct QueueEntry *qe;
+ int rc;
+
+ if (m_tx_queue.empty()) {
+ /* queue is empty; unsubscribe write-events */
+ return 0;
+ }
+
+ qe = m_tx_queue.front();
+ m_tx_queue.pop();
+ rc = write(m_fd, qe->data, qe->len);
+ if (rc < 0) {
+ TTCN_error("error during write: %s\n", strerror(errno));
+ /* FIXME: close/delete fd */
+ }
+ else if (rc < qe->len)
+ TTCN_error("could only write %u of %u bytes\n", rc, qe->len);
+
+ delete qe;
+
+ return 1;
+}
+
+
+
+E1TS__PT_PROVIDER::E1TS__PT_PROVIDER(const char *par_port_name)
+ : PORT(par_port_name)
+{
+ osmo_init_logging2(NULL, NULL);
+}
+
+E1TS__PT_PROVIDER::~E1TS__PT_PROVIDER()
+{
+}
+
+void E1TS__PT_PROVIDER::log(const char *fmt, ...)
+{
+ TTCN_Logger::begin_event(TTCN_WARNING);
+ TTCN_Logger::log_event("E1TS Test port (%s): ", get_name());
+ va_list args;
+ va_start(args, fmt);
+ TTCN_Logger::log_event_va_list(fmt, args);
+ va_end(args);
+ TTCN_Logger::end_event();
+}
+
+void E1TS__PT_PROVIDER::set_parameter(const char *parameter_name, const char *parameter_value)
+{
+ if (!strcmp(parameter_name, "e1d_socket_path"))
+ m_e1d_socket_path = parameter_value;
+ else
+ TTCN_error("Unsupported E1TS test port parameter `%s'.", parameter_name);
+}
+
+void E1TS__PT_PROVIDER::Handle_Fd_Event(int fd, boolean is_readable, boolean is_writable,
+ boolean is_error)
+{
+ uint8_t buf[65535];
+ E1_Timeslot *ts;
+ int rc;
+
+ /* find E1TS_identity by fd */
+ ts = ts_by_fd(fd);
+
+ if (!ts)
+ TTCN_error("Unknown file descriptor %d\n", fd);
+
+ if (is_readable) {
+ rc = read(fd, buf, sizeof(buf));
+ if (rc > 0)
+ incoming_message(E1TS__unitdata(ts->m_id, OCTETSTRING(rc, buf)));
+ else if (rc == 0) {
+ TTCN_error("EOF on E1TS fd, closing");
+ m_ts_by_id.erase(m_ts_by_id.find(ts->m_id));
+ m_ts_by_fd.erase(m_ts_by_fd.find(ts->m_fd));
+ Handler_Remove_Fd(ts->m_fd);
+ delete ts;
+ }
+ }
+
+ if (is_writable) {
+ /* dequeue next message; unregister for 'write' if nothing to write */
+ if (ts->dequeue_tx() == 0)
+ Handler_Remove_Fd_Write(ts->m_fd);
+ }
+}
+
+void E1TS__PT_PROVIDER::user_map(const char * /*system_port*/)
+{
+ m_e1d_clnt = osmo_e1dp_client_create(NULL, m_e1d_socket_path);
+}
+
+void E1TS__PT_PROVIDER::user_unmap(const char * /*system_port*/)
+{
+ /* close/destroy all timeslots */
+ for (auto it = m_ts_by_id.begin(); it != m_ts_by_id.end(); it++) {
+ E1_Timeslot *ts = it->second;
+ Handler_Remove_Fd(ts->m_fd);
+ delete ts;
+ }
+ m_ts_by_id.clear();
+ m_ts_by_fd.clear();
+
+ /* close client connection to daemon */
+ osmo_e1dp_client_destroy(m_e1d_clnt);
+}
+
+void E1TS__PT_PROVIDER::user_start()
+{
+}
+
+void E1TS__PT_PROVIDER::user_stop()
+{
+}
+
+static enum osmo_e1dp_ts_mode e1dp_mode(E1TS__mode in)
+{
+ switch (in) {
+ case E1TS__PortTypes::E1TS__mode::E1TS__MODE__RAW:
+ return E1DP_TSMODE_RAW;
+ case E1TS__PortTypes::E1TS__mode::E1TS__MODE__HDLCFCS:
+ return E1DP_TSMODE_HDLCFCS;
+ default:
+ TTCN_error("Unknown E1TS_mode %d\n", in);
+ }
+}
+
+E1_Timeslot *E1TS__PT_PROVIDER::ts_by_fd(int fd)
+{
+ auto it = m_ts_by_fd.find(fd);
+ if (it == m_ts_by_fd.end()) {
+ TTCN_error("couldn't find FD for identity");
+ return NULL;
+ } else
+ return it->second;
+}
+
+
+E1_Timeslot *E1TS__PT_PROVIDER::ts_by_id(const E1TS__identity& id)
+{
+ auto it = m_ts_by_id.find(id);
+ if (it == m_ts_by_id.end())
+ return NULL;
+ else
+ return it->second;
+}
+
+
+void E1TS__PT_PROVIDER::outgoing_send(const E1TS__open& send_par)
+{
+ int fd;
+ enum osmo_e1dp_ts_mode mode = e1dp_mode(send_par.mode());
+
+ fd = osmo_e1dp_client_ts_open(m_e1d_clnt, send_par.id().interface__nr(),
+ send_par.id().line__nr(), send_par.id().ts__nr(), mode);
+
+ if (fd >= 0) {
+ E1_Timeslot *ts = new E1_Timeslot(*this, send_par.id(), send_par.mode(), fd);
+ m_ts_by_id.insert(std::make_pair(send_par.id(), ts));
+ m_ts_by_fd.insert(std::make_pair(fd, ts));
+ Handler_Add_Fd_Read(fd);
+ incoming_message(E1TS__result(send_par.req__hdl(), 0));
+ } else {
+ incoming_message(E1TS__result(send_par.req__hdl(), fd));
+ }
+}
+
+void E1TS__PT_PROVIDER::outgoing_send(const E1TS__close& send_par)
+{
+ /* find fd by map */
+ E1_Timeslot *ts = ts_by_id(send_par.id());
+
+ if (!ts)
+ return;
+
+ m_ts_by_id.erase(m_ts_by_id.find(send_par.id()));
+ m_ts_by_fd.erase(m_ts_by_fd.find(ts->m_fd));
+ Handler_Remove_Fd(ts->m_fd);
+ delete ts;
+}
+
+void E1TS__PT_PROVIDER::outgoing_send(const E1TS__unitdata& send_par)
+{
+ /* find fd by map */
+ E1_Timeslot *ts = ts_by_id(send_par.id());
+
+ if (!ts)
+ return;
+
+ ts->enqueue_tx(send_par.data(), send_par.data().lengthof());
+ Handler_Add_Fd_Write(ts->m_fd);
+}
+
+
+} /* namespace */
diff --git a/src/E1TS_PT.hh b/src/E1TS_PT.hh
new file mode 100644
index 0000000..9b7c75f
--- /dev/null
+++ b/src/E1TS_PT.hh
@@ -0,0 +1,100 @@
+#pragma once
+
+#include <map>
+#include <queue>
+
+#include <TTCN3.hh>
+
+extern "C" {
+#include <osmocom/e1d/proto_clnt.h>
+}
+
+#include "E1TS_PortTypes.hh"
+
+namespace E1TS__PortType {
+
+using namespace E1TS__PortTypes;
+
+class E1TS__PT_PROVIDER;
+
+class DerivedId {
+public:
+ DerivedId(const E1TS__identity &id);
+ unsigned int interface_nr;
+ unsigned int line_nr;
+ unsigned int ts_nr;
+};
+
+class QueueEntry {
+public:
+ QueueEntry(const uint8_t *pdata, unsigned int plen);
+ ~QueueEntry();
+
+ uint8_t *data;
+ unsigned int len;
+};
+
+class E1_Timeslot {
+public:
+ E1_Timeslot(E1TS__PT_PROVIDER &pr, E1TS__identity id, E1TS__mode mode, int fd);
+ ~E1_Timeslot();
+
+ int enqueue_tx(const uint8_t *data, unsigned int len);
+ int dequeue_tx(void);
+
+ E1TS__identity m_id;
+ int m_fd;
+
+private:
+ E1TS__PT_PROVIDER &m_pt;
+ E1TS__mode m_mode;
+ std::queue<QueueEntry *> m_tx_queue;
+};
+
+
+class E1TS__PT_PROVIDER : public PORT {
+public:
+ E1TS__PT_PROVIDER(const char *par_port_name);
+ ~E1TS__PT_PROVIDER();
+
+ void set_parameter(const char *parameter_name, const char *parameter_value);
+
+private:
+ void Handle_Fd_Event(int fd, boolean is_readable, boolean is_writable, boolean is_error);
+
+protected:
+ void user_map(const char *system_port);
+ void user_unmap(const char *system_port);
+
+ void user_start();
+ void user_stop();
+
+ void outgoing_send(const E1TS__open& send_par);
+ void outgoing_send(const E1TS__close& send_par);
+ void outgoing_send(const E1TS__unitdata& send_par);
+
+ virtual void incoming_message(const E1TS__result& incoming_par) = 0;
+ virtual void incoming_message(const E1TS__unitdata &incoming_par) = 0;
+
+public:
+ void log(const char *fmt, ...);
+
+private:
+ /* parameter */
+ const char *m_e1d_socket_path = E1DP_DEFAULT_SOCKET;
+
+ E1_Timeslot *ts_by_fd(int fd);
+ E1_Timeslot *ts_by_id(const E1TS__identity &id);
+
+ /* client to the E1 Daemon */
+ struct osmo_e1dp_client *m_e1d_clnt;
+
+ /* per-timeslot file descriptors */
+ std::map<DerivedId, E1_Timeslot *> m_ts_by_id;
+ std::map<int, E1_Timeslot *> m_ts_by_fd;
+
+};
+
+
+
+}
diff --git a/src/E1TS_PortType.ttcn b/src/E1TS_PortType.ttcn
new file mode 100644
index 0000000..fdaa6f3
--- /dev/null
+++ b/src/E1TS_PortType.ttcn
@@ -0,0 +1,12 @@
+module E1TS_PortType {
+import from E1TS_PortTypes all;
+
+type port E1TS_PT message {
+ out E1TS_open;
+ in E1TS_result;
+
+ out E1TS_unitdata;
+ in E1TS_unitdata;
+} with { extension "provider" };
+
+}
diff --git a/src/E1TS_PortTypes.ttcn b/src/E1TS_PortTypes.ttcn
new file mode 100644
index 0000000..bccb996
--- /dev/null
+++ b/src/E1TS_PortTypes.ttcn
@@ -0,0 +1,87 @@
+module E1TS_PortTypes {
+
+type record E1TS_identity {
+ integer interface_nr,
+ integer line_nr,
+ integer ts_nr
+};
+
+type enumerated E1TS_mode {
+ E1TS_MODE_RAW,
+ E1TS_MODE_HDLCFCS
+};
+
+type record E1TS_open {
+ integer req_hdl,
+ E1TS_identity id,
+ E1TS_mode mode,
+ charstring driver
+};
+
+type record E1TS_close {
+ E1TS_identity id
+};
+
+type record E1TS_result {
+ integer req_hdl,
+ integer status
+};
+
+type record E1TS_unitdata {
+ E1TS_identity id,
+ octetstring data
+};
+
+template (value) E1TS_identity ts_E1TS_ID(template (value) integer if_nr,
+ template (value) integer li_nr,
+ template (value) integer ts_nr) := {
+ interface_nr := if_nr,
+ line_nr := li_nr,
+ ts_nr := ts_nr
+}
+
+template (present) E1TS_identity tr_E1TS_ID(template (present) integer if_nr,
+ template (present) integer li_nr,
+ template (present) integer ts_nr) := {
+ interface_nr := if_nr,
+ line_nr := li_nr,
+ ts_nr := ts_nr
+}
+
+template (value) E1TS_open ts_E1TS_open(template (value) integer req_hdl,
+ template (value) E1TS_identity id,
+ template (value) E1TS_mode mode := E1TS_MODE_RAW,
+ template (value) charstring driver := "e1d") := {
+ req_hdl := req_hdl,
+ id := id,
+ mode := mode,
+ driver := driver
+}
+
+
+template (value) E1TS_close ts_E1TS_close(template (value) E1TS_identity id) := {
+ id := id
+}
+
+template (present) E1TS_result tr_E1TS_result(template (present) integer req_hdl := ?,
+ template (present) integer status := ?) := {
+ req_hdl := req_hdl,
+ status := status
+}
+
+template (value) E1TS_unitdata ts_E1TS_unitdata(template (value) E1TS_identity id,
+ template (value) octetstring data) := {
+ id := id,
+ data := data
+}
+
+template (present) E1TS_unitdata tr_E1TS_unitdata(template (present) E1TS_identity id,
+ template (present) octetstring data) := {
+ id := id,
+ data := data
+}
+
+
+
+
+}