Example #1
0
    def __init__(self, buff, verbose=False):
        '''Open a serial connection and wait for the ready signal'''
        self.verbose = verbose
        self.last_received = 0
        self.serial = buff

        # Create the logger
        self.logger = TimedLogger(self.serial.start_time, textcolor=self.LOGGING_COLOR)

        self.serial.start()
        if not self.wait_for_ready():
            exit(1)
Example #2
0
    def __init__(self, device, verbose=False, baud=9600):
        """Open a serial connection and wait for the ready signal"""
        self.device = device
        self.verbose = verbose
        self.baud = baud
        self.last_received = 0

        # Create the serial buffer and start it up
        self.serial = SerialBuffer(device, baud)

        # Create the logger
        self.logger = TimedLogger(self.serial.start_time, textcolor=self.LOGGING_COLOR)

        self.serial.start()
        if not self.wait_for_ready():
            exit(1)
Example #3
0
    def __init__(self, options):
        # Connect to serial connection
        self.ser = HMTLSerial(options.device,
                              verbose=options.verbose,
                              baud=options.baud)
        self.logger = TimedLogger(self.ser.serial.start_time,
                                  textcolor=self.LOGGING_COLOR)

        self.address = (options.address, options.port)
        self.terminate = False

         # TODO: Is this needed at all? If so should the SerialBuffer handle synchronization?
        self.serial_cv = threading.Condition()

        self.conn = None
        self.listener = None
Example #4
0
File: client.py Project: HMTL/HMTL
    def __init__(self, address='localhost', port=6000, hmtladdress=None,
                 verbose=False, logger=True, authenticate=True):
        self.logger = TimedLogger()
        if not logger:
            self.logger.disable()

        self.address = hmtladdress
        self.verbose = verbose

        address = (address, port)
        try:
            if authenticate:
                authkey = b'secret password'
            else:
                authkey = None
            self.conn = Client(address, authkey=authkey)
        except Exception as e:
            raise Exception("Failed to connect to '%s'" % (str(address)))
        random.seed()
        print("HMTLClient initialized")
Example #5
0
File: server.py Project: HMTL/HMTL
    def __init__(self, serial_device, address, device_scan=False, logger=True):
        self.ser = serial_device
        self.address = address

        self.logger = TimedLogger(self.ser.serial.start_time,
                                  textcolor=self.LOGGING_COLOR)
        if not logger:
            self.logger.disable()

        self.terminate = False

         # TODO: Is this needed at all? If so should the SerialBuffer handle synchronization?
        self.serial_cv = threading.Condition()

        self.conn = None
        self.listener = None

        if device_scan:
            self.scanner = DeviceScanner(self, True)
            self.scanner.start()
        else:
            self.scanner = None
Example #6
0
File: server.py Project: HMTL/HMTL
    def __init__(self, server, verbose=True, period=60.0):
        threading.Thread.__init__(self)

        self.server = server
        self.verbose = verbose

        self.logger = TimedLogger(self.server.ser.serial.start_time,
                                  textcolor=TimedLogger.MAGENTA)
        self.logger.log("Scanner initialized")

        # Period between scans
        self.scan_period = period

        # Period between address
        self.address_period = 0.25

        # TODO: This range is arbitrary for scanning purposes
        self.address_range = [x for x in range(120, 150)]

        # Set as a daemon so that this thread will exit correctly
        # when the parent receives a kill signal
        self.daemon = True

        self.devices = {}
Example #7
0
class HMTLSerial():

    # Default logging color
    LOGGING_COLOR = TimedLogger.WHITE

    # How long to wait for the ready signal after connection
    MAX_READY_WAIT = 10

    def __init__(self, buff, verbose=False):
        '''Open a serial connection and wait for the ready signal'''
        self.verbose = verbose
        self.last_received = 0
        self.serial = buff

        # Create the logger
        self.logger = TimedLogger(self.serial.start_time, textcolor=self.LOGGING_COLOR)

        self.serial.start()
        if not self.wait_for_ready():
            exit(1)

    def get_message(self, timeout=None):
        """Returns the next line of text or a complete HMTL message"""

        item = self.serial.get(wait=timeout)

        if not item:
            return None

        self.last_received = time.time()

        return item

    # Wait for data from device indicating its ready for commands
    def wait_for_ready(self):
        """Wait for the Arduino to send its ready signal"""
        self.logger.log("***** Waiting for ready from Arduino *****")
        start_wait = time.time()
        while True:
            item = self.get_message(1.0)

            # After connecting to the serial device there is sometimes data
            # from before the module resets, so wait a bit for that to clear.
            if (time.time() - start_wait) < 0.5:
                continue

            if item and (item.data == HMTLprotocol.HMTL_CONFIG_READY):
                self.logger.log("***** Recieved ready *****")
                return True
            if (time.time() - start_wait) > self.MAX_READY_WAIT:
                raise Exception("Timed out waiting for ready signal")

    # Send terminated data and wait for (N)ACK
    def send_and_confirm(self, data, terminated, timeout=10):
        """Send a command and wait for the ACK"""

        self.serial.write(data)
        if (terminated):
            self.serial.write(HMTLprotocol.HMTL_TERMINATOR)

        start_wait = time.time()
        while True:
            item = self.get_message()
            if item.data == HMTLprotocol.HMTL_CONFIG_ACK:
                return True
            if item.data == HMTLprotocol.HMTL_CONFIG_FAIL:
                raise HMTLConfigException("Configuration command failed")
            if (time.time() - start_wait) > timeout:
                raise Exception("Timed out waiting for ACK signal")


# XXX: Here we need a method of getting data back from poll or the like

    # Send a text command
    def send_command(self, command):
        self.logger.log("send_command: %s" % (command))
        self.send_and_confirm(command, True)

    # Send a binary config update
    def send_config(self, type, config):
        self.logger.log("send_config:  %-10s %s" % (type, hexlify(config)))
        self.send_and_confirm(config, True)
Example #8
0
File: server.py Project: HMTL/HMTL
class HMTLServer():
    address = ('localhost', 6000)

    # Default logging color
    LOGGING_COLOR = TimedLogger.RED

    def __init__(self, serial_device, address, device_scan=False, logger=True):
        self.ser = serial_device
        self.address = address

        self.logger = TimedLogger(self.ser.serial.start_time,
                                  textcolor=self.LOGGING_COLOR)
        if not logger:
            self.logger.disable()

        self.terminate = False

         # TODO: Is this needed at all? If so should the SerialBuffer handle synchronization?
        self.serial_cv = threading.Condition()

        self.conn = None
        self.listener = None

        if device_scan:
            self.scanner = DeviceScanner(self, True)
            self.scanner.start()
        else:
            self.scanner = None

    def get_connection(self):
        try:
            self.logger.log("Waiting for connection")
            self.listener = Listener(self.address, authkey='secret password')
            self.conn = self.listener.accept()
            self.logger.log("Connection accepted from %s:%d" %
                            self.listener.last_accepted)
        except KeyboardInterrupt:
            print("Exiting")
            self.terminate = True

    def handle_msg(self, item):
        if item.data == SERVER_EXIT:
            self.logger.log("* Received exit signal *")
            self.conn.send(SERVER_ACK)
            self.close()
        elif item.data == SERVER_DATA_REQ:
            self.logger.log("* Recieved data request")
            item = self.get_data_msg()
            if item:
                self.conn.send(item.data)
            else:
                self.conn.send(None)
        else:
            # Forward the message to the device
            self.serial_cv.acquire()
            self.send_data(item.data)
            self.serial_cv.release()

            # Reply with acknowledgement
            self.conn.send(SERVER_ACK)

    def send_data(self, data):
            self.serial_cv.acquire()
            self.ser.send_and_confirm(data, False)
            self.serial_cv.release()


    # Wait for and handle incoming connections
    def listen(self):
        self.logger.log("Server started")
        self.get_connection()

        while not self.terminate:
            try:
                data = self.conn.recv()
                item = InputItem.from_data(data)

                self.logger.log("Received: %s" % item)
                self.handle_msg(item)
                self.logger.log("Acked: %s" % item)

            except (EOFError, IOError):
                # Attempt to reconnect
                self.logger.log("Lost connection")
                self.listener.close()
                self.get_connection()
            except Exception as e:
                # Close the connection on uncaught exception
                self.logger.log("Exception during listen")
                self.close()
                raise e

    def close(self):
        self.listener.close()
        if self.conn:
            self.conn.close()
        self.terminate = True

    def get_data_msg(self, timeout=0.25):
        """Listen on the serial device for a properly formatted data message"""

        self.serial_cv.acquire()
        self.logger.log("Starting data request")
        
        time_limit = time.time() + timeout
        item = None
        while True:
            # Try to get a message with low timeout
            item = self.ser.get_message(timeout=0.1)
            if item and item.is_hmtl:
                self.logger.log("Received response: %s:\n%s" %
                                (item, HMTLprotocol.decode_data(item.data)))
                break

            # Check for timeout
            if time.time() > time_limit:
                self.logger.log("Data request time limit exceeded")
                item = None
                break

        self.serial_cv.release()

        return item
Example #9
0
File: server.py Project: HMTL/HMTL
class DeviceScanner(threading.Thread):
    """
    This class performs a background scan for HMTL devices and maintains a list
    of discovered devices
    """

    def __init__(self, server, verbose=True, period=60.0):
        threading.Thread.__init__(self)

        self.server = server
        self.verbose = verbose

        self.logger = TimedLogger(self.server.ser.serial.start_time,
                                  textcolor=TimedLogger.MAGENTA)
        self.logger.log("Scanner initialized")

        # Period between scans
        self.scan_period = period

        # Period between address
        self.address_period = 0.25

        # TODO: This range is arbitrary for scanning purposes
        self.address_range = [x for x in range(120, 150)]

        # Set as a daemon so that this thread will exit correctly
        # when the parent receives a kill signal
        self.daemon = True

        self.devices = {}

    def get_devices(self):
        return self.devices

    def log(self, msg):
        if self.verbose:
            self.logger.log(msg)

    def stop(self):
        self._Thread__stop()

    def run(self):
        self.log("Scanner started")

        while True:
            self.log("Starting scan")

            for address in self.address_range:
                self.log("Polling address %d" % address)

                msg = HMTLprotocol.get_poll_msg(address)

                try:
                    self.server.send_data(msg)
                    item = self.server.get_data_msg()
                    if item:
                        (text, msg) = HMTLprotocol.decode_msg(item.data)
                        if (isinstance(msg, HMTLprotocol.PollHdr)):
                            self.log("Poll response: %s" % (msg.dump()))

                            if self.devices[address]:
                                # A device previously responded to this address
                                self.devices[address].update(msg)
                            else:
                                # Create a new device on this address
                                self.devices[address] = HMTLModule(msg)
                        else:
                            self.log("XXX: Wrong message type? %s" % (msg.dump()))
                    elif self.devices[address]:
                        # There was no response for a module we previously had configured
                        self.log("No response for known address %d" % address)
                        self.devices[address].set_active(False)
                except Exception as e:
                    print("Exception: %s" % e)
                    pass

                time.sleep(self.address_period)

            self.log("Current devices:")
            for deviceid in self.devices.keys():
                self.log("  %s" % (self.devices[deviceid].dump()))

            time.sleep(self.scan_period)
Example #10
0
File: client.py Project: HMTL/HMTL
class HMTLClient():
    address = HMTLprotocol.BROADCAST
    verbose = False

    def __init__(self, address='localhost', port=6000, hmtladdress=None,
                 verbose=False, logger=True, authenticate=True):
        self.logger = TimedLogger()
        if not logger:
            self.logger.disable()

        self.address = hmtladdress
        self.verbose = verbose

        address = (address, port)
        try:
            if authenticate:
                authkey = b'secret password'
            else:
                authkey = None
            self.conn = Client(address, authkey=authkey)
        except Exception as e:
            raise Exception("Failed to connect to '%s'" % (str(address)))
        random.seed()
        print("HMTLClient initialized")

    def close(self):
        self.conn.close()

    def send(self, msg):
        if (self.verbose):
            self.logger.log(" - Sending %s" % (hexlify(msg)))

        self.conn.send(msg)

    def get_ack(self):
        msg = self.conn.recv()
        if (self.verbose):
            self.logger.log(" - Received: '%s' '%s'" % (msg, hexlify(msg)))
        if (msg == server.SERVER_ACK):
            return True
        else:
            return False

    def send_and_ack(self, msg, expect_response=False):
        self.send(msg)

        # Wait for message acknowledgement
        if self.verbose:
            self.logger.log(" - Waiting on ack")

        # Wait for an ack from the server
        has_ack = False
        while True:
            if self.get_ack():
                has_ack = True
                break

        if has_ack and expect_response:
            # If a response is expected then request the response data from the
            # server, repeating until the message indicates that there is no
            # more data.

            messages = []
            headers = []

            more_data = True
            while more_data:
                more_data = False

                # Request response data
                msg = self.get_response_data()
                messages.append(msg)

                if self.verbose:
                    if msg:
                            self.logger.log(" - Received data response: '%s':\n%s" %
                                  (hexlify(msg), HMTLprotocol.decode_data(msg)))
                    else:
                        self.logger.log(" - Failed to receive data response")

                try:
                    # Attempt to decode the message
                    decoded_msg = HMTLprotocol.msg_to_headers(msg)
                    if decoded_msg:
                        headers.append(decoded_msg)

                        # Check if the message indicate that there are
                        # additional messages expected.
                        hdr = decoded_msg[0]
                        if isinstance(hdr, HMTLprotocol.MsgHdr):
                            if hdr.more_data():
                                # Request another message
                                more_data = True
                    else:
                        headers.append(None)
                except Exception as e:
                    print("Exception decoding messages: %s" % (str(e)))
                    headers.append(None)

            return messages, headers

        return [None, None]

    def get_response_data(self):
        '''Request and attempt to retrieve response data'''
        self.conn.send(server.SERVER_DATA_REQ)
        #TODO: This should pickle some object with parameters like timeout
        msg = self.conn.recv()
        return msg
        

    def send_exit(self):
        self.send_and_ack(server.SERVER_EXIT)