Another pass at Marlin Compatibility mode. Functional enough to test.

This commit is contained in:
Rob Giseburt
2017-01-20 14:36:21 -06:00
parent c1b2a91115
commit 3556a2cbf3
16 changed files with 526 additions and 147 deletions
+31 -2
View File
@@ -594,7 +594,10 @@ static float _calc_ABC(const uint8_t axis, const float target[])
if ((cm.a[axis].axis_mode == AXIS_STANDARD) || (cm.a[axis].axis_mode == AXIS_INHIBITED)) {
return(target[axis]); // no mm conversion - it's in degrees
}
return(_to_millimeters(target[axis]) * 360 / (2 * M_PI * cm.a[axis].radius));
// radius mode
return (_to_millimeters(target[axis]) * 360.0 / (2.0 * M_PI * cm.a[axis].radius));
}
void cm_set_model_target(const float target[], const bool flags[])
@@ -624,9 +627,27 @@ void cm_set_model_target(const float target[], const bool flags[])
} else {
tmp = _calc_ABC(axis, target);
}
#if MARLIN_COMPAT_ENABLED == true
// If we are in absolute mode (generally), but the extruder is relative,
// then we adjust the extruder to a relative position
if (cm.gmx.marlin_flavor && (cm.a[axis].axis_mode == AXIS_RADIUS)) {
if (cm.gmx.extruder_mode == EXTRUDER_MOVES_ABSOLUTE) {
cm.gm.target[axis] = tmp + cm_get_active_coord_offset(axis);
}
else if (cm.gmx.extruder_mode == EXTRUDER_MOVES_RELATIVE) {
cm.gm.target[axis] += tmp;
}
// TODO
// else {
// cm.gm.target[axis] += tmp * cm.gmx.volume_to_filament_length[axis-3];
// }
}
else
#endif // MARLIN_COMPAT_ENABLED
if (cm.gm.distance_mode == ABSOLUTE_DISTANCE_MODE) {
cm.gm.target[axis] = tmp + cm_get_active_coord_offset(axis); // sacidu93's fix to Issue #22
} else {
}
else {
cm.gm.target[axis] += tmp;
}
}
@@ -2024,6 +2045,14 @@ stat_t cm_json_command(char *json_string)
return mp_json_command(json_string);
}
/*
* cm_json_command_immediate() - M100.1
*/
stat_t cm_json_command_immediate(char *json_string)
{
return mp_json_command_immediate(json_string);
}
/*
* cm_json_wait() - M102
*/
+21 -3
View File
@@ -180,8 +180,16 @@ typedef enum { // these are in order to optimized CASE
NEXT_ACTION_JSON_WAIT, // M101
#if MARLIN_COMPAT_ENABLED == true
NEXT_ACTION_MARLIN_SET_EXTRUDER_TEMP, // 104, 109
NEXT_ACTION_MARLIN_SET_BED_TEMP, // 140, 190
NEXT_ACTION_MARLIN_PRINT_TEMPERATURES, // M105
NEXT_ACTION_MARLIN_PRINT_POSITION, // M114
NEXT_ACTION_MARLIN_SET_EXTRUDER_TEMP, // M104, M109
NEXT_ACTION_MARLIN_SET_BED_TEMP, // M140, M190
NEXT_ACTION_MARLIN_CANCEL_WAIT_TEMP, // M108
NEXT_ACTION_MARLIN_TRAM_BED, // G29
NEXT_ACTION_MARLIN_SET_FAN_SPEED, // M106
NEXT_ACTION_MARLIN_STOP_FAN, // M107
NEXT_ACTION_MARLIN_DISABLE_MOTORS, // M84
NEXT_ACTION_MARLIN_DISPLAY_ON_SCREEN, // M117
#endif
} cmNextAction;
@@ -384,6 +392,14 @@ typedef struct GCodeState { // Gcode model state - used by model, pl
};
} GCodeState_t;
#if MARLIN_COMPAT_ENABLED == true
enum cmExtruderMode {
EXTRUDER_MOVES_ABSOLUTE = 0, // M82
EXTRUDER_MOVES_RELATIVE, // M83
EXTRUDER_MOVES_VOLUMETRIC // Ultimaker2Marlin
};
#endif // MARLIN_COMPAT_ENABLED
typedef struct GCodeStateExtended { // Gcode dynamic state extensions - used by model and arcs
uint16_t magic_start; // magic number to test memory integrity
uint8_t next_action; // handles G modal group 1 moves & non-modals
@@ -409,7 +425,8 @@ typedef struct GCodeStateExtended { // Gcode dynamic state extensions - used
#if MARLIN_COMPAT_ENABLED == true
bool marlin_flavor;
#endif
cmExtruderMode extruder_mode; // Mode of the extruder - changes how "E" is interpreted
#endif // MARLIN_COMPAT_ENABLED
uint16_t magic_end;
@@ -679,6 +696,7 @@ void cm_optional_program_stop(void); // M1
void cm_program_end(void); // M2
stat_t cm_json_command(char *json_string); // M100
stat_t cm_json_command_immediate(char *json_string); // M100.1
stat_t cm_json_wait(char *json_string); // M102
/*--- Cycles ---*/
+16
View File
@@ -328,6 +328,18 @@ static stat_t _controller_state()
return (STAT_OK);
}
/*
* _reset_comms_mode() - reset the communications mode (and other effected settings) after connection or disconnection
*/
void _reset_comms_mode() {
// reset the communications mode
cs.comm_mode = COMM_MODE;
js.json_mode = (COMM_MODE < AUTO_MODE) ? COMM_MODE : JSON_MODE;
sr.status_report_verbosity = STATUS_REPORT_VERBOSITY;
qr.queue_report_verbosity = QUEUE_REPORT_VERBOSITY;
}
/*
* controller_set_connected(bool) - hook for xio to tell the controller that we
* have/don't have a connection.
@@ -335,6 +347,8 @@ static stat_t _controller_state()
void controller_set_connected(bool is_connected) {
if (is_connected) {
_reset_comms_mode();
cs.controller_state = CONTROLLER_CONNECTED; // we JUST connected
} else { // we just disconnected from the last device, we'll expect a banner again
cs.controller_state = CONTROLLER_NOT_CONNECTED;
@@ -353,6 +367,8 @@ void controller_set_muted(bool is_muted) {
const bool only_to_muted = true;
xio_writeline("{\"muted\":true}\n", only_to_muted);
} else {
_reset_comms_mode();
// one channel just got unmuted, announce it (except to the muted)
xio_writeline("{\"muted\":false}\n");
}
+6 -6
View File
@@ -206,7 +206,7 @@ char *get_status_message(stat_t status);
#define STAT_INPUT_FROM_MUTED_CHANNEL_ERROR 117 // input from a muted channel was ignored
#define STAT_CHECKSUM_MATCH_FAILED 118 // the provided checksum didn't match
#define STAT_LINE_NUMBER_OUT_OF_SEQUENCE 119
#define STAT_LINE_NUMBER_OUT_OF_SEQUENCE 119 // the provided line number was out of sequence
#define STAT_ERROR_120 120
#define STAT_ERROR_121 121
@@ -315,7 +315,7 @@ char *get_status_message(stat_t status);
#define STAT_TEMPERATURE_CONTROL_ERROR 209 // temperature controls err'd out
#define STAT_ERROR_210 210
#define STAT_G29_NOT_CONFIGURED 210
#define STAT_ERROR_211 211
#define STAT_ERROR_212 212
#define STAT_ERROR_213 213
@@ -501,9 +501,9 @@ static const char stat_113[] = "JSON string too long";
static const char stat_114[] = "JSON txt fields cannot be nested";
static const char stat_115[] = "JSON maximum nesting depth exceeded";
static const char stat_116[] = "JSON value does not agree with variable type";
static const char stat_117[] = "117";
static const char stat_118[] = "118";
static const char stat_119[] = "119";
static const char stat_117[] = "Input from a muted channel was ignored";
static const char stat_118[] = "The provided checksum didn't match";
static const char stat_119[] = "The provided line number was out of sequence";
static const char stat_120[] = "120";
static const char stat_121[] = "121";
@@ -606,7 +606,7 @@ static const char stat_207[] = "Kill job";
static const char stat_208[] = "No GPIO for this value";
static const char stat_209[] = "209";
static const char stat_210[] = "210";
static const char stat_210[] = "Marlin G29 command was not configured at compile-time";
static const char stat_211[] = "211";
static const char stat_212[] = "212";
static const char stat_213[] = "213";
+167 -38
View File
@@ -74,10 +74,9 @@ typedef struct GCodeInputValue { // Gcode inputs - meaning depends on context
bool sso_control; // M51 spindle speed override control
#if MARLIN_COMPAT_ENABLED == true
bool marlin_temp_requested; // M105 temperature report request (Marlin-only)
bool marlin_position_requested; // M114 position report request (Marlin-only)
float E_word; // E - "extruder" - may be interpreted any number of ways
bool marlin_wait_for_temp; // M140 or M190 - wait for temperature (Marlin-only)
bool marlin_relative_extruder_mode; // M82, M83 (Marlin-only)
#endif
} GCodeValue_t;
@@ -120,8 +119,11 @@ typedef struct GCodeFlags { // Gcode input flags
bool sso_control;
#if MARLIN_COMPAT_ENABLED == true
bool marlin_temp_requested;
bool marlin_position_requested;
bool E_word;
bool marlin_wait_for_temp; // M140 or M190 - wait for temperature (Marlin-only)
bool marlin_relative_extruder_mode;
#endif
} GCodeFlag_t;
@@ -488,18 +490,31 @@ stat_t _get_next_gcode_word(char **pstr, char *letter, float *value)
*letter = **pstr;
(*pstr)++;
// X-axis-becomes-a-hexadecimal-number get-value case, e.g. G0X100 --> G255
if ((**pstr == '0') && (*(*pstr+1) == 'X')) {
*value = 0;
(*pstr)++;
return (STAT_OK); // pointer points to X
}
// // X-axis-becomes-a-hexadecimal-number get-value case, e.g. G0X100 --> G255
// if ((**pstr == '0') && (*(*pstr+1) == 'X')) {
// *value = 0;
// (*pstr)++;
// return (STAT_OK); // pointer points to X
// }
//
// // get-value general case
// char *end = *pstr;
// *value = strtof(*pstr, &end);
// get-value general case
char *end;
*value = strtof(*pstr, &end);
char *end = *pstr;
*value = c_atof(end);
if(end == *pstr) {
#if MARLIN_COMPAT_ENABLED == true
if (cm.gmx.marlin_flavor) {
*value = 0;
} else {
return(STAT_BAD_NUMBER_FORMAT);
}
#else
return(STAT_BAD_NUMBER_FORMAT);
#endif
} // more robust test then checking for value=0;
*pstr = end;
return (STAT_OK); // pointer points to next character after the word
@@ -585,7 +600,14 @@ stat_t _parse_gcode_block(char *buf, char *active_comment)
case 21: SET_MODAL (MODAL_GROUP_G6, units_mode, MILLIMETERS);
case 28: {
switch (_point(value)) {
case 0: SET_MODAL (MODAL_GROUP_G0, next_action, NEXT_ACTION_GOTO_G28_POSITION);
case 0: {
#if MARLIN_COMPAT_ENABLED == true
if (cm.gmx.marlin_flavor) {
SET_NON_MODAL (next_action, NEXT_ACTION_SEARCH_HOME);
}
#endif
SET_MODAL (MODAL_GROUP_G0, next_action, NEXT_ACTION_GOTO_G28_POSITION);
}
case 1: SET_MODAL (MODAL_GROUP_G0, next_action, NEXT_ACTION_SET_G28_POSITION);
case 2: SET_NON_MODAL (next_action, NEXT_ACTION_SEARCH_HOME);
case 3: SET_NON_MODAL (next_action, NEXT_ACTION_SET_ABSOLUTE_ORIGIN);
@@ -668,6 +690,10 @@ stat_t _parse_gcode_block(char *buf, char *active_comment)
case 93: SET_MODAL (MODAL_GROUP_G5, feed_rate_mode, INVERSE_TIME_MODE);
case 94: SET_MODAL (MODAL_GROUP_G5, feed_rate_mode, UNITS_PER_MINUTE_MODE);
// case 95: SET_MODAL (MODAL_GROUP_G5, feed_rate_mode, UNITS_PER_REVOLUTION_MODE);
#if MARLIN_COMPAT_ENABLED == true
case 29: SET_NON_MODAL (next_action, NEXT_ACTION_MARLIN_TRAM_BED);
#endif // MARLIN_COMPAT_ENABLED
default: status = STAT_GCODE_COMMAND_UNSUPPORTED;
}
break;
@@ -695,19 +721,36 @@ stat_t _parse_gcode_block(char *buf, char *active_comment)
}
break;
case 51: SET_MODAL (MODAL_GROUP_M9, sso_control, true);
case 100: SET_NON_MODAL (next_action, NEXT_ACTION_JSON_COMMAND_SYNC);
case 100:
switch (_point(value)) {
case 0: SET_NON_MODAL (next_action, NEXT_ACTION_JSON_COMMAND_SYNC);
case 1: SET_NON_MODAL (next_action, NEXT_ACTION_JSON_COMMAND_ASYNC);
default: status = STAT_GCODE_COMMAND_UNSUPPORTED;
}
break;
case 101: SET_NON_MODAL (next_action, NEXT_ACTION_JSON_WAIT);
#if MARLIN_COMPAT_ENABLED == true
#warning MARLIN_COMPAT_ENABLED
case 105: SET_NON_MODAL (marlin_temp_requested, true);
case 114: SET_NON_MODAL (marlin_position_requested, true);
case 105: SET_NON_MODAL (next_action, NEXT_ACTION_MARLIN_PRINT_TEMPERATURES);
case 114: SET_NON_MODAL (next_action, NEXT_ACTION_MARLIN_PRINT_POSITION);
case 140: gv.marlin_wait_for_temp = true; // NO break!
case 140: gf.marlin_wait_for_temp = true; // NO break!
case 104: SET_NON_MODAL (next_action, NEXT_ACTION_MARLIN_SET_EXTRUDER_TEMP);
case 190: gv.marlin_wait_for_temp = true; // NO break!
case 190: gf.marlin_wait_for_temp = true; // NO break!
case 109: SET_NON_MODAL (next_action, NEXT_ACTION_MARLIN_SET_BED_TEMP);
case 108: SET_NON_MODAL (next_action, NEXT_ACTION_MARLIN_CANCEL_WAIT_TEMP);
case 82: SET_NON_MODAL (marlin_relative_extruder_mode, false);
case 83: SET_NON_MODAL (marlin_relative_extruder_mode, true);
case 106: SET_NON_MODAL (next_action, NEXT_ACTION_MARLIN_SET_FAN_SPEED);
case 107: SET_NON_MODAL (next_action, NEXT_ACTION_MARLIN_STOP_FAN);
case 117: return STAT_OK; //SET_NON_MODAL (next_action, NEXT_ACTION_MARLIN_DISPLAY_ON_SCREEN);
case 84: SET_NON_MODAL (next_action, NEXT_ACTION_MARLIN_DISABLE_MOTORS);
#endif // MARLIN_COMPAT_ENABLED
default: status = STAT_MCODE_COMMAND_UNSUPPORTED;
@@ -734,6 +777,9 @@ stat_t _parse_gcode_block(char *buf, char *active_comment)
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
#if MARLIN_COMPAT_ENABLED == true
case 'E': SET_NON_MODAL (E_word, value); // extruder value
#endif // MARLIN_COMPAT_ENABLED
default: status = STAT_GCODE_COMMAND_UNSUPPORTED;
}
if(status != STAT_OK) break;
@@ -792,33 +838,116 @@ stat_t _execute_gcode_block(char *active_comment)
EXEC_FUNC(cm_set_feed_rate, F_word); // F
#if MARLIN_COMPAT_ENABLED == true
// adjust T real quick
if (cm.gmx.marlin_flavor && gf.tool_select) {
cm_select_tool(gv.tool_select); // We need to go ahead and apply to tool select
}
// Handle Marlin specifics
// must be before we deal with S_word and P_word, since it MIGHT use those
if (gf.marlin_temp_requested) { // M105
js.json_mode = MARLIN_COMM_MODE; // we use M105 to know when to switch
ritorno(marlin_request_temperature_report());
}
if (gf.marlin_position_requested) { // M114
js.json_mode = MARLIN_COMM_MODE; // we use M105 to know when to switch
ritorno(marlin_request_position_report());
// Deal with E
EXEC_FUNC(cm_marlin_set_extruder_mode, marlin_relative_extruder_mode); // M82, M83
if (gf.E_word) {
cm.gmx.marlin_flavor = true; // E should ONLY be seen in marlin flavor
// Ennn T0 -> Annn
if (cm.gm.tool_select == 0) {
gf.target[AXIS_A] = true;
gv.target[AXIS_A] = gv.E_word;
}
// Ennn T1 -> Bnnn
else if (cm.gm.tool_select == 1) {
gf.target[AXIS_B] = true;
gv.target[AXIS_B] = gv.E_word;
}
else {
return STAT_INPUT_VALUE_RANGE_ERROR;
}
}
switch (gv.next_action) {
case NEXT_ACTION_MARLIN_SET_EXTRUDER_TEMP: { // M104 or M140
float temp = 0;
if (gf.S_word) { temp = gv.S_word; }
if (gf.P_word) { temp = gv.P_word; } // we treat them the same, for now
status = marlin_set_temperature(cm.gm.tool_select, temp, gv.marlin_wait_for_temp);
return status;
case NEXT_ACTION_MARLIN_PRINT_TEMPERATURES: { // M105
js.json_mode = MARLIN_COMM_MODE; // we use M105 to know when to switch
ritorno(marlin_request_temperature_report());
break;
}
case NEXT_ACTION_MARLIN_PRINT_POSITION: { // M114
js.json_mode = MARLIN_COMM_MODE; // we use M105 to know when to switch
ritorno(marlin_request_position_report());
break;
}
case NEXT_ACTION_MARLIN_SET_EXTRUDER_TEMP: // M104 or M140
case NEXT_ACTION_MARLIN_SET_BED_TEMP: { // M109 or M190
cm.gmx.marlin_flavor = true; // these gcodes are ONLY in marlin flavor
float temp = 0;
if (gf.S_word) { temp = gv.S_word; }
if (gf.P_word) { temp = gv.P_word; } // we treat them the same, for now
// Note: tool is zero-based, so to gt he3 (the bed) we pass tool as 2
status = marlin_set_temperature(2, temp, gv.marlin_wait_for_temp);
uint8_t tool = (NEXT_ACTION_MARLIN_SET_EXTRUDER_TEMP == gv.next_action) ? cm.gm.tool_select : 2; // heat bed is 2 here, normally 3
ritorno(marlin_set_temperature(tool, temp, gf.marlin_wait_for_temp));
gf.P_word = false;
gf.S_word = false;
break;
}
case NEXT_ACTION_MARLIN_CANCEL_WAIT_TEMP: { // M108
js.json_mode = MARLIN_COMM_MODE; // we use M105 to know when to switch
cm_request_feedhold();
cm_request_queue_flush();
break;
}
case NEXT_ACTION_MARLIN_TRAM_BED: { // G29
cm.gmx.marlin_flavor = true; // these gcodes are ONLY in marlin flavor
ritorno(marlin_start_tramming_bed());
break;
}
case NEXT_ACTION_MARLIN_SET_FAN_SPEED: { // M106
cm.gmx.marlin_flavor = true; // these gcodes are ONLY in marlin flavor
ritorno(marlin_set_fan_speed(gf.P_word?gv.P_word:0, gf.S_word?gv.S_word:0));
gf.P_word = false;
gf.S_word = false;
break;
}
case NEXT_ACTION_MARLIN_STOP_FAN: { // M107
cm.gmx.marlin_flavor = true; // these gcodes are ONLY in marlin flavor
ritorno(marlin_set_fan_speed(gf.P_word?gv.P_word:0, 0));
gf.P_word = false;
gf.S_word = false;
break;
}
// adjust G28 (already adjusted to G28.2)
// with no X, Y, or Z, we assume all three
case NEXT_ACTION_SEARCH_HOME: { // G28 (g2core G28.2)
if (!gf.target[AXIS_X] && !gf.target[AXIS_Y] && !gf.target[AXIS_Z]) {
gv.target[AXIS_X]=0.0; gf.target[AXIS_X]=true;
gv.target[AXIS_Y]=0.0; gf.target[AXIS_Y]=true;
gv.target[AXIS_Z]=0.0; gf.target[AXIS_Z]=true;
}
break;
}
case NEXT_ACTION_MARLIN_DISABLE_MOTORS: { // M84
ritorno(marlin_disable_motors());
break;
}
case NEXT_ACTION_MARLIN_DISPLAY_ON_SCREEN: { // M184
// ignore for now
return status;
}
case NEXT_ACTION_DEFAULT: {
if (cm.gmx.marlin_flavor) {
// adjust G0 to almost always be the same as G1
if (gf.motion_mode)
{
if (gf.E_word &&
(!gf.target[AXIS_X] && !gf.target[AXIS_Y] && !gf.target[AXIS_Z])
)
{
gv.motion_mode = MOTION_MODE_STRAIGHT_TRAVERSE; // G0
} else {
gv.motion_mode = MOTION_MODE_STRAIGHT_FEED; // G1
}
}
}
break;
}
}
@@ -900,9 +1029,9 @@ stat_t _execute_gcode_block(char *active_comment)
case NEXT_ACTION_SUSPEND_ORIGIN_OFFSETS: { status = cm_suspend_origin_offsets(); break;} // G92.2
case NEXT_ACTION_RESUME_ORIGIN_OFFSETS: { status = cm_resume_origin_offsets(); break;} // G92.3
case NEXT_ACTION_JSON_COMMAND_SYNC: { status = cm_json_command(active_comment); break;} // M100
case NEXT_ACTION_JSON_COMMAND_SYNC: { status = cm_json_command(active_comment); break;} // M100.0
case NEXT_ACTION_JSON_COMMAND_ASYNC: { status = cm_json_command_immediate(active_comment); break;} // M100.1
case NEXT_ACTION_JSON_WAIT: { status = cm_json_wait(active_comment); break;} // M101
// case NEXT_ACTION_JSON_COMMAND_IMMEDIATE: { status = mp_json_command_immediate(active_comment); break;} // M102
case NEXT_ACTION_DEFAULT: {
cm_set_absolute_override(MODEL, gv.absolute_override); // apply absolute override
+4 -3
View File
@@ -85,7 +85,7 @@ static stat_t _get_nv_pair(nvObj_t *nv, char **pstr, int8_t *depth);
* _json_parser_execute() executes sets and gets in an application agnostic way. It should work for other apps than g2core
*/
void json_parser(char *str)
stat_t json_parser(char *str, bool suppress_response) // suppress_response defaults to false, see decalaration in .h
{
nvObj_t *nv = nv_reset_nv_list(); // get a fresh nvObj list
stat_t status = _json_parser_kernal(nv, str);
@@ -93,11 +93,12 @@ void json_parser(char *str)
nv = nv_body;
status = _json_parser_execute(nv);
}
if (status == STAT_COMPLETE) { // skip the print if returning from something that already did it.
return;
if (suppress_response || (status == STAT_COMPLETE)) { // skip the print if returning from something that already did it.
return status;
}
nv_print_list(status, TEXT_NO_PRINT, JSON_RESPONSE_FORMAT);
sr_request_status_report(SR_REQUEST_TIMED); // generate incremental status report to show any changes
return STAT_OK;
}
// This is almost the same as json_parser, except it doesn't *always* execute the parsed out list, and it never returns a reponse
+1 -1
View File
@@ -82,7 +82,7 @@ extern jsSingleton_t js;
/**** Function Prototypes ****/
void json_parser(char *str);
stat_t json_parser(char *str, bool suppress_response = false);
void json_parse_for_exec(char *str, bool execute);
uint16_t json_serialize(nvObj_t *nv, char *out_buf, uint16_t size);
void json_print_object(nvObj_t *nv);
+193 -86
View File
@@ -65,7 +65,7 @@ enum class MarlinSetTempState {
MarlinSetTempState set_temp_state; // record the state for the temperature-control pseudo-cycle
// These next parameters for the next temperature-control pseudo-cycle are only needed until the calls are queued.
float next_temperature; // as it says
uint8_t next_temperature_tool; // this is a g2core (1-based) tool
uint8_t next_temperature_tool; // 0-based, with 2 being the heat-bed
// Information about if we are to be dumping periodic temperature updates
bool temperature_updates_requested = false;
@@ -74,10 +74,101 @@ Motate::Timeout temperature_update_timeout;
// local helper functions and macros
/*
* marlin_verify_checksum() - check to see if we have a line number (cheaply) and a valid checksum
* _report_temperatures() - convenience function to get a value via the JSON NV system
*/
nvObj_t *_get_spcific_nv(const char *key) {
nvObj_t *nv = nv_reset_nv_list(); // returns first object in the body
strncpy(nv->token, key, TOKEN_LEN);
// validate and post-process the token
if ((nv->index = nv_get_index((const char *)"", nv->token)) == NO_MATCH) { // get index or fail it
// since we JUST provided the keys, this should never happen
return nullptr;
}
strcpy(nv->group, cfgArray[nv->index].group); // capture the group string if there is one
nv_get(nv);
return nv;
}
/*
* _report_temperatures() - convenience function called from marlin_response() and marlin_callback()
*/
void _report_temperatures(char *(&str)) {
// Tool 0 is extruder 1
uint8_t tool = cm.gm.tool_select;
nvObj_t *nv = nullptr;
if (tool == 0) {
nv = _get_spcific_nv("he1t");
} else if (tool == 1) {
nv = _get_spcific_nv("he2t");
} else {
return; // we have no way of reporting errors here, ATM
}
if (!nv) { return; }
str += sprintf(str, " T:%.2f", (float)nv->value);
if (tool == 0) {
nv = _get_spcific_nv("he1st");
} else if (tool == 1) {
nv = _get_spcific_nv("he2st");
} else {
return; // we have no way of reporting errors here, ATM
}
if (!nv) { return; }
str += sprintf(str, " /%.2f", (float)nv->value);
nv = _get_spcific_nv("he3t");
if (!nv) { return; }
str += sprintf(str, " B:%.2f", (float)nv->value);
nv = _get_spcific_nv("he3st");
if (!nv) { return; }
str += sprintf(str, " /%.2f", (float)nv->value);
if (tool == 0) {
nv = _get_spcific_nv("he1op");
} else if (tool == 1) {
nv = _get_spcific_nv("he2op");
} if (!nv) { return; }
str += sprintf(str, " @:%.0f", (float)nv->value * 255.0);
nv = _get_spcific_nv("he3op");
if (!nv) { return; }
str += sprintf(str, " B@:%.0f", (float)nv->value * 255.0);
}
/*
* _report_position() - convenience function called from marlin_response()
*/
void _report_position(char *(&str)) {
str += sprintf(str, " X:%.2f", cm_get_work_position(ACTIVE_MODEL, 0));
str += sprintf(str, " Y:%.2f", cm_get_work_position(ACTIVE_MODEL, 1));
str += sprintf(str, " Z:%.2f", cm_get_work_position(ACTIVE_MODEL, 2));
uint8_t tool = cm.gm.tool_select;
if (tool == 0) {
str += sprintf(str, " E:%.2f", cm_get_work_position(ACTIVE_MODEL, 3));
} else if (tool == 1) {
str += sprintf(str, " E:%.2f", cm_get_work_position(ACTIVE_MODEL, 4));
}
}
/***********************************************************************************
* CONFIGURATION AND INTERFACE FUNCTIONS
* Functions to get and set variables from the cfgArray table
***********************************************************************************/
/*
* marlin_verify_checksum() - check to see if we have a line number (cheaply) and a valid checksum
* called from gcode_parser
*/
stat_t marlin_verify_checksum(char *str)
{
if (*str != 'N') { return STAT_OK; } // we only check if we have a line number
@@ -91,12 +182,18 @@ stat_t marlin_verify_checksum(char *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;
if (c == '*') {
*(str-1) = 0; // null terminate, the parser won't like this * here!
if (strtol(str, NULL, 10) != checksum) {
return STAT_CHECKSUM_MATCH_FAILED;
}
}
return STAT_OK;
}
/*
* _marlin_fake_stk500_response() - convenience function for formang responses from marlin_handle_fake_stk500()
*/
void _marlin_fake_stk500_response(char *resp, uint16_t length)
{
char *str = resp;
@@ -151,15 +248,13 @@ bool marlin_handle_fake_stk500(char *str)
}
/***********************************************************************************
* CONFIGURATION AND INTERFACE FUNCTIONS
* Functions to get and set variables from the cfgArray table
***********************************************************************************/
/*
* marlin_request_temperature_report() - called from the gcode parser for M105
*/
stat_t marlin_request_temperature_report() // M105
{
uint8_t tool = cm.gm.tool_select;
if (tool > 1) {
if ((tool < 0) || (tool > 1)) {
return STAT_INPUT_VALUE_RANGE_ERROR;
}
@@ -167,82 +262,19 @@ stat_t marlin_request_temperature_report() // M105
return STAT_OK;
}
/*
* marlin_request_temperature_report() - called from the gcode parser for M114
*/
stat_t marlin_request_position_report() // M114
{
position_requested = true;
return STAT_OK;
}
nvObj_t *_get_spcific_nv(const char *key) {
nvObj_t *nv = nv_reset_nv_list(); // returns first object in the body
strncpy(nv->token, key, TOKEN_LEN);
// validate and post-process the token
if ((nv->index = nv_get_index((const char *)"", nv->token)) == NO_MATCH) { // get index or fail it
// since we JUST provided the keys, this should never happen
return nullptr;
}
strcpy(nv->group, cfgArray[nv->index].group); // capture the group string if there is one
nv_get(nv);
return nv;
}
void _report_temperatures(char *(&str)) {
// Tool 0 is extruder 1
uint8_t tool = cm.gm.tool_select;
nvObj_t *nv = nullptr;
if (tool == 0) {
nv = _get_spcific_nv("he1t");
} else if (tool == 1) {
nv = _get_spcific_nv("he2t");
} else {
return; // we have no way of reporting errors here, ATM
}
if (!nv) { return; }
str += sprintf(str, " T:%.2f", (float)nv->value);
if (tool == 0) {
nv = _get_spcific_nv("he1st");
} else if (tool == 1) {
nv = _get_spcific_nv("he2st");
} else {
return; // we have no way of reporting errors here, ATM
}
if (!nv) { return; }
str += sprintf(str, " /%.2f", (float)nv->value);
nv = _get_spcific_nv("he3t");
if (!nv) { return; }
str += sprintf(str, " B:%.2f", (float)nv->value);
nv = _get_spcific_nv("he3st");
if (!nv) { return; }
str += sprintf(str, " /%.2f", (float)nv->value);
}
void _report_position(char *(&str)) {
//
// Tool 0 is extruder 1
uint8_t tool = cm.gm.tool_select;
str += sprintf(str, " X:%.2f", cm_get_work_position(ACTIVE_MODEL, 0));
str += sprintf(str, " Y:%.2f", cm_get_work_position(ACTIVE_MODEL, 1));
str += sprintf(str, " Z:%.2f", cm_get_work_position(ACTIVE_MODEL, 2));
if (tool == 0) {
str += sprintf(str, " E:%.2f", cm_get_work_position(ACTIVE_MODEL, 3));
} else if (tool == 1) {
str += sprintf(str, " E:%.2f", cm_get_work_position(ACTIVE_MODEL, 4));
}
}
/*
* marlin_response() - marlin mirror if text_response()
* marlin_response() - marlin mirror of text_response(), called from _dispatch_kernel() in controller.cpp
*/
void marlin_response(const stat_t status, char *buf)
{
@@ -283,6 +315,7 @@ void marlin_response(const stat_t status, char *buf)
xio_writeline(buffer);
}
/*
* _marlin_start_temperature_updates()/_marlin_end_temperature_updates() -
* calls from commands in the buffer to manage temperature_updates_requested
@@ -291,11 +324,11 @@ void _marlin_start_temperature_updates(float* vect, bool* flag) {
temperature_updates_requested = true;
temperature_update_timeout.set(1); // immediately
}
void _marlin_end_temperature_updates(float* vect, bool* flag) {
temperature_updates_requested = false;
}
/*
* _queue_next_temperature_comands() - returns true if it finished
*/
@@ -312,7 +345,7 @@ bool _queue_next_temperature_commands()
if ((MarlinSetTempState::SettingTemperature == set_temp_state) ||
(MarlinSetTempState::SettingTemperatureNoWait == set_temp_state))
{
str += sprintf(str, "{he%dst:%.2f}", next_temperature_tool, next_temperature);
str += sprintf(str, "{he%dst:%.2f}", next_temperature_tool+1, next_temperature);
cm_json_command(buffer);
if (MarlinSetTempState::SettingTemperatureNoWait == set_temp_state) {
@@ -337,7 +370,7 @@ bool _queue_next_temperature_commands()
if (MarlinSetTempState::StartingWait == set_temp_state) {
str = buffer;
str += sprintf(str, "{he%dat:t}", next_temperature_tool);
str += sprintf(str, "{he%dat:t}", next_temperature_tool+1);
cm_json_wait(buffer);
set_temp_state = MarlinSetTempState::StoppingUpdates;
@@ -356,12 +389,13 @@ bool _queue_next_temperature_commands()
return true;
}
/*
* marlin_callback() - called by controller dispatcher - return STAT_EAGAIN if it failed
*/
stat_t marlin_callback()
{
if (temperature_updates_requested && (temperature_update_timeout.isPast())) {
if ((js.json_mode == MARLIN_COMM_MODE) && temperature_updates_requested && (temperature_update_timeout.isPast())) {
char buffer[128];
char *str = buffer;
@@ -383,22 +417,95 @@ stat_t marlin_callback()
}
/*
* marlin_set_temperature() - called from the gcode parser for M104,M140,M109,M190
*/
stat_t marlin_set_temperature(uint8_t tool, float temperature, bool wait) {
if (MarlinSetTempState::Idle != set_temp_state) {
return (STAT_BUFFER_FULL_FATAL); // this shouldn't happen
return (STAT_BUFFER_FULL_FATAL); // we shouldn't be here
}
if ((tool < 0) || (tool > 3)) {
if ((tool < 0) || (tool > 2)) {
return STAT_INPUT_VALUE_RANGE_ERROR;
}
set_temp_state = wait ? MarlinSetTempState::SettingTemperature : MarlinSetTempState::SettingTemperatureNoWait;
next_temperature = temperature;
// Note the conversion from a "marlin" tool (zero-base) to a g2core tool (1-based)
next_temperature_tool = tool + 1;
next_temperature_tool = tool;
_queue_next_temperature_commands(); // we can ignore the return
return (STAT_OK);
}
#ifdef MARLIN_G29_SCRIPT
auto marlin_g29_file = make_xio_flash_file(MARLIN_G29_SCRIPT);
#endif
/*
* marlin_start_tramming_bed() - called from the gcode parser for G29
*/
stat_t marlin_start_tramming_bed() {
#ifndef MARLIN_G29_SCRIPT
return (STAT_G29_NOT_CONFIGURED);
#else
xio_send_file(marlin_g29_file);
return (STAT_OK);
#endif
}
/*
* cm_marlin_set_extruder_mode() - M82, M83 (affects MODEL only)
*
* EXTRUDER_MOVES_ABSOLUTE = 0, // M82
* EXTRUDER_MOVES_RELATIVE, // M83
* EXTRUDER_MOVES_VOLUMETRIC // Ultimaker2Marlin
*/
stat_t cm_marlin_set_extruder_mode(const uint8_t mode)
{
cm.gmx.extruder_mode = (cmExtruderMode)mode;
return (STAT_OK);
}
/*
* marlin_set_fan_speed() - M106, M107
*
*/
stat_t marlin_set_fan_speed(const uint8_t fan, float speed)
{
char buffer[128];
char *str = buffer;
if ((fan != 0) || (speed < 0.0) || (speed > 255.0)) {
return STAT_INPUT_VALUE_RANGE_ERROR;
}
// TODO: support other fans, or remapping output
str += sprintf(str, "{out4:%.2f}", (speed < 1.0) ? speed : (speed / 255.0));
cm_json_command(buffer);
return (STAT_OK);
}
/*
* marlin_disable_motors() - M84
*
*/
stat_t marlin_disable_motors()
{
char buffer[128];
char *str = buffer;
// TODO: support other parameters
strncpy(str, "{md:0}", 6);
cm_json_command(buffer);
return (STAT_OK);
}
#endif // MARLIN_COMPAT_ENABLED == true
+9
View File
@@ -28,15 +28,24 @@
* Global Scope Functions
*/
// gcode parsing and fack stk500v2
stat_t marlin_verify_checksum(char *str);
bool marlin_handle_fake_stk500(char *str);
// gcode handling
stat_t marlin_start_tramming_bed(); //G29
stat_t marlin_request_temperature_report(); // M105
stat_t marlin_request_position_report(); // M114
stat_t marlin_set_temperature(uint8_t tool, float temperature, bool wait); // M104, M109, M140, M190
// response handler (primarily just prints "ok")
void marlin_response(const stat_t status, char *buf);
// controller loop callback
stat_t marlin_callback();
stat_t cm_marlin_set_extruder_mode(const uint8_t mode); // M82, M82
stat_t marlin_set_fan_speed(const uint8_t fan, float speed); // M106, M107
stat_t marlin_disable_motors(); // M84
#endif // End of include guard: MARLIN_COMPAT_H_ONCE
+9 -1
View File
@@ -311,7 +311,7 @@ stat_t mp_runtime_command(mpBuf_t *bf)
/*************************************************************************
* mp_json_command() - queue a json command
* _exec_json_command() - execute json string
* _exec_json_command() - execute json string (from exec system)
*/
stat_t mp_json_command(char *json_string)
@@ -334,6 +334,14 @@ static void _exec_json_command(float *value, bool *flag)
jc.free_buffer();
}
/*************************************************************************
* mp_json_command_immediate() - execute a json command with response suppressed
*/
stat_t mp_json_command_immediate(char *json_string)
{
return json_parser(json_string);
}
/*************************************************************************
* mp_json_wait() - queue a json wait command
+1
View File
@@ -537,6 +537,7 @@ stat_t mp_runtime_command(mpBuf_t *bf);
stat_t mp_json_command(char *json_string);
stat_t mp_json_wait(char *json_string);
stat_t mp_json_command_immediate(char *json_string);
stat_t mp_dwell(const float seconds);
void mp_end_dwell(void);
+5 -2
View File
@@ -111,8 +111,11 @@ void rpt_print_loading_configs_message(void)
void rpt_print_system_ready_message(void)
{
#warning DEAL WITH STARTUP MESSAGE
//_startup_helper(STAT_OK, "SYSTEM READY");
#if MARLIN_COMPAT_ENABLED == true
#warning DEAL WITH STARTUP MESSAGE
#else
_startup_helper(STAT_OK, "SYSTEM READY");
#endif
if (cs.comm_mode == TEXT_MODE) { text_response(STAT_OK, (char *)"");}// prompt
}
@@ -87,6 +87,23 @@
#define GCODE_DEFAULT_PATH_CONTROL PATH_CONTINUOUS
#define GCODE_DEFAULT_DISTANCE_MODE ABSOLUTE_DISTANCE_MODE
#define MARLIN_G29_SCRIPT \
"(MSG Tramming started)\n" \
"M100 ({\"_leds\":3})\n" \
"G1 X0 Y145 Z6 F20000\n" \
"G38.2 Z-10 F200\n" \
"G1 Z5 F20000\n" \
"M100 ({\"_leds\":5})\n" \
"G1 X210 Y65 F20000\n" \
"G38.2 Z-10 F200\n" \
"G1 Z5 F20000\n" \
"M100 ({\"_leds\":6})\n" \
"G1 X0 Y10 F20000\n" \
"G38.2 Z-10 F200\n" \
"G1 Z5 F20000\n" \
"M100 ({\"_leds\":3})\n" \
"M100 ({\"tram\":1})" \
"(MSG Tramming completed)\n"
// *** motor settings ************************************************************************************
+4 -1
View File
@@ -365,7 +365,10 @@ struct PID {
if (_rise_time_timeout.isPast()) {
if (input < _rise_time_checkpoint) {
// FAILURE!!
cm_alarm(STAT_TEMPERATURE_CONTROL_ERROR, "Heater temperature failed to rise fast enough.");
char buffer[128];
char *str = buffer;
str += sprintf(str, "Heater temperature failed to rise fast enough. At: %f Set: %f", input, _set_point);
cm_alarm(STAT_TEMPERATURE_CONTROL_ERROR, buffer);
_set_point = 0;
_rise_time_timeout.clear();
return -1;
+16
View File
@@ -173,6 +173,22 @@ inline T avg(const T a,const T b) {return (a+b)/2; }
#define M_SQRT3 (1.73205080756888)
#endif
// Fraction part
constexpr float c_atof_frac_(char *&p_, float v_, float m_) {
return ((*p_ >= '0') && (*p_ <= '9')) ? (v_ = ((v_) + ((*p_) - '0') * m_), c_atof_frac_(++p_, v_, m_ / 10.0)) : v_;
}
// Integer part
template <typename int_type>
constexpr float c_atof_int_(char *&p_, int_type v_) {
return (*p_ == '.')
? (float)(v_) + c_atof_frac_(++p_, 0, 1.0 / 10.0)
: (((*p_ >= '0') && (*p_ <= '9')) ? ((v_ = ((*p_) - '0') + (v_ * 10)), c_atof_int_(++p_, v_)) : v_);
}
// Start portion
constexpr float c_atof(char *&p_) { return (*p_ == '-') ? (c_atof_int_(++p_, 0) * -1.0) : (c_atof_int_(p_, 0)); }
// It's assumed that the string buffer contains at lest count_ non-\0 chars
//constexpr int c_strreverse(char * const t, const int count_, char hold = 0) {
+26 -4
View File
@@ -640,15 +640,17 @@ struct LineRXBuffer : RXBuffer<_size, owner_type, char> {
char c = _data[_scan_offset];
if (c == 0) {
#if MARLIN_COMPAT_ENABLED == true
// it's possible something will try to talk stk500v2 to us.
// See https://github.com/synthetos/g2/wiki/Marlin-Compatibility#stk500v2
if ((_stk_parser_state == STK500V2_State::Done) && (c == 0)) {
_debug_trap("scan ran into NULL");
flush(); // consider the connection and all data trashed
return false;
}
#if MARLIN_COMPAT_ENABLED == true
// it's possible something will try to talk stk500v2 to us.
// See https://github.com/synthetos/g2/wiki/Marlin-Compatibility#stk500v2
if (_stk_parser_state >= STK500V2_State::Timeout)
{
if (_stk_parser_state == STK500V2_State::Timeout) {
@@ -672,6 +674,7 @@ struct LineRXBuffer : RXBuffer<_size, owner_type, char> {
else if ((c == '{') || (c == '\n') || (c == '\r') || (c == 'G') || (c == 'M')) {
// jump out of bootloader mode
_stk_parser_state = STK500V2_State::Done;
_read_offset = _scan_offset;
continue;
}
@@ -690,6 +693,7 @@ struct LineRXBuffer : RXBuffer<_size, owner_type, char> {
} else {
// end-of-header marker was corrupt, start over
_stk_packet_data_length = 0;
_read_offset = _scan_offset;
_stk_parser_state = STK500V2_State::Start;
}
} else if (_stk_parser_state == STK500V2_State::Data) {
@@ -706,9 +710,21 @@ struct LineRXBuffer : RXBuffer<_size, owner_type, char> {
// we will use the "control" return machanism to handle this
// since controls don't have to be \r\n-terminated
is_control = true;
ends_line = true;
// this line is complete, reset the state engine
_stk_parser_state = STK500V2_State::Start;
}
}
else
#else
if (c == 0) {
_debug_trap("scan ran into NULL");
flush(); // consider the connection and all data trashed
return false;
}
#endif
// Look for line endings
if (c == '\r' || c == '\n') {
@@ -1237,6 +1253,12 @@ struct xioFlashFileDeviceWrapper : xioDeviceWrapperBase { // describes a devi
_current_file = nullptr;
}
bool flushToCommand() final {
// the end of the file is the next "command"
_current_file = nullptr;
return false;
}
int16_t write(const char *buffer, int16_t len) final {
return -1;
}