示例#1
0
	def upload(self, port, board): # {{{
		wake = (yield)
		assert self.socket.data['role'] in ('benjamin', 'admin')
		assert port in ports
		if ports[port]:
			disable(ports[port], 'disabled for upload')
		def cancel():
			# Waking the generator kills the process.
			wake('Aborted')
		ports[port] = cancel
		command = self._get_command(board, port)
		data = ['']
		log('Flashing firmware: ' + ' '.join(command))
		broadcast(None, 'port_state', port, 3)
		process = subprocess.Popen(command, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.STDOUT, close_fds = True)
		def output():
			d = ''
			try:
				d = process.stdout.read().decode('utf-8')
			except:
				data[0] += '\nError writing %s firmware: ' % board + traceback.format_exc()
				log(repr(data[0]))
				wake(data[0])
				return False
			if d != '':
				#broadcast(None, 'message', port, '\n'.join(data[0].split('\n')[-4:]))
				data[0] += d
				return True
			wake(data[0])
			return False
		def error():
			data[0] += '\nError writing %s firmware: ' % board
			log(repr(data[0]))
			wake(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)
		websocketd.add_read(process.stdout, output, error)
		broadcast(None, 'uploading', port, 'uploading firmware for %s' % board)
		#broadcast(None, 'message', port, '')
		d = (yield)
		try:
			process.kill()	# In case it wasn't dead yet.
		except:
			pass
		try:
			process.communicate()	# Clean up.
		except:
			pass
		broadcast(None, 'uploading', port, None)
		#broadcast(None, 'message', port, '')
		broadcast(None, 'port_state', port, 0)
		ports[port] = None
		if autodetect:
			websocketd.call(None, detect, port)
		if d:
			return 'firmware upload for %s: ' % board + d
		else:
			return 'firmware for %s successfully uploaded' % board
示例#2
0
	def upload(self, port, board): # {{{
		wake = (yield)
		assert self.socket.data['role'] in ('benjamin', 'admin')
		assert port in ports
		if ports[port]:
			disable(ports[port], 'disabled for upload')
		def cancel():
			# Waking the generator kills the process.
			wake('Aborted')
		ports[port] = cancel
		command = self._get_command(board, port)
		data = ['']
		log('Flashing firmware: ' + ' '.join(command))
		broadcast(None, 'port_state', port, 3)
		process = subprocess.Popen(command, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.STDOUT, close_fds = True)
		def output():
			d = ''
			try:
				d = process.stdout.read().decode('utf-8')
			except:
				data[0] += '\nError writing %s firmware: ' % board + traceback.format_exc()
				log(repr(data[0]))
				wake(data[0])
				return False
			if d != '':
				#broadcast(None, 'message', port, '\n'.join(data[0].split('\n')[-4:]))
				data[0] += d
				return True
			wake(data[0])
			return False
		def error():
			data[0] += '\nError writing %s firmware: ' % board
			log(repr(data[0]))
			wake(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)
		websocketd.add_read(process.stdout, output, error)
		broadcast(None, 'uploading', port, 'uploading firmware for %s' % board)
		#broadcast(None, 'message', port, '')
		d = (yield)
		try:
			process.kill()	# In case it wasn't dead yet.
		except:
			pass
		try:
			process.communicate()	# Clean up.
		except:
			pass
		broadcast(None, 'uploading', port, None)
		#broadcast(None, 'message', port, '')
		broadcast(None, 'port_state', port, 0)
		ports[port] = None
		if autodetect:
			websocketd.call(None, detect, port)
		if d:
			return 'firmware upload for %s: ' % board + d
		else:
			return 'firmware for %s successfully uploaded' % board
示例#3
0
    def upload(self, port, board):  # {{{
        assert self.socket.data['role'] in ('benjamin', 'admin')
        assert ports[port] is None
        wake = (yield)
        command = self._get_command(board, port)
        data = ['']
        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().decode('utf-8')
            except:
                data[
                    0] += '\nError writing %s firmware: ' % board + traceback.format_exc(
                    )
                log(repr(data[0]))
                wake(data[0])
                return False
            if d != '':
                self._broadcast(None, 'message', port,
                                '\n'.join(data[0].split('\n')[-4:]))
                data[0] += d
                return True
            wake(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)
        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:
            websocketd.call(None, self.detect, port)
        if d:
            return 'firmware upload for %s: ' % board + d
        else:
            return 'firmware for %s successfully uploaded' % board
示例#4
0
def add_port(port): # {{{
	if port in ports:
		log('already existing port %s cannot be added' % port)
		return
	if not re.match(config['whitelist'], port) or re.match(config['blacklist'], port) or re.match(config['add-blacklist'], port):
		#log('skipping blacklisted or non-whitelisted port %s' % port)
		return
	ports[port] = None
	broadcast(None, 'new_port', port, upload_options(port))
	broadcast(None, 'port_state', port, 0)
	if autodetect:
		websocketd.call(None, detect, port)
示例#5
0
def add_port(port): # {{{
	if port in ports:
		log('already existing port %s cannot be added' % port)
		return
	if not re.match(config['whitelist'], port) or re.match(config['blacklist'], port) or re.match(config['add-blacklist'], port):
		#log('skipping blacklisted or non-whitelisted port %s' % port)
		return
	ports[port] = None
	broadcast(None, 'new_port', port, upload_options(port))
	broadcast(None, 'port_state', port, 0)
	if autodetect:
		websocketd.call(None, detect, port)
示例#6
0
	def detect_all(cls): # {{{
		resumeinfo = [(yield), None]
		for p in ports:
			if ports[p] is not None:
				continue
			c = websocketd.call(resumeinfo, cls.detect, p)
			while c(): c.args = (yield websocketd.WAIT)
示例#7
0
 def printer_input(self, fd, cond):  # {{{
     line = self.process.stdout.readline()
     if line == b'':
         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.decode('utf-8'))
     #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 orphans[x].uuid == self.uuid]:
             # This for loop always runs 0 or 1 times, never more.
             log('killing duplicate orphan')
             orphans[o].call('die', (
                 'admin',
                 'replaced by connection with same uuid',
             ), {}, lambda success, ret: None)
             del orphans[o]
         orphans[self.run_id] = self
         Connection._broadcast(None, 'del_printer', port)
         if autodetect:
             websocketd.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
示例#8
0
	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 websocketd.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:
			websocketd.call(None, self.detect, port)()
		if d:
			yield ('firmware upload for %s: ' % board + d)
		else:
			yield ('firmware for %s successfully uploaded' % board)
示例#9
0
	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 = websocketd.call(resumeinfo, detect, port)
		while c(): c.args = (yield websocketd.WAIT)
示例#10
0
	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 orphans[x].uuid == self.uuid]:
				# This for loop always runs 0 or 1 times, never more.
				log('killing duplicate orphan')
				orphans[o].call('die', ('admin', 'replaced by connection with same uuid',), {}, lambda success, ret: None)
				del orphans[x]
			orphans[self.run_id] = self
			Connection._broadcast(None, 'del_printer', port)
			if autodetect:
				websocketd.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
示例#11
0
	def upload(self, port, board): # {{{
		assert self.socket.data['role'] in ('benjamin', 'admin')
		assert ports[port] is None
		wake = (yield)
		command = self._get_command(board, port)
		data = ['']
		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().decode('utf-8')
			except:
				data[0] += '\nError writing %s firmware: ' % board + traceback.format_exc()
				log(repr(data[0]))
				wake(data[0])
				return False
			if d != '':
				self._broadcast(None, 'message', port, '\n'.join(data[0].split('\n')[-4:]))
				data[0] += d
				return True
			wake(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)
		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:
			websocketd.call(None, self.detect, port)
		if d:
			return 'firmware upload for %s: ' % board + d
		else:
			return 'firmware for %s successfully uploaded' % board
示例#12
0
	def machine_input(self): # {{{
		while self.process is not None:
			data = self.process.stdout.read()
			if data is None:
				#log('%s: no data now' % self.name)
				# No more data.
				return True
			if data == b'':
				# Connection closed.
				self.die('because there was an error')
				return False
			self.buffer += data
			#log('machine input:' + repr(data))
			while b'\n'[0] in self.buffer:
				pos = self.buffer.index(b'\n'[0])
				line = self.buffer[:pos]
				self.buffer = self.buffer[pos + 1:]
				data = json.loads(line.decode('utf-8'))
				#log('machine command input:' + repr(data))
				if data[1] == 'broadcast':
					broadcast(data[2], data[3], self.uuid, *(data[4:]))
				elif data[1] == 'disconnect':
					port = self.port
					ports[self.port] = None
					broadcast(None, 'port_state', port, 0)
					if autodetect:
						websocketd.call(None, detect, 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 machine process: %s' % repr(data))
示例#13
0
	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 = websocketd.call(resumeinfo, cls.detect, port)
			while c(): c.args = (yield websocketd.WAIT)
示例#14
0
        def process_done(fd, cond):
            data = p.stdout.read()
            if data:
                log('Data from completion callback: %s' % repr(data))
                return True
            log('Callback for print completion done; return: %s' %
                repr(p.wait()))
            return False

        GLib.io_add_watch(p.stdout.fileno(), GLib.IO_IN, process_done)


# }}}

if config['local'] != '':
    websocketd.call(None, Connection.add_port, '-')

# Detect serial ports. {{{
# 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'):
        websocketd.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():
            websocketd.call(None, Connection.add_port, tty[0])
    except:
        traceback.print_exc()
示例#15
0
	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'] != '':
	websocketd.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'):
		websocketd.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():
			websocketd.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])