class SerialSensorReader(SensorReader): def __init__(self,commConfig,sensorName,rowType=(),rateSec=60,db=None,log=None): SensorReader.__init__(self,commConfig,sensorName,rowType,rateSec,db,log) self.eol = "\n" self.delimiterPattern = "\\S+" self.delimiter = " " def initSensor(self): from serial import Serial self.serialP = Serial(**self.commConfig) self.resetSensor() def stopSensor(self): self.serialP.close() def getReadings(self): readings = [] ts = str((int(time())/self.rateSec)*self.rateSec) while self.serialP.inWaiting(): line = readlineR(self.serialP,self.eol) readings.append(self.delimiter.join([ts, line])) readings = [x for x in readings if x != None] return readings def toRow(self, reading): row = re.findall(self.delimiterPattern,reading.strip()) row = [x.strip() for x in row] return row def resetSensor(self): print "Reseting Sensor:" + self.sensorName return readlineR(self.serialP,self.eol)
def scan(dev="/dev/ttyS", sta=1, end=256): """ scanner serial port --> None <-- list port available """ mLis = [] # if sys.platform == 'win32': # # winzoz # por = "COM" # else: # # Unix # por = "/dev/ttyS" # #por = "/dev/ttyUSB" # #por = "/dev/ttymxc" print "try with:", dev for ind in range(sta,end): try: ser = Serial("%s%d" %(dev, ind)) por = ser.portstr.find(dev) print ser.portstr, por mLis.append( (ind, ser.portstr[sta:])) ser.close() except SerialException: pass print "found it:" return mLis
class MachineCom(): def __init__(self, port = 'AUTO', baudrate = 250000): self.serial = None if port == 'AUTO': programmer = stk500v2.Stk500v2() for port in serialList(): try: programmer.connect(port) programmer.close() self.serial = Serial(port, baudrate, timeout=5) break except ispBase.IspError: pass programmer.close() else: self.serial = Serial(port, baudrate, timeout=5) def readline(self): if self.serial == None: return '' ret = self.serial.readline() print "Recv: " + ret.rstrip() return ret def close(self): if self.serial != None: self.serial.close() self.serial = None def sendCommand(self, cmd): if self.serial == None: return self.serial.write(cmd + '\n')
class SerialPortBackEnd(BackEnd): def __init__(self, port = None, baudrate = 115200, read_timeout = 1.0, write_timeout = 0.1): """ Provides a serial-port back-end for the protocol. Timeouts are in seconds. """ BackEnd.__init__(self) self.name = "Serial" # Start the emulator as a child-process self.serial = Serial(port, baudrate = baudrate, timeout = read_timeout, writeTimeout = write_timeout) def read(self, length): return self.serial.read(length) def write(self, data): self.serial.write(data) def flush(self): self.serial.flush() def close(self): self.serial.close()
class tarjetaTOC(): ''' Clase de comunicacion con la tarjeta mediante puerto serial. ''' def __init__(self, controlador): ''' Constructor de la clase ''' self.puerto = "/dev/ttyS0" self.BAUDS = "9600" self.TIMEOUT = 1 self.serial = Serial(port=self.puerto, baudrate=self.BAUDS, bytesize=8, stopbits=1, timeout=self.TIMEOUT, dsrdtr=False, rtscts=True) self.cerrar_puerto() def abrir_puerto(self): try: self.serial.open() #time.sleep(2) except: print "Error de apertura de puerto" def cerrar_puerto(self): self.serial.close() def desconectar(self): self.cerrar_puerto() def escribir_datos(self, datos): # Escribe datos en el puerto self.serial.flushOutput() self.serial.write(datos) print "Escribio" def crear_datos_simulador(self): pass def leer_datos(self): recv = self.serial.readline() if len(recv) >= 5: self.serial.flushInput() return recv else: return (recv) def enviar_comando(self, comando): # Envia un comando y espera a que se reciba respuesta self.abrir_puerto() self.escribir_datos(comando) recv = self.leer_datos() self.cerrar_puerto() return recv
def main(): if len(sys.argv) != 2: print('requires one argument, the filter position') sys.exit(1) filterwheel = Serial('/dev/filterwheel', 115200, timeout=0.1) filterwheel.write('pos=%i\r' % int(sys.argv[1])) filterwheel.close()
class SerialNavigator(AbstractNavigator): FORWARD = "Forward"; BACKWARD ="Backward"; LEFT = "Left"; RIGHT = "Right"; __movements = { FORWARD : '1', BACKWARD: '2', LEFT : '3', RIGHT: '4' }; __serial = None; @classmethod def __init__(self, com, baudRate, dataBits): self.__serial = Serial( com-1, baudRate, dataBits); self.__serial.close(); self.__serial.open(); @classmethod def moveForward(self): self.__serial.write(self.__movements[self.FORWARD]); @classmethod def moveBackward(self): self.__serial.write(self.__movements[self.BACKWARD]); @classmethod def turnLeft(self): self.__serial.write(self.__movements[self.LEFT]); @classmethod def turnRight(self): self.__serial.write(self.__movements[self.RIGHT]);
class ESP8266(): def __init__(self, port, baud_rate): print "opening connection" self.ser = Serial(port, baud_rate, timeout=1) self.ser.close() self.ser.open() print "connection opened" def send_command(self, cmd, timeout=1000, until="-a-string-thats-never-there-"): self.ser.write(cmd + "\r\n") last_activity = millis() buf = "" while True and (millis() - last_activity) < timeout and until not in buf: bytes_to_read = self.ser.inWaiting() buf += self.ser.read(bytes_to_read) if bytes_to_read > 0: last_activity = millis() return buf def make_http_request(self, host, port, route): start = millis() self.send_command("AT+CIPSTART=0,\"TCP\",\"" + host + "\"," + str(port), 500, "OK") self.send_command("AT+CIPSTATUS", 500, "OK") msg = "GET " + route + " HTTP/1.1\r\nHost: " + host + "\r\n\r\n" self.send_command("AT+CIPSEND=0," + str(len(msg)), 500, "OK") result = self.send_command(msg, 10000, "+IPD,0,5:0") print result self.send_command("AT+CIPCLOSE=0", 500, ",CLOSED") print str(1 if "CC3000" in result else 0) + "," + str(millis() - start)
def testConnection(self): """Test connection with defined settings""" port_name = self.ui.portNameComboBox.currentText() try: baud_rate = int(self.ui.baudRateComboBox.currentText()) except ValueError: baud_rate = 9600 if not port_name or not baud_rate: QMessageBox.warning(self, 'Test Connection', 'Please specify Port Name and Baud Rate') else: connected = False try: serial = Serial(port_name, baud_rate) if serial.isOpen(): connected = True serial.close() except SerialException: pass if connected: QMessageBox.information(self, 'Test Connection', 'Connection ok!') else: QMessageBox.information(self, 'Test Connection', 'Connection failed!')
def _openPortWithBaudrate(self, port, baudrate): if baudrate != 0: return Serial(port, baudrate, timeout=2) for baudrate in baudrateList(): try: ser = Serial(port, baudrate, timeout=2) except: print "Unexpected error while connecting to serial port:" + port, sys.exc_info()[0] continue ser.setDTR(1) time.sleep(0.1) ser.setDTR(0) time.sleep(0.2) starttime = time.time() for line in ser: if "start" in line: ser.close() ser = Serial(port, baudrate, timeout=2) ser.setDTR(1) time.sleep(0.1) ser.setDTR(0) time.sleep(0.2) return ser if starttime - time.time() > 10: break ser.close() return None
class SerialCommunicator: def __init__(self, port='/dev/usb/ttyUSB0', baudrate=19200): self.connection = Serial() self.connection.port = port self.connection.baudrate = baudrate def set_port(self, port_name): self.connection.port = port_name def send_command(self, message): self.connection.open() self.connection.write(message) # Waits until the robot starts the response while self.connection.read() != SOT: time.sleep(SLEEPING_TIME) message_length = self.connection.read() remaining_chars = ord(message_length) + 1 message = self.connection.read(remaining_chars) message_type = message[0] encoded_data = message[1:-1] self.connection.close() return message_type, encoded_data
def sms(modem_device,tel,message): s=Serial(modem_device) s.write('AT+CMGF=1\r\n'.encode('ascii')) s.write('AT+CMGS="{}"\r\n'.format(tel).encode('ascii')) s.write(message.encode('ascii')) s.write(b'\x1a') s.close()
class SerialInstrument(object): def __init__(self, port, baud=19200): self.port = port self.baud = baud def read(self, num=None): if num: while self.instr.inWaiting() < num: pass return self.instr.read(num) while not self.instr.inWaiting(): pass return self.instr.read() def write(self, data): self.instr.write(data) def __enter__(self): self.instr = Serial(self.port, self.baud) self.instr.open() return self def __exit__(self, type, value, tb): self.instr.close()
def uart1(portName, q): while not exitFlag: queueLock.acquire() if not workQueue.empty(): data = q.get() ser = Serial( data, baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=None) while True: line = ser.readline(ser.inWaiting()).decode('utf-8')[:-2] if line: t = line.split(",") line2 = float(t[5]) if line2 > 0: print(portName, line2) if line == '520': subprocess.call(["xte", "key Up"]) elif line == '620': subprocess.call(["xte", "key Down"]) elif line == '110': break ser.close()
class SerialSocket(WebSocket): def __init__(self, sock, protocols=None, extensions=None, environ=None, heartbeat_freq=None): super(SerialSocket, self).__init__(sock, protocols, extensions, environ, heartbeat_freq) self.serial = Serial() def received_message(self, message): if message.data[0:len(OPEN_CONNECTION_STRING)] == OPEN_CONNECTION_STRING: port = message.data[len(OPEN_CONNECTION_STRING):] self.serial.port = port self.serial.baudrate = 115200 try: self.serial.open() except SerialException as se: self.send("Failed to connect to: " + port + "\n\r(" + se.message + ")\n\r") return if self.serial.isOpen(): self.send("Connection established with: " + port + "\n\r") thread.start_new_thread(serial_poll, (self.serial, self)) else: self.send("Failed to connect to: " + port + "\n\r") else: if self.serial.isOpen(): self.send(message.data) self.serial.write(message.data) def close(self, code=1000, reason=''): # close serial connection print 'closing' self.serial.close() super(SerialSocket, self).close(code, reason)
def main(argv): loglevels = [logging.CRITICAL, logging.ERROR, logging.WARN, logging.INFO, logging.DEBUG] parser = argparse.ArgumentParser(argv) parser.add_argument('-v', '--verbosity', type=int, default=4, help='set logging verbosity, 1=CRITICAL, 5=DEBUG') parser.add_argument('tty', help='Serial port device file name') parser.add_argument('-b', '--baudrate', default=115200, type=int, help='Serial port baudrate') args = parser.parse_args() # logging setup logging.basicConfig(level=loglevels[args.verbosity-1]) # open serial port try: logging.debug("Open serial port %s, baud=%d", args.tty, args.baudrate) port = Serial(args.tty, args.baudrate, dsrdtr=0, rtscts=0, timeout=0.3) except IOError: logging.critical("error opening serial port", file=sys.stderr) sys.exit(2) try: app = rssi_plot() app.plot_rssi(port) except KeyboardInterrupt: port.close() sys.exit(2)
class AcquisitionThread(Thread): BAUDRATE = 57600 START_CHARACTER = b's' PACKET_SIZE = 69 def __init__(self, acquisition_queue): super(AcquisitionThread, self).__init__() self.acquisition_queue = acquisition_queue self.exit_flag = False def run(self): port_nb = serial_port()[0] self.device = Serial(port_nb, baudrate=self.BAUDRATE, timeout=0.2) while not self.exit_flag: c = self.device.read(1) if c == self.START_CHARACTER: while self.device.inWaiting() < self.PACKET_SIZE: pass data = self.device.read(self.PACKET_SIZE) rocket_data = RocketData(data) # checksum_validated = rocket_data.validateCheckSum() checksum_validated = True if checksum_validated: self.acquisition_queue.put(rocket_data) self.device.close() def stop(self): self.exit_flag = True
class GPS: def __init__(self, port_name, baud_rate, logger): self.logger = logger self.logger.write("Starting GPS Communications") self.serial = Serial(port_name, baud_rate) self.lat = 0 self.long = 0 def get_GPS(self): while (self.lat == 0.0): self.logger.write("Waiting for GPS") time.sleep(1) return (self.lat, self.long) def read_data(self): if self.serial.inWaiting() > 0: data = self.serial.readline().rstrip() if data[0:6] == "$GPRMC": fields = data.split(',') if fields[2] == 'A': self.lat = int(fields[3][0:2]) + (float(fields[3][2:]) / 60.0) #ASSUMES TWO DIGIT LATITUDE self.long = int(fields[5][0:3]) + (float(fields[5][3:]) / 60.0) #ASSUMES THREE DIGIT LONGITUDE else: self.lat = 0.0 self.long = 0.0 def close(self): self.serial.close()
class SerialPortDataSource: def __init__(self, params): self.port = Serial() self.port.port = params['port'] self.port.baudrate = params['baudrate'] def open(self): try: self.port.open() return True except SerialException as e: return str(e) def close(self): self.port.close() def execute(self, command): self.port.write(command + '\r\n') res = "" c = '' while (c != '>'): res += c c = self.port.read(1) return res
def run(command): global protocolSettings global databaseSettings global usefix if command == "list": listPorts() elif command == "read": debug("Reading sequence") process(read(usefix)) elif command == "defaults": listDefaults() elif command == "jobread": debug("Starting endless read") global serialSettings global job job = True serial = None try: serial = Serial(port=serialSettings["port"], baudrate=serialSettings["baudrate"]) debug("flushing") serial.flushInput() serial.flushOutput() while True: debug("Reading sequence (job)") process(read(usefix, serial)) sleep(float(databaseSettings["wait"])) finally: if serial is not None and serial.isOpen(): serial.close() else: log("Unknown command: " + command)
def handle(self, *args, **options): if len(args) < 2: print "No enough arguments" return n = 0 MAX = 5 while(n < MAX): try: ser = Serial(args[0], args[1], timeout=5) ser.write('t') temp = float(ser.readline()[:-1]) / 10 ser.write('c') state = ser.read() TempHistory.objects.create(datetime=datetime.utcnow(), temp=temp, state=state) settings = TempSettings.load() ser.write('sl{:d} '.format(int(settings.low_boundary * 10))) ser.write('sh{:d} '.format(int(settings.high_boundary * 10))) except TimeoutException: ser.close() n += 1 else: break if n == MAX: sys.stderr.write('Error syncing with thermostat')
def available_ports(): usb_serial_ports = filter( (lambda x: x.startswith('ttyUSB')), os.listdir('/dev')) ports = [] for p in usb_serial_ports: ports.append(serial_for_url('/dev/'+p, do_not_open=True)) """ also check for old school serial ports, my hope is that this will enable both USB serial adapters and standard serial ports Scans COM1 through COM255 for available serial ports returns a list of available ports """ for i in range(256): try: p = Serial(i) p.close() ports.append(p) except SerialException: pass return ports
class SerialServer(Thread): def __init__(self, port="/dev/ttyACM0", baudrate=9600, timetoread=2): Thread.__init__(self) self.server = Serial(port=port, baudrate=baudrate) self.dataInQueeud = False self.running = True self.timetoread = timetoread #periodicite de lecture du port self.datas = "" #les donnees lus self.dataToSend = "" #les donneees à envoyer def run(self): """lecture continue du port série. Lorsqu'il y'a quelque chose à lire, il lie puis envoie les donnees""" while self.running == True: while self.server.inWaiting() > 0: self.datas += self.server.readline() sleep(self.timetoread) #pause #envoie s'il y'a quelques a envoyer if self.dataToSend != "": self.server.write(self.dataToSend) self.server.flush() def recvdatas(self): res = self.datas self.datas = "" return res def senddatas(self, data = ""): self.dataToSend = data def toStop(self): self.server.close() self.running = False
def buildDataSet(mySerialPort, numOfPoints, workingDir): # Ask user for # of samples and prefix of dir (numOfSamples, prefix) = askForPnN() # Create the dir to store the results createResultsDir(prefix, workingDir) # Now create nSample files with the results for i in range(0, numOfSamples, 1): print "\nSpeak into the mic now\n" # Open the serial port port = Serial(mySerialPort, 230400, timeout=2.0) port.close() port.open() # Read results from serial line rawData = getSerialData(numOfPoints, port) # Close the serial port port.close() # Normalize the data and convert to FFT dataNorm = normalize(rawData) saveAsWav(dataNorm, prefix, workingDir, i) dataFFT = fftMyWav(dataNorm, numOfPoints) saveAsTxt(dataFFT, prefix, workingDir, i) print "\nGot it. " + str(numOfSamples - i - 1) + " samples left to go." return numOfSamples
class Joystick(): def __init__(self, port, baud=57600): self.port = port self.baud = baud self.ser = None def open(self): try: self.ser = Serial(self.port, self.baud) except: print(" Open serial port %s failled with baudrate %d"%(self.port, self.baud)) def __enter__(self): self.open() return self def __exit__(self, type, value, traceback): self.ser.close() return True def __iter__(self): print("iter") return self def __next__(self): s = self.ser.readline() return s
class PlotUpdater(threading.Thread): """This class sets the fraction of the progressbar""" #Thread event, stops the thread if it is set. stopthread = threading.Event() def __init__(self, gui): threading.Thread.__init__(self) #Call constructor of parent self.gui = gui self.frac = 0 self.ser = Serial("/dev/ttyACM0",115200) #self.ser.timeout = 1 self.i = 0 def run(self): """Run method, this is the code that runs while thread is alive.""" #self.ser.readline() #self.ser.readline() #While the stopthread event isn't setted, the thread keeps going on while not self.stopthread.isSet() : # Acquiring the gtk global mutex #gtk.threads_enter() #Setting the fraction self.frac += 0.01 self.i += 1 #self.gui.line.set_data((t, np.sin(3*np.pi*(t+self.frac)))) rslt = '' self.ser.write("d\n") s = self.ser.readline().strip() while s != '' : rslt += s+'\n' s = self.ser.readline().strip() #print repr(s) try: n = np.loadtxt(StringIO(rslt)) angles = n[:,1] intensities = n[:,2] #(self.gui.s0p, self.gui.s1, self.gui.s2, self.gui.s3, self.gui.dop)=get_stokes(angles,intensities) self.gui.line.set_data((angles, intensities)) except ValueError: print "Value Error" # Releasing the gtk global mutex #gtk.threads_leave() #Delaying 100ms until the next iteration self.ser.close() def stop(self): """Stop method, sets the event to terminate the thread's main loop""" self.stopthread.set()
def listenPort(): ser = Serial(port=config.serialPort, baudrate=config.serialBaudrate, timeout=1) print("connected to: " + ser.portstr) while True: line = ser.readline() if line: parse(line) ser.close()
def main(): port = Serial(options.port, options.baudrate, timeout=options.timeout) mk2 = MK2(port).start() #mk2.set_state(3) print mk2.get_state() port.close()
def __init__(self): try: self._toQuit = False rospy.init_node('RiCTraffic') params = RiCParam() ser = Serial('/dev/%s' % params.getConPort()) ser.flushInput() ser.flushOutput() incomingHandler = IncomingHandler() input = ser output = SerialWriteHandler(ser, incomingHandler, input) data = [] toPrint = '' input.baudrate = 9600 incomingLength = 0 headerId = 0 devBuilder = DeviceBuilder(params, output, input, incomingHandler) gotHeaderStart = False gotHeaderDebug = False msgHandler = None server = None rospy.loginfo("Current version: %.2f" % VERSION) is_wd_active = False try: self.waitForConnection(output) if self.checkVer(input): input.timeout = None rospy.loginfo("Configuring devices...") devBuilder.createServos() devBuilder.createCLMotors() devBuilder.createDiff() devBuilder.createURF() devBuilder.createSwitchs() devBuilder.createPPM() devBuilder.createIMU() devBuilder.createRelays() devBuilder.createGPS() devBuilder.createOpenLoopMotors() devBuilder.createBattery() devBuilder.createOpenDiff() devBuilder.createDiffFour() devBuilder.createEmergencySwitch() devs = devBuilder.getDevs() devBuilder.sendFinishBuilding() input.timeout = None rospy.loginfo("Done, RiC Board is ready.") msgHandler = IncomingMsgHandler(devs, output) server = Server(devs, params) Thread(target=self.checkForSubscribers, args=(devs, )).start() Thread(target=msgHandler.run, args=()).start() wd_keep_alive = int(round(time.time() * 1000)) while not rospy.is_shutdown() and not is_wd_active: if gotHeaderStart: if len(data) < 1: data.append(input.read()) incomingLength, headerId = incomingHandler.getIncomingHeaderSizeAndId( data) elif incomingLength >= 1: for i in range(1, incomingLength): data.append(input.read()) msg = self.genData(data, headerId) if msg is not None and msg.getId() != CON_REQ: msgHandler.addMsg(msg) elif msg.getId( ) == CON_REQ and not msg.toConnect(): subprocess.Popen( shlex.split("pkill -f RiCTraffic")) rospy.logerr( "Emergency button is activated.") break data = [] gotHeaderStart = False else: data = [] gotHeaderStart = False elif gotHeaderDebug: size = ord(input.read()) for i in xrange(size): toPrint += input.read() code = ord(input.read()) if code == INFO: rospy.loginfo(toPrint) elif code == ERROR: rospy.logerr(toPrint) elif code == WARRNING: rospy.logwarn(toPrint) toPrint = '' gotHeaderDebug = False elif input.inWaiting() > 0: checkHead = ord(input.read()) if checkHead == HEADER_START: gotHeaderStart = True elif checkHead == HEADER_DEBUG: gotHeaderDebug = True elif checkHead == KEEP_ALIVE_HEADER: wd_keep_alive = int(round(time.time() * 1000)) is_wd_active = (int(round(time.time() * 1000)) - wd_keep_alive) > WD_TIMEOUT else: raise VersionError(NEED_TO_UPDATE) if is_wd_active: rospy.logerr( "RiCBoard isn't responding.\nThe Following things can make this happen:" "\n1) If accidentally the manual driving is turn on, If so turn it off the relaunch the RiCBoard" "\n2) If accidentally the RiCTakeovver gui is turn on,If so turn it off the relaunch the RiCBoard" "\n3) The RiCBoard is stuck, If so please power off the robot and start it again. And contact RobotICan support by this email: [email protected]" ) except KeyboardInterrupt: pass except VersionError: rospy.logerr( "Can't load RiCBoard because the version don't mach please update the firmware." ) finally: if not is_wd_active: con = ConnectionResponse(False) output.writeAndWaitForAck(con.dataTosend(), RES_ID) ser.close() if msgHandler != None: msgHandler.close() self._toQuit = True except SerialException: rospy.logerr( "Can't find RiCBoard, please check if its connected to the computer." )
class Uart(threading.Thread, Device): def __init__(self, port, baudrate=115200, device_name=None, rtscts=True): self.events_queue = collections.deque(maxlen=EVT_Q_BUF) threading.Thread.__init__(self) if not device_name: device_name = port self.device_name = device_name self.logger = logging.getLogger(self.device_name) Device.__init__(self, self.device_name) self._write_lock = threading.Lock() self.logger.debug("log Opening port %s, baudrate %s, rtscts %s", port, baudrate, rtscts) # We change the baudrate around to reset the UART state. # This is a trick to force detection of flow control settings etc. _trick_baudrate = 9600 if baudrate == _trick_baudrate: _trick_baudrate = 115200 self.serial = Serial(port=port, baudrate=_trick_baudrate, rtscts=rtscts, timeout=0.1) self.serial.baudrate = baudrate self.keep_running = True self.start() def __del__(self): self.stop() def stop(self): self.keep_running = False self.kill_writer() def get_packet_from_uart(self): tmp = bytearray([]) while self.keep_running: tmp += bytearray(self.serial.read()) tmp_len = len(tmp) if tmp_len > 0: pkt_len = tmp[0] if tmp_len > pkt_len: data = tmp[:pkt_len + 1] yield data tmp = tmp[pkt_len + 1:] def run(self): for pkt in self.get_packet_from_uart(): self.logger.debug("RX: %s", pkt.hex()) try: if len(pkt) < 2: self.logger.error('Invalid packet: %r', pkt) continue parsed_packet = event_deserialize(pkt) if not parsed_packet: self.logger.error("Unable to deserialize %s", pkt.hex()) except Exception: self.logger.error('Exception with packet %s', pkt.hex()) self.logger.error('traceback: %s', traceback.format_exc()) parsed_packet = None if parsed_packet: self.events_queue.append(parsed_packet) self.logger.debug('parsed_packet %r', parsed_packet) self.process_packet(parsed_packet) self.serial.close() self.logger.debug("exited read event") def write_data(self, cmd): with self._write_lock: if self.keep_running: data = cmd.serialize() self.logger.debug("TX: %s", bytearray(data).hex()) self.serial.write(bytearray(data)) self.process_command(cmd) def __repr__(self): return '%s(port="%s", baudrate=%s, device_name="%s")' % ( self.__class__.__name__, self.serial.port, self.serial.baudrate, self.device_name)
class Manipulator(): def __init__(self): #print(time, self, file=stderr) self.r2 = photo() im2 = Image.open('test.png') (self.x, self.y) = im2.size def search_object(self, object_serch): #найти объект на снимке self.x_degree = 0 self.y_degree = 0 self.object_file = object_serch for Y1 in range(0, self.y, Step): print('конец строки', file=stderr) for X1 in range(0, self.x, Step): for path, dirs, files in os.walk(self.object_file): for f in files: i = '%s/%s' % (path, f) self.r1 = cv.imread(i) im1 = Image.open("%s/%s" % (path, f)) (x1, y1) = im1.size self.r2_1 = self.r2[Y1:Y1 + y1, X1:X1 + x1] self.r2_2 = cv.resize(self.r2_1, (Compress, Compress)) self.r1 = cv.resize(self.r1, (Compress, Compress)) compare(self.r1, self.r2_2) print(i, ' ', compare(self.r1, self.r2_2), file=stderr) if compare(self.r1, self.r2_2) <= Coefficient: print('обьект найден :)', file=stderr) #////////////////////////////////////////////////////////////////////////////// #расчет расположения обьекта на фото self.X_pix = X1 + (y1 / 2) self.Y_pix = Y1 + (x1 / 2) print('X', self.X_pix, "/", 'Y', self.Y_pix, file=stderr) #////////////////////////////////////////////////////////////////////////////// #расчет угла поворота #self.a1=(self.Y_pix) #self.b1=(self.X_pix) #self.a2=(self.x/2)-self.a1 #self.b2=(self.y-self.b1) #self.tg_A=(self.b2/self.a2) #print( 'tg',self.tg_A) self.x_degree = int( (0 + self.X_pix) / 2 / (self.x / 360)) if self.x_degree > 180: self.x_degree = 180 self.y_degree = int( (0 + self.Y_pix) / 2 / (self.y / 360)) break #////////////////////////////////////////////////////////////////////////////// if compare(self.r1, self.r2_2) <= Coefficient: break if compare(self.r1, self.r2_2) <= Coefficient: break if compare(self.r1, self.r2_2) >= Coefficient: print('обьект не найден :(', file=stderr) return self.x_degree, self.y_degree def show_object(self): #вывести найденное изображение на экран try: if compare(self.r1, self.r2_2) <= Coefficient: cv.imshow('обьект', self.r2_1) cv.waitKey(0) cv.destroyAllWindows() elif compare(self.r1, self.r2_2) >= Coefficient: print('не удалось показать изображение :(', file=stderr) except AttributeError: pass def show_diagram_photo(self): #вывести изображение в plt try: print('разрешение -', '(', self.x, '/', self.y, ')') plt.imshow(cv.cvtColor(self.r2, cv.COLOR_BGR2RGB)) except AttributeError: print('не удалось показать диаграмму :(', file=stderr) def connect(self, com='/dev/ttyACM0', serial=9600): #подключение к ардуино self.com = com # номер ком порта self.serial = serial # частота try: self.arduino = Serial(self.com, self.serial, timeout=2) sleep(1) print("Connected to arduino! :)", file=stderr) except SerialException: print("Error connecting to arduino!!! :(", file=stderr) def disconnect(self): #отключение от ардуино self.arduino.close() print('Disconnected arduino!', file=stderr) def moveX(self, x): #отправка угла поворота на ардуино по оси X try: print('градусы X =', x) self.arduino.write(bytes([9, x])) sleep(1) print('движение по X ', file=stderr) except AttributeError: print('Arduino:X не отправлен', file=stderr) def moveY(self, y): #отправка угла поворота на ардуино по оси Y try: print('градусы Y =', y, file=stderr) sleep(1) self.arduino.write(bytes([9, y])) sleep(1) print('движение по Y', file=stderr) except AttributeError: print('Arduino:Y не отправлен', file=stderr)
class Stk500v2(ispBase.IspBase): def __init__(self): self.serial = None self.seq = 1 self.last_addr = -1 self.progress_callback = None def connect(self, port="COM22", speed=115200): if self.serial is not None: self.close() try: self.serial = Serial(str(port), speed, timeout=1, writeTimeout=10000) except SerialException: raise ispBase.IspError("Failed to open serial port") except: raise ispBase.IspError( "Unexpected error while connecting to serial port:" + port + ":" + str(sys.exc_info()[0])) self.seq = 1 #Reset the controller for n in range(0, 2): self.serial.setDTR(True) time.sleep(0.1) self.serial.setDTR(False) time.sleep(0.1) time.sleep(0.2) self.serial.flushInput() self.serial.flushOutput() try: if self.sendMessage([ 0x10, 0xc8, 0x64, 0x19, 0x20, 0x00, 0x53, 0x03, 0xac, 0x53, 0x00, 0x00 ]) != [0x10, 0x00]: raise ispBase.IspError("Failed to enter programming mode") self.sendMessage([0x06, 0x80, 0x00, 0x00, 0x00]) if self.sendMessage([0xEE])[1] == 0x00: self._has_checksum = True else: self._has_checksum = False except ispBase.IspError: self.close() raise self.serial.timeout = 5 def close(self): if self.serial is not None: self.serial.close() self.serial = None #Leave ISP does not reset the serial port, only resets the device, and returns the serial port after disconnecting it from the programming interface. # This allows you to use the serial port without opening it again. def leaveISP(self): if self.serial is not None: if self.sendMessage([0x11]) != [0x11, 0x00]: raise ispBase.IspError("Failed to leave programming mode") ret = self.serial self.serial = None return ret return None def isConnected(self): return self.serial is not None def hasChecksumFunction(self): return self._has_checksum def sendISP(self, data): recv = self.sendMessage( [0x1D, 4, 4, 0, data[0], data[1], data[2], data[3]]) return recv[2:6] def writeFlash(self, flash_data): #Set load addr to 0, in case we have more then 64k flash we need to enable the address extension page_size = self.chip["pageSize"] * 2 flash_size = page_size * self.chip["pageCount"] Logger.log("d", "Writing flash") if flash_size > 0xFFFF: self.sendMessage([0x06, 0x80, 0x00, 0x00, 0x00]) else: self.sendMessage([0x06, 0x00, 0x00, 0x00, 0x00]) load_count = (len(flash_data) + page_size - 1) / page_size for i in range(0, int(load_count)): self.sendMessage([ 0x13, page_size >> 8, page_size & 0xFF, 0xc1, 0x0a, 0x40, 0x4c, 0x20, 0x00, 0x00 ] + flash_data[(i * page_size):(i * page_size + page_size)]) if self.progress_callback is not None: if self._has_checksum: self.progress_callback(i + 1, load_count) else: self.progress_callback(i + 1, load_count * 2) def verifyFlash(self, flash_data): if self._has_checksum: self.sendMessage([ 0x06, 0x00, (len(flash_data) >> 17) & 0xFF, (len(flash_data) >> 9) & 0xFF, (len(flash_data) >> 1) & 0xFF ]) res = self.sendMessage([0xEE]) checksum_recv = res[2] | (res[3] << 8) checksum = 0 for d in flash_data: checksum += d checksum &= 0xFFFF if hex(checksum) != hex(checksum_recv): raise ispBase.IspError( "Verify checksum mismatch: 0x%x != 0x%x" % (checksum & 0xFFFF, checksum_recv)) else: #Set load addr to 0, in case we have more then 64k flash we need to enable the address extension flash_size = self.chip["pageSize"] * 2 * self.chip["pageCount"] if flash_size > 0xFFFF: self.sendMessage([0x06, 0x80, 0x00, 0x00, 0x00]) else: self.sendMessage([0x06, 0x00, 0x00, 0x00, 0x00]) load_count = (len(flash_data) + 0xFF) / 0x100 for i in range(0, int(load_count)): recv = self.sendMessage([0x14, 0x01, 0x00, 0x20])[2:0x102] if self.progress_callback is not None: self.progress_callback(load_count + i + 1, load_count * 2) for j in range(0, 0x100): if i * 0x100 + j < len(flash_data) and flash_data[ i * 0x100 + j] != recv[j]: raise ispBase.IspError("Verify error at: 0x%x" % (i * 0x100 + j)) def sendMessage(self, data): message = struct.pack(">BBHB", 0x1B, self.seq, len(data), 0x0E) for c in data: message += struct.pack(">B", c) checksum = 0 for c in message: checksum ^= c message += struct.pack(">B", checksum) try: self.serial.write(message) self.serial.flush() except SerialTimeoutException: raise ispBase.IspError("Serial send timeout") self.seq = (self.seq + 1) & 0xFF return self.recvMessage() def recvMessage(self): state = "Start" checksum = 0 while True: s = self.serial.read() if len(s) < 1: raise ispBase.IspError("Timeout") b = struct.unpack(">B", s)[0] checksum ^= b if state == "Start": if b == 0x1B: state = "GetSeq" checksum = 0x1B elif state == "GetSeq": state = "MsgSize1" elif state == "MsgSize1": msg_size = b << 8 state = "MsgSize2" elif state == "MsgSize2": msg_size |= b state = "Token" elif state == "Token": if b != 0x0E: state = "Start" else: state = "Data" data = [] elif state == "Data": data.append(b) if len(data) == msg_size: state = "Checksum" elif state == "Checksum": if checksum != 0: state = "Start" else: return data
class printcore(): def __init__(self, port = None, baud = None, dtr=None): """Initializes a printcore instance. Pass the port and baud rate to connect immediately""" self.baud = None self.dtr = None self.port = None self.analyzer = gcoder.GCode() # Serial instance connected to the printer, should be None when # disconnected self.printer = None # clear to send, enabled after responses # FIXME: should probably be changed to a sliding window approach self.clear = 0 # The printer has responded to the initial command and is active self.online = False # is a print currently running, true if printing, false if paused self.printing = False self.mainqueue = None self.priqueue = Queue(0) self.queueindex = 0 self.lineno = 0 self.resendfrom = -1 self.paused = False self.sentlines = {} self.log = deque(maxlen = 10000) self.sent = [] self.writefailures = 0 self.tempcb = None # impl (wholeline) self.recvcb = None # impl (wholeline) self.sendcb = None # impl (wholeline) self.preprintsendcb = None # impl (wholeline) self.printsendcb = None # impl (wholeline) self.layerchangecb = None # impl (wholeline) self.errorcb = None # impl (wholeline) self.startcb = None # impl () self.endcb = None # impl () self.onlinecb = None # impl () self.loud = False # emit sent and received lines to terminal self.tcp_streaming_mode = False self.greetings = ['start', 'Grbl '] self.wait = 0 # default wait period for send(), send_now() self.read_thread = None self.stop_read_thread = False self.send_thread = None self.stop_send_thread = False self.print_thread = None if port is not None and baud is not None: self.connect(port, baud) self.xy_feedrate = None self.z_feedrate = None def logError(self, error): if self.errorcb: try: self.errorcb(error) except: logging.error(traceback.format_exc()) else: logging.error(error) @locked def disconnect(self): """Disconnects from printer and pauses the print """ if self.printer: if self.read_thread: self.stop_read_thread = True if threading.current_thread() != self.read_thread: self.read_thread.join() self.read_thread = None if self.print_thread: self.printing = False self.print_thread.join() self._stop_sender() try: self.printer.close() except socket.error: pass except OSError: pass self.printer = None self.online = False self.printing = False @locked def connect(self, port = None, baud = None, dtr=None, err_message_softness=False): """Set port and baudrate if given, then connect to printer """ if self.printer: self.disconnect() if port is not None: self.port = port if baud is not None: self.baud = baud if dtr is not None: self.dtr = dtr if self.port is not None and self.baud is not None: # Connect to socket if "port" is an IP, device if not host_regexp = re.compile("^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$|^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$") is_serial = True if ":" in port: bits = port.split(":") if len(bits) == 2: hostname = bits[0] try: port = int(bits[1]) if host_regexp.match(hostname) and 1 <= port <= 65535: is_serial = False except: pass self.writefailures = 0 if not is_serial: self.printer_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.printer_tcp.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) self.timeout = 0.25 self.printer_tcp.settimeout(1.0) try: self.printer_tcp.connect((hostname, port)) self.printer_tcp.settimeout(self.timeout) self.printer = self.printer_tcp.makefile() except socket.error as e: self.logError(_("Could not connect to %s:%s:") % (hostname, port) + "\n" + _("Socket error %s:") % e.errno + "\n" + e.strerror) self.printer = None self.printer_tcp = None return else: disable_hup(self.port) self.printer_tcp = None try: self.printer = Serial(port = self.port, baudrate = self.baud, timeout = 0.25, parity = PARITY_ODD) self.printer.close() self.printer.parity = PARITY_NONE try: # This appears not to work on many platforms, # so we're going to call it but not care if it fails self.printer.setDTR(dtr) except: #not sure whether to output an error message #self.logError(_("Could not set DTR on this platform")) pass self.printer.open() except SerialException as e: self.printer = None raise return e.errno except IOError as e: if not err_message_softness: self.logError(_("Could not connect to %s at baudrate %s:") % (self.port, self.baud) + "\n" + _("IO error: %s") % e) self.printer = None raise return self.stop_read_thread = False self.read_thread = threading.Thread(target = self._listen) self.read_thread.start() self._start_sender() def reset(self): """Reset the printer """ if self.printer and not self.printer_tcp: self.printer.setDTR(1) time.sleep(0.2) self.printer.setDTR(0) def _readline(self): try: try: line = self.printer.readline() if self.printer_tcp and not line: raise OSError(-1, "Read EOF from socket") except socket.timeout: return "" if len(line) > 1: self.log.append(line) if self.recvcb: try: self.recvcb(line) except: self.logError(traceback.format_exc()) if self.loud: logging.info("RECV: %s" % line.rstrip()) return line except SelectError as e: if 'Bad file descriptor' in e.args[1]: self.logError(_(u"Can't read from printer (disconnected?) (SelectError {0}): {1}").format(e.errno, decode_utf8(e.strerror))) return None else: self.logError(_(u"SelectError ({0}): {1}").format(e.errno, decode_utf8(e.strerror))) raise except SerialException as e: self.logError(_(u"Can't read from printer (disconnected?) (SerialException): {0}").format(decode_utf8(str(e)))) return None except socket.error as e: self.logError(_(u"Can't read from printer (disconnected?) (Socket error {0}): {1}").format(e.errno, decode_utf8(e.strerror))) return None except OSError as e: if e.errno == errno.EAGAIN: # Not a real error, no data was available return "" self.logError(_(u"Can't read from printer (disconnected?) (OS Error {0}): {1}").format(e.errno, e.strerror)) return None def _listen_can_continue(self): if self.printer_tcp: return not self.stop_read_thread and self.printer return (not self.stop_read_thread and self.printer and self.printer.isOpen()) def _listen_until_online(self): while not self.online and self._listen_can_continue(): self._send("M105") if self.writefailures >= 4: logging.error(_("Aborting connection attempt after 4 failed writes.")) return empty_lines = 0 while self._listen_can_continue(): line = self._readline() if line is None: break # connection problem # workaround cases where M105 was sent before printer Serial # was online an empty line means read timeout was reached, # meaning no data was received thus we count those empty lines, # and once we have seen 15 in a row, we just break and send a # new M105 # 15 was chosen based on the fact that it gives enough time for # Gen7 bootloader to time out, and that the non received M105 # issues should be quite rare so we can wait for a long time # before resending if not line: empty_lines += 1 if empty_lines == 15: break else: empty_lines = 0 if line.startswith(tuple(self.greetings)) \ or line.startswith('ok') or "T:" in line: self.online = True if self.onlinecb: try: self.onlinecb() except: self.logError(traceback.format_exc()) return def _listen(self): """This function acts on messages from the firmware """ self.clear = True if not self.printing: self._listen_until_online() while self._listen_can_continue(): line = self._readline() if line is None: break if line.startswith('DEBUG_'): continue if line.startswith(tuple(self.greetings)) or line.startswith('ok'): self.clear = True if line.startswith('ok') and "T:" in line and self.tempcb: # callback for temp, status, whatever try: self.tempcb(line) except: self.logError(traceback.format_exc()) elif line.startswith('Error'): self.logError(line) # Teststrings for resend parsing # Firmware exp. result # line="rs N2 Expected checksum 67" # Teacup 2 if line.lower().startswith("resend") or line.startswith("rs"): for haystack in ["N:", "N", ":"]: line = line.replace(haystack, " ") linewords = line.split() while len(linewords) != 0: try: toresend = int(linewords.pop(0)) self.resendfrom = toresend break except: pass self.clear = True self.clear = True def _start_sender(self): self.stop_send_thread = False self.send_thread = threading.Thread(target = self._sender) self.send_thread.start() def _stop_sender(self): if self.send_thread: self.stop_send_thread = True self.send_thread.join() self.send_thread = None def _sender(self): while not self.stop_send_thread: try: command = self.priqueue.get(True, 0.1) except QueueEmpty: continue while self.printer and self.printing and not self.clear: time.sleep(0.001) self._send(command) while self.printer and self.printing and not self.clear: time.sleep(0.001) def _checksum(self, command): return reduce(lambda x, y: x ^ y, map(ord, command)) def startprint(self, gcode, startindex = 0): """Start a print, gcode is an array of gcode commands. returns True on success, False if already printing. The print queue will be replaced with the contents of the data array, the next line will be set to 0 and the firmware notified. Printing will then start in a parallel thread. """ if self.printing or not self.online or not self.printer: return False self.queueindex = startindex self.mainqueue = gcode self.printing = True self.lineno = 0 self.resendfrom = -1 self._send("M110", -1, True) if not gcode or not gcode.lines: return True self.clear = False resuming = (startindex != 0) self.print_thread = threading.Thread(target = self._print, kwargs = {"resuming": resuming}) self.print_thread.start() return True def cancelprint(self): self.pause() self.paused = False self.mainqueue = None self.clear = True # run a simple script if it exists, no multithreading def runSmallScript(self, filename): if filename is None: return f = None try: with open(filename) as f: for i in f: l = i.replace("\n", "") l = l[:l.find(";")] # remove comments self.send_now(l) except: pass def pause(self): """Pauses the print, saving the current position. """ if not self.printing: return False self.paused = True self.printing = False # try joining the print thread: enclose it in try/except because we # might be calling it from the thread itself try: self.print_thread.join() except RuntimeError, e: if e.message == "cannot join current thread": pass else: self.logError(traceback.format_exc()) except:
class MTRF64Adapter(object): _packet_size = 17 _serial = None _read_thread = None _command_response_queue = Queue() _incoming_queue = Queue() _send_lock = Lock() _listener_thread = None _listener = None _is_released = False def __init__(self, port: str, on_receive_data=None): self._serial = Serial(baudrate=9600) self._serial.port = port self._serial.open() self._listener = on_receive_data self._read_thread = Thread(target=self._read_loop) self._read_thread.daemon = True self._read_thread.start() self._listener_thread = Thread(target=self._read_from_incoming_queue) self._listener_thread.daemon = True self._listener_thread.start() def release(self): self._is_released = True self._serial.close() self._incoming_queue.put(None) self._listener = None def send(self, data: OutgoingData) -> [IncomingData]: responses = [] packet = self._build(data) with self._send_lock: _LOGGER.debug("Send:\n - request: {0},\n - packet: {1}".format( data, packet)) self._command_response_queue.queue.clear() self._serial.write(packet) try: while True: response = self._command_response_queue.get(timeout=2) responses.append(response) if response.count == 0: break except Empty as err: _LOGGER.error("Error receiving response: {0}.".format(err)) # For NooLite.TX we should make a bit delay. Adapter send the response without waiting until command was delivered. # So if we send new command until previous command was sent to module, adapter will ignore new command. Note: if data.mode == Mode.TX or data.mode == Mode.RX: sleep(0.2) return responses # Private def _crc(self, data) -> int: sum = 0 for i in range(0, len(data)): sum = sum + data[i] sum = sum & 0xFF return sum def _build(self, data: OutgoingData) -> bytes: format_begin = Struct(">BBBBBBB4sI") format_end = Struct("BB") packet = format_begin.pack(171, data.mode, data.action, 0, data.channel, data.command, data.format, data.data, data.id) packet_end = format_end.pack(self._crc(packet), 172) packet = packet + packet_end return packet def _parse(self, packet: bytes) -> IncomingData: if len(packet) != self._packet_size: raise IncomingDataException("Invalid packet size: {0}".format( len(packet))) format = Struct(">BBBBBBB4sIBB") data = IncomingData() start_byte, data.mode, data.status, data.count, data.channel, data.command, data.format, data.data, data.id, crc, stop_byte = format.unpack( packet) if (start_byte != 173) or (stop_byte != 174) or (crc != self._crc( packet[0:-2])): raise IncomingDataException("Invalid response") return data def _read_loop(self): while True: packet = self._serial.read(self._packet_size) if self._is_released: break try: data = self._parse(packet) _LOGGER.debug("Receive:\n - packet: {0},\n - data: {1}".format( packet, data)) if data.mode == Mode.TX or data.mode == Mode.TX_F: self._command_response_queue.put(data) elif data.mode == Mode.RX or data.mode == Mode.RX_F: self._incoming_queue.put(data) else: pass except IncomingDataException as err: _LOGGER.error("Packet error: {0}".format(err)) pass def _read_from_incoming_queue(self): while True: input_data = self._incoming_queue.get() if self._is_released: break if self._listener is not None: self._listener(input_data)
print(ser.readline()) ser.write("AT+RB".encode()) print(ser.readline()) ser.write("AT+RC".encode()) print(ser.readline()) ser.write("AT+RF".encode()) print(ser.readline()) ser.write("AT+RP".encode()) print(ser.readline()) ser.write("AT".encode()) print(ser.readline()) # initializeAntenna() ser.close() currentBaud = int(antennaConfig["baud"]) ser = Serial("/dev/ttyS0", currentBaud) newMessage = False id = 0 payload = [] def quit(_,__): killThreads.set() thrd.join() exit(0) def sendSerial():
class Uart: class Receiver(Thread, IMqttConnector): def __init__(self, handle): super().__init__() self.__running = True self.__handle: Serial = handle # MQTT self.__mqtt = MqttClient(self, "127.0.0.1", [], "UART") self.__topic = "" # enOcean packet self.__packet = {} self.__rawPacket = [] self.__syncByte = "55" self.__byte = "" self.__uniqueID = "00:00:00:00" self.__dataLength = 0 self.__RORG = "f6" self.start() def Receive(self, server, topic: str, payload: bytes): pass def Connected(self, server): pass def Acknowledge(self, server, messageId: int): pass def Send(self, topics, msg): if msg[6] == "f6": jsonMsg = { 'packet': { 'header': { 'syncByte': msg[0], 'dataLength': msg[1] + msg[2], 'optionalDataLength': msg[3], 'packetType': msg[4], 'CRC8H': msg[5] }, 'data': { 'RORG': msg[6], 'data': msg[7], 'senderID': msg[8] + msg[9] + msg[10] + msg[11], 'status': msg[12] }, 'optionalData': { 'subTelNum': msg[13], 'destinationID': msg[14] + msg[15] + msg[16] + msg[17], 'dBm': msg[18], 'securityLevel': msg[19], 'CRC8D': msg[20] } } } if msg[6] == "a5": jsonMsg = { 'packet': { 'header': { 'syncByte': msg[0], 'dataLength': msg[1] + msg[2], 'optionalDataLength': msg[3], 'packetType': msg[4], 'CRC8H': msg[5] }, 'data': { 'RORG': msg[6], 'DB3': msg[7], 'DB2': msg[8], 'DB1': msg[9], 'DB0': msg[10], 'senderID': msg[11] + msg[12] + msg[13] + msg[14], 'status': msg[15] }, 'optionalData': { 'subTelNum': msg[16], 'destinationID': msg[17] + msg[18] + msg[19] + msg[20], 'dBm': msg[21], 'securityLevel': msg[22], 'CRC8D': msg[23] } } } # print(jsonMsg) jsonMsg = json.dumps(jsonMsg) self.__mqtt.sendMessage(self.__topic, jsonMsg) def run(self) -> None: while self.__running: self.__byte = (self.__handle.read(1).hex()) # Check for SyncByte if self.__byte == self.__syncByte: # Start saving packet with sync byte self.__rawPacket.append(self.__byte) # Add the header of the packet for x in range(0, 5): self.__rawPacket.append(self.__handle.read(1).hex()) self.__dataLength = int( self.__rawPacket[1] + self.__rawPacket[2], 16) for x in range(0, self.__dataLength): self.__rawPacket.append(self.__handle.read(1).hex()) self.__RORG = self.__rawPacket[6] for x in range(0, 8): self.__rawPacket.append(self.__handle.read(1).hex()) # Extract uniqueID for packet if self.__RORG == "f6": self.__uniqueID = self.__rawPacket[8] self.__uniqueID += self.__rawPacket[9] self.__uniqueID += self.__rawPacket[10] self.__uniqueID += self.__rawPacket[11] if self.__RORG == "a5": self.__uniqueID = self.__rawPacket[11] self.__uniqueID += self.__rawPacket[12] self.__uniqueID += self.__rawPacket[13] self.__uniqueID += self.__rawPacket[14] print("[UART] Receiving enOcean packet from : " + self.__uniqueID) self.__topic = "enocean/device/id/{}".format( self.__uniqueID) # Send packet to topics with uniqueID self.Send(self.__topic, self.__rawPacket) self.__rawPacket.clear() def Stop(self): print("[UART] Serial line closed") self.__running = False self.__handle.cancel_read() def __init__(self): self.__SerialPortName = "/dev/ttyAMA0" self.__SerialPortSpeed = "57600" self.__handle = Serial(self.__SerialPortName, self.__SerialPortSpeed, timeout=2.0) print(("[UART] Serial line {} @ {} bauds opened".format( self.__SerialPortName, self.__SerialPortSpeed))) self.__thread: Uart.Receiver = self.Receiver(self.__handle) def __del__(self): self.Stop() self.__handle.close() def Stop(self): self.__thread.Stop()
class Polytec(Instrument): """The polytec class""" def __init__(self, config, plotter): """Constructor""" Instrument.__init__(self, config, plotter) self._serial = None self._signal = None self.min_used = None self.max_used = None def config(self, metadata, total_updates): """Configure the vibrometer. :param metadata: experiment metadata :type metadata: dict :param total_updates: number of updates for the experiment :type total_updates: int """ name = self.__class__.__name__ self._serial = Serial( port=PlaceConfig().get_config_value(name, "port"), baudrate=PlaceConfig().get_config_value(name, "baudrate"), timeout=10, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS) if self._config['dd_300']: self._setup_decoder(metadata, 'dd_300') if self._config['dd_900']: self._setup_decoder(metadata, 'dd_900') if self._config['vd_08']: self._setup_decoder(metadata, 'vd_08') if self._config['vd_09']: self._setup_decoder(metadata, 'vd_09') if self._config['autofocus'] == 'custom': curr_set = self._write_and_readline( 'GetDevInfo,SensorHead,0,Focus\n') curr_min, curr_max = ast.literal_eval(curr_set) self.min_used = max(curr_min, self._config['area_min']) self.max_used = min(curr_max, self._config['area_max']) metadata['actual_area_min'] = self.min_used metadata['actual_area_max'] = self.max_used def update(self, update_number, progress): """Update the vibrometer. :param update_number: the count of the current update (0-indexed) :type update_number: int :param progress: a dictionary of values passed back to your Elm app :type progress: dict :returns: an array containing the signal level :rtype: numpy.array dtype='uint64' """ if self._config['autofocus'] != 'none': if update_number == 0 or self._config[ 'autofocus_everytime'] is True: self._autofocus_vibrometer(span=self._config['autofocus'], timeout=self._config['timeout']) signal_level = self._get_signal_level() field = '{}-signal'.format(self.__class__.__name__) data = np.array([(signal_level, )], dtype=[(field, 'uint64')]) if self._config['plot']: self._draw_plot(signal_level, update_number, progress) return data def cleanup(self, abort=False): """Closes the serial port to the Polytec. :param abort: indicates that the experiment is being aborted and is unfinished :type abort: bool """ if abort is False: self._serial.close() # PRIVATE METHODS def _write(self, message): """Send a message :param message: message to be sent to the Polytec receiver :type message: str """ self._serial.write(message.encode()) def _write_and_readline(self, message): """Send a message and get a response. :param message: message to be sent to the Polytec receiver :type message: str :returns: the decoded response :rtype: str """ self._write(message) return self._serial.readline().decode('ascii', 'replace') def _setup_decoder(self, metadata, name): """Set the range for the decoder and obtain metadata :param metadata: experiment metadata :type metadata: dict :param name: the name to use for the decoder :type name: str """ id_ = PlaceConfig().get_config_value(self.__class__.__name__, name) self._set_range(id_, self._config[name + '_range']) if name == 'vd_08' or name == 'vd_09': metadata[name + '_time_delay'] = self._get_delay(id_) metadata[name + '_maximum_frequency'] = self._get_maximum_frequency(id_) def _autofocus_vibrometer(self, span='Full', timeout=30): """Autofocus the vibrometer. :param span: the range in which the vibrometer should look for focus :type span: str :param timeout: the number of seconds to wait for focus before failing :type timeout: int :raises RuntimeError: if focus is not found before timeout """ if self._config['autofocus'] == 'custom': self._write('Set,SensorHead,0,AutoFocusArea,{},{}\n'.format( self.min_used, self.max_used)) else: self._write('Set,SensorHead,0,AutoFocusSpan,' + span + '\n') self._write('Set,SensorHead,0,AutoFocus,Search\n') countdown = timeout tick = 1 while countdown > 0: sleep(tick) countdown -= tick if self._write_and_readline( 'Get,SensorHead,0,AutoFocusResult\n') == 'Found\n': break else: raise RuntimeError('autofocus failed') def _get_delay(self, id_): """Get time delay. :param id_: the identification string for the decoder :type id_: str :returns: the delay time :rtype: float """ delay_string = self._write_and_readline('Get,' + id_ + ',SignalDelay\n') return float(re.findall(_NUMBER, delay_string)[0]) def _get_maximum_frequency(self, id_): """Get the maximum frequency. :param id_: the identification string for the decoder :type id_: str :returns: the frequency value of the selected decoder :rtype: float :raises ValueError: if maximum frequency is not available """ frequency_string = self._write_and_readline('Get,' + id_ + ',MaxFreq\n') if frequency_string == 'Not Available': raise ValueError( 'maximum frequency for {} not available'.format(id_)) return _parse_frequency(frequency_string) def _get_range(self, name, id_): """Get the current range. :param name: the name for the decoder :type name: str :param id_: the identification string for the decoder :type id_: str :returns: the range value and units returned from the instrument :rtype: float, string :raises ValueError: if decoder name is not recognized """ decoder_range = self._write_and_readline('Get,' + id_ + ',Range\n') if name == 'dd_300': range_num = re.findall(_NUMBER, self._config['dd_300_range']) elif name == 'dd_900': raw_num = re.findall(_NUMBER, self._config['dd_900_range']) range_num = [string.replace('um', 'µm') for string in raw_num] elif name == 'vd_08': range_num = re.findall(_NUMBER, self._config['vd_08_range']) elif name == 'vd_09': range_num = re.findall(_NUMBER, self._config['vd_09_range']) else: raise ValueError('unknown decoder: ' + name) del_num_r = len(range_num) + 1 calib = float(range_num[0]) calib_unit = decoder_range[del_num_r:].lstrip() return calib, calib_unit def _set_range(self, id_, range_): """Set the range. :param id_: the identification string for the decoder :type id_: str :param range_: the desired decoder range :type range_: str """ self._write('Set,' + id_ + ',Range,' + range_ + '\n') def _get_signal_level(self): return int(self._write_and_readline('Get,SignalLevel,0,Value\n')) def _draw_plot(self, signal_level, update_number, progress): if update_number == 0: self._signal = [signal_level] else: self._signal.append(signal_level) title = 'Signal level at each PLACE update' self.plotter.view(title, [ self.plotter.line( self._signal, color='purple', shape='cross', label='signal') ])
class LX16AServos(): _released = False SerialPort = None _shutingDown = False CMD_START_BYTE = 0x55 CMD_SERVO_MOVE_TIME_WRITE_BYTE = 1 CMD_READ_DATA_BYTE = 3 CMD_TEMP_READ_BYTE = 26 CMD_VOLT_READ_BYTE = 27 CMD_POS_READ_BYTE = 28 CMD_LOAD_OR_UNLOAD_WRITE = 31 TX_DELAY_TIME = 0.00002 _readWaitTime1 = 0.001 _readWaitTime2 = 0.001 def __init__(self): self.SerialPort = Serial("/dev/ttyUSB0", baudrate=115200) self.SerialPort.setDTR(1) def checksumWithLength(self, id, byteArry): check = id + len(byteArry) + 2 for val in byteArry: check = check + val check = bytes([(~(check)) & 0xff]) return check[0] def checksum(self, id, byteArry): check = id for val in byteArry: check = check + val check = bytes([(~(check)) & 0xff]) return check[0] def MoveServo(self, id, speed, position): if (self._shutingDown == True): return False if (position < 0): position = 0 if (position > 1000): position = 1000 if (speed < 0): speed = 0 if (speed > 10000): speed = 10000 p = [position & 0xff, position >> 8] s = [speed & 0xff, speed >> 8] command = bytes( [self.CMD_SERVO_MOVE_TIME_WRITE_BYTE, p[0], p[1], s[0], s[1]]) self.SerialPort.write( bytes([ self.CMD_START_BYTE, self.CMD_START_BYTE, id, len(command) + 2 ])) self.SerialPort.write(command) self.SerialPort.write(bytes([self.checksumWithLength(id, command)])) sleep(self.TX_DELAY_TIME) return True def SetServoPower(self, id, on): value = 0 if (on == True): value = 1 command = bytes([self.CMD_LOAD_OR_UNLOAD_WRITE, value]) self.SerialPort.write( bytes([ self.CMD_START_BYTE, self.CMD_START_BYTE, id, len(command) + 2 ])) self.SerialPort.write(command) self.SerialPort.write(bytes([self.checksumWithLength(id, command)])) sleep(self.TX_DELAY_TIME) return True def ReadTemperature(self, id): if (self._shutingDown == True): return False self.SerialPort.flushInput() command = bytes([self.CMD_READ_DATA_BYTE, self.CMD_TEMP_READ_BYTE]) self.SerialPort.write( bytes([self.CMD_START_BYTE, self.CMD_START_BYTE, id])) self.SerialPort.write(command) self.SerialPort.write(bytes([self.checksum(id, command)])) sleep(self.TX_DELAY_TIME) sleep(0.1) retry = 0 while retry < 100: if (self.SerialPort.inWaiting() > 0): value = self.SerialPort.read(1) if value != '': for pos in range(0, 7): if pos == 5: tempture = int(ord(value)) return tempture value = self.SerialPort.read(1) retry += 1 sleep(0.1) print("Servo " + str(id) + " not responding!") return -1 def ReadVolt(self, id, showError=True): if (self._shutingDown == True): return False self.SerialPort.flushInput() command = bytes([self.CMD_READ_DATA_BYTE, self.CMD_VOLT_READ_BYTE]) self.SerialPort.write( bytes([self.CMD_START_BYTE, self.CMD_START_BYTE, id])) self.SerialPort.write(command) self.SerialPort.write(bytes([self.checksum(id, command)])) sleep(0.1) retry = 0 while retry < 100: if (self.SerialPort.inWaiting() > 0): value = self.SerialPort.read(1) if value != '': for pos in range(0, 8): if pos == 5: volt1 = int(ord(value)) if pos == 6: volt2 = int(ord(value)) volt2 = volt1 + 256 * volt2 return volt2 value = self.SerialPort.read(1) retry += 1 sleep(0.1) if (showError == True): print("Servo " + str(id) + " not responding!") return -1 def ShutDown(self, ids): self._shutingDown = True for id in ids: print("shutting down servo " + str(id)) self.SetServoPower(id, False) def ReadPos(self, id, showError=True): if (self._shutingDown == True): return False self.SerialPort.flushInput() command = bytes([self.CMD_READ_DATA_BYTE, self.CMD_POS_READ_BYTE]) self.SerialPort.write( bytes([self.CMD_START_BYTE, self.CMD_START_BYTE, id])) self.SerialPort.write(command) self.SerialPort.write(bytes([self.checksum(id, command)])) sleep(0.001) retry = 0 while retry < 100: if (self.SerialPort.inWaiting() > 0): value = self.SerialPort.read(1) if value != '': for pos in range(0, 8): if pos == 5: pos1 = int(ord(value)) if pos == 6: pos2 = int(ord(value)) pos2 = pos1 + 256 * pos2 return pos2 if (self.SerialPort.inWaiting() == 0): sleep(self._readWaitTime1) if (self.SerialPort.inWaiting() > 0): value = self.SerialPort.read(1) else: print("Servo " + str(id) + " value loss!") retry += 1 sleep(self._readWaitTime2) if (showError == True): print("Servo " + str(id) + " not responding!") return -1 def Release(self): if (self._released == False): self.SerialPort.close() def __del__(self): self.Release()
class PiAnywhere(): MAX_UART_BUFFER = 128 def __init__(self): self.uart = Serial("/dev/ttyS0") self.uart.baudrate = 9600 self.uart.timeout = 1 def __exit__(self): self.uart.close() def send_command(self, command): self.uart.write(command) response = self.uart.read(MAX_UART_BUFFER) return response def send_command_with_check(self, command, check): if not (command.startswith(("AT+", "PI+"))): raise PIANYWHERE_BAD_COMMAND() self.uart.write(command.append("/r/n")) response = self.uart.read(self.MAX_UART_BUFFER) if (check in response): return true elif ("ERROR" in response): raise PIANYWHERE_ERROR_RESPONSE() elif ("NO CARRIER" in response): raise PIANYWHERE_NO_CARRIER() elif ("BUFFER OVERFLOW" in response): raise PIANYWHERE_BUFFER_OVERFLOW() else: raise PIANYWHERE_BAD_RESPONSE() def add_sms_responder(self, number): return self.send_command_with_check("PI+SETRESPONDER=%s" % number, "OK") def remove_sms_responder(self, number): return self.send_command_with_check("PI+UNSETRESPONDER=%s" % number, "OK") def clear_sms_responders(self): return self.send_command_with_check("PI+CLEARRESPONDERS", "OK") def send_sms_message(self, number, message): self.send_command_with_check("AT+", "OK") def get_all_sms_messages(self): self.send_command_with_check("AT+", "OK") def get_unread_sms_messages(self): self.send_command_with_check("AT+", "OK") def get_sms_message(self, id): self.send_command_with_check("AT+", "OK") def set_wake_datetime(self, datetime): self.send_command_with_check("PI+WAKEON=%s" % datetime, "OK") def set_sleep_datetime(self, datetime): self.send_command_with_check("PI+SLEEPON=%s" % datetime, "OK") def get_pianywhere_date(self): datetime = send_command_with_check("PI+DATETIME", "OK") return time.strptime(datetime, '%b %d %Y %I:%M%p') def powerkey_modem(self): self.send_command_with_check("AT+", "OK") def reset_modem(self): self.send_command_with_check("AT+", "OK")
def doFlashTasmota(self, room: str, espType: str, siteId: str): port = self.findUSBPort(timeout=60) if port: self.MqttManager.say(text=self.TalkManager.randomTalk( 'usbDeviceFound', module='AliceCore'), client=siteId) try: mac = ESPLoader.detect_chip(port=port, baud=115200).read_mac() mac = '%s' % (':'.join(map(lambda x: '%02x' % x, mac))) cmd = list() cmd.append('--port') cmd.append(port) cmd.append('--baud') cmd.append('115200') cmd.append('--after') cmd.append('no_reset') cmd.append('write_flash') cmd.append('--flash_mode') cmd.append('dout') cmd.append('0x00000') cmd.append('sonoff.bin') cmd.append('--erase-all') esptool.main(cmd) except Exception as e: self._logger.error( f'[{self.name}] Something went wrong flashing esp device: {e}' ) self.MqttManager.say(text=self.TalkManager.randomTalk( 'espFailed', module='AliceCore'), client=siteId) self._broadcastFlag.clear() return else: self.MqttManager.say(text=self.TalkManager.randomTalk( 'noESPFound', module='AliceCore'), client=siteId) self._broadcastFlag.clear() return self._logger.info(f'[{self.name}] Tasmota flash done') self.MqttManager.say(text=self.TalkManager.randomTalk( 'espFlashedUnplugReplug', module='AliceCore'), client=siteId) found = self.findUSBPort(timeout=60) if found: self.MqttManager.say(text=self.TalkManager.randomTalk( 'espFoundReadyForConf', module='AliceCore'), client=siteId) time.sleep(10) uid = self._getFreeUID(mac) tasmotaConfigs = TasmotaConfigs(deviceType=espType, uid=uid) confs = tasmotaConfigs.getBacklogConfigs(room) if not confs: self._logger.error( f'[{self.name}] Something went wrong getting tasmota configuration' ) self.MqttManager.say(text=self.TalkManager.randomTalk( 'espFailed', module='AliceCore'), client=siteId) else: serial = Serial() serial.baudrate = 115200 serial.port = port serial.open() try: for group in confs: cmd = ';'.join(group['cmds']) if len(group['cmds']) > 1: cmd = f'Backlog {cmd}' arr = list() if len(cmd) > 50: while len(cmd) > 50: arr.append(cmd[:50]) cmd = cmd[50:] arr.append(f'{cmd}\r\n') else: arr.append(f'{cmd}\r\n') for piece in arr: serial.write(piece.encode()) self._logger.info('[{}] Sent {}'.format( self.name, piece.replace('\r\n', ''))) time.sleep(0.5) time.sleep(group['waitAfter']) serial.close() self._logger.info( f'[{self.name}] Tasmota flashing and configuring done') self.MqttManager.say(text=self.TalkManager.randomTalk( 'espFlashingDone', module='AliceCore'), client=siteId) self.addNewDevice(espType, room, uid) self._broadcastFlag.clear() except Exception as e: self._logger.error( f'[{self.name}] Something went wrong writting configuration to esp device: {e}' ) self.MqttManager.say(text=self.TalkManager.randomTalk( 'espFailed', module='AliceCore'), client=siteId) self._broadcastFlag.clear() serial.close() else: self.MqttManager.say(text=self.TalkManager.randomTalk( 'espFailed', module='AliceCore'), client=siteId) self._broadcastFlag.clear() return
class TestSuite(): '''Class representing the ImageProc test suite''' def __init__(self, dev_name, baud_rate=230400, dest_addr='\xff\xff'): ''' Description: Initiate the 802.15.4 connection and configure the target. Class must be instantiated with a connection name. On Windows this is typically of the form "COMX". On Mac, the serial device connection string is typically '/dev/tty.DEVICE_NAME-SPP-(1)' where the number at the end is optional depending on the version of the OS. Inputs: dev_name: The device name to connect to. Examples are COM5 or /dev/tty.usbserial. print ord(datum) ''' if dev_name == "" or dev_name == None: print "You did not instantiate the class with a device name " + \ "(eg. COM5, /dev/tty.usbserial)." sys.exit(1) if dest_addr == '\xff\xff': print "Destination address is set to broadcast. You will " +\ "interfere with other 802.15.4 devices in the area." +\ " To avoid interfering, instantiate the class with a " +\ "destination address explicitly." self.dest_addr = dest_addr self.last_packet = None try: self.conn = Serial(dev_name, baudrate=baud_rate, rtscts=True) if self.conn.isOpen(): self.radio = XBee(self.conn, callback=self.receive) print "Radio opened:" + str(dev_name) pass else: raise SerialException('') except (AttributeError, SerialException): print "Unable to open a connection to the target. Please" + \ " verify your basestation is enabled and properly configured." raise def set_dest_addr(self, dest_addr): self.dest_addr = dest_addr def check_conn(self): ''' Description: A simple utility function for checking the status of the connection. ''' if self.conn == None or not self.conn.isOpen(): print 'The connection to the target appears to be closed.' return False else: return True def receive(self, packet): self.last_packet = packet rf_data = packet.get('rf_data') typeID = ord(rf_data[1]) print "got packet type " + str(typeID) if typeID == kTestAccelCmd or typeID == kTestGyroCmd: self.print_gyro(self.last_packet) elif typeID == kTestDFlashCmd: print ''.join(rf_data[2:]) # print rf_data[2:] # print map(ord,rf_data[2:]) # print map(str,rf_data[2:]) elif typeID == kTestMotorCmd: print ''.join(rf_data[2:]) elif typeID == kTestHallCmd: self.print_hall(self.last_packet) # elif typeID == kTestRadioCmd: # self.print_packet(self.last_packet) def test_radio(self): ''' Description: This test sends command packets to the target requesting the results of a radio test. The results should be the receipt of three packets. The payloads of those three packets should print as consecutive integers 0-9, 10-19, and 20-29 respectively. ''' header = chr(kStatusUnused) + chr(kTestRadioCmd) for i in range(1, 3): data_out = header + ''.join([str(datum) for datum in range((i-1)*10,i*10)]) print("\nTransmitting packet " + str(i) + "...") print map(str,data_out[2:]) print data_out[2:] if(self.check_conn()): self.radio.tx(dest_addr=self.dest_addr, data=data_out) time.sleep(0.1) # possible over run of packets? self.print_packet(self.last_packet) time.sleep(1) ############ def test_gyro(self, num_test_packets): ''' Description: Read the XYZ values from the gyroscope. ''' data_out = chr(kStatusUnused) + chr(kTestGyroCmd) + chr(num_test_packets) if self.check_conn(): self.radio.tx(dest_addr=self.dest_addr, data=data_out) time.sleep(num_test_packets * 0.5) ################# def test_accel(self, num_test_packets): ''' Description: Read the XYZ values from the accelerometer. ''' data_out = chr(kStatusUnused) + chr(kTestAccelCmd) + chr(num_test_packets) packets_received = 0 prev_data = None if(self.check_conn()): self.radio.tx(dest_addr=self.dest_addr, data=data_out) time.sleep(num_test_packets * 0.5) ############### def test_hall(self, num_test_packets): ''' Description: Read the position values from the Hall angle sensors. ''' data_out = chr(kStatusUnused) + chr(kTestHallCmd) + chr(num_test_packets) if self.check_conn(): self.radio.tx(dest_addr=self.dest_addr, data=data_out) time.sleep(num_test_packets * 0.5) ################ def test_dflash(self): ''' Description: Read out a set of strings that have been written to and read from memory. ''' data_out = chr(kStatusUnused) + chr(kTestDFlashCmd) if(self.check_conn()): self.radio.tx(dest_addr=self.dest_addr, data=data_out) time.sleep(1) #################### def test_motor(self, motor_id,duty_cycle): ''' Description: Turn on a motor. Parameters: motor_id : The motor number to turn on time : The amount of time to turn the motor on for (in milliseconds) duty_cycle : The duty cycle of the PWM signal used to control the motor in -4000 < dc < 4000 direction : The direction to spin the motor. There are *three* options for this parameter. 0 - reverse, 1 - forward, 2 high impedance motor controller output = braking return_emf : Send the back emf readings over the radio channel. ''' duration = 500; # time in milliseconds data_out = chr(kStatusUnused) + chr(kTestMotorCmd) + \ pack('3h', motor_id, duration, duty_cycle) print "testing motor " + str(motor_id) if(self.check_conn()): self.radio.tx(dest_addr=self.dest_addr, data=data_out) time.sleep(1) ########### def test_sma(self, chan_id, time, duty_cycle): ''' Description: Turn on an SMA Parameters: chan_id : The SMA channel to turn on time : The amount of time to turn the SMA on for (in seconds) duty_cycle : The duty cycle of the PWM signal used to control the SMA in percent (0 - 100) ''' if(duty_cycle < 0 or duty_cycle > 100): print("You entered an invalid duty cycle.") return data_out = chr(kStatusUnused) + chr(kTestSMACmd) + chr(chan_id) + \ chr(time) + chr(duty_cycle) if(self.check_conn()): self.radio.tx(dest_addr=self.dest_addr, data=data_out) def print_packet(self, packet): ''' Description: Print the contents of a packet to the screen. This function will primarily be used for debugging purposes. May need to replace print with stdio or stderr to accommodate GUI test suite. ''' if(packet is not None): print("Received the following: ") print("RSSI: " + str(ord(packet.get('rssi')))) (src_h, src_l) = unpack('cc', packet.get('source_addr')) print("Source Address: 0x%.2X 0x%.2X" % (ord(src_h), ord(src_l))) print("ID: " + (packet.get('id'))) print("Options: " + str(ord(packet.get('options')))) rf_data = packet.get('rf_data') print("Status Field: " + str(ord(rf_data[0]))) print("Type Field: " + str(ord(rf_data[1]))) # print("Payload Data: " + ''.join([str(ord(i)) for i in rf_data[2:]])) print "Payload Data: " print map(ord,rf_data[2:]) # print("Payload" + rf_data[2:]) print map(str,rf_data[2:]) # print(map(chr,rf_data)) # gyro packet : int xl_data[3]; int gyro_data[3]; int temp; def print_gyro(self, packet): rf_data = packet.get('rf_data') # print "length of data " + str(len(rf_data[2:])) print "xl data:" + str(map(hex,unpack('3h',rf_data[2:8]))) print "gyro data:" + str(map(hex,unpack('3h',rf_data[8:14]))) print "temperature:" + str(map(hex,unpack('1h',rf_data[14:16]))) # print map(hex,unpack('7h',rf_data[2:])) # Austria Microsystems Hall angle sensor packet: # int pos; long oticks; int calibPOS; int offset; def print_hall(self,packet): rf_data = packet.get('rf_data') index = 0 for i in range(1,3): print "Hall encoder:" + str(i-1) print "position" + str(map(hex,unpack('1h',rf_data[index+2:index+4]))) + \ " revolutions" + str(map(hex,unpack('1i',rf_data[index+4:index+8]))) print "cal. pos and offset" + \ str(map(hex,unpack('2h',rf_data[index+8:index+12]))) index = index + 10 print " " def __del__(self): ''' Description: Clean up the connection when the object is deleted. ''' self.radio.halt() self.conn.close()
class SerialConnectorPrimitive(ConnectorPrimitive): def __init__(self, name, port, baudrate, config): ConnectorPrimitive.__init__(self, name) self.port = port self.baudrate = int(baudrate) self.timeout = 0.01 # 10 milli sec self.config = config self.target_id = self.config.get('target_id', None) self.polling_timeout = config.get('polling_timeout', 60) self.forced_reset_timeout = config.get('forced_reset_timeout', 1) self.skip_reset = config.get('skip_reset', False) self.serial = None # Values used to call serial port listener... # Check if serial port for given target_id changed # If it does we will use new port to open connections and make sure reset plugin # later can reuse opened already serial port # # Note: This listener opens serial port and keeps connection so reset plugin uses # serial port object not serial port name! serial_port = HostTestPluginBase().check_serial_port_ready(self.port, target_id=self.target_id, timeout=self.polling_timeout) if serial_port is None: raise ConnectorPrimitiveException("Serial port not ready!") if serial_port != self.port: # Serial port changed for given targetID self.logger.prn_inf("serial port changed from '%s to '%s')"% (self.port, serial_port)) self.port = serial_port startTime = time.time() self.logger.prn_inf("serial(port=%s, baudrate=%d, timeout=%s)"% (self.port, self.baudrate, self.timeout)) while time.time() - startTime < self.polling_timeout: try: # TIMEOUT: While creating Serial object timeout is delibrately passed as 0. Because blocking in Serial.read # impacts thread and mutliprocess functioning in Python. Hence, instead in self.read() s delay (sleep()) is # inserted to let serial buffer collect data and avoid spinning on non blocking read(). self.serial = Serial(self.port, baudrate=self.baudrate, timeout=0) except SerialException as e: self.serial = None self.LAST_ERROR = "connection lost, serial.Serial(%s, %d, %d): %s"% (self.port, self.baudrate, self.timeout, str(e)) self.logger.prn_err(str(e)) self.logger.prn_err("Retry after 1 sec until %s seconds" % self.polling_timeout) else: if not self.skip_reset: self.reset_dev_via_serial(delay=self.forced_reset_timeout) break time.sleep(1) def reset_dev_via_serial(self, delay=1): """! Reset device using selected method, calls one of the reset plugins """ reset_type = self.config.get('reset_type', 'default') if not reset_type: reset_type = 'default' disk = self.config.get('disk', None) self.logger.prn_inf("reset device using '%s' plugin..."% reset_type) result = host_tests_plugins.call_plugin('ResetMethod', reset_type, serial=self.serial, disk=disk, target_id=self.target_id) # Post-reset sleep if delay: self.logger.prn_inf("waiting %.2f sec after reset"% delay) time.sleep(delay) self.logger.prn_inf("wait for it...") return result def read(self, count): """! Read data from serial port RX buffer """ # TIMEOUT: Since read is called in a loop, wait for self.timeout period before calling serial.read(). See # comment on serial.Serial() call above about timeout. time.sleep(self.timeout) c = str() try: if self.serial: c = self.serial.read(count) except SerialException as e: self.serial = None self.LAST_ERROR = "connection lost, serial.read(%d): %s"% (count, str(e)) self.logger.prn_err(str(e)) return c def write(self, payload, log=False): """! Write data to serial port TX buffer """ try: if self.serial: self.serial.write(payload) if log: self.logger.prn_txd(payload) except SerialException as e: self.serial = None self.LAST_ERROR = "connection lost, serial.write(%d bytes): %s"% (len(payload), str(e)) self.logger.prn_err(str(e)) return payload def flush(self): if self.serial: self.serial.flush() def connected(self): return bool(self.serial) def finish(self): if self.serial: self.serial.close() def __del__(self): self.finish()
def TouchSerialPort(env, port, baudrate): s = Serial(port=env.subst(port), baudrate=baudrate) s.setDTR(False) s.close() sleep(0.4)
class ArduinoSerial(object): DEFAULT_BAUD = 115200 _logger = logging.getLogger("ArduinoSerial") def __init__(self, port, scalex=1, scaley=1): self._serial = Serial() self._scale_x = scalex self._scale_y = scaley self.open(port) def _send_gcode(self, gcode): if gcode: self._logger.debug("sending gcode %s", gcode) #gcode += "\n" try: self._serial.write("%s\r\n" % (gcode,)) # Wait for grbl response with carriage return grbl_out = self._serial.readline().strip() except SerialException: pass else: if grbl_out: self._logger.debug("recived %s", grbl_out) def _go_to(self, point): """ Send a command to the arduino to move the magnet to a specific (x, y) """ self._logger.debug("going to %s", point) self._send_gcode("G90X%sY%s" % (point[1] * self._scale_y, point[0] * self._scale_x)) def _set_magnet_state(self, is_on): """ Send a command to the arduino to activate/deactivate the magnet """ self._logger.debug("turning magnet %s", "on" if is_on else "off") self._send_gcode("M4" if is_on else "M3") def open(self, port, baud=DEFAULT_BAUD): try: self._serial = Serial(port=port, baudrate=baud) self._serial.open() except Exception as e: self._logger.error('Failed to open {}'.format(e)) return self._send_gcode("") self._send_gcode("") self._logger.info("%s is opened", self._serial.port) def close(self): self._serial.close() self._logger.info("%s is closed", self._serial.port) def move(self, points): """ Move a game piece via the given points """ self._logger.info("moving via %s", points) # deactivate the magnet for safety before moving self._set_magnet_state(False) # go to the 'from' piece location self._go_to(points.pop(0)) # activate the magnet for moving self._set_magnet_state(True) # move via the points (dragging the piece with the magnet) for point in points: self._go_to(point) # deactivate the magnet for safety self._set_magnet_state(False)
class DfuTransportSerial(DfuTransport): DEFAULT_BAUD_RATE = 115200 DEFAULT_FLOW_CONTROL = True DEFAULT_TIMEOUT = 30.0 # Timeout time for board response DEFAULT_SERIAL_PORT_TIMEOUT = 1.0 # Timeout time on serial port read DEFAULT_PRN = 0 DEFAULT_DO_PING = True OP_CODE = { 'CreateObject': 0x01, 'SetPRN': 0x02, 'CalcChecSum': 0x03, 'Execute': 0x04, 'ReadError': 0x05, 'ReadObject': 0x06, 'GetSerialMTU': 0x07, 'WriteObject': 0x08, 'Ping': 0x09, 'Response': 0x60, } def __init__(self, com_port, baud_rate=DEFAULT_BAUD_RATE, flow_control=DEFAULT_FLOW_CONTROL, timeout=DEFAULT_TIMEOUT, prn=DEFAULT_PRN, do_ping=DEFAULT_DO_PING): super().__init__() self.com_port = com_port self.baud_rate = baud_rate self.flow_control = 1 if flow_control else 0 self.timeout = timeout self.prn = prn self.serial_port = None self.dfu_adapter = None self.ping_id = 0 self.do_ping = do_ping self.mtu = 0 """:type: serial.Serial """ def open(self): super().open() try: self.__ensure_bootloader() self.serial_port = Serial(port=self.com_port, baudrate=self.baud_rate, rtscts=self.flow_control, timeout=self.DEFAULT_SERIAL_PORT_TIMEOUT) self.dfu_adapter = DFUAdapter(self.serial_port) except Exception as e: raise NordicSemiException("Serial port could not be opened on {0}" ". Reason: {1}".format( self.com_port, e.strerror)) if self.do_ping: ping_success = False start = datetime.now() while (datetime.now() - start < timedelta(seconds=self.timeout) and ping_success == False): if self.__ping() == True: ping_success = True if ping_success == False: raise NordicSemiException( "No ping response after opening COM port") self.__set_prn() self.__get_mtu() def close(self): super().close() self.serial_port.close() def send_init_packet(self, init_packet): def try_to_recover(): if response['offset'] == 0 or response['offset'] > len( init_packet): # There is no init packet or present init packet is too long. return False expected_crc = (binascii.crc32(init_packet[:response['offset']]) & 0xFFFFFFFF) if expected_crc != response['crc']: # Present init packet is invalid. return False if len(init_packet) > response['offset']: # Send missing part. try: self.__stream_data(data=init_packet[response['offset']:], crc=expected_crc, offset=response['offset']) except ValidationException: return False self.__execute() return True response = self.__select_command() assert len( init_packet) <= response['max_size'], 'Init command is too long' if try_to_recover(): return try: self.__create_command(len(init_packet)) self.__stream_data(data=init_packet) self.__execute() except ValidationException: raise NordicSemiException("Failed to send init packet") def send_firmware(self, firmware): def try_to_recover(): if response['offset'] == 0: # Nothing to recover return expected_crc = binascii.crc32( firmware[:response['offset']]) & 0xFFFFFFFF remainder = response['offset'] % response['max_size'] if expected_crc != response['crc']: # Invalid CRC. Remove corrupted data. response[ 'offset'] -= remainder if remainder != 0 else response[ 'max_size'] response['crc'] = \ binascii.crc32(firmware[:response['offset']]) & 0xFFFFFFFF return if (remainder != 0) and (response['offset'] != len(firmware)): # Send rest of the page. try: to_send = firmware[response['offset']:response['offset'] + response['max_size'] - remainder] response['crc'] = self.__stream_data( data=to_send, crc=response['crc'], offset=response['offset']) response['offset'] += len(to_send) except ValidationException: # Remove corrupted data. response['offset'] -= remainder response['crc'] = \ binascii.crc32(firmware[:response['offset']]) & 0xFFFFFFFF return self.__execute() self._send_event(event_type=DfuEvent.PROGRESS_EVENT, progress=response['offset']) response = self.__select_data() try_to_recover() for i in range(response['offset'], len(firmware), response['max_size']): data = firmware[i:i + response['max_size']] try: self.__create_data(len(data)) response['crc'] = self.__stream_data(data=data, crc=response['crc'], offset=i) self.__execute() except ValidationException: raise NordicSemiException("Failed to send firmware") self._send_event(event_type=DfuEvent.PROGRESS_EVENT, progress=len(data)) def __ensure_bootloader(self): lister = DeviceLister() device = None start = datetime.now() while not device and datetime.now() - start < timedelta( seconds=self.timeout): time.sleep(0.5) device = lister.get_device(com=self.com_port) if device: device_serial_number = device.serial_number if not self.__is_device_in_bootloader_mode(device): retry_count = 10 wait_time_ms = 500 trigger = DFUTrigger() try: trigger.enter_bootloader_mode(device) logger.info("Serial: DFU bootloader was triggered") except NordicSemiException as err: logger.error(err) for checks in range(retry_count): logger.info("Serial: Waiting {} ms for device to enter bootloader {}/{} time"\ .format(500, checks + 1, retry_count)) time.sleep(wait_time_ms / 1000.0) device = lister.get_device( serial_number=device_serial_number) if self.__is_device_in_bootloader_mode(device): self.com_port = device.get_first_available_com_port() break trigger.clean() if not self.__is_device_in_bootloader_mode(device): logger.info( "Serial: Device is either not in bootloader mode, or using an unsupported bootloader." ) def __is_device_in_bootloader_mode(self, device): if not device: return False # Return true if nrf bootloader or Jlink interface detected. return ( (device.vendor_id.lower() == '1915' and device.product_id.lower() == '521f') # nRF52 SDFU USB or (device.vendor_id.lower() == '1366' and device.product_id.lower() == '0105') # JLink CDC UART Port or (device.vendor_id.lower() == '1366' and device.product_id.lower() == '1015') ) # JLink CDC UART Port (MSD) def __set_prn(self): logger.debug("Serial: Set Packet Receipt Notification {}".format( self.prn)) self.dfu_adapter.send_message([DfuTransportSerial.OP_CODE['SetPRN']] + list(struct.pack('<H', self.prn))) self.__get_response(DfuTransportSerial.OP_CODE['SetPRN']) def __get_mtu(self): self.dfu_adapter.send_message( [DfuTransportSerial.OP_CODE['GetSerialMTU']]) response = self.__get_response( DfuTransportSerial.OP_CODE['GetSerialMTU']) self.mtu = struct.unpack('<H', bytearray(response))[0] def __ping(self): self.ping_id = (self.ping_id + 1) % 256 self.dfu_adapter.send_message( [DfuTransportSerial.OP_CODE['Ping'], self.ping_id]) resp = self.dfu_adapter.get_message( ) # Receive raw response to check return code if (resp is None): logger.debug('Serial: No ping response') return False if resp[0] != DfuTransportSerial.OP_CODE['Response']: logger.debug('Serial: No Response: 0x{:02X}'.format(resp[0])) return False if resp[1] != DfuTransportSerial.OP_CODE['Ping']: logger.debug('Serial: Unexpected Executed OP_CODE.\n' \ + 'Expected: 0x{:02X} Received: 0x{:02X}'.format(DfuTransportSerial.OP_CODE['Ping'], resp[1])) return False if resp[2] != DfuTransport.RES_CODE['Success']: # Returning an error code is seen as good enough. The bootloader is up and running return True else: if struct.unpack('B', bytearray(resp[3:]))[0] == self.ping_id: return True else: return False def __create_command(self, size): self.__create_object(0x01, size) def __create_data(self, size): self.__create_object(0x02, size) def __create_object(self, object_type, size): self.dfu_adapter.send_message([DfuTransportSerial.OP_CODE['CreateObject'], object_type]\ + list(struct.pack('<L', size))) self.__get_response(DfuTransportSerial.OP_CODE['CreateObject']) def __calculate_checksum(self): self.dfu_adapter.send_message( [DfuTransportSerial.OP_CODE['CalcChecSum']]) response = self.__get_response( DfuTransportSerial.OP_CODE['CalcChecSum']) if response is None: raise NordicSemiException( 'Did not receive checksum response from DFU target. ' 'If MSD is enabled on the target device, try to disable it ref. ' 'https://wiki.segger.com/index.php?title=J-Link-OB_SAM3U') (offset, crc) = struct.unpack('<II', bytearray(response)) return {'offset': offset, 'crc': crc} def __execute(self): self.dfu_adapter.send_message([DfuTransportSerial.OP_CODE['Execute']]) self.__get_response(DfuTransportSerial.OP_CODE['Execute']) def __select_command(self): return self.__select_object(0x01) def __select_data(self): return self.__select_object(0x02) def __select_object(self, object_type): logger.debug("Serial: Selecting Object: type:{}".format(object_type)) self.dfu_adapter.send_message( [DfuTransportSerial.OP_CODE['ReadObject'], object_type]) response = self.__get_response( DfuTransportSerial.OP_CODE['ReadObject']) (max_size, offset, crc) = struct.unpack('<III', bytearray(response)) logger.debug( "Serial: Object selected: " + " max_size:{} offset:{} crc:{}".format(max_size, offset, crc)) return {'max_size': max_size, 'offset': offset, 'crc': crc} def __get_checksum_response(self): resp = self.__get_response(DfuTransportSerial.OP_CODE['CalcChecSum']) (offset, crc) = struct.unpack('<II', bytearray(resp)) return {'offset': offset, 'crc': crc} def __stream_data(self, data, crc=0, offset=0): logger.debug( "Serial: Streaming Data: " + "len:{0} offset:{1} crc:0x{2:08X}".format(len(data), offset, crc)) def validate_crc(): if (crc != response['crc']): raise ValidationException('Failed CRC validation.\n'\ + 'Expected: {} Received: {}.'.format(crc, response['crc'])) if (offset != response['offset']): raise ValidationException('Failed offset validation.\n'\ + 'Expected: {} Received: {}.'.format(offset, response['offset'])) current_pnr = 0 for i in range(0, len(data), (self.mtu - 1) // 2 - 1): # append the write data opcode to the front # here the maximum data size is self.mtu/2, # due to the slip encoding which at maximum doubles the size to_transmit = data[i:i + (self.mtu - 1) // 2 - 1] to_transmit = struct.pack( 'B', DfuTransportSerial.OP_CODE['WriteObject']) + to_transmit self.dfu_adapter.send_message(list(to_transmit)) crc = binascii.crc32(to_transmit[1:], crc) & 0xFFFFFFFF offset += len(to_transmit) - 1 current_pnr += 1 if self.prn == current_pnr: current_pnr = 0 response = self.__get_checksum_response() validate_crc() response = self.__calculate_checksum() validate_crc() return crc def __get_response(self, operation): def get_dict_key(dictionary, value): return next( (key for key, val in list(dictionary.items()) if val == value), None) resp = self.dfu_adapter.get_message() if resp is None: return None if resp[0] != DfuTransportSerial.OP_CODE['Response']: raise NordicSemiException('No Response: 0x{:02X}'.format(resp[0])) if resp[1] != operation: raise NordicSemiException('Unexpected Executed OP_CODE.\n' \ + 'Expected: 0x{:02X} Received: 0x{:02X}'.format(operation, resp[1])) if resp[2] == DfuTransport.RES_CODE['Success']: return resp[3:] elif resp[2] == DfuTransport.RES_CODE['ExtendedError']: try: data = DfuTransport.EXT_ERROR_CODE[resp[3]] except IndexError: data = "Unsupported extended error type {}".format(resp[3]) raise NordicSemiException('Extended Error 0x{:02X}: {}'.format( resp[3], data)) else: raise NordicSemiException('Response Code {}'.format( get_dict_key(DfuTransport.RES_CODE, resp[2])))
class Modem(): #Serial port settings read_buffer_size = 1024 #Some constants linesep = '\r\n' ok_response = 'OK' error_response = 'ERROR' clcc_header = "+CLCC:" clip_header = "+CLIP:" clcc_enabled = False #Status storage variables status = {"state": "idle", "type": None} #The Caller ID variable - is set when a call is received and cleard when a call ends #When set, it looks like this: #current_callerid = {"number":"something", "type":"unknown"/"international"/"national"/"network-specific"} current_callerid = None def __init__(self, serial_path="/dev/ttyAMA0", serial_timeout=0.5, read_timeout=0.2): self.serial_path = serial_path self.serial_timeout = serial_timeout self.read_timeout = read_timeout self.executing_command = Event() self.should_monitor = Event() self.unexpected_queue = Queue() def init_modem(self): self.port = Serial(self.serial_path, 115200, timeout=self.serial_timeout) self.at() self.enable_verbosity() print("Battery voltage is: {}".format(self.get_voltage())) self.enable_clcc() self.enable_clip() self.set_message_mode("pdu") #self.at_command("AT+CSSN=1,1") self.save_settings() def deinit_modem(self): try: self.port.close() except: #Could be not created or already closed pass #Functions that the user will be calling def call(self, number): #ATD in CLCC is going to generate CLCC data straight away, #so that's going into the queue to be processed separately response = self.at_command("ATD{};".format(number), nook=True) self.queue_unexpected_data(response) return True def ussd(self, string): result = self.at_command('AT+CUSD=1,"{}"'.format(string)) def hangup(self): return self.at_command("ATH", noresponse=True) def answer(self): return self.at_command("ATA") #Debugging helpers def pprint_status(self): print("--------------------------") print("New state: {}".format(self.status["state"])) if self.current_callerid: print("Caller ID: {}, type: {}".format( self.current_callerid["number"], self.current_callerid["type"])) def print_callerid(self, callerid): if self.current_callerid: print("Incoming: {} ({})".format(self.current_callerid["number"], self.current_callerid["type"])) #Call state set function - that also calls a callback def set_state(self, key, value): self.status[key] = value if callable(self.update_state_cb): self.update_state_cb(key, value) #Callbacks that change the call state and clean state variables #Not to be overridden directly as they might have desirable side effects #Also, they're called in a hackish way and overriding would fail anyway #Call-specific callbacks # "0":on_talking, def on_talking(self): #Call answered, voice comms established self.set_state("state", "talking") #self.pprint_status() # "1":on_held, def on_held(self): #Held call signal if self.status["type"] == "incoming": self.set_state("state", "held") else: self.set_state("state", "holding") #self.pprint_status() # "2":on_dialing, def on_dialing(self): assert (self.status["type"] == "outgoing") self.set_state("state", "dialing") #self.pprint_status() # "3":on_alerting, def on_alerting(self): assert (self.status["type"] == "outgoing") self.set_state("state", "alerting") #self.pprint_status() # "4":on_incoming, def on_incoming(self): assert (self.status["type"] == "incoming") self.set_state("state", "incoming_call") #self.pprint_status() # "5":on_waiting, def on_waiting(self): assert (self.status["type"] == "incoming") self.set_state("state", "incoming") #self.pprint_status() # "6":on_disconnect def on_disconnect(self, incoming=True): #Either finished or missed call if self.status["type"] == "incoming" and self.status["state"] not in [ "held", "talking" ]: self.set_state("state", "missed_call") else: self.set_state("state", "finished") Timer(3, self.on_idle).start() #self.pprint_status() def on_idle(self): #Cleans up variables and sets state to "idle" #Only runs from threading.Timer since modem sends no "idle" CLCC message #Safety check to ensure this doesn't run during a call #if call happens right after previous call ends: if self.status["state"] not in ["active_call", "held"]: self.current_callerid = None self.set_state("state", "idle") self.set_state("type", None) #self.pprint_status() #SMS callbacks def on_incoming_message(self, cmti_line): #New message signal print("You've got mail! Line: {}".format( cmti_line[len("+CMTI:"):]).strip()) self.read_all_messages() def read_all_messages(self): prev_timeout = self.serial_timeout self.serial_timeout = 1 #TODO: get message count and base timeout on that output = self.at_command("AT+CMGL") self.serial_timeout = prev_timeout if len(output) % 2 == 1: print("CMGL output lines not in pairs?") print("PDATA: {}".format(repr(output))) return False cmgl_header = "+CMGL: " for i in range(len(output) / 2): header = output[i * 2] if not header.startswith(cmgl_header): print( "Line presumed to be CMGL doesn't start with CMGL header!") continue id, x, x, pdu_len = header[len(cmgl_header):].split(",") smsc_pdu_str = output[(i * 2) + 1] self.decode_message(smsc_pdu_str, pdu_len, id) def decode_message(self, smsc_pdu_str, pdu_len, id): print("Reading message {}".format(id)) pdu_len = int(pdu_len) #Just in case smsc_len = len( smsc_pdu_str) - pdu_len * 2 #We get PDU length in octets if smsc_len == 0: print("No SMSC in PDU - seems like it can happen!") pdu_str = smsc_pdu_str[smsc_len:] #Discarding SMSC info #SMSC info might actually be useful in the future - maybe its spoofing could be detected? Does it even happen? smspdu.pdu.dump(pdu_str) #Non-CLCC exclusive callbacks #(the non-CLCC path might not even work that well, for what I know) def on_ring(self): print("Ring ring ring bananaphone!") #AT command-controlled modem settings and simple functions def get_manufacturer(self): return self.at_command("AT+CGMI") def get_model(self): return self.at_command("AT+CGMM") def get_imei(self): return self.at_command("AT+GSN") def save_settings(self): self.at_command("AT&W") def enable_verbosity(self): return self.at_command('AT+CMEE=1') def enable_clcc(self): self.clcc_enabled = True return self.at_command('AT+CLCC=1') def set_message_mode(self, mode_str): if mode_str.lower() == "text": return self.at_command('AT+CMGF=1') elif mode_str.lower() == "pdu": return self.at_command('AT+CMGF=0') else: raise ValueError("Wrong message mode: {}".format(mode_str)) def enable_clip(self): return self.at_command('AT+CLIP=1') def at(self): response = self.at_command('AT') if response is True: return raise ATError(expected=self.ok_response, received=response) #Auxiliary functions that aren't related to phone functionality #TODO: Expose this to an external API of sorts def get_voltage(self): answer = self.at_command('AT+CBC') if not answer.startswith('+CBC'): return 0.0 #TODO - this needs to be better! voltage_str = answer.split(':')[1].split(',')[2] voltage = round(int(voltage_str) / 1000.0, 2) return voltage #Call status and Caller ID message processing code #This is where we get call information info def process_clcc(self, clcc_line): clcc_line = clcc_line[len(self.clcc_header):] clcc_line = clcc_line.strip() elements = clcc_line.split(',') if len(elements) < 5: print("Unrecognized number of CLCC elements!") print("PDATA: " + repr(elements)) return elif len(elements) > 8: print("Too much CLCC elements!") print("PDATA: " + repr(elements)) elements = elements[:8] if len(elements) > 7: #Elements 5 and 6 are present self.set_callerid(elements[5], elements[6]) call_type = elements[1] call_status = elements[2] new_state = "incoming" if call_type == "1" else "outgoing" self.set_state("type", new_state) self.clcc_mapping[call_status](self) def process_clip(self, line): clip_line = line[len(self.clip_header):] clip_line = clip_line.strip() elements = clip_line.split(',') if len(elements) < 2: raise ATError(expected="valid CLIP string with >2 elements", received=line) elif len(elements) < 6: print("Less than 6 CLIP elements, noting") print("PDATA: " + repr(elements)) elif len(elements) > 6: print("Too much CLIP elements, what's wrong?!") print("PDATA: " + repr(elements)) elements = elements[:6] number = elements[0] type_id = elements[1] self.set_callerid(number, type_id) def set_callerid(self, number, type_id): clip_type_mapping = { "129": "unknown", "161": "national", "145": "international", "177": "network-specific" } if type_id not in clip_type_mapping.keys(): print("PDATA: CLIP type id {} not found in type mapping!".format( type_id)) type = "unknown" else: type = clip_type_mapping[type_id] #Setting status variable self.current_callerid = {"number": number.strip('\"'), "type": type} clcc_mapping = { "0": on_talking, "1": on_held, "2": on_dialing, "3": on_alerting, "4": on_incoming, "5": on_waiting, "6": on_disconnect } def on_clcc(self, clcc_line): for i in range(4): if not has_nonascii(clcc_line) or not is_csv(clcc_line): break print("Garbled call info line! Try {}, line: {}".format( i, clcc_line)) sleep(1) clcc_response = self.at_command("AT+CLCC", nook=True) print(repr(lines)) for line in lines: if line.startswith(self.clcc_header): clcc_line = line else: self.queue_unexpected_data(line) if has_nonascii(clcc_line) or not is_csv(clcc_line): print("Still garbled CLCC line!") return #print("Call info OK, line: {}".format(repr(clcc_line[len(self.clcc_header):])).strip()) self.process_clcc(clcc_line) def on_clip(self, line): self.process_clip(line) #Low-level functions def check_input(self): input = self.port.read(self.read_buffer_size) if input: self.queue_unexpected_data(input) def at_command(self, command, noresponse=False, nook=False): self.executing_command.set() self.check_input() self.port.write(command + self.linesep) echo = self.port.read(len(command)) #checking for command echo if echo != command: raise ATError(received=echo, expected=command) #print(repr(self.port.read(len(self.linesep)+1))) self.port.read( len(self.linesep) + 1 ) #shifting through the line separator - that +1 seems to be necessary when we're reading right after the echo if noresponse: return True #one of commands that doesn't need a response answer = self.port.read(self.read_buffer_size) self.executing_command.clear() lines = filter(None, answer.split(self.linesep)) #print(lines) if nook: return lines if self.ok_response not in lines: #expecting OK as one of the elements raise ATError(expected=self.ok_response, received=lines) #We can have a sudden undervoltage warning, though #I'll assume the OK always goes last in the command #So we can pass anything after OK to the unexpected line parser ok_response_index = lines.index(self.ok_response) if ok_response_index + 1 < len(lines): self.queue_unexpected_data(lines[(ok_response_index + 1):]) lines = lines[:(ok_response_index + 1)] if len(lines) == 1: #Single-line response if lines[0] == self.ok_response: return True else: return lines[0] else: lines = lines[:-1] if len(lines) == 1: return lines[0] else: return lines #Functions for background monitoring of any unexpected input def queue_unexpected_data(self, data): self.unexpected_queue.put(data) def process_incoming_data(self, data): logging.debug("Incoming data: {}".format(repr(data))) if isinstance(data, str): data = data.split(self.linesep) lines = filter(None, data) for line in lines: #print(line) #Now onto the callbacks #We should ignore some messages if we're using CLIP #As those messages will appear anyway, but processing them #would be redundant. It could be much prettier, though. if line == "OK": continue if line == "RING": if not self.clcc_enabled: self.on_ring() continue if line == "BUSY": if not self.clcc_enabled: self.on_busy() continue if line == "HANGUP": if not self.clcc_enabled: self.on_hangup() continue if line == "NO ANSWER": if not self.clcc_enabled: self.on_noanswer() continue if line == "NO CARRIER": if not self.clcc_enabled: self.on_nocarrier() continue if line in ["SMS Ready", "Call Ready"]: continue #Modem just reset if line.startswith("+CMTI:"): self.on_incoming_message(line) continue if line.startswith(self.clcc_header): self.on_clcc(line) continue if line.startswith(self.clip_header): self.on_clip(line) continue self.parse_unexpected_message(line) def parse_unexpected_message(self, data): #haaaax if self.linesep[::-1] in "".join(data): lines = "".join(data).split(self.linesep[::-1]) logging.debug("Unexpected line: {}".format(data)) print("Unexpected line: {}".format(data)) #The monitor thread - it receives data from the modem and calls callbacks def monitor(self): while self.should_monitor.isSet(): #print("Monitoring...") if not self.executing_command.isSet(): #First, the serial port #print("Reading data through serial!") data = self.port.read(self.read_buffer_size) if data: print("Got data through serial!") self.process_incoming_data(data) #Then, the queue of unexpected messages received from other commands #print("Reading data from queue!") try: data = self.unexpected_queue.get_nowait() except Empty: pass else: print("Got data from queue!") self.process_incoming_data(data) #print("Got to sleep") sleep(self.serial_timeout) #print("Returned from sleep") #try: # print(modem.at_command("AT+CPAS")) #except: # print("CPAS exception") print("Stopped monitoring!") def start_monitoring(self): self.should_monitor.set() self.thread = Thread(target=self.monitor) self.thread.daemon = True self.thread.start() def stop_monitoring(self): self.should_monitor.clear()
class Ev3: class _MsgType: class Mode: def __init__(self, first, second): self.second = second self.first = first speed = Mode(10, 165) start = Mode(8, 166) stop = Mode(9, 163) class Motors: A = 0b1 B = 0b10 C = 0b100 D = 0b1000 class Stop: FLOAT = 0 BREAK = 1 def __init__(self, port_name): self._controller = Serial(port_name, baudrate=9600, stopbits=serial.STOPBITS_ONE, parity=serial.PARITY_NONE, bytesize=serial.EIGHTBITS) time.sleep(1) self._lock = threading.Lock() def set_speed(self, motor, val): message = self._pack_msg(self._MsgType.speed) if val > 127: val = 127 if val < -127: val = -127 if val < 0: val = 255 - abs(val) for i in range(0, 3): message.append(0) message[9] = motor message[10] = 129 message[11] = val self._send(message) def start(self, motor): message = self._pack_msg(self._MsgType.start) for i in range(0, 1): message.append(0) message[9] = motor self._send(message) def stop(self, motor, type): message = self._pack_msg(self._MsgType.stop) for i in range(0, 2): message.append(0) message[9] = motor message[10] = type self._send(message) def _send(self, message): try: self._lock.acquire() self._controller.write(bytes(message)) finally: self._lock.release() @staticmethod def _pack_msg(mode): msg = [0 for i in range(9)] msg[0] = mode.first msg[7] = mode.second msg[4] = 128 return msg def close(self): self._controller.close() def __del__(self): self.close()
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()
class printcore(): def __init__(self, port=None, baud=None, dtr=None): """Initializes a printcore instance. Pass the port and baud rate to connect immediately""" self.baud = None self.dtr = None self.port = None self.analyzer = gcoder.GCode() # Serial instance connected to the printer, should be None when # disconnected self.printer = None # clear to send, enabled after responses # FIXME: should probably be changed to a sliding window approach self.clear = 0 # The printer has responded to the initial command and is active self.online = False # is a print currently running, true if printing, false if paused self.printing = False self.mainqueue = None self.priqueue = Queue(0) self.queueindex = 0 self.lineno = 0 self.resendfrom = -1 self.paused = False self.sentlines = {} self.log = deque(maxlen=10000) self.sent = [] self.writefailures = 0 self.tempcb = None # impl (wholeline) self.recvcb = None # impl (wholeline) self.sendcb = None # impl (wholeline) self.preprintsendcb = None # impl (wholeline) self.printsendcb = None # impl (wholeline) self.layerchangecb = None # impl (wholeline) self.errorcb = None # impl (wholeline) self.startcb = None # impl () self.endcb = None # impl () self.onlinecb = None # impl () self.loud = False # emit sent and received lines to terminal self.tcp_streaming_mode = False self.greetings = ['start', 'Grbl '] self.wait = 0 # default wait period for send(), send_now() self.read_thread = None self.stop_read_thread = False self.send_thread = None self.stop_send_thread = False self.print_thread = None self.readline_buf = [] self.selector = None self.event_handler = PRINTCORE_HANDLER # Not all platforms need to do this parity workaround, and some drivers # don't support it. Limit it to platforms that actually require it # here to avoid doing redundant work elsewhere and potentially breaking # things. self.needs_parity_workaround = platform.system( ) == "linux" and os.path.exists("/etc/debian") for handler in self.event_handler: try: handler.on_init() except: logging.error(traceback.format_exc()) if port is not None and baud is not None: self.connect(port, baud) self.xy_feedrate = None self.z_feedrate = None def addEventHandler(self, handler): ''' Adds an event handler. @param handler: The handler to be added. ''' self.event_handler.append(handler) def logError(self, error): for handler in self.event_handler: try: handler.on_error(error) except: logging.error(traceback.format_exc()) if self.errorcb: try: self.errorcb(error) except: logging.error(traceback.format_exc()) else: logging.error(error) @locked def disconnect(self): """Disconnects from printer and pauses the print """ if self.printer: if self.read_thread: self.stop_read_thread = True if threading.current_thread() != self.read_thread: self.read_thread.join() self.read_thread = None if self.print_thread: self.printing = False self.print_thread.join() self._stop_sender() try: if self.selector is not None: self.selector.unregister(self.printer_tcp) self.selector.close() self.selector = None if self.printer_tcp is not None: self.printer_tcp.close() self.printer_tcp = None self.printer.close() except socket.error: logger.error(traceback.format_exc()) pass except OSError: logger.error(traceback.format_exc()) pass for handler in self.event_handler: try: handler.on_disconnect() except: logging.error(traceback.format_exc()) self.printer = None self.online = False self.printing = False @locked def connect(self, port=None, baud=None, dtr=None): """Set port and baudrate if given, then connect to printer """ if self.printer: self.disconnect() if port is not None: self.port = port if baud is not None: self.baud = baud if dtr is not None: self.dtr = dtr if self.port is not None and self.baud is not None: # Connect to socket if "port" is an IP, device if not host_regexp = re.compile( "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$|^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$" ) is_serial = True if ":" in self.port: bits = self.port.split(":") if len(bits) == 2: hostname = bits[0] try: port_number = int(bits[1]) if host_regexp.match( hostname) and 1 <= port_number <= 65535: is_serial = False except: pass self.writefailures = 0 if not is_serial: self.printer_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.printer_tcp.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) self.timeout = 0.25 self.printer_tcp.settimeout(1.0) try: self.printer_tcp.connect((hostname, port_number)) #a single read timeout raises OSError for all later reads #probably since python 3.5 #use non blocking instead self.printer_tcp.settimeout(0) self.printer = self.printer_tcp.makefile('rwb', buffering=0) self.selector = selectors.DefaultSelector() self.selector.register(self.printer_tcp, selectors.EVENT_READ) except socket.error as e: if (e.strerror is None): e.strerror = "" self.logError( _("Could not connect to %s:%s:") % (hostname, port_number) + "\n" + _("Socket error %s:") % e.errno + "\n" + e.strerror) self.printer = None self.printer_tcp = None return else: disable_hup(self.port) self.printer_tcp = None try: if self.needs_parity_workaround: self.printer = Serial(port=self.port, baudrate=self.baud, timeout=0.25, parity=PARITY_ODD) self.printer.close() self.printer.parity = PARITY_NONE else: self.printer = Serial(baudrate=self.baud, timeout=0.25, parity=PARITY_NONE) self.printer.port = self.port try: #this appears not to work on many platforms, so we're going to call it but not care if it fails self.printer.dtr = dtr except: #self.logError(_("Could not set DTR on this platform")) #not sure whether to output an error message pass self.printer.open() except SerialException as e: self.logError( _("Could not connect to %s at baudrate %s:") % (self.port, self.baud) + "\n" + _("Serial error: %s") % e) self.printer = None return except IOError as e: self.logError( _("Could not connect to %s at baudrate %s:") % (self.port, self.baud) + "\n" + _("IO error: %s") % e) self.printer = None return for handler in self.event_handler: try: handler.on_connect() except: logging.error(traceback.format_exc()) self.stop_read_thread = False self.read_thread = threading.Thread(target=self._listen, name='read thread') self.read_thread.start() self._start_sender() def reset(self): """Reset the printer """ if self.printer and not self.printer_tcp: self.printer.dtr = 1 time.sleep(0.2) self.printer.dtr = 0 def _readline_buf(self): "Try to readline from buffer" if len(self.readline_buf): chunk = self.readline_buf[-1] eol = chunk.find(b'\n') if eol >= 0: line = b''.join(self.readline_buf[:-1]) + chunk[:(eol + 1)] self.readline_buf = [] if eol + 1 < len(chunk): self.readline_buf.append(chunk[(eol + 1):]) return line return PR_AGAIN def _readline_nb(self): "Non blocking readline. Socket based files do not support non blocking or timeouting readline" if self.printer_tcp: line = self._readline_buf() if line: return line chunk_size = 256 while True: chunk = self.printer.read(chunk_size) if chunk is SYS_AGAIN and self.selector.select(self.timeout): chunk = self.printer.read(chunk_size) #print('_readline_nb chunk', chunk, type(chunk)) if chunk: self.readline_buf.append(chunk) line = self._readline_buf() if line: return line elif chunk is SYS_AGAIN: return PR_AGAIN else: #chunk == b'' means EOF line = b''.join(self.readline_buf) self.readline_buf = [] self.stop_read_thread = True return line if line else PR_EOF else: # serial port return self.printer.readline() def _readline(self): try: line_bytes = self._readline_nb() if line_bytes is PR_EOF: self.logError( _("Can't read from printer (disconnected?). line_bytes is None" )) return PR_EOF line = line_bytes.decode('utf-8') if len(line) > 1: self.log.append(line) for handler in self.event_handler: try: handler.on_recv(line) except: logging.error(traceback.format_exc()) if self.recvcb: try: self.recvcb(line) except: self.logError(traceback.format_exc()) if self.loud: logging.info("RECV: %s" % line.rstrip()) return line except UnicodeDecodeError: self.logError( _("Got rubbish reply from %s at baudrate %s:") % (self.port, self.baud) + "\n" + _("Maybe a bad baudrate?")) return None except SelectError as e: if 'Bad file descriptor' in e.args[1]: self.logError( _("Can't read from printer (disconnected?) (SelectError {0}): {1}" ).format(e.errno, decode_utf8(e.strerror))) return None else: self.logError( _("SelectError ({0}): {1}").format(e.errno, decode_utf8( e.strerror))) raise except SerialException as e: self.logError( _("Can't read from printer (disconnected?) (SerialException): {0}" ).format(decode_utf8(str(e)))) return None except socket.error as e: self.logError( _("Can't read from printer (disconnected?) (Socket error {0}): {1}" ).format(e.errno, decode_utf8(e.strerror))) return None except OSError as e: if e.errno == errno.EAGAIN: # Not a real error, no data was available return "" self.logError( _("Can't read from printer (disconnected?) (OS Error {0}): {1}" ).format(e.errno, e.strerror)) return None def _listen_can_continue(self): if self.printer_tcp: return not self.stop_read_thread and self.printer return (not self.stop_read_thread and self.printer and self.printer.is_open) def _listen_until_online(self): while not self.online and self._listen_can_continue(): self._send("M105") if self.writefailures >= 4: logging.error( _("Aborting connection attempt after 4 failed writes.")) return empty_lines = 0 while self._listen_can_continue(): line = self._readline() if line is None: break # connection problem # workaround cases where M105 was sent before printer Serial # was online an empty line means read timeout was reached, # meaning no data was received thus we count those empty lines, # and once we have seen 15 in a row, we just break and send a # new M105 # 15 was chosen based on the fact that it gives enough time for # Gen7 bootloader to time out, and that the non received M105 # issues should be quite rare so we can wait for a long time # before resending if not line: empty_lines += 1 if empty_lines == 15: break else: empty_lines = 0 if line.startswith(tuple(self.greetings)) \ or line.startswith('ok') or "T:" in line: self.online = True for handler in self.event_handler: try: handler.on_online() except: logging.error(traceback.format_exc()) if self.onlinecb: try: self.onlinecb() except: self.logError(traceback.format_exc()) return def _listen(self): """This function acts on messages from the firmware """ self.clear = True if not self.printing: self._listen_until_online() while self._listen_can_continue(): line = self._readline() if line is None: logging.debug('_readline() is None, exiting _listen()') break if line.startswith('DEBUG_'): continue if line.startswith(tuple(self.greetings)) or line.startswith('ok'): self.clear = True if line.startswith('ok') and "T:" in line: for handler in self.event_handler: try: handler.on_temp(line) except: logging.error(traceback.format_exc()) if self.tempcb: # callback for temp, status, whatever try: self.tempcb(line) except: self.logError(traceback.format_exc()) elif line.startswith('Error'): self.logError(line) # Teststrings for resend parsing # Firmware exp. result # line="rs N2 Expected checksum 67" # Teacup 2 if line.lower().startswith("resend") or line.startswith("rs"): for haystack in ["N:", "N", ":"]: line = line.replace(haystack, " ") linewords = line.split() while len(linewords) != 0: try: toresend = int(linewords.pop(0)) self.resendfrom = toresend break except: pass self.clear = True self.clear = True logging.debug('Exiting read thread') def _start_sender(self): self.stop_send_thread = False self.send_thread = threading.Thread(target=self._sender, name='send thread') self.send_thread.start() def _stop_sender(self): if self.send_thread: self.stop_send_thread = True self.send_thread.join() self.send_thread = None def _sender(self): while not self.stop_send_thread: try: command = self.priqueue.get(True, 0.1) except QueueEmpty: continue while self.printer and self.printing and not self.clear: time.sleep(0.001) self._send(command) while self.printer and self.printing and not self.clear: time.sleep(0.001) def _checksum(self, command): return reduce(lambda x, y: x ^ y, map(ord, command)) def startprint(self, gcode, startindex=0): """Start a print, gcode is an array of gcode commands. returns True on success, False if already printing. The print queue will be replaced with the contents of the data array, the next line will be set to 0 and the firmware notified. Printing will then start in a parallel thread. """ if self.printing or not self.online or not self.printer: return False self.queueindex = startindex self.mainqueue = gcode self.printing = True self.lineno = 0 self.resendfrom = -1 if not gcode or not gcode.lines: return True self.clear = False self._send("M110", -1, True) resuming = (startindex != 0) self.print_thread = threading.Thread(target=self._print, name='print thread', kwargs={"resuming": resuming}) self.print_thread.start() return True def cancelprint(self): self.pause() self.paused = False self.mainqueue = None self.clear = True # run a simple script if it exists, no multithreading def runSmallScript(self, filename): if not filename: return try: with open(filename) as f: for i in f: l = i.replace("\n", "") l = l.partition(';')[0] # remove comments self.send_now(l) except: pass def pause(self): """Pauses the print, saving the current position. """ if not self.printing: return False self.paused = True self.printing = False # ';@pause' in the gcode file calls pause from the print thread if not threading.current_thread() is self.print_thread: try: self.print_thread.join() except: self.logError(traceback.format_exc()) self.print_thread = None # saves the status self.pauseX = self.analyzer.abs_x self.pauseY = self.analyzer.abs_y self.pauseZ = self.analyzer.abs_z self.pauseE = self.analyzer.abs_e self.pauseF = self.analyzer.current_f self.pauseRelative = self.analyzer.relative self.pauseRelativeE = self.analyzer.relative_e def resume(self): """Resumes a paused print.""" if not self.paused: return False # restores the status self.send_now("G90") # go to absolute coordinates xyFeed = '' if self.xy_feedrate is None else ' F' + str( self.xy_feedrate) zFeed = '' if self.z_feedrate is None else ' F' + str(self.z_feedrate) self.send_now("G1 X%s Y%s%s" % (self.pauseX, self.pauseY, xyFeed)) self.send_now("G1 Z" + str(self.pauseZ) + zFeed) self.send_now("G92 E" + str(self.pauseE)) # go back to relative if needed if self.pauseRelative: self.send_now("G91") if self.pauseRelativeE: self.send_now('M83') # reset old feed rate self.send_now("G1 F" + str(self.pauseF)) self.paused = False self.printing = True self.print_thread = threading.Thread(target=self._print, name='print thread', kwargs={"resuming": True}) self.print_thread.start() def send(self, command, wait=0): """Adds a command to the checksummed main command queue if printing, or sends the command immediately if not printing""" if self.online: if self.printing: self.mainqueue.append(command) else: self.priqueue.put_nowait(command) else: self.logError(_("Not connected to printer.")) def send_now(self, command, wait=0): """Sends a command to the printer ahead of the command queue, without a checksum""" if self.online: self.priqueue.put_nowait(command) else: self.logError(_("Not connected to printer.")) def _print(self, resuming=False): self._stop_sender() try: for handler in self.event_handler: try: handler.on_start(resuming) except: logging.error(traceback.format_exc()) if self.startcb: # callback for printing started try: self.startcb(resuming) except: self.logError( _("Print start callback failed with:") + "\n" + traceback.format_exc()) while self.printing and self.printer and self.online: self._sendnext() self.sentlines = {} self.log.clear() self.sent = [] for handler in self.event_handler: try: handler.on_end() except: logging.error(traceback.format_exc()) if self.endcb: # callback for printing done try: self.endcb() except: self.logError( _("Print end callback failed with:") + "\n" + traceback.format_exc()) except: self.logError( _("Print thread died due to the following error:") + "\n" + traceback.format_exc()) finally: self.print_thread = None self._start_sender() def process_host_command(self, command): """only ;@pause command is implemented as a host command in printcore, but hosts are free to reimplement this method""" command = command.lstrip() if command.startswith(";@pause"): self.pause() def _sendnext(self): if not self.printer: return while self.printer and self.printing and not self.clear: time.sleep(0.001) # Only wait for oks when using serial connections or when not using tcp # in streaming mode if not self.printer_tcp or not self.tcp_streaming_mode: self.clear = False if not (self.printing and self.printer and self.online): self.clear = True return if self.resendfrom < self.lineno and self.resendfrom > -1: self._send(self.sentlines[self.resendfrom], self.resendfrom, False) self.resendfrom += 1 return self.resendfrom = -1 if not self.priqueue.empty(): self._send(self.priqueue.get_nowait()) self.priqueue.task_done() return if self.printing and self.mainqueue.has_index(self.queueindex): (layer, line) = self.mainqueue.idxs(self.queueindex) gline = self.mainqueue.all_layers[layer][line] if self.queueindex > 0: (prev_layer, prev_line) = self.mainqueue.idxs(self.queueindex - 1) if prev_layer != layer: for handler in self.event_handler: try: handler.on_layerchange(layer) except: logging.error(traceback.format_exc()) if self.layerchangecb and self.queueindex > 0: (prev_layer, prev_line) = self.mainqueue.idxs(self.queueindex - 1) if prev_layer != layer: try: self.layerchangecb(layer) except: self.logError(traceback.format_exc()) for handler in self.event_handler: try: handler.on_preprintsend(gline, self.queueindex, self.mainqueue) except: logging.error(traceback.format_exc()) if self.preprintsendcb: if self.mainqueue.has_index(self.queueindex + 1): (next_layer, next_line) = self.mainqueue.idxs(self.queueindex + 1) next_gline = self.mainqueue.all_layers[next_layer][ next_line] else: next_gline = None gline = self.preprintsendcb(gline, next_gline) if gline is None: self.queueindex += 1 self.clear = True return tline = gline.raw if tline.lstrip().startswith(";@"): # check for host command self.process_host_command(tline) self.queueindex += 1 self.clear = True return # Strip comments tline = gcoder.gcode_strip_comment_exp.sub("", tline).strip() if tline: self._send(tline, self.lineno, True) self.lineno += 1 for handler in self.event_handler: try: handler.on_printsend(gline) except: logging.error(traceback.format_exc()) if self.printsendcb: try: self.printsendcb(gline) except: self.logError(traceback.format_exc()) else: self.clear = True self.queueindex += 1 else: self.printing = False self.clear = True if not self.paused: self.queueindex = 0 self.lineno = 0 self._send("M110", -1, True) def _send(self, command, lineno=0, calcchecksum=False): # Only add checksums if over serial (tcp does the flow control itself) if calcchecksum and not self.printer_tcp: prefix = "N" + str(lineno) + " " + command command = prefix + "*" + str(self._checksum(prefix)) if "M110" not in command: self.sentlines[lineno] = command if self.printer: self.sent.append(command) # run the command through the analyzer gline = None try: gline = self.analyzer.append(command, store=False) except: logging.warning( _("Could not analyze command %s:") % command + "\n" + traceback.format_exc()) if self.loud: logging.info("SENT: %s" % command) for handler in self.event_handler: try: handler.on_send(command, gline) except: logging.error(traceback.format_exc()) if self.sendcb: try: self.sendcb(command, gline) except: self.logError(traceback.format_exc()) try: self.printer.write((command + "\n").encode('ascii')) if self.printer_tcp: try: self.printer.flush() except socket.timeout: pass self.writefailures = 0 except socket.error as e: if e.errno is None: self.logError( _("Can't write to printer (disconnected ?):") + "\n" + traceback.format_exc()) else: self.logError( _("Can't write to printer (disconnected?) (Socket error {0}): {1}" ).format(e.errno, decode_utf8(e.strerror))) self.writefailures += 1 except SerialException as e: self.logError( _("Can't write to printer (disconnected?) (SerialException): {0}" ).format(decode_utf8(str(e)))) self.writefailures += 1 except RuntimeError as e: self.logError( _("Socket connection broken, disconnected. ({0}): {1}"). format(e.errno, decode_utf8(e.strerror))) self.writefailures += 1
class UBXStreamer: """ UBXStreamer class. """ def __init__(self, port, baudrate, timeout=5): """ Constructor. """ self._serial_object = None self._serial_thread = None self._ubxreader = None self._connected = False self._reading = False self._port = port self._baudrate = baudrate self._timeout = timeout def __del__(self): """ Destructor. """ self.stop_read_thread() self.disconnect() def connect(self): """ Open serial connection. """ try: self._serial_object = Serial(self._port, self._baudrate, timeout=self._timeout) self._ubxreader = UBXReader(BufferedReader(self._serial_object), False) self._connected = True except (SerialException, SerialTimeoutException) as err: print(f"Error connecting to serial port {err}") def disconnect(self): """ Close serial connection. """ if self._connected and self._serial_object: try: self._serial_object.close() except (SerialException, SerialTimeoutException) as err: print(f"Error disconnecting from serial port {err}") self._connected = False def start_read_thread(self): """ Start the serial reader thread. """ if self._connected: self._reading = True self._serial_thread = Thread(target=self._read_thread, daemon=True) self._serial_thread.start() def stop_read_thread(self): """ Stop the serial reader thread. """ if self._serial_thread is not None: self._reading = False def send(self, data): """ Send data to serial connection. """ self._serial_object.write(data) def flush(self): """ Flush input buffer """ self._serial_object.reset_input_buffer() def waiting(self): """ Check if any messages remaining in the input buffer """ return self._serial_object.in_waiting def _read_thread(self): """ THREADED PROCESS Reads and parses UBX message data from stream """ while self._reading and self._serial_object: if self._serial_object.in_waiting: try: (_, parsed_data) = self._ubxreader.read() if parsed_data: print(parsed_data) except ( ube.UBXStreamError, ube.UBXMessageError, ube.UBXTypeError, ube.UBXParseError, ) as err: print(f"Something went wrong {err}") continue def poll_uart(self, layer=0): """ Poll the current BBR UART1/2 configuration """ position = 0 keys = ["CFG_UART1_BAUDRATE", "CFG_UART2_BAUDRATE"] msg = UBXMessage.config_poll(layer, position, keys) ubp.send(msg.serialize()) def set_uart(self, layers=1): """ Set the current BBR UART1/2 configuration """ transaction = 0 cfgData = [("CFG_UART1_BAUDRATE", 115200), ("CFG_UART2_BAUDRATE", 57600)] msg = UBXMessage.config_set(layers, transaction, cfgData) ubp.send(msg.serialize()) def unset_uart(self, layers=1): """ Unset (del) the current BBR UART1/2 configuration """ transaction = 0 keys = ["CFG_UART1_BAUDRATE", "CFG_UART2_BAUDRATE"] msg = UBXMessage.config_del(layers, transaction, keys) ubp.send(msg.serialize())
class Serial_instrument(Instrument): def __init__(self): # Initialize shared Instrument superclass attributes... super().__init__() self.ser = Serial() self.ser.baudrate = self.baudrate self.ser.timeout = self.timeout self.port = None self.capfile = "save/Serial_instrument.log" # Default should be overridden in instrument-specific module self.echo = False # Flag to enable printing to user display whatever is written to capfile def set_timeout(self, t): self.ser.timeout = t def set_baudrate(self, b): self.ser.baudrate = b def set_serialport(self): ports = [port for port in list_ports.comports()] portmenu = [ "%s - %s" % (port.device, port.description) for port in ports ] # Present port selection menu to user... userselection = common.dynamicmenu_get("Select an available port", portmenu, lastitem=('C', 'Cancel')) if not userselection: # Cancelled by user... return False port_id = int(userselection) self.port = ports[port_id] self.ser.port = self.port[0] return True def serialport_open(self): """Open connection to a serial port and initialize a log file.""" while not self.port: # No port chosen, try to choose one... if not self.set_serialport(): again = input("Would you like to try to connect again? y/[n] ") if again.lower() != "y": # Cancelled by user... return False try: #print("Setting a %d sec timeout..." % self.ser.timeout) self.ser.open() except BaseException as msg: input("\nError! %s [Press ENTER to continue]..." % msg) return False print("Connected to %s." % self.port) with open(self.capfile, "w") as capfile: self.capfileheader = " ".join( ("=" * 22, "Session log - %s" % dt.now().strftime("%Y/%m/%d %H:%M:%S"), "=" * 22, "\r\n")) capfile.write(self.capfileheader) return True def cap_cmd(self, cmd): """ Send a single commmand cmd to an instrument. Write the reply to the capture file. If instrument echoes the command, the command will also be captured. """ self.ser.reset_input_buffer() self.send_cmd(cmd) self.cap_buf() return True def get_cmd(self, cmd): """ Use this to send a command to an instrument using cap_cmd, then return the contents of the reply buffer """ self.cap_cmd(cmd) return self.buf def send_cmd(self, cmd): return self.ser.write((cmd + '\r\n').encode('ascii')) def read_reply(self): # Read incoming serial input and store in a buffer until no new bytes are # received for duration of the timeout. self.buf = self.ser.read(self.ser.in_waiting).decode('ascii') while True: cur = self.buf self.buf += self.ser.read(1).decode('ascii') if cur == self.buf: return True def cap_buf(self): # Read serial input and append to the capture file. self.read_reply() self.capfile_append(self.buf) return True def connect(self): # Wrapper to open a serial connection. while not self.connected(): if not self.serialport_open(): common.usercancelled() return True return True def connected(self): # Wrapper to test for open serial port. Returns True of False. return self.ser.is_open def disconnect(self): # Wrapper to close a serial connection. Returns True or False. self.ser.close() return not self.ser.is_open def capfile_append(self, lines): # Append text to a capture file. Pass text to append as lines. with open(self.capfile, 'a') as capfile: capfile.write(lines) if self.echo: print(lines) def buffer_empty(self): # Check for unread bytes in serial input buffer. Returns True of False. if not self.ser.in_waiting: return True else: return False def rename_capfile(self, dst): # Renames the active capture file. Useful when title is not known at the time # the capture file is first opened. This will silently clobber the destination # file if it already exists. if common.rename_file(self.capfile, dst): return True else: return False
from serial import Serial import time serial_port = Serial(port='/dev/cu.usbmodem143101', baudrate=9600) if serial_port.isOpen(): serial_port.close() serial_port.open() time.sleep(1) lu = serial_port.readline() chaine = lu.decode('ascii') print(chaine) serial_port.write(b'HELLO \r') time.sleep(1) lu = serial_port.readline() chaine = lu.decode('ascii') print(chaine) print("entrer quit pour quitter") while 1: commande = input("Entrez une commande : ") if commande == 'quit': break commande += "\r" serial_port.write(commande.encode()) serial_port.close()
class ComConnection(object): """Serial wrapper which can be instantiated using serial number""" def __init__(self, serial_number=None, command=None, baudrate=9600): """ Constructor Parameters ---------- serial_number: string The usb-serial's serial number command: string Command to be send baudrate: int Baud rate such as 9600 or 115200 etc. Default is 9600 """ self.serial_number = serial_number self.command = command self.serial = Serial() self.serial.baudrate = baudrate def __del__(self): """Destructor""" try: self.close() except: pass # errors on shutdown def __str__(self): return "SRN: {} Command: {}".format(self.serial_number, self.command) def get_device_name(self, serial_number): """ Get full device name/path from serial number Parameters ---------- serial_number: string The usb-serial's serial number Returns ------- string Full device name/path, e.g. /dev/ttyUSBx (on *.nix system or COMx on Windows) Raises ------ IOError When not found device with this serial number """ serial_numbers = [] for pinfo in comports(): if str(pinfo.serial_number).strip() == str(serial_number).strip(): return pinfo.device # save list of serial numbers for user reference serial_numbers.append(pinfo.serial_number.encode('utf-8')) raise IOError('Could not find device with provided serial number {}Found devices with following serial numbers: {}{}'.format(linesep, linesep, serial_numbers)) def connect(self): """ Open/connect to serial port """ # open serial port try: device = self.get_device_name(self.serial_number) self.serial.port = device # Set RTS line to low logic level self.serial.rts = False self.serial.open() except Exception as ex: self.handle_serial_error(ex) def send_command(self): """ Send data/command to serial port """ if self.serial.is_open: try: # Unicode strings must be encoded data = self.command.encode('utf-8') self.serial.write(data) except Exception as ex: self.handle_serial_error(ex) else: raise IOError('Try to send data when the connection is closed') def receive_command(self): """Receive command from serial port""" if self.serial.is_open: return self.serial.read_all() def close(self): """Close all resources""" self.serial.close() def handle_serial_error(self, error=None): """Serial port error""" # terminate connection self.close() # forward exception if isinstance(error, Exception): raise error # pylint: disable-msg=E0702
class UBXStreamer: """ UBXStreamer class. """ def __init__(self, port, baudrate, timeout=5): """ Constructor. """ self._serial_object = None self._serial_thread = None self._ubxreader = None self._connected = False self._reading = False self._port = port self._baudrate = baudrate self._timeout = timeout def __del__(self): """ Destructor. """ self.stop_read_thread() self.disconnect() def connect(self): """ Open serial connection. """ try: self._serial_object = Serial(self._port, self._baudrate, timeout=self._timeout) self._ubxreader = UBXReader(BufferedReader(self._serial_object), False) self._connected = True except (SerialException, SerialTimeoutException) as err: print(f"Error connecting to serial port {err}") def disconnect(self): """ Close serial connection. """ if self._connected and self._serial_object: try: self._serial_object.close() except (SerialException, SerialTimeoutException) as err: print(f"Error disconnecting from serial port {err}") self._connected = False def start_read_thread(self): """ Start the serial reader thread. """ if self._connected: self._reading = True self._serial_thread = Thread(target=self._read_thread, daemon=False) self._serial_thread.start() def stop_read_thread(self): """ Stop the serial reader thread. """ if self._serial_thread is not None: self._reading = False self._serial_thread.join() def send(self, data): """ Send data to serial connection. """ self._serial_object.write(data) def flush(self): """ Flush input buffer """ self._serial_object.reset_input_buffer() def waiting(self): """ Check if any messages remaining in the input buffer """ return self._serial_object.in_waiting def _read_thread(self): """ THREADED PROCESS Reads and parses UBX message data from stream """ while self._reading and self._serial_object: if self._serial_object.in_waiting: try: (raw_data, parsed_data) = self._ubxreader.read() # if raw_data: # print(raw_data) if parsed_data: print(parsed_data) except ( ube.UBXStreamError, ube.UBXMessageError, ube.UBXTypeError, ube.UBXParseError, ) as err: print(f"Something went wrong {err}") continue
class SerialSensors: def __init__(self): self.serial = Serial() self.lastReading = "No Data=0\n" self.getParams() self.portSem = Semaphore() self.varSem = Semaphore() self.recThread = Thread(target=self.recieve) self.txThread = Thread(target=self.transmit) def getParams(self): try: f = open("serialParams.config", "r") lines = f.readlines() f.close() lines = [line.replace("\n", "") for line in lines] lines = [line.split("=") for line in lines] params = {} for line in lines: params.update({line[0].lower(): line[1]}) self.serial.port = "COM1" if "port" not in params else params[ "port"] self.serial.baud = 9600 if "baud" not in params else int( params["baud"]) self.serial.timeout = 3 if "timeout" not in params else int( params["timeout"]) except: self.serial.port = "COM1" self.serial.baud = 9600 self.serial.timeout = 3 def recieve(self): while self.run: try: self.portSem.acquire() result = self.serial.readline().decode("utf-8").replace( "\n", "") self.portSem.release() if "=" in result: self.varSem.acquire() self.lastReading = result self.varSem.release() sleep(0.5) except: sleep(0.5) def transmit(self): while self.run: try: self.portSem.acquire() self.serial.write(b".") self.portSem.release() except: pass sleep(2) try: self.portSem.acquire() self.serial.write(b"*") self.portSem.release() except: pass def getData(self): self.varSem.acquire() result = self.lastReading self.varSem.release() return result def start(self): self.serial.open() self.run = True self.recThread.start() self.txThread.start() def stop(self): self.run = False self.txThread.join() self.recThread.join() self.serial.close()
class USBSerial: def __init__(self, port, baudrate, timeout = 0.1, write_timeout = 0.11, open = False): ''' init method if open is set True then call open_serial() ''' self._port = port self._baudrate = baudrate self._timeout = timeout self._write_timeout = write_timeout self.serial = None if open: self.open_serial() @property def port(self): return self._port @port.setter def port(self, port): ''' port setter method if serial was opened - Close serial - Open serial ''' self._port = port if not self.serial: self.close_serial() self.open_serial() @property def baudrate(self): return self._baudrate @property def timeout(self): return self._timeout def open_serial(self): if not self.serial: self.close_serial() try: self.serial = Serial(port = self._port, baudrate = self._baudrate, timeout = self._timeout) except Exception as inst: print(type(inst)) # the exception instance print(inst.args) # arguments stored in .args print(inst) print('Error : Can not open Serial, Retry!') return False return True def close_serial(self): if self.serial: self.serial.close() self.serial = None def write(self, message): if self.serial: if type(message) is not str: message = str(message) message += '\n' self.serial.write(bytes(message.encode())) def readline(self): if not self.serial: if not self.open_serial(): return return self.serial.readline().decode('utf-8').strip() def read(self, size = 1): if not self.serial: if not self.open_serial(): return return self.serial.read(size) def flush(self): self.serial.flush() def test(self): ''' Print out status ''' if self: if self.serial: print('> Serial is opened') else: print('> Serial is not opened') if self.port: print('Port : %s'%(self.port)) if self._baudrate: print('Baudrate : %s'%(self._baudrate)) if self._timeout: print('Timeout : %s'%(self._timeout))
class SerialTNC(APRSPacketSource): """ listens for raw APRS frames being sent over USB `in ASCII text` An example of this is the Kenwood TNC. >>> tnc = SerialTNC(serial_port='COM5') >>> print(tnc.packets) alternatively, set to `'auto'` to connect to the first open serial port >>> tnc = SerialTNC(serial_port='auto') >>> print(tnc.packets) """ def __init__(self, serial_port: str = None, callsigns: List[str] = None): """ Connect to TNC over given serial port. :param serial_port: port name :param callsigns: list of callsigns to return from source """ if serial_port is None or serial_port == "" or serial_port == "auto": try: serial_port = next_open_serial_port() except ConnectionError: raise ConnectionError("could not find TNC connected to serial") else: serial_port = serial_port.strip('"') self.serial_connection = Serial(serial_port, baudrate=9600, timeout=1) super().__init__(self.serial_connection.port, callsigns) self.__last_access_time = None @property def packets(self) -> List[APRSPacket]: if self.__last_access_time is not None and self.interval is not None: interval = datetime.now() - self.__last_access_time if interval < self.interval: raise TimeIntervalError( f"interval {interval} less than minimum interval {self.interval}" ) packets = [] for line in self.serial_connection.readlines(): try: packet = APRSPacket.from_frame(line, source=self.location) packets.append(packet) except Exception as error: logging.error(f"{error.__class__.__name__} - {error}") if self.callsigns is not None: packets = [ packet for packet in packets if packet.from_callsign in self.callsigns ] self.__last_access_time = datetime.now() return packets def close(self): self.serial_connection.close() def __repr__(self): return ( f"{self.__class__.__name__}({repr(self.location)}, {repr(self.callsigns)})" )
class Arduino: ''' Configuration Parameters ''' N_ANALOG_PORTS = 6 N_DIGITAL_PORTS = 12 def __init__(self, port="/dev/ttyUSB0", baudrate=57600, timeout=0.5): self.PID_RATE = 30 # Do not change this! It is a fixed property of the Arduino PID controller. self.PID_INTERVAL = 1000 / 30 self.port = port self.baudrate = baudrate self.timeout = timeout self.encoder_count = 0 self.writeTimeout = timeout self.interCharTimeout = timeout / 30. # Keep things thread safe self.mutex = thread.allocate_lock() # An array to cache analog sensor readings self.analog_sensor_cache = [None] * self.N_ANALOG_PORTS # An array to cache digital sensor readings self.digital_sensor_cache = [None] * self.N_DIGITAL_PORTS def connect(self): try: print "Connecting to Arduino on port", self.port, "..." self.port = Serial(port=self.port, baudrate=self.baudrate, timeout=self.timeout, writeTimeout=self.writeTimeout) # The next line is necessary to give the firmware time to wake up. time.sleep(1) test = self.get_baud() if test != self.baudrate: time.sleep(1) test = self.get_baud() if test != self.baudrate: raise SerialException print "Connected at", self.baudrate print "Arduino is ready." except SerialException: print "Serial Exception:" print sys.exc_info() print "Traceback follows:" traceback.print_exc(file=sys.stdout) print "Cannot connect to Arduino!" os._exit(1) def open(self): ''' Open the serial port. ''' self.port.open() def close(self): ''' Close the serial port. ''' self.port.close() def send(self, cmd): ''' This command should not be used on its own: it is called by the execute commands below in a thread safe manner. ''' self.port.write(cmd + '\r') def recv(self, timeout=0.5): timeout = min(timeout, self.timeout) ''' This command should not be used on its own: it is called by the execute commands below in a thread safe manner. Note: we use read() instead of readline() since readline() tends to return garbage characters from the Arduino ''' c = '' value = '' attempts = 0 while c != '\r': c = self.port.read(1) value += c attempts += 1 if attempts * self.interCharTimeout > timeout: return None value = value.strip('\r') return value def recv_ack(self): ''' This command should not be used on its own: it is called by the execute commands below in a thread safe manner. ''' ack = self.recv(self.timeout) return ack == 'OK' def recv_int(self): ''' This command should not be used on its own: it is called by the execute commands below in a thread safe manner. ''' value = self.recv(self.timeout) try: return int(value) except: return None def recv_array(self): ''' This command should not be used on its own: it is called by the execute commands below in a thread safe manner. ''' try: values = self.recv(self.timeout * self.N_ANALOG_PORTS).split() return map(int, values) except: return [] def execute(self, cmd): ''' Thread safe execution of "cmd" on the Arduino returning a single integer value. ''' self.mutex.acquire() try: self.port.flushInput() except: pass ntries = 1 attempts = 0 try: self.port.write(cmd + '\r') value = self.recv(self.timeout) while attempts < ntries and (value == '' or value == 'Invalid Command' or value == None): try: self.port.flushInput() self.port.write(cmd + '\r') value = self.recv(self.timeout) except: print "Exception executing command: " + cmd attempts += 1 except: self.mutex.release() print "Exception executing command: " + cmd value = None self.mutex.release() return int(value) def execute_array(self, cmd): ''' Thread safe execution of "cmd" on the Arduino returning an array. ''' self.mutex.acquire() try: self.port.flushInput() except: pass ntries = 1 attempts = 0 try: self.port.write(cmd + '\r') values = self.recv_array() while attempts < ntries and (values == '' or values == 'Invalid Command' or values == [] or values == None): try: self.port.flushInput() self.port.write(cmd + '\r') values = self.recv_array() except: print("Exception executing command: " + cmd) attempts += 1 except: self.mutex.release() print "Exception executing command: " + cmd raise SerialException return [] try: values = map(int, values) except: values = [] self.mutex.release() return values def execute_ack(self, cmd): ''' Thread safe execution of "cmd" on the Arduino returning True if response is ACK. ''' self.mutex.acquire() try: self.port.flushInput() except: pass ntries = 1 attempts = 0 try: self.port.write(cmd + '\r') #print cmd ack = self.recv(self.timeout) while attempts < ntries and (ack == '' or ack == 'Invalid Command' or ack == None): try: self.port.flushInput() self.port.write(cmd + '\r') ack = self.recv(self.timeout) except: print "Exception executing command: " + cmd attempts += 1 except: self.mutex.release() print "execute_ack exception when executing", cmd print sys.exc_info() return 0 self.mutex.release() return ack == 'OK' #def update_pid(self, Kp, Kd, Ki, Ko): #''' Set the PID parameters on the Arduino #''' #print "Updating PID parameters" #cmd = 'u ' + str(Kp) + ':' + str(Kd) + ':' + str(Ki) + ':' + str(Ko) #self.execute_ack(cmd) def update_pid(self, left_Kp, left_Kd, left_Ki, left_Ko, right_Kp, right_Kd, right_Ki, right_Ko): ''' Set the PID parameters on the Arduino ''' print "Updating PID parameters" cmd = 'u ' + str(left_Kp) + ':' + str(left_Kd) + ':' + str( left_Ki) + ':' + str(left_Ko) + ':' + str(right_Kp) + ':' + str( right_Kd) + ':' + str(right_Ki) + ':' + str(right_Ko) #print "update_pid command: " + cmd self.execute_ack(cmd) def get_baud(self): ''' Get the current baud rate on the serial port. ''' return int(self.execute('b')) def get_encoder_counts(self): values = self.execute_array('e') if len(values) not in [2, 4]: print "Encoder count was not 2 or 4 for 4wd" raise SerialException return None else: return values def reset_encoders(self): ''' Reset the encoder counts to 0 ''' return self.execute_ack('r') def drive(self, right, left): ''' Speeds are given in encoder ticks per PID interval ''' return self.execute_ack('m %d %d' % (right, left)) def drive_m_per_s(self, right, left): ''' Set the motor speeds in meters per second. ''' left_revs_per_second = float(left) / (self.wheel_diameter * PI) right_revs_per_second = float(right) / (self.wheel_diameter * PI) left_ticks_per_loop = int(left_revs_per_second * self.encoder_resolution * self.PID_INTERVAL * self.gear_reduction) right_ticks_per_loop = int(right_revs_per_second * self.encoder_resolution * self.PID_INTERVAL * self.gear_reduction) self.drive(right_ticks_per_loop, left_ticks_per_loop) def stop(self): ''' Stop both motors. ''' self.drive(0, 0) def analog_read(self, pin): return self.execute('a %d' % pin) def analog_write(self, pin, value): return self.execute_ack('x %d %d' % (pin, value)) def digital_read(self, pin): return self.execute('d %d' % pin) def digital_write(self, pin, value): return self.execute_ack('w %d %d' % (pin, value)) def pin_mode(self, pin, mode): return self.execute_ack('c %d %d' % (pin, mode)) def servo_write(self, id, pos): ''' Usage: servo_write(id, pos) Position is given in radians and converted to degrees before sending ''' return self.execute_ack( 's %d %d' % (id, int(min(SERVO_MAX, max(SERVO_MIN, degrees(pos)))))) def servo_read(self, id): ''' Usage: servo_read(id) The returned position is converted from degrees to radians ''' return radians(self.execute('t %d' % id)) def ping(self, pin): ''' The srf05/Ping command queries an SRF05/Ping sonar sensor connected to the General Purpose I/O line pinId for a distance, and returns the range in cm. Sonar distance resolution is integer based. ''' return self.execute('p %d' % pin) def get_pidin(self): values = self.execute_array('i') print("pidin_raw_data: " + str(values)) if len(values) not in [2, 4]: print "pidin was not 2 or 4 for 4wd" raise SerialException return None else: return values def get_pidout(self): values = self.execute_array('f') print("pidout_raw_data: " + str(values)) if len(values) not in [2, 4]: print "pidout was not 2 or 4 for 4wd" raise SerialException return None else: return values
def list_ports(): """ Lists serial port names :raises EnvironmentError: On unsupported or unknown platforms :returns: A list of the serial ports available on the system """ if sys.platform.startswith('win'): ports = ['COM%s' % (i + 1) for i in range(256)] elif sys.platform.startswith('linux') or sys.platform.startswith('cygwin'): # this excludes your current terminal "/dev/tty" ports = glob.glob('/dev/tty[A-Za-z]*') elif sys.platform.startswith('darwin'): ports = glob.glob('/dev/tty.*') else: raise EnvironmentError('Unsupported platform') result = [] for port in ports: try: s = Serial(port) s.close() result.append(port) except (OSError, SerialException): pass return result
def update(self, red, green, blue, time = 10): """ Change the device to the requested color for the period specified. @param red the red component of the color (0 to 255) @param green the green component of the color (0 to 255) @param blue the blue component of the color (0 to 255) @param time the time (in seconds) to hold the color. @return true if the command was sucessfuly sent to the device. """ # Set up the serial port port = None try: port = Serial(self._port, baudrate = 57600, timeout = 0.2) except: return False # Write the data data = "!%c%c%c%c\n" % ( trimValue(red), trimValue(green), trimValue(blue), trimValue(time) ) for ch in data: port.write(ch) sleep(0.01) # All done port.close() return True