コード例 #1
0
class SP(object):
    """A Calvin serialport object"""
    def __init__(self, devicename, baudrate, bytesize, parity, stopbits,
                 timeout, xonxoff, rtscts, trigger, actor_id):
        self._trigger = trigger
        self._actor_id = actor_id
        self._port = SerialPort(RawProtocol(self), devicename, reactor,
                                baudrate, bytesize, parity, stopbits, timeout,
                                xonxoff, rtscts)

    def trigger(self):
        self._trigger(actor_ids=[self._actor_id])

    def write(self, data):
        fdesc.writeToFD(self._port.fileno(), data)

    def read(self):
        data = self._port.protocol.data
        self._port.protocol.data = b""
        return data

    def hasData(self):
        return len(self._port.protocol.data)

    def close(self):
        self._port.loseConnection()
コード例 #2
0
ファイル: serialport.py プロジェクト: JvanDalfsen/calvin-base
class SP(object):

    """A Calvin serialport object"""

    def __init__(self, devicename, baudrate, bytesize, parity, stopbits, timeout, xonxoff, rtscts, trigger, actor_id):
        self._trigger  = trigger
        self._actor_id = actor_id
        self._port      = SerialPort(
            RawProtocol(self),
            devicename,
            reactor,
            baudrate,
            bytesize,
            parity,
            stopbits,
            timeout,
            xonxoff,
            rtscts)

    def trigger(self):
        self._trigger(actor_ids=[self._actor_id])

    def write(self, data):
        fdesc.writeToFD(self._port.fileno(), data)

    def read(self):
        data = self._port.protocol.data
        self._port.protocol.data = b""
        return data

    def hasData(self):
        return len(self._port.protocol.data)

    def close(self):
        self._port.loseConnection()
コード例 #3
0
class SerialTransport(DeviceTransport):

    #: Default config
    config = Instance(SerialConfig, ())

    #: Connection port
    connection = Instance(SerialPort)

    #: Whether a serial connection spools depends on the device (configuration)
    always_spools = set_default(False)

    #: Wrapper
    _protocol = Instance(InkcutProtocol)

    def connect(self):
        try:
            config = self.config

            #: Save a reference
            self.protocol.transport = self

            #: Make the wrapper
            self._protocol = InkcutProtocol(self, self.protocol)

            self.connection = SerialPort(
                self._protocol,
                config.port,
                reactor,
                baudrate=config.baudrate,
                bytesize=config.bytesize,
                parity=SERIAL_PARITIES[config.parity],
                stopbits=config.stopbits,
                xonxoff=config.xonxoff,
                rtscts=config.rtscts
            )
            log.debug("{} | opened".format(self.config.port))
        except Exception as e:
            #: Make sure to log any issues as these tracebacks can get
            #: squashed by twisted
            log.error("{} | {}".format(
                self.config.port, traceback.format_exc()
            ))
            raise

    def write(self, data):
        if not self.connection:
            raise IOError("Port is not opened")
        log.debug("-> {} | {}".format(self.config.port, data))
        if hasattr(data, 'encode'):
            data = data.encode()
        self._protocol.transport.write(data)

    def disconnect(self):
        if self.connection:
            log.debug("{} | closed".format(self.config.port))
            self.connection.loseConnection()
            self.connection = None

    def __repr__(self):
        return self.config.port
コード例 #4
0
ファイル: ioservice.py プロジェクト: komcg/azathoth-server
class IoService(service.Service):
    name = "ioservice"
    def __init__(self, port, speed=115200):
        self.port = port
        self.speed = speed
    
    def startService(self):
        log.msg(system='IoService', format="service starting")
        self.protocol = IoProtocol(self)
        log.msg(system='IoService', format="opening serial port %(port)s", port=self.port)
        self.serial = SerialPort(self.protocol, self.port, reactor, baudrate=self.speed)
        self.lcd = Lcd(self)
        self.sonar = Sonar(self)
        self.protocol.register_callback(0x01, self.onHandshake)
        self.protocol.register_callback(0xee, self.onIoError)
        service.Service.startService(self)

    def stopService(self):
        log.msg(system='IoService', format="service stopping")
        self.serial.loseConnection()
        service.Service.stopService(self)

    def onHandshake(self, data):
        log.msg(system='IoService', format="Controller is alive") 
        self.parent.triggerEvent('IO_HANDSHAKE')

    def onIoError(self, data):
        log.msg(system='IoService', format="Controller error, code %(code)#x", code=data[0])
        self.parent.triggerEvent('IO_ERROR', data[0])
コード例 #5
0
ファイル: serial.py プロジェクト: sveinse/lumina
class ReconnectingSerialPort(Reconnector):
    """ A class for serial port connection that will retry the connection
        if the connection fails
    """

    def __init__(self, reactor, protocol, port, *args, **kwargs):
        Reconnector.__init__(self, reactor)
        self.protocol = protocol
        self.port = port
        self.args = args
        self.kwargs = kwargs
        self.serialport = None


    def connect(self):
        try:
            self.serialport = SerialPort(self.protocol, self.port, self.reactor,
                                         *self.args, **self.kwargs)
            self.resetDelay()
        except SerialException:
            self.connectionFailed(Failure())


    def connectionLost(self, reason):
        self.serialport = None
        self.retry()


    def connectionFailed(self, reason):
        self.serialport = None
        self.retry()


    def loseConnection(self, *args, **kwargs):
        ''' Lose connection to the serial port '''
        self.stopTrying()
        if self.serialport:
            self.serialport.loseConnection(*args, **kwargs)
コード例 #6
0
class KetiDriver(SmapDriver):
    CHANNELS = [('temperature', 'C', 'double'), ('humidity', '%RH', 'double'),
                ('light', 'lx', 'long'), ('pir', '#', 'long'),
                ('co2', 'ppm', 'long')]

    def setup(self, opts):
        self.port = opts.get('SerialPort', '/dev/ttyrd00')
        self.baud = int(opts.get('BaudRate', 115200))
        self.namespace = opts.get('Namespace', None)
        if self.namespace: self.namespace = uuid.UUID(self.namespace)

    def uuid(self, serial_id, channel):
        # create consistent uuids for data based on the serial id
        key = serial_id + '-' + channel
        if self.namespace:
            return uuid.uuid5(self.namespace, key)
        else:
            return SmapDriver.uuid(self, key)

    def start(self):
        self.serial = SerialPort(KetiMoteReceiver(self),
                                 self.port,
                                 reactor,
                                 baudrate=self.baud)

    def stop(self):
        return self.serial.loseConnection()

    def create_channels(self, msg):
        if not self.get_collection('/' + str(msg['node_id'])):
            for (name, unit, dtype) in self.CHANNELS:
                self.add_timeseries('/' + str(msg['node_id']) + '/' + name,
                                    self.uuid(msg['serial_id'], name),
                                    unit,
                                    data_type=dtype)
            self.set_metadata(
                '/' + str(msg['node_id']), {
                    'Metadata/Instrument/PartNumber':
                    str(msg['node_id']),
                    'Metadata/Instrument/SerialNumber':
                    ':'.join(map(lambda x: hex(ord(x))[2:], msg['serial_id']))
                })

    def dataReceived(self, msg):
        self.create_channels(msg)
        for (name, _, __) in self.CHANNELS:
            if name in msg:
                self._add('/' + str(msg['node_id']) + '/' + name, msg[name])
コード例 #7
0
class KetiDriver(SmapDriver):
    CHANNELS = [('temperature', 'C', 'double'),
                ('humidity', '%RH', 'double'),
                ('light', 'lx', 'long'),
                ('pir', '#', 'long'),
                ('co2', 'ppm', 'long')]
    
    def setup(self, opts):
        self.port = opts.get('SerialPort', '/dev/ttyrd00')
        self.baud = int(opts.get('BaudRate', 115200))
        self.namespace = opts.get('Namespace', None)
        if self.namespace: self.namespace = uuid.UUID(self.namespace)

    def uuid(self, serial_id, channel):
        # create consistent uuids for data based on the serial id
        key = serial_id + '-' + channel
        if self.namespace:
            return uuid.uuid5(self.namespace, key)
        else:
            return SmapDriver.uuid(self, key)

    def start(self):
        self.serial = SerialPort(KetiMoteReceiver(self), self.port,
                                 reactor, baudrate=self.baud)

    def stop(self):
        return self.serial.loseConnection()

    def create_channels(self, msg):
        if not self.get_collection('/' + str(msg['node_id'])):
            for (name, unit, dtype) in self.CHANNELS:
                self.add_timeseries('/' + str(msg['node_id']) + '/' + name,
                                    self.uuid(msg['serial_id'], name),
                                    unit, data_type=dtype)
            self.set_metadata('/' + str(msg['node_id']), {
                'Metadata/Instrument/PartNumber': str(msg['node_id']),
                'Metadata/Instrument/SerialNumber': ':'.join(map(lambda x: hex(ord(x))[2:],
                                                                msg['serial_id']))
                })

    def dataReceived(self, msg):
        self.create_channels(msg)
        for (name, _, __) in self.CHANNELS:
            if name in msg:
                self._add('/' + str(msg['node_id']) + '/' + name,
                          msg[name])
コード例 #8
0
ファイル: runner.py プロジェクト: chintal/driver2200087
class InstProtocol2200087(Protocol):
    """
    This is a twisted protocol which handles serial communications with
    2200087 multimeters. This protocol exists and operates within the context
    of a twisted reactor. Applications themselves built on twisted should be
    able to simply import this protocol (or its factory).

    If you would like the protocol to produce datapoints in a different format,
    this protocol should be sub-classed in order to do so. The changes necessary
    would likely begin in this class's frame_recieved() function.

    Synchronous / non-twisted applications should use the InstInterface2200087
    class instead. The InstInterface2200087 class accepts a parameter to specify
    which protocol factory to use, in case you intend to subclass this protocol.

    :param port: Port on which the device is connected. Default '/dev/ttyUSB0'.
    :type port: str
    :param buffer_size: Length of the point buffer in the protocol. Default 100.
    :type buffer_size: int

    """
    def __init__(self, port, buffer_size=100):
        self._buffer = ""
        self._frame_size = 14
        self._point_buffer_size = buffer_size
        self.point_buffer = None
        self.reset_buffer()
        self._serial_port = port
        self._serial_transport = None
        self._frame_processor = process_chunk

    def reset_buffer(self):
        """
        Resets the point buffer. Any data presently within it will be lost.
        """
        self.point_buffer = deque(maxlen=self._point_buffer_size)

    def make_serial_connection(self):
        """
        Creates the serial connection to the port specified by the instance's
        _serial_port variable and sets the instance's _serial_transport variable
        to the twisted.internet.serialport.SerialPort instance.
        """
        self._serial_transport = SerialPort(self,
                                            self._serial_port,
                                            reactor,
                                            baudrate=2400,
                                            bytesize=8,
                                            parity='N',
                                            stopbits=1,
                                            timeout=5,
                                            xonxoff=0,
                                            rtscts=0)

    def break_serial_connection(self):
        """
        Calls loseConnection() on the instance's _serial_transport object.
        """
        self._serial_transport.loseConnection()

    def connectionMade(self):
        """
        This function is called by twisted when a connection to the serial
        transport is successfully opened.
        """
        pass

    def connectionLost(self, reason=connectionDone):
        """
        This function is called by twisted when the connection to the
        serial transport is lost.
        """
        print "Lost Connection to Device"
        print reason

    def dataReceived(self, data):
        """
        This function is called by twisted when new bytes are received by the
        serial transport.

        This data is appended to the protocol's framing buffer, _buffer, and
        when the length of the buffer is longer than the frame size, that many
        bytes are pulled out of the start of the buffer and frame_recieved is
        called with the frame.

        This function also performs the initial frame synchronization by
        dumping any bytes in the beginning of the buffer which aren't the
        first byte of the frame. In its steady state, the protocol framing
        buffer will always have the beginning of a frame as the first element.

        :param data: The data bytes received
        :type data: str

        """
        self._buffer += data
        while len(self._buffer) and self._buffer[0].encode('hex')[0] != '1':
            self._buffer = self._buffer[1:]
        while len(self._buffer) >= self._frame_size:
            self.frame_received(self._buffer[0:self._frame_size])
            self._buffer = self._buffer[self._frame_size:]

    def frame_received(self, frame):
        """
        This function is called by data_received when a full frame is received
        by the serial transport and the protocol.

        This function recasts the frame into the format used by the serialDecoder
        and then uses that module to process the frame into the final string. This
        string is then appended to the protocol's point buffer.

        This string is treated as a fully processed datapoint for the purposes
        of this module.

        :param frame: The full frame representing a single data point
        :type frame: str

        """
        frame = [byte.encode('hex') for byte in frame]
        chunk = ' '.join(frame)
        point = self._frame_processor(chunk)
        self.point_buffer.append(point)

    def latest_point(self, flush=True):
        """
        This function can be called to obtain the latest data point from the
        protocol's point buffer. The intended use of this function is to allow
        random reads from the DMM. Such a typical application will want to
        discard all the older data points (including the one returned), which
        it can do with flush=True.

        This function should only be called when there is data already in the
        protocol buffer, which can be determined using data_available().

        This is a twisted protocol function, and should not be called directly
        by synchronous / non-twisted code. Instead, its counterpart in the
        InstInterface object should be used.

        :param flush: Whether to flush all the older data points.
        :type flush: bool
        :return: Latest Data Point as processed by the serialDecoder
        :rtype: str

        """
        rval = self.point_buffer[-1]
        if flush is True:
            self.point_buffer.clear()
        return rval

    def next_point(self):
        """
        This function can be called to obtain the next data point from the
        protocol's point buffer. The intended use of this function is to allow
        continuous streaming reads from the DMM. Such a typical application will
        want to pop the element from the left of the point buffer, which is what
        this function does.

        This function should only be called when there is data already in the
        protocol buffer, which can be determined using data_available().

        This is a twisted protocol function, and should not be called directly
        by synchronous / non-twisted code. Instead, its counterpart in the
        InstInterface object should be used.

        :return: Next Data Point in the point buffer as processed by the serialDecoder
        :rtype: str

        """
        return self.point_buffer.popleft()

    def next_chunk(self):
        """
        This function can be called to obtain a copy of the protocol's point
        buffer with all but the latest point in protocol's point buffer. The
        intended use of this function is to allow continuous streaming reads
        from the DMM. Such a typical application will want to pop the elements
        from the left of the point buffer, which is what this function does.

        This function should only be called when there is data already in the
        protocol buffer, which can be determined using data_available().

        This is a twisted protocol function, and should not be called directly
        by synchronous / non-twisted code. Instead, its counterpart in the
        InstInterface object should be used.

        :return: Copy of point_buffer with all but the latest_point
        :rtype: deque
        """
        rval = self.point_buffer
        self.point_buffer = deque([rval.pop()], maxlen=self._point_buffer_size)
        return rval

    def data_available(self):
        """
        This function can be called to read the number of data points waiting in
        the protocol's point buffer.

        This is a twisted protocol function, and should not be called directly
        by synchronous / non-twisted code. Instead, its counterpart in the
        InstInterface object should be used.

        :return: Number of points waiting in the protocol's point buffer
        :rtype: int

        """
        return len(self.point_buffer)
コード例 #9
0
class TrafficLightSerial(basic.LineReceiver, TrafficLight):

    delimiter = '\n'.encode('ascii')

    config_map = {
        "min_on_current": 0,
        "max_on_current": 1,
        "max_off_current": 2
    }

    rx_timeout = 3

    baud = 19200

    @classmethod
    def open(cls, name, port, reset_pin=None, reactor=reactor):
        local_light = cls()
        local_light.setLogger(logging.getLogger(name))
        serial = SerialPort(baudrate=cls.baud,
                            deviceNameOrPortNumber=port,
                            protocol=local_light,
                            reactor=reactor)
        local_light.setSerial(serial)
        local_light.setPort(port)
        local_light.setReset(reset_pin)
        local_light.reactor = reactor
        local_light.sendUpdate()
        #reactor.call_later(cls.rx_timeout, local_light.timed_out)
        return local_light

    def reopen(self):
        '''
        Tries to reestablish a serial link in case of HW issues
        '''
        print(dir(self.serial))

        self.serial = SerialPort(baudrate=self.baud,
                                 deviceNameOrPortNumber=self.port,
                                 protocol=self,
                                 reactor=self.reactor)

    def lineLengthExceeded(self, line):
        logging.error("Line length exceeded/codeDecodeErrorbaud rate error?")
        print(self.serial)
        self.serial.loseConnection()
        self.serial.stopReading()
        self.reactor.callLater(1, self.reopen)
        #self.reopen()

    def setPort(self, port):
        self.port = port

    def setSerial(self, serial):
        self.serial = serial

    def setReset(self, pin):
        if pin is None:
            self.reset_name = None
            return

        self.reset_name = "/sys/class/gpio/gpio{}/value".format(pin)
        try:
            with open("/sys/class/gpio/export", "w") as f:
                f.write("{}\n".format(pin))
        except Exception as e:
            logging.error(
                "Could not open/write exports in gpiofs: {}".format(e))

    def lineReceived(self, line):
        # Ignore blank lines
        if not line:
            return
        try:
            line = line.decode("ascii").strip()
            (self.state, self.batt_voltage, self.error_state,
             self.lamp_currents[0], self.lamp_currents[1],
             self.lamp_currents[2]) = line.split(" ")
            self.last_seen = time()
        except (ValueError, UnicodeDecodeError):
            logging.info("Received garbled line")
        # logging.warning("update myself: {}".format(self))

    def setConfig(self, param, value):
        if param in self.config_map:
            cmd = "s{}={}".format(self.config_map[param], int(value))
            self.sendLine(cmd)
        else:
            raise ValueError("Unknown parameter {}".format(param))

    def sendUpdate(self):
        if self.give_way:
            self.sendLine("G".encode("ascii"))
        else:
            self.sendLine("g".encode("ascii"))
        if self.temp_error:
            self.sendLine("E".encode("ascii"))
        else:
            self.sendLine("e".encode("ascii"))

    def serviceWatchdog(self):
        self.sendUpdate()
コード例 #10
0
class SerialNodesController(object):
    def __init__(self, oNodeControl):
        self._NodeControl = oNodeControl
        # list all serial ports: python -m serial.tools.list_ports
        self._ResetState = 10
        self._connectSerialPort()

    def _connectSerialPort(self):
        self.Close()
        myProtocol = SerialNodesProtocol(self._NodeControl,
                                         OnReceive=self.OnMsgReceive)
        self._serialPort = SerialPort(myProtocol,
                                      self._NodeControl.nodeProps.get(
                                          'serialnodes', 'serialport'),
                                      reactor,
                                      baudrate=9600,
                                      bytesize=serial.EIGHTBITS,
                                      parity=serial.PARITY_NONE)
        self._NodeControl.log.debug(
            'Serial port: %s open.' %
            self._NodeControl.nodeProps.get('serialnodes', 'serialport'))
        sleep(1)

    def OnMsgReceive(self, RecMsg):
        myNodeID = '999'  # self._NodeControl.nodeProps.get('system', 'nodeId')

        if str(RecMsg.ToAdress) == myNodeID:
            # for this node
            if ((int(RecMsg.Function) == 1) and (int(RecMsg.MsgValue) == 1)):
                self._NodeControl.log.debug("Deuropen signal (keypad)")
                self.doOpenDoor()
                self._NodeControl.MQTTPublish(sTopic="deur/keyopen",
                                              sValue="ON",
                                              iQOS=0,
                                              bRetain=False)
                reactor.callLater(self._ResetState,
                                  self.ResetState,
                                  topic="deur/keyopen")
            elif ((int(RecMsg.Function) == 2) and (int(RecMsg.MsgValue) == 1)):
                self._NodeControl.log.debug("Deuropen signal (RFID)")
                self.doOpenDoor()
                self._NodeControl.MQTTPublish(sTopic="deur/rfidopen",
                                              sValue="ON",
                                              iQOS=0,
                                              bRetain=False)
                reactor.callLater(self._ResetState,
                                  self.ResetState,
                                  topic="deur/rfidopen")
            elif ((int(RecMsg.Function) == 3) and (int(RecMsg.MsgValue) == 1)):
                self._NodeControl.log.debug("Deurbel signal.")
                self._NodeControl.MQTTPublish(sTopic="deur/ring",
                                              sValue="ON",
                                              iQOS=0,
                                              bRetain=False)
                reactor.callLater(self._ResetState,
                                  self.ResetState,
                                  topic="deur/ring")
            elif ((int(RecMsg.Function) == 4) and (int(RecMsg.MsgValue) == 1)):
                self._NodeControl.log.debug("Tampering Keypad")
                self._NodeControl.MQTTPublish(sTopic="tampering/keypad",
                                              sValue="ON",
                                              iQOS=0,
                                              bRetain=False)
            elif ((int(RecMsg.Function) == 4) and (int(RecMsg.MsgValue) == 0)):
                reactor.callLater(self._ResetState,
                                  self.ResetState,
                                  topic="tampering/keypad")

    def ResetState(self, topic):
        self._NodeControl.MQTTPublish(sTopic=topic,
                                      sValue="OFF",
                                      iQOS=0,
                                      bRetain=False)

    def SendMessage(self, sSerialMessage):
        try:
            self._serialPort.write(sSerialMessage)
            sleep(0.1)
            return True
        except Exception as exp:
            print(traceback.format_exc())
            self._NodeControl.log.error("SendMessage error: %s." %
                                        traceback.format_exc())
            return False

    def Close(self):
        try:
            self._serialPort.loseConnection()
            self._serialPort = None
        except:
            pass

    def doOpenDoor(self):
        if self._NodeControl.nodeProps.has_option('dooropener', 'active') and\
                self._NodeControl.nodeProps.getboolean('dooropener', 'active'):
            idoorUnlockTime = 5
            if self._NodeControl.nodeProps.has_option('dooropener',
                                                      'unlockTime'):
                idoorUnlockTime = float(
                    self._NodeControl.nodeProps.get('dooropener',
                                                    'unlockTime'))
            self._NodeControl.log.debug("Door opening")
            wiringpi.digitalWrite(17, 1)
            self._NodeControl.log.debug("Door opening done")
            reactor.callLater(idoorUnlockTime, self.releaseDoorLockEvent)

    def releaseDoorLockEvent(self):
        self._NodeControl.log.debug("releaseDoorLockEvent")
        wiringpi.digitalWrite(17, 0)
        self._NodeControl.log.debug("Deur GPIO 17 off")
コード例 #11
0
ファイル: runner.py プロジェクト: chintal/driver2200087
class InstProtocol2200087(Protocol):
    """
    This is a twisted protocol which handles serial communications with
    2200087 multimeters. This protocol exists and operates within the context
    of a twisted reactor. Applications themselves built on twisted should be
    able to simply import this protocol (or its factory).

    If you would like the protocol to produce datapoints in a different format,
    this protocol should be sub-classed in order to do so. The changes necessary
    would likely begin in this class's frame_recieved() function.

    Synchronous / non-twisted applications should use the InstInterface2200087
    class instead. The InstInterface2200087 class accepts a parameter to specify
    which protocol factory to use, in case you intend to subclass this protocol.

    :param port: Port on which the device is connected. Default '/dev/ttyUSB0'.
    :type port: str
    :param buffer_size: Length of the point buffer in the protocol. Default 100.
    :type buffer_size: int

    """
    def __init__(self, port, buffer_size=100):
        self._buffer = ""
        self._frame_size = 14
        self._point_buffer_size = buffer_size
        self.point_buffer = None
        self.reset_buffer()
        self._serial_port = port
        self._serial_transport = None
        self._frame_processor = process_chunk

    def reset_buffer(self):
        """
        Resets the point buffer. Any data presently within it will be lost.
        """
        self.point_buffer = deque(maxlen=self._point_buffer_size)

    def make_serial_connection(self):
        """
        Creates the serial connection to the port specified by the instance's
        _serial_port variable and sets the instance's _serial_transport variable
        to the twisted.internet.serialport.SerialPort instance.
        """
        self._serial_transport = SerialPort(self, self._serial_port, reactor,
                                            baudrate=2400, bytesize=8,
                                            parity='N', stopbits=1, timeout=5,
                                            xonxoff=0, rtscts=0)

    def break_serial_connection(self):
        """
        Calls loseConnection() on the instance's _serial_transport object.
        """
        self._serial_transport.loseConnection()

    def connectionMade(self):
        """
        This function is called by twisted when a connection to the serial
        transport is successfully opened.
        """
        pass

    def connectionLost(self, reason=connectionDone):
        """
        This function is called by twisted when the connection to the
        serial transport is lost.
        """
        print "Lost Connection to Device"
        print reason

    def dataReceived(self, data):
        """
        This function is called by twisted when new bytes are received by the
        serial transport.

        This data is appended to the protocol's framing buffer, _buffer, and
        when the length of the buffer is longer than the frame size, that many
        bytes are pulled out of the start of the buffer and frame_recieved is
        called with the frame.

        This function also performs the initial frame synchronization by
        dumping any bytes in the beginning of the buffer which aren't the
        first byte of the frame. In its steady state, the protocol framing
        buffer will always have the beginning of a frame as the first element.

        :param data: The data bytes received
        :type data: str

        """
        self._buffer += data
        while len(self._buffer) and self._buffer[0].encode('hex')[0] != '1':
            self._buffer = self._buffer[1:]
        while len(self._buffer) >= self._frame_size:
            self.frame_received(self._buffer[0:self._frame_size])
            self._buffer = self._buffer[self._frame_size:]

    def frame_received(self, frame):
        """
        This function is called by data_received when a full frame is received
        by the serial transport and the protocol.

        This function recasts the frame into the format used by the serialDecoder
        and then uses that module to process the frame into the final string. This
        string is then appended to the protocol's point buffer.

        This string is treated as a fully processed datapoint for the purposes
        of this module.

        :param frame: The full frame representing a single data point
        :type frame: str

        """
        frame = [byte.encode('hex') for byte in frame]
        chunk = ' '.join(frame)
        point = self._frame_processor(chunk)
        self.point_buffer.append(point)

    def latest_point(self, flush=True):
        """
        This function can be called to obtain the latest data point from the
        protocol's point buffer. The intended use of this function is to allow
        random reads from the DMM. Such a typical application will want to
        discard all the older data points (including the one returned), which
        it can do with flush=True.

        This function should only be called when there is data already in the
        protocol buffer, which can be determined using data_available().

        This is a twisted protocol function, and should not be called directly
        by synchronous / non-twisted code. Instead, its counterpart in the
        InstInterface object should be used.

        :param flush: Whether to flush all the older data points.
        :type flush: bool
        :return: Latest Data Point as processed by the serialDecoder
        :rtype: str

        """
        rval = self.point_buffer[-1]
        if flush is True:
            self.point_buffer.clear()
        return rval

    def next_point(self):
        """
        This function can be called to obtain the next data point from the
        protocol's point buffer. The intended use of this function is to allow
        continuous streaming reads from the DMM. Such a typical application will
        want to pop the element from the left of the point buffer, which is what
        this function does.

        This function should only be called when there is data already in the
        protocol buffer, which can be determined using data_available().

        This is a twisted protocol function, and should not be called directly
        by synchronous / non-twisted code. Instead, its counterpart in the
        InstInterface object should be used.

        :return: Next Data Point in the point buffer as processed by the serialDecoder
        :rtype: str

        """
        return self.point_buffer.popleft()

    def next_chunk(self):
        """
        This function can be called to obtain a copy of the protocol's point
        buffer with all but the latest point in protocol's point buffer. The
        intended use of this function is to allow continuous streaming reads
        from the DMM. Such a typical application will want to pop the elements
        from the left of the point buffer, which is what this function does.

        This function should only be called when there is data already in the
        protocol buffer, which can be determined using data_available().

        This is a twisted protocol function, and should not be called directly
        by synchronous / non-twisted code. Instead, its counterpart in the
        InstInterface object should be used.

        :return: Copy of point_buffer with all but the latest_point
        :rtype: deque
        """
        rval = self.point_buffer
        self.point_buffer = deque([rval.pop()], maxlen=self._point_buffer_size)
        return rval

    def data_available(self):
        """
        This function can be called to read the number of data points waiting in
        the protocol's point buffer.

        This is a twisted protocol function, and should not be called directly
        by synchronous / non-twisted code. Instead, its counterpart in the
        InstInterface object should be used.

        :return: Number of points waiting in the protocol's point buffer
        :rtype: int

        """
        return len(self.point_buffer)
コード例 #12
0
ファイル: driveservice.py プロジェクト: komcg/azathoth-server
class DriveService(service.Service):
    name = "driveservice"
    def __init__(self, port, speed=115200):
        self.port = port
        self.speed = speed
        self.cal_x_cur = 0
        self.cal_y_cur = 0
        self.cal_x_eeprom = 0
        self.cal_y_eeprom = 0

    def startService(self):
        log.msg(system='DriveService', format="service starting")
        self.protocol = DriveProtocol(self)
        log.msg(system='DriveService', format="opening serial port %(port)s", port=self.port)
        self.serial = SerialPort(self.protocol, self.port, reactor, baudrate=self.speed)
        self.protocol.register_callback(0x01, self._onHandshake)
        self.protocol.register_callback(0x41, self._onReceiveCalibration)
        self.protocol.register_callback(0x42, self._onReceiveStatus)
        self.protocol.register_callback(0xee, self._onDriveError)
        service.Service.startService(self)
    
    def stopService(self):
        log.msg(system='DriveService', format="service stopping")
        self.serial.loseConnection()
        service.Service.stopService(self)

    def setMode(self, mode):
        self.protocol.cmd_mode(mode)

    def directJoystick(self, xpos, ypos):
        self.protocol.cmd_joystick(xpos, ypos)

    def setCalibration(self, xvalue, yvalue):
        self.protocol.cmd_calibrate_set(xvalue, yvalue)

    def storeCalibration(self):
        self.protocol.cmd_calibrate_store()

    def driveSelect(self, enable):
        self.protocol.cmd_driveselect(enable)

    def stop(self):
        self.protocol.cmd_joystick(0, 0)

    def estop(self):
        self.protocol.cmd_estop()

    def reset(self):
        self.protocol.cmd_reset()

    def getCalibration(self):
        self.protocol.req_calibration()
        self.calibration_d = defer.Deferred()
        return self.calibration_d

    def _onHandshake(self, data):
        log.msg(system='DriveService', format="Controller is alive")
        self.parent.triggerEvent('DRV_HANDSHAKE')

    def _onDriveError(self, data):
        log.msg(system='DriveService', format="Controller error, code %(code)#x", code=data[0])
        self.parent.triggerEvent('DRV_ERROR', data[0])

    def _onReceiveStatus(self, data):
        status = data[0];
        xpos = data[1];
        ypos = data[2];
        xval = data[3];
        yval = data[4];
        self.parent.triggerEvent('DRV_STATUS', status, xpos, ypos, xval, yval)

    def _onReceiveCalibration(self, data):
        log.msg(system='DriveService', format="receivied calibration values")
        calibration = {}
        calibration['current_x'] = data[0]
        calibration['current_y'] = data[1]
        calibration['eeprom_x'] = data[2]
        calibration['eeprom_y'] = data[3]
        self.cal_x_cur = data[0]
        self.cal_y_cur = data[1]
        self.cal_x_eeprom = data[2]
        self.cal_y_eeprom = data[3]
        if self.calibration_d is not None:
            self.calibration_d.callback(calibration)
            self.calibration_d = None