#pragma once #include #include #include "grbl_communication.h" #include "grbl.h" namespace grbl { enum class machine_status { idle, run, hold, jog, alarm, door, check, home, sleep, tool, unknown }; 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; std::string sub_status; float work_pos[3] = {0}; float machine_pos[3] = {0}; size_t buffers_free = 0; size_t rx_chars_free = 0; size_t line_number = 0; float feed_rate = 0; float programmed_rpm = 0; float actual_rpm = 0; std::string signals; float axis_offsets[3] = {0}; std::string coordinate_system; std::string overrides; std::string accessory_status; bool mpg = false; bool homing_complete = false; std::string scaled_axis; bool tool_length_reference_offset_set = false; std::string firmware; }; inline bool operator==(const realtime_status_report& a, const realtime_status_report& b) { return a.status == b.status && a.sub_status == b.sub_status && a.machine_pos[0] == b.machine_pos[0] && a.machine_pos[1] == b.machine_pos[1] && a.machine_pos[2] == b.machine_pos[2] && a.work_pos[0] == b.work_pos[0] && a.work_pos[1] == b.work_pos[1] && a.work_pos[2] == b.work_pos[2]; } 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, idle, }; struct jog_state { bool left_pressed = false; bool right_pressed = false; bool up_pressed = false; bool down_pressed = false; bool z_up_pressed = false; bool z_down_pressed = false; bool speed_fast_pressed = false; bool speed_slow_pressed = false; [[nodiscard]] bool no_jogging() const; }; static bool operator==(const jog_state& a, const jog_state& b) { if (a.left_pressed != b.left_pressed || a.right_pressed != b.right_pressed || a.up_pressed != b.up_pressed || a.down_pressed != b.down_pressed || a.z_up_pressed != b.z_up_pressed || a.z_down_pressed != b.z_down_pressed || a.speed_fast_pressed != b.speed_fast_pressed || a.speed_slow_pressed != b.speed_slow_pressed) { return false; } return true; } static bool operator!=(const jog_state& a, const jog_state& b) { return !(a == b); } struct machine_listener { virtual void on_connected() = 0; virtual void on_disconnected() = 0; virtual void on_realtime_status_report(realtime_status_report) = 0; 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; virtual void on_settings_reloaded() = 0; virtual void on_parameters_reloaded() = 0; }; enum class init_stage { start, set_work_pos, fetch_settings, fetch_parameters }; enum class check_stage { start, enable_check_mode, run_program, disable_check_mode }; enum class run_stage { start, run_program, }; 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; bool continue_program(); void move_to_next_check_stage(); check_stage stage = check_stage::start; machine *cnc; bool check_failed; size_t check_error; }; 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; bool continue_program(); void move_to_next_run_stage(); machine *cnc; run_stage stage = run_stage::start; bool run_failed; size_t run_error; }; 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; } }; enum class jog_direction { x_up, x_down, y_up, y_down, z_up, z_down, }; struct machine : public transport_callbacks { machine(); ~machine(); void set_listener(grbl::machine_listener *listener); void connect(); void set_work_offset(std::string work_offset); std::array get_work_pos() const; void run_program(const grbl::program& pgm, const std::string& work_offset); void check_program(const grbl::program& pgm); void request_jog(jog_state jog) const; void request_jog_fixed(jog_direction dir, float distance, float feed); 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(); void request_reset(); void request_cycle_start(); void request_feed_hold(); // 0 = G54, 1 = G55, etc void zero_offset(int which); void go_to_zero(bool x, bool y, bool z); // 0 = G54, 1 = G55, etc axis 0=X, 1=Y, 2=Z void zero_offset_axis(int offset_index, int axis); 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; std::string current_work_offset; float current_work_offset_values[3] = {0}; public: const float *get_current_work_offset_values() const; protected: volatile size_t awaiting_responses = 0; realtime_status_report last_report{}; machine_listener *listener = nullptr; transport *pipe = nullptr; grbl_machine_state state = grbl_machine_state::disconnected; program running_program; size_t executed_instructions = 0; void reset_machine_state(); }; }