From cacbe1b8aab84ea942ace4ce0e02cf650486f835 Mon Sep 17 00:00:00 2001 From: Adrian Scripca Date: Thu, 4 May 2023 14:15:33 +0300 Subject: [PATCH] Introduced machine state handlers (check and run still need work). Added proper init handler, fetching settings and parameters and exposing them to UI. Added spindle rendering. --- grbl_machine.cpp | 469 ++++++++++++++++++++++++++++++++++++++++++----- grbl_machine.h | 100 +++++++++- main.cpp | 252 +++++++++++++++++-------- render.cpp | 207 +++++++++++++-------- render.h | 14 +- 5 files changed, 842 insertions(+), 200 deletions(-) diff --git a/grbl_machine.cpp b/grbl_machine.cpp index 4c39677..884aac9 100644 --- a/grbl_machine.cpp +++ b/grbl_machine.cpp @@ -9,6 +9,13 @@ static bool starts_with(const std::string& line, const std::string& prefix) { grbl::machine::machine() { pipe = new tcp_transport("192.168.5.39", 23); + states[grbl_machine_state::disconnected] = new machine_state_connect; + states[grbl_machine_state::init] = new machine_state_init; + states[grbl_machine_state::idle] = new machine_state_idle; + states[grbl_machine_state::check_program] = new machine_state_check_program; + states[grbl_machine_state::run_program] = new machine_state_run_program; + + switch_to_state(grbl_machine_state::disconnected); } grbl::machine::~machine() { @@ -21,14 +28,15 @@ void grbl::machine::connect() { void grbl::machine::on_connected(grbl::transport *transport) { std::cout << "grbl machine connected" << std::endl; + states[state]->on_connected(this); // telnet handshake so that we get the banner. banner won't be coming otherwise // t->send("\xff\xfd\x18\xff\xfd\x20\xff\xfd\x23\xff\xfd\x27"); - pipe->send("\xff\xfd\x18"); - +// pipe->send("\xff\xfd\x18"); } void grbl::machine::on_disconnected(grbl::transport *transport) { std::cout << "grbl machine disconnected" << std::endl; + switch_to_state(grbl_machine_state::disconnected); } grbl::realtime_status_report grbl::parse_status_report(std::string line, grbl::realtime_status_report& result) { @@ -234,56 +242,260 @@ std::string grbl::error_to_string(size_t error) { } } +std::string grbl::setting_description(int number) { + switch (number) { + case 0: + return "Step pulse time (microseconds)\nSets time length per step. Minimum 3 microseconds."; + case 1: + return "Step idle delay (milliseconds)\nSets a short hold delay when stopping to let dynamics settle before disabling steppers. Value 255 keeps motors enabled."; + case 2: + return "Step pulse invert (mask)\nInverts the step signals (active low)."; + case 3: + return "Step direction invert (mask)\nInverts the direction signals (active low)."; + case 4: + return "Invert step enable pin (boolean)\nInverts the stepper driver enable signals (active low). If the stepper drivers shares the same enable signal only X is used."; + case 5: + return "Invert limit pins (mask)\nInverts the axis limit input signals. "; + case 6: + return "Invert probe pin (boolean)\nInverts the probe input pin signal."; + case 10: + return "Status report options (mask)\nSpecifies optional data included in status reports."; + case 11: + return "Junction deviation (mm)\nSets how fast Grbl travels through consecutive motions. Lower value slows it down."; + case 12: + return "Arc tolerance (mm)\nSets the G2 and G3 arc tracing accuracy based on radial error. Beware: A very small value may effect performance."; + case 13: + return "Report in inches (boolean)\nEnables inch units when returning any position and rate value that is not a settings value."; + case 14: + return "Invert control pins (mask)\nInverts the control signals (active low)."; + case 15: + return "Invert coolant pins (mask)\nInverts the coolant and mist signals (active low)."; + case 16: + return "Invert spindle signals (mask)\nInverts the spindle on counterclockwise and PWM signals (active low)."; + case 17: + return "Pullup disable control pins (mask)\nDisable the control signals pullup resistors. Potentially enables pulldown resistor if available."; + case 18: + return "Pullup disable limit pins (mask)\nDisable the limit signals pullup resistors. Potentially enables pulldown resistor if available."; + case 19: + return "Pullup disable probe pin (boolean)\nDisable the probe signal pullup resistor. Potentially enables pulldown resistor if available."; + case 20: + return "Soft limits enable (boolean)\nEnables soft limits checks within machine travel and sets alarm when exceeded. Requires homing."; + case 21: + return "Hard limits enable (mask)\nWhen enabled immediately halts motion and throws an alarm when switch is triggered. In strict mode only homing is possible after switch is triggered. "; + case 22: + return "Homing cycle enable (boolean)\nEnables homing cycle. Requires limit switches on all axes."; + case 23: + return "Homing direction invert (mask)\nHoming searches for a switch in the positive direction. Set axis bit to search in negative direction."; + case 24: + return "Homing locate feed rate (mm/min)\nFeed rate to slowly engage limit switch to determine its location accurately."; + case 25: + return "Homing search seek rate (mm/min)\nSeek rate to quickly find the limit switch before the slower locating phase."; + case 26: + return "Homing switch debounce delay (milliseconds)\nSets a short delay between phases of homing cycle to let a switch debounce."; + case 27: + return "Homing switch pull-off distance (mm)\nRetract distance after triggering switch to disengage it. Homing will fail if switch isn't cleared."; + case 28: + return "G73 Retract distance (mm)\nG73 retract distance (for chip breaking drilling)."; + case 29: + return "Pulse delay (microseconds)\nStep pulse delay."; + case 30: + return "Maximum spindle speed (RPM)\nMaximum spindle speed. Sets PWM to maximum duty cycle."; + case 31: + return "Minimum spindle speed (RPM)\nMinimum spindle speed. Sets PWM to minimum duty cycle."; + case 32: + return "Mode of operation (integer)\nLaser mode: consecutive G1/2/3 commands will not halt when spindle speed is changed. Lathe mode: allows use of G7, G8, G96 and G97."; + case 33: + return "Spindle PWM frequency (Hz)\nSpindle PWM frequency."; + case 34: + return "Spindle PWM off value (percent)\nSpindle PWM off value in percent (duty cycle)."; + case 35: + return "Spindle PWM min value (percent)\nSpindle PWM min value in percent (duty cycle)."; + case 36: + return "Spindle PWM max value (percent)\nSpindle PWM max value in percent (duty cycle)."; + case 37: + return "Steppers deenergize (mask)\nSpecifies which steppers not to disable when stopped."; + case 38: + return "Spindle PPR (pulses)\nSpindle encoder pulses per revolution."; + case 39: + return "Enable legacy RT commands (boolean)\nEnables \"normal\" processing of ?, ! and ~ characters when part of $-setting or comment. If disabled then they are added to the input string instead."; + case 40: + return "Limit jog commands (boolean)\nLimit jog commands to machine limits for homed axes."; + case 43: + return "Homing passes, (Number of homing passes. Minimum 1)\n maximum 128."; + case 44: + return "Axes homing, first pass (mask)\nAxes to home in first pass."; + case 45: + return "Axes homing, second pass (mask)\nAxes to home in second pass."; + case 46: + return "Axes homing,third pass (mask)\nAxes to home in third pass."; + case 47: + return "Axes homing, fourth pass (mask)\nAxes to home in fourth pass."; + case 48: + return "Axes homing, fifthpass (mask)\nAxes to home in fifth pass."; + case 49: + return "Axes homing, sixth pass (mask)\nAxes to home in sixth pass."; + case 50: + return "Step jog speed (mm/min)\nStep jogging speed in millimeters per minute."; + case 51: + return "Slow jog speed (mm/min)\nSlow jogging speed in millimeters per minute."; + case 52: + return "Fast jog speed (mm/min)\nFast jogging speed in millimeters per minut."; + case 53: + return "Step jog distance (mm)\nJog distance for single step jogging."; + case 54: + return "Slow jog distance (mm)\nJog distance before automatic stop."; + case 55: + return "Fast jog distance (mm)\nJog distance before automatic stop."; + case 60: + return "Restore overrides ()\nRestore overrides to default values at program end."; + case 61: + return "Ignore door when idle ()\nEnable this if it is desirable to open the safety door when in IDLE mode (eg. for jogging)."; + case 62: + return "Sleep enable ()\nEnable sleep mode. "; + case 63: + return "Disable laser ()\nDisable laser during hold. "; + case 64: + return "Force init alarm ()\nStarts Grbl in alarm mode after a cold reset."; + case 65: + return "Check limits at init ()\nIf limit switches are engaged after reset this forces Grbl to start in alarm mode."; + case 66: + return "Homing init lock, (If homing is enabled)\n homing init lock sets Grbl into an alarm state upon power up. Clear by performing a homing cycle."; + case 70: + return "Stream,,Input stream source: 0 - serial, 1 - bluetooth ( 2 - ethernet)\n 3 - WiFi"; + case 71: + return "WiFi SSID ()\nWiFi SSID."; + case 72: + return "WiFi Password ()\nWiFi Password."; + case 73: + return "WiFi Port ()\nWiFi Port Number listening for incoming connections."; + case 74: + return "Bluetooth device ()\nBluetooth device name."; + case 75: + return "Bluetooth service ()\nBluetooth service name."; + + case 80: return "Spindle P-gain"; + case 81: return "Spindle I-gain"; + case 82: return "Spindle D-gain"; + case 84: return "Spindle PID max error"; + case 85: return "Spindle PID max I error\nSpindle PID max integrator error"; + + case 90: return "Spindle sync P-gain"; + case 91: return "Spindle sync I-gain"; + case 92: return "Spindle sync D-gain"; + case 95: return "Spindle sync PID max I error\nSpindle sync PID max integrator error"; + + case 100: + return "X-axis travel resolution (step/mm)\nX-axis travel resolution in steps per millimeter."; + case 101: + return "Y-axis travel resolution (step/mm)\nY-axis travel resolution in steps per millimeter."; + case 102: + return "Z-axis travel resolution (step/mm)\nZ-axis travel resolution in steps per millimeter."; + case 103: + return "A-axis travel resolution (step/mm)\nA-axis travel resolution in steps per millimeter."; + case 104: + return "B-axis travel resolution (step/mm)\nB-axis travel resolution in steps per millimeter."; + case 105: + return "C-axis travel resolution (step/mm)\nC-axis travel resolution in steps per millimeter."; + case 110: + return "X-axis maximum rate (mm/min)\nX-axis maximum rate. Used as G0 rapid rate."; + case 111: + return "Y-axis maximum rate (mm/min)\nY-axis maximum rate. Used as G0 rapid rate."; + case 112: + return "Z-axis maximum rate (mm/min)\nZ-axis maximum rate. Used as G0 rapid rate."; + case 113: + return "A-axis maximum rate (mm/min)\nA-axis maximum rate. Used as G0 rapid rate."; + case 114: + return "B-axis maximum rate (mm/min)\nB-axis maximum rate. Used as G0 rapid rate."; + case 115: + return "C-axis maximum rate (mm/min)\nC-axis maximum rate. Used as G0 rapid rate."; + case 120: + return "X-axis acceleration (mm/sec^2)\nX-axis acceleration. Used for motion planning to not exceed motor torque and lose steps."; + case 121: + return "Y-axis acceleration (mm/sec^2)\nY-axis acceleration. Used for motion planning to not exceed motor torque and lose steps."; + case 122: + return "Z-axis acceleration (mm/sec^2)\nZ-axis acceleration. Used for motion planning to not exceed motor torque and lose steps."; + case 123: + return "A-axis acceleration (mm/sec^2)\nA-axis acceleration. Used for motion planning to not exceed motor torque and lose steps."; + case 124: + return "B-axis acceleration (mm/sec^2)\nB-axis acceleration. Used for motion planning to not exceed motor torque and lose steps."; + case 125: + return "C-axis acceleration (mm/sec^2)\nC-axis acceleration. Used for motion planning to not exceed motor torque and lose steps."; + case 130: + return "X-axis maximum travel (mm)\nMaximum X-axis travel distance from homing switch. Determines valid machine space for soft-limits and homing search distances."; + case 131: + return "Y-axis maximum travel (mm)\nMaximum Y-axis travel distance from homing switch. Determines valid machine space for soft-limits and homing search distances."; + case 132: + return "Z-axis maximum travel (mm)\nMaximum Z-axis travel distance from homing switch. Determines valid machine space for soft-limits and homing search distances."; + case 133: + return "A-axis maximum travel (mm)\nMaximum A-axis travel distance from homing switch. Determines valid machine space for soft-limits and homing search distances."; + case 134: + return "B-axis maximum travel (mm)\nMaximum B-axis travel distance from homing switch. Determines valid machine space for soft-limits and homing search distances."; + case 135: + return "C-axis maximum travel (mm)\nMaximum B-axis travel distance from homing switch. Determines valid machine space for soft-limits and homing search distances."; + case 160: + return "X-axis backlash compensation (mm)\nX-axis backlash distance to compensate for."; + case 161: + return "Y-axis backlash compensation (mm)\nY-axis backlash distance to compensate for."; + case 162: + return "Z-axis backlash compensation (mm)\nZ-axis backlash distance to compensate for."; + case 163: + return "A-axis backlash compensation (mm)\nA-axis backlash distance to compensate for."; + case 164: + return "B-axis backlash compensation (mm)\nB-axis backlash distance to compensate for."; + case 165: + return "C-axis backlash compensation (mm)\nB-axis backlash distance to compensate for."; + default: + return "unknown setting"; + } +} + void grbl::machine::on_line_received(std::string line, grbl::transport *transport) { if (line.at(0) != '<') std::cout << ">> " << line << std::endl; - if (starts_with(line, "ok")) { - if (state == grbl_machine_state::run_program || state == grbl_machine_state::check_program) { - if (!entered_check_mode) { - entered_check_mode = true; - } - continue_program(); - } else if (state == grbl_machine_state::idle && entered_check_mode) { - entered_check_mode = false; - } + states[state]->on_line_received(line); - } else if (starts_with(line, "error")) { - size_t error = std::stoi(line.substr(6)); - if (state == grbl_machine_state::run_program) { - listener->on_run_completed(false, executed_instructions - 1, error); - state = grbl_machine_state::idle; - } else if (state == grbl_machine_state::check_program) { - listener->on_check_completed(false, executed_instructions - 1, error); - state = grbl_machine_state::idle; - pipe->send("$C"); // exit check mode - } -// on_error(error); - } else { - // we have a push message - if (starts_with(line, "Grbl")) { - listener->on_banner(line); - reset_machine_state(); - } else if (starts_with(line, "<")) { - last_report = parse_status_report(line, last_report); - listener->on_realtime_status_report(last_report); - } else if (starts_with(line, "[MSG:")) { - listener->on_message(line.substr(5, line.size() - 6)); - } else if (starts_with(line, "ALARM:")) { - listener->on_alarm(std::stoi(line.substr(6))); - } - } - -// if (state == grbl_machine_state::run_program) { -// if (line.rfind("ok", 0) == 0) { +// if (starts_with(line, "ok")) { +// if (state == grbl_machine_state::run_program || state == grbl_machine_state::check_program) { +// if (!entered_check_mode) { +// entered_check_mode = true; +// } // continue_program(); -// } else if (line.rfind("error", 0) == 0) { -// std::cerr << "Received error" << std::endl; -// } else { +// } else if (state == grbl_machine_state::idle && entered_check_mode) { +// entered_check_mode = false; // } +// +// } else if (starts_with(line, "error")) { +// size_t error = std::stoi(line.substr(6)); +// if (state == grbl_machine_state::run_program) { +// listener->on_run_completed(false, executed_instructions - 1, error); +// state = grbl_machine_state::idle; +// } else if (state == grbl_machine_state::check_program) { +// listener->on_check_completed(false, executed_instructions - 1, error); +// state = grbl_machine_state::idle; +// pipe->send("$C"); // exit check mode +// } +//// on_error(error); // } else { -// // evaluate responses when not running a program +// // we have a push message +// if (starts_with(line, "Grbl")) { +// listener->on_banner(line); +// pipe->send("$10=0"); // display position in work pos, please +// pipe->send("$$"); // get all settings +// pipe->send("$#"); // get all offsets +// reset_machine_state(); +// } else if (starts_with(line, "<")) { +// last_report = parse_status_report(line, last_report); +// listener->on_realtime_status_report(last_report); +// } else if (starts_with(line, "[MSG:")) { +// listener->on_message(line.substr(5, line.size() - 6)); +// } else if (starts_with(line, "ALARM:")) { +// listener->on_alarm(std::stoi(line.substr(6))); +// } else { +// std::cout << "received >> " << line << std::endl; +// } // } + } void grbl::machine::continue_program() { @@ -383,6 +595,177 @@ void grbl::machine::reset_machine_state() { executed_instructions = false; } +void grbl::machine::switch_to_state(grbl::grbl_machine_state new_state) { + states[state]->on_exit(this); + state = new_state; + states[state]->on_enter(this); +} + +const std::map& grbl::machine::get_settings() const { + return settings; +} + +const std::map& grbl::machine::get_parameters() const { + return parameters; +} + bool grbl::jog_state::no_jogging() const { return !(up_pressed || down_pressed || left_pressed || right_pressed || z_up_pressed || z_down_pressed); } + +// connect state +void grbl::machine_state_connect::on_connected(machine *m) { + // trigger a soft reset +// m->pipe->send("\xff\xfd\x18"); + m->request_reset(); +} + +void grbl::machine_state_connect::on_disconnected(machine *m) { +} + +void grbl::machine_state_connect::on_enter(grbl::machine *m) { + cnc = m; +} + +void grbl::machine_state_connect::on_exit(grbl::machine *m) { +} + +void grbl::machine_state_connect::on_line_received(std::string line) { +// std::cerr << "Should not get content while connecting!" << std::endl; + if (starts_with(line, "Grbl")) { + cnc->listener->on_banner(line); + cnc->switch_to_state(grbl_machine_state::init); + } +} + +// init state +void grbl::machine_state_init::on_enter(grbl::machine *m) { + cnc = m; + init_state = init_stage::start; + move_to_next_init_stage(); +} + +void grbl::machine_state_init::on_exit(grbl::machine *m) { + cnc->listener->on_init_completed(); +} + +void grbl::machine_state_init::on_line_received(std::string line) { + if (starts_with(line, "ok")) { + move_to_next_init_stage(); + } else if (starts_with(line, "error")) { + // TODO: how should we act? + std::cerr << "Init failed!!!!!!!!!!!!!!!!!! FIXME!" << std::endl; + } else { + if (starts_with(line, "$")) { + auto pieces = split_string(line, "="); + cnc->settings[pieces[0]] = pieces[1]; + } else if (starts_with(line, "[G") || starts_with(line, "[H") || starts_with(line, "[T") || starts_with(line, "[P")) { + line = line.substr(1, line.size() - 2); + // TODO: some parameters have more than two : + auto pieces = split_string(line, ":"); + cnc->parameters[pieces[0]] = pieces[1]; + } + } +} + +void grbl::machine_state_init::on_connected(machine *m) { +} + +void grbl::machine_state_init::on_disconnected(machine *m) { +} + +void grbl::machine_state_init::move_to_next_init_stage() { + switch (init_state) { + case init_stage::start: + init_state = init_stage::set_work_pos; + cnc->pipe->send("$10=0"); + break; + case init_stage::set_work_pos: + init_state = init_stage::fetch_settings; + cnc->pipe->send("$$"); + break; + case init_stage::fetch_settings: + init_state = init_stage::fetch_parameters; + cnc->pipe->send("$#"); + break; + case init_stage::fetch_parameters: + std::cout << "CNC initialization done" << std::endl; + cnc->switch_to_state(grbl_machine_state::idle); + break; + } +} + + +// idle state +void grbl::machine_state_idle::on_connected(machine *m) { +} + +void grbl::machine_state_idle::on_disconnected(machine *m) { + +} + +void grbl::machine_state_idle::on_enter(grbl::machine *m) { + cnc = m; +} + +void grbl::machine_state_idle::on_exit(grbl::machine *m) { + +} + +void grbl::machine_state_idle::on_line_received(std::string line) { + if (starts_with(line, "ok")) { + } else if (starts_with(line, "error")) { + } else if (starts_with(line, "Grbl")) { + cnc->listener->on_banner(line); + cnc->reset_machine_state(); + } else if (starts_with(line, "<")) { + cnc->last_report = parse_status_report(line, cnc->last_report); + cnc->listener->on_realtime_status_report(cnc->last_report); + + } else if (starts_with(line, "[MSG:")) { + cnc->listener->on_message(line.substr(5, line.size() - 6)); + } else if (starts_with(line, "ALARM:")) { + cnc->listener->on_alarm(std::stoi(line.substr(6))); + } +} + +// check program +void grbl::machine_state_check_program::on_connected(machine *m) { +} + +void grbl::machine_state_check_program::on_disconnected(machine *m) { +} + +void grbl::machine_state_check_program::on_enter(grbl::machine *m) { + +} + +void grbl::machine_state_check_program::on_exit(grbl::machine *m) { + +} + +void grbl::machine_state_check_program::on_line_received(std::string line) { + +} + + +// run program +void grbl::machine_state_run_program::on_connected(machine *m) { + +} + +void grbl::machine_state_run_program::on_disconnected(machine *m) { + +} + +void grbl::machine_state_run_program::on_enter(grbl::machine *m) { + +} + +void grbl::machine_state_run_program::on_exit(grbl::machine *m) { + +} + +void grbl::machine_state_run_program::on_line_received(std::string line) { + +} diff --git a/grbl_machine.h b/grbl_machine.h index d7bf766..01a1a03 100644 --- a/grbl_machine.h +++ b/grbl_machine.h @@ -1,5 +1,7 @@ #pragma once +#include +#include #include "grbl_communication.h" #include "grbl.h" @@ -23,6 +25,7 @@ machine_status status_from_string(const std::string& status); std::string status_to_string(const machine_status& status); std::string alarm_to_string(int alarm); std::string error_to_string(size_t error); +std::string setting_description(int number); struct realtime_status_report { machine_status status; @@ -61,6 +64,7 @@ inline bool operator==(const realtime_status_report& a, const realtime_status_re realtime_status_report parse_status_report(std::string line, grbl::realtime_status_report& result); enum class grbl_machine_state { + disconnected, init, run_program, check_program, @@ -105,10 +109,89 @@ struct machine_listener { virtual void on_banner(std::string line) = 0; virtual void on_message(std::string message) = 0; virtual void on_alarm(int alarm) = 0; + virtual void on_init_completed() = 0; virtual void on_run_completed(bool success, size_t failed_index, size_t error) = 0; virtual void on_check_completed(bool success, size_t failed_index, size_t error) = 0; }; + +enum class init_stage { + start, + set_work_pos, + fetch_settings, + fetch_parameters +}; + +struct machine; + +struct machine_state { + virtual void on_connected(machine *m) = 0; + virtual void on_disconnected(machine *m) = 0; + virtual void on_enter(machine *m) = 0; + virtual void on_exit(machine *m) = 0; + virtual void on_line_received(std::string line) = 0; +}; + +struct machine_state_connect : public machine_state { + void on_connected(machine *m) override; + void on_disconnected(machine *m) override; + void on_enter(machine *m) override; + void on_exit(machine *m) override; + void on_line_received(std::string line) override; + machine *cnc; +}; + +struct machine_state_init : public machine_state { + void on_connected(machine *m) override; + void on_disconnected(machine *m) override; + void on_enter(machine *m) override; + void on_exit(machine *m) override; + void on_line_received(std::string line) override; + + init_stage init_state = init_stage::start; + void move_to_next_init_stage(); + + machine* cnc; +}; + +struct machine_state_idle : public machine_state { + void on_connected(machine *m) override; + void on_disconnected(machine *m) override; + void on_enter(machine *m) override; + void on_exit(machine *m) override; + void on_line_received(std::string line) override; + machine *cnc; +}; + +struct machine_state_check_program : public machine_state { + void on_connected(machine *m) override; + void on_disconnected(machine *m) override; + void on_enter(machine *m) override; + void on_exit(machine *m) override; + void on_line_received(std::string line) override; +}; + +struct machine_state_run_program : public machine_state { + void on_connected(machine *m) override; + void on_disconnected(machine *m) override; + void on_enter(machine *m) override; + void on_exit(machine *m) override; + void on_line_received(std::string line) override; +}; + + +struct settings_cmp { + bool operator()(const std::string& a, const std::string& b) const { + return std::stoi(a.substr(1)) < std::stoi(b.substr(1)); + } +}; + +struct parameters_cmp { + bool operator()(const std::string& a, const std::string& b) const { + return a < b; + } +}; + struct machine : public transport_callbacks { machine(); ~machine(); @@ -121,6 +204,8 @@ struct machine : public transport_callbacks { void cancel_jog() const; [[nodiscard]] realtime_status_report get_status() const { return last_report; }; + const std::map& get_settings() const; + const std::map& get_parameters() const; void request_unlock(); void request_home(); @@ -129,15 +214,28 @@ struct machine : public transport_callbacks { void request_cycle_start(); void request_feed_hold(); + protected: void on_connected(transport *transport) override; void on_disconnected(transport *transport) override; void on_line_received(std::string line, transport *transport) override; + void switch_to_state(grbl_machine_state new_state); + + friend class machine_state_connect; + friend class machine_state_init; + friend class machine_state_idle; + friend class machine_state_check_program; + friend class machine_state_run_program; + + std::map states; + std::map settings; + std::map parameters; + realtime_status_report last_report{}; machine_listener *listener = nullptr; transport *pipe = nullptr; - grbl_machine_state state = grbl_machine_state::init; + grbl_machine_state state = grbl_machine_state::disconnected; program running_program; size_t executed_instructions = 0; bool entered_check_mode = false; diff --git a/main.cpp b/main.cpp index 1c79aad..a5cee6a 100644 --- a/main.cpp +++ b/main.cpp @@ -1,16 +1,3 @@ -/* - src/example1.cpp -- C++ version of an example application that shows - how to use the various widget classes. For a Python implementation, see - '../python/example1.py'. - - NanoGUI was developed by Wenzel Jakob . - The widget drawing code is based on the NanoVG demo application - by Mikko Mononen. - - All rights reserved. Use of this source code is governed by a - BSD-style license that can be found in the LICENSE.txt file. -*/ - #include #include #include @@ -22,6 +9,8 @@ #include #include #include +#include +#include #include #include #include @@ -43,6 +32,7 @@ #include "string_utils.h" #include "render.h" #include "glm/gtx/quaternion.hpp" +#include "nanogui/nanogui.h" #include #include #include // glm::vec3 @@ -77,58 +67,152 @@ public: float cam_zoom = 0; glm::quat cam_src_rotation = glm::quat(1.0, 0.0, 0.0, 0.0); // identity quaternion - void init_program_geometry() { - renderer.update(pgm, cnc); + TabWidget *tab_widget; + VScrollPanel *settings_vscroll; + Widget *settings_layer; - auto max_pos = renderer.get_extents_max(); - auto min_pos = renderer.get_extents_min(); + VScrollPanel *parameters_vscroll; + Widget *parameters_layer; + TextBox *mpos_x_text, *mpos_y_text, *mpos_z_text; - cam_target = (max_pos - min_pos) / 2.0f; - cam_zoom = (max_pos.x - min_pos.x); - cam_src_rotation = glm::quat(1.0, 0.0, 0.0, 0.0); + void fill_in_settings() { + settings_vscroll = new VScrollPanel(tab_widget); + tab_widget->append_tab("Settings", settings_vscroll); + + settings_layer = new Widget(settings_vscroll); + settings_layer->set_layout(new GridLayout(Orientation::Horizontal, 1, Alignment::Middle)); + + auto& settings = cnc.get_settings(); + + for (auto& s: settings) { + auto w = settings_layer->add(); + w->set_layout(new BoxLayout(Orientation::Horizontal, Alignment::Middle, 2, 2)); + auto x = w->add