def detect_all(cls): # {{{ resumeinfo = [(yield), None] for p in ports: if ports[p] is not None: continue c = websockets.call(resumeinfo, cls.detect, p) while c(): c.args = (yield websockets.WAIT)
def upload(self, port, board): # {{{ assert self.socket.data['role'] in ('benjamin', 'admin') assert ports[port] is None resumeinfo = [(yield), None] sudo, brd, protocol, baudrate, mcu = self._get_info(board) self.disable(port) data = [''] filename = fhs.read_data(os.path.join('firmware', brd + '.hex'), opened = False) command = sudo + (config['avrdude'], '-q', '-q', '-c', protocol) + baudrate + ('-p', mcu, '-P', port, '-U', 'flash:w:' + filename + ':i') log('Flashing firmware: ' + ' '.join(command)) process = subprocess.Popen(command, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.STDOUT, close_fds = True) def output(fd, cond): d = '' try: d = process.stdout.read() except: data[0] += '\nError writing %s firmware: ' % board + traceback.format_exc() log(repr(data[0])) resumeinfo[0](data[0]) return False if d != '': self._broadcast(None, 'message', port, '\n'.join(data[0].split('\n')[-4:])) data[0] += d return True resumeinfo[0](data[0]) return False fl = fcntl.fcntl(process.stdout.fileno(), fcntl.F_GETFL) fcntl.fcntl(process.stdout.fileno(), fcntl.F_SETFL, fl | os.O_NONBLOCK) GLib.io_add_watch(process.stdout, GLib.IO_IN | GLib.IO_PRI | GLib.IO_HUP, output) self._broadcast(None, 'blocked', port, 'uploading firmware for %s' % board) self._broadcast(None, 'message', port, '') d = (yield websockets.WAIT) try: process.kill() # In case it wasn't dead yet. except OSError: pass process.communicate() # Clean up. self._broadcast(None, 'blocked', port, None) self._broadcast(None, 'message', port, '') if autodetect: websockets.call(None, self.detect, port)() if d: yield ('firmware upload for %s: ' % board + d) else: yield ('firmware for %s successfully uploaded' % board)
def detect(cls, port): # {{{ resumeinfo = [(yield), None] log('detecting printer on %s' % port) if port not in ports or ports[port] != None: log('port is not in detectable state') return ports[port] = False c = websockets.call(resumeinfo, detect, port) while c(): c.args = (yield websockets.WAIT)
def printer_input(self, fd, cond): # {{{ line = self.process.stdout.readline() if line == '': log('%s died.' % self.name) self.process.communicate() # Clean up the zombie. for t in range(3): for w in self.waiters[t]: self.waiters[t][w](False, 'Printer died') Connection._disable('admin', self.port) return False data = json.loads(line) #log('printer input:' + repr(data)) if data[1] == 'broadcast': Connection._broadcast(data[2], data[3], self.port, *(data[4:])) elif data[1] == 'disconnect': # Don't remember a printer that hasn't sent its name yet. port = self.port ports[self.port] = None # If there already is an orphan with the same uuid, kill the old orphan. for o in [x for x in orphans if x[0] == self.uuid]: # This for loop always runs 0 or 1 times, never more. log('killing duplicate orphan') del orphans[x] orphans[self.run_id] = self Connection._broadcast(None, 'del_printer', port) if autodetect: websockets.call(None, Connection.detect, self.port)() elif data[1] == 'error': if data[0] is None: # Error on command without id. log('error on command without id: %s' % repr(data)) else: self.waiters[0].pop(data[0])(False, data[2]) elif data[1] == 'return': self.waiters[0].pop(data[0])(True, data[2]) elif data[1] == 'movecb': self.waiters[1].pop(data[0])(True, data[2]) elif data[1] == 'tempcb': self.waiters[2].pop(data[0])(True, data[2]) else: raise AssertionError('invalid reply from printer process: %s' % repr(data)) return True
def add_port(cls, port): # {{{ resumeinfo = [(yield), None] if port in ports: log('already existing port %s cannot be added' % port) return if re.match(config['blacklist'], port) or re.match(config['add-blacklist'], port): #log('skipping blacklisted port %s' % port) return ports[port] = None cls._broadcast(None, 'new_port', port); if autodetect: c = websockets.call(resumeinfo, cls.detect, port) while c(): c.args = (yield websockets.WAIT)
if config['done']: cmd = config['done'] cmd = cmd.replace('[[STATE]]', 'completed' if completed else 'aborted').replace('[[REASON]]', reason) log('running %s' % cmd) p = subprocess.Popen(cmd, stdout = subprocess.PIPE, shell = True, close_fds = True) def process_done(fd, cond): data = p.stdout.read() if data: return True log('Flashing done; return: %s' % repr(p.wait())) return False GLib.io_add_watch(p.stdout.fileno(), GLib.IO_IN, process_done) # }}} if config['local'] != '': websockets.call(None, Connection.add_port, '-')() # Assume a GNU/Linux system; if you have something else, you need to come up with a way to iterate over all your serial ports and implement it here. Patches welcome, especially if they are platform-independent. try: # Try Linux sysfs. for tty in os.listdir('/sys/class/tty'): websockets.call(None, Connection.add_port, '/dev/' + tty)() except: # Try more generic approach. Don't use this by default, because it doesn't detect all ports on GNU/Linux. try: import serial.tools.list_ports for tty in serial.tools.list_ports.comports(): websockets.call(None, Connection.add_port, tty[0])() except: traceback.print_exc() log('Not probing serial ports, because an error occurred: %s' % sys.exc_info()[1])