def _sendCommand(self, cmd): """ cmd (str): command to be sent to Power Control unit. returns (str): answer received from the Power Control unit raises: IOError: if an ERROR is returned by the Power Control firmware. """ cmd = (cmd + "\n").encode('latin1') with self._ser_access: logging.debug("Sending command %s" % to_str_escape(cmd)) self._serial.write(cmd) ans = b'' char = None while char != b'\n': char = self._serial.read() if not char: logging.error("Timeout after receiving %s", to_str_escape(ans)) # TODO: See how you should handle a timeout before you raise # an HWError raise HwError( "Power Control Unit connection timeout. " "Please turn off and on the power to the box.") # Handle ERROR coming from Power control unit firmware ans += char logging.debug("Received answer %s", to_str_escape(ans)) ans = ans.decode('latin1') if ans.startswith("ERROR"): raise PowerControlError(ans.split(' ', 1)[1]) return ans.rstrip()
def _sendCommand(self, cmd): """ cmd (str): command to be sent to device (without the CR) returns (str): answer received from the device (without \n or \r) raises: DPSSError: if an ERROR is returned by the device. """ cmd = cmd + "\r" with self._ser_access: logging.debug("Sending command %s", to_str_escape(cmd)) self._serial.write(cmd.encode('latin1')) ans = b'' while ans[-2:] != b'\r\n': char = self._serial.read() if not char: raise IOError("Timeout after receiving %s" % to_str_escape(ans)) ans += char logging.debug("Received answer %s", to_str_escape(ans)) # TODO: check for other error answer? # Normally the device either answers OK, or a value, for commands finishing with a "?" if ans.startswith("Syntax error"): raise DPSSError(ans) return ans.decode('latin1').rstrip()
def _decodeMessage(self, msg): ''' Decodes a message sent to the device and writes appropriate responses to the output buffer. msg: a string input message ''' msg = msg.strip() # clean whitespace from message if msg == b'': # Empty message logging.warning('%s: Empty message received', self.name) return if msg == b":SYST:ERR?": # Error query logging.debug('%s: Error state requested: %d', self.name, self._error_state) if self._error_state: self._output_buffer += b'113,"Invalid command"\n' else: self._output_buffer += b'0,"No error"\n' elif msg == b"*IDN?": # Request identifier command self._output_buffer += b'SimRigol\n' logging.debug('%s: Return identifier', self.name) elif re.match(b":SOUR(1|2):FREQ?", msg): self._output_buffer += b'%E\n' % (self._frequency, ) elif re.match(b":OUTP(1|2) ON", msg): # Channel 1 on command self._error_state = False logging.debug('%s: Set output on', self.name) elif re.match(b":OUTP(1|2) OFF", msg): # Channel 1 off command self._error_state = False logging.debug('%s: Set output off', self.name) elif re.match(b":SOUR(1|2):APPL:SQU", msg): # Apply square wave command # Try to unpack the command to see if the format is correct try: cmd, para = msg.split(b" ") frequency, amplitude_pp, dc_bias, phase_shift = [ float(s) for s in para.split(b',') ] self._frequency = frequency logging.debug( '%s: Set square wave %f Hz, %f Vpp, %f V bias, %f degrees', self.name, frequency, amplitude_pp, dc_bias, phase_shift) except TypeError: # could not unpack message self._error_state = True logging.exception('%s: Error Setting square wave %s', self.name, to_str_escape(msg)) elif re.match(b":SOUR(1|2):FUNC:SQU:DCYC", msg): # Duty cycle setting # Try to unpack the command to see if the format is correct try: cmd, para = msg.split(b" ") logging.debug('%s: Setting duty cycle to %f %%', self.name, float(para)) except TypeError: # could not unpack message self._error_state = True logging.exception('%s: Error Setting duty cycle %s', self.name, to_str_escape(msg)) else: self._error_state = True logging.exception('%s: Error state set for message: %s', self.name, to_str_escape(msg))
def _sendQuery(self, cmd): """ cmd (byte str): command to be sent to device returns (str): answer received from the device raise: IOError if no answer is returned in time """ with self._net_access: logging.debug("Sending: %s", to_str_escape(cmd)) self._socket.sendall(cmd + b'\r\n') ans = b'' # TODO: Possibility that multiple replies will be contained within one packet # Might have to add this functionality while ans[-2:] != b"\r\n": try: ans += self._socket.recv(4096) except socket.timeout: # this is ok. Just means the server didn't send anything. # Keep listening logging.warning("Socket timeout on message %s", to_str_escape(cmd)) logging.debug("Received: %s", to_str_escape(ans)) return ans.strip().decode("latin1")
def _sendQuery(self, cmd): """ cmd (byte str): command to be sent to device (without the LF, but with the ?) returns (byte str): answer received from the device (without \n or \r) raise: IOError if no answer is returned in time """ cmd = cmd + b"\n" with self._ser_access: logging.debug("Sending command %s", to_str_escape(cmd)) self._serial.write(cmd) self._serial.timeout = 1 ans = b'' while ans[-1:] != b'\n': char = self._serial.read() if not char: raise IOError("Timeout after receiving %s" % to_str_escape(ans)) ans += char logging.debug("Received answer %s", to_str_escape(ans)) time.sleep(0.05) # prevent overloading the device with messages return ans.strip()
def _setValue(self, com, val=None): """ Write a value (str) com (str): 3 characters command val (None or str): value to set raise: IOError if problem decoding the answer or timeout OXXError: if the device is unhappy (eg, unknown command, out of range) """ if val is None: val = "" ans = self.acc.sendCommand("%s%s%s" % (com, self._com_chan, val)) if not ans.startswith(com): raise IOError("Expected answer to start with %s but got %s" % (com, to_str_escape(ans))) status = ans[len(com) + len(self._com_chan):] if not status: logging.warning("Answer too short after setting %s: %s", com, to_str_escape(ans)) elif status[0] == "x": raise OXXError("Failed to set %s to %s" % (com, val)) elif status[0] == ">": pass else: logging.warning("Unexpected answer after setting %s: %s", com, to_str_escape(ans))
def sendCommand(self, com): """ Send a command which does not expect any report back com (string): command to send (not including the ? and the \r) return (string): the report without prefix ("!") nor carriage return. """ assert (len(com) <= 50) full_com = ("?" + com + "\r").encode('latin1') logging.debug("Sending: '%s'", to_str_escape(full_com)) self._serial.write(full_com) # ensure everything is received, before expecting an answer self._serial.flush() # Read lines per line until it's an answer (!) while True: line = self.readMessage() if line[0] == "$": # ad-hoc message => we don't care logging.debug("Skipping ad-hoc message '%s'", to_str_escape(line)) else: break if not line[0] == "!": raise IOError("Answer prefix (!) not found.") if line.startswith("!UK"): # !UK or !UK[n] raise OXXError("Unknown command (%s)." % to_str_escape(com)) return line[1:]
def _sendCommand(self, cmd): """ cmd (byte str): command to be sent to PMT Control unit. returns (byte str): answer received from the PMT Control unit raises: PMTControlError: if an ERROR is returned by the PMT Control firmware. HwError: in case the of connection timeout """ cmd = cmd + b"\n" with self._ser_access: logging.debug("Sending command %s", to_str_escape(cmd)) try: self._serial.write(cmd) except IOError: logging.warn("Failed to send command to PMT Control firmware, " "trying to reconnect.") if self._recovering: raise else: self._tryRecover() # send command again logging.debug( "Sending command %s again after auto-reconnect" % to_str_escape(cmd)) return self._sendCommand(cmd[:-1]) # cmd without \n ans = b'' char = None while char != b'\n': try: char = self._serial.read() except IOError: logging.warn("Failed to read from PMT Control firmware, " "trying to reconnect.") if self._recovering: raise else: self._tryRecover() # don't send command again raise IOError( "Failed to read from PMT Control firmware, " "restarted serial connection.") if not char: logging.error("Timeout after receiving %s", to_str_escape(ans)) # TODO: See how you should handle a timeout before you raise # an HWError raise HwError( "PMT Control Unit connection timeout. " "Please turn off and on the power to the box.") # Handle ERROR coming from PMT control unit firmware ans += char logging.debug("Received answer %s", to_str_escape(ans)) if ans.startswith(b"ERROR"): raise PMTControlError(ans.split(b' ', 1)[1]) return ans.rstrip()
def _parseMessage(self, msg): """ msg (str): the message to parse (without the \r) return None: self._output_buf is updated if necessary """ logging.debug("SIM: parsing %s", to_str_escape(msg)) m = re.match(br"(?P<com>\*?[A-Za-z:]+\??)\W*(?P<args>.*)", msg) if not m: logging.error("Received unexpected message %s", msg) return com = m.group("com").upper() if m.group("args"): args = m.group("args").strip() else: args = None logging.debug("SIM: decoded message as %s %s", to_str_escape(com), args) # decode the command if com == b"*IDN?": self._sendAnswer(b"KEITHLEY INSTRUMENTS INC.,MODEL 6485,123456,C01 Sep 27 2017 12:22:00/A02 /J") elif com == b"*CLS": pass elif com == b"*STB?": self._sendAnswer(b"0") # It's all fine elif com == b"STAT:QUE?": if not self._errorq: self._sendAnswer(b"0,\"No error\"") else: err = self._errorq.pop(0) self._sendAnswer(b"%d,\"Error %d\"" % (err, err)) elif com == b"CONF:CURR": pass elif com == b":CURR:RANG:AUTO": pass elif com == b"SYST:LFR?": self._sendAnswer(b"%g" % self._lfr) elif com == b":NPLC?": self._sendAnswer(b"%g" % self._nplc) elif com == b":NPLC": if not args: self._addError(6) else: self._nplc = float(args) elif com in (b"MEAS:CURR?", b"READ?"): dur = (self._nplc / self._lfr) * 3 + 0.01 time.sleep(dur) ts = time.time() - self._time_start val = random.uniform(-1e-9, 1e-9) self._sendAnswer(b"%EA,%E,%E" % (val, ts, 0)) else: logging.warning(b"SIM: Unsupported instruction %s", to_str_escape(com)) # TODO: add an error to the queue self._addError(1)
def _sendCommand(self, cmd): """ :param cmd: (bytes) command to be sent to the hardware :returns: (str) response """ cmd += EOL with self._ser_access: logging.debug("Sending command %s", to_str_escape(cmd)) try: self._serial.write(cmd) # TODO: what kind of exception is raised? Needs to be more specific. except: logging.warning("Failed to read from PMT Control firmware, " "trying to reconnect.") if self._recovering: raise else: self._tryRecover() # don't send command again raise IOError("Failed to read from PMT Control firmware, " "restarted serial connection.") resp = b"" while resp[-len(EOL):] != EOL: try: char = self._serial.read() # TODO: what kind of exception is raised? Needs to be more specific. except: logging.warning("Failed to read from PMT Control firmware, " "trying to reconnect.") if self._recovering: raise else: self._tryRecover() # don't send command again raise IOError("Failed to read from PMT Control firmware, " "restarted serial connection.") if not char: raise IOError("Timeout after receiving %s" % to_str_escape(resp)) else: resp += char logging.debug("Received response %s", to_str_escape(resp)) # Check response (command should be echoed back) if not resp.startswith(cmd[:-len(EOL)-1]): raise IOError("Response starts with %s != %s" % (to_str_escape(resp[:len(cmd)]), cmd)) if b"_??_" in resp: raise ValueError("Received response %s, command %s not understood." % (to_str_escape(resp), cmd)) if b"!" in resp: raise PMDError(0, to_str_escape(resp)) # Format: # * for query with response: <cmd>:<ret><EOL> (will return <ret>) # * for set command without response: <cmd><EOL> (will return "") return resp[len(cmd) + 1 - len(EOL):-len(EOL)].decode("latin1")
def _SendCmd(self, cmd): """ Send query/order to device cmd: valid query command for Remcon SEM returns str if successful, otherwise raises error """ cmd = cmd + self.eol with self._ser_access: logging.debug("Sending command %s", to_str_escape(cmd)) self._serial.write(cmd) # Acknowledge ack = self._serial.read() # valid/invalid if ack not in (RS_VALID, RS_INVALID): raise IOError( "Acknowledge sign is expected, received '%s' instead." % ack) ans = ack # EOL while ans[-len(self.eol):] != self.eol: char = self._serial.read() if not char: raise IOError("Timeout after receiving %s" % to_str_escape(ans)) else: ans += char logging.debug("Received answer %s", to_str_escape(ans)) # Status stat = self._serial.read() # Success/fail ans = stat # Value while ans[-len(self.eol):] != self.eol: char = self._serial.read() if not char: raise IOError("Timeout after receiving %s" % to_str_escape(ans)) else: ans += char logging.debug("Received answer %s", to_str_escape(ans)) value = ans[1:-len(self.eol)] if stat == RS_SUCCESS: return value elif stat == RS_FAIL: raise RemconError( int(value), "Error %s after receiving command %s." % (int(value), cmd)) else: raise IOError( "Status sign is expected, received '%s' instead." % stat)
def sendQueryCommand(self, cmd): """ Sends one command, and expect a reply cmd (str): command to send, including the ? returns: ans (str): response of the driver raises: IOError: if problem with sending/receiving data over the connection """ if not self._is_connected: raise IOError("Device %s not connected." % (self._host, )) msg = ("%s\n" % cmd).encode('ascii') logging.debug("Sending command %s", to_str_escape(msg)) with self._net_access: self.socket.sendall(msg) # read the answer end_time = time.time() + 0.5 ans = b"" while True: try: data = self.socket.recv(4096) except socket.timeout: raise IOError("Controller %s timed out after %s" % (self._host, to_str_escape(msg))) if not data: logging.debug("Received empty message") ans += data # does it look like we received a full answer? if b"\n" in ans: break if time.time() > end_time: raise IOError("Controller %s timed out after %s" % (self._host, to_str_escape(msg))) time.sleep(0.01) logging.debug("Received: %s", to_str_escape(ans)) ans, left = ans.split(b"\n", 1) # remove the end of line characters if left: logging.error("Received too much data, will discard the end: %s", to_str_escape(left)) ans = ans.decode('latin1') return ans
def _ReadMessage(self, timeout=None): """ Reads the next message timeout (0 < float): maximum time to wait for the message return: mid (int): message ID data (bytes): bytes 3&4 or the data of the message raise: IOError: if failed to send or receive message """ old_timeout = self._serial.timeout if timeout is not None: # Should be only for the first byte, but doing it for the first 6 # should rarely matter self._serial.timeout = timeout try: # read the first (required) 6 bytes msg = b"" for i in range(6): char = self._serial.read() # empty if timeout if not char: raise IOError( "Controller timed out, after receiving '%s'" % to_str_escape(msg)) msg += char finally: self._serial.timeout = old_timeout mid = struct.unpack("<H", msg[0:2])[0] if not (ord(msg[4:5]) & 0x80): # short message logging.debug("Received: '%s'", ", ".join("%02X" % c for c in bytearray(msg))) return mid, msg[2:4] # long message length = struct.unpack("<H", msg[2:4])[0] for i in range(length): char = self._serial.read() # empty if timeout if not char: raise IOError("Controller timed out, after receiving '%s'" % to_str_escape(msg)) msg += char logging.debug("Received: '%s'", ", ".join("%02X" % c for c in bytearray(msg))) return mid, msg[6:]
def GetSpecInfo(self): """ Return: wavelength (float): in meters power (float): theoretical maximum power (W) subdev (set of int): subdevices available """ ans = self._getValue("GSI") # Expects something like: # GSI [m63] (optional) int (wl in nm) § int (power in mW) try: m = re.match(r"(\[m(?P<mdev>\d+)])?(?P<wl>\d+)\xa7(?P<power>\d+)", ans) mdev = m.group("mdev") if mdev is None: mdev = 0 # None if no mdev bitmask else: mdev = int(mdev) wl = int(m.group("wl")) * 1e-9 # m power = int(m.group("power")) * 1e-3 # W except Exception: raise ValueError("Failed to decode spec info answer '%s'" % to_str_escape(ans)) # Convert the bitmask into a set of int subdev = set() n = 1 while mdev: if mdev & 0x1: subdev.add(n) n += 1 mdev >>= 1 return wl, power, subdev
def readMessage(self): """ Reads one message from the device (== any character until \r) return str: the message (raw, without the ending \r) raise: IOError in case of timeout """ line = b"" char = self._serial.read() # empty if timeout while char and char != b"\r": # FIXME: it seems that flushing the input doesn't work. It's # still possible to receives 0's at the beginning. # This is a kludge to workaround that if not line and char == b"\x00": logging.debug("Discarding null byte") char = b"" # normal char line += char char = self._serial.read() logging.debug("Received: '%s'", to_str_escape(line)) # Check it's a valid answer if not char: # should always finish by a "\r" raise IOError("Controller timeout.") return line.decode('latin1')
def _listen(self): ''' This method runs in a separate thread and listens for messages sent to the device via IP sockets ''' # Listen for incoming connections self.socket.listen(1) while not self._shutdown_flag.is_set(): # Wait for a connection logging.debug('%s: Waiting for a connection', self.name) connection, client_address = self.socket.accept() # this function blocks until a connection is received. try: logging.debug('%s: Connection from : %s', self.name, client_address) # Receive the data in small chunks and retransmit it while True: data = connection.recv(4096) # read from the socket if data: data = data.strip() # determine a command for line in data.splitlines(): logging.debug('%s: Received: %s' % (self.name, to_str_escape(line))) self._decodeMessage(line) time.sleep(0.105) # wait a little before responding self._sendBuffer(connection) else: # no more data to receive break finally: # Clean up the connection connection.close()
def _sendOrder(self, cmd): """ cmd (str): command to be sent to device (without the CR) """ cmd = (cmd + "\r").encode('ascii') with self._ser_access: logging.debug("Sending command %s", to_str_escape(cmd)) self._serial.write(cmd)
def _sendOrder(self, cmd): """ cmd (byte str): command to be sent to device (without the CR) """ cmd = cmd + b"\r" with self._ser_access: logging.debug("Sending command %s", to_str_escape(cmd)) self._serial.write(cmd)
def _sendQuery(self, com): """ Send a command which expects an answer com (byte string): command to send (not including the ? and the \r) return (byte string): the answer without newline and suffix ("> ") raises IOError: if there is a timeout TLFWError: if the hardware reports an error """ # TODO: handle IOError and automatically try to reconnect (cf LLE) assert isinstance(com, bytes), 'com argument needs to be a byte string' assert (len(com) <= 50) # commands cannot be long full_com = com + b"\r" with self._ser_access: logging.debug("Sending: '%s'", to_str_escape(full_com)) self._serial.write(full_com) # ensure everything is received, before expecting an answer self._serial.flush() # Read until end of answer line = b"" while True: char = self._serial.read() # empty if timeout if not char: # should always finish by a "> " raise IOError("Controller timeout, after receiving '%s'" % to_str_escape(line)) # normal char line += char if line[-2:] == b"> ": break logging.debug("Received: '%s'", to_str_escape(line)) # remove echo + suffix + new line line = line[len(full_com):-2].rstrip(b"\r") # if it's an error message => raise an error m = re.match(self.re_err, line) if m: err = m.group(1) raise TLFWError("Device rejected command '%s': %s" % (com, err)) return line
def _processCommand(self, com): """ process the command, and put the result in the output buffer com (str): command """ logging.debug("Simulator received command %s", to_str_escape(com)) out = None try: if com == b"*idn?": out = b"THORLABS FW102C/FW212C Fake Filter Wheel version 1.01" elif com.endswith(b"?"): name = com[:-1] val = self._state[name] out = b"%d" % val elif com.startswith(b"pos="): val = int(com[4:]) if not 1 <= val <= self._state[b"pcount"]: raise ValueError("%d" % val) # simulate a move curpos = self._state[b"pos"] p1, p2 = sorted([val, curpos]) dist = min(p2 - p1, (6 + p1) - p2) if self._state[b"speed"] == 0: dur = 2 else: dur = 1 time.sleep(dist * dur) self._state[b"pos"] = val # no output else: # TODO: set of speed, trig, sensors, logging.debug("Command '%s' unknown", to_str_escape(com)) raise KeyError("%s" % to_str_escape(com)) except ValueError: out = b"Command error CMD_ARG_INVALID\n" except KeyError: out = b"Command error CMD_NOT_DEFINED\n" # add the response end if out is None: out = b"" else: out += b"\r" out += b"> " self._output_buf += out
def _sendGetCommand(self, com, prefix="", suffix="\r\n\x03"): # Should normally never be called assert (len(com) <= 10) assert (len(prefix) <= 2) com = com.encode('latin1') logging.debug("Sending: %s", to_str_escape(com)) self.serial.write(com) return ""
def _parseMessage(self, msg): """ msg (str): the message to parse (without the \r) return None: self._output_buf is updated if necessary """ logging.debug("SIM: parsing %s", to_str_escape(msg)) msg = msg.decode( "latin1").strip() # remove leading and trailing whitespace msg = "".join(msg.split()) # remove all space characters if msg == "*ESR?": # error status register self._sendAnswer(b"%d" % (self._status_byte, )) elif msg == "*CLS": self._status_byte = POWER_ON elif msg == "*IDN?": self._sendAnswer(b"LSCI,MODEL335,fake,0.0") elif re.match('LOCK', msg): pass # Query setpoint elif re.match('SETP\?', msg): self._sendAnswer(b"+%.3f" % (self._setpoint, )) # set setpoint elif re.match("SETP", msg): vals = msg[4:].split(',') self._setpoint = float(vals[1]) # Query heating range elif re.match('RANGE\?', msg): self._sendAnswer(b"%d" % (self._heating, )) # set heating range elif re.match("RANGE", msg): vals = msg[5:].split(',') self._heating = int(vals[1]) # Query temperature elif re.match('KRDG\?', msg): # send temperature with some noise if os.path.exists( os.path.join(model.BASE_DIRECTORY, "temp_increase.txt")): logging.info( "Simulator set to increase temperature by 1 deg each reading" ) self._temperature += 1 self._sendAnswer(b"+%.3f" % (self._temperature)) else: self._sendAnswer( b"+%.3f" % (self._temperature + random.uniform(-0.1, 0.1), )) if self._heating: if self._temperature < self._setpoint: # heating is enabled self._temperature += 0.05 * self._heating # simulate heating else: self._temperature -= 0.1 else: # no heating so no temperature control # maintain stable temperature if self._temperature > STABLE_TEMPERATURE: self._temperature -= 0.1 # cool off with no heating else: self._status_byte |= COMMAND_ERROR
def _sendBuffer(self, connection): ''' Transmit the contents of the output buffer over the connection connection: an active accepted socket connection ''' if self._output_buffer: # check if there is data in the buffer connection.sendall(self._output_buffer) logging.debug('%s: Sending transmission: %s', self.name, to_str_escape(self._output_buffer)) self._output_buffer = b'' # clear the buffer
def _sendGetCommand(self, com, prefix="", suffix="\r\n\x03"): """ Send a command and return its report com (string): the command to send prefix (string): the prefix to the report, it will be removed from the return value suffix (string): the suffix of the report. Read will continue until it is found or there is a timeout. It is removed from the return value. return (string): the report without prefix nor newline """ assert (len(com) <= 10) assert (len(prefix) <= 2) com = com.encode('latin1') logging.debug("Sending: %s", to_str_escape(com)) self.serial.write(com) char = self.serial.read() # empty if timeout report = char while char and not report.endswith(suffix): char = self.serial.read() report += char if not char: if not self._try_recover: raise IOError("PI controller %d timeout." % self.address) success = self.recoverTimeout() if success: logging.warning("PI controller %d timeout, but recovered.", self.address) # TODO try to send again the command else: raise IOError("PI controller %d timeout, not recovered." % self.address) logging.debug("Receive: %s", to_str_escape(report)) if not report.startswith(prefix): raise IOError("Report prefix unexpected after '%s': '%s'." % (com, report)) report = report.decode( 'latin1') if sys.version_info[0] >= 3 else report return report.lstrip(prefix).rstrip(suffix)
def recv(self, size=1): if not self._output_buf: # simulate timeout time.sleep(self.timeout) raise socket.timeout("No data after %g s" % (self.timeout,)) ret = self._output_buf[:size] self._output_buf = self._output_buf[len(ret):] logging.debug("SIM: Sending %s", to_str_escape(ret)) return ret
def _sendSetCommand(self, com): """ Send a command which does not expect any report back com (string): command to send (including the \r if necessary) """ for sc in com.split(","): assert (len(sc) < 10) com = com.encode('latin1') logging.debug("Sending: %s", to_str_escape(com)) self.serial.write(com)
def _flushInput(self): """ Ensure there is no more data queued to be read on the bus (=serial port) """ with self._ser_access: self._serial.flush() self._serial.flushInput() # Shouldn't be necessary, but just in case skipped = self._serial.read(1000) # More than 1000 chars => give up logging.debug("Skipping input %s", to_str_escape(skipped))
def flushInput(self): """ Ensure there is no more data queued to be read on the bus (=serial port) """ self._serial.flush() self._serial.flushInput() while True: data = self._serial.read(100) if len(data) < 100: break logging.debug("Flushing data %s", to_str_escape(data))
def IsMotionDone(self, axis): """ Check whether the axis is in motion axis (1<=int<=4): axis number return (bool): False if in motion, True if motion is finished """ resp = self._sendQueryCommand(b"MD", axis=axis) if resp == b"0": # motion in progress return False elif resp == b"1": # no motion return True else: raise IOError("Failed to decode answer about motion '%s'" % to_str_escape(resp))
def _sendQuery(self, cmd): """ cmd (byte str): command to be sent to device (without the CR, but with the ?) returns (str): answer received from the device (without \n or \r) raise: IOError if no answer is returned in time """ cmd = cmd + b"\r" with self._ser_access: logging.debug("Sending command %s", to_str_escape(cmd)) self._serial.write(cmd) self._serial.timeout = 1 ans = b'' while ans[-1:] != b'\r': char = self._serial.read() if not char: raise IOError("Timeout after receiving %s" % to_str_escape(ans)) ans += char logging.debug("Received answer %s", to_str_escape(ans)) return ans.strip().decode("latin1")