-
Notifications
You must be signed in to change notification settings - Fork 30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for gcode_macro #30
base: master
Are you sure you want to change the base?
Conversation
Hi @hesiod Are you still working on this? Best regards, |
@dalegaard Actually I was waiting for some initial feedback (on whether you're interested in this feature in principle) before I worked on it any further 🙂 FYI, there is one known issue with the PR currently: I misunderstood how Klipper's macro variables ( |
Hi @hesiod That's my bad, I hadn't considered you were looking for feedback at this stage. Sorry about that. I'm very interested in supporting this feature if it can be demonstrated to work well in real world use cases. Supporting every possible macro under the sun isn't an objective, but e.g. the FastGyroidInfill of #33 seems like it could be supported pretty well. I haven't done any code checks at this point, but I'll try to take a look over things tonight. Note that I changed a good chunk of the configuration system, so that part will likely need to be changed significantly from when you submitted this PR. Best regards, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a few preliminary comments :-)
@@ -314,7 +315,7 @@ mod parser { | |||
} | |||
|
|||
fn traditional_gcode(s: &str) -> IResult<&str, (GCodeOperation, Option<&str>)> { | |||
let (s, letter) = satisfy(|c| c.is_alphabetic())(s)?; | |||
let (s, letter) = satisfy(|c| matches!(c.to_ascii_lowercase(), 'g' | 'm'))(s)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is probably not good, as e.g. tool selections fall under "traditional gcode" as well. Why was this change needed?
@@ -279,7 +280,7 @@ mod parser { | |||
fn parse(s: &str) -> IResult<&str, GCodeCommand> { | |||
let (s, _) = space0(s)?; | |||
|
|||
let (s, _line_no) = opt(line_number)(s)?; | |||
// let (s, _line_no) = opt(line_number)(s)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was there an issue with this?
@@ -121,7 +122,7 @@ impl Display for GCodeTraditionalParams { | |||
} | |||
} | |||
|
|||
#[derive(Debug, PartialEq, PartialOrd, Clone)] | |||
#[derive(Debug, PartialEq, Eq, PartialOrd, Clone, Serialize)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer to add a to_map
or similar function that the caller can then serialize after. Doesn't feel right to need this to be Serialize
within gcode.rs
. A better option still is likely to add a wrapper in macros.rs
. This wrapper can implement minijinja::value::Object
and call directly to getters without going through a serialization step.
impl minijinja::value::Object for PrinterObj { | ||
fn get_attr(&self, name: &str) -> Option<minijinja::value::Value> { | ||
match name { | ||
"toolhead" => Some(minijinja::value::Value::from_serializable( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of serializing the toolhead, I think it's probably better to have a wrapper that implements Object
. I fear serialization could have performance implications.
|
||
#[derive(Debug, Clone, Default, Serialize, Deserialize)] | ||
#[serde(default)] | ||
pub struct GCodeMacro<S = serde_json::Value> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you foresee a case that could need this S
parameter to be configurable? I would probably remove it and statically use serde_json::Value
.
"restore_gcode_state" => { | ||
// todo!() | ||
} | ||
other => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In Klipper macros can override any gcode line. Really we should perform macro rendering at the top of process_cmd
, potentially even creating a process_non_macro
that process_cmd
can call after performing macro expansion. Some care needs to be taken as we need to track the correct number of commands that an input line expands in to, even if that happens in nested macros. This might take a bigger rework of the process_cmd
input system entirely.
Add (incomplete) support for G-Code macros.
Some architecture notes:
{ expr }
instead of the normal double braces{{ expr }}
), necessitating an additional regex replace step.PrinterObj
utilizing minijinja's dynamic object support. I previously simply serialized the printer object as local context for template evaluation, but since the configuration can be a little large this made macro evaluation relatively slow. Still perfectly adequate in terms of runtime, but why not improve performance a little. So I decided to expose the printer attributes usingPrinterObj
.gcode_macro foobar
.TODOs (should definitely be fixed):
lib_klipper
shouldn't depend onserde_json
Known limitations:
replace_existing
is not supportedtoolhead.position
,toolhead.axis_maximum
andtoolhead.homed_axes
- the latter is always set to "xyz")float
,int
,min
, andmax
are implemented atmabs
filter in minijinja does not work for unsigned integers which are automatically used in some cases, throwing unnecessary errors - this is an upstream bug (?), but perhaps it can be fixed locally