Skip to content
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

User MCode Template Questions #50

Closed
5ocworkshop opened this issue Jul 29, 2021 · 7 comments
Closed

User MCode Template Questions #50

5ocworkshop opened this issue Jul 29, 2021 · 7 comments

Comments

@5ocworkshop
Copy link

The templates you recently added are great, but I haven't been able to get the user mcode example one to work. I was wondering if you could take a look and see if there is something obvious that is wrong. I copied and edited your code. It compiles fine within my tree.

I am calling the mcode from the MDI in IOSender with: M356 Q1 and I receive ok but nothing visible happens.

Is this the correct way to call it? I'm new to user mcodes.

I have temporarily added an entry in gcode.h that looks like this:
RGB_Inspection_Light = 356, //!< 356 - M356 // ** Collides with Plasma ** On = 1, Off = 2, RGB white LED inspection light in RGB plugin

I am not currently including the plasma module and I don't see the plasma codes defined in this file, but I did notice that $356 is referred to on the github summary page. Is this possibly the issue?

Here is the code section:

// check - check if M-code is handled here.
// parameters: mcode - M-code to check for (some are predefined in user_mcode_t in grbl/gcode.h), use a cast if not.
// returns:    mcode if handled, UserMCode_Ignore otherwise (UserMCode_Ignore is defined in grbl/gcode.h).
static user_mcode_t check (user_mcode_t mcode)
{
    return mcode == RGB_Inspection_Light 
                     ? mcode                                                            // Handled by us.
                     : (user_mcode.check ? user_mcode.check(mcode) : UserMCode_Ignore); // If another handler present then call it or return ignore.
}

// validate - validate parameters
// parameters: gc_block - pointer to parser_block_t struct (defined in grbl/gcode.h).
//             gc_block->words - holds a bitfield of parameter words available.
//             If float values are NAN (Not A Number) this means they are not available.
//             If integer values has all bits set to 1 this means they are not available.
// returns:    status_code_t enum (defined in grbl/gcode.h): Status_OK if validated ok, appropriate status from enum if not.

static status_code_t validate (parser_block_t *gc_block, parameter_words_t *deprecated)
{
    status_code_t state = Status_GcodeValueWordMissing;

    switch(gc_block->user_mcode) {

        case RGB_Inspection_Light:
            if(gc_block->words.p && !isnan(gc_block->values.p))             // Check if P parameter value is supplied.
                state = Status_BadNumberFormat;                             // Return error if so.

            if(gc_block->words.q && isnan(gc_block->values.q))              // Check if Q parameter value is supplied.
                state = Status_BadNumberFormat;                             // Return error if not.

            if(state != Status_BadNumberFormat && gc_block->words.q) {      // Are required parameters provided?
                if(gc_block->values.q > 0.0f && gc_block->values.q <= 5.0f) // Yes, is Q parameter value in range (1-5)?
                    state = Status_OK;                                      // Yes - return ok status.
                else
                    state = Status_GcodeValueOutOfRange;                    // No - return error status.
                if(gc_block->words.q)                                       // If P parameter is present set
                    gc_block->values.p = 1.0f;                              // value to 1 for execution.
                gc_block->words.p = gc_block->words.q = Off;                // Claim parameters.
                gc_block->user_mcode_sync = true;                           // Optional: execute command synchronized
            }
            break;

        default:
            state = Status_Unhandled;
            break;
    }

    // If not handled by us and another handler present then call it.
    return state == Status_Unhandled && user_mcode.validate ? user_mcode.validate(gc_block, deprecated) : state;
}

// execute - execute M-code
// parameters: state - sys.state (bitmap, defined in system.h)
//             gc_block - pointer to parser_block_t struct (defined in grbl/gcode.h).
// returns:    -
static void execute (sys_state_t state, parser_block_t *gc_block) {

    bool handled = true;

    switch(gc_block->user_mcode) {

        case RGB_Inspection_Light:
            // do something: Q parameter value can be found in gc_block->values.q.
            //               P parameter has its value in gc_block->values.p set to 1 if present, NAN if not.
            if (gc_block->values.q == 1) {
                rgb_set_state(RGB_WHITE);
            }
            else {
                if (gc_block->values.q == 2)
                   rgb_set_state(RGB_OFF);
            }
            break;

        default:
            handled = false;
            break;
    }


    if(!handled && user_mcode.execute)          // If not handled by us and another handler present
        user_mcode.execute(state, gc_block);    // then call it.
}

And I have the relevant sections in my init function:

`void my_plugin_init() // Init function called from drivers_init()
{
    if(hal.port.num_digital_out >= 3) {

        hal.port.num_digital_out -= 3;  // Remove the our outputs from the list of available outputs
        base_port = hal.port.num_digital_out;

        if(hal.port.set_pin_description) {  // Viewable from $PINS command in MDI
            uint32_t idx = 0;
            do {
                hal.port.set_pin_description(true, true, base_port + idx, rgb[idx]);
                if (idx == 0) { red_port = idx; } else
                if (idx == 1) { blue_port = idx; } else
                if (idx == 2) { green_port = idx; }
                idx++;                
            } while(idx <= 2);
        }
        startMS = hal.get_elapsed_ticks();

        // Save away current HAL pointers so that we can use them to keep
        // any chain of M-code handlers intact.
        memcpy(&user_mcode, &hal.user_mcode, sizeof(user_mcode_ptrs_t));

        // Redirect HAL pointers to our code.
        hal.user_mcode.check = check;
        hal.user_mcode.validate = validate;
        hal.user_mcode.execute = execute;
       
        driver_reset = hal.driver_reset;                // Subscribe to driver reset event
        hal.driver_reset = driverReset;

        on_report_options = grbl.on_report_options;     // Subscribe to report options event
        grbl.on_report_options = onReportOptions;

        on_state_change = grbl.on_state_change;         // Subscribe to the state changed event by saving away the original
        grbl.on_state_change = onStateChanged;          // function pointer and adding ours to the chain.

        on_realtime_report = grbl.on_realtime_report;   // Subscribe to realtime report events AKA ? reports
        grbl.on_realtime_report = onRealtimeReport;     

        on_program_completed = grbl.on_program_completed; // Subscribe to on program completed events (lightshow on complete?)
        grbl.on_program_completed = onProgramCompleted;   // Not using this yet, will add back if needed

        on_execute_realtime = grbl.on_execute_realtime;     // Subscribe to the realtime execution event
        grbl.on_execute_realtime = realtimeIndicators;      // Spindle monitoring, flashing LEDs etc live here

    } else
        protocol_enqueue_rt_command(warning_msg);
}`
 
@5ocworkshop
Copy link
Author

It's after midnight here and I posted my message and shut things down and left the shop. As I was about to turn in for the night I thought "I wonder if I'm blocking the light by accident". So I stuck a delay(2000) in after the rgb_set_state(RGB_WHITE) call and sure enough the light popped on.

I'll improve my state handling in the morning, so you can disregard my request.

Before I forget though, I did have to change something in your code to get it to compile. I changed line 86 in your mcode example from:

return state == Status_Unhandled && user_mcode.validate ? user_mcode.validate(gc_block, parameter_words) : state;

to

return state == Status_Unhandled && user_mcode.validate ? user_mcode.validate(gc_block, deprecated) : state;

It was a guess on my part, please advise if this is a valid change.

Thanks.

@terjeio
Copy link
Contributor

terjeio commented Jul 29, 2021

So I stuck a delay(2000) in

If you want your plugin to be generic (usable by all drivers having enough ioports) use
hal.delay_ms(2000, NULL);
instead.

It was a guess on my part, please advise if this is a valid change.

It is valid, I'll fix the template.

@5ocworkshop
Copy link
Author

If you want your plugin to be generic (usable by all drivers having enough ioports) use
hal.delay_ms(2000, NULL);
instead.

Yes, I would like it to be usable by all drivers.

I only threw the delay in temporarily as a debug method since I knew it would block, but is that hal call a non-blocking way to generate a delay? That would be very helpful.

@5ocworkshop
Copy link
Author

Also, I noticed the "plugins" link in the last sentence of the readme summary on the Templates repo is a broken link.

"The HAL supports a wide range of extension possibilities, this without touching the core grbl codebase. Some examples can be found in the plugins folder."

@5ocworkshop
Copy link
Author

I was just looking through the codes at Marlin and this one caught my eye (amusingly, only 1 off from the code I chose). Is it your preference to adopt codes already in use at Marlin, in applicable? This one is a reasonable approximation of the inspection light function I am adding: https://marlinfw.org/docs/gcode/M355.html

@terjeio
Copy link
Contributor

terjeio commented Jul 29, 2021

First stop for determining a new M-code is LinuxCNC then Marlin. If no good match is found I try to avoid Marlin codes that has a fair chance of beeing relevant for grblHAL.

@terjeio
Copy link
Contributor

terjeio commented Aug 2, 2021

but is that hal call a non-blocking way to generate a delay

Yes, if you supply a callback function. Note that currently only one callback can be active at any time - I plan to change this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants