diff --git a/g2core/canonical_machine.h b/g2core/canonical_machine.h index 2b77784a..3d15e730 100644 --- a/g2core/canonical_machine.h +++ b/g2core/canonical_machine.h @@ -34,6 +34,7 @@ #include "config.h" #include "hardware.h" // Note: hardware.h is specific to the hardware target selected +#include "settings.h" /* Defines, Macros, and Assorted Parameters */ @@ -374,7 +375,6 @@ typedef struct GCodeState { // Gcode model state - used by model, pl coord_system = ABSOLUTE_COORDS; tool = 0; tool_select = 0; - }; } GCodeState_t; @@ -401,6 +401,10 @@ typedef struct GCodeStateExtended { // Gcode dynamic state extensions - used // float cutter_radius; // D - cutter radius compensation (0 is off) // float cutter_length; // H - cutter length compensation (0 is off) +#if MARLIN_COMPAT_ENABLED == true + bool marlin_flavor; +#endif + uint16_t magic_end; } GCodeStateX_t; diff --git a/g2core/error.h b/g2core/error.h index 609c65ee..724247f9 100644 --- a/g2core/error.h +++ b/g2core/error.h @@ -205,8 +205,8 @@ char *get_status_message(stat_t status); #define STAT_VALUE_TYPE_ERROR 116 // JSON value does not agree with variable type #define STAT_INPUT_FROM_MUTED_CHANNEL_ERROR 117 // input from a muted channel was ignored -#define STAT_ERROR_118 118 -#define STAT_ERROR_119 119 +#define STAT_CHECKSUM_MATCH_FAILED 118 // the provided checksum didn't match +#define STAT_LINE_NUMBER_OUT_OF_SEQUENCE 119 #define STAT_ERROR_120 120 #define STAT_ERROR_121 121 diff --git a/g2core/g2core.xcodeproj/project.pbxproj b/g2core/g2core.xcodeproj/project.pbxproj index 670d7df0..16f0ed26 100644 --- a/g2core/g2core.xcodeproj/project.pbxproj +++ b/g2core/g2core.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ D44E72C11D663B0300ECD5DD /* coolant.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D44E72C01D663B0300ECD5DD /* coolant.cpp */; }; D457117C17053EFA00EA19A8 /* Makefile in Sources */ = {isa = PBXBuildFile; fileRef = D457117B17053EFA00EA19A8 /* Makefile */; }; + D4694F9E1E295B5E00F813BA /* marlin_compatibility.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D4694F9C1E295B5E00F813BA /* marlin_compatibility.cpp */; }; D48F5A56172CB1FA00D0E055 /* canonical_machine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D48F5A40172CB1F900D0E055 /* canonical_machine.cpp */; }; D48F5A57172CB1FA00D0E055 /* config_app.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D48F5A41172CB1F900D0E055 /* config_app.cpp */; }; D48F5A58172CB1FA00D0E055 /* config.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D48F5A42172CB1F900D0E055 /* config.cpp */; }; @@ -59,6 +60,8 @@ D44E72C21D663B0F00ECD5DD /* coolant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = coolant.h; sourceTree = ""; }; D4522DC91C45F41D0086AAE6 /* g2core_info.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = g2core_info.h; sourceTree = ""; }; D457117B17053EFA00EA19A8 /* Makefile */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; path = Makefile; sourceTree = ""; usesTabs = 1; xcLanguageSpecificationIdentifier = xcode.lang.sh; }; + D4694F9C1E295B5E00F813BA /* marlin_compatibility.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = marlin_compatibility.cpp; sourceTree = ""; }; + D4694F9D1E295B5E00F813BA /* marlin_compatibility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = marlin_compatibility.h; sourceTree = ""; }; D47B744C1D4925B4004FAB53 /* device */ = {isa = PBXFileReference; lastKnownFileType = folder; path = device; sourceTree = ""; }; D48F5A40172CB1F900D0E055 /* canonical_machine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = canonical_machine.cpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; D48F5A41172CB1F900D0E055 /* config_app.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = config_app.cpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; @@ -160,6 +163,8 @@ D48F5A74172CB21100D0E055 /* json_parser.h */, D48F5A4A172CB1FA00D0E055 /* kinematics.cpp */, D48F5A75172CB21100D0E055 /* kinematics.h */, + D4694F9C1E295B5E00F813BA /* marlin_compatibility.cpp */, + D4694F9D1E295B5E00F813BA /* marlin_compatibility.h */, D48F5A4C172CB1FA00D0E055 /* persistence.cpp */, D48F5A76172CB21100D0E055 /* persistence.h */, D48F5A4D172CB1FA00D0E055 /* plan_arc.cpp */, @@ -420,6 +425,7 @@ D457117C17053EFA00EA19A8 /* Makefile in Sources */, D4B657A718B5C23C00F8616C /* pwm.cpp in Sources */, D44E72C11D663B0300ECD5DD /* coolant.cpp in Sources */, + D4694F9E1E295B5E00F813BA /* marlin_compatibility.cpp in Sources */, D4B657A318B5C21600F8616C /* cycle_probing.cpp in Sources */, D4D6453919BCAE3F0053705B /* plan_zoid.cpp in Sources */, D4B657A218B5C21600F8616C /* cycle_jogging.cpp in Sources */, diff --git a/g2core/gcode_parser.cpp b/g2core/gcode_parser.cpp index f8d71d93..cc2ff40b 100644 --- a/g2core/gcode_parser.cpp +++ b/g2core/gcode_parser.cpp @@ -22,15 +22,20 @@ #include "controller.h" #include "gcode_parser.h" #include "canonical_machine.h" +#include "settings.h" #include "spindle.h" #include "coolant.h" #include "util.h" #include "xio.h" // for char definitions +#if MARLIN_COMPAT_ENABLED == true +#include "marlin_compatibility.h" +#endif + // Structures used by Gcode parser typedef struct GCodeInputValue { // Gcode inputs - meaning depends on context - + uint8_t next_action; // handles G modal group 1 moves & non-modals cmMotionMode motion_mode; // Group1: G0, G1, G2, G3, G38.2, G80, G81, G82, G83, G84, G85, G86, G87, G88, G89 uint8_t program_flow; // used only by the gcode_parser @@ -116,17 +121,18 @@ GCodeValue_t gv; // gcode input values GCodeFlag_t gf; // gcode input flags // local helper functions and macros -static void _normalize_gcode_block(char *str, char **active_comment, uint8_t *block_delete_flag); -static stat_t _get_next_gcode_word(char **pstr, char *letter, float *value); -static stat_t _point(float value); -static stat_t _validate_gcode_block(char *active_comment); -static stat_t _parse_gcode_block(char *line, char *active_comment); // Parse the block into the GN/GF structs -static stat_t _execute_gcode_block(char *active_comment); // Execute the gcode block +void _normalize_gcode_block(char *str, char **active_comment, uint8_t *block_delete_flag); +stat_t _get_next_gcode_word(char **pstr, char *letter, float *value); +stat_t _point(float value); +stat_t _verify_checksum(char *str); +stat_t _validate_gcode_block(char *active_comment); +stat_t _parse_gcode_block(char *line, char *active_comment); // Parse the block into the GN/GF structs +stat_t _execute_gcode_block(char *active_comment); // Execute the gcode block #define SET_MODAL(m,parm,val) ({gv.parm=val; gf.parm=true; gp.modals[m]=true; break;}) #define SET_NON_MODAL(parm,val) ({gv.parm=val; gf.parm=true; break;}) #define EXEC_FUNC(f,v) if(gf.v) { status=f(gv.v);} - + /* * gcode_parser_init() */ @@ -150,6 +156,11 @@ stat_t gcode_parser(char *block) char *active_comment = &none; // gcode comment or NUL string uint8_t block_delete_flag; + stat_t check_ret = _verify_checksum(str); + if (check_ret != STAT_OK) { + return check_ret; + } + _normalize_gcode_block(str, &active_comment, &block_delete_flag); // TODO, now MSG is put in the active comment, handle that. @@ -171,6 +182,24 @@ stat_t gcode_parser(char *block) return(_parse_gcode_block(block, active_comment)); } +/* + * _verify_checksum() - ensure that, if there is a checksum, that it's valid + * + * Returns STAT_OK is it's valid. + * Returns STAT_CHECKSUM_MATCH_FAILED if the checksum doesn't match. + */ +stat_t _verify_checksum(char *str) +{ +#if MARLIN_COMPAT_ENABLED == true + if (true == cm.gmx.marlin_flavor) { + return marlin_verify_checksum(str); + } +#endif + + // for now, always assume it's ok + return STAT_OK; +} + /* * _normalize_gcode_block() - normalize a block (line) of gcode in place * @@ -205,9 +234,9 @@ stat_t gcode_parser(char *block) * - block_delete_flag is set true if block delete encountered, false otherwise */ -static char _normalize_scratch[RX_BUFFER_MIN_SIZE]; +char _normalize_scratch[RX_BUFFER_MIN_SIZE]; -static void _normalize_gcode_block(char *str, char **active_comment, uint8_t *block_delete_flag) +void _normalize_gcode_block(char *str, char **active_comment, uint8_t *block_delete_flag) { _normalize_scratch[0] = 0; @@ -435,7 +464,7 @@ static void _normalize_gcode_block(char *str, char **active_comment, uint8_t *bl * G0X... is not interpreted as hexadecimal. This is trapped. */ -static stat_t _get_next_gcode_word(char **pstr, char *letter, float *value) +stat_t _get_next_gcode_word(char **pstr, char *letter, float *value) { if (**pstr == NUL) { return (STAT_COMPLETE); } // no more words @@ -467,7 +496,7 @@ static stat_t _get_next_gcode_word(char **pstr, char *letter, float *value) * _point() - isolate the decimal point value as an integer */ -static uint8_t _point(float value) +uint8_t _point(const float value) { return((uint8_t)(value*10 - trunc(value)*10)); // isolate the decimal point as an int } @@ -476,7 +505,7 @@ static uint8_t _point(float value) * _validate_gcode_block() - check for some gross Gcode block semantic violations */ -static stat_t _validate_gcode_block(char *active_comment) +stat_t _validate_gcode_block(char *active_comment) { // Check for modal group violations. From NIST, section 3.4 "It is an error to put // a G-code from group 1 and a G-code from group 0 on the same line if both of them @@ -505,7 +534,7 @@ static stat_t _validate_gcode_block(char *active_comment) * contain only uppercase characters and signed floats (no whitespace). */ -static stat_t _parse_gcode_block(char *buf, char *active_comment) +stat_t _parse_gcode_block(char *buf, char *active_comment) { char *pstr = (char *)buf; // persistent pointer into gcode block for parsing words char letter; // parsed letter, eg.g. G or X or Y @@ -678,7 +707,7 @@ static stat_t _parse_gcode_block(char *buf, char *active_comment) case 'K': SET_NON_MODAL (arc_offset[2], value); case 'L': SET_NON_MODAL (L_word, value); case 'R': SET_NON_MODAL (arc_radius, value); - case 'N': SET_NON_MODAL (linenum,(uint32_t)value); // line number + case 'N': SET_NON_MODAL (linenum,(uint32_t)value); // line number default: status = STAT_GCODE_COMMAND_UNSUPPORTED; } if(status != STAT_OK) break; @@ -728,7 +757,7 @@ static stat_t _parse_gcode_block(char *buf, char *active_comment) * to calling the canonical functions (which do the unit conversions) */ -static stat_t _execute_gcode_block(char *active_comment) +stat_t _execute_gcode_block(char *active_comment) { stat_t status = STAT_OK; @@ -754,7 +783,7 @@ static stat_t _execute_gcode_block(char *active_comment) if (gf.mto_control) { // manual traverse override ritorno(cm_mto_control(gv.P_word, gf.P_word)); } - + if (gv.next_action == NEXT_ACTION_DWELL) { // G4 - dwell ritorno(cm_dwell(gv.P_word)); // return if error, otherwise complete the block } @@ -764,23 +793,23 @@ static stat_t _execute_gcode_block(char *active_comment) switch (gv.next_action) { // Tool length offsets case NEXT_ACTION_SET_TL_OFFSET: { // G43 - ritorno(cm_set_tl_offset(gv.H_word, gf.H_word, false)); - break; + ritorno(cm_set_tl_offset(gv.H_word, gf.H_word, false)); + break; } case NEXT_ACTION_SET_ADDITIONAL_TL_OFFSET: { // G43.2 - ritorno(cm_set_tl_offset(gv.H_word, gf.H_word, true)); - break; + ritorno(cm_set_tl_offset(gv.H_word, gf.H_word, true)); + break; } case NEXT_ACTION_CANCEL_TL_OFFSET: { // G49 - ritorno(cm_cancel_tl_offset()); - break; + ritorno(cm_cancel_tl_offset()); + break; } } EXEC_FUNC(cm_set_coord_system, coord_system); // G54, G55, G56, G57, G58, G59 if (gf.path_control) { // G61, G61.1, G64 - status = cm_set_path_control(MODEL, gv.path_control); + status = cm_set_path_control(MODEL, gv.path_control); } EXEC_FUNC(cm_set_distance_mode, distance_mode); // G90, G91 @@ -802,10 +831,10 @@ static stat_t _execute_gcode_block(char *active_comment) case NEXT_ACTION_STRAIGHT_PROBE_AWAY_ERR:{ status = cm_straight_probe(gv.target, gf.target, true, false); break;} // G38.4 case NEXT_ACTION_STRAIGHT_PROBE_AWAY: { status = cm_straight_probe(gv.target, gf.target, false, false); break;}// G38.5 - case NEXT_ACTION_SET_G10_DATA: { status = cm_set_g10_data(gv.P_word, gf.P_word, + case NEXT_ACTION_SET_G10_DATA: { status = cm_set_g10_data(gv.P_word, gf.P_word, gv.L_word, gf.L_word, gv.target, gf.target); break;} - + case NEXT_ACTION_SET_ORIGIN_OFFSETS: { status = cm_set_origin_offsets(gv.target, gf.target); break;}// G92 case NEXT_ACTION_RESET_ORIGIN_OFFSETS: { status = cm_reset_origin_offsets(); break;} // G92.1 case NEXT_ACTION_SUSPEND_ORIGIN_OFFSETS: { status = cm_suspend_origin_offsets(); break;} // G92.2 diff --git a/g2core/marlin_compatibility.cpp b/g2core/marlin_compatibility.cpp new file mode 100644 index 00000000..54c5e022 --- /dev/null +++ b/g2core/marlin_compatibility.cpp @@ -0,0 +1,89 @@ +/* + * marlin_compatibility.cpp - support for marlin protocol and gcode + * This file is part of the g2core project + * + * Copyright (c) 2017 Alden S. Hart, Jr. + * Copyright (c) 2017 Rob Giseburt + * + * This file ("the software") is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2 as published by the + * Free Software Foundation. You should have received a copy of the GNU General Public + * License, version 2 along with the software. If not, see . + * + * THE SOFTWARE IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT WITHOUT ANY + * WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include "g2core.h" // #1 +#include "config.h" // #2 +#include "settings.h" + +#if MARLIN_COMPAT_ENABLED == true + +#include "controller.h" +#include "gcode_parser.h" +#include "canonical_machine.h" +#include "util.h" +#include "xio.h" // for char definitions + +// Structures used + +// local helper functions and macros + +/* + * marlin_verify_checksum() - check to see if we have a line number (cheaply) and a valid checksum + */ + +stat_t marlin_verify_checksum(char *str) +{ + if (*str != 'N') { return STAT_OK; } // we only check if we have a line number + + char checksum = 0; + char c = *str++; + while (c && (c != '*')) { + checksum ^= c; + c = *str++; + } + + // c might be 0 here, in which case we didn't get a checksum and we return STAT_OK + + if ((c == '*') && strtol(str, NULL, 10) != checksum) { + return STAT_CHECKSUM_MATCH_FAILED; + } + return STAT_OK; +} + + + +/*********************************************************************************** + * CONFIGURATION AND INTERFACE FUNCTIONS + * Functions to get and set variables from the cfgArray table + ***********************************************************************************/ + +//stat_t gc_get_gc(nvObj_t *nv) +//{ +// ritorno(nv_copy_string(nv, cs.saved_buf)); +// nv->valuetype = TYPE_STRING; +// return (STAT_OK); +//} +// +//stat_t gc_run_gc(nvObj_t *nv) +//{ +// return(gcode_parser(*nv->stringp)); +//} + +/*********************************************************************************** + * TEXT MODE SUPPORT + * Functions to print variables from the cfgArray table + ***********************************************************************************/ + +#ifdef __TEXT_MODE + +// no text mode functions here. Move along + +#endif // __TEXT_MODE + +#endif // MARLIN_COMPAT_ENABLED == true diff --git a/g2core/marlin_compatibility.h b/g2core/marlin_compatibility.h new file mode 100644 index 00000000..19070a03 --- /dev/null +++ b/g2core/marlin_compatibility.h @@ -0,0 +1,33 @@ +/* + * marlin_compatibility.cpp - support for marlin protocol and gcode + * This file is part of the g2core project + * + * Copyright (c) 2017 Alden S. Hart, Jr. + * Copyright (c) 2017 Rob Giseburt + * + * This file ("the software") is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2 as published by the + * Free Software Foundation. You should have received a copy of the GNU General Public + * License, version 2 along with the software. If not, see . + * + * THE SOFTWARE IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT WITHOUT ANY + * WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef MARLIN_COMPAT_H_ONCE +#define MARLIN_COMPAT_H_ONCE + +#include "g2core.h" // #1 +#include "config.h" // #2 + +/* + * Global Scope Functions + */ + +stat_t marlin_verify_checksum(char *str); + +#endif // End of include guard: MARLIN_COMPAT_H_ONCE diff --git a/g2core/settings/settings_Printrbot_Play.h b/g2core/settings/settings_Printrbot_Play.h index 09d996ef..317f6da6 100644 --- a/g2core/settings/settings_Printrbot_Play.h +++ b/g2core/settings/settings_Printrbot_Play.h @@ -103,13 +103,13 @@ #define M1_POWER_LEVEL 0.4 // 1mp // 80 steps/mm at 1/16 microstepping = 40 mm/rev -#define M3_MOTOR_MAP AXIS_Y -#define M3_STEP_ANGLE 1.8 -#define M3_TRAVEL_PER_REV 40.64 -#define M3_MICROSTEPS 32 -#define M3_POLARITY 0 -#define M3_POWER_MODE MOTOR_POWER_MODE -#define M3_POWER_LEVEL 0.4 +#define M5_MOTOR_MAP AXIS_Y +#define M5_STEP_ANGLE 1.8 +#define M5_TRAVEL_PER_REV 40.64 +#define M5_MICROSTEPS 32 +#define M5_POLARITY 0 +#define M5_POWER_MODE MOTOR_POWER_MODE +#define M5_POWER_LEVEL 0.4 #define M2_MOTOR_MAP AXIS_Z #define M2_STEP_ANGLE 1.8 @@ -129,13 +129,13 @@ #define M4_POWER_LEVEL 0.4 // 96 steps/mm at 1/16 microstepping = 33.3333 mm/rev -#define M5_MOTOR_MAP AXIS_B -#define M5_STEP_ANGLE 1.8 -#define M5_TRAVEL_PER_REV 360 // degrees moved per motor rev -#define M5_MICROSTEPS 32 -#define M5_POLARITY 0 -#define M5_POWER_MODE MOTOR_POWER_MODE -#define M5_POWER_LEVEL 0.35 +#define M3_MOTOR_MAP AXIS_B +#define M3_STEP_ANGLE 1.8 +#define M3_TRAVEL_PER_REV 360 // degrees moved per motor rev +#define M3_MICROSTEPS 32 +#define M3_POLARITY 0 +#define M3_POWER_MODE MOTOR_POWER_MODE +#define M3_POWER_LEVEL 0.35 // *** axis settings ********************************************************************************** diff --git a/g2core/settings/settings_Printrbot_Plus.h b/g2core/settings/settings_Printrbot_Plus.h index 4ca7db27..4460a922 100644 --- a/g2core/settings/settings_Printrbot_Plus.h +++ b/g2core/settings/settings_Printrbot_Plus.h @@ -57,6 +57,7 @@ // Communications and reporting settings +#define MARLIN_COMPAT_ENABLED true // enable marlin compatibility mode #define COMM_MODE JSON_MODE // one of: TEXT_MODE, JSON_MODE #define XIO_ENABLE_FLOW_CONTROL FLOW_CONTROL_RTS // FLOW_CONTROL_OFF, FLOW_CONTROL_RTS diff --git a/g2core/settings/settings_default.h b/g2core/settings/settings_default.h index 37ad7848..19be85db 100644 --- a/g2core/settings/settings_default.h +++ b/g2core/settings/settings_default.h @@ -171,6 +171,11 @@ //#define STATUS_REPORT_DEFAULTS "line","vel","mpox","mpoy","mpoz","mpoa","coor","ofsa","ofsx","ofsy","ofsz","dist","unit","stat","homz","homy","homx","momo" #endif + +#ifndef MARLIN_COMPAT_ENABLED +#define MARLIN_COMPAT_ENABLED false // boolean, either true or false +#endif + // *** Gcode Startup Defaults *** // #ifndef GCODE_DEFAULT_UNITS