def initServer( self ): #first open the serial port try: self.connection = SerialConnection(GaugeFormat) print "Serial port opened successfully: {}".format(GaugeFormat.name) except serial.SerialException: raise Error("Failed to open port {}".format(GaugeFormat.name))
def __init__(self, port): print("Device: Initializing myself as a new device on port %s..." % port) self.port = port self.em = EventsManager() self.components = {} #Dict componentID:component self.abort = False self.deviceMessageQueue = [] self.serialConnection = SerialConnection(port, self.addToMessageQueue) self.processMessageQueue() self.sendCommand({ "command": "devices", "params": None }) #request info about what components are on the device self.sendCommand({ "command": "interval", "params": 2 }) #sets the data-sending rate to 1 second print("Device: Done Initializing.")
class GaugeServer( LabradServer ): """The Pfeiffer Gauge provides pressure values for the resonator experiment, connected to the COM1 serial port on the windows machine""" name = 'Pfeiffer Pressure Gauge' #dictionary which tells you how many bytes you need to read for a given request after ENQ is sent. #includes CR, LF NUM_BYTES = { 'PR1':13+2, 'UNI':1+2} # number of bytes which are read after a request is sent, before replying with ENQ NUM_ACK_BYTES = 3 #codes for units returned by the gauge UNIT_CODES = { 0: 'mbar', 1: 'torr', 2: 'Pa'} def initServer( self ): #first open the serial port try: self.connection = SerialConnection(GaugeFormat) print "Serial port opened successfully: {}".format(GaugeFormat.name) except serial.SerialException: raise Error("Failed to open port {}".format(GaugeFormat.name)) def stopServer(self): if hasattr(self, 'connection'): print "Closing the serial port {}".format(GaugeFormat.name) self.connection.close() @setting(1, 'getPortname', returns='s') def getPortname(self, c): """Name of the COM port being used""" return(GaugeFormat.name) @setting(2, 'getBaudrate', returns='i') def getBaudrate(self, c): """reutrn baud rate for the connection""" return GaugeFormat.baudrate @setting(3, 'getParity', returns= 's') def getParity(self, c): """ parity setting for the connection""" return GaugeFormat.parity @setting(4, 'getByteSize', returns ='i') def getByteSize(self, c): """number of data bits""" return GaugeFormat.bytesize @setting(5, 'getStopBits', returns='i') def getStopBits(self, c): """number of stop bits""" return GaugeFormat.stopbits @setting(6, 'getTimeout', returns='i') def getTimeout(self, c): """timeout, in seconds, for the serial connection""" return GaugeFormat.timeout @setting(11, 'WriteSerial', data= 's', returns = 'i') def writeSerial(self, c, data): """ Writes the given data to the serial port. Returns the number of bytes written""" nb = yield self._write(data) returnValue(nb) @setting(12, "ReadSerial", numbytes = 'i', returns='s') def readSerial(self, c, numbytes=10): """ Read specified number of bytes from the serial port ( if none provided, read 10)""" data = yield self._read(numbytes) returnValue(data) @setting(13, "ReadPressure", returns = ['v[mbar]', 'v[torr]', 'v[Pa]', 's']) def readPressure(self, c): """return the current pressure""" pressure_str = yield self.getResponse('PR1') try: p = self.parsePressure(pressure_str) except Error as e: returnValue('Gauge off') else: units = yield self.getUnits(c) if (units == 'mbar'): #labrad doesn't recognize the mbar unit so switch to bar p = p/1000 units = 'bar' returnValue(WithUnit(p, units)) @setting(14, "getUnits", returns='s') def getUnits(self, c): """return the current pressure units""" respstr = yield self.getResponse('UNI') unitstr = self.UNIT_CODES[int(respstr)] returnValue(unitstr) @setting(21, "info", returns = 's') def info(self, c): info_str = """this is a Labrad server for the Pfeiffer Dual Gauge which monitors pressure for the resonator experiment. Pressure values can be obtained by calling readpressure(). The Serial port settings can be viewed by clients but not edited. They are determined by the pfeiffer specifications you can edit the server file at C:\Users\experimenter\Desktop\LabRad\resonator\PfeifferGaugeServer.py on the windows machine. There is only one serial port on this machine, COM1, and it has to be open for the server to function.""" return info_str @inlineCallbacks def _write(self, data): """Write string to the port""" nb = yield self.connection.write(data) returnValue(nb) @inlineCallbacks def _writeCRLF(self, data): """Write string plus termination characters""" nb = yield self._write(data + '\r\n') returnValue(nb) @inlineCallbacks def _read(self, nb): """Read the specified number of bytes from the port""" data = yield self.connection.read(nb) returnValue(data) @inlineCallbacks def writeENQ(self): """Writes <ENQ> to the serial port to request transmission of previously specified data""" s = self.connection.getASCIICode('ENQ') yield self._writeCRLF(s) @inlineCallbacks def request(self, req): """ sends the specified 3-byte request string and returns whether or not the request was successfully acknowledged (1 if success)""" nb = yield self._writeCRLF(req) resp = yield self._read(self.NUM_ACK_BYTES) returnValue (not self.isError(resp)) @inlineCallbacks def getResponse(self, req): """ submit the request specified by the 3-byte string REQ. if the request is acknowledged the response string will be returned, minus the CR LF. otherwise an error is raised""" ack = yield self.request(req) if (not ack): #raise Error('bad request to gauge') returnValue('bad request to gauge') else: nb_enq = yield self.writeENQ() resp = yield self._read(self.getNumBytes(req)) if resp == '': returnValue('gauge off or not responding') else: resp = self.strip(resp) returnValue(resp) def strip(self,s): """remove termination characters from the end""" if ((s[-1] != '\n') or (s[-2] != '\r')): print "error here", s raise Error('bad string format') else: return s[:-2] def isError(self, s): """checks if output s from the gauge is an error""" if s == '': return False try: val= (self.strip(s) == self.connection.getASCIICode('NAK')) except Error: val = True return val def parsePressure(self, pstring): """ get the pressure value from the string returned by PR1""" try: start = pstring.index(', ') +2 return float(pstring[start:]) except ValueError: raise Error('Bad pressure string sent to parser') def getNumBytes(self, req): """ get the number of bytes that need to be read for the given request""" try: return self.NUM_BYTES[req] except KeyError: raise Error('bad request')
class RhizoDevice(): def __init__(self, port): print("Device: Initializing myself as a new device on port %s..." % port) self.port = port self.em = EventsManager() self.components = {} #Dict componentID:component self.abort = False self.deviceMessageQueue = [] self.serialConnection = SerialConnection(port, self.addToMessageQueue) self.processMessageQueue() self.sendCommand({ "command": "devices", "params": None }) #request info about what components are on the device self.sendCommand({ "command": "interval", "params": 2 }) #sets the data-sending rate to 1 second print("Device: Done Initializing.") def destroy(self): for componentID in self.components: self.em.unsubscribe(self.sendCommand) self.em.publish("component-removed", {"componentID": componentID}) self.serialConnection.closeConnection() self.serialConnection = False self.abort = True def addComponent(self, component_name): componentID = "%s/%s" % (self.port, component_name) if not componentID in self.components: self.components[componentID] = Component(componentID) self.em.publish("component-added", {"componentID": componentID}) self.em.subscribe("%s/command" % componentID, self.sendCommand) self.sendCommand({ "command": "%s: info" % component_name, "params": None }) #request info about this component def updateComponents(self, component_name, key, value): componentID = "%s/%s" % (self.port, component_name) if componentID in self.components: self.components[componentID].updateInfo(key, value) else: self.addComponent(component_name) #messaging related methods def sendCommand(self, message): command = message["command"] params = message["params"] try: if params is not None: msg = "%s %s" % (command, params) self.serialConnection.writeMessage(msg) else: msg = command self.serialConnection.writeMessage(msg) except: print("Device: Error sending command over serial connection.") # collect messages from the SerialConnection def addToMessageQueue(self, message): self.deviceMessageQueue.append(message) # process incoming serial message queue def _processMessageQueue(self): while True: if not self.abort: if len(self.deviceMessageQueue) > 0: msg = self.deviceMessageQueue.pop(0) msg_array = msg.decode('utf-8').split("|")[0].split( " " ) # Ugly, but this is just how the messages seem to be formatted: "c:v 492|69100" cmd = msg_array.pop(0).split(":") #Decide what kind of message it was-- either meta:devices [components], or componentId:info_type [value] if cmd[0] == "meta": if cmd[1] == "devices": for component in msg_array: self.addComponent(component) else: if cmd[0] == "nack": print("Device not acknowledging messages") pass if len(cmd) > 1: if cmd[1] == "nack" or cmd[1] == "ack": pass else: comp = cmd[0] key = cmd[1] value = msg_array if key == "v": key = "state" self.updateComponents(comp, key, value) else: pass else: break def processMessageQueue(self): t = threading.Thread(target=self._processMessageQueue) t.start()
def setUpClass(cls): print "making serial connection" cls.ser = SerialConnection("root", "chip", "/dev/chip_usb") cls.ser.connect()