Ejemplo n.º 1
0
class SimpleMQTTBoard:

    # ************   BEGIN CONSTANTS DEFINITION ****************

    DEBUG = True

    # ************   END CONSTANTS DEFINITION ****************

    # ************   BEGIN PRIVATE FIELDS DEFINITION ****************

    mqtt_client = None  # self board uses mqtt
    asip = None  # The client for the aisp protocol
    queue = Queue(
        10)  # Buffer # TODO: use pipe instead of queue for better performances
    #  FIXME: fix Queue dimension?
    Broker = ""
    _TCPport = 1883
    _ClientID = ""
    _SUBTOPIC = ""
    _PUBTOPIC = ""

    # ************   END PRIVATE FIELDS DEFINITION ****************

    # self constructor takes the Broker address
    # Here the listener and the queue reader are started
    def __init__(self, Broker, BoardID):
        try:
            self.Broker = Broker
            self._ClientID = "Client"
            self._SUBTOPIC = "asip/" + BoardID + "/out"
            self._PUBTOPIC = "asip/" + BoardID + "/in"

            self.mqtt_client = mqtt.Client(self._ClientID)
            self.mqtt_client.on_connect = self.on_connect
            self.connect()
            self.buffer = ""

            self.asip = AsipClient(self.SimpleMQTTWriter(self))
        except Exception as e:
            sys.stdout.write(
                "Exception: caught {} while init tcp socket and asip protocols\n"
                .format(e))

        try:
            # NOTICE: two request_port_mapping() are required. If this method is not called two times,
            # the client won't be able to set the pin mapping
            # time.sleep(0.5)
            # self.request_port_mapping()
            # time.sleep(1)
            # self.request_port_mapping()
            # time.sleep(1)

            # ListenerThread is the one that reads incoming messages from mqtt
            # ConsumerThread is the one that read the queue filled by ListenerThread and call the asip process_input
            # Sender is the thread that publish messages
            self.ListenerThread(self.queue, self.mqtt_client, True, self.DEBUG,
                                self._SUBTOPIC).start()
            self.ConsumerThread(self.queue, self.asip, True,
                                self.DEBUG).start()
            self.Sender(self).start()

            self.mqtt_client.loop_start()  # starting mqtt loop

            # TODO: check following code
            # while self.asip.isVersionOk() == False:  # flag will be set to true when valid version message is received
            #     self.request_info()
            #     time.sleep(1.0)
            while not self.asip.check_mapping():
                print("Requesting mapping")
                self.request_port_mapping()
                time.sleep(0.25)
            sys.stdout.write("**** Everything check ****\n")
        except Exception as e:
            #TODO: improve exception handling
            sys.stdout.write(
                "Exception: caught {} while launching threads\n".format(e))

    # ************ BEGIN PUBLIC METHODS *************

    # The following methods are just a replica from the asip class.
    # TODO: add parameter checikng in each function (raise exception?)
    def digital_read(self, pin):
        return self.asip.digital_read(pin)

    def analog_read(self, pin):
        return self.asip.analog_read(pin)

    def set_pin_mode(self, pin, mode):
        self.asip.set_pin_mode(pin, mode)

    def digital_write(self, pin, value):
        self.asip.digital_write(pin, value)

    def analog_write(self, pin, value):
        self.asip.analog_write(pin, value)

    def request_info(self):
        self.asip.request_info()

    def request_port_mapping(self):
        self.asip.request_port_mapping()

    def set_auto_report_interval(self, interval):
        self.asip.set_auto_report_interval(interval)

    def add_service(self, service_id, asip_service):
        self.asip.add_service(service_id, asip_service)

    def get_asip_client(self):
        return self.asip

    # ************ END PUBLIC METHODS *************

    # ************ BEGIN PRIVATE METHODS *************

    # The callback for when the client receives a CONNACK response from the server.
    def on_connect(self, client, userdata, flags, rc):
        if self.DEBUG:
            sys.stdout.write("DEBUG: Connected with result code {}".format(rc))

        # Subscribing in on_connect() means that if we lose the connection and
        # reconnect then subscriptions will be renewed.
        #self.mqtt_client.subscribe("$SYS/#")
        #self.mqtt_client.subscribe(self._SUBTOPIC)

    def connect(self):
        if self.DEBUG:
            sys.stdout.write(
                "DEBUG: Connecting to mqtt broker {} on port {}".format(
                    self.Broker, self._TCPport))
        self.mqtt_client.connect(self.Broker, self._TCPport, 180)

    def sendData(self, msg):
        self.mqtt_client.publish(self._PUBTOPIC, msg)

    def disconnect(self):
        if self.DEBUG:
            sys.stdout.write("DEBUG: DEBUG: Disconnected from mqtt")
        self.mqtt_client.disconnect()

    # ************ END PRIVATE METHODS *************

    # ************ BEGIN PRIVATE CLASSES *************

    class Sender(Thread):
        def __init__(self, parent):
            Thread.__init__(self)
            self.parent = parent
            self.running = True

        def run(self):
            while self.running:
                if not self.parent.buffer:
                    pass
                else:
                    if self.parent.DEBUG:
                        sys.stdout.write("DEBUG: Sending: {}\n".format(
                            self.parent.buffer[0:self.parent.buffer.index('\n'
                                                                          )]))
                    self.parent.mqtt_client.publish(
                        self.parent._PUBTOPIC,
                        self.parent.buffer[0:self.parent.buffer.index('\n')])
                    self.parent.buffer = self.parent.buffer[self.parent.buffer.
                                                            index('\n') + 1:]
                    if self.parent.DEBUG:
                        sys.stdout.write("DEBUG: Rest of buffer {}\n".format(
                            self.parent.buffer))

    # As described above, SimpleMQTTBoard writes messages to the tcp stream.
    # inner class SimpleMQTTWriter implements abstract class AsipWriter:
    class SimpleMQTTWriter(AsipWriter):
        parent = None

        def __init__(self, parent):
            self.parent = parent

        # val is a string
        # TODO: improve try catch
        def write(self, val):
            # TODO: insert a way to check weather the connection is still open or not
            try:
                # it fills a buffer
                self.parent.buffer = self.parent.buffer + val + '\n'
                if self.parent.DEBUG:
                    sys.stdout.write("DEBUG: Just sent {}".format(val))
            except Exception as e:
                pass

    # ListenerThread and ConsumerThread are implemented following the Producer/Consumer pattern
    # A class for a listener that read the tcp ip messages and put incoming messages on a queue
    # TODO: implement try catch
    class ListenerThread(Thread):

        queue = None
        mqtt_client = None
        running = False
        DEBUG = False
        temp_buff = ""

        # overriding constructor
        def __init__(self, queue, mqtt_client, running, debug, subtopic):
            Thread.__init__(self)
            self.queue = queue
            self.mqtt_client = mqtt_client
            self.mqtt_client.on_message = self.on_message  # callback
            self.mqtt_client.subscribe(topic=subtopic)
            self.running = running
            self.DEBUG = debug
            if self.DEBUG:
                sys.stdout.write("DEBUG: listener thread process created \n")

        # if needed, kill will stops the loop inside run method
        def kill(self):
            self.running = False

        # The callback for when a PUBLISH message is received from the server.
        def on_message(self, client, userdata, msg):
            if not msg.payload:
                pass
            else:
                temp = msg.payload.decode('utf-8')
                self.queue.put(temp)
                if self.DEBUG:
                    sys.stdout.write("DEBUG: Received {}\n".format(temp))

    # A class that reads the queue and launch the processInput method of the AispClient.
    class ConsumerThread(Thread):

        queue = None
        asip = None
        running = False
        DEBUG = False

        # overriding constructor
        def __init__(self, queue, asip, running, debug):
            Thread.__init__(self)
            self.queue = queue
            self.asip = asip
            self.running = running
            self.DEBUG = debug
            if self.DEBUG:
                sys.stdout.write("DEBUG: consumer thread created \n")

        # if needed, kill will stops the loop inside run method
        def kill(self):
            self.running = False

        # overriding run method, thread activity
        def run(self):
            while self.running:
                temp = self.queue.get()
                self.asip.process_input(temp)
                self.queue.task_done()
Ejemplo n.º 2
0
class TCPBoard:

    # ************   BEGIN CONSTANTS DEFINITION ****************

    DEBUG = True  # Activates debug messages
    __BUFFER_SIZE = 256  # TCP buffer size
    __RECV_TIMEOUT = 2  # socket receive timeout in second

    # ************   END CONSTANTS DEFINITION ****************

    # ************   BEGIN PRIVATE FIELDS DEFINITION ****************

    # asip: The client for the asip protocol
    # __sock_conn: tcp/ip socket communication
    __threads = []  # List of threads

    # ************   END PRIVATE FIELDS DEFINITION ****************

    # tcp_port = 6789 is the one used by the java bridge by franco in mirto
    def __init__(self, ip_address='127.0.0.1', tcp_port=5005):
        try:
            sys.stdout.write("Setting tcp: attempting to connect to {} and port {}\n".format(ip_address, tcp_port))
            self.__sock_conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.__sock_conn.connect((ip_address, tcp_port))
            self.asip = AsipClient(self.SimpleTCPWriter(self.__sock_conn, self.DEBUG))
        except Exception as e:
            sys.stdout.write("Exception caught in init tcp socket and asip protocols {}\n".format(e))
            try:  # try to close connection
                self.close_tcp_conn()
            finally:
                sys.exit(1)

        # Listener creation
        try:
            self.__threads.append(self.ListenerThread(
                self.asip, self.__sock_conn, self.__RECV_TIMEOUT, self.__BUFFER_SIZE, self.DEBUG))
            sys.stdout.write("Creating Threads: starting\n")
            self.__threads[0].start()
            while not self.__threads[0].is_alive():  # checking that listener is alive
                pass
            sys.stdout.write("Creating Threads: all threads created and alive\n")
        except Exception as e:
            sys.stdout.write("Caught exception in threads launch: {}\n".format(e))
            self.thread_killer()
            sys.exit(1)
        else:
            # Running
            try:
                # TODO: version checking still missing
                # flag will be set to true when valid version message is received
                # while self.asip.isVersionOk() == False:
                #     self.asip.request_info()
                #     time.sleep(1.0)
                # Checking mapping
                while not self.asip.check_mapping():
                    self.asip.request_port_mapping()
                    time.sleep(0.5)
                self.asip.set_auto_report_interval(0)
                sys.stdout.write("Creating Threads: Mapping received, auto-report interval set to 0. Running now!\n")

           # KeyboardInterrupt handling in order to close every thread correctly
            except KeyboardInterrupt:  # KeyboardInterrupt handling in order to close every thread correctly
                sys.stdout.write("KeyboardInterrupt while checking mapping. Attempting to close listener thread.\n")
                self.thread_killer()
                sys.exit()
            except Exception as e:  # killing threads and exiting in case of generic exception
                sys.stdout.write("Caught generic exception while checking mapping: {}\n".format(e))
                self.thread_killer()
                sys.exit(1)

    # ************ BEGIN PUBLIC METHODS *************

    # stops and waits for the join for threads in the given pool
    # TODO: improve in case of timeout of the join
    def thread_killer(self):
        for i in self.__threads:
            try:
                i.stopper()
                sys.stdout.write("Killing Threads: event for {} successfully set\n".format(i))
            except Exception as e:
                sys.stdout.write("Caught exception while stropping thread {}.\nException is: {}\n".format(i, e))
        time.sleep(0.5)
        sys.stdout.write("Killing Threads: waiting for join\n")
        for i in self.__threads:
            i.join()
            sys.stdout.write("Killing Threads: thread {} successfully closed\n".format(i))
        self.__threads = []
        try:
            self.close_tcp_conn()
        except Exception as e:
            sys.stdout.write("Caught generic exception while calling close_tcp_conn: {}\n".format(e))
        sys.stdout.write("All threads terminated.\n")
        return True

    def get_asip_client(self):
        return self.asip

    # ************ END PUBLIC METHODS *************

    # ************ BEGIN PRIVATE METHODS *************

    def close_tcp_conn(self):
        self.__sock_conn.shutdown(socket.SHUT_RDWR)
        self.__sock_conn.close()
        sys.stdout.write("Connection closed.\n")

    # ************ END PRIVATE METHODS *************

    # ************ BEGIN PRIVATE CLASSES *************

    # As described above, SimpleTCPBoard writes messages to the tcp stream.
    # inner class SimpleTCPWriter implements abstract class AsipWriter:
    class SimpleTCPWriter(AsipWriter):

        def __init__(self, sock_conn, debug=False):
            self.sock_conn = sock_conn
            self.DEBUG = debug

        # val is a string
        # TODO: improve try catch
        def write(self, val):
            # TODO: insert a way to check weather the connection is still open or not
            try:
                self.sock_conn.send(val)
                if self.DEBUG:
                    sys.stdout.write("DEBUG: sent {}\n".format(val))
            except Exception as e:
                sys.stdout.write("Caught exception in serial write: {}\n".format(e))

    # ListenerThread read the tcp/ip stream and call process_input
    class ListenerThread(Thread):

        # overriding constructor
        def __init__(self, asip, sock_conn, timeout, buffer_size=256, debug=False):
            Thread.__init__(self)
            self.asip = asip
            self.sock_conn = sock_conn
            self.sock_conn.settimeout(timeout)  # setting socket recv timeout
            self.BUFFER_SIZE = buffer_size
            self.DEBUG = debug
            self._stopper = threading.Event()
            sys.stdout.write("Listener Thread: thread process created.\n")

        # if needed, kill will stops the loop inside run method
        def stopper(self):
            sys.stdout.write("Listener Thread: now stopping.\n")
            self._stopper.set()

        # overriding run method, thread activity
        def run(self):
            time.sleep(2)  # TODO: maybe reduce this sleep?
            sys.stdout.write("Listener Thread: now running.\n")
            temp_buffer = ""
            while not self._stopper.is_set():
                try:
                    data = self.sock_conn.recv(self.BUFFER_SIZE)
                    # sys.stdout.write("Received data is: {}\n".format(data))
                    if data != '\r' and data != '\n' and data != ' ' and data is not None:  # ignore empty lines
                        if "\n" in data:
                            # If there is at least one newline, we need to process
                            # the message (the buffer may contain previous characters).
                            while "\n" in data and len(data) > 0:
                                # But remember that there could be more than one newline in the buffer
                                temp_buffer += (data[0:data.index("\n")])
                                temp = temp_buffer.encode()
                                self.asip.process_input(temp)
                                temp_buffer = ""
                                if data[data.index("\n")+1:] == '\n':
                                    data = ''
                                    break
                                else:
                                    data = data[data.index("\n")+1:]
                            if len(data) > 0 and data not in ('\r', '\n', ' '):
                                temp_buffer = data
                        else:
                            temp_buffer += data
                except socket.timeout as e:
                    err = e.args[0]
                    if err == 'timed out':  # socket time out, if the _stop value is set, program will exit
                        continue
                except Exception as e:
                    sys.stdout.write("Caught exception in listener: {}\nListener will now stop\n".format(e))
                    self.stopper()

            sys.stdout.write("Listener Thread: stopped\n")

    # ************ END PRIVATE CLASSES *************
Ejemplo n.º 3
0
class MQTTBoard:

    # ************   BEGIN CONSTANTS DEFINITION ****************

    DEBUG = True  # Activates debug messages
    __TCP_port = 1883  # MQTT registered port

    # ************   END CONSTANTS DEFINITION ****************

    # ************   BEGIN PRIVATE FIELDS DEFINITION ****************

    # asip: The client for the asip protocol
    # mqtt_client: self board uses mqtt
    __threads = []  # List of threads

    # ************   END PRIVATE FIELDS DEFINITION ****************

    # self constructor takes the broker address and the target board
    # client name and keepalive are optional parameters
    def __init__(self,
                 broker_ip,
                 target_board,
                 my_name="Client",
                 keepalive=180):

        # setting mqtt connection and asip protocol
        try:
            sys.stdout.write(
                "Setting mqtt: attempting to connect to broker {}\n".format(
                    broker_ip))
            self.__Broker = broker_ip
            self.__keepalive = keepalive
            self.__SUBTOPIC = "asip/" + target_board + "/in"
            self.__PUBTOPIC = "asip/" + target_board + "/out"

            self.mqtt_client = mqtt.Client(my_name)
            self.mqtt_client.on_connect = self.on_connect
            self.connect()

            self.asip = AsipClient(
                self.SimpleMQTTWriter(self.mqtt_client, self.__PUBTOPIC,
                                      self.DEBUG))
        except Exception as e:
            sys.stdout.write(
                "Exception caught in init mqtt and asip protocols: {}\n".
                format(e))
            try:  # try to close connection
                self.disconnect()
            except Exception as e:
                sys.stdout.write(
                    "Caught generic exception while disconnecting MQTT: {}\n".
                    format(e))
            finally:
                sys.exit(1)

        # Listener creation
        try:
            self.__threads.append(
                self.ListenerThread(self.asip, self.mqtt_client,
                                    self.__SUBTOPIC, self.DEBUG))
            sys.stdout.write("Creating Threads: starting\n")
            self.__threads[0].start()
            while not self.__threads[0].is_alive(
            ):  # checking that listener is alive
                pass
            sys.stdout.write(
                "Creating Threads: all threads created and alive\n")

            self.mqtt_client.loop_start()  # starting mqtt loop

        except Exception as e:
            sys.stdout.write(
                "Caught exception in threads launch: {}\n".format(e))
            self.thread_killer()
            sys.exit(1)
        else:
            # Running
            try:
                # TODO: version checking still missing
                # flag will be set to true when valid version message is received
                # while self.asip.isVersionOk() == False:
                #     self.asip.request_info()
                #     time.sleep(1.0)
                # Checking mapping
                while not self.asip.check_mapping():
                    self.asip.request_port_mapping()
                    time.sleep(0.5)
                self.asip.set_auto_report_interval(0)
                sys.stdout.write(
                    "Creating Threads: Mapping received, auto-report interval set to 0. Running now!\n"
                )

        # KeyboardInterrupt handling in order to close every thread correctly
            except KeyboardInterrupt:  # KeyboardInterrupt handling in order to close every thread correctly
                sys.stdout.write(
                    "KeyboardInterrupt while checking mapping. Attempting to close listener thread.\n"
                )
                self.thread_killer()
                sys.exit()
            except Exception as e:  # killing threads and exiting in case of generic exception
                sys.stdout.write(
                    "Caught generic exception while checking mapping: {}\n".
                    format(e))
                self.thread_killer()
                sys.exit(1)

    # ************ BEGIN PUBLIC METHODS *************

    # stops and waits for the join for threads in the given pool
    # TODO: improve in case of timeout of the join
    def thread_killer(self):
        for i in self.__threads:
            try:
                i.stopper()
                sys.stdout.write(
                    "Killing Threads: event for {} successfully set\n".format(
                        i))
            except Exception as e:
                sys.stdout.write(
                    "Caught exception while stropping thread {}.\nException is: {}\n"
                    .format(i, e))
        time.sleep(0.5)
        sys.stdout.write("Killing Threads: waiting for join\n")
        for i in self.__threads:
            i.join()
            sys.stdout.write(
                "Killing Threads: thread {} successfully closed\n".format(i))
        self.__threads = []
        try:
            self.disconnect()
        except Exception as e:
            sys.stdout.write(
                "Caught generic exception while disconnecting MQTT: {}\n".
                format(e))
        sys.stdout.write("All threads terminated.\n")
        return True

    def get_asip_client(self):
        return self.asip

    # ************ END PUBLIC METHODS *************

    # ************ BEGIN PRIVATE METHODS *************

    # The callback for when the client receives a CONNACK response from the server.
    def on_connect(self, client, userdata, flags, rc):
        if self.DEBUG:
            sys.stdout.write("Connected with result code: {}\n".format(rc))

    def connect(self):
        self.mqtt_client.connect(self.__Broker, self.__TCP_port,
                                 self.__keepalive)
        sys.stdout.write(
            "Connected to MQTT broker: {}  port: {} keepalive: {} .\n".format(
                self.__Broker, self.__TCP_port, self.__keepalive))

    def disconnect(self):
        self.mqtt_client.disconnect()
        sys.stdout.write("Disconnected from MQTT broker.\n")

    # ************ END PRIVATE METHODS *************

    # ************ BEGIN PRIVATE CLASSES *************

    # SimpleMQTTBoard writes messages to the MQTT stream.
    # inner class SimpleMQTTWriter implements abstract class AsipWriter:
    class SimpleMQTTWriter(AsipWriter):
        def __init__(self, mqtt_client, pubtopic, debug=False):
            self.mqtt_client = mqtt_client
            self.pubtopic = pubtopic
            self.DEBUG = debug

        # val is a string
        # TODO: improve try catch
        def write(self, val):
            # TODO: insert a way to check weather the connection is still open or not
            try:
                self.mqtt_client.publish(self.pubtopic, val)
                if self.DEBUG:
                    sys.stdout.write("DEBUG: sent {}\n".format(val))
            except Exception as e:
                sys.stdout.write(
                    "Caught exception in MQTT publish: {}\n".format(e))

    # ListenerThread read the mqtt stream and call process_input
    class ListenerThread(Thread):

        # overriding constructor
        def __init__(self, asip, mqtt_client, subtopic, debug=False):
            Thread.__init__(self)
            self.asip = asip
            self.mqtt_client = mqtt_client
            self.mqtt_client.on_message = self.on_message  # callback
            self.DEBUG = debug
            self.listener_buffer = ""
            self.mqtt_client.subscribe(topic=subtopic)
            sys.stdout.write(
                "Listener Thread: subscribed to topic: {} .\n".format(
                    subtopic))
            self._stopper = threading.Event()
            sys.stdout.write("Listener Thread: thread process created.\n")

        # if needed, kill will stops the loop inside run method
        def stopper(self):
            sys.stdout.write("Listener Thread: now stopping.\n")
            self._stopper.set()

        # The callback for when a PUBLISH message is received from the server.
        def on_message(self, client, userdata, msg):
            try:
                if not msg.payload:
                    pass
                else:
                    data = msg.payload.decode('utf-8')
                    if data != '\r' and data != '\n' and data != ' ':  # ignore empty lines
                        self.listener_buffer += data
                    if self.DEBUG:
                        sys.stdout.write("DEBUG: Received {}\n".format(data))
            except Exception as e:
                sys.stdout.write(
                    "Exception in listener on_message method: {}\nListener will now stop\n"
                    .format(e))
                self.stopper()

        # overriding run method, thread activity
        def run(self):
            time.sleep(2)  # TODO: maybe reduce this sleep?
            sys.stdout.write("Listener Thread: now running.\n")
            while not self._stopper.is_set():
                time.sleep(0.001)  # TODO: thread concurrency
                try:
                    # If there is at least one newline, we need to process the message
                    # (the buffer may contain previous characters).
                    while "\n" in self.listener_buffer:
                        temp = self.listener_buffer[0:self.listener_buffer.
                                                    index("\n")]
                        self.asip.process_input(temp)
                        self.listener_buffer = self.listener_buffer[
                            self.listener_buffer.index("\n") + 1:]
                except Exception as e:
                    sys.stdout.write(
                        "Exception in listener run method: {}\nListener will now stop\n"
                        .format(e))
                    self.stopper()

            sys.stdout.write("Listener Thread: stopped\n")
Ejemplo n.º 4
0
class SerialBoard:

    # ************   BEGIN CONSTANTS DEFINITION ****************

    DEBUG = False  # Activates debug messages
    __SERIAL_TIMEOUT = 2  # serial timeout (avoid blocking in case of issues)
    __PORT_INDEX_TO_OPEN = 0
    __BAUD_RATE = 57600

    # ************   END CONSTANTS DEFINITION ****************

    # ************   BEGIN PRIVATE FIELDS DEFINITION ****************

    # asip: The client for the asip protocol
    # __ser_conn: self board uses serial communication
    __ports = []  # serial ports array
    __threads = []  # List of threads

    # ************   END PRIVATE FIELDS DEFINITION ****************

    # Self constructor find the name of an active serial port and it creates a Serial objted
    def __init__(self):

        # Serial connection creation, AsipClient object creation
        try:
            self.__ser_conn = Serial()
            self.serial_port_finder(self.__PORT_INDEX_TO_OPEN)
            sys.stdout.write("Setting Serial: attempting to open {}\n".format(self.__ports[self.__PORT_INDEX_TO_OPEN]))
            self.open_serial(self.__ports[self.__PORT_INDEX_TO_OPEN], self.__BAUD_RATE)
            sys.stdout.write("Setting Serial: serial port {} opened\n".format(self.__ports[self.__PORT_INDEX_TO_OPEN]))
            self.asip = AsipClient(self.SimpleWriter(self.__ser_conn, self.DEBUG))
        except serial.SerialException as e:
            sys.stdout.write("Exception while init serial connection: {}\n".format(e))
            sys.exit(1)

        # Listener creation
        try:
            self.__threads.append(self.ListenerThread(self.asip, self.__ser_conn, self.DEBUG))
            sys.stdout.write("Creating Threads: starting\n")
            self.__threads[0].start()
            while not self.__threads[0].is_alive():  # checking that listener is alive
                pass
            sys.stdout.write("Creating Threads: all threads created and alive\n")
        except Exception as e:
            sys.stdout.write("Caught exception in threads launch: {}\n".format(e))
            self.thread_killer()
            sys.exit(1)
        else:
            # Running
            try:
                # TODO: version checking still mis
                # flag will be set to true when valid version message is received
                # while self.asip.isVersionOk() == False:
                #     self.asip.request_info()
                #     time.sleep(1.0)sing
                # Checking mapping
                while not self.asip.check_mapping():
                    self.asip.request_port_mapping()
                    time.sleep(0.5)
                self.asip.set_auto_report_interval(100)
                sys.stdout.write("Creating Threads: Mapping received, auto-report interval set to 0. Running now!\n")
            except KeyboardInterrupt:  # KeyboardInterrupt handling in order to close every thread correctly
                sys.stdout.write("KeyboardInterrupt while checking mapping. Attempting to close listener thread.\n")
                self.thread_killer()
                sys.exit()
            except Exception as e:  # killing threads and exiting in case of generic exception
                sys.stdout.write("Caught generic exception while checking mapping: {}\n".format(e))
                self.thread_killer()
                sys.exit(1)

    # ************ BEGIN PUBLIC METHODS *************

    # stops and wait for the join for threads in the given pool
    # TODO: improve in case of timeout of the join
    def thread_killer(self):
        for i in self.__threads:
            try:
                i.stopper()
                sys.stdout.write("Killing Threads: event for {} successfully set\n".format(i))
            except Exception as e:
                sys.stdout.write("Caught exception while stropping thread {}.\nException is: {}\n".format(i, e))
        time.sleep(0.5)
        sys.stdout.write("Killing Threads: waiting for join\n")
        for i in self.__threads:
            i.join()
            sys.stdout.write("Killing Threads: thread {} successfully closed\n".format(i))
        self.__threads = []
        sys.stdout.write("All threads terminated.\n")
        return True

    def get_asip_client(self):
        return self.asip

    # ************ END PUBLIC METHODS *************

    # ************ BEGIN PRIVATE METHODS *************

    def open_serial(self, port, baud_rate):
        if self.__ser_conn.isOpen():
            self.__ser_conn.close()
        self.__ser_conn.port = port
        self.__ser_conn.baudrate = baud_rate
        self.__ser_conn.timeout = self.__SERIAL_TIMEOUT
        self.__ser_conn.open()
        # Toggle DTR to reset Arduino
        self.__ser_conn.setDTR(False)
        time.sleep(1)
        # toss any data already received, see
        self.__ser_conn.flushInput()
        time.sleep(1)
        self.__ser_conn.setDTR(True)
        time.sleep(1)

    def close_serial(self):
        self.__ser_conn.close()

    # This methods retrieves the operating system and set the Arduino serial port
    """Lists serial ports

    :raises EnvironmentError:
        On unsupported or unknown platforms
    :returns:
        A list of available serial ports
    """
    # TODO: test needed for linux and windows implementation
    # TODO: improve try except
    def serial_port_finder(self, desired_index):

        system = sys.platform
        if system.startswith('win'):
            temp_ports = ['COM' + str(i + 1) for i in range(255)]
        elif system.startswith('linux'):
            # this is to exclude your current terminal "/dev/tty"
            temp_ports = glob.glob('/dev/tty[A-Za-z]*')
        elif system.startswith('darwin'):
            temp_ports = glob.glob('/dev/tty.usbmodem*')
            cp2104 = glob.glob('/dev/tty.SLAB_USBtoUART')  # append usb to serial converter cp2104
            ft232rl = glob.glob('/dev/tty.usbserial-A9MP5N37')  # append usb to serial converter ft232rl
            fth = glob.glob('/dev/tty.usbserial-FTHI5TLH')  # append usb to serial cable
            #new = glob.glob('/dev/tty.usbmodemfd121')
            #temp_ports = glob.glob('/dev/tty.SLAB_USBtoUART')
            #temp_ports = glob.glob('/dev/tty.usbserial-A9MP5N37')
            if cp2104 is not None:
                temp_ports += cp2104
            if ft232rl is not None:
                temp_ports += ft232rl
            if fth is not None:
                temp_ports += fth
            #if new is not None: # FIXME: REMOVE!!! Only used for tests
            #    temp_ports = new
        else:
            raise EnvironmentError('Unsupported platform')

        for port in temp_ports:
            try:
                self.__ser_conn.port = port
                self.__ser_conn.open()
                self.__ser_conn.close()
                self.__ports.append(port)
                if len(self.__ports) > desired_index:
                    return  # we have found the desired port
            except serial.SerialException:
                pass
        if self.DEBUG:
            sys.stdout.write("DEBUG: available ports are {}\n".format(self.__ports))

    # ************ END PRIVATE METHODS *************

    # ************ BEGIN PRIVATE CLASSES *************

    # As described above, SimpleSerialBoard writes messages to the serial port.
    # inner class SimpleWriter implements abstract class AsipWriter:
    class SimpleWriter(AsipWriter):

        def __init__(self, ser_conn, debug=False):
            self.ser_conn = ser_conn
            self.DEBUG = debug

        # val is a string
        # TODO: improve try catch, add exit in case of exception too
        def write(self, val):
            if self.ser_conn.isOpen():
                try:
                    temp = val.encode()
                    self.ser_conn.write(temp)
                    if self.DEBUG:
                        sys.stdout.write("DEBUG: just wrote in serial {}\n".format(temp))
                except (OSError, serial.SerialException) as e:
                    sys.stdout.write("Caught exception in serial write: {}\n".format(e))
            else:
                raise serial.SerialException

    # ListenerThread read the serial stream and call process_input
    class ListenerThread(Thread):

        # overriding constructor
        def __init__(self, asip, ser_conn, debug=False):
            Thread.__init__(self)
            self.asip = asip
            self.ser_conn = ser_conn
            self.DEBUG = debug
            self._stopper = threading.Event()
            sys.stdout.write("Listener Thread: thread process created.\n")

        # if needed, kill will stops the loop inside run method
        def stopper(self):
            sys.stdout.write("Listener Thread: now stopping.\n")
            self._stopper.set()

        # overriding run method, thread activity
        def run(self):
            time.sleep(2)  # TODO: maybe reduce this sleep?
            sys.stdout.write("Listener Thread: now running.\n")
            ser_buffer = ""
            while not self._stopper.is_set():
                try:
                    c = self.ser_conn.read()  # attempt to read a character from Serial
                    c = c.decode('utf-8', errors='ignore')
                    if len(c) == 0:  # was anything read?
                        pass
                    else:
                        # if self.DEBUG:
                        #    sys.stdout.write("DEBUG: Char from serial: {}\n".format(c))
                        if c == '\n' or c == '\n':
                            if len(ser_buffer) > 0:
                                ser_buffer += '\n'
                                self.asip.process_input(ser_buffer)
                                if self.DEBUG:
                                    sys.stdout.write("DEBUG: Complete message from serial: {}\n".format(ser_buffer))
                            ser_buffer = ""
                        else:
                            ser_buffer += c
                except serial.SerialTimeoutException:
                    continue  # Go to next iteration in case of serial timeout
                except serial.SerialException as e:
                    sys.stdout.write(
                        "Caught SerialException in serial read: {}\nListener Thread will now stop\n".format(e))
                    self.stopper()
                except Exception as e:
                    sys.stdout.write("Caught exception: {}\nListener Thread will NOT stop\n".format(e))
                    #self.stopper()

            sys.stdout.write("Listener Thread: stopped\n")
class SimpleSerialBoard:

    # ************   BEGIN CONSTANTS DEFINITION ****************

    DEBUG = False

    # ************   END CONSTANTS DEFINITION ****************

    # ************   BEGIN PRIVATE FIELDS DEFINITION ****************

    ser_conn = None  # self board uses serial communication
    asip = None  # The client for the aisp protocol
    queue = Queue(
        10)  # Buffer # TODO: use pipe instead of queue for better performances
    #  FIXME: fix Queue dimension?
    _port = ""  #serial port
    _ports = []  #serial ports array

    # ************   END PRIVATE FIELDS DEFINITION ****************

    # self constructor takes the name of the serial port and it creates a Serial object
    # Here the serial listener and the queue reader are started
    def __init__(self):
        # TODO: very simple implementation, need to improve
        #self.ser_conn = Serial()
        #self.serial_port_finder()
        try:
            # old implementation was:
            #self.ser_conn = Serial(port='/dev/cu.usbmodemfd121', baudrate=57600)
            # self.ser_conn = Serial(port=self._port, baudrate=57600)
            self.ser_conn = Serial()
            portIndexToOpen = 0
            self.serial_port_finder(portIndexToOpen)
            print("attempting to open " + self._ports[portIndexToOpen])
            self.open_serial(self._ports[0], 57600)
            print("port opened")
            self.asip = AsipClient(self.SimpleWriter(self))
        except Exception as e:
            sys.stdout.write(
                "Exception: caught {} while init serial and asip protocols\n".
                format(e))

        try:
            self.ListenerThread(self.queue, self.ser_conn, True,
                                self.DEBUG).start()
            self.ConsumerThread(self.queue, self.asip, True,
                                self.DEBUG).start()
            while self.asip.isVersionOk(
            ) == False:  # flag will be set to true when valid version message is received
                self.request_info()
                time.sleep(1.0)
            self.request_port_mapping()
            #time.sleep(1)
        except Exception as e:
            #TODO: improve exception handling
            sys.stdout.write(
                "Exception: caught {} while launching threads\n".format(e))

    # ************ BEGIN PUBLIC METHODS *************

    # The following methods are just a replica from the asip class.
    # TODO: add parameter checikng in each function (raise exception?)
    def digital_read(self, pin):
        return self.asip.digital_read(pin)

    def analog_read(self, pin):
        return self.asip.analog_read(pin)

    def set_pin_mode(self, pin, mode):
        self.asip.set_pin_mode(pin, mode)

    def digital_write(self, pin, value):
        self.asip.digital_write(pin, value)

    def analog_write(self, pin, value):
        self.asip.analog_write(pin, value)

    def request_info(self):
        self.asip.request_info()

    def request_port_mapping(self):
        self.asip.request_port_mapping()

    def set_auto_report_interval(self, interval):
        self.asip.set_auto_report_interval(interval)

    def add_service(self, service_id, asip_service):
        self.asip.add_service(service_id, asip_service)

    def get_asip_client(self):
        return self.asip

    # ************ END PUBLIC METHODS *************

    # ************ BEGIN PRIVATE METHODS *************

    def open_serial(self, port, baudrate):
        if self.ser_conn.isOpen():
            self.ser_conn.close()
        self.ser_conn.port = port
        self.ser_conn.baudrate = baudrate
        self.ser_conn.open()
        # Toggle DTR to reset Arduino
        self.ser_conn.setDTR(False)
        time.sleep(1)
        # toss any data already received, see
        self.ser_conn.flushInput()
        self.ser_conn.setDTR(True)

    def close_serial(self):
        self.ser_conn.close()

    # This methods retrieves the operating system and set the Arduino serial port
    """Lists serial ports

    :raises EnvironmentError:
        On unsupported or unknown platforms
    :returns:
        A list of available serial ports
    """

    # TODO: test needed for linux and windows implementation
    def serial_port_finder(self, desiredIndex):
        #system = platform.system()
        # if self.DEBUG:
        #     sys.stdout.write("DEBUG: detected os is {}\n".format(system))
        # if 'linux' in system:
        #     pass
        # elif 'Darwin' == system: # also 'mac' or 'darwin' may work?
        #     for file in os.listdir("/dev"):
        #         if file.startswith("tty.usbmodem"):
        #             self._port = "/dev/" + file
        #             if self.DEBUG:
        #                 sys.stdout.write("DEBUG: serial file is {}\n".format(file))
        #             break
        # elif ('win' in system) or ('Win' in system) or ('cygwin' in system) or ('nt' in system):
        #     pass
        # else:
        #     raise EnvironmentError('Unsupported platform')
        # if self.DEBUG:
        #     sys.stdout.write("DEBUG: port is {}\n".format(self._port))

        system = sys.platform
        if system.startswith('win'):
            temp_ports = ['COM' + str(i + 1) for i in range(255)]
        elif system.startswith('linux'):
            # this is to exclude your current terminal "/dev/tty"
            temp_ports = glob.glob('/dev/tty[A-Za-z]*')
        elif system.startswith('darwin'):
            temp_ports = glob.glob('/dev/tty.usbmodem*')
        else:
            raise EnvironmentError('Unsupported platform')

        for port in temp_ports:
            try:
                self.ser_conn.port = port
                s = self.ser_conn.open()
                self.ser_conn.close()
                self._ports.append(port)
                if (len(self._ports) > desiredIndex):
                    return  # we have found the desired port
            except serial.SerialException:
                pass
        if self.DEBUG:
            sys.stdout.write("DEBUG: available ports are {}\n".format(
                self._ports))

    # ************ END PRIVATE METHODS *************

    # ************ BEGIN PRIVATE CLASSES *************

    # As described above, SimpleSerialBoard writes messages to the serial port.
    # inner class SimpleWriter implements abstract class AsipWriter:
    class SimpleWriter(AsipWriter):
        parent = None

        def __init__(self, parent):
            self.parent = parent

        # val is a string
        # TODO: improve try catch
        def write(self, val):
            #print(val),
            if self.parent.ser_conn.isOpen():
                try:
                    self.parent.ser_conn.write(val.encode())
                except (OSError, serial.SerialException):
                    pass
            else:
                raise serial.SerialException

    # ListenerThread and ConsumerThread are implemented following the Producer/Consumer pattern
    # A class for a listener that rad the serial stream and put incoming messages on a queue
    # TODO: implement try catch
    class ListenerThread(Thread):

        queue = None
        ser_conn = None
        running = False
        DEBUG = False

        # overriding constructor
        def __init__(self, queue, ser_conn, running, debug):
            Thread.__init__(self)
            self.queue = queue
            self.ser_conn = ser_conn
            self.running = running
            self.DEBUG = debug
            if self.DEBUG:
                sys.stdout.write("DEBUG: serial thread process created \n")

        # if needed, kill will stops the loop inside run method
        def kill(self):
            self.running = False

        # overriding run method, thread activity
        def run(self):
            temp_buff = ""
            time.sleep(2)
            # TODO: implement ser.inWaiting() >= minMsgLen to check number of char in the receive buffer?

            while self.running:
                if self.DEBUG:
                    sys.stdout.write(
                        "DEBUG: Temp buff is now {}\n".format(temp_buff))
                val = self.ser_conn.readline()
                if self.DEBUG:
                    sys.stdout.write(
                        "DEBUG: val value when retrieving from serial is {}\n".
                        format(val))
                val = val.decode('utf-8')
                if self.DEBUG:
                    sys.stdout.write(
                        "DEBUG: val value after decode is {}".format(val))
                if val is not None and val != "\n":
                    if "\n" in val:
                        # If there is at least one newline, we need to process
                        # the message (the buffer may contain previous characters).

                        while ("\n" in val and len(val) > 0):
                            # But remember that there could be more than one newline in the buffer
                            temp_buff += (val[0:val.index("\n")])
                            self.queue.put(temp_buff)
                            if self.DEBUG:
                                sys.stdout.write(
                                    "DEBUG: Serial produced {}\n".format(
                                        temp_buff))
                            temp_buff = ""
                            val = val[val.index("\n") + 1:]
                            if self.DEBUG:
                                sys.stdout.write(
                                    "DEBUG: Now val is {}\n".format(val))
                        if len(val) > 0:
                            temp_buff = val
                        if self.DEBUG:
                            sys.stdout.write(
                                "DEBUG: After internal while buffer is {}\n".
                                format(temp_buff))
                    else:
                        temp_buff += val
                        if self.DEBUG:
                            sys.stdout.write(
                                "DEBUG: else case, buff is equal to val, so they are {}\n"
                                .format(temp_buff))

    # A class that reads the queue and launch the processInput method of the AispClient.
    class ConsumerThread(Thread):

        queue = None
        asip = None
        running = False
        DEBUG = False

        # overriding constructor
        def __init__(self, queue, asip, running, debug):
            Thread.__init__(self)
            self.queue = queue
            self.asip = asip
            self.running = running
            self.DEBUG = debug
            if self.DEBUG:
                sys.stdout.write("DEBUG: consumer thread created \n")

        # if needed, kill will stops the loop inside run method
        def kill(self):
            self.running = False

        # overriding run method, thread activity
        def run(self):
            # global _queue
            # global asip
            while self.running:
                temp = self.queue.get()
                self.asip.process_input(temp)
                self.queue.task_done()
Ejemplo n.º 6
0
class SimpleSerialBoard:

    # ************   BEGIN CONSTANTS DEFINITION ****************

    DEBUG = True

    # ************   END CONSTANTS DEFINITION ****************

    # ************   BEGIN PRIVATE FIELDS DEFINITION ****************

    ser_conn = None  # self board uses serial communication
    asip = None  # The client for the aisp protocol
    queue = Queue(10)  # Buffer # TODO: use pipe instead of queue for better performances
    #  FIXME: fix Queue dimension?
    _port = "" #serial port
    _ports = [] #serial ports array
    __running = False
  
    # ************   END PRIVATE FIELDS DEFINITION ****************

    # self constructor takes the name of the serial port and it creates a Serial object
    # Here the serial listener and the queue reader are started
    def __init__(self):
        # TODO: very simple implementation, need to improve
        #self.ser_conn = Serial()
        #self.serial_port_finder()
        try:
            # old implementation was:
            #self.ser_conn = Serial(port='/dev/cu.usbmodemfd121', baudrate=57600)
            # self.ser_conn = Serial(port=self._port, baudrate=57600)
            self.ser_conn = Serial()
            portIndexToOpen = 0             
            self.serial_port_finder(portIndexToOpen)
            sys.stdout.write("attempting to open {}\n".format(self._ports[portIndexToOpen]))
            self.open_serial(self._ports[0], 57600)      
            sys.stdout.write("port opened\n")
            self.asip = AsipClient(self.SimpleWriter(self))
        except Exception as e:
            sys.stdout.write("Exception: caught {} while init serial and asip protocols\n".format(e))

        try:
            self.__running = True
            self.ListenerThread(self.queue, self.ser_conn, self.__running, self.DEBUG).start()
            self.ConsumerThread(self.queue, self.asip, self.__running, self.DEBUG).start()
            self.KeyboardListener(self).start()
            print("****** I am here ******")
            #while self.asip.isVersionOk() == False:  # flag will be set to true when valid version message is received
                #self.request_info()
                #time.sleep(1.0)
            self.request_port_mapping()          
            time.sleep(1)
            self.request_port_mapping()
            time.sleep(1)
            while not self.asip.check_mapping():
                self.request_port_mapping()
                time.sleep(0.1)
            print("**** Everything check ****")
        except Exception as e:
            #TODO: improve exception handling
            sys.stdout.write("Exception: caught {} while launching threads\n".format(e))


    # ************ BEGIN PUBLIC METHODS *************

    # The following methods are just a replica from the asip class.
    # TODO: add parameter checikng in each function (raise exception?)
    def digital_read(self, pin):
        return self.asip.digital_read(pin)

    def analog_read(self, pin):
        return self.asip.analog_read(pin)

    def set_pin_mode(self, pin, mode):
        self.asip.set_pin_mode(pin, mode)

    def digital_write(self, pin, value):
        self.asip.digital_write(pin, value)

    def analog_write(self, pin, value):
        self.asip.analog_write(pin, value)

    def request_info(self):
        self.asip.request_info()
    
    def request_port_mapping(self):
        self.asip.request_port_mapping()

    def set_auto_report_interval(self, interval):
        self.asip.set_auto_report_interval(interval)

    def add_service(self, service_id, asip_service):
        self.asip.add_service(service_id, asip_service)

    def get_asip_client(self):
        return self.asip

    # ************ END PUBLIC METHODS *************


    # ************ BEGIN PRIVATE METHODS *************

    def open_serial(self, port, baudrate):
        if self.ser_conn.isOpen():
            self.ser_conn.close()
        self.ser_conn.port = port
        self.ser_conn.baudrate = baudrate
        # self.ser_conn.timeout = None # 0 or None?
        self.ser_conn.open()
        # Toggle DTR to reset Arduino
        self.ser_conn.setDTR(False)
        time.sleep(1)
        # toss any data already received, see
        self.ser_conn.flushInput()
        self.ser_conn.setDTR(True)

    def close_serial(self):
        self.ser_conn.close()

    # This methods retrieves the operating system and set the Arduino serial port
    """Lists serial ports

    :raises EnvironmentError:
        On unsupported or unknown platforms
    :returns:
        A list of available serial ports
    """
    # TODO: test needed for linux and windows implementation
    def serial_port_finder(self, desiredIndex):
        #system = platform.system()
        # if self.DEBUG:
        #     sys.stdout.write("DEBUG: detected os is {}\n".format(system))
        # if 'linux' in system:
        #     pass
        # elif 'Darwin' == system: # also 'mac' or 'darwin' may work?
        #     for file in os.listdir("/dev"):
        #         if file.startswith("tty.usbmodem"):
        #             self._port = "/dev/" + file
        #             if self.DEBUG:
        #                 sys.stdout.write("DEBUG: serial file is {}\n".format(file))
        #             break
        # elif ('win' in system) or ('Win' in system) or ('cygwin' in system) or ('nt' in system):
        #     pass
        # else:
        #     raise EnvironmentError('Unsupported platform')
        # if self.DEBUG:
        #     sys.stdout.write("DEBUG: port is {}\n".format(self._port))

        system = sys.platform
        if system.startswith('win'):
            temp_ports = ['COM' + str(i + 1) for i in range(255)]          
        elif system.startswith('linux'):
            # this is to exclude your current terminal "/dev/tty"
            temp_ports = glob.glob('/dev/tty[A-Za-z]*')
        elif system.startswith('darwin'):
            temp_ports = glob.glob('/dev/tty.usbmodem*')
            cp2104 = glob.glob('/dev/tty.SLAB_USBtoUART') # append usb to serial converter cp2104
            ft232rl = glob.glob('/dev/tty.usbserial-A9MP5N37') # append usb to serial converter ft232rl
            fth = glob.glob('/dev/tty.usbserial-FTHI5TLH') # append usb to serial cable
            # new = glob.glob('/dev/tty.usbmodemfa131')
            #temp_ports = glob.glob('/dev/tty.SLAB_USBtoUART')
            #temp_ports = glob.glob('/dev/tty.usbserial-A9MP5N37')
            if cp2104 is not None:
                temp_ports += cp2104
            if ft232rl is not None:
                temp_ports += ft232rl
            if fth is not None:
                temp_ports += fth
            #if new is not None: # FIXME: REMOVE!!! Only used for tests
            #    temp_ports = new
        else:
            raise EnvironmentError('Unsupported platform')

        for port in temp_ports:
            try:
                self.ser_conn.port = port
                s = self.ser_conn.open()
                self.ser_conn.close()
                self._ports.append(port)
                if(len(self._ports) > desiredIndex):
                    return  # we have found the desired port
            except serial.SerialException:
                pass
        if self.DEBUG:
             sys.stdout.write("DEBUG: available ports are {}\n".format(self._ports))

    # ************ END PRIVATE METHODS *************


    # ************ BEGIN PRIVATE CLASSES *************

    # As described above, SimpleSerialBoard writes messages to the serial port.
    # inner class SimpleWriter implements abstract class AsipWriter:
    class SimpleWriter(AsipWriter):
        parent = None

        def __init__(self, parent):
            self.parent = parent

        # val is a string
        # TODO: improve try catch
        def write(self, val):
            #print(val), 
            if self.parent.ser_conn.isOpen():
                try:
                    temp = val.encode()
                    self.parent.ser_conn.write(temp)
                    if self.parent.DEBUG:
                        sys.stdout.write("DEBUG: just wrote in serial {}\n".format(temp))
                except (OSError, serial.SerialException):
                    pass
            else:
                raise serial.SerialException

    class KeyboardListener(Thread):

        def __init__(self, parent):
            Thread.__init__(self)
            self.parent = parent
            self.running = True

        # if needed, kill will stops the loop inside run method
        def kill(self):
            self.running = False

        def run(self):
            while self.running:
                if self.heardEnter():
                    sys.stdout.write("*** Closing ***hty\n")
                    self.parent.__running = False
                    time.sleep(0.5)
                    self.parent.close_serial()
                    self.running = False

        def heardEnter(self):
            i,o,e = select.select([sys.stdin],[],[],0.0001)
            for s in i:
                if s == sys.stdin:
                    input = sys.stdin.readline()
                    return True
                return False


    # ListenerThread and ConsumerThread are implemented following the Producer/Consumer pattern
    # A class for a listener that rad the serial stream and put incoming messages on a queue
    # TODO: implement try catch
    class ListenerThread(Thread):

        queue = None
        ser_conn = None
        running = False
        DEBUG = False

        # overriding constructor
        def __init__(self, queue, ser_conn, running, debug):
            Thread.__init__(self)
            self.queue = queue
            self.ser_conn = ser_conn
            self.running = running
            self.DEBUG = debug
            if self.DEBUG:
                sys.stdout.write("DEBUG: serial thread process created \n")

        # if needed, kill will stops the loop inside run method
        def kill(self):
            self.running = False

        # overriding run method, thread activity
        def run(self):
            temp_buff = ""
            time.sleep(2)
            # TODO: implement ser.inWaiting() >= minMsgLen to check number of char in the receive buffer?
            serBuffer = ""

            while self.running:
                # #if self.DEBUG:
                # #    sys.stdout.write("DEBUG: Temp buff is now {}\n".format(temp_buff))
                # time.sleep(0.1)
                # val = self.ser_conn.readline()
                # #val = self.ser_conn.read()
                # if self.DEBUG:
                #     sys.stdout.write("DEBUG: val value when retrieving from serial is {}\n".format(val))
                # val = val.decode('utf-8', errors= 'ignore')
                # if self.DEBUG:
                #     sys.stdout.write("DEBUG: val value after decode is {}".format(val))
                # if val is not None and val!="\n" and val!=" ":
                #     if "\n" in val:
                #         # If there is at least one newline, we need to process
                #         # the message (the buffer may contain previous characters).
                #
                #         while ("\n" in val and len(val) > 0):
                #             # But remember that there could be more than one newline in the buffer
                #             temp_buff += (val[0:val.index("\n")])
                #             self.queue.put(temp_buff)
                #             if self.DEBUG:
                #                 sys.stdout.write("DEBUG: Serial produced {}\n".format(temp_buff))
                #             temp_buff = ""
                #             val = val[val.index("\n")+1:]
                #             if self.DEBUG:
                #                 sys.stdout.write("DEBUG: Now val is {}\n".format(val))
                #         if len(val)>0:
                #             temp_buff = val
                #         if self.DEBUG:
                #             sys.stdout.write("DEBUG: After internal while buffer is {}\n".format(temp_buff))
                #     else:
                #         temp_buff += val
                #         if self.DEBUG:
                #             sys.stdout.write("DEBUG: else case, buff is equal to val, so they are {}\n".format(temp_buff))
                try:
                    while True:
                        c = self.ser_conn.read() # attempt to read a character from Serial
                        c = c.decode('utf-8', errors= 'ignore')
                        #was anything read?
                        if len(c) == 0:
                            break

                        # check if character is a delimiter
                        if c == '\r':
                            c = '' # ignore CR
                        elif c == '\n':
                            serBuffer += "\n" # add the newline to the buffer
                            if self.DEBUG:
                                sys.stdout.write("Serial buffer is now {}\n".format(serBuffer))
                            self.queue.put(serBuffer)
                            serBuffer = '' # empty the buffer
                        else:
                            #print("Try to print: {}".format(c))
                            serBuffer += c # add to the buffer
                except (OSError, serial.SerialException):
                    self.running = False
                    sys.stdout.write("Serial Exception in listener\n")

    # A class that reads the queue and launch the processInput method of the AispClient.
    class ConsumerThread(Thread):

        queue = None
        asip = None
        running = False
        DEBUG = False

        # overriding constructor
        def __init__(self, queue, asip, running, debug):
            Thread.__init__(self)
            self.queue = queue
            self.asip = asip
            self.running = running
            self.DEBUG = debug
            if self.DEBUG:
                sys.stdout.write("DEBUG: consumer thread created \n")

        # if needed, kill will stops the loop inside run method
        def kill(self):
            self.running = False

        # overriding run method, thread activity
        def run(self):
            # global _queue
            # global asip
            while self.running:
                temp = self.queue.get()
                self.asip.process_input(temp)
                self.queue.task_done()
                # if temp == "\n":
                    # print("WARNING")
                # print ("Consumed", temp)

    # ************ END PRIVATE CLASSES *************
Ejemplo n.º 7
0
class MQTTBoard:

    # ************   BEGIN CONSTANTS DEFINITION ****************

    DEBUG = True  # Activates debug messages
    __TCP_port = 1883  # MQTT registered port

    # ************   END CONSTANTS DEFINITION ****************

    # ************   BEGIN PRIVATE FIELDS DEFINITION ****************

    # asip: The client for the asip protocol
    # mqtt_client: self board uses mqtt
    __threads = []  # List of threads

    # ************   END PRIVATE FIELDS DEFINITION ****************

    # self constructor takes the broker address and the target board
    # client name and keepalive are optional parameters
    def __init__(self, broker_ip, target_board, my_name="Client", keepalive=180):

        # setting mqtt connection and asip protocol
        try:
            sys.stdout.write("Setting mqtt: attempting to connect to broker {}\n".format(broker_ip))
            self.__Broker = broker_ip
            self.__keepalive = keepalive
            self.__SUBTOPIC = "asip/"+target_board+"/in"
            self.__PUBTOPIC = "asip/"+target_board+"/out"

            self.mqtt_client = mqtt.Client(my_name)
            self.mqtt_client.on_connect = self.on_connect
            self.connect()

            self.asip = AsipClient(self.SimpleMQTTWriter(self.mqtt_client, self.__PUBTOPIC, self.DEBUG))
        except Exception as e:
            sys.stdout.write("Exception caught in init mqtt and asip protocols: {}\n".format(e))
            try:  # try to close connection
                self.disconnect()
            except Exception as e:
                sys.stdout.write("Caught generic exception while disconnecting MQTT: {}\n".format(e))
            finally:
                sys.exit(1)

        # Listener creation
        try:
            self.__threads.append(self.ListenerThread(
                self.asip, self.mqtt_client, self.__SUBTOPIC, self.DEBUG))
            sys.stdout.write("Creating Threads: starting\n")
            self.__threads[0].start()
            while not self.__threads[0].is_alive():  # checking that listener is alive
                pass
            sys.stdout.write("Creating Threads: all threads created and alive\n")

            self.mqtt_client.loop_start()  # starting mqtt loop

        except Exception as e:
            sys.stdout.write("Caught exception in threads launch: {}\n".format(e))
            self.thread_killer()
            sys.exit(1)
        else:
            # Running
            try:
                # TODO: version checking still missing
                # flag will be set to true when valid version message is received
                # while self.asip.isVersionOk() == False:
                #     self.asip.request_info()
                #     time.sleep(1.0)
                # Checking mapping
                while not self.asip.check_mapping():
                    self.asip.request_port_mapping()
                    time.sleep(0.5)
                self.asip.set_auto_report_interval(0)
                sys.stdout.write("Creating Threads: Mapping received, auto-report interval set to 0. Running now!\n")

           # KeyboardInterrupt handling in order to close every thread correctly
            except KeyboardInterrupt:  # KeyboardInterrupt handling in order to close every thread correctly
                sys.stdout.write("KeyboardInterrupt while checking mapping. Attempting to close listener thread.\n")
                self.thread_killer()
                sys.exit()
            except Exception as e:  # killing threads and exiting in case of generic exception
                sys.stdout.write("Caught generic exception while checking mapping: {}\n".format(e))
                self.thread_killer()
                sys.exit(1)

    # ************ BEGIN PUBLIC METHODS *************

    # stops and waits for the join for threads in the given pool
    # TODO: improve in case of timeout of the join
    def thread_killer(self):
        for i in self.__threads:
            try:
                i.stopper()
                sys.stdout.write("Killing Threads: event for {} successfully set\n".format(i))
            except Exception as e:
                sys.stdout.write("Caught exception while stropping thread {}.\nException is: {}\n".format(i, e))
        time.sleep(0.5)
        sys.stdout.write("Killing Threads: waiting for join\n")
        for i in self.__threads:
            i.join()
            sys.stdout.write("Killing Threads: thread {} successfully closed\n".format(i))
        self.__threads = []
        try:
            self.disconnect()
        except Exception as e:
            sys.stdout.write("Caught generic exception while disconnecting MQTT: {}\n".format(e))
        sys.stdout.write("All threads terminated.\n")
        return True

    def get_asip_client(self):
        return self.asip

    # ************ END PUBLIC METHODS *************

    # ************ BEGIN PRIVATE METHODS *************

    # The callback for when the client receives a CONNACK response from the server.
    def on_connect(self, client, userdata, flags, rc):
        if self.DEBUG:
            sys.stdout.write("Connected with result code: {}\n".format(rc))

    def connect(self):
        self.mqtt_client.connect(self.__Broker, self.__TCP_port, self.__keepalive)
        sys.stdout.write("Connected to MQTT broker: {}  port: {} keepalive: {} .\n"
                         .format(self.__Broker, self.__TCP_port, self.__keepalive))

    def disconnect(self):
        self.mqtt_client.disconnect()
        sys.stdout.write("Disconnected from MQTT broker.\n")

    # ************ END PRIVATE METHODS *************

    # ************ BEGIN PRIVATE CLASSES *************

    # SimpleMQTTBoard writes messages to the MQTT stream.
    # inner class SimpleMQTTWriter implements abstract class AsipWriter:
    class SimpleMQTTWriter(AsipWriter):

        def __init__(self, mqtt_client, pubtopic, debug=False):
            self.mqtt_client = mqtt_client
            self.pubtopic = pubtopic
            self.DEBUG = debug

        # val is a string
        # TODO: improve try catch
        def write(self, val):
            # TODO: insert a way to check weather the connection is still open or not
            try:
                self.mqtt_client.publish(self.pubtopic, val)
                if self.DEBUG:
                    sys.stdout.write("DEBUG: sent {}\n".format(val))
            except Exception as e:
                sys.stdout.write("Caught exception in MQTT publish: {}\n".format(e))

    # ListenerThread read the mqtt stream and call process_input
    class ListenerThread(Thread):

        # overriding constructor
        def __init__(self, asip, mqtt_client, subtopic, debug=False):
            Thread.__init__(self)
            self.asip = asip
            self.mqtt_client = mqtt_client
            self.mqtt_client.on_message = self.on_message  # callback
            self.DEBUG = debug
            self.listener_buffer = ""
            self.mqtt_client.subscribe(topic=subtopic)
            sys.stdout.write("Listener Thread: subscribed to topic: {} .\n".format(subtopic))
            self._stopper = threading.Event()
            sys.stdout.write("Listener Thread: thread process created.\n")

        # if needed, kill will stops the loop inside run method
        def stopper(self):
            sys.stdout.write("Listener Thread: now stopping.\n")
            self._stopper.set()

        # The callback for when a PUBLISH message is received from the server.
        def on_message(self, client, userdata, msg):
            try:
                if not msg.payload:
                    pass
                else:
                    data = msg.payload.decode('utf-8')
                    if data != '\r' and data != '\n' and data != ' ':  # ignore empty lines
                        self.listener_buffer += data
                    if self.DEBUG:
                        sys.stdout.write("DEBUG: Received {}\n".format(data))
            except Exception as e:
                sys.stdout.write("Exception in listener on_message method: {}\nListener will now stop\n".format(e))
                self.stopper()

        # overriding run method, thread activity
        def run(self):
            time.sleep(2)  # TODO: maybe reduce this sleep?
            sys.stdout.write("Listener Thread: now running.\n")
            while not self._stopper.is_set():
                time.sleep(0.001)  # TODO: thread concurrency
                try:
                    # If there is at least one newline, we need to process the message
                    # (the buffer may contain previous characters).
                    while "\n" in self.listener_buffer:
                        temp = self.listener_buffer[0:self.listener_buffer.index("\n")]
                        self.asip.process_input(temp)
                        self.listener_buffer = self.listener_buffer[self.listener_buffer.index("\n")+1:]
                except Exception as e:
                    sys.stdout.write("Exception in listener run method: {}\nListener will now stop\n".format(e))
                    self.stopper()

            sys.stdout.write("Listener Thread: stopped\n")

    # ************ END PRIVATE CLASSES *************
Ejemplo n.º 8
0
class SimpleTCPBoard:

    # ************   BEGIN CONSTANTS DEFINITION ****************

    DEBUG = True

    # ************   END CONSTANTS DEFINITION ****************

    # ************   BEGIN PRIVATE FIELDS DEFINITION ****************

    sock_conn = None  # self board uses socket
    asip = None  # The client for the aisp protocol
    queue = Queue(
        10)  # Buffer # TODO: use pipe instead of queue for better performances
    #  FIXME: fix Queue dimension?
    IPaddress = ""
    #_TCPport = 6789 # the one used by the java bridge by franco in mirto
    _TCPport = 5005

    # ************   END PRIVATE FIELDS DEFINITION ****************

    # self constructor takes the IP address
    # Here the tcp ip listener and the queue reader are started
    def __init__(self, IPaddress):
        try:
            self.IPaddress = IPaddress
            sys.stdout.write(
                "Attempting to connect to {} and port {}\n".format(
                    self.IPaddress, self._TCPport))
            self.sock_conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.sock_conn.connect((self.IPaddress, self._TCPport))
            self.asip = AsipClient(
                self.SimpleTCPWriter(self, sock_conn=self.sock_conn))
        except Exception as e:
            sys.stdout.write(
                "Exception caught in init tcp socket and asip protocols {}\n".
                format(e))
        else:
            worker = []
            try:
                # NOTICE: two request_port_mapping() are required. If this method is not called two times,
                # the client won't be able to set the pin mapping
                worker.append(
                    self.ListenerThread(self.queue, self.sock_conn, True,
                                        self.DEBUG))
                worker.append(
                    self.ConsumerThread(self.queue, self.asip, True,
                                        self.DEBUG))
                for i in worker:
                    if self.DEBUG:
                        print("Starting {}".format(i))
                    i.start()
                all_alive = False
                while not all_alive:  # cheching that every thread is alive
                    # TODO: improve syntax in following line
                    if worker[0].is_alive() and worker[1].is_alive():
                        all_alive = True

                # TODO: check following code
                # while self.asip.isVersionOk() == False:  # flag will be set to true when valid version message is received
                #     self.request_info()
                #     time.sleep(1.0)
                active_workers = threading.active_count()
                sys.stdout.write("*** All threads created and alive ***\n")
            except Exception as e:
                sys.stdout.write(
                    "Caught exception in thread launch: {}\n".format(e))
                self.close_tcp_conn()
                self.thread_killer(worker)
                sys.exit(1)
            else:
                try:

                    while not self.asip.check_mapping():
                        self.request_port_mapping()
                        time.sleep(0.25)
                    self.set_auto_report_interval(0)
                    # checking that a thread is not killed by an exception
                    while len(threading.enumerate()) == active_workers:
                        pass
                # KeyboardInterrupt handling in order to close every thread correctly
                except KeyboardInterrupt:
                    sys.stdout.write(
                        "KeyboardInterrupt: attempting to close threads.\n")
                finally:
                    # killing thread in both cases: keyboardinterrupt or exception in one of the thread
                    self.close_tcp_conn()
                    self.thread_killer(worker)
                    sys.stdout.write("All terminated.\n")
                    sys.exit()

    # ************ BEGIN PUBLIC METHODS *************

    # The following methods are just a replica from the asip class.
    # TODO: add parameter checikng in each function (raise exception?)
    def digital_read(self, pin):
        return self.asip.digital_read(pin)

    def analog_read(self, pin):
        return self.asip.analog_read(pin)

    def set_pin_mode(self, pin, mode):
        self.asip.set_pin_mode(pin, mode)

    def digital_write(self, pin, value):
        self.asip.digital_write(pin, value)

    def analog_write(self, pin, value):
        self.asip.analog_write(pin, value)

    def request_info(self):
        self.asip.request_info()

    def request_port_mapping(self):
        self.asip.request_port_mapping()

    def set_auto_report_interval(self, interval):
        self.asip.set_auto_report_interval(interval)

    def add_service(self, service_id, asip_service):
        self.asip.add_service(service_id, asip_service)

    def get_asip_client(self):
        return self.asip

    # ************ END PUBLIC METHODS *************

    # ************ BEGIN PRIVATE METHODS *************

    #def open_serial(self, port, baudrate):

    def close_tcp_conn(self):
        self.sock_conn.close()

    # stops and wait for the join for threads in the given pool
    # TODO: improve in case of timeout of the join
    def thread_killer(self, thread_pool):
        for i in thread_pool:
            i.stop()
            if self.DEBUG:
                sys.stdout.write("Event for {} successfully set\n".format(i))
        sys.stdout.write("Waiting for join\n")
        for i in thread_pool:
            i.join()
            if self.DEBUG:
                sys.stdout.write("Thread {} successfully closed\n".format(i))
        return True

    # ************ END PRIVATE METHODS *************

    # ************ BEGIN PRIVATE CLASSES *************

    # As described above, SimpleTCPBoard writes messages to the tcp stream.
    # inner class SimpleTCPWriter implements abstract class AsipWriter:
    class SimpleTCPWriter(AsipWriter):
        parent = None
        sock_conn = None

        def __init__(self, parent, sock_conn):
            self.parent = parent
            self.sock_conn = sock_conn

        # val is a string
        # TODO: improve try catch
        def write(self, val):
            # TODO: insert a way to check weather the connection is still open or not
            try:
                #if self.parent.DEBUG:
                #sys.stdout.write("DEBUG: sending {}\n".format(val))
                #temp = self.writeUTF(val)
                #self.sock_conn.sendall((val+'\n').encode('utf-8'))
                temp = val  #+ '\n'
                #self.sock_conn.send(b"temp") # temp.encode('utf-8')
                #self.sock_conn.sendall(bytes(temp,encoding='utf8'))
                # self.parent.sock_conn.send(val)
                #temp.encode('utf-8')
                self.sock_conn.send(temp)
                if self.parent.DEBUG:
                    sys.stdout.write("DEBUG: sent {}\n".format(temp))
            except Exception as e:
                pass

        # def writeUTF(self, str):
        #     temp = None
        #     utf8 = str.encode('utf-8')
        #     length = len(utf8)
        #     temp.append(struct.pack('!H', length))
        #     format = '!' + str(length) + 's'
        #     temp.append(struct.pack(format, utf8))
        #     return temp

    # ListenerThread and ConsumerThread are implemented following the Producer/Consumer pattern
    # A class for a listener that read the tcp ip messages and put incoming messages on a queue
    # TODO: implement try catch
    class ListenerThread(Thread):

        queue = None
        sock_conn = None
        running = False
        DEBUG = False
        BUFFER_SIZE = 256

        # overriding constructor
        def __init__(self, queue, sock_conn, running, debug):
            Thread.__init__(self)
            self.queue = queue
            self.sock_conn = sock_conn
            self.running = running
            self.DEBUG = debug
            self._stop = threading.Event()
            if self.DEBUG:
                sys.stdout.write("DEBUG: listener thread process created \n")

        # if needed, kill will stops the loop inside run method
        def stop(self):
            self._stop.set()

        # overriding run method, thread activity
        def run(self):
            temp_buff = ""
            time.sleep(2)
            write_buffer = ""
            # TODO: implement ser.inWaiting() >= minMsgLen to check number of char in the receive buffer?

            while not self._stop.is_set():
                # data = self.sock_conn.recv(512).decode('utf-8')
                # #data = data[2:]
                # if not data:
                #     pass
                # else:
                #     self.queue.put(data)
                #     print("Received {}\n".format(data))

                # if self.DEBUG:
                #     sys.stdout.write("DEBUG: Temp buff is now {}\n".format(temp_buff))
                # val = self.sock_conn.recv(2)
                # if self.DEBUG:
                #     sys.stdout.write("DEBUG: val value when retrieving from tcp ip stream is {}\n".format(val))
                #
                # val = val.decode('utf-8')
                # time.sleep(0.1)
                # if self.DEBUG:
                #     sys.stdout.write("DEBUG: val value after decode is {}".format(val))
                # if val is not None and val!="\n":
                #     if "\n" in val:
                #         # If there is at least one newline, we need to process
                #         # the message (the buffer may contain previous characters).
                #
                #         while ("\n" in val and len(val) > 0):
                #             # But remember that there could be more than one newline in the buffer
                #             temp_buff += (val[0:val.index("\n")])
                #             self.queue.put(temp_buff)
                #             if self.DEBUG:
                #                 sys.stdout.write("DEBUG: tcp ip produced {}\n".format(temp_buff))
                #             temp_buff = ""
                #             val = val[val.index("\n")+1:]
                #             if self.DEBUG:
                #                 sys.stdout.write("DEBUG: Now val is {}\n".format(val))
                #         if len(val)>0:
                #             temp_buff = val
                #         if self.DEBUG:
                #             sys.stdout.write("DEBUG: After internal while buffer is {}\n".format(temp_buff))
                #     else:
                #         temp_buff += val
                #         if self.DEBUG:
                #             sys.stdout.write("DEBUG: else case, buff is equal to val, so they are {}\n".format(temp_buff))

                data = self.sock_conn.recv(self.BUFFER_SIZE)
                # print("Received data is: {}".format(data))
                if data != '\r' and data != '\n' and data != ' ' and data is not None:  # ignore empty lines
                    if "\n" in data:
                        # If there is at least one newline, we need to process
                        # the message (the buffer may contain previous characters).
                        while ("\n" in data and len(data) > 0):
                            # But remember that there could be more than one newline in the buffer
                            write_buffer += (data[0:data.index("\n")])
                            temp = write_buffer.encode()
                            self.queue.put(temp)
                            #print("Inserting in queue {}".format(temp))
                            write_buffer = ""
                            if data[data.index("\n") + 1:] == '\n':
                                data = ''
                                break
                            else:
                                data = data[data.index("\n") + 1:]
                        if len(data) > 0 and data not in ('\r', '\n', ' '):
                            write_buffer = data
                    else:
                        write_buffer += data

    # A class that reads the queue and launch the processInput method of the AispClient.
    class ConsumerThread(Thread):

        queue = None
        asip = None
        running = False
        DEBUG = False

        # overriding constructor
        def __init__(self, queue, asip, running, debug):
            Thread.__init__(self)
            self.queue = queue
            self.asip = asip
            self.running = running
            self.DEBUG = debug
            self._stop = threading.Event()
            if self.DEBUG:
                sys.stdout.write("DEBUG: consumer thread created \n")

        # if needed, kill will stops the loop inside run method
        def stop(self):
            self._stop.set()

        # overriding run method, thread activity
        def run(self):
            # global _queue
            # global asip
            while not self._stop.is_set():
                temp = self.queue.get()
                # print("Consumer, calling process_input with input: {}\n".format(temp))
                self.asip.process_input(temp)
                self.queue.task_done()
Ejemplo n.º 9
0
class SerialBoard:

    # ************   BEGIN CONSTANTS DEFINITION ****************

    DEBUG = False  # Activates debug messages
    __SERIAL_TIMEOUT = 2  # serial timeout (avoid blocking in case of issues)
    __PORT_INDEX_TO_OPEN = 0
    __BAUD_RATE = 57600

    # ************   END CONSTANTS DEFINITION ****************

    # ************   BEGIN PRIVATE FIELDS DEFINITION ****************

    # asip: The client for the asip protocol
    # __ser_conn: self board uses serial communication
    __ports = []  # serial ports array
    __threads = []  # List of threads

    # ************   END PRIVATE FIELDS DEFINITION ****************

    # Self constructor find the name of an active serial port and it creates a Serial objted
    def __init__(self):

        # Serial connection creation, AsipClient object creation
        try:
            self.__ser_conn = Serial()
            self.serial_port_finder(self.__PORT_INDEX_TO_OPEN)
            sys.stdout.write("Setting Serial: attempting to open {}\n".format(
                self.__ports[self.__PORT_INDEX_TO_OPEN]))
            self.open_serial(self.__ports[self.__PORT_INDEX_TO_OPEN],
                             self.__BAUD_RATE)
            sys.stdout.write("Setting Serial: serial port {} opened\n".format(
                self.__ports[self.__PORT_INDEX_TO_OPEN]))
            self.asip = AsipClient(
                self.SimpleWriter(self.__ser_conn, self.DEBUG))
        except serial.SerialException as e:
            sys.stdout.write(
                "Exception while init serial connection: {}\n".format(e))
            sys.exit(1)

        # Listener creation
        try:
            self.__threads.append(
                self.ListenerThread(self.asip, self.__ser_conn, self.DEBUG))
            sys.stdout.write("Creating Threads: starting\n")
            self.__threads[0].start()
            while not self.__threads[0].is_alive(
            ):  # checking that listener is alive
                pass
            sys.stdout.write(
                "Creating Threads: all threads created and alive\n")
        except Exception as e:
            sys.stdout.write(
                "Caught exception in threads launch: {}\n".format(e))
            self.thread_killer()
            sys.exit(1)
        else:
            # Running
            try:
                # TODO: version checking still mis
                # flag will be set to true when valid version message is received
                # while self.asip.isVersionOk() == False:
                #     self.asip.request_info()
                #     time.sleep(1.0)sing
                # Checking mapping
                while not self.asip.check_mapping():
                    self.asip.request_port_mapping()
                    time.sleep(0.5)
                self.asip.set_auto_report_interval(100)
                sys.stdout.write(
                    "Creating Threads: Mapping received, auto-report interval set to 0. Running now!\n"
                )
            except KeyboardInterrupt:  # KeyboardInterrupt handling in order to close every thread correctly
                sys.stdout.write(
                    "KeyboardInterrupt while checking mapping. Attempting to close listener thread.\n"
                )
                self.thread_killer()
                sys.exit()
            except Exception as e:  # killing threads and exiting in case of generic exception
                sys.stdout.write(
                    "Caught generic exception while checking mapping: {}\n".
                    format(e))
                self.thread_killer()
                sys.exit(1)

    # ************ BEGIN PUBLIC METHODS *************

    # stops and wait for the join for threads in the given pool
    # TODO: improve in case of timeout of the join
    def thread_killer(self):
        for i in self.__threads:
            try:
                i.stopper()
                sys.stdout.write(
                    "Killing Threads: event for {} successfully set\n".format(
                        i))
            except Exception as e:
                sys.stdout.write(
                    "Caught exception while stropping thread {}.\nException is: {}\n"
                    .format(i, e))
        time.sleep(0.5)
        sys.stdout.write("Killing Threads: waiting for join\n")
        for i in self.__threads:
            i.join()
            sys.stdout.write(
                "Killing Threads: thread {} successfully closed\n".format(i))
        self.__threads = []
        sys.stdout.write("All threads terminated.\n")
        return True

    def get_asip_client(self):
        return self.asip

    # ************ END PUBLIC METHODS *************

    # ************ BEGIN PRIVATE METHODS *************

    def open_serial(self, port, baud_rate):
        if self.__ser_conn.isOpen():
            self.__ser_conn.close()
        self.__ser_conn.port = port
        self.__ser_conn.baudrate = baud_rate
        self.__ser_conn.timeout = self.__SERIAL_TIMEOUT
        self.__ser_conn.open()
        # Toggle DTR to reset Arduino
        self.__ser_conn.setDTR(False)
        time.sleep(1)
        # toss any data already received, see
        self.__ser_conn.flushInput()
        time.sleep(1)
        self.__ser_conn.setDTR(True)
        time.sleep(1)

    def close_serial(self):
        self.__ser_conn.close()

    # This methods retrieves the operating system and set the Arduino serial port
    """Lists serial ports

    :raises EnvironmentError:
        On unsupported or unknown platforms
    :returns:
        A list of available serial ports
    """

    # TODO: test needed for linux and windows implementation
    # TODO: improve try except
    def serial_port_finder(self, desired_index):

        system = sys.platform
        if system.startswith('win'):
            temp_ports = ['COM' + str(i + 1) for i in range(255)]
        elif system.startswith('linux'):
            # this is to exclude your current terminal "/dev/tty"
            temp_ports = glob.glob('/dev/tty[A-Za-z]*')
        elif system.startswith('darwin'):
            temp_ports = glob.glob('/dev/tty.usbmodem*')
            cp2104 = glob.glob('/dev/tty.SLAB_USBtoUART'
                               )  # append usb to serial converter cp2104
            ft232rl = glob.glob('/dev/tty.usbserial-A9MP5N37'
                                )  # append usb to serial converter ft232rl
            fth = glob.glob(
                '/dev/tty.usbserial-FTHI5TLH')  # append usb to serial cable
            #new = glob.glob('/dev/tty.usbmodemfd121')
            #temp_ports = glob.glob('/dev/tty.SLAB_USBtoUART')
            #temp_ports = glob.glob('/dev/tty.usbserial-A9MP5N37')
            if cp2104 is not None:
                temp_ports += cp2104
            if ft232rl is not None:
                temp_ports += ft232rl
            if fth is not None:
                temp_ports += fth
            #if new is not None: # FIXME: REMOVE!!! Only used for tests
            #    temp_ports = new
        else:
            raise EnvironmentError('Unsupported platform')

        for port in temp_ports:
            try:
                self.__ser_conn.port = port
                self.__ser_conn.open()
                self.__ser_conn.close()
                self.__ports.append(port)
                if len(self.__ports) > desired_index:
                    return  # we have found the desired port
            except serial.SerialException:
                pass
        if self.DEBUG:
            sys.stdout.write("DEBUG: available ports are {}\n".format(
                self.__ports))

    # ************ END PRIVATE METHODS *************

    # ************ BEGIN PRIVATE CLASSES *************

    # As described above, SimpleSerialBoard writes messages to the serial port.
    # inner class SimpleWriter implements abstract class AsipWriter:
    class SimpleWriter(AsipWriter):
        def __init__(self, ser_conn, debug=False):
            self.ser_conn = ser_conn
            self.DEBUG = debug

        # val is a string
        # TODO: improve try catch, add exit in case of exception too
        def write(self, val):
            if self.ser_conn.isOpen():
                try:
                    temp = val.encode()
                    self.ser_conn.write(temp)
                    if self.DEBUG:
                        sys.stdout.write(
                            "DEBUG: just wrote in serial {}\n".format(temp))
                except (OSError, serial.SerialException) as e:
                    sys.stdout.write(
                        "Caught exception in serial write: {}\n".format(e))
            else:
                raise serial.SerialException

    # ListenerThread read the serial stream and call process_input
    class ListenerThread(Thread):

        # overriding constructor
        def __init__(self, asip, ser_conn, debug=False):
            Thread.__init__(self)
            self.asip = asip
            self.ser_conn = ser_conn
            self.DEBUG = debug
            self._stopper = threading.Event()
            sys.stdout.write("Listener Thread: thread process created.\n")

        # if needed, kill will stops the loop inside run method
        def stopper(self):
            sys.stdout.write("Listener Thread: now stopping.\n")
            self._stopper.set()

        # overriding run method, thread activity
        def run(self):
            time.sleep(2)  # TODO: maybe reduce this sleep?
            sys.stdout.write("Listener Thread: now running.\n")
            ser_buffer = ""
            while not self._stopper.is_set():
                try:
                    c = self.ser_conn.read(
                    )  # attempt to read a character from Serial
                    c = c.decode('utf-8', errors='ignore')
                    if len(c) == 0:  # was anything read?
                        pass
                    else:
                        # if self.DEBUG:
                        #    sys.stdout.write("DEBUG: Char from serial: {}\n".format(c))
                        if c == '\n' or c == '\n':
                            if len(ser_buffer) > 0:
                                ser_buffer += '\n'
                                self.asip.process_input(ser_buffer)
                                if self.DEBUG:
                                    sys.stdout.write(
                                        "DEBUG: Complete message from serial: {}\n"
                                        .format(ser_buffer))
                            ser_buffer = ""
                        else:
                            ser_buffer += c
                except serial.SerialTimeoutException:
                    continue  # Go to next iteration in case of serial timeout
                except serial.SerialException as e:
                    sys.stdout.write(
                        "Caught SerialException in serial read: {}\nListener Thread will now stop\n"
                        .format(e))
                    self.stopper()
                except Exception as e:
                    sys.stdout.write(
                        "Caught exception: {}\nListener Thread will NOT stop\n"
                        .format(e))
                    #self.stopper()

            sys.stdout.write("Listener Thread: stopped\n")