*/
-#include <string>
-using std::string;
#include "Gcode.h"
#include "libs/StreamOutput.h"
#include "utils.h"
-
#include <stdlib.h>
+#include <algorithm>
+// This is a gcode object. It reprensents a GCode string/command, an caches some important values about that command for the sake of performance.
+// It gets passed around in events, and attached to the queue ( that'll change )
+Gcode::Gcode(const string &command, StreamOutput *stream, bool strip)
+{
+ this->command= strdup(command.c_str());
+ this->m= 0;
+ this->g= 0;
+ this->add_nl= false;
+ this->stream= stream;
+ this->millimeters_of_travel = 0.0F;
+ this->accepted_by_module = false;
+ prepare_cached_values(strip);
+}
-Gcode::Gcode(const string& command, StreamOutput* stream) : command(command), m(0), g(0), add_nl(false), stream(stream) {
- prepare_cached_values();
- this->millimeters_of_travel = 0L;
+Gcode::~Gcode()
+{
+ if(command != nullptr) {
+ // TODO we can reference count this so we share copies, may save more ram than the extra count we need to store
+ free(command);
+ }
}
-Gcode::Gcode(const Gcode& to_copy){
- this->command.assign( to_copy.command );
+Gcode::Gcode(const Gcode &to_copy)
+{
+ this->command = strdup(to_copy.command); // TODO we can reference count this so we share copies, may save more ram than the extra count we need to store
this->millimeters_of_travel = to_copy.millimeters_of_travel;
this->has_m = to_copy.has_m;
this->has_g = to_copy.has_g;
this->g = to_copy.g;
this->add_nl = to_copy.add_nl;
this->stream = to_copy.stream;
+ this->accepted_by_module = false;
+ this->txt_after_ok.assign( to_copy.txt_after_ok );
}
-Gcode& Gcode::operator= (const Gcode& to_copy){
- if( this != &to_copy ){
- this->command.assign( to_copy.command );
+Gcode &Gcode::operator= (const Gcode &to_copy)
+{
+ if( this != &to_copy ) {
+ this->command = strdup(to_copy.command); // TODO we can reference count this so we share copies, may save more ram than the extra count we need to store
this->millimeters_of_travel = to_copy.millimeters_of_travel;
this->has_m = to_copy.has_m;
this->has_g = to_copy.has_g;
this->g = to_copy.g;
this->add_nl = to_copy.add_nl;
this->stream = to_copy.stream;
+ this->txt_after_ok.assign( to_copy.txt_after_ok );
}
+ this->accepted_by_module = false;
return *this;
}
// Whether or not a Gcode has a letter
-bool Gcode::has_letter( char letter ){
- //return ( this->command->find( letter ) != string::npos );
- for (std::string::const_iterator c = this->command.cbegin(); c != this->command.cend(); c++) {
- if( *c == letter ){
+bool Gcode::has_letter( char letter ) const
+{
+ for (size_t i = 0; i < strlen(this->command); ++i) {
+ if( command[i] == letter ) {
return true;
}
}
}
// Retrieve the value for a given letter
-// We don't use the high-level methods of std::string because they call malloc and it's very bad to do that inside of interrupts
-double Gcode::get_value( char letter ){
- //__disable_irq();
- const char* cs = command.c_str();
- char* cn = NULL;
- for (; *cs; cs++){
- if( letter == *cs ){
- cs++;
- double r = strtod(cs, &cn);
- if (cn > cs)
- return r;
- }
+float Gcode::get_value( char letter, char **ptr ) const
+{
+ const char *cs = command;
+ char *cn = NULL;
+ for (; *cs; cs++) {
+ if( letter == *cs ) {
+ cs++;
+ float r = strtof(cs, &cn);
+ if(ptr != nullptr) *ptr= cn;
+ if (cn > cs)
+ return r;
+ }
}
- //__enable_irq();
+ if(ptr != nullptr) *ptr= nullptr;
return 0;
}
-int Gcode::get_int( char letter )
+int Gcode::get_int( char letter, char **ptr ) const
{
- const char* cs = command.c_str();
- char* cn = NULL;
- for (; *cs; cs++){
- if( letter == *cs ){
+ const char *cs = command;
+ char *cn = NULL;
+ for (; *cs; cs++) {
+ if( letter == *cs ) {
cs++;
int r = strtol(cs, &cn, 10);
+ if(ptr != nullptr) *ptr= cn;
if (cn > cs)
return r;
}
}
+ if(ptr != nullptr) *ptr= nullptr;
return 0;
}
-int Gcode::get_num_args(){
+int Gcode::get_num_args() const
+{
int count = 0;
- for(size_t i=1; i<this->command.length(); i++){
- if( this->command.at(i) >= 'A' && this->command.at(i) <= 'Z' ){
+ for(size_t i = 1; i < strlen(command); i++) {
+ if( this->command[i] >= 'A' && this->command[i] <= 'Z' ) {
count++;
}
}
return count;
}
-void Gcode::prepare_cached_values(){
- if( this->has_letter('G') ){
+// Cache some of this command's properties, so we don't have to parse the string every time we want to look at them
+void Gcode::prepare_cached_values(bool strip)
+{
+ char *p= nullptr;
+ if( this->has_letter('G') ) {
this->has_g = true;
- this->g = this->get_int('G');
- }else{
+ this->g = this->get_int('G', &p);
+ } else {
this->has_g = false;
}
- if( this->has_letter('M') ){
+ if( this->has_letter('M') ) {
this->has_m = true;
- this->m = this->get_int('M');
- }else{
+ this->m = this->get_int('M', &p);
+ } else {
this->has_m = false;
}
+
+ if(!strip) return;
+
+ // remove the Gxxx or Mxxx from string
+ if (p != nullptr) {
+ char *n= strdup(p); // create new string starting at end of the numeric value
+ free(command);
+ command= n;
+ }
+}
+
+void Gcode::mark_as_taken()
+{
+ this->accepted_by_module = true;
+}
+
+// strip off X Y Z I J parameters if G0/1/2/3
+void Gcode::strip_parameters()
+{
+ if(has_g && g <= 4){
+ // strip the command of the XYZIJK parameters
+ string newcmd;
+ char *cn= command;
+ // find the start of each parameter
+ char *pch= strpbrk(cn, "XYZIJK");
+ while (pch != nullptr) {
+ if(pch > cn) {
+ // copy non parameters to new string
+ newcmd.append(cn, pch-cn);
+ }
+ // find the end of the parameter and its value
+ char *eos;
+ strtof(pch+1, &eos);
+ cn= eos; // point to end of last parameter
+ pch= strpbrk(cn, "XYZIJ"); // find next parameter
+ }
+ // append anything left on the line
+ newcmd.append(cn);
+ // strip whitespace to save even more
+ newcmd.erase(std::remove_if(newcmd.begin(), newcmd.end(), ::isspace), newcmd.end());
+
+ // release the old one
+ free(command);
+ // copy the new shortened one
+ command= strdup(newcmd.c_str());
+ }
}