mirror of
				https://github.com/Klipper3d/klipper.git
				synced 2025-11-03 03:46:25 +01:00 
			
		
		
		
	klippy: Store printer startup parameters in new "start_args" dictionary
Store pertinent information from the software startup in a dictionary that the various printer components can access instead of in individual variables in the Printer() class. This makes it easier to add future command-line options. Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
		@@ -9,15 +9,15 @@ import homing, extruder
 | 
			
		||||
# Parse out incoming GCode and find and translate head movements
 | 
			
		||||
class GCodeParser:
 | 
			
		||||
    RETRY_TIME = 0.100
 | 
			
		||||
    def __init__(self, printer, fd, is_fileinput=False):
 | 
			
		||||
    def __init__(self, printer, fd):
 | 
			
		||||
        self.printer = printer
 | 
			
		||||
        self.fd = fd
 | 
			
		||||
        self.is_fileinput = is_fileinput
 | 
			
		||||
        # Input handling
 | 
			
		||||
        self.reactor = printer.reactor
 | 
			
		||||
        self.is_processing_data = False
 | 
			
		||||
        self.is_fileinput = not not printer.get_start_args().get("debuginput")
 | 
			
		||||
        self.fd_handle = None
 | 
			
		||||
        if not is_fileinput:
 | 
			
		||||
        if not self.is_fileinput:
 | 
			
		||||
            self.fd_handle = self.reactor.register_fd(self.fd, self.process_data)
 | 
			
		||||
        self.partial_input = ""
 | 
			
		||||
        self.bytes_read = 0
 | 
			
		||||
@@ -140,7 +140,6 @@ class GCodeParser:
 | 
			
		||||
        if not data and self.is_fileinput:
 | 
			
		||||
            self.motor_heater_off()
 | 
			
		||||
            if self.toolhead is not None:
 | 
			
		||||
                if not self.printer.mcu.is_fileoutput():
 | 
			
		||||
                self.toolhead.wait_moves()
 | 
			
		||||
            self.printer.request_exit('exit_eof')
 | 
			
		||||
        self.is_processing_data = False
 | 
			
		||||
@@ -392,8 +391,8 @@ class GCodeParser:
 | 
			
		||||
    cmd_M115_when_not_ready = True
 | 
			
		||||
    def cmd_M115(self, params):
 | 
			
		||||
        # Get Firmware Version and Capabilities
 | 
			
		||||
        kw = {"FIRMWARE_NAME": "Klipper"
 | 
			
		||||
              , "FIRMWARE_VERSION": self.printer.software_version}
 | 
			
		||||
        software_version = self.printer.get_start_args().get('software_version')
 | 
			
		||||
        kw = {"FIRMWARE_NAME": "Klipper", "FIRMWARE_VERSION": software_version}
 | 
			
		||||
        self.ack(" ".join(["%s:%s" % (k, v) for k, v in kw.items()]))
 | 
			
		||||
    def cmd_M140(self, params):
 | 
			
		||||
        # Set Bed Temperature
 | 
			
		||||
 
 | 
			
		||||
@@ -112,8 +112,8 @@ class PrinterHeater:
 | 
			
		||||
        self.min_extrude_temp = config.getfloat(
 | 
			
		||||
            'min_extrude_temp', 170., minval=self.min_temp, maxval=self.max_temp)
 | 
			
		||||
        self.max_power = config.getfloat('max_power', 1., above=0., maxval=1.)
 | 
			
		||||
        self.can_extrude = (self.min_extrude_temp <= 0.
 | 
			
		||||
                            or printer.mcu.is_fileoutput())
 | 
			
		||||
        is_fileoutput = printer.get_start_args().get('debugoutput') is not None
 | 
			
		||||
        self.can_extrude = self.min_extrude_temp <= 0. or is_fileoutput
 | 
			
		||||
        self.lock = threading.Lock()
 | 
			
		||||
        self.last_temp = 0.
 | 
			
		||||
        self.last_temp_time = 0.
 | 
			
		||||
 
 | 
			
		||||
@@ -123,30 +123,25 @@ class ConfigLogger():
 | 
			
		||||
        self.lines.append(data.strip())
 | 
			
		||||
 | 
			
		||||
class Printer:
 | 
			
		||||
    def __init__(self, conffile, input_fd, startup_state
 | 
			
		||||
                 , is_fileinput=False, version="?", bglogger=None):
 | 
			
		||||
        self.conffile = conffile
 | 
			
		||||
        self.startup_state = startup_state
 | 
			
		||||
        self.software_version = version
 | 
			
		||||
    def __init__(self, input_fd, bglogger, start_args):
 | 
			
		||||
        self.bglogger = bglogger
 | 
			
		||||
        self.start_args = start_args
 | 
			
		||||
        if bglogger is not None:
 | 
			
		||||
            bglogger.set_rollover_info("config", None)
 | 
			
		||||
        self.reactor = reactor.Reactor()
 | 
			
		||||
        self.objects = {}
 | 
			
		||||
        self.gcode = gcode.GCodeParser(self, input_fd, is_fileinput)
 | 
			
		||||
        self.gcode = gcode.GCodeParser(self, input_fd)
 | 
			
		||||
        self.stats_timer = self.reactor.register_timer(self.stats)
 | 
			
		||||
        self.connect_timer = self.reactor.register_timer(
 | 
			
		||||
            self.connect, self.reactor.NOW)
 | 
			
		||||
        self.all_config_options = {}
 | 
			
		||||
        self.need_dump_debug = False
 | 
			
		||||
        self.state_message = message_startup
 | 
			
		||||
        self.debugoutput = self.dictionary = None
 | 
			
		||||
        self.run_result = None
 | 
			
		||||
        self.fileconfig = None
 | 
			
		||||
        self.mcu = None
 | 
			
		||||
    def set_fileoutput(self, debugoutput, dictionary):
 | 
			
		||||
        self.debugoutput = debugoutput
 | 
			
		||||
        self.dictionary = dictionary
 | 
			
		||||
    def get_start_args(self):
 | 
			
		||||
        return self.start_args
 | 
			
		||||
    def stats(self, eventtime, force_output=False):
 | 
			
		||||
        if self.need_dump_debug:
 | 
			
		||||
            # Call dump_debug here so it is executed in the main thread
 | 
			
		||||
@@ -168,15 +163,14 @@ class Printer:
 | 
			
		||||
        self.objects[name] = obj
 | 
			
		||||
    def load_config(self):
 | 
			
		||||
        self.fileconfig = ConfigParser.RawConfigParser()
 | 
			
		||||
        res = self.fileconfig.read(self.conffile)
 | 
			
		||||
        config_file = self.start_args['config_file']
 | 
			
		||||
        res = self.fileconfig.read(config_file)
 | 
			
		||||
        if not res:
 | 
			
		||||
            raise ConfigParser.Error("Unable to open config file %s" % (
 | 
			
		||||
                self.conffile,))
 | 
			
		||||
                config_file,))
 | 
			
		||||
        if self.bglogger is not None:
 | 
			
		||||
            ConfigLogger(self.fileconfig, self.bglogger)
 | 
			
		||||
        self.mcu = mcu.MCU(self, ConfigWrapper(self, 'mcu'))
 | 
			
		||||
        if self.debugoutput is not None:
 | 
			
		||||
            self.mcu.connect_file(self.debugoutput, self.dictionary)
 | 
			
		||||
        # Create printer components
 | 
			
		||||
        config = ConfigWrapper(self, 'printer')
 | 
			
		||||
        for m in [extruder, fan, heater, toolhead]:
 | 
			
		||||
@@ -197,7 +191,7 @@ class Printer:
 | 
			
		||||
    def connect(self, eventtime):
 | 
			
		||||
        try:
 | 
			
		||||
            self.load_config()
 | 
			
		||||
            if self.debugoutput is None:
 | 
			
		||||
            if self.start_args.get('debugoutput') is None:
 | 
			
		||||
                self.reactor.update_timer(self.stats_timer, self.reactor.NOW)
 | 
			
		||||
            self.mcu.connect()
 | 
			
		||||
            self.gcode.set_printer_ready(True)
 | 
			
		||||
@@ -259,8 +253,6 @@ class Printer:
 | 
			
		||||
                self.mcu.disconnect()
 | 
			
		||||
        except:
 | 
			
		||||
            logging.exception("Unhandled exception during firmware_restart")
 | 
			
		||||
    def get_startup_state(self):
 | 
			
		||||
        return self.startup_state
 | 
			
		||||
    def request_exit(self, result="exit"):
 | 
			
		||||
        self.run_result = result
 | 
			
		||||
        self.reactor.end()
 | 
			
		||||
@@ -270,18 +262,10 @@ class Printer:
 | 
			
		||||
# Startup
 | 
			
		||||
######################################################################
 | 
			
		||||
 | 
			
		||||
def read_dictionary(filename):
 | 
			
		||||
    dfile = open(filename, 'rb')
 | 
			
		||||
    dictionary = dfile.read()
 | 
			
		||||
    dfile.close()
 | 
			
		||||
    return dictionary
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
    usage = "%prog [options] <config file>"
 | 
			
		||||
    opts = optparse.OptionParser(usage)
 | 
			
		||||
    opts.add_option("-o", "--debugoutput", dest="outputfile",
 | 
			
		||||
                    help="write output to file instead of to serial port")
 | 
			
		||||
    opts.add_option("-i", "--debuginput", dest="inputfile",
 | 
			
		||||
    opts.add_option("-i", "--debuginput", dest="debuginput",
 | 
			
		||||
                    help="read commands from file instead of from tty port")
 | 
			
		||||
    opts.add_option("-I", "--input-tty", dest="inputtty", default='/tmp/printer',
 | 
			
		||||
                    help="input tty name (default is /tmp/printer)")
 | 
			
		||||
@@ -289,63 +273,60 @@ def main():
 | 
			
		||||
                    help="write log to file instead of stderr")
 | 
			
		||||
    opts.add_option("-v", action="store_true", dest="verbose",
 | 
			
		||||
                    help="enable debug messages")
 | 
			
		||||
    opts.add_option("-d", dest="read_dictionary",
 | 
			
		||||
    opts.add_option("-o", "--debugoutput", dest="debugoutput",
 | 
			
		||||
                    help="write output to file instead of to serial port")
 | 
			
		||||
    opts.add_option("-d", "--dictionary", dest="dictionary",
 | 
			
		||||
                    help="file to read for mcu protocol dictionary")
 | 
			
		||||
    options, args = opts.parse_args()
 | 
			
		||||
    if len(args) != 1:
 | 
			
		||||
        opts.error("Incorrect number of arguments")
 | 
			
		||||
    conffile = args[0]
 | 
			
		||||
    start_args = {'config_file': args[0], 'start_reason': 'startup'}
 | 
			
		||||
 | 
			
		||||
    input_fd = debuginput = debugoutput = bglogger = None
 | 
			
		||||
    input_fd = bglogger = None
 | 
			
		||||
 | 
			
		||||
    debuglevel = logging.INFO
 | 
			
		||||
    if options.verbose:
 | 
			
		||||
        debuglevel = logging.DEBUG
 | 
			
		||||
    if options.inputfile:
 | 
			
		||||
        debuginput = open(options.inputfile, 'rb')
 | 
			
		||||
    if options.debuginput:
 | 
			
		||||
        start_args['debuginput'] = options.debuginput
 | 
			
		||||
        debuginput = open(options.debuginput, 'rb')
 | 
			
		||||
        input_fd = debuginput.fileno()
 | 
			
		||||
    else:
 | 
			
		||||
        input_fd = util.create_pty(options.inputtty)
 | 
			
		||||
    if options.outputfile:
 | 
			
		||||
        debugoutput = open(options.outputfile, 'wb')
 | 
			
		||||
    if options.debugoutput:
 | 
			
		||||
        start_args['debugoutput'] = options.debugoutput
 | 
			
		||||
        start_args['dictionary'] = options.dictionary
 | 
			
		||||
    if options.logfile:
 | 
			
		||||
        bglogger = queuelogger.setup_bg_logging(options.logfile, debuglevel)
 | 
			
		||||
    else:
 | 
			
		||||
        logging.basicConfig(level=debuglevel)
 | 
			
		||||
    logging.info("Starting Klippy...")
 | 
			
		||||
    software_version = util.get_git_version()
 | 
			
		||||
    start_args['software_version'] = util.get_git_version()
 | 
			
		||||
    if bglogger is not None:
 | 
			
		||||
        lines = ["Args: %s" % (sys.argv,),
 | 
			
		||||
                 "Git version: %s" % (repr(software_version),),
 | 
			
		||||
                 "Git version: %s" % (repr(start_args['software_version']),),
 | 
			
		||||
                 "CPU: %s" % (util.get_cpu_info(),),
 | 
			
		||||
                 "Python: %s" % (repr(sys.version),)]
 | 
			
		||||
        lines = "\n".join(lines)
 | 
			
		||||
        logging.info(lines)
 | 
			
		||||
        bglogger.set_rollover_info('versions', lines)
 | 
			
		||||
 | 
			
		||||
    # Start firmware
 | 
			
		||||
    res = 'startup'
 | 
			
		||||
    # Start Printer() class
 | 
			
		||||
    while 1:
 | 
			
		||||
        is_fileinput = debuginput is not None
 | 
			
		||||
        printer = Printer(
 | 
			
		||||
            conffile, input_fd, res, is_fileinput, software_version, bglogger)
 | 
			
		||||
        if debugoutput:
 | 
			
		||||
            proto_dict = read_dictionary(options.read_dictionary)
 | 
			
		||||
            printer.set_fileoutput(debugoutput, proto_dict)
 | 
			
		||||
        printer = Printer(input_fd, bglogger, start_args)
 | 
			
		||||
        res = printer.run()
 | 
			
		||||
        if res == 'restart':
 | 
			
		||||
            printer.disconnect()
 | 
			
		||||
            time.sleep(1.)
 | 
			
		||||
            logging.info("Restarting printer")
 | 
			
		||||
            continue
 | 
			
		||||
        elif res == 'firmware_restart':
 | 
			
		||||
            printer.firmware_restart()
 | 
			
		||||
            time.sleep(1.)
 | 
			
		||||
            logging.info("Restarting printer")
 | 
			
		||||
            continue
 | 
			
		||||
        elif res == 'exit_eof':
 | 
			
		||||
            printer.disconnect()
 | 
			
		||||
            break
 | 
			
		||||
        else:
 | 
			
		||||
            break
 | 
			
		||||
        time.sleep(1.)
 | 
			
		||||
        logging.info("Restarting printer")
 | 
			
		||||
        start_args['start_reason'] = res
 | 
			
		||||
 | 
			
		||||
    if bglogger is not None:
 | 
			
		||||
        bglogger.stop()
 | 
			
		||||
 
 | 
			
		||||
@@ -390,7 +390,6 @@ class MCU:
 | 
			
		||||
            printer.reactor, self._serialport, baud)
 | 
			
		||||
        self.is_shutdown = False
 | 
			
		||||
        self._shutdown_msg = ""
 | 
			
		||||
        self._is_fileoutput = False
 | 
			
		||||
        self._timeout_timer = printer.reactor.register_timer(
 | 
			
		||||
            self.timeout_handler)
 | 
			
		||||
        rmethods = {m: m for m in ['arduino', 'command', 'rpi_usb']}
 | 
			
		||||
@@ -442,14 +441,17 @@ class MCU:
 | 
			
		||||
        self._printer.note_shutdown(self._shutdown_msg)
 | 
			
		||||
    # Connection phase
 | 
			
		||||
    def _check_restart(self, reason):
 | 
			
		||||
        if self._printer.get_startup_state() == 'firmware_restart':
 | 
			
		||||
        start_reason = self._printer.get_start_args().get("start_reason")
 | 
			
		||||
        if start_reason == 'firmware_restart':
 | 
			
		||||
            return
 | 
			
		||||
        logging.info("Attempting automated firmware restart: %s" % (reason,))
 | 
			
		||||
        self._printer.request_exit('firmware_restart')
 | 
			
		||||
        self._printer.reactor.pause(self._printer.reactor.monotonic() + 2.000)
 | 
			
		||||
        raise error("Attempt firmware restart failed")
 | 
			
		||||
    def connect(self):
 | 
			
		||||
        if not self._is_fileoutput:
 | 
			
		||||
        if self.is_fileoutput():
 | 
			
		||||
            self._connect_file()
 | 
			
		||||
        else:
 | 
			
		||||
            if (self._restart_method == 'rpi_usb'
 | 
			
		||||
                and not os.path.exists(self._serialport)):
 | 
			
		||||
                # Try toggling usb power
 | 
			
		||||
@@ -470,9 +472,16 @@ class MCU:
 | 
			
		||||
        self.register_msg(self.handle_mcu_stats, 'stats')
 | 
			
		||||
        self._build_config()
 | 
			
		||||
        self._send_config()
 | 
			
		||||
    def connect_file(self, debugoutput, dictionary, pace=False):
 | 
			
		||||
        self._is_fileoutput = True
 | 
			
		||||
        self.serial.connect_file(debugoutput, dictionary)
 | 
			
		||||
    def _connect_file(self, pace=False):
 | 
			
		||||
        # In a debugging mode.  Open debug output file and read data dictionary
 | 
			
		||||
        out_fname = self._printer.get_start_args().get('debugoutput')
 | 
			
		||||
        outfile = open(out_fname, 'wb')
 | 
			
		||||
        dict_fname = self._printer.get_start_args().get('dictionary')
 | 
			
		||||
        dfile = open(dict_fname, 'rb')
 | 
			
		||||
        dict_data = dfile.read()
 | 
			
		||||
        dfile.close()
 | 
			
		||||
        self.serial.connect_file(outfile, dict_data)
 | 
			
		||||
        # Handle pacing
 | 
			
		||||
        if not pace:
 | 
			
		||||
            def dummy_set_print_start_time(eventtime):
 | 
			
		||||
                pass
 | 
			
		||||
@@ -527,7 +536,7 @@ class MCU:
 | 
			
		||||
        self.disconnect()
 | 
			
		||||
        serialhdl.arduino_reset(self._serialport, reactor)
 | 
			
		||||
    def is_fileoutput(self):
 | 
			
		||||
        return self._is_fileoutput
 | 
			
		||||
        return self._printer.get_start_args().get('debugoutput') is not None
 | 
			
		||||
    # Configuration phase
 | 
			
		||||
    def _add_custom(self):
 | 
			
		||||
        for line in self._custom.split('\n'):
 | 
			
		||||
@@ -564,7 +573,7 @@ class MCU:
 | 
			
		||||
        self.add_config_cmd("finalize_config crc=%d" % (self._config_crc,))
 | 
			
		||||
    def _send_config(self):
 | 
			
		||||
        msg = self.create_command("get_config")
 | 
			
		||||
        if self._is_fileoutput:
 | 
			
		||||
        if self.is_fileoutput():
 | 
			
		||||
            config_params = {
 | 
			
		||||
                'is_config': 0, 'move_count': 500, 'crc': self._config_crc}
 | 
			
		||||
        else:
 | 
			
		||||
@@ -577,14 +586,16 @@ class MCU:
 | 
			
		||||
            logging.info("Sending printer configuration...")
 | 
			
		||||
            for c in self._config_cmds:
 | 
			
		||||
                self.send(self.create_command(c))
 | 
			
		||||
            if not self._is_fileoutput:
 | 
			
		||||
            if not self.is_fileoutput():
 | 
			
		||||
                config_params = self.serial.send_with_response(msg, 'config')
 | 
			
		||||
                if not config_params['is_config']:
 | 
			
		||||
                    if self.is_shutdown:
 | 
			
		||||
                        raise error("Firmware error during config: %s" % (
 | 
			
		||||
                            self._shutdown_msg,))
 | 
			
		||||
                    raise error("Unable to configure printer")
 | 
			
		||||
        elif self._printer.get_startup_state() == 'firmware_restart':
 | 
			
		||||
        else:
 | 
			
		||||
            start_reason = self._printer.get_start_args().get("start_reason")
 | 
			
		||||
            if start_reason == 'firmware_restart':
 | 
			
		||||
                raise error("Failed automated reset of micro-controller")
 | 
			
		||||
        if self._config_crc != config_params['crc']:
 | 
			
		||||
            self._check_restart("CRC mismatch")
 | 
			
		||||
 
 | 
			
		||||
@@ -91,7 +91,7 @@ class PrinterHomingStepper(PrinterStepper):
 | 
			
		||||
                logging.info("Endstop for %s is not accurate enough for stepper"
 | 
			
		||||
                             " phase adjustment" % (name,))
 | 
			
		||||
                self.homing_stepper_phases = None
 | 
			
		||||
            if printer.mcu.is_fileoutput():
 | 
			
		||||
            if printer.get_start_args().get('debugoutput') is not None:
 | 
			
		||||
                self.homing_endstop_accuracy = self.homing_stepper_phases
 | 
			
		||||
    def enable_endstop_checking(self, move_time, step_time):
 | 
			
		||||
        mcu_time = self.mcu_endstop.print_to_mcu_time(move_time)
 | 
			
		||||
 
 | 
			
		||||
@@ -359,6 +359,8 @@ class ToolHead:
 | 
			
		||||
        logging.debug('; Max time of %f' % (last_move_time,))
 | 
			
		||||
    def wait_moves(self):
 | 
			
		||||
        self._flush_lookahead()
 | 
			
		||||
        if self.printer.get_start_args().get('debugoutput') is not None:
 | 
			
		||||
            return
 | 
			
		||||
        eventtime = self.reactor.monotonic()
 | 
			
		||||
        while self.print_time:
 | 
			
		||||
            eventtime = self.reactor.pause(eventtime + 0.100)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user