Skip to content

Commit

Permalink
add danger options v1 (#67)
Browse files Browse the repository at this point in the history
* add debug options v1

* rename to danger options

* fix tests

* docs
  • Loading branch information
bwnance authored Oct 12, 2023
1 parent 6e7730a commit 2a37eb5
Show file tree
Hide file tree
Showing 11 changed files with 197 additions and 20 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ Features merged into the master branch:

- [probe: z_calibration](https://github.com/DangerKlippers/danger-klipper/pull/31) ([klipper#4614](https://github.com/Klipper3d/klipper/pull/4614) / [protoloft/z_calibration](https://github.com/protoloft/klipper_z_calibration))

- [core: danger_options](https://github.com/DangerKlippers/danger-klipper/pull/67)

"Dangerous Klipper for dangerous users"

Klipper is a 3d-Printer firmware. It combines the power of a general
Expand Down
25 changes: 25 additions & 0 deletions docs/Config_Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,31 @@ pins such as "extra_mcu:ar9" may then be used elsewhere in the config
[mcu my_extra_mcu]
# See the "mcu" section for configuration parameters.
```
## ⚠️ Danger Options
A collection of DangerKlipper-specific system options
```
[danger_options]
# If an unused config option or section should cause an error
# if False, will warn but allow klipper to still run
error_on_unused_config_options: True
# If statistics should be logged
# (helpful for keeping the log clean during development)
log_statistics: True
# If the config file should be logged at startup
log_config_file_at_startup: True
# If the bed mesh should be logged on startup
# (helpful for keeping the log clean during development)
log_bed_mesh_at_startup: True
# If we should log detailed crash info when an exception occurs
# Most of it is overly-verbose and fluff and we still get a stack trace
# for normal exceptions, so setting to False can help save time while developing
log_shutdown_info: True
```

## Common kinematic settings

Expand Down
39 changes: 31 additions & 8 deletions klippy/configfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,8 @@ def __init__(self, printer):
self.status_save_pending = {}
self.status_settings = {}
self.status_warnings = []
self.unused_sections = []
self.unused_options = []
self.save_config_pending = False
gcode = self.printer.lookup_object("gcode")
gcode.register_command(
Expand Down Expand Up @@ -426,7 +428,7 @@ def read_main_config(self):
cfg = self._build_config_wrapper(regular_data + autosave_data, filename)
return cfg

def check_unused_options(self, config):
def check_unused_options(self, config, error_on_unused):
fileconfig = config.fileconfig
objects = dict(self.printer.lookup_objects())
# Determine all the fields that have been accessed
Expand All @@ -439,16 +441,23 @@ def check_unused_options(self, config):
for section_name in fileconfig.sections():
section = section_name.lower()
if section not in valid_sections and section not in objects:
raise error(
"Section '%s' is not a valid config section" % (section,)
)
if error_on_unused:
raise error(
"Section '%s' is not a valid config section"
% (section,)
)
else:
self.unused_sections.append(section)
for option in fileconfig.options(section_name):
option = option.lower()
if (section, option) not in access_tracking:
raise error(
"Option '%s' is not valid in section '%s'"
% (option, section)
)
if error_on_unused:
raise error(
"Option '%s' is not valid in section '%s'"
% (option, section)
)
else:
self.unused_options.append((section, option))
# Setup get_status()
self._build_status(config)

Expand Down Expand Up @@ -483,6 +492,20 @@ def _build_status(self, config):
res["section"] = section
res["option"] = option
self.status_warnings.append(res)
for section, option in self.unused_options:
res = {"type": "unused_option"}
res["message"] = "Option '%s' in section '%s' is invalid" % (
option,
section,
)
res["section"] = section
res["option"] = option
self.status_warnings.append(res)
for section in self.unused_sections:
res = {"type": "unused_section"}
res["message"] = "Section '%s' is invalid" % (section,)
res["section"] = section
self.status_warnings.append(res)

def get_status(self, eventtime):
return {
Expand Down
4 changes: 3 additions & 1 deletion klippy/extras/bed_mesh.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,9 @@ def __init__(self, config):

def handle_connect(self):
self.toolhead = self.printer.lookup_object("toolhead")
self.bmc.print_generated_points(logging.info)
self.danger_options = self.printer.lookup_object("danger_options")
if self.danger_options.log_bed_mesh_at_startup:
self.bmc.print_generated_points(logging.info)

def set_mesh(self, mesh):
if mesh is not None and self.fade_end != self.FADE_DISABLE:
Expand Down
17 changes: 17 additions & 0 deletions klippy/extras/danger_options.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
class DangerOptions:
def __init__(self, config):
self.log_statistics = config.getboolean("log_statistics", True)
self.log_config_file_at_startup = config.getboolean(
"log_config_file_at_startup", True
)
self.log_bed_mesh_at_startup = config.getboolean(
"log_bed_mesh_at_startup", True
)
self.log_shutdown_info = config.getboolean("log_shutdown_info", True)
self.error_on_unused_config_options = config.getboolean(
"error_on_unused_config_options", True
)


def load_config(config):
return DangerOptions(config)
3 changes: 2 additions & 1 deletion klippy/extras/statistics.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ def get_status(self, eventtime):
class PrinterStats:
def __init__(self, config):
self.printer = config.get_printer()
self.danger_options = self.printer.lookup_object("danger_options")
reactor = self.printer.get_reactor()
self.stats_timer = reactor.register_timer(self.generate_stats)
self.stats_cb = []
Expand All @@ -78,7 +79,7 @@ def handle_ready(self):

def generate_stats(self, eventtime):
stats = [cb(eventtime) for cb in self.stats_cb]
if max([s[0] for s in stats]):
if max([s[0] for s in stats]) and self.danger_options.log_statistics:
logging.info(
"Stats %.1f: %s", eventtime, " ".join([s[1] for s in stats])
)
Expand Down
10 changes: 8 additions & 2 deletions klippy/klippy.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,11 @@ def load_object(self, config, section, default=configfile.sentinel):
def _read_config(self):
self.objects["configfile"] = pconfig = configfile.PrinterConfig(self)
config = pconfig.read_main_config()
if self.bglogger is not None:
danger_options = self.load_object(config, "danger_options")
if (
self.bglogger is not None
and danger_options.log_config_file_at_startup
):
pconfig.log_config(config)
# Create printer components
for m in [pins, mcu]:
Expand All @@ -164,7 +168,8 @@ def _read_config(self):
for m in [toolhead]:
m.add_printer_objects(config)
# Validate that there are no undefined parameters in the config file
pconfig.check_unused_options(config)
error_on_unused = danger_options.error_on_unused_config_options
pconfig.check_unused_options(config, error_on_unused)

def _build_protocol_error_message(self, e):
host_version = self.start_args["software_version"]
Expand Down Expand Up @@ -428,6 +433,7 @@ def main():
bglogger = queuelogger.setup_bg_logging(options.logfile, debuglevel)
else:
logging.getLogger().setLevel(debuglevel)
logging.info("=======================")
logging.info("Starting Klippy...")
git_info = util.get_git_version()
git_vers = git_info["version"]
Expand Down
19 changes: 11 additions & 8 deletions klippy/mcu.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class error(Exception):
# Command transmit helper classes
######################################################################


# Class to retry sending of a query command until a given response is received
class RetryAsyncCommand:
TIMEOUT_TIME = 5.0
Expand Down Expand Up @@ -744,6 +745,7 @@ class MCU:

def __init__(self, config, clocksync):
self._printer = printer = config.get_printer()
self.danger_options = printer.lookup_object("danger_options")
self._clocksync = clocksync
self._reactor = printer.get_reactor()
self._name = config.get_name()
Expand Down Expand Up @@ -833,14 +835,15 @@ def _handle_shutdown(self, params):
if clock is not None:
self._shutdown_clock = self.clock32_to_clock64(clock)
self._shutdown_msg = msg = params["static_string_id"]
logging.info(
"MCU '%s' %s: %s\n%s\n%s",
self._name,
params["#name"],
self._shutdown_msg,
self._clocksync.dump_debug(),
self._serial.dump_debug(),
)
if self.danger_options.log_shutdown_info:
logging.info(
"MCU '%s' %s: %s\n%s\n%s",
self._name,
params["#name"],
self._shutdown_msg,
self._clocksync.dump_debug(),
self._serial.dump_debug(),
)
prefix = "MCU '%s' shutdown: " % (self._name,)
if params["#name"] == "is_shutdown":
prefix = "Previous MCU '%s' shutdown: " % (self._name,)
Expand Down
2 changes: 2 additions & 0 deletions klippy/toolhead.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
# mm/second), _v2 is velocity squared (mm^2/s^2), _t is time (in
# seconds), _r is ratio (scalar between 0.0 and 1.0)


# Class to track each move request
class Move:
def __init__(self, toolhead, start_pos, end_pos, speed):
Expand Down Expand Up @@ -128,6 +129,7 @@ def set_junction(self, start_v2, cruise_v2, end_v2):

LOOKAHEAD_FLUSH_TIME = 0.250


# Class to track a list of pending move requests and to facilitate
# "look-ahead" across moves to reduce acceleration between moves.
class MoveQueue:
Expand Down
84 changes: 84 additions & 0 deletions test/klippy/danger_options.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@

[poopybutt]
[danger_options]
log_statistics: False
log_config_file_at_startup: False
error_on_unused_config_options: False
log_bed_mesh_at_startup: False
log_shutdown_info: False

[stepper_x]
step_pin: PF0
dir_pin: PF1
enable_pin: !PD7
microsteps: 16
rotation_distance: 40
endstop_pin: ^PE5
position_endstop: 0
position_max: 200
homing_speed: 50

[stepper_y]
step_pin: PF6
dir_pin: !PF7
enable_pin: !PF2
microsteps: 16
rotation_distance: 40
endstop_pin: ^PJ1
position_endstop: 0
position_max: 200
homing_speed: 50

[stepper_z]
step_pin: PL3
dir_pin: PL1
enable_pin: !PK0
microsteps: 16
rotation_distance: 8
endstop_pin: probe:z_virtual_endstop
position_max: 200

[extruder]
step_pin: PA4
dir_pin: PA6
enable_pin: !PA2
microsteps: 16
rotation_distance: 33.5
nozzle_diameter: 0.400
filament_diameter: 1.750
heater_pin: PB4
sensor_type: EPCOS 100K B57560G104F
sensor_pin: PK5
control: pid
pid_Kp: 22.2
pid_Ki: 1.08
pid_Kd: 114
min_temp: 0
max_temp: 250

[heater_bed]
heater_pin: PH5
sensor_type: EPCOS 100K B57560G104F
sensor_pin: PK6
control: watermark
min_temp: 0
max_temp: 130

[probe]
pin: PH6
z_offset: 1.15
drop_first_result: true

[bed_mesh]
mesh_min: 10,10
mesh_max: 180,180

[mcu]
serial: /dev/ttyACM0

[printer]
kinematics: cartesian
max_velocity: 300
max_accel: 3000
max_z_velocity: 5
max_z_accel: 100
12 changes: 12 additions & 0 deletions test/klippy/danger_options.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
CONFIG danger_options.cfg
DICTIONARY atmega2560.dict

# Start by homing the printer.
G28

G1 F6000

# Z / X / Y moves
G1 Z1
G1 X1
G1 Y1

0 comments on commit 2a37eb5

Please sign in to comment.