Duet3D Logo Duet3D
    • Tags
    • Documentation
    • Order
    • Register
    • Login
    1. Home
    2. mikeabuilder
    • Profile
    • Following 0
    • Followers 1
    • Topics 66
    • Posts 377
    • Best 100
    • Controversial 1
    • Groups 0

    mikeabuilder

    @mikeabuilder

    Retired computer architect. Science and technology fan. Non-user of social media (it ain't "technology" and it ain't "science" - it's... I don't know what, but not technology or science"). Will almost always ask either "why was it done that way", or "why wasn't it done this way".

    136
    Reputation
    29
    Profile views
    377
    Posts
    1
    Followers
    0
    Following
    Joined Last Online
    Location Seattle, WA

    mikeabuilder Unfollow Follow

    Best posts made by mikeabuilder

    • A rudimentary array macro

      No question or issue, just sharing something.

      A thread in this forum mentioned having macros write their own macros and it occurred to me maybe this could work to make a rudimentary array. It festered in my brain like the last few words in the NY Times Sunday crossword. This morning I got it working. The code is below, but I'll describe how it works and it's shortcomings.

      A new array is initialized when a macro that needs an array calls the code below using an M98. The user supplies an array name. Then the macro below echos commands into a file with the array name. Now this newly-created macro (say my_array.g) can be called from the original macro. It supports adding new elements, changing the value of existing elements and querying the value of existing elements. When called, it puts the appropriate return value into a global variable called "global.array_response". So it only clogs memory with a single additional global variable.

      Writing it was a bit of a mind-bender because of nested echos to files and their associated escaped quote marks, the array macro appending to itself when an element is added or changed, and the need for the array macro to call itself to find it's own length so it can increment the array index when adding an element. Also, in the initialization macro, the echoed strings all needed to be kept under the length limit.

      The shortcoming of this macro is that it will allow the user to replace a value at an index that is outside the length of the array (say, replace loc[10] when the array is only three elements long). This will then add a gap in the array for future normal adds. I might work on that. This same shortcoming would also let someone use this as a data dictionary, using strings as the array index parameter.

      Now I need to find a reason to use an array in a macro...

      ; Array.g is a macro intended to be used by other macros to manage data in an array-like structure. 
      ; You call array.g once to create an array macro.  You call that macro add an element to the array, 
      ; read the value at a specified index, get the length of the array, or replace a value at an existing index. 
      
      ; This macro creates the array in a /temp sub-folder of the sys directory, but you can change the location if you want.
      ; Author: mikeabuilder
      
      ; One day, if RRF adds array support to the core RRF funstionality, this macro will no longer be needed.
      ; That will be a happy day. 
      
      var Array_location = "0:/sys/temp/"
      
      
      
      ; Typical usage
      ;  M98 P"0:/sys/array.g" S"array name"
      ;
      ;Parameter definition and usage
      ;  S"array_name"  Required parameter. This is the name of an array you want to create. If you use a name that was used previously, the old array will be overwritten.
      
      ; PARAMETER CHECK
      if !exists(param.S)
        M291 P"No macro name provided. Cancelling array build" S3 T-1
        M99
      
      var file = var.Array_location^param.S^".g"  ;create full path to the new array
      
      
      ; The following lines are all echoed into the new array file
      echo >{var.file}  "; This file was created by the macro array.g, normally located in the /sys directory."
      echo >>{var.file} "; It is used as method for creating a rudimentary array data capability for other macros."
      echo >>{var.file} "; This macro is called to add elements to the array, read values of an existing element,"
      echo >>{var.file} "; change the values of existing element, or get the number of elements in the array."
      echo >>{var.file} "; The requested data is passed back to the calling macro by putting it into a global "
      echo >>{var.file} "; variable called gloabl.macro_response."
      echo >>{var.file} "; Author: mikeabuilder"
      echo >>{var.file} "; "
      echo >>{var.file} "; TYPICAL USE"
      echo >>{var.file} "; M98 P""0:/sys/temp/"^var.file^""" V""value""  I""index"" L                "
      echo >>{var.file} "; "
      echo >>{var.file} "; PARAMETERS"
      echo >>{var.file} ";  V""value""   When used without the I parameter, the value is appended to that array as a new     "
      echo >>{var.file} ";               element. The value of global.macro_response is set to the array index of the added  "
      echo >>{var.file} ";               value.                                                                              "
      echo >>{var.file} ";  I""number""  When used without the A parameter, the value of element I[number] is returned in    "
      echo >>{var.file} ";             global.macro_response.                                                                "
      echo >>{var.file} ";             When both A and I parameters are used, the existing value of the element I[number] is "
      echo >>{var.file} ";             replaced. If there is no element I[number], a new element I[number] is created. It    "
      echo >>{var.file} ";             might get overwritten.                                                                "
      echo >>{var.file} ";  None       If no parameter is present, the length of the array is returned in                    "
      echo >>{var.file} ";             global.array_response.                                                                "
      echo >>{var.file} "; "
      echo >>{var.file} "; THEORY OF OPERATION"
      echo >>{var.file} "; When array elemenmts are added or changed, they are added to the end of this macro file. Changed  "
      echo >>{var.file} "; element values result is multiple values in this file. The valie closest to the end of the file is"
      echo >>{var.file} "; the current value. This means that a value that is changed a lot will make the file longer and    "
      echo >>{var.file} "; longer. Simple enough, eh? "
      echo >>{var.file} ""
      echo >>{var.file} ""
      echo >>{var.file} ";START OF THE REAL WORK"
      echo >>{var.file} ""
      echo >>{var.file} "; If we are appending or replacing, this is the easy part"
      echo >>{var.file} "; Set up some variables"
      echo >>{var.file} "var index = 0                                                                                       "
      echo >>{var.file} "if !exists(global.array_response)                                                                   "
      echo >>{var.file} "  global array_response = var.index                                                                 "
      echo >>{var.file} "else                                                                                                "
      echo >>{var.file} "  set global.array_response = var.index                                                             "
      
      echo >>{var.file} "var my_len = 0                                                                                      "
      echo >>{var.file} {"var file = """^var.file^""""}
      echo >>{var.file} ""
      echo >>{var.file} "; If we are adding a new element or changing the value of an existing element it happens here.      "
      echo >>{var.file} "if exists(param.V)          ; We are appending or changing                                          "
      echo >>{var.file} "  if exists(param.I)        ; An index is supplied, so we are changing a value                      "
      echo >>{var.file} "    set var.index = param.I  ; The user supplied the index for the element to be replaced           "
      echo >>{var.file} "  else                      ; We are adding a new element so we need to get the next unused index   "
      echo >>{var.file} "    M98 P"""^{var.file}^"""  ; query myself for the length of my array                              "
      echo >>{var.file} "    set var.index = global.array_response  ; The array length is the next index                     "
      echo >>{var.file} "                                                                                                    "
      echo >>{var.file} "  ; we have the index and the value to add, so lets add to our own file                             "
      echo >>{var.file} "  "
      echo >>{var.file} "  echo >>{var.file} ""       ;NEXT ARRAY ELEMENT""                                                  "
      echo >>{var.file} "  echo >>{var.file} ""if exists(param.I)  ; we are returning an existing value""                    "
      echo >>{var.file} "  echo >>{var.file} ""  if param.I = ""^var.index                                                   "
      echo >>{var.file} "  echo >>{var.file} ""  set global.array_response = """"""^param.V^""""""""                         "
      echo >>{var.file} "  echo >>{var.file} ""else""                                                                        "
      echo >>{var.file} "  echo >>{var.file} ""  set var.my_len = max(global.array_response,""^var.index+1^"")""             "
      echo >>{var.file} "  echo >>{var.file} ""  set global.array_response= var.my_len""                                     "
      echo >>{var.file} ";  "
      
      posted in Gcode meta commands
      mikeabuilderundefined
      mikeabuilder
    • RE: Input shaping guidance

      Quick update - I used the sliders on the raw data to isolate on the data after the move stopped and then did the fft again. I have a sharp peak at 22.5Hz. I captured the data again after adding an M593 P"zvd" and in the resulting waveform, that frequency is gone. Super-cool. I'm off to play with a ringing tower.

      posted in Tuning and tweaking
      mikeabuilderundefined
      mikeabuilder
    • RE: How to put a conditional question based action into a macro

      Here's my answer, but it's based on me only knowing one way to "read" a user input - the M291 command. Someone else might have a better method.

      M291 posts a message and the user has two response options, "OK" and "Cancel". According to the M291 wiki page, if the users responds "OK", execution continues, but if they respond "Cancel", it "cancels the operation in progress".

      I use the M291 in the following way:

      global response = "Cancel"   ;set the variable to the default Value.
      
      M291 P"To keep the default, select "Cancel" R"To change the default to the new value, select OK" S3  ; use the box title and the message to describe the two options. 
      
      set global. response = "OK"
      

      I put these lines in their own macro. If the user responds OK, the last line is executed and the global variable becomes the OK value. If they select Cancel, the macro exits without executing the last mine and the "Cancel value is used.

      Someone may know better what "operation in progress" means and maybe this could be written in an if statement in the code.

      A good FW wishlist item would be new M291 parameters to specify the words on the buttons, and have the response stored in the object model so you could read the response directly.

      posted in Gcode meta commands
      mikeabuilderundefined
      mikeabuilder
    • Macro for PA testing with Prusa Slicer

      I thought I'd share this simple macro I wrote for tweaking the PA parameter while printing. I made it because I could not get the prusa slicer code provided in the PA wiki page ( https://duet3d.dozuki.com/Wiki/Pressure_advance) to work for me.

      My macro works by inserting an M98 call in the "Before Layer Change" area in the Custom G-code part of Printer Settings in PrusaSlicer. The complete line of code is:

      M98 P"0:/macros/PA_tester.g" L[layer_num]
      

      The slicer calls the macro I've named "PA_tester.g" and passes a parameter L and the layer number. This happens for every later change.

      The Macro, which I adapted from the PA wiki page looks like this:

      ; This macro changes the pressure advance setting every 25 layers so that the user can see the effect of different PA values 
      
      ; 0.2mm layer, 8 bands 5mm each, total height 40mm
      if param.L = 1 
        M572 D0 S0.0
      elif param.L== 25
        M572 D0 S0.05
      elif param.L== 50
        M572 D0 S0.10
      elif param.L== 75
        M572 D0 S0.15
      elif param.L== 100
        M572 D0 S0.20
      elif param.L== 125
        M572 D0 S0.25
      elif param.L== 150
        M572 D0 S0.30
      elif param.L== 175
        M572 D0 S0.35
      
      m99
      

      The advantage of this over the in-slicer Prusa version on the PA page (beyond that code not working), is that I can change the PA parameters and the layers they change on and reprint my test part without needing to go back to the slicer.

      posted in Gcode meta commands
      mikeabuilderundefined
      mikeabuilder
    • time measurements

      I'm working on some macros where I want to measure time to less than 1 second resolution. I created this command to get me to msec resolution. It may be of use to others.

      mod(mod({+state.time},10000),10000) + state.msUpTime/1000
      

      It takes the time in seconds since the datum, strips off all but the last 4 digits and adds the ms portion of uptime to it. Note that the msec portion is not synched to universal time, but synched to the last board boot. Still very good for measuring and accurate duration up to 9999seconds (2.77 hours)

      Someone may have a cleaner way to do it than doing mod twice, but it gets the job done.

      posted in Gcode meta commands
      mikeabuilderundefined
      mikeabuilder
    • RE: Network time sometimes missing. How to force it to try again.

      Thanks @chrishamm. Reading your response made me realize that I not only mistyped "SBC" but also that I was backwards about it. My system is NOT running in SBC mode, it's stand-alone. So thanks for answering that version of the question.

      I'm restating your "never supported NPT" comment to see if I understand the implications for a machine running in stand-alone mode:

      • The stand-along RRF will not "know" the time until a client connects. This means all log entries will have a timestamp based on the machine's uptime (time since boot).

      • If/When a client connects, if that client is DWC, then DWC will set RRF's date-time.

      • If a client other than DWC connects, and it connects using rr_connect with the time option, then RRF will update with the time from the client.

      This explains a lot of unexplained macro errors I've observed over the past three years. And I can see now that I'll need to rewrite all the macros to not use state.time for measuring duration. I'll convert them all over to using state.upTime rather than state.time.

      I think I'll also look into making an Rpi pico that powers up with my system and that does the rr_conenct function.

      posted in Gcode meta commands
      mikeabuilderundefined
      mikeabuilder
    • RE: Filament-type visible in Object Model?

      It's buried in the move section.

      move.extruders[<#>].filament
      

      You need to give an extruder number. For the extruder on the current tool:

      move.extruders[state.currentTool].filament
      

      If you tool has multiple extruders... I'm not sure

      posted in Firmware wishlist
      mikeabuilderundefined
      mikeabuilder
    • RE: Question about the quality of the Duet software..

      I second @alankilian's suggestion. At a minimum, knowing if there is a local pub where happy users could pay off part of the company tab.

      And regarding testing, maybe there is a process whereby users could volunteer to run some non-destructive tests on our machines to contribute to a larger data set? Maybe even contribute some modules?

      posted in General Discussion
      mikeabuilderundefined
      mikeabuilder
    • RE: Fine editor for working with Duet boards

      One of my "back in my day" sayings for the new kids used to be showing them a 3.5" dual density (2.88MB - size defined to 2 decimal places) floppy disk in a hard case and tell them this was the "premium" small portable storage 30 years ago. Then I'd tell then how many it would take to store the same amount as a modern device. Today, that's a 1TB micro SD card (that us old guys can barely handle, they're so tiny). So, roughly 350,000 old-style disks. They were about 1/8 inch thick, so a stack of 350K would be over 3600 feet tall.

      Oh yeah, and we had to write to those old ones with a piece of charcoal by candle-light. After walking 5 miles to work through snowdrifts.

      And they hadn't even invented espresso.

      Harumpf.

      posted in Third-party software
      mikeabuilderundefined
      mikeabuilder
    • RE: implementing a slicer checker

      Thanks for all the thoughtful responses. I'll work on a feature request and submit through proper channels. I think I'll ask for a named macro that runs after the print header is processed but before additional lines, and that named metadata in that header be available at that time. I can think of a few uses in addition to my use case.

      posted in Gcode meta commands
      mikeabuilderundefined
      mikeabuilder

    Latest posts made by mikeabuilder

    • RE: M291 S4 J2 T0 problem

      @dc42 - thanks for having a look at this. I see three possible issues (maybe trickiness in the way RRF works)

      1. RRF allowing PanelDu or DWC to launch (queue?) a macro start while the one they just launched is being executed ( in my test code, paused by G4 ). This seems to be the thing leading to the stack overflow.

      2. The behavior when an asynchronously launched macro calls for a message window when another macro already has one displayed.

      I also suspect that some of the queuing behavior is desirable for some of the controls (like temperature adjustments) in DWC and PanelDu. No idea how to reconcile the two.

      posted in Gcode meta commands
      mikeabuilderundefined
      mikeabuilder
    • RE: M291 S4 J2 T0 problem

      I think maybe I am asking about starting macros asynchronously. Here's an repro case for the problem I'm experiencing.

      HW - MB6HC
      RRF - 3.6.0-rc.2
      DWC - 3.6.0-rc.2
      PanelDu FW - 3.5.1-v3-7.0

      This macro logs it's starting time, waits a bit (10 seconds), then executes an M291. It also logs the M291 response and its exit time and cause.

      ; before starting this test, be sure a global variable named "counter" has been created with a value of 0
      var my_id = global.counter +1  
      set  global.counter = var.my_id
      var my_log_offset = ""
      while iterations < var.my_id
        set var.my_log_offset = (var.my_log_offset^ "  ")
      
      echo >>"0:/macros/async_log.txt" state.time, var.my_log_offset, var.my_id, "Instance starting" 
      
      ; wait for a bit to allow async start attempts
      G4 S10
      
      M291 S4 T0 J2 K{"continue",} P"select any option"
      echo >>"0:/macros/async_log.txt" state.time, var.my_log_offset, var.my_id, ("Result: "^result^"  Input: "^input)
      
      if result = -1 ; user cancelled
        echo >>"0:/macros/async_log.txt" state.time, var.my_log_offset, var.my_id, "exiting because user cancelled"
        M99
      
      echo >>"0:/macros/async_log.txt" state.time, var.my_log_offset, var.my_id, "exiting at EOF"
      

      I did two experiments with this macro.
      First, I used PanelDu to start the macro three times, touching the button at intervals of about one second. I saw the user interface message appear three times and each time I pressed the "continue" button (input 0) This resulted in the following test log entries. The logs show that instances 2 and 3 were running before instance 1 completed. I think this is an example of asynchronous macros from the same input channel (assuming PanelDu is one channel). Based on the 10 second interval between the logged start times, I think the PanelDu queued the macros to RRF and each subsequent macro started after the G4 timer timed out. So now I see a potential conflict between wanting PanelDu to be able to queue commands for things like modifying temperatures, and not wanting it to be able to queue commands so macros can't be started over and over.

      The logs also imply that the M291 messages overwrote each other and the first one I responded to was from instance 3, not instance 1.

      2025-05-16T09:22:59    1 Instance starting
      2025-05-16T09:23:09      2 Instance starting
      2025-05-16T09:23:19        3 Instance starting
      2025-05-16T09:23:42        3 Result: 0  Input: 0
      2025-05-16T09:23:42        3 exiting at EOF
      2025-05-16T09:23:42      2 Result: 0  Input: 0
      2025-05-16T09:23:42      2 exiting at EOF
      2025-05-16T09:23:42    1 Result: 0  Input: 0
      2025-05-16T09:23:42    1 exiting at EOF
      

      My second experiment was the same as the first, but instead of touching the PanelDu button to start the macro 3 times, I touched it 10 times. In this case, I saw one M291 window pop up and after the M291 window closed nothing happened for a while (maybe 20 seconds), then I got an overflow message on PanelDu and after closing that message, PanelDu continued to show "Busy" in the upper right corner. After a couple minutes, I went back indoors to where my DWC connection is and saw an M291 message there. I responded to it and several others. Here's the log of that sequence - I added a couple of lines to show where I switched to DWC. After this, PanelDu shows "Idle". The system log from this time is below my test logs where you can see the stack overflow messages.

      2025-05-16T09:23:51          4 Instance starting
      2025-05-16T09:24:01            5 Instance starting
      2025-05-16T09:24:11              6 Instance starting
      2025-05-16T09:24:21                7 Instance starting
      2025-05-16T09:24:31                  8 Instance starting
      
      
      2025-05-16T09:27:25                  8 Result: 0  Input: 0
      2025-05-16T09:27:25                  8 exiting at EOF
      2025-05-16T09:27:25                7 Result: 0  Input: 0
      2025-05-16T09:27:25                7 exiting at EOF
      2025-05-16T09:27:25              6 Result: 0  Input: 0
      2025-05-16T09:27:25              6 exiting at EOF
      2025-05-16T09:27:25            5 Result: 0  Input: 0
      2025-05-16T09:27:25            5 exiting at EOF
      2025-05-16T09:27:25          4 Result: 0  Input: 0
      2025-05-16T09:27:25          4 exiting at EOF
      

      System log entries:

      2025-05-16 09:23:09 [info] M291: - [no title] - select any option
      2025-05-16 09:23:19 [info] M291: - [no title] - select any option
      2025-05-16 09:23:29 [info] M291: - [no title] - select any option
      2025-05-16 09:23:29 [info] M292: cancelled=false shouldAbort=false
      2025-05-16 09:23:31 [info] M292: cancelled=false shouldAbort=false
      2025-05-16 09:23:42 [info] M292: cancelled=false shouldAbort=false
      2025-05-16 09:24:01 [info] M291: - [no title] - select any option
      2025-05-16 09:24:11 [info] M291: - [no title] - select any option
      2025-05-16 09:24:21 [info] M291: - [no title] - select any option
      2025-05-16 09:24:31 [info] M291: - [no title] - select any option
      2025-05-16 09:24:41 [info] M291: - [no title] - select any option
      2025-05-16 09:24:41 [warn] Error: Push(): stack overflow on Aux
      2025-05-16 09:24:41 [warn] Error: Push(): stack overflow on Aux
      2025-05-16 09:24:41 [warn] Error: Push(): stack overflow on Aux
      2025-05-16 09:24:41 [warn] Error: Push(): stack overflow on Aux
      2025-05-16 09:24:41 [warn] Error: Push(): stack overflow on Aux
      2025-05-16 09:27:21 [info] M292: cancelled=false shouldAbort=false
      2025-05-16 09:27:22 [info] M292: cancelled=false shouldAbort=false
      2025-05-16 09:27:23 [info] M292: cancelled=false shouldAbort=false
      2025-05-16 09:27:24 [info] M292: cancelled=false shouldAbort=false
      2025-05-16 09:27:25 [info] M292: cancelled=false shouldAbort=false
      

      I subsequently reproduced the same results using DWC and starting the macro with mouse clicks, except that DWC did not get stuck in a "Busy" state.

      I now have a theory about the root cause of issues I've had with my system that relies on PanelDu. I have had people (including me) click on a macro button on PanelDu while a print is running and then having a subsequent tool dock macro fail (resulting in a crash). My theory is that the macro button press filled the "Push()" and when one of the tool docking macros tried to run there was an overflow and it got skipped.

      I don't think those behaviors should be OK. Am I missing something?

      The only thing I can think of as a way around this is for me to maintain some kind of global lock token that gets set in start.g (or whenever a critical macro is going to start), then have all user initiated macros not start if the global lock is set. Stop.g would need to release the global lock. I can imagine this would get complicated with multiple locks for some macros that might be called either by a print file or on their own - like tool change macros.

      Sorry for the long post, but this is bothersome.

      posted in Gcode meta commands
      mikeabuilderundefined
      mikeabuilder
    • RE: M291 S4 J2 T0 problem

      @dc42 - thank for clarifying that. Maybe the doc page should be explicit about this on S4-7.

      I still have a concern about other macros pushing a blocking message off the user interface and leaving the first macro in a hung state. Can you clarify whether it's possible for a second macro to start execution while the first is waiting for a message response?

      Maybe this is asking if macros can started asynchronously. I've recently been having issues where it appears that macros are started multiple times from PanelDu, causing blocking messages to replace each other, and ultimately leading to "too many files open" errors. Maybe I should develop a simple repro case.

      posted in Gcode meta commands
      mikeabuilderundefined
      mikeabuilder
    • M291 S4 J2 T0 problem

      I think there's a logical flaw in M291 that can lead to files being left open. Or maybe I'm not reading the docs correctly.

      Here's my analysis

      S 4 (or greater) - these are non-blocking. My understanding of this means that other code can be run while the message box is being displayed.

      J 1 or 2 - Enables the T parameter

      T0 - No timeout.

      With any of these combinations, macro file (foo.g) can post a message and wait for user input. Then, another macro (bar.g) can start (because foo's message is non-blocking). If bar (the second macro) posts a message, then foo's message box (without timeout) will no longer be displayed. The macro foo.g now seems unrecoverable and is seems lost forever.

      Or does bar's message box request cause bar's input request to be cancelled (per the J parameter)?

      I suggest that any when the T0 parameter is used with those S and J parameters, the message should become blocking.

      posted in Gcode meta commands
      mikeabuilderundefined
      mikeabuilder
    • RE: PanelDu debouncing ideas

      Final (I hope) follow-up on this issue - Further testing today showed that my implementation of a timer to try to prevent de-bouncing was not adequate - I still had a few multiple-starts of macros. I implemented a new method for de-bouncing that seems to be working better. I created a global macro to use as a token. I have one per macro that I want to de-bounce. When the macro starts, the first thing it does is try to "grab the token" by checking the state of the global variable (false means the token is available, true means it is already taken". If the state is false, the macro grabs the token by setting it to true and proceeds. Any other instances of this macro that start will find the value of the token to be true and that triggers them to exit. At every exit point of the macro, it needs to "release the token" by resetting it to false. No timers.

      posted in Gcode meta commands
      mikeabuilderundefined
      mikeabuilder
    • RE: Can I start a print job from a macro

      @Phaedrux - I have now. Thanks!

      posted in Gcode meta commands
      mikeabuilderundefined
      mikeabuilder
    • Can I start a print job from a macro

      RRF 3.6.0-rc.2
      MB6HC

      I've created a print job designed to help me tweak my z offset. It's a single layer rectangle with some added meta commands to let me position it anywhere on the bed. It works great. It's called "first layer.gcode"

      I've also written a macro utility to assist in changing filaments. it also works great.

      Now I want to let the user start tart the print job at the end of the filament changing macro, but I'm not sure how to do this. I tried M98 P"0:/gcodes/first layer.gcode". This does launch the job, but it does not run start.g at the beginning or enable the pause and cancel buttons in DWC. Is there a proper way to do this? I know I can add a conditional call of start.g and stop.g in first_layer.gcode, but I want to have access to the pause and cancel print buttons.

      posted in Gcode meta commands
      mikeabuilderundefined
      mikeabuilder
    • RE: PanelDu debouncing ideas

      @dc42 - Following up on this issue. I've implemented trace logging through all my macros and yesterday I had another incidence of the same issue that started me looking at debouncing on PanelDu. The symptom is that I get this Error in my event log:
      2025-04-29 10:25:15 [warn] Error: Push(): stack overflow on Aux

      I still suspect multiple starts on one attempted PanelDu touch (fingernail only), but there are a couple of odd things I'm hoping to understand.

      The macro called from the PanelDu touch is 0:/macros/Load or Unload Filament.g and I post a message via M118 at the beginning of the macro. Then the macro asks the user to select whether to Load, Unload, or Cancel, using
      M291 S4 T0 P"FILAMENT - Load, Unload, or Cancel" K{"Load", "Unload", "Cancel"}

      Here is the event log just before the error. You can see that the macro is starting multiple times and the M291 is being logged each time. After these n=messages, the M292 acks are logged. If the user replies to the M291 with "unload", then another macro ( 0:/macros/load_unload_filaments/unload_current_filament.g) is called. Thar macro has a start message then posts a message with the current tool and filament. Then my stack overflow happens.

      2025-04-29 10:24:47 [info] starting 0:/macros/Load or Unload Flament.g
      2025-04-29 10:24:47 [info] M291: - [no title] - FILAMENT  -  Load, Unload, or Cancel
      2025-04-29 10:24:49 [info] starting 0:/macros/Load or Unload Flament.g
      2025-04-29 10:24:49 [info] M291: - [no title] - FILAMENT  -  Load, Unload, or Cancel
      2025-04-29 10:24:49 [info] starting 0:/macros/Load or Unload Flament.g
      2025-04-29 10:24:49 [info] M291: - [no title] - FILAMENT  -  Load, Unload, or Cancel
      2025-04-29 10:24:50 [info] starting 0:/macros/Load or Unload Flament.g
      2025-04-29 10:24:50 [info] M291: - [no title] - FILAMENT  -  Load, Unload, or Cancel
      2025-04-29 10:24:51 [info] starting 0:/macros/Load or Unload Flament.g
      2025-04-29 10:24:51 [info] M291: - [no title] - FILAMENT  -  Load, Unload, or Cancel
      2025-04-29 10:24:53 [info] M292: cancelled=false shouldAbort=true
      2025-04-29 10:25:00 [info] M292: cancelled=false shouldAbort=true
      2025-04-29 10:25:03 [info] M292: cancelled=false shouldAbort=true
      2025-04-29 10:25:10 [info] M292: cancelled=false shouldAbort=true
      2025-04-29 10:25:15 [info] M292: cancelled=false shouldAbort=true
      2025-04-29 10:25:15 [info] starting 0:/macros/load_unload_filaments/unload_current_filament.g
      2025-04-29 10:25:15 [info] M291: - [no title] - Current Tool Number: 1      Current filament: PLA
      2025-04-29 10:25:15 [warn] Error: Push(): stack overflow on Aux
      2025-04-29 10:25:20 [info] M292: cancelled=false shouldAbort=true
      
      

      One question I had is "which of the M291's in the 5 macro starts was responded to by the user?" The T0 parameter on the M291 means it will not time out, but I do not think this makes it blocking. So each of the first 4 M291 messages is lost. Are those macro starts left at a paused execution state? Are they taking up "open file" slots and pushing me towards my stack overflow?
      Is there a an easy (meaning via object model or gcode) for me to see how many files are open?

      My trace data (below) confirms that the last of the 5 repeated opens is the one that was responded to. In my tracing, at the start of every macro, a global variable is incremented and that number assigned as the trace-number for that instance of that file being run. I also log the start time of the macro and these correspond to the times in even log. And on line 6, you can see that the trace number 225 (the last instance of "load or unload Filament") is logging that it's calling the next macro.

      221 , 2025-04-29T10:24:47 , 2522 , 0:/macros/load_unload_filaments/Load or Unload Filament.g , Starting Macro
      222 , 2025-04-29T10:24:49 , 2524 , 0:/macros/load_unload_filaments/Load or Unload Filament.g , Starting Macro
      223 , 2025-04-29T10:24:49 , 2524 , 0:/macros/load_unload_filaments/Load or Unload Filament.g , Starting Macro
      224 , 2025-04-29T10:24:50 , 2524 , 0:/macros/load_unload_filaments/Load or Unload Filament.g , Starting Macro
      225 , 2025-04-29T10:24:51 , 2525 , 0:/macros/load_unload_filaments/Load or Unload Filament.g , Starting Macro
      225 , 2025-04-29T10:25:15 , 2550 , 0:/macros/load_unload_filaments/Load or Unload Filament.g , About to call: 0:/macros/load_unload_filaments/unload_current_filament.g
          226 , 2025-04-29T10:25:15 , 2550 , 0:/macros/macros/load_unload_filaments/unload_current_filament.g , Starting Macro
      

      So, as we used to say, "a lotta crap to read, what do we do?" I'm writing a debouncer into the start of the macro to not let it start too quickly after the last time it started. I'm picking 5 seconds.

      Does all my analysis and plan seem reasonable?

      I don't think these are needed, but here's my M122 output (m122 output.txt ), my full trace (trace_12.txt ) and the load and unload filament macro (pre start time debouncer) (Load or Unload Filament.g )

      posted in Gcode meta commands
      mikeabuilderundefined
      mikeabuilder
    • RE: Odd behavior of M292 or maybe M291

      @chrishamm - thanks for the response and the github pointer. I took a look at the description and see it's just the same as what I found. Some of the description is beyond my knowledge, but it's good to know I'm only 2 years behind the leading engineers in finding things. 🙂

      posted in Gcode meta commands
      mikeabuilderundefined
      mikeabuilder
    • RE: Odd behavior of M292 or maybe M291

      My Bad. I should have included my HW info.

      1. Display device is DWC. I also have a PanelDue 7i on this machine, and I just tested launching the macro from it. When I do, only my echo messages appear on the PanelDue console, none of the M292 messages.

      2. Duet board is MB6HC and is stand alone.

      3. RRF and DWC are both 3.6.0-rc.2

      posted in Gcode meta commands
      mikeabuilderundefined
      mikeabuilder