#include "libs/StreamOutput.h"
#include "Gcode.h"
#include "checksumm.h"
-#include "Pauser.h"
#include "Config.h"
#include "ConfigValue.h"
#include "SDFAT.h"
#include "PlayerPublicAccess.h"
#include "TemperatureControlPublicAccess.h"
#include "TemperatureControlPool.h"
+#include "ExtruderPublicAccess.h"
#include <cstddef>
#include <cmath>
#define before_resume_gcode_checksum CHECKSUM("before_resume_gcode")
#define leave_heaters_on_suspend_checksum CHECKSUM("leave_heaters_on_suspend")
-
-#define extruder_checksum CHECKSUM("extruder")
-#define save_state_checksum CHECKSUM("save_state")
-#define restore_state_checksum CHECKSUM("restore_state")
-
extern SDFAT mounter;
Player::Player()
this->booted = false;
this->elapsed_secs = 0;
this->reply_stream = nullptr;
- this->halted= false;
this->suspended= false;
this->suspend_loops= 0;
}
this->leave_heaters_on = THEKERNEL->config->value(leave_heaters_on_suspend_checksum)->by_default(false)->as_bool();
}
-void Player::on_halt(void *arg)
+void Player::on_halt(void* argument)
{
- halted= (arg == nullptr);
+ if(argument == nullptr && this->playing_file ) {
+ abort_command("1", &(StreamOutput::NullStream));
+ }
}
void Player::on_second_tick(void *)
string args = get_arguments(gcode->get_command());
if (gcode->has_m) {
if (gcode->m == 21) { // Dummy code; makes Octoprint happy -- supposed to initialize SD card
- gcode->mark_as_taken();
mounter.remount();
gcode->stream->printf("SD card ok\r\n");
} else if (gcode->m == 23) { // select file
- gcode->mark_as_taken();
this->filename = "/sd/" + args; // filename is whatever is in args
- this->current_stream = &(StreamOutput::NullStream);
+ this->current_stream = nullptr;
if(this->current_file_handler != NULL) {
this->playing_file = false;
this->elapsed_secs = 0;
} else if (gcode->m == 24) { // start print
- gcode->mark_as_taken();
if (this->current_file_handler != NULL) {
this->playing_file = true;
// this would be a problem if the stream goes away before the file has finished,
}
} else if (gcode->m == 25) { // pause print
- gcode->mark_as_taken();
this->playing_file = false;
} else if (gcode->m == 26) { // Reset print. Slightly different than M26 in Marlin and the rest
- gcode->mark_as_taken();
if(this->current_file_handler != NULL) {
string currentfn = this->filename.c_str();
unsigned long old_size = this->file_size;
} else {
this->filename = currentfn;
this->file_size = old_size;
- this->current_stream = &(StreamOutput::NullStream);
+ this->current_stream = nullptr;
}
}
} else {
}
} else if (gcode->m == 27) { // report print progress, in format used by Marlin
- gcode->mark_as_taken();
progress_command("-b", gcode->stream);
} else if (gcode->m == 32) { // select file and start print
- gcode->mark_as_taken();
// Get filename
this->filename = "/sd/" + args; // filename is whatever is in args including spaces
- this->current_stream = &(StreamOutput::NullStream);
+ this->current_stream = nullptr;
if(this->current_file_handler != NULL) {
this->playing_file = false;
this->played_cnt = 0;
this->elapsed_secs = 0;
- } else if (gcode->m == 600) { // suspend print, Not entirely Marlin compliant
- this->suspend_command("", &(StreamOutput::NullStream));
+
+ } else if (gcode->m == 600) { // suspend print, Not entirely Marlin compliant, M600.1 will leave the heaters on
+ this->suspend_command((gcode->subcode == 1)?"h":"", gcode->stream);
+
+ } else if (gcode->m == 601) { // resume print
+ this->resume_command("", gcode->stream);
+ }
+
+ }else if(gcode->has_g) {
+ if(gcode->g == 28) { // homing cancels suspend
+ if(this->suspended) {
+ // clean up
+ this->suspended= false;
+ THEROBOT->pop_state();
+ this->saved_temperatures.clear();
+ this->was_playing_file= false;
+ this->suspend_loops= 0;
+ }
}
}
}
// When a new line is received, check if it is a command, and if it is, act upon it
void Player::on_console_line_received( void *argument )
{
- if(halted) return; // if in halted state ignore any commands
+ if(THEKERNEL->is_halted()) return; // if in halted state ignore any commands
SerialMessage new_message = *static_cast<SerialMessage *>(argument);
// Output to the current stream if we were passed the -v ( verbose ) option
if( options.find_first_of("Vv") == string::npos ) {
- this->current_stream = &(StreamOutput::NullStream);
+ this->current_stream = nullptr;
} else {
// we send to the kernels stream as it cannot go away
this->current_stream = THEKERNEL->streams;
unsigned int pcnt = (file_size - (file_size - played_cnt)) * 100 / file_size;
// If -b or -B is passed, report in the format used by Marlin and the others.
if (!sdprinting) {
- stream->printf("%u %% complete, elapsed time: %lu s", pcnt, this->elapsed_secs);
+ stream->printf("file: %s, %u %% complete, elapsed time: %lu s", this->filename.c_str(), pcnt, this->elapsed_secs);
if(est > 0) {
stream->printf(", est time: %lu s", est);
}
THEKERNEL->conveyor->flush_queue();
// now the position will think it is at the last received pos, so we need to do FK to get the actuator position and reset the current position
- THEKERNEL->robot->reset_position_from_current_actuator_position();
+ THEROBOT->reset_position_from_current_actuator_position();
+ stream->printf("Aborted playing or paused file. Please turn any heaters off manually\r\n");
}
- stream->printf("Aborted playing or paused file\r\n");
}
void Player::on_main_loop(void *argument)
}
if( this->playing_file ) {
- if(halted) {
- abort_command("1", &(StreamOutput::NullStream));
+ if(THEKERNEL->is_halted()) {
return;
}
}
if(len == 1) continue; // empty line
- this->current_stream->printf("%s", buf);
+ if(this->current_stream != nullptr) {
+ this->current_stream->printf("%s", buf);
+ }
+
struct SerialMessage message;
message.message = buf;
- message.stream = this->current_stream;
+ message.stream = this->current_stream == nullptr ? &(StreamOutput::NullStream) : this->current_stream;
// waits for the queue to have enough room
THEKERNEL->call_event(ON_CONSOLE_LINE_RECEIVED, &message);
} else {
// discard long line
- this->current_stream->printf("Warning: Discarded long line\n");
+ if(this->current_stream != nullptr) { this->current_stream->printf("Warning: Discarded long line\n"); }
discard = true;
}
}
return;
}
- stream->printf("ok Suspending print, waiting for queue to empty...\n");
+ stream->printf("Suspending print, waiting for queue to empty...\n");
+
+ // override the leave_heaters_on setting
+ this->override_leave_heaters_on= (parameters == "h");
suspended= true;
if( this->playing_file ) {
// we need to allow main loop to cycle a few times to clear any buffered commands in the serial streams etc
suspend_loops= 10;
- suspend_stream= stream;
}
// this completes the suspend
void Player::suspend_part2()
{
+ // need to use streams here as the original stream may have changed
+ THEKERNEL->streams->printf("// Waiting for queue to empty (Host must stop sending)...\n");
// wait for queue to empty
- THEKERNEL->conveyor->wait_for_empty_queue();
+ THEKERNEL->conveyor->wait_for_idle();
- suspend_stream->printf("Saving current state...\n");
+ THEKERNEL->streams->printf("// Saving current state...\n");
// save current XYZ position
- THEKERNEL->robot->get_axis_position(this->saved_position);
+ THEROBOT->get_axis_position(this->saved_position);
// save current extruder state
PublicData::set_value( extruder_checksum, save_state_checksum, nullptr );
- // save state
- this->saved_inch_mode= THEKERNEL->robot->inch_mode;
- this->saved_absolute_mode= THEKERNEL->robot->absolute_mode;
- this->saved_feed_rate= THEKERNEL->robot->get_feed_rate();
+ // save state use M120
+ THEROBOT->push_state();
// TODO retract by optional amount...
this->saved_temperatures.clear();
- if(!this->leave_heaters_on) {
- // save current temperatures
- for(auto m : THEKERNEL->temperature_control_pool->get_controllers()) {
+ if(!this->leave_heaters_on && !this->override_leave_heaters_on) {
+ // save current temperatures, get a vector of all the controllers data
+ std::vector<struct pad_temperature> controllers;
+ bool ok = PublicData::get_value(temperature_control_checksum, poll_controls_checksum, &controllers);
+ if (ok) {
// query each heater and save the target temperature if on
- void *p;
- if(PublicData::get_value( temperature_control_checksum, m, current_temperature_checksum, &p )) {
- struct pad_temperature *temp= static_cast<struct pad_temperature *>(p);
+ for (auto &c : controllers) {
// TODO see if in exclude list
- if(temp != nullptr && temp->target_temperature > 0) {
- this->saved_temperatures[m]= temp->target_temperature;
+ if(c.target_temperature > 0) {
+ this->saved_temperatures[c.id]= c.target_temperature;
}
}
}
-
// turn off heaters that were on
for(auto& h : this->saved_temperatures) {
float t= 0;
THEKERNEL->call_event(ON_CONSOLE_LINE_RECEIVED, &message );
}
- suspend_stream->printf("Print Suspended, enter resume to continue printing\n");
+ THEKERNEL->streams->printf("// Print Suspended, enter resume to continue printing\n");
}
/**
return;
}
- stream->printf("ok resuming print...\n");
-
- // set heaters to saved temps
- for(auto& h : this->saved_temperatures) {
- float t= h.second;
- PublicData::set_value( temperature_control_checksum, h.first, &t );
- }
+ stream->printf("resuming print...\n");
// wait for them to reach temp
if(!this->saved_temperatures.empty()) {
+ // set heaters to saved temps
+ for(auto& h : this->saved_temperatures) {
+ float t= h.second;
+ PublicData::set_value( temperature_control_checksum, h.first, &t );
+ }
stream->printf("Waiting for heaters...\n");
bool wait= true;
uint32_t tus= us_ticker_read(); // mbed call
}
for(auto& h : this->saved_temperatures) {
- void *p;
- if(PublicData::get_value( temperature_control_checksum, h.first, current_temperature_checksum, &p )) {
- struct pad_temperature *temp= static_cast<struct pad_temperature *>(p);
- if(timeup) stream->printf("%s:%3.1f /%3.1f @%d ", temp->designator.c_str(), temp->current_temperature, ((temp->target_temperature == -1) ? 0.0 : temp->target_temperature), temp->pwm);
- wait= wait || (temp->current_temperature < h.second);
+ struct pad_temperature temp;
+ if(PublicData::get_value( temperature_control_checksum, current_temperature_checksum, h.first, &temp )) {
+ if(timeup)
+ stream->printf("%s:%3.1f /%3.1f @%d ", temp.designator.c_str(), temp.current_temperature, ((temp.target_temperature == -1) ? 0.0 : temp.target_temperature), temp.pwm);
+ wait= wait || (temp.current_temperature < h.second);
}
}
if(timeup) stream->printf("\n");
if(wait)
THEKERNEL->call_event(ON_IDLE, this);
+
+ if(THEKERNEL->is_halted()) {
+ // abort temp wait and rest of resume
+ THEKERNEL->streams->printf("Resume aborted by kill\n");
+ THEROBOT->pop_state();
+ this->saved_temperatures.clear();
+ suspended= false;
+ return;
+ }
}
}
// Restore position
stream->printf("Restoring saved XYZ positions and state...\n");
- THEKERNEL->robot->inch_mode= saved_inch_mode;
- THEKERNEL->robot->absolute_mode= saved_absolute_mode;
- char buf[128];
+ THEROBOT->pop_state();
+ bool abs_mode= THEROBOT->absolute_mode; // what mode we were in
+ // force absolute mode for restoring position, then set to the saved relative/absolute mode
+ THEROBOT->absolute_mode= true;
{
- int n = snprintf(buf, sizeof(buf), "G1 X%f Y%f Z%f F%f", saved_position[0], saved_position[1], saved_position[2], saved_feed_rate);
- string g(buf, n);
- Gcode gcode(g, &(StreamOutput::NullStream));
- THEKERNEL->call_event(ON_GCODE_RECEIVED, &gcode );
+ // NOTE position was saved in MCS so must use G53 to restore position
+ char buf[128];
+ snprintf(buf, sizeof(buf), "G53 G0 X%f Y%f Z%f", saved_position[0], saved_position[1], saved_position[2]);
+ struct SerialMessage message;
+ message.message = buf;
+ message.stream = &(StreamOutput::NullStream);
+ THEKERNEL->call_event(ON_CONSOLE_LINE_RECEIVED, &message );
}
+ THEROBOT->absolute_mode= abs_mode;
// restore extruder state
PublicData::set_value( extruder_checksum, restore_state_checksum, nullptr );
if(this->was_playing_file) {
this->playing_file = true;
+ this->was_playing_file= false;
}else{
// Send resume to host
THEKERNEL->streams->printf("// action:resume\r\n");