Пример #1
0
	def _tls_init(self):
		# Set up members for using tls, if requested.
		if self.tls in (False, '-'):
			self.tls = False
			return
		if self.tls in (None, True, ''):
			self.tls = fhs.module_get_config('network')['tls']
		if self.tls == '':
			self.tls = socket.getfqdn()
		elif self.tls == '-':
			self.tls = False
			return
		# Use tls.
		fc = fhs.read_data(os.path.join('certs', self.tls + os.extsep + 'pem'), opened = False, packagename = 'network')
		fk = fhs.read_data(os.path.join('private', self.tls + os.extsep + 'key'), opened = False, packagename = 'network')
		if fc is None or fk is None:
			# Create new self-signed certificate.
			certfile = fhs.write_data(os.path.join('certs', self.tls + os.extsep + 'pem'), opened = False, packagename = 'network')
			csrfile = fhs.write_data(os.path.join('csr', self.tls + os.extsep + 'csr'), opened = False, packagename = 'network')
			for p in (certfile, csrfile):
				path = os.path.dirname(p)
				if not os.path.exists(path):
					os.makedirs(path)
			keyfile = fhs.write_data(os.path.join('private', self.tls + os.extsep + 'key'), opened = False, packagename = 'network')
			path = os.path.dirname(keyfile)
			if not os.path.exists(path):
				os.makedirs(path, 0o700)
			os.system('openssl req -x509 -nodes -days 3650 -newkey rsa:4096 -subj "/CN=%s" -keyout "%s" -out "%s"' % (self.tls, keyfile, certfile))
			os.system('openssl req -subj "/CN=%s" -new -key "%s" -out "%s"' % (self.tls, keyfile, csrfile))
			fc = fhs.read_data(os.path.join('certs', self.tls + os.extsep + 'pem'), opened = False, packagename = 'network')
			fk = fhs.read_data(os.path.join('private', self.tls + os.extsep + 'key'), opened = False, packagename = 'network')
		self._tls_cert = fc
		self._tls_key = fk
Пример #2
0
	def _tls_init(self):
		# Set up members for using tls, if requested.
		if self.tls in (False, '-'):
			self.tls = False
			return
		if self.tls in (None, True, ''):
			self.tls = fhs.module_get_config('network')['tls']
		if self.tls == '':
			self.tls = socket.getfqdn()
		elif self.tls == '-':
			self.tls = False
			return
		# Use tls.
		fc = fhs.read_data(os.path.join('certs', self.tls + os.extsep + 'pem'), opened = False, packagename = 'network')
		fk = fhs.read_data(os.path.join('private', self.tls + os.extsep + 'key'), opened = False, packagename = 'network')
		if fc is None or fk is None:
			# Create new self-signed certificate.
			certfile = fhs.write_data(os.path.join('certs', self.tls + os.extsep + 'pem'), opened = False, packagename = 'network')
			csrfile = fhs.write_data(os.path.join('csr', self.tls + os.extsep + 'csr'), opened = False, packagename = 'network')
			for p in (certfile, csrfile):
				path = os.path.dirname(p)
				if not os.path.exists(path):
					os.makedirs(path)
			keyfile = fhs.write_data(os.path.join('private', self.tls + os.extsep + 'key'), opened = False, packagename = 'network')
			path = os.path.dirname(keyfile)
			if not os.path.exists(path):
				os.makedirs(path, 0o700)
			os.system('openssl req -x509 -nodes -days 3650 -newkey rsa:4096 -subj "/CN=%s" -keyout "%s" -out "%s"' % (self.tls, keyfile, certfile))
			os.system('openssl req -subj "/CN=%s" -new -key "%s" -out "%s"' % (self.tls, keyfile, csrfile))
			fc = fhs.read_data(os.path.join('certs', self.tls + os.extsep + 'pem'), opened = False, packagename = 'network')
			fk = fhs.read_data(os.path.join('private', self.tls + os.extsep + 'key'), opened = False, packagename = 'network')
		self._tls_cert = fc
		self._tls_key = fk
Пример #3
0
 def _read_boards(self):
     boards = {}
     for d in fhs.read_data('hardware',
                            packagename='arduino',
                            dir=True,
                            multiple=True):
         for board in os.listdir(d):
             boards_txt = os.path.join(d, board,
                                       'boards' + os.extsep + 'txt')
             if not os.path.exists(boards_txt):
                 continue
             with open(boards_txt) as b:
                 for line in b:
                     if line.startswith('#') or line.strip() == '':
                         continue
                     parse = re.match('([^.=]+)\.([^=]+)=(.*)$',
                                      line.strip())
                     if parse is None:
                         log('Warning: invalid line in %s: %s' %
                             (boards_txt, line.strip()))
                         continue
                     tag, option, value = parse.groups()
                     if tag not in boards:
                         boards[tag] = {}
                     if option in boards[tag]:
                         if boards[tag][option] != value:
                             log('%s: duplicate tag %s.%s with different value (%s != %s); using %s'
                                 %
                                 (boards_txt, tag, option, value,
                                  boards[tag][option], boards[tag][option]))
                             continue
                     boards[tag][option] = value
     for tag in tuple(boards.keys()):
         if 'name' not in boards[tag]:
             boards[tag]['name'] = tag
         if any(x not in boards[tag]
                for x in ('upload.protocol', 'upload.speed', 'build.mcu',
                          'upload.maximum_size')):
             log('skipping %s because hardware information is incomplete (%s)'
                 % (boards[tag]['name'], repr(boards[tag])))
             del boards[tag]
             continue
         if int(boards[tag]['upload.maximum_size']) < 32000:
             # Not enough memory; don't complain about skipping this board.
             del boards[tag]
             continue
         if fhs.read_data(os.path.join(
                 'firmware', boards[tag]['build.mcu'] + os.extsep + 'hex'),
                          opened=False) is None:
             log('skipping %s because firmware for %s is not installed' %
                 (boards[tag]['name'], boards[tag]['build.mcu']))
             del boards[tag]
             continue
     return boards
Пример #4
0
	def _get_command(self, board, port): # {{{
		if board == 'bbbmelzi ':
			return ('sudo', fhs.read_data(os.path.join('bb', 'flash-bb-0'), opened = False), fhs.read_data(os.path.join('bb', 'avrdude.conf'), opened = False), fhs.read_data(os.path.join('firmware', 'atmega1284p' + os.extsep + 'hex'), opened = False))
		if board == 'bb4melzi ':
			return ('sudo', fhs.read_data(os.path.join('bb', 'flash-bb-4'), opened = False), fhs.read_data(os.path.join('bb', 'avrdude.conf'), opened = False), fhs.read_data(os.path.join('firmware', 'atmega1284p' + os.extsep + 'hex'), opened = False))
		boards = read_boards()
		if board not in boards:
			raise ValueError('board type not supported')
		filename = fhs.read_data(os.path.join('firmware', boards[board]['build.mcu'] + os.extsep + 'hex'), opened = False)
		if filename is None:
			raise NotImplementedError('Firmware is not available')
		return ('avrdude', '-D', '-q', '-q', '-p', boards[board]['build.mcu'], '-C', '/etc/avrdude.conf', '-b', boards[board]['upload.speed'], '-c', boards[board]['upload.protocol'], '-P', port, '-U', 'flash:w:' + filename + ':i')
Пример #5
0
def create_printer(uuid=None):  # {{{
    if uuid is None:
        uuid = protocol.new_uuid()
    process = subprocess.Popen(
        (fhs.read_data('driver.py', opened=False), '--uuid', uuid, '--cdriver',
         fhs.read_data('franklin-cdriver', opened=False), '--allow-system',
         config['allow-system']) + (('--system', ) if fhs.is_system else ()) +
        (('--arc', 'False') if not config['arc'] else ()),
        stdin=subprocess.PIPE,
        stdout=subprocess.PIPE,
        close_fds=True)
    printers[uuid] = Printer(None, process, None, None)
    return uuid
Пример #6
0
 def _get_command(self, board, port):  # {{{
     if board == 'bbbmelzi ':
         return ('sudo', fhs.read_data('flash-bbb', opened=False),
                 fhs.read_data('avrdude.conf', opened=False),
                 fhs.read_data(os.path.join(
                     'firmware', 'atmega1284p' + os.extsep + 'hex'),
                               opened=False))
     if board == 'bb4melzi ':
         return ('sudo', fhs.read_data('flash-bb-O4', opened=False),
                 fhs.read_data('avrdude.conf', opened=False),
                 fhs.read_data(os.path.join(
                     'firmware', 'atmega1284p' + os.extsep + 'hex'),
                               opened=False))
     boards = self._read_boards()
     if board not in boards:
         raise ValueError('board type not supported')
     filename = fhs.read_data(os.path.join(
         'firmware', boards[board]['build.mcu'] + os.extsep + 'hex'),
                              opened=False)
     if filename is None:
         raise NotImplementedError('Firmware is not available')
     return ('avrdude', '-q', '-q', '-p', boards[board]['build.mcu'], '-b',
             boards[board]['upload.speed'], '-c',
             boards[board]['upload.protocol'], '-P', port, '-U',
             'flash:w:' + filename + ':i')
Пример #7
0
def clear_cache():
    basedirs = fhs.read_data('db', dir = True, opened = False, multiple = True)
    cachefile = os.path.join(basedirs[0],"cache.pickle");
    if os.path.exists(cachefile):
        logging.info ("Clearing cache file {}".format(os.path.join(basedirs[0],"cache.pickle")))
        try:
            os.remove(cachefile)
        except Exception as e:
            logging.exception("Clearing cache failed",e)
Пример #8
0
def clear_cache():
    basedirs = fhs.read_data('db', dir=True, opened=False, multiple=True)
    cachefile = os.path.join(basedirs[0], "cache.pickle")
    if os.path.exists(cachefile):
        logging.info("Clearing cache file {}".format(
            os.path.join(basedirs[0], "cache.pickle")))
        try:
            os.remove(cachefile)
        except Exception as e:
            logging.exception("Clearing cache failed", e)
Пример #9
0
def create_machine(uuid=None):  # {{{
    if uuid is None:
        uuid = protocol.new_uuid()
    process = subprocess.Popen(
        (fhs.read_data('driver.py', opened=False), '--uuid', uuid,
         '--allow-system', config['allow-system']) +
        (('--system', ) if fhs.is_system else ()),
        stdin=subprocess.PIPE,
        stdout=subprocess.PIPE,
        close_fds=True)
    machines[uuid] = Machine(None, process, None)
    return uuid
Пример #10
0
def read_boards(): # {{{
	boards = {}
	for d in fhs.read_data('hardware', packagename = 'arduino', dir = True, multiple = True):
		for board in os.listdir(d):
			boards_txt = os.path.join(d, board, 'boards' + os.extsep + 'txt')
			if not os.path.exists(boards_txt):
				continue
			with open(boards_txt) as b:
				for line in b:
					if line.startswith('#') or line.strip() == '':
						continue
					parse = re.match('([^.=]+)\.([^=]+)=(.*)$', line.strip())
					if parse is None:
						log('Warning: invalid line in %s: %s' % (boards_txt, line.strip()))
						continue
					tag, option, value = parse.groups()
					if tag not in boards:
						boards[tag] = {}
					if option in boards[tag]:
						if boards[tag][option] != value:
							log('%s: duplicate tag %s.%s with different value (%s != %s); using %s' % (boards_txt, tag, option, value, boards[tag][option], boards[tag][option]))
							continue
					boards[tag][option] = value
	for tag in tuple(boards.keys()):
		if 'name' not in boards[tag]:
			boards[tag]['name'] = tag
		if any(x not in boards[tag] for x in ('upload.protocol', 'upload.speed', 'build.mcu', 'upload.maximum_size')):
			#log('skipping %s because hardware information is incomplete (%s)' % (boards[tag]['name'], repr(boards[tag])))
			del boards[tag]
			continue
		if int(boards[tag]['upload.maximum_size']) < 30000:
			# Not enough memory; don't complain about skipping this board.
			del boards[tag]
			continue
		if fhs.read_data(os.path.join('firmware', boards[tag]['build.mcu'] + os.extsep + 'hex'), opened = False) is None:
			#log('skipping %s because firmware for %s is not installed' % (boards[tag]['name'], boards[tag]['build.mcu']))
			del boards[tag]
			continue
	return boards
Пример #11
0
def read(use_cache=True, unique_names=False):
    '''Read all db files from all fhs data directories (and pwd)
    Return list of tracks.'''
    # db = list of tracks.
    # track = { 'name': name, 'files': list of (filename, offset), 'announcefiles' : list of (filename, offset),'fragments': list of fragments and groups, 'end': time }
    # fragment = ( 'fragment', name, start_time )
    # group = ( 'group', name, list of fragments and groups )
    tracks = []
    basedirs = fhs.read_data('db', dir=True, opened=False, multiple=True)
    if use_cache:
        try:
            import pickle
            logging.info("Trying to use cache from {}".format(
                os.path.join(basedirs[0], "cache.pickle")))
            tracks = pickle.load(
                open(os.path.join(basedirs[0], "cache.pickle"), 'rb'))
        except Exception as e:  #TODO: Narrow exception class.
            logging.info("Cache not found")
        if len(tracks) > 1:
            return tracks
    # Parse all fragments files.
    used = set()
    usednames = set()
    for dirname in basedirs:
        for root, dirs, files in os.walk(dirname, followlinks=True):
            if FRAGMENTS in files:
                if makepath(root, FRAGMENTS) in used:
                    continue
                used.add(makepath(root, FRAGMENTS))
                parse_fragments(root, tracks, used, usednames)
    # Add all other files.
    for dirname in basedirs:
        for root, dirs, files in os.walk(dirname, followlinks=True):
            root = os.path.abspath(root)
            for filename in files:
                if makepath(root, filename) in used:
                    continue
                if os.path.splitext(filename)[1] not in exts:
                    continue
                tracks.append(add_unfragmented_file(filename, root, usednames))
                used.add(makepath(filename, root))
    tracks = load_test_tracks(tracks)
    try:
        import pickle
        logging.info("Writing cache")
        pickle.dump(tracks,
                    open(os.path.join(basedirs[0], "cache.pickle"), 'wb'))
    except Exception as e:
        logging.warning("Writing cache failed")
        logging.exception(e)
    return tracks
Пример #12
0
		def boot_printer_input():
			id[2] = True
			ids = [protocol.single[code][0] for code in ('ID', 'STARTUP')]
			# CMD:1 ID:8 Checksum:3
			while len(id[0]) < 12:
				try:
					data = printer.read(12 - len(id[0]))
				except OSError:
					continue
				except IOError:
					continue
				id[0] += data
				#log('incomplete id: ' + id[0])
				if len(id[0]) < 12:
					return True
				if id[0][0] not in ids or not protocol.check(id[0]):
					log('skip non-id: %s (%s)' % (''.join('%02x' % x for x in id[0]), repr(id[0])))
					f = len(id[0])
					for start in ids:
						if start in id[0][1:]:
							p = id[0].index(bytes((start,)))
							if p < f:
								f = p
							log('Keeping some')
					if f == 0:
						f = 1
					id[0] = id[0][f:]
					return True
			# We have something to handle; cancel the timeout, but keep the serial port open to avoid a reset. (I don't think this even works, but it doesn't hurt.)
			websocketd.remove_timeout(timeout_handle[0])
			# This printer was running and tried to send an id.  Check the id.
			id[0] = id[0][1:9]
			if id[0] in orphans:
				log('accepting orphan %s on %s' % (''.join('%02x' % x for x in id[0]), port))
				ports[port] = orphans.pop(id[0])
				ports[port].port = port
				def close_port(success, data):
					log('reconnect complete; closing server port')
					printer.close()
				log('reconnecting %s' % port)
				ports[port].call('reconnect', ['admin', port], {}, lambda success, ret: ports[port].call('send_printer', ['admin', None], {}, close_port) if success else close_port)
				broadcast(None, 'port_state', port, 2)
				return False
			run_id = nextid()
			log('accepting unknown printer on port %s (id %s)' % (port, ''.join('%02x' % x for x in run_id)))
			#log('orphans: %s' % repr(tuple(orphans.keys())))
			process = subprocess.Popen((fhs.read_data('driver.py', opened = False), '--cdriver', fhs.read_data('franklin-cdriver', opened = False), '--port', port, '--run-id', run_id, '--allow-system', config['allow-system']) + (('--system',) if fhs.is_system else ()), stdin = subprocess.PIPE, stdout = subprocess.PIPE, close_fds = True)
			ports[port] = Port(port, process, printer, run_id)
			return False
Пример #13
0
def find_path(name, packagename): # {{{
	'''Search name from environment, in current directory, and in user configuration.'''
	# Allow overriding with environment keys.
	d = os.getenv('GUI_PATH_' + packagename.upper())
	if d is not None and os.path.exists(os.path.join(d, name)):
		return d
	d = os.getenv('GUI_PATH')
	if d is not None and os.path.exists(os.path.join(d, name)):
		return d
	ret = fhs.read_data(name, opened = False, packagename = packagename)
	if ret is not None:
		return ret
	# Give up.
	sys.stderr.write('Warning: gui definition for %s not found\n' % name)
	return None
Пример #14
0
def read(use_cache = True, unique_names = False):
    '''Read all db files from all fhs data directories (and pwd)
    Return list of tracks.'''
    # db = list of tracks. 
    # track = { 'name': name, 'files': list of (filename, offset), 'announcefiles' : list of (filename, offset),'fragments': list of fragments and groups, 'end': time }
    # fragment = ( 'fragment', name, start_time )
    # group = ( 'group', name, list of fragments and groups )
    tracks = []
    basedirs = fhs.read_data('db', dir = True, opened = False, multiple = True)
    if use_cache:
        try:
            import pickle
            logging.info ("Trying to use cache from {}".format(os.path.join(basedirs[0],"cache.pickle")))
            tracks = pickle.load(open(os.path.join(basedirs[0],"cache.pickle"),'rb'))
        except Exception as e: #TODO: Narrow exception class.
            logging.info("Cache not found")
        if len(tracks) > 1:
            return tracks
    # Parse all fragments files.
    used = set()
    usednames = set()
    for dirname in basedirs:
        for root, dirs, files in os.walk(dirname, followlinks=True):
            if FRAGMENTS in files:
                if makepath(root, FRAGMENTS) in used:
                    continue
                used.add(makepath(root, FRAGMENTS))
                parse_fragments(root, tracks, used, usednames)
    # Add all other files.
    for dirname in basedirs:
        for root, dirs, files in os.walk(dirname, followlinks=True):
            root = os.path.abspath(root)
            for filename in files:
                if makepath(root, filename) in used:
                    continue
                if os.path.splitext(filename)[1] not in exts:
                    continue
                tracks.append(add_unfragmented_file(filename, root, usednames))
                used.add(makepath(filename,root))
    tracks = load_test_tracks(tracks)
    try:
        import pickle
        logging.info ("Writing cache")
        pickle.dump(tracks,open(os.path.join(basedirs[0],"cache.pickle"),'wb'))
    except Exception as e:
        logging.warning ("Writing cache failed")
        logging.exception (e)
    return tracks
Пример #15
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 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)
Пример #16
0
		'tls': 'True',
	})
# }}}

# Global variables. {{{
httpd = None
default_printer = (None, None)
ports = {}
autodetect = config['autodetect'].lower() == 'true'
tls = config['tls'].lower() == 'true'
orphans = {}
scripts = {}
# }}}

# Load scripts. {{{
for d in fhs.read_data('scripts', dir = True, multiple = True):
	for s in os.listdir(d):
		name, ext = os.path.splitext(s)
		if ext != os.extsep + 'js' or name in scripts:
			continue
		dataname = os.path.join(d, name + os.extsep + 'dat')
		scripts[name] = [open(os.path.join(d, s)).read(), open(dataname).read() if os.path.exists(dataname) else None]
nextscriptname = 0
while '%04d' % nextscriptname in scripts:
	nextscriptname += 1
# }}}

class Server(websocketd.RPChttpd): # {{{
	def auth_message(self, connection, is_websocket):
		path = connection.address.path
		for extra in ('/', '/websocket'):
Пример #17
0
        'tls': 'True',
    })
# }}}

# Global variables. {{{
httpd = None
default_printer = (None, None)
ports = {}
autodetect = config['autodetect'].lower() == 'true'
tls = config['tls'].lower() == 'true'
orphans = {}
scripts = {}
# }}}

# Load scripts. {{{
for d in fhs.read_data('scripts', dir=True, multiple=True):
    for s in os.listdir(d):
        name, ext = os.path.splitext(s)
        if ext != os.extsep + 'js' or name in scripts:
            continue
        dataname = os.path.join(d, name + os.extsep + 'dat')
        scripts[name] = [
            open(os.path.join(d, s)).read(),
            open(dataname).read() if os.path.exists(dataname) else None
        ]
nextscriptname = 0
while '%04d' % nextscriptname in scripts:
    nextscriptname += 1
# }}}

Пример #18
0
        def boot_machine_input():
            id[2] = True
            ids = [protocol.single[code][0] for code in ('ID', 'STARTUP')]
            # CMD:1 ID:8 + 16 Checksum:9 Total: 34
            while len(id[0]) < 34:
                try:
                    data = machine.read(34 - len(id[0]))
                except OSError:
                    continue
                except IOError:
                    continue
                id[0] += data
                #log('incomplete id: ' + id[0])
                if len(id[0]) < 34:
                    if len(id[0]) > 0 and id[0][0] == protocol.single[
                            'CONTROLLER'][0]:
                        # This is a controller. Spawn the process, then cancel this detection.
                        websocketd.remove_timeout(timeout_handle[0])
                        machine.close()
                        ports[port] = None
                        broadcast(None, 'port_state', port, 0)
                        log('Starting controller driver on ' + port)
                        env = os.environ.copy()
                        env['PORT'] = port
                        subprocess.Popen(config['controller'],
                                         env=env,
                                         shell=True)
                        return False
                    return True
                if id[0][0] not in ids or not protocol.check(id[0]):
                    log('skip non-id: %s (%s)' %
                        (''.join('%02x' % x for x in id[0]), repr(id[0])))
                    f = len(id[0])
                    for start in ids:
                        if start in id[0][1:]:
                            p = id[0].index(bytes((start, )), 1)
                            if p < f:
                                f = p
                            log('Keeping some')
                    if f == 0:
                        f = 1
                    id[0] = id[0][f:]
                    return True
            # We have something to handle; cancel the timeout, but keep the serial port open to avoid a reset. (I don't think this even works, but it doesn't hurt.)
            websocketd.remove_timeout(timeout_handle[0])
            # This machine was running and tried to send an id.  Check the id.
            uuid = id[0][9:9 + 16]
            if (uuid[7] & 0xf0) != 0x40 or (uuid[9] & 0xc0) != 0x80:
                # Broken uuid; create a new one and set it.
                log('broken uuid: ' + repr(uuid))
                uuid = None
            else:
                uuid = ''.join('%02x' % x for x in uuid[:16])
                uuid = uuid[:8] + '-' + uuid[8:12] + '-' + uuid[
                    12:16] + '-' + uuid[16:20] + '-' + uuid[20:32]
                id[0] = id[0][1:9]
                running_machine = [
                    p for p in machines if machines[p].run_id == id[0]
                ]
                assert len(running_machine) < 2
                if len(running_machine) > 0:
                    p = running_machine[0]
                    assert p.uuid == uuid
                    if p.port is not None:
                        disable(
                            p.uuid,
                            'disabled machine which was detected on different port'
                        )
                    log('rediscovered machine %s on %s' %
                        (''.join('%02x' % x for x in id[0]), port))
                    ports[port] = p.uuid
                    p.port = port

                    def close_port(success, data):
                        log('reconnect complete; closing server port')
                        machine.close()

                    p.call(
                        'reconnect', ['admin', port], {},
                        lambda success, ret: (ports[port].call(
                            'send_machine', ['admin', None], {}, close_port)
                                              if success else close_port()))
                    broadcast(None, 'port_state', port, 2)
                    return False
            run_id = nextid()
            # Find uuid or create new Machine object.
            if uuid in machines:
                log('accepting known machine on port %s (uuid %s)' %
                    (port, uuid))
                machines[uuid].port = port
                ports[port] = uuid
                log('connecting %s to port %s' % (uuid, port))
                machines[uuid].call('connect',
                                    ['admin', port, [chr(x) for x in run_id]],
                                    {}, lambda success, ret: None)
            else:
                log('accepting unknown machine on port %s' % port)
                # Close detect port so it doesn't interfere.
                machine.close()
                #log('machines: %s' % repr(tuple(machines.keys())))
                process = subprocess.Popen(
                    (fhs.read_data('driver.py', opened=False), '--uuid',
                     uuid if uuid is not None else '', '--allow-system',
                     config['allow-system']) +
                    (('--system', ) if fhs.is_system else
                     ()) + (('--arc', 'False') if not config['arc'] else ()),
                    stdin=subprocess.PIPE,
                    stdout=subprocess.PIPE,
                    close_fds=True)
                new_machine = Machine(port,
                                      process,
                                      run_id,
                                      send=uuid is not None)

                def finish():
                    log('finish detect %s' % repr(uuid))
                    ports[port] = uuid
                    machines[uuid] = new_machine
                    log('connecting new machine %s to port %s' % (uuid, port))
                    new_machine.call('connect',
                                     ['admin', port, [chr(x) for x in run_id]],
                                     {}, lambda success, ret: None)

                if uuid is None:

                    def prefinish(success, uuid):
                        assert success
                        new_machine.uuid = uuid
                        new_machine.finish(finish)

                    new_machine.call('reset_uuid', ['admin'], {}, prefinish)
                else:
                    finish()
            return False
Пример #19
0
def detect(port):  # {{{
    log('detecting machine on %s' % port)
    if port not in ports:
        log('port does not exist')
        return
    if ports[port] != None:
        # Abort detection in progress.
        if ports[port]:
            disable(ports[port], 'disabled to prepare for detection')
        if ports[port] != None:
            # This should never happen.
            log('BUG: port is not in detectable state. Please report this.')
            return
    broadcast(None, 'port_state', port, 1)
    if port == '-' or port.startswith('!'):
        run_id = nextid()
        process = subprocess.Popen(
            (fhs.read_data('driver.py', opened=False), '--uuid', '-',
             '--allow-system', config['allow-system']) +
            (('--system', ) if fhs.is_system else
             ()) + (('--arc', 'False') if not config['arc'] else ()),
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            close_fds=True)
        machines[port] = Machine(port, process, run_id)
        ports[port] = port
        return False
    if not os.path.exists(port):
        log("not detecting on %s, because file doesn't exist." % port)
        return False
    if config['predetect']:
        env = os.environ.copy()
        env['PORT'] = port
        subprocess.call(config['predetect'], env=env, shell=True)
    try:
        machine = serial.Serial(port, baudrate=115200, timeout=0)
    except serial.SerialException as e:
        log('failed to open serial port %s (%s).' % (port, str(e)))
        del ports[port]
        #traceback.print_exc()
        return False
    # We need to get the machine id first.  If the machine is booting, this can take a while.
    id = [None, None, None, None]  # data, timeouts, had data

    # Wait to make sure the command is interpreted as a new packet.
    def part2():
        id[0] = b''
        id[1] = 0
        id[2] = False

        def timeout():
            id[1] += 1
            if id[1] >= 30:
                # Timeout.  Give up.
                websocketd.remove_read(watcher)
                machine.close()
                log('Timeout waiting for machine on port %s; giving up.' %
                    port)
                ports[port] = None
                broadcast(None, 'port_state', port, 0)
                return
            if not id[2]:
                machine.write(protocol.single['ID'])
            else:
                id[2] = False
            timeout_handle[0] = websocketd.add_timeout(time.time() + .5,
                                                       timeout)

        def boot_machine_input():
            id[2] = True
            ids = [protocol.single[code][0] for code in ('ID', 'STARTUP')]
            # CMD:1 ID:8 + 16 Checksum:9 Total: 34
            while len(id[0]) < 34:
                try:
                    data = machine.read(34 - len(id[0]))
                except OSError:
                    continue
                except IOError:
                    continue
                id[0] += data
                #log('incomplete id: ' + id[0])
                if len(id[0]) < 34:
                    if len(id[0]) > 0 and id[0][0] == protocol.single[
                            'CONTROLLER'][0]:
                        # This is a controller. Spawn the process, then cancel this detection.
                        websocketd.remove_timeout(timeout_handle[0])
                        machine.close()
                        ports[port] = None
                        broadcast(None, 'port_state', port, 0)
                        log('Starting controller driver on ' + port)
                        env = os.environ.copy()
                        env['PORT'] = port
                        subprocess.Popen(config['controller'],
                                         env=env,
                                         shell=True)
                        return False
                    return True
                if id[0][0] not in ids or not protocol.check(id[0]):
                    log('skip non-id: %s (%s)' %
                        (''.join('%02x' % x for x in id[0]), repr(id[0])))
                    f = len(id[0])
                    for start in ids:
                        if start in id[0][1:]:
                            p = id[0].index(bytes((start, )), 1)
                            if p < f:
                                f = p
                            log('Keeping some')
                    if f == 0:
                        f = 1
                    id[0] = id[0][f:]
                    return True
            # We have something to handle; cancel the timeout, but keep the serial port open to avoid a reset. (I don't think this even works, but it doesn't hurt.)
            websocketd.remove_timeout(timeout_handle[0])
            # This machine was running and tried to send an id.  Check the id.
            uuid = id[0][9:9 + 16]
            if (uuid[7] & 0xf0) != 0x40 or (uuid[9] & 0xc0) != 0x80:
                # Broken uuid; create a new one and set it.
                log('broken uuid: ' + repr(uuid))
                uuid = None
            else:
                uuid = ''.join('%02x' % x for x in uuid[:16])
                uuid = uuid[:8] + '-' + uuid[8:12] + '-' + uuid[
                    12:16] + '-' + uuid[16:20] + '-' + uuid[20:32]
                id[0] = id[0][1:9]
                running_machine = [
                    p for p in machines if machines[p].run_id == id[0]
                ]
                assert len(running_machine) < 2
                if len(running_machine) > 0:
                    p = running_machine[0]
                    assert p.uuid == uuid
                    if p.port is not None:
                        disable(
                            p.uuid,
                            'disabled machine which was detected on different port'
                        )
                    log('rediscovered machine %s on %s' %
                        (''.join('%02x' % x for x in id[0]), port))
                    ports[port] = p.uuid
                    p.port = port

                    def close_port(success, data):
                        log('reconnect complete; closing server port')
                        machine.close()

                    p.call(
                        'reconnect', ['admin', port], {},
                        lambda success, ret: (ports[port].call(
                            'send_machine', ['admin', None], {}, close_port)
                                              if success else close_port()))
                    broadcast(None, 'port_state', port, 2)
                    return False
            run_id = nextid()
            # Find uuid or create new Machine object.
            if uuid in machines:
                log('accepting known machine on port %s (uuid %s)' %
                    (port, uuid))
                machines[uuid].port = port
                ports[port] = uuid
                log('connecting %s to port %s' % (uuid, port))
                machines[uuid].call('connect',
                                    ['admin', port, [chr(x) for x in run_id]],
                                    {}, lambda success, ret: None)
            else:
                log('accepting unknown machine on port %s' % port)
                # Close detect port so it doesn't interfere.
                machine.close()
                #log('machines: %s' % repr(tuple(machines.keys())))
                process = subprocess.Popen(
                    (fhs.read_data('driver.py', opened=False), '--uuid',
                     uuid if uuid is not None else '', '--allow-system',
                     config['allow-system']) +
                    (('--system', ) if fhs.is_system else
                     ()) + (('--arc', 'False') if not config['arc'] else ()),
                    stdin=subprocess.PIPE,
                    stdout=subprocess.PIPE,
                    close_fds=True)
                new_machine = Machine(port,
                                      process,
                                      run_id,
                                      send=uuid is not None)

                def finish():
                    log('finish detect %s' % repr(uuid))
                    ports[port] = uuid
                    machines[uuid] = new_machine
                    log('connecting new machine %s to port %s' % (uuid, port))
                    new_machine.call('connect',
                                     ['admin', port, [chr(x) for x in run_id]],
                                     {}, lambda success, ret: None)

                if uuid is None:

                    def prefinish(success, uuid):
                        assert success
                        new_machine.uuid = uuid
                        new_machine.finish(finish)

                    new_machine.call('reset_uuid', ['admin'], {}, prefinish)
                else:
                    finish()
            return False

        def boot_machine_error():
            log('error during machine detection on port %s.' % port)
            websocketd.remove_timeout(timeout_handle[0])
            machine.close()
            ports[port] = None
            broadcast(None, 'port_state', port, 0)
            return False

        machine.write(protocol.single['ID'])
        timeout_handle = [websocketd.add_timeout(time.time() + .5, timeout)]
        watcher = websocketd.add_read(machine, boot_machine_input,
                                      boot_machine_error)

        def cancel():
            websocketd.remove_timeout(timeout_handle[0])
            websocketd.remove_read(watcher)
            machine.close()
            ports[port] = None

        ports[port] = cancel

    # Wait at least a second before sending anything, otherwise the bootloader thinks we might be trying to reprogram it.
    handle = websocketd.add_timeout(time.time() + 1.5, part2)

    def cancel():
        websocketd.remove_timeout(handle)
        ports[port] = None

    ports[port] = cancel
Пример #20
0
		def boot_machine_input():
			id[2] = True
			ids = [protocol.single[code][0] for code in ('ID', 'STARTUP')]
			# CMD:1 ID:8 + 16 Checksum:9 Total: 34
			while len(id[0]) < 34:
				try:
					data = machine.read(34 - len(id[0]))
				except OSError:
					continue
				except IOError:
					continue
				id[0] += data
				#log('incomplete id: ' + id[0])
				if len(id[0]) < 34:
					if len(id[0]) > 0 and id[0][0] == protocol.single['CONTROLLER'][0]:
						# This is a controller. Spawn the process, then cancel this detection.
						websocketd.remove_timeout(timeout_handle[0])
						machine.close()
						ports[port] = None
						broadcast(None, 'port_state', port, 0)
						log('Starting controller driver on ' + port)
						env = os.environ.copy()
						env['PORT'] = port
						subprocess.Popen(config['controller'], env = env, shell = True)
						return False
					return True
				if id[0][0] not in ids or not protocol.check(id[0]):
					log('skip non-id: %s (%s)' % (''.join('%02x' % x for x in id[0]), repr(id[0])))
					f = len(id[0])
					for start in ids:
						if start in id[0][1:]:
							p = id[0].index(bytes((start,)), 1)
							if p < f:
								f = p
							log('Keeping some')
					if f == 0:
						f = 1
					id[0] = id[0][f:]
					return True
			# We have something to handle; cancel the timeout, but keep the serial port open to avoid a reset. (I don't think this even works, but it doesn't hurt.)
			websocketd.remove_timeout(timeout_handle[0])
			# This machine was running and tried to send an id.  Check the id.
			uuid = id[0][9:9 + 16]
			if (uuid[7] & 0xf0) != 0x40 or (uuid[9] & 0xc0) != 0x80:
				# Broken uuid; create a new one and set it.
				log('broken uuid: ' + repr(uuid))
				uuid = None
			else:
				uuid = ''.join('%02x' % x for x in uuid[:16])
				uuid = uuid[:8] + '-' + uuid[8:12] + '-' + uuid[12:16] + '-' + uuid[16:20] + '-' + uuid[20:32]
				id[0] = id[0][1:9]
				running_machine = [p for p in machines if machines[p].run_id == id[0]]
				assert len(running_machine) < 2
				if len(running_machine) > 0:
					p = running_machine[0]
					assert p.uuid == uuid
					if p.port is not None:
						disable(p.uuid, 'disabled machine which was detected on different port')
					log('rediscovered machine %s on %s' % (''.join('%02x' % x for x in id[0]), port))
					ports[port] = p.uuid
					p.port = port
					def close_port(success, data):
						log('reconnect complete; closing server port')
						machine.close()
					p.call('reconnect', ['admin', port], {}, lambda success, ret: (ports[port].call('send_machine', ['admin', None], {}, close_port) if success else close_port()))
					broadcast(None, 'port_state', port, 2)
					return False
			run_id = nextid()
			# Find uuid or create new Machine object.
			if uuid in machines:
				log('accepting known machine on port %s (uuid %s)' % (port, uuid))
				machines[uuid].port = port
				ports[port] = uuid
				log('connecting %s to port %s' % (uuid, port))
				machines[uuid].call('connect', ['admin', port, [chr(x) for x in run_id]], {}, lambda success, ret: None)
			else:
				log('accepting unknown machine on port %s' % port)
				# Close detect port so it doesn't interfere.
				machine.close()
				#log('machines: %s' % repr(tuple(machines.keys())))
				process = subprocess.Popen((fhs.read_data('driver.py', opened = False), '--uuid', uuid if uuid is not None else '', '--allow-system', config['allow-system']) + (('--system',) if fhs.is_system else ()) + (('--arc', 'False') if not config['arc'] else ()), stdin = subprocess.PIPE, stdout = subprocess.PIPE, close_fds = True)
				new_machine = Machine(port, process, run_id, send = False)
				def finish():
					log('finish detect %s' % repr(uuid))
					ports[port] = uuid
					machines[uuid] = new_machine
					log('connecting new machine %s to port %s' % (uuid, port))
					new_machine.call('connect', ['admin', port, [chr(x) for x in run_id]], {}, lambda success, ret: None)
				if uuid is None:
					def prefinish(success, uuid):
						assert success
						new_machine.uuid = uuid
						new_machine.finish(finish)
					new_machine.call('reset_uuid', ['admin'], {}, prefinish)
				else:
					new_machine.finish(finish)
			return False
Пример #21
0
        def boot_printer_input(fd, cond):
            id[2] = True
            ids = [protocol.single[code][0] for code in ('ID', 'STARTUP')]
            # CMD:1 ID:8 Checksum:3
            while len(id[0]) < 12:
                try:
                    data = printer.read(12 - len(id[0]))
                except OSError:
                    continue
                except IOError:
                    continue
                id[0] += data
                #log('incomplete id: ' + id[0])
                if len(id[0]) < 12:
                    return True
                if id[0][0] not in ids or not protocol.check(id[0]):
                    log('skip non-id: %s (%s)' %
                        (''.join('%02x' % x for x in id[0]), repr(id[0])))
                    f = len(id[0])
                    for start in ids:
                        if start in id[0][1:]:
                            p = id[0].index(bytes((start, )))
                            if p < f:
                                f = p
                            log('Keeping some')
                    if f == 0:
                        f = 1
                    id[0] = id[0][f:]
                    return True
            # We have something to handle; cancel the timeout, but keep the serial port open to avoid a reset. (I don't think this even works, but it doesn't hurt.)
            GLib.source_remove(timeout_handle)
            # This printer was running and tried to send an id.  Check the id.
            id[0] = id[0][1:9]
            if id[0] in orphans:
                log('accepting orphan %s on %s' %
                    (''.join('%02x' % x for x in id[0]), port))
                ports[port] = orphans.pop(id[0])
                ports[port].port = port

                def close_port(success, data):
                    log('reconnect complete; closing server port')
                    printer.close()

                log('reconnecting %s' % port)
                ports[port].call(
                    'reconnect', ['admin', port], {},
                    lambda success, ret: ports[port].call(
                        'send_printer', ['admin', None], {}, close_port)
                    if success else close_port)
                return False
            run_id = nextid()
            log('accepting unknown printer on port %s (id %s)' %
                (port, ''.join('%02x' % x for x in run_id)))
            #log('orphans: %s' % repr(tuple(orphans.keys())))
            process = subprocess.Popen(
                (fhs.read_data('driver.py', opened=False), '--cdriver',
                 fhs.read_data('cdriver', opened=False), '--port', port,
                 '--run-id', run_id, '--allow-system', config['allow-system'])
                + (('--system', ) if fhs.is_system else ()),
                stdin=subprocess.PIPE,
                stdout=subprocess.PIPE,
                close_fds=True)
            ports[port] = Port(port, process, printer, run_id)
            return False
Пример #22
0
def detect(port): # {{{
	if port == '-' or port.startswith('!'):
		run_id = nextid()
		process = subprocess.Popen((fhs.read_data('driver.py', opened = False), '--cdriver', config['local'] or fhs.read_data('cdriver', opened = False), '--port', port, '--run-id', run_id, '--allow-system', config['allow-system']) + (('--system',) if fhs.is_system else ()), stdin = subprocess.PIPE, stdout = subprocess.PIPE, close_fds = True)
		ports[port] = Port(port, process, None, run_id)
		return False
	if not os.path.exists(port):
		log("not detecting on %s, because file doesn't exist." % port)
		return False
	if config['predetect']:
		subprocess.call(config['predetect'].replace('#PORT#', port), shell = True)
	try:
		printer = serial.Serial(port, baudrate = 115200, timeout = 0)
	except serial.SerialException:
		log('failed to open serial port.')
		traceback.print_exc();
		return False
	# We need to get the printer id first.  If the printer is booting, this can take a while.
	id = [None, None, None, None]	# data, timeouts, had data
	# Wait to make sure the command is interpreted as a new packet.
	def part2():
		id[0] = b''
		id[1] = 0
		id[2] = False
		def timeout():
			id[1] += 1
			if id[1] >= 30:
				# Timeout.  Give up.
				GLib.source_remove(watcher)
				printer.close()
				log('Timeout waiting for printer on port %s; giving up.' % port)
				ports[port] = None
				return False
			if not id[2]:
				printer.write(protocol.single['ID'])
			else:
				id[2] = False
			return True
		def boot_printer_input(fd, cond):
			id[2] = True
			ids = [protocol.single[code][0] for code in ('ID', 'STARTUP')]
			# CMD:1 ID:8 Checksum:3
			while len(id[0]) < 12:
				try:
					data = printer.read(12 - len(id[0]))
				except OSError:
					continue
				except IOError:
					continue
				id[0] += data
				#log('incomplete id: ' + id[0])
				if len(id[0]) < 12:
					return True
				if id[0][0] not in ids or not protocol.check(id[0]):
					log('skip non-id: %s (%s)' % (''.join('%02x' % x for x in id[0]), repr(id[0])))
					f = len(id[0])
					for start in ids:
						if start in id[0][1:]:
							p = id[0].index(bytes((start,)))
							if p < f:
								f = p
							log('Keeping some')
					if f == 0:
						f = 1
					id[0] = id[0][f:]
					return True
			# We have something to handle; cancel the timeout, but keep the serial port open to avoid a reset. (I don't think this even works, but it doesn't hurt.)
			GLib.source_remove(timeout_handle)
			# This printer was running and tried to send an id.  Check the id.
			id[0] = id[0][1:9]
			if id[0] in orphans:
				log('accepting orphan %s on %s' % (''.join('%02x' % x for x in id[0]), port))
				ports[port] = orphans.pop(id[0])
				ports[port].port = port
				def close_port(success, data):
					log('reconnect complete; closing server port')
					printer.close()
				log('reconnecting %s' % port)
				ports[port].call('reconnect', ['admin', port], {}, lambda success, ret: ports[port].call('send_printer', ['admin', None], {}, close_port) if success else close_port)
				return False
			run_id = nextid()
			log('accepting unknown printer on port %s (id %s)' % (port, ''.join('%02x' % x for x in run_id)))
			#log('orphans: %s' % repr(tuple(orphans.keys())))
			process = subprocess.Popen((fhs.read_data('driver.py', opened = False), '--cdriver', fhs.read_data('cdriver', opened = False), '--port', port, '--run-id', run_id, '--allow-system', config['allow-system']) + (('--system',) if fhs.is_system else ()), stdin = subprocess.PIPE, stdout = subprocess.PIPE, close_fds = True)
			ports[port] = Port(port, process, printer, run_id)
			return False
		printer.write(protocol.single['ID'])
		timeout_handle = GLib.timeout_add(500, timeout)
		watcher = GLib.io_add_watch(printer.fileno(), GLib.IO_IN, boot_printer_input)
	# Wait at least a second before sending anything, otherwise the bootloader thinks we might be trying to reprogram it.
	# This is only a problem for RAMPS; don't wait for ports that cannot be RAMPS.
	if 'ACM' in port:
		GLib.timeout_add(1500, part2)
	else:
		part2()
Пример #23
0
			machine.close()
			ports[port] = None
		ports[port] = cancel
	# Wait at least a second before sending anything, otherwise the bootloader thinks we might be trying to reprogram it.
	handle = websocketd.add_timeout(time.time() + 1.5, part2)
	def cancel():
		websocketd.remove_timeout(handle)
		ports[port] = None
	ports[port] = cancel
# }}}

# Main loop. {{{
def _disconnect(socket, data):
	del Connection.connections[socket.connection.id]
try:
	httpd = Server(config['port'], Connection, disconnect_cb = _disconnect, httpdirs = fhs.read_data('html', dir = True, multiple = True), address = config['address'], log = config['log'], tls = tls)
	udevsocket = fhs.write_runtime('udev.socket', packagename = 'franklin', opened = False)
	os.makedirs(os.path.dirname(udevsocket), exist_ok = True)
	if os.path.exists(udevsocket):
		os.unlink(udevsocket)
	udevserver = network.Server(udevsocket, Admin_Connection)
except OSError:
	log('failed to start server: %s' % sys.exc_info()[1])
	sys.exit(1)
# }}}

# Initialization. {{{
def create_machine(uuid = None): # {{{
	if uuid is None:
		uuid = protocol.new_uuid()
	process = subprocess.Popen((fhs.read_data('driver.py', opened = False), '--uuid', uuid, '--allow-system', config['allow-system']) + (('--system',) if fhs.is_system else ()), stdin = subprocess.PIPE, stdout = subprocess.PIPE, close_fds = True)
Пример #24
0
			machine.close()
			ports[port] = None
		ports[port] = cancel
	# Wait at least a second before sending anything, otherwise the bootloader thinks we might be trying to reprogram it.
	handle = websocketd.add_timeout(time.time() + 1.5, part2)
	def cancel():
		websocketd.remove_timeout(handle)
		ports[port] = None
	ports[port] = cancel
# }}}

# Main loop. {{{
def _disconnect(socket, data):
	del Connection.connections[socket.connection.id]
try:
	httpd = Server(config['port'], Connection, disconnect_cb = _disconnect, httpdirs = fhs.read_data('html', dir = True, multiple = True), address = config['address'], log = config['log'], tls = tls)
	udevsocket = fhs.write_runtime('udev.socket', packagename = 'franklin', opened = False)
	os.makedirs(os.path.dirname(udevsocket), exist_ok = True)
	if os.path.exists(udevsocket):
		os.unlink(udevsocket)
	udevserver = network.Server(udevsocket, Admin_Connection)
except OSError:
	log('failed to start server: %s' % sys.exc_info()[1])
	sys.exit(1)
# }}}

# Initialization. {{{
def create_machine(uuid = None): # {{{
	if uuid is None:
		uuid = protocol.new_uuid()
	process = subprocess.Popen((fhs.read_data('driver.py', opened = False), '--uuid', uuid, '--allow-system', config['allow-system']) + (('--system',) if fhs.is_system else ()) + (('--arc', 'False') if not config['arc'] else ()), stdin = subprocess.PIPE, stdout = subprocess.PIPE, close_fds = True)
Пример #25
0
def create_machine(uuid = None): # {{{
	if uuid is None:
		uuid = protocol.new_uuid()
	process = subprocess.Popen((fhs.read_data('driver.py', opened = False), '--uuid', uuid, '--allow-system', config['allow-system']) + (('--system',) if fhs.is_system else ()) + (('--arc', 'False') if not config['arc'] else ()), stdin = subprocess.PIPE, stdout = subprocess.PIPE, close_fds = True)
	machines[uuid] = Machine(None, process, None)
	return uuid
Пример #26
0
def detect(port):  # {{{
    if port == '-' or port.startswith('!'):
        run_id = nextid()
        process = subprocess.Popen(
            (fhs.read_data('driver.py', opened=False), '--cdriver',
             config['local'] or fhs.read_data('cdriver', opened=False),
             '--port', port, '--run-id', run_id, '--allow-system',
             config['allow-system']) + (('--system', ) if fhs.is_system else
                                        ()),
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            close_fds=True)
        ports[port] = Port(port, process, None, run_id)
        return False
    if not os.path.exists(port):
        log("not detecting on %s, because file doesn't exist." % port)
        return False
    if config['predetect']:
        subprocess.call(config['predetect'].replace('#PORT#', port),
                        shell=True)
    try:
        printer = serial.Serial(port, baudrate=115200, timeout=0)
    except serial.SerialException:
        log('failed to open serial port.')
        traceback.print_exc()
        return False
    # We need to get the printer id first.  If the printer is booting, this can take a while.
    id = [None, None, None, None]  # data, timeouts, had data

    # Wait to make sure the command is interpreted as a new packet.
    def part2():
        id[0] = b''
        id[1] = 0
        id[2] = False

        def timeout():
            id[1] += 1
            if id[1] >= 30:
                # Timeout.  Give up.
                GLib.source_remove(watcher)
                printer.close()
                log('Timeout waiting for printer on port %s; giving up.' %
                    port)
                ports[port] = None
                return False
            if not id[2]:
                printer.write(protocol.single['ID'])
            else:
                id[2] = False
            return True

        def boot_printer_input(fd, cond):
            id[2] = True
            ids = [protocol.single[code][0] for code in ('ID', 'STARTUP')]
            # CMD:1 ID:8 Checksum:3
            while len(id[0]) < 12:
                try:
                    data = printer.read(12 - len(id[0]))
                except OSError:
                    continue
                except IOError:
                    continue
                id[0] += data
                #log('incomplete id: ' + id[0])
                if len(id[0]) < 12:
                    return True
                if id[0][0] not in ids or not protocol.check(id[0]):
                    log('skip non-id: %s (%s)' %
                        (''.join('%02x' % x for x in id[0]), repr(id[0])))
                    f = len(id[0])
                    for start in ids:
                        if start in id[0][1:]:
                            p = id[0].index(bytes((start, )))
                            if p < f:
                                f = p
                            log('Keeping some')
                    if f == 0:
                        f = 1
                    id[0] = id[0][f:]
                    return True
            # We have something to handle; cancel the timeout, but keep the serial port open to avoid a reset. (I don't think this even works, but it doesn't hurt.)
            GLib.source_remove(timeout_handle)
            # This printer was running and tried to send an id.  Check the id.
            id[0] = id[0][1:9]
            if id[0] in orphans:
                log('accepting orphan %s on %s' %
                    (''.join('%02x' % x for x in id[0]), port))
                ports[port] = orphans.pop(id[0])
                ports[port].port = port

                def close_port(success, data):
                    log('reconnect complete; closing server port')
                    printer.close()

                log('reconnecting %s' % port)
                ports[port].call(
                    'reconnect', ['admin', port], {},
                    lambda success, ret: ports[port].call(
                        'send_printer', ['admin', None], {}, close_port)
                    if success else close_port)
                return False
            run_id = nextid()
            log('accepting unknown printer on port %s (id %s)' %
                (port, ''.join('%02x' % x for x in run_id)))
            #log('orphans: %s' % repr(tuple(orphans.keys())))
            process = subprocess.Popen(
                (fhs.read_data('driver.py', opened=False), '--cdriver',
                 fhs.read_data('cdriver', opened=False), '--port', port,
                 '--run-id', run_id, '--allow-system', config['allow-system'])
                + (('--system', ) if fhs.is_system else ()),
                stdin=subprocess.PIPE,
                stdout=subprocess.PIPE,
                close_fds=True)
            ports[port] = Port(port, process, printer, run_id)
            return False

        printer.write(protocol.single['ID'])
        timeout_handle = GLib.timeout_add(500, timeout)
        watcher = GLib.io_add_watch(printer.fileno(), GLib.IO_IN,
                                    boot_printer_input)

    # Wait at least a second before sending anything, otherwise the bootloader thinks we might be trying to reprogram it.
    # This is only a problem for RAMPS; don't wait for ports that cannot be RAMPS.
    if 'ACM' in port:
        GLib.timeout_add(1500, part2)
    else:
        part2()
Пример #27
0
        def boot_printer_input():
            id[2] = True
            ids = [protocol.single[code][0] for code in ('ID', 'STARTUP')]
            # CMD:1 ID:8 + 16 Checksum:9 Total: 34
            while len(id[0]) < 34:
                try:
                    data = printer.read(34 - len(id[0]))
                except OSError:
                    continue
                except IOError:
                    continue
                id[0] += data
                #log('incomplete id: ' + id[0])
                if len(id[0]) < 34:
                    return True
                if id[0][0] not in ids or not protocol.check(id[0]):
                    log('skip non-id: %s (%s)' %
                        (''.join('%02x' % x for x in id[0]), repr(id[0])))
                    f = len(id[0])
                    for start in ids:
                        if start in id[0][1:]:
                            p = id[0].index(bytes((start, )), 1)
                            if p < f:
                                f = p
                            log('Keeping some')
                    if f == 0:
                        f = 1
                    id[0] = id[0][f:]
                    return True
            # We have something to handle; cancel the timeout, but keep the serial port open to avoid a reset. (I don't think this even works, but it doesn't hurt.)
            websocketd.remove_timeout(timeout_handle[0])
            # This printer was running and tried to send an id.  Check the id.
            uuid = id[0][9:9 + 16]
            if (uuid[7] & 0xf0) != 0x40 or (uuid[9] & 0xc0) != 0x80:
                # Broken uuid; create a new one and set it.
                log('broken uuid: ' + repr(uuid))
                uuid = None
            else:
                uuid = ''.join('%02x' % x for x in uuid[:16])
                uuid = uuid[:8] + '-' + uuid[8:12] + '-' + uuid[
                    12:16] + '-' + uuid[16:20] + '-' + uuid[20:32]
                id[0] = id[0][1:9]
                running_printer = [
                    p for p in printers if printers[p].run_id == id[0]
                ]
                assert len(running_printer) < 2
                if len(running_printer) > 0:
                    p = running_printer[0]
                    assert p.uuid == uuid
                    if p.port is not None:
                        disable(
                            p.uuid,
                            'disabled printer which was detected on different port'
                        )
                    log('rediscovered printer %s on %s' %
                        (''.join('%02x' % x for x in id[0]), port))
                    ports[port] = p.uuid
                    p.port = port

                    def close_port(success, data):
                        log('reconnect complete; closing server port')
                        printer.close()

                    p.call(
                        'reconnect', ['admin', port], {},
                        lambda success, ret: (ports[port].call(
                            'send_printer', ['admin', None], {}, close_port)
                                              if success else close_port()))
                    broadcast(None, 'port_state', port, 2)
                    return False
            run_id = nextid()
            # Find uuid or create new Printer object.
            if uuid in printers:
                log('accepting known printer on port %s (uuid %s)' %
                    (port, uuid))
                printers[uuid].port = port
                ports[port] = uuid
                log('connecting %s to port %s' % (uuid, port))
                printers[uuid].call('connect',
                                    ['admin', port, [chr(x) for x in run_id]],
                                    {}, lambda success, ret: None)
            else:
                log('accepting unknown printer on port %s' % port)
                #log('printers: %s' % repr(tuple(printers.keys())))
                process = subprocess.Popen(
                    (fhs.read_data('driver.py', opened=False), '--cdriver',
                     fhs.read_data('franklin-cdriver', opened=False), '--uuid',
                     uuid if uuid is not None else '', '--allow-system',
                     config['allow-system']) +
                    (('--system', ) if fhs.is_system else
                     ()) + (('--arc', 'False') if not config['arc'] else ()),
                    stdin=subprocess.PIPE,
                    stdout=subprocess.PIPE,
                    close_fds=True)
                new_printer = Printer(port, process, printer, run_id)

                def finish(success, uuid):
                    assert success
                    ports[port] = uuid
                    printers[uuid] = new_printer
                    log('connecting new printer %s to port %s' % (uuid, port))
                    new_printer.call('connect',
                                     ['admin', port, [chr(x) for x in run_id]],
                                     {}, lambda success, ret: None)

                if uuid is None:
                    new_printer.call('reset_uuid', ['admin'], {}, finish)
                else:
                    finish(True, uuid)
            return False
Пример #28
0

# }}}
# }}}


# Main loop. {{{
def _disconnect(socket, data):
    del Connection.connections[socket.connection.id]


try:
    httpd = Server(config['port'],
                   Connection,
                   disconnect_cb=_disconnect,
                   httpdirs=fhs.read_data('html', dir=True, multiple=True),
                   address=config['address'],
                   log=config['log'],
                   tls=tls)
except OSError:
    log('failed to start server: %s' % sys.exc_info()[1])
    sys.exit(1)
# }}}


# Initialization. {{{
def create_machine(uuid=None):  # {{{
    if uuid is None:
        uuid = protocol.new_uuid()
    process = subprocess.Popen(
        (fhs.read_data('driver.py', opened=False), '--uuid', uuid,
Пример #29
0
def detect(port): # {{{
	log('detecting machine on %s' % port)
	if port not in ports:
		log('port does not exist')
		return
	if ports[port] != None:
		# Abort detection in progress.
		if ports[port]:
			disable(ports[port], 'disabled to prepare for detection')
		if ports[port] != None:
			# This should never happen.
			log('BUG: port is not in detectable state. Please report this.')
			return
	broadcast(None, 'port_state', port, 1)
	if port == '-' or port.startswith('!'):
		run_id = nextid()
		process = subprocess.Popen((fhs.read_data('driver.py', opened = False), '--uuid', '-', '--allow-system', config['allow-system']) + (('--system',) if fhs.is_system else ()) + (('--arc', 'False') if not config['arc'] else ()), stdin = subprocess.PIPE, stdout = subprocess.PIPE, close_fds = True)
		machines[port] = Machine(port, process, run_id)
		ports[port] = port
		return False
	if not os.path.exists(port):
		log("not detecting on %s, because file doesn't exist." % port)
		return False
	if config['predetect']:
		env = os.environ.copy()
		env['PORT'] = port
		subprocess.call(config['predetect'], env = env, shell = True)
	try:
		machine = serial.Serial(port, baudrate = 115200, timeout = 0)
	except serial.SerialException as e:
		log('failed to open serial port %s (%s).' % (port, str(e)))
		del ports[port]
		#traceback.print_exc()
		return False
	# We need to get the machine id first.  If the machine is booting, this can take a while.
	id = [None, None, None, None]	# data, timeouts, had data
	# Wait to make sure the command is interpreted as a new packet.
	def part2():
		id[0] = b''
		id[1] = 0
		id[2] = False
		def timeout():
			id[1] += 1
			if id[1] >= 30:
				# Timeout.  Give up.
				websocketd.remove_read(watcher)
				machine.close()
				log('Timeout waiting for machine on port %s; giving up.' % port)
				ports[port] = None
				broadcast(None, 'port_state', port, 0)
				return
			if not id[2]:
				machine.write(protocol.single['ID'])
			else:
				id[2] = False
			timeout_handle[0] = websocketd.add_timeout(time.time() + .5, timeout)
		def boot_machine_input():
			id[2] = True
			ids = [protocol.single[code][0] for code in ('ID', 'STARTUP')]
			# CMD:1 ID:8 + 16 Checksum:9 Total: 34
			while len(id[0]) < 34:
				try:
					data = machine.read(34 - len(id[0]))
				except OSError:
					continue
				except IOError:
					continue
				id[0] += data
				#log('incomplete id: ' + id[0])
				if len(id[0]) < 34:
					if len(id[0]) > 0 and id[0][0] == protocol.single['CONTROLLER'][0]:
						# This is a controller. Spawn the process, then cancel this detection.
						websocketd.remove_timeout(timeout_handle[0])
						machine.close()
						ports[port] = None
						broadcast(None, 'port_state', port, 0)
						log('Starting controller driver on ' + port)
						env = os.environ.copy()
						env['PORT'] = port
						subprocess.Popen(config['controller'], env = env, shell = True)
						return False
					return True
				if id[0][0] not in ids or not protocol.check(id[0]):
					log('skip non-id: %s (%s)' % (''.join('%02x' % x for x in id[0]), repr(id[0])))
					f = len(id[0])
					for start in ids:
						if start in id[0][1:]:
							p = id[0].index(bytes((start,)), 1)
							if p < f:
								f = p
							log('Keeping some')
					if f == 0:
						f = 1
					id[0] = id[0][f:]
					return True
			# We have something to handle; cancel the timeout, but keep the serial port open to avoid a reset. (I don't think this even works, but it doesn't hurt.)
			websocketd.remove_timeout(timeout_handle[0])
			# This machine was running and tried to send an id.  Check the id.
			uuid = id[0][9:9 + 16]
			if (uuid[7] & 0xf0) != 0x40 or (uuid[9] & 0xc0) != 0x80:
				# Broken uuid; create a new one and set it.
				log('broken uuid: ' + repr(uuid))
				uuid = None
			else:
				uuid = ''.join('%02x' % x for x in uuid[:16])
				uuid = uuid[:8] + '-' + uuid[8:12] + '-' + uuid[12:16] + '-' + uuid[16:20] + '-' + uuid[20:32]
				id[0] = id[0][1:9]
				running_machine = [p for p in machines if machines[p].run_id == id[0]]
				assert len(running_machine) < 2
				if len(running_machine) > 0:
					p = running_machine[0]
					assert p.uuid == uuid
					if p.port is not None:
						disable(p.uuid, 'disabled machine which was detected on different port')
					log('rediscovered machine %s on %s' % (''.join('%02x' % x for x in id[0]), port))
					ports[port] = p.uuid
					p.port = port
					def close_port(success, data):
						log('reconnect complete; closing server port')
						machine.close()
					p.call('reconnect', ['admin', port], {}, lambda success, ret: (ports[port].call('send_machine', ['admin', None], {}, close_port) if success else close_port()))
					broadcast(None, 'port_state', port, 2)
					return False
			run_id = nextid()
			# Find uuid or create new Machine object.
			if uuid in machines:
				log('accepting known machine on port %s (uuid %s)' % (port, uuid))
				machines[uuid].port = port
				ports[port] = uuid
				log('connecting %s to port %s' % (uuid, port))
				machines[uuid].call('connect', ['admin', port, [chr(x) for x in run_id]], {}, lambda success, ret: None)
			else:
				log('accepting unknown machine on port %s' % port)
				# Close detect port so it doesn't interfere.
				machine.close()
				#log('machines: %s' % repr(tuple(machines.keys())))
				process = subprocess.Popen((fhs.read_data('driver.py', opened = False), '--uuid', uuid if uuid is not None else '', '--allow-system', config['allow-system']) + (('--system',) if fhs.is_system else ()) + (('--arc', 'False') if not config['arc'] else ()), stdin = subprocess.PIPE, stdout = subprocess.PIPE, close_fds = True)
				new_machine = Machine(port, process, run_id, send = False)
				def finish():
					log('finish detect %s' % repr(uuid))
					ports[port] = uuid
					machines[uuid] = new_machine
					log('connecting new machine %s to port %s' % (uuid, port))
					new_machine.call('connect', ['admin', port, [chr(x) for x in run_id]], {}, lambda success, ret: None)
				if uuid is None:
					def prefinish(success, uuid):
						assert success
						new_machine.uuid = uuid
						new_machine.finish(finish)
					new_machine.call('reset_uuid', ['admin'], {}, prefinish)
				else:
					new_machine.finish(finish)
			return False
		def boot_machine_error():
			log('error during machine detection on port %s.' % port)
			websocketd.remove_timeout(timeout_handle[0])
			machine.close()
			ports[port] = None
			broadcast(None, 'port_state', port, 0)
			return False
		machine.write(protocol.single['ID'])
		timeout_handle = [websocketd.add_timeout(time.time() + .5, timeout)]
		watcher = websocketd.add_read(machine, boot_machine_input, boot_machine_error)
		def cancel():
			websocketd.remove_timeout(timeout_handle[0])
			websocketd.remove_read(watcher)
			machine.close()
			ports[port] = None
		ports[port] = cancel
	# Wait at least a second before sending anything, otherwise the bootloader thinks we might be trying to reprogram it.
	handle = websocketd.add_timeout(time.time() + 1.5, part2)
	def cancel():
		websocketd.remove_timeout(handle)
		ports[port] = None
	ports[port] = cancel
Пример #30
0
def Game(): # Main function to start a game. {{{
	global server, title_game, have_2d, have_3d, _num_players
	# Set up the game name.
	if not hasattr(__main__, 'name') or __main__.name is None:
		__main__.name = os.path.basename(sys.argv[0]).capitalize()
	# Initialize fhs module.
	if not fhs.initialized:
		fhs.init({}, packagename = __main__.name.lower(), game = True)
	# Set up other constants.
	if not hasattr(__main__, 'autokill'):
		__main__.autokill = True
	have_2d = fhs.read_data(os.path.join('html', '2d'), dir = True, opened = False) is not None
	have_3d = fhs.read_data(os.path.join('html', '3d'), dir = True, opened = False) is not None or not have_2d
	# Fill in min and max if not specified.
	assert hasattr(__main__, 'num_players')
	if isinstance(__main__.num_players, int):
		_num_players = (__main__.num_players, __main__.num_players)
	else:
		_num_players = __main__.num_players
	assert 1 <= _num_players[0] and (_num_players[1] is None or _num_players[0] <= _num_players[1])
	# Build asset string for inserting in js.
	for subdir, use_3d in (('2d', False), ('3d', True)):
		targets = []
		for base in ('img', 'jta', 'gani', 'audio', 'text'):
			for d in (os.path.join('html', base), os.path.join('html', subdir, base)):
				for p in fhs.read_data(d, dir = True, multiple = True, opened = False):
					targets.extend(f.encode('utf-8') for f in os.listdir(p) if not f.startswith('.') and not os.path.isdir(os.path.join(p, f)))
		if len(targets) > 0:
			loader_js[use_3d] = b'\n'.join(b"\tplease.load('" + f + b"');" for f in targets)
		else:
			# Nothing to load, but force the "finished loading" event to fire anyway.
			loader_js[use_3d] = b'\twindow.dispatchEvent(new CustomEvent("mgrl_media_ready"));'
	# Set up commands.
	cmds['leave'] = {None: leave}
	if hasattr(__main__, 'commands'):
		for c in __main__.commands:
			cmds[c] = {None: __main__.commands[c]}
	# Start up websockets server.
	config = fhs.module_get_config('webgame')
	httpdirs = [fhs.read_data(x, opened = False, multiple = True, dir = True) for x in ('html', os.path.join('html', '2d'), os.path.join('html', '3d'))]
	server = websocketd.RPChttpd(config['port'], Connection, tls = config['tls'], httpdirs = httpdirs[0] + httpdirs[1] + httpdirs[2])
	server.handle_ext('png', 'image/png')
	server.handle_ext('jpg', 'image/jpeg')
	server.handle_ext('jpeg', 'image/jpeg')
	server.handle_ext('gif', 'image/gif')
	server.handle_ext('gani', 'text/plain')
	server.handle_ext('wav', 'audio/wav')
	server.handle_ext('ogg', 'audio/ogg')
	server.handle_ext('mp3', 'audio/mp3')
	server.handle_ext('jta', 'application/octet-stream')
	server.handle_ext('txt', 'text/plain')
	server.handle_ext('frag', 'text/plain')
	server.handle_ext('vert', 'text/plain')
	server.handle_ext('glsl', 'text/plain')
	# Set up title page.
	if hasattr(__main__, 'Title'):
		title_game = Instance(__main__.Title, '')
	else:
		title_game = Instance(Title, '')
	log('Game "%s" started' % __main__.name)
	# Main loop.
	websocketd.fgloop()
Пример #31
0
		'allow-system': '^$',
		'admin': '',
		'expert': '',
		'user': '',
		'done': '',
		'local': '',
		'driver': '',
		'cdriver': '',
		'log': '',
		'tls': 'True',
		'avrdudeconfig': '/usr/lib/franklin/avrdude.conf'
	})
if config['audiodir'] == '':
	config['audiodir'] = fhs.write_cache(name = 'audio', dir = True),
if config['driver'] == '':
	config['driver'] = fhs.read_data('driver.py', opened = False)
if config['cdriver'] == '':
	config['cdriver'] = fhs.read_data('cdriver', opened = False)
# }}}

# Global variables. {{{
httpd = None
default_printer = (None, None)
ports = {}
autodetect = config['autodetect'].lower() == 'true'
tls = config['tls'].lower() == 'true'
orphans = {}
scripts = {}
# }}}

# Load scripts. {{{