First published version
diff --git a/doc/README.md b/doc/README.md
new file mode 100644
index 0000000..cc2c14c
--- /dev/null
+++ b/doc/README.md
@@ -0,0 +1,91 @@
+<!---
+##############################################################################
+# Copyright (c) 2000-2017 Ericsson Telecom AB
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+#  Contributors:
+#   Lenard Nagy
+#
+##############################################################################
+-->
+
+# GPIO testport for use with Titan test executor on Raspberry Pi 
+
+## General introduction
+Titan is a TTCN-3 compiler and test executor, which is able to run on the Raspberry Pi (model 2B and 3B were tested). GPIO (general purpose input/output) pins on the Raspberry Pi are able to control and/or receive signals from physical computing devices (leds, buttons, valves, etc...). Testports are programmable connections between Titan and any physical interface on a device, in this case GPIO pins on the Raspberry Pi.
+
+The current implementation is using the sysfs interface to access GPIO pins.
+
+## Usage
+
+### Preparations
+
+* In Your TTCN-3 module the GPIOPinPort module must be included:
+
+    import from GPIOPinPort all;
+
+* Create a component in the module:
+** Important: the name of the port instance MUST be either gpio# or in case of port arrays gpio[#], where # is an integer between (and including) 2 and 27, which will be the actual pin number of the GPIO!
+
+    type component GPIO {
+	port GPIO_Pin_Port gpio27;
+	port GPIO_Pin_Port gpio[2..26];
+        timer t_short;
+    }
+
+* Map any or all the ports You want to use:
+
+    map(self:gpio[11], system:gpio[11]);
+    map(self:gpio27, system:gpio27);
+    map(self:gpio[26], system:gpio[26]);
+
+### Setting a pin to output, and setting the value of the pin
+
+* To set direction on the gpio pin to OUT a "send" operation is to be performed:
+
+    var GPIO_PIN_DIRECTION gpio27_direction := OUT;
+    gpio27.send(gpio27_direction);
+
+* Similarly, to set the value (HIGH/LOW) a "send" operation is to be performed:
+
+    var GPIO_PIN_VALUE gpio27_value := HIGH;
+    gpio27.send(gpio27_value);
+
+### Listening for input changes on pin(s)
+
+    var integer v_index;
+    
+    var GPIO_PIN_DIRECTION gpio_direction_in := IN;
+    gpio[26].send(gpio_direction_in);
+    gpio27.send(gpio_direction_in);
+    
+    t_short.start(5.0);
+    	
+    alt {
+        [] gpio27.receive {
+           setverdict(pass,"message received on port index 27");
+           }
+        [] any from gpio.receive -> @index value v_index {
+           setverdict(fail,"unexpected message received on port index: ",v_index);
+           }
+        [] t_short.timeout {
+           log("Timeout while waiting for input to change");
+           setverdict(inconc);
+           }
+    }	
+
+### Unmap all the used ports
+    
+    unmap(self:gpio27, system:gpio27);
+    unmap(self:gpio[11], system:gpio[11]);
+    unmap(self:gpio[26], system:gpio[26]);
+
+## References
+* About Titan: https://projects.eclipse.org/projects/tools.titan
+* About TTCN-3: http://www.ttcn-3.org/
+* About Raspberry Pi: https://www.raspberrypi.org/
+* About GPIO on Raspberry Pi: https://www.raspberrypi.org/documentation/usage/gpio/README.md
+
diff --git a/src/GPIOPinPort.ttcn b/src/GPIOPinPort.ttcn
new file mode 100644
index 0000000..a78d24b
--- /dev/null
+++ b/src/GPIOPinPort.ttcn
@@ -0,0 +1,44 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2000-2017 Ericsson Telecom AB
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// which accompanies this distribution, and is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// Contributors:
+// Lenard Nagy
+//
+///////////////////////////////////////////////////////////////////////////////
+module GPIOPinPort {
+	
+	type enumerated GPIO_PIN_DIRECTION {
+	  IN,	//"in"
+	  OUT	//"out"
+	}
+
+	type enumerated GPIO_PIN_VALUE {
+	  LOW,	//"0"
+	  HIGH  //"1"
+	}
+	
+	type record GPIO_PIN_STATUS {
+	  boolean            is_exported,
+	  GPIO_PIN_DIRECTION direction,
+	  GPIO_PIN_VALUE     val
+	}
+	
+	// Raspberry Pi GPIO port
+	//	When a port of this type is used it MUST be named as "gpio[2-27]"
+	//
+	//	E.g.: 
+	//	type component GPIO {
+	//		port GPIO_Pin_Port gpio24;
+	//	}
+	//
+	type port GPIO_Pin_Port message {
+	  out 
+		GPIO_PIN_DIRECTION, GPIO_PIN_VALUE, GPIO_PIN_STATUS
+      in 
+		GPIO_PIN_VALUE, GPIO_PIN_STATUS;
+	}
+}
diff --git a/src/GPIO_Pin_Port.cc b/src/GPIO_Pin_Port.cc
new file mode 100644
index 0000000..2397647
--- /dev/null
+++ b/src/GPIO_Pin_Port.cc
@@ -0,0 +1,322 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2000-2017 Ericsson Telecom AB
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// which accompanies this distribution, and is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// Contributors:
+// Lenard Nagy
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "GPIO_Pin_Port.hh"
+
+namespace GPIOPinPort {
+
+	static const char *gpio_dir      = "/sys/class/gpio/";
+	static const char *export_file   = "/sys/class/gpio/export";
+	static const char *unexport_file = "/sys/class/gpio/unexport";
+
+	//DEBUG
+	//const char *export_file   = "/home/elnrnag/gpio/export";
+	//const char *unexport_file = "/home/elnrnag/gpio/unexport";
+	//DEBUG
+
+	static const string GPIO_DIRECTION_OUT = "out";
+	static const string GPIO_DIRECTION_IN  = "in";
+	static const string GPIO_VALUE_HIGH    = "1";
+	static const string GPIO_VALUE_LOW     = "0";
+	static const string GPIO_EDGE_NONE     = "none";
+	static const string GPIO_EDGE_BOTH     = "both";
+
+	static const int NUMBER_OF_PINS = 26;
+
+GPIO__Pin__Port::GPIO__Pin__Port(const char *par_port_name)
+	: GPIO__Pin__Port_BASE(par_port_name)
+{
+
+}
+
+GPIO__Pin__Port::~GPIO__Pin__Port()
+{
+
+}
+
+void GPIO__Pin__Port::set_parameter(const char * /*parameter_name*/,
+	const char * /*parameter_value*/)
+{
+
+}
+
+/*void GPIO__Pin__Port::Handle_Fd_Event(int fd, boolean is_readable,
+	boolean is_writable, boolean is_error) {}*/
+
+void GPIO__Pin__Port::Handle_Fd_Event_Error(int fd)
+{
+	Handle_Fd_Event_Readable(fd);
+}
+
+void GPIO__Pin__Port::Handle_Fd_Event_Writable(int /*fd*/)
+{
+
+}
+
+void GPIO__Pin__Port::Handle_Fd_Event_Readable(int fd)
+{
+	//unregister_fd_handler();
+	//set_edge_on_pin(GPIO_EDGE_NONE);
+	//printf("FileDescriptor: %d",fd);
+
+	GPIOPinPort::GPIO__PIN__VALUE ret_val;
+	if (get_value_of_pin() == GPIO_VALUE_HIGH) {
+		ret_val = GPIO__PIN__VALUE::HIGH;
+	} else {
+		ret_val = GPIO__PIN__VALUE::LOW;
+	}
+
+	if (ret_val != original_value) {
+	  original_value = ret_val;
+	  incoming_message(ret_val);
+	}
+
+}
+
+/*void GPIO__Pin__Port::Handle_Timeout(double time_since_last_call) {}*/
+
+void GPIO__Pin__Port::user_map(const char * system_port)
+{
+	if ((strlen(system_port) >= 5) && (strlen(system_port) <= 8)) {
+		char* str = (char*)malloc(strlen(system_port)+1);
+		strcpy(str, system_port);
+
+		removechars(str, '[');
+		removechars(str, ']');
+
+		pin.assign(str);
+		printf("length: %zd\n",strlen(pin.c_str()));
+
+		pin_num.assign(str+4);
+
+		printf("Mapping %s\n", pin.c_str());
+		export_pin();
+	} else {
+		TTCN_error("Invalid gpio pin name: %s\nThe port variable name in TTCN code MUST be \"gpio[2-27]\"\n", pin.c_str());
+
+	}
+}
+
+void GPIO__Pin__Port::user_unmap(const char * system_port)
+{
+	unregister_fd_handler(fd_edge);
+	unexport_pin();
+}
+
+void GPIO__Pin__Port::user_start()
+{
+
+}
+
+void GPIO__Pin__Port::user_stop()
+{
+
+}
+
+void GPIO__Pin__Port::outgoing_send(const GPIO__PIN__DIRECTION& direction)
+{
+	if (direction == GPIO__PIN__DIRECTION::IN) {
+		set_direction_of_pin(GPIO_DIRECTION_IN);
+		set_edge_on_pin(GPIO_EDGE_BOTH);
+
+		if (get_value_of_pin() == GPIO_VALUE_HIGH) {
+		  original_value = GPIO__PIN__VALUE::HIGH;
+		} else {
+		  original_value = GPIO__PIN__VALUE::LOW;
+		}
+
+	} else if (direction == GPIO__PIN__DIRECTION::OUT) {
+		set_edge_on_pin(GPIO_EDGE_NONE);
+		set_direction_of_pin(GPIO_DIRECTION_OUT);
+	} else {
+		//TODO: ERROR, must be set
+	}
+}
+
+void GPIO__Pin__Port::outgoing_send(const GPIO__PIN__VALUE& value)
+{
+	if (value == GPIO__PIN__VALUE::LOW) {
+		set_value_of_pin(GPIO_VALUE_LOW);
+	} else if (value == GPIO__PIN__VALUE::HIGH) {
+		set_value_of_pin(GPIO_VALUE_HIGH);
+	} else {
+		TTCN_error("Value for %s must be set", pin.c_str());
+	}
+}
+
+void GPIO__Pin__Port::outgoing_send(const GPIO__PIN__STATUS& stat)
+{
+	GPIO__PIN__STATUS status;
+	if (file_exists(get_pin_dir())){
+		status.is__exported() = true;
+
+		string direction = get_direction_of_pin();
+		if (0 == direction.compare(GPIO_DIRECTION_IN)) {
+			status.direction() = GPIO__PIN__DIRECTION::IN;
+		} else if (0 == direction.compare(GPIO_DIRECTION_OUT)) {
+			status.direction() = GPIO__PIN__DIRECTION::OUT;
+		} else {
+			TTCN_error("Invalid direction when reading direction of %s", pin.c_str());
+		}
+
+		string value = get_value_of_pin();
+		if (0 == value.compare(GPIO_VALUE_LOW)) {
+			status.val() = GPIO__PIN__VALUE::LOW;
+		} else if (0 == value.compare(GPIO_VALUE_HIGH)) {
+			status.val() = GPIO__PIN__VALUE::HIGH;
+		} else {
+			TTCN_error("Invalid value when reading value of %s\n", pin.c_str());
+		}
+	} else {
+		status.is__exported() = false;
+	}
+	incoming_message(status);
+}
+
+//Utility functions
+void GPIO__Pin__Port::export_pin() {
+	if (!file_exists(get_pin_dir().c_str())) {
+		printf("Exporting gpio%s... (export file: %s)\n", pin_num.c_str(), export_file);
+		ofstream exfile;
+		exfile.exceptions(ofstream::failbit | ofstream::badbit);
+		exfile.open (export_file);
+		exfile << pin_num.c_str();
+	} else {
+		printf("===WARNING=== %s was already exported!\n",pin.c_str());
+	}
+}
+
+void GPIO__Pin__Port::unexport_pin() {
+	ofstream unexfile;
+	unexfile.exceptions(ofstream::failbit | ofstream::badbit);
+	unexfile.open (unexport_file);
+	string pin_s(pin_num);
+	unexfile << pin_s.c_str();
+
+}
+
+
+void GPIO__Pin__Port::set_direction_of_pin(const string direction) {
+	string pin_direction_filename = get_pin_dir()+"/direction";
+	printf("Set direction of %s to %s\n", pin.c_str(), direction.c_str());
+	ofstream pin_direction_file;
+	pin_direction_file.exceptions(ofstream::failbit | ofstream::badbit);
+	pin_direction_file.open (pin_direction_filename.c_str());
+	pin_direction_file << direction.c_str();
+	pin_direction_file.close();
+}
+
+
+string GPIO__Pin__Port::get_direction_of_pin() {
+	string pin_direction_filename = get_pin_dir()+"/direction";
+	string line;
+	ifstream pin_direction_file;
+	pin_direction_file.exceptions(ifstream::failbit | ifstream::badbit);
+	pin_direction_file.open (pin_direction_filename.c_str());
+	getline(pin_direction_file,line);
+	pin_direction_file.close();
+	return line;
+}
+
+void GPIO__Pin__Port::set_value_of_pin(const string value) {
+	string pin_value_filename = get_pin_dir()+"/value";
+	printf("Set value of %s to %s\n", pin.c_str(), value.c_str());
+	ofstream pin_value_file;
+	pin_value_file.exceptions(ofstream::failbit | ofstream::badbit);
+	pin_value_file.open (pin_value_filename.c_str());
+	pin_value_file << value.c_str();
+	pin_value_file.close();
+}
+
+string GPIO__Pin__Port::get_value_of_pin() {
+	string pin_value_filename = get_pin_dir()+"/value";
+	string line;
+	ifstream pin_value_file;
+	pin_value_file.exceptions(ifstream::failbit | ifstream::badbit);
+	pin_value_file.open (pin_value_filename.c_str());
+	getline(pin_value_file,line);
+	pin_value_file.close();
+	return line;
+}
+
+void GPIO__Pin__Port::set_edge_on_pin(const string edge) {
+	string pin_edge_filename = get_pin_dir()+"/edge";
+	printf("Set edge to \"%s\" on %s\n", edge.c_str(),pin.c_str());
+	ofstream pin_edge_file;
+	pin_edge_file.exceptions(ofstream::failbit | ofstream::badbit);
+	pin_edge_file.open (pin_edge_filename.c_str());
+	pin_edge_file << edge.c_str();
+	pin_edge_file.close();
+	if (edge != GPIO_EDGE_NONE) {
+		int fd = open(pin_edge_filename.c_str(),O_RDONLY);
+		register_fd_handler(fd);
+	}
+
+}
+
+void GPIO__Pin__Port::register_fd_handler(int fd) {
+	if (fd > 0) {
+		Handler_Add_Fd_Read(fd);
+		fd_edge = fd;
+	}
+}
+
+void GPIO__Pin__Port::unregister_fd_handler(int fd) {
+	if (fd > 0) {
+		Handler_Remove_Fd_Read(fd);
+		close(fd);
+		fd_edge = -1;
+	}
+}
+
+
+string GPIO__Pin__Port::int2string(int i) {
+	string str;
+	stringstream ss;
+	ss << i;
+	ss >> str;
+	return str;
+}
+
+int GPIO__Pin__Port::string2int(const char* str) {
+	stringstream strValue;
+	strValue << str;
+
+	unsigned int intValue;
+	strValue >> intValue;
+
+	return intValue;
+}
+
+void GPIO__Pin__Port::removechars(char* s, char c) {
+	int writer = 0, reader = 0;
+	while (s[reader])
+    	{
+	       	if (s[reader]!=c)
+        	{
+        		s[writer++] = s[reader];
+        	}
+        	reader++;
+    	}
+	s[writer]=0;
+}
+
+bool GPIO__Pin__Port::file_exists (const std::string& name) {
+	return ( access( name.c_str(), F_OK ) != -1 );
+}
+
+string GPIO__Pin__Port::get_pin_dir() {
+	return string(gpio_dir)+pin;
+}
+
+} /* end of namespace */
+
diff --git a/src/GPIO_Pin_Port.hh b/src/GPIO_Pin_Port.hh
new file mode 100644
index 0000000..41783cc
--- /dev/null
+++ b/src/GPIO_Pin_Port.hh
@@ -0,0 +1,79 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2000-2017 Ericsson Telecom AB
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// which accompanies this distribution, and is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// Contributors:
+// Lenard Nagy
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef GPIO__Pin__Port_HH
+#define GPIO__Pin__Port_HH
+
+#include "GPIOPinPort.hh"
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <sstream>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+using namespace std;
+
+
+namespace GPIOPinPort {
+
+class GPIO__Pin__Port : public GPIO__Pin__Port_BASE {
+public:
+	GPIO__Pin__Port(const char *par_port_name = NULL);
+	~GPIO__Pin__Port();
+
+	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); */
+	void Handle_Fd_Event_Error(int fd);
+	void Handle_Fd_Event_Writable(int fd);
+	void Handle_Fd_Event_Readable(int fd);
+	/* void Handle_Timeout(double time_since_last_call); */
+protected:
+	string pin; //Will contain the gpio pin name, e.g. "gpio24"
+	string pin_num; //Will contain only the gpio pin number, e.g. "24"
+
+	int fd_edge;
+
+	void user_map(const char *system_port);
+	void user_unmap(const char *system_port);
+
+	void user_start();
+	void user_stop();
+
+	void outgoing_send(const GPIO__PIN__DIRECTION& send_par);
+	void outgoing_send(const GPIO__PIN__VALUE& send_par);
+	void outgoing_send(const GPIO__PIN__STATUS& send_par);
+
+	void export_pin();
+	void unexport_pin();
+	void set_direction_of_pin(const string direction);
+	string get_direction_of_pin();
+	void set_value_of_pin(const string value);
+	string get_value_of_pin();
+	void set_edge_on_pin(const string edge);
+	void register_fd_handler(int fd);
+	void unregister_fd_handler(int fd);
+	string int2string(int i);
+	int string2int(const char* str);
+	void removechars(char* s, char c);
+	bool file_exists (const std::string& name);
+	string get_pin_dir();
+        GPIO__PIN__DIRECTION original_value;
+	};
+
+} /* end of namespace */
+
+#endif