-4963f9a9bf4f4b228c8501f6710e350d FirmwareBin/firmware.bin
+f3b1b6e6897abf1bc26c195fea842546 FirmwareBin/firmware.bin
kernel->streams->printf(" Build version %s, Build date %s\r\n", version.get_build(), version.get_build_date());
bool sdok= (sd.disk_initialize() == 0);
- if(!sdok) kernel->streams->printf("SDCard is disabled\r\n");
+ if(!sdok) kernel->streams->printf("SDCard failed to initialize\r\n");
+
+ #ifdef NONETWORK
+ kernel->streams->printf("NETWORK is disabled\r\n");
+ #endif
#ifdef DISABLEMSD
// attempt to be able to disable msd in config
}
- if(!uploading) {
- //Prepare gcode for dispatch
+ if(!uploading || upload_stream != new_message.stream) {
+ // Prepare gcode for dispatch
Gcode *gcode = new Gcode(single_command, new_message.stream);
if(THEKERNEL->is_halted()) {
} else {
new_message.stream->printf("open failed, File: %s.\r\nok\r\n", this->upload_filename.c_str());
}
+
+ // only save stuff from this stream
+ upload_stream= new_message.stream;
+
//printf("Start Uploading file: %s, %p\n", upload_filename.c_str(), upload_fd);
continue;
delete gcode;
} else {
- // we are uploading a file so save it
+ // we are uploading and it is the upload stream so so save it
if(single_command.substr(0, 3) == "M29") {
// done uploading, close file
fclose(upload_fd);
upload_fd = NULL;
uploading = false;
upload_filename.clear();
+ upload_stream= nullptr;
new_message.stream->printf("Done saving file.\r\nok\r\n");
continue;
}
#include <string>
using std::string;
+class StreamOutput;
+
class GcodeDispatch : public Module
{
public:
int currentline;
string upload_filename;
FILE *upload_fd;
+ StreamOutput* upload_stream{nullptr};
uint8_t modal_group_1;
struct {
bool uploading: 1;
std::vector<Robot::wcs_t> Robot::get_wcs_state() const
{
std::vector<wcs_t> v;
- v.push_back(wcs_t(current_wcs, k_max_wcs, 0));
+ v.push_back(wcs_t(current_wcs, MAX_WCS, 0));
for(auto& i : wcs_offsets) {
v.push_back(i);
}
size_t n = gcode->get_uint('P');
if(n == 0) n = current_wcs; // set current coordinate system
else --n;
- if(n < k_max_wcs) {
+ if(n < MAX_WCS) {
float x, y, z;
std::tie(x, y, z) = wcs_offsets[n];
if(gcode->get_int('L') == 20) {
current_wcs = gcode->g - 54;
if(gcode->g == 59 && gcode->subcode > 0) {
current_wcs += gcode->subcode;
- if(current_wcs >= k_max_wcs) current_wcs = k_max_wcs - 1;
+ if(current_wcs >= MAX_WCS) current_wcs = MAX_WCS - 1;
}
break;
actuators[1]->change_steps_per_mm(this->to_millimeters(gcode->get_value('Y')));
if (gcode->has_letter('Z'))
actuators[2]->change_steps_per_mm(this->to_millimeters(gcode->get_value('Z')));
- if (gcode->has_letter('F'))
- seconds_per_minute = gcode->get_value('F');
- gcode->stream->printf("X:%g Y:%g Z:%g F:%g ", actuators[0]->steps_per_mm, actuators[1]->steps_per_mm, actuators[2]->steps_per_mm, seconds_per_minute);
+ gcode->stream->printf("X:%f Y:%f Z:%f ", actuators[0]->steps_per_mm, actuators[1]->steps_per_mm, actuators[2]->steps_per_mm);
gcode->add_nl = true;
check_max_actuator_speeds();
return;
{
ActuatorCoordinates actuator_pos;
for (size_t i = 0; i < actuators.size(); i++) {
+ // NOTE actuator::current_position is curently NOT the same as actuator::last_milestone after an abrupt abort
actuator_pos[i] = actuators[i]->get_current_position();
}
+
+ // discover machine position from where actuators actually are
arm_solution->actuator_to_cartesian(actuator_pos, last_machine_position);
// FIXME problem is this includes any compensation transform, and without an inverse compensation we cannot get a correct last_milestone
memcpy(last_milestone, last_machine_position, sizeof last_milestone);
- // now reset actuator correctly, NOTE this may lose a little precision
- // NOTE I do not recall why this was necessary, maybe to correct for small errors in FK
- // arm_solution->cartesian_to_actuator(last_machine_position, actuator_pos);
- // for (size_t i = 0; i < actuators.size(); i++)
- // actuators[i]->change_last_milestone(actuator_pos[i]);
+ // now reset actuator::last_milestone, NOTE this may lose a little precision as FK is not always entirely accurate.
+ // NOTE This is required to sync the machine position with the actuator position, we do a somewhat redundant cartesian_to_actuator() call
+ // to get everything in perfect sync.
+ arm_solution->cartesian_to_actuator(last_machine_position, actuator_pos);
+ for (size_t i = 0; i < actuators.size(); i++)
+ actuators[i]->change_last_milestone(actuator_pos[i]);
}
// Convert target (in machine coordinates) from millimeters to steps, and append this to the planner
class BaseSolution;
class StepperMotor;
+// 9 WCS offsets
+#define MAX_WCS 9UL
+
class Robot : public Module {
public:
+ using wcs_t= std::tuple<float, float, float>;
Robot();
void on_module_loaded();
void on_gcode_received(void* argument);
float to_millimeters( float value ) const { return this->inch_mode ? value * 25.4F : value; }
float from_millimeters( float value) const { return this->inch_mode ? value/25.4F : value; }
void get_axis_position(float position[]) const { memcpy(position, this->last_milestone, sizeof this->last_milestone); }
+ wcs_t get_axis_position() const { return wcs_t(last_milestone[0], last_milestone[1], last_milestone[2]); }
int print_position(uint8_t subcode, char *buf, size_t bufsize) const;
uint8_t get_current_wcs() const { return current_wcs; }
- using wcs_t= std::tuple<float, float, float>;
std::vector<wcs_t> get_wcs_state() const;
BaseSolution* arm_solution; // Selected Arm solution ( millimeters to step calculation )
// Workspace coordinate systems
wcs_t mcs2wcs(const float *pos) const;
- static const size_t k_max_wcs= 9; // setup 9 WCS offsets
- std::array<wcs_t, k_max_wcs> wcs_offsets; // these are persistent once saved with M500
+ std::array<wcs_t, MAX_WCS> wcs_offsets; // these are persistent once saved with M500
uint8_t current_wcs{0}; // 0 means G54 is enabled thisĀ is persistent once saved with M500
wcs_t g92_offset;
wcs_t tool_offset; // used for multiple extruders, sets the tool offset for the current extruder applied first
#define input_pin_behavior_checksum CHECKSUM("input_pin_behavior")
#define toggle_checksum CHECKSUM("toggle")
#define momentary_checksum CHECKSUM("momentary")
+#define command_subcode_checksum CHECKSUM("subcode")
#define input_on_command_checksum CHECKSUM("input_on_command")
#define input_off_command_checksum CHECKSUM("input_off_command")
#define output_pin_checksum CHECKSUM("output_pin")
{
this->input_pin.from_string( THEKERNEL->config->value(switch_checksum, this->name_checksum, input_pin_checksum )->by_default("nc")->as_string())->as_input();
this->input_pin_behavior = THEKERNEL->config->value(switch_checksum, this->name_checksum, input_pin_behavior_checksum )->by_default(momentary_checksum)->as_number();
+ this->subcode = THEKERNEL->config->value(switch_checksum, this->name_checksum, command_subcode_checksum )->by_default(0)->as_number();
std::string input_on_command = THEKERNEL->config->value(switch_checksum, this->name_checksum, input_on_command_checksum )->by_default("")->as_string();
std::string input_off_command = THEKERNEL->config->value(switch_checksum, this->name_checksum, input_off_command_checksum )->by_default("")->as_string();
this->output_on_command = THEKERNEL->config->value(switch_checksum, this->name_checksum, output_on_command_checksum )->by_default("")->as_string();
bool Switch::match_input_on_gcode(const Gcode *gcode) const
{
- return ((input_on_command_letter == 'M' && gcode->has_m && gcode->m == input_on_command_code) ||
+ bool b= ((input_on_command_letter == 'M' && gcode->has_m && gcode->m == input_on_command_code) ||
(input_on_command_letter == 'G' && gcode->has_g && gcode->g == input_on_command_code));
+
+ return (b && gcode->subcode == this->subcode);
}
bool Switch::match_input_off_gcode(const Gcode *gcode) const
{
- return ((input_off_command_letter == 'M' && gcode->has_m && gcode->m == input_off_command_code) ||
+ bool b= ((input_off_command_letter == 'M' && gcode->has_m && gcode->m == input_off_command_code) ||
(input_off_command_letter == 'G' && gcode->has_g && gcode->g == input_off_command_code));
+ return (b && gcode->subcode == this->subcode);
}
void Switch::on_gcode_received(void *argument)
if (this->output_type == SIGMADELTA) {
// SIGMADELTA output pin turn on (or off if S0)
if(gcode->has_letter('S')) {
- int v = round(gcode->get_value('S') * sigmadelta_pin->max_pwm() / 255.0); // scale by max_pwm so input of 255 and max_pwm of 128 would set value to 128
+ int v = (gcode->get_int('S') * sigmadelta_pin->max_pwm()) / 255; // scale by max_pwm so input of 255 and max_pwm of 128 would set value to 128
if(v != this->sigmadelta_pin->get_pwm()){ // optimize... ignore if already set to the same pwm
// drain queue
THEKERNEL->conveyor->wait_for_empty_queue();
char input_on_command_letter;
char input_off_command_letter;
struct {
+ uint8_t subcode:4;
bool switch_changed:1;
bool input_pin_state:1;
bool switch_state:1;
float max_delta= 0;
float last_z= NAN;
+ float start_z;
+ std::tie(std::ignore, std::ignore, start_z)= THEKERNEL->robot->get_axis_position();
+
for(auto& i : pp) {
int s;
if(!zprobe->doProbeAt(s, i[0], i[1])) return false;
float z = zprobe->zsteps_to_mm(s);
- gcode->stream->printf("X:%1.4f Y:%1.4f Z:%1.4f (%d) A:%1.4f B:%1.4f C:%1.4f\n",
- i[0], i[1], z, s,
- THEKERNEL->robot->actuators[0]->get_current_position()+z,
- THEKERNEL->robot->actuators[1]->get_current_position()+z,
- THEKERNEL->robot->actuators[2]->get_current_position()+z);
+ if(gcode->subcode == 0) {
+ gcode->stream->printf("X:%1.4f Y:%1.4f Z:%1.4f (%d) A:%1.4f B:%1.4f C:%1.4f\n",
+ i[0], i[1], z, s,
+ THEKERNEL->robot->actuators[0]->get_current_position()+z,
+ THEKERNEL->robot->actuators[1]->get_current_position()+z,
+ THEKERNEL->robot->actuators[2]->get_current_position()+z);
+
+ }else if(gcode->subcode == 1) {
+ // format that can be pasted here http://escher3d.com/pages/wizards/wizarddelta.php
+ gcode->stream->printf("X%1.4f Y%1.4f Z%1.4f\n", i[0], i[1], start_z - z);
+ }
if(isnan(last_z)) {
last_z= z;
}
} else {
- if(gcode->subcode == 0) {
+ if(!gcode->has_letter('P')) {
// find the first strategy to handle the gcode
for(auto s : strategies){
if(s->handleGcode(gcode)) {
gcode->stream->printf("No strategy found to handle G%d\n", gcode->g);
}else{
- // subcode selects which strategy to send the code to
- // they are loaded in the order they are defined in config, 1 being the first, 2 being the second and so on.
- int i= gcode->subcode-1;
- if(gcode->subcode < strategies.size()) {
+ // P paramater selects which strategy to send the code to
+ // they are loaded in the order they are defined in config, 0 being the first, 1 being the second and so on.
+ uint16_t i= gcode->get_value('P');
+ if(i < strategies.size()) {
if(!strategies[i]->handleGcode(gcode)){
- gcode->stream->printf("strategy #%d did not handle G%d\n", i+1, gcode->g);
+ gcode->stream->printf("strategy #%d did not handle G%d\n", i, gcode->g);
}
return;
}else{
- gcode->stream->printf("strategy #%d is not loaded\n", i+1);
+ gcode->stream->printf("strategy #%d is not loaded\n", i);
}
}
}
} 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;
+ THEKERNEL->robot->pop_state();
+ this->saved_temperatures.clear();
+ this->was_playing_file= false;
+ this->suspend_loops= 0;
+ }
+ }
}
}
#include "version.h"
const char *Version::get_build(void) const {
- return __GITVERSIONSTRING__;
+ #ifdef DISABLEMSD
+ return __GITVERSIONSTRING__ "NOMSD";
+ #else
+ return __GITVERSIONSTRING__;
+ #endif
}
const char *Version::get_build_date(void) const {
return __DATE__ " " __TIME__;