Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of Smoothie by
GcodeDispatch.cpp
00001 /* 00002 This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl). 00003 Smoothie is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. 00004 Smoothie is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 00005 You should have received a copy of the GNU General Public License along with Smoothie. If not, see <http://www.gnu.org/licenses/>. 00006 */ 00007 00008 #include <string> 00009 using std::string; 00010 #include "libs/Module.h" 00011 #include "libs/Kernel.h" 00012 #include "utils/Gcode.h" 00013 #include "libs/nuts_bolts.h" 00014 #include "GcodeDispatch.h" 00015 #include "modules/robot/Conveyor.h" 00016 #include "libs/SerialMessage.h" 00017 #include "libs/StreamOutput.h" 00018 #include "libs/FileStream.h" 00019 00020 GcodeDispatch::GcodeDispatch() {} 00021 00022 // Called when the module has just been loaded 00023 void GcodeDispatch::on_module_loaded() 00024 { 00025 return_error_on_unhandled_gcode = THEKERNEL->config->value( return_error_on_unhandled_gcode_checksum )->by_default(false)->as_bool(); 00026 this->register_for_event(ON_CONSOLE_LINE_RECEIVED); 00027 currentline = -1; 00028 uploading = false; 00029 last_g= 255; 00030 } 00031 00032 // When a command is received, if it is a Gcode, dispatch it as an object via an event 00033 void GcodeDispatch::on_console_line_received(void *line) 00034 { 00035 SerialMessage new_message = *static_cast<SerialMessage *>(line); 00036 string possible_command = new_message.message; 00037 00038 int ln = 0; 00039 int cs = 0; 00040 00041 try_again: 00042 00043 char first_char = possible_command[0]; 00044 unsigned int n; 00045 if ( first_char == 'G' || first_char == 'M' || first_char == 'T' || first_char == 'N' ) { 00046 00047 //Get linenumber 00048 if ( first_char == 'N' ) { 00049 Gcode full_line = Gcode(possible_command, new_message.stream); 00050 ln = (int) full_line.get_value('N'); 00051 int chksum = (int) full_line.get_value('*'); 00052 00053 //Catch message if it is M110: Set Current Line Number 00054 if ( full_line.has_letter('M') ) { 00055 if ( ((int) full_line.get_value('M')) == 110 ) { 00056 currentline = ln; 00057 new_message.stream->printf("ok\r\n"); 00058 return; 00059 } 00060 } 00061 00062 //Strip checksum value from possible_command 00063 size_t chkpos = possible_command.find_first_of("*"); 00064 possible_command = possible_command.substr(0, chkpos); 00065 //Calculate checksum 00066 if ( chkpos != string::npos ) { 00067 for (auto c = possible_command.cbegin(); *c != '*' && c != possible_command.cend(); c++) 00068 cs = cs ^ *c; 00069 cs &= 0xff; // Defensive programming... 00070 cs -= chksum; 00071 } 00072 //Strip line number value from possible_command 00073 size_t lnsize = possible_command.find_first_not_of("N0123456789.,- "); 00074 possible_command = possible_command.substr(lnsize); 00075 00076 } else { 00077 //Assume checks succeeded 00078 cs = 0x00; 00079 ln = currentline + 1; 00080 } 00081 00082 //Remove comments 00083 size_t comment = possible_command.find_first_of(";("); 00084 if( comment != string::npos ) { 00085 possible_command = possible_command.substr(0, comment); 00086 } 00087 00088 //If checksum passes then process message, else request resend 00089 int nextline = currentline + 1; 00090 if( cs == 0x00 && ln == nextline ) { 00091 if( first_char == 'N' ) { 00092 currentline = nextline; 00093 } 00094 00095 while(possible_command.size() > 0) { 00096 size_t nextcmd = possible_command.find_first_of("GMT", possible_command.find_first_of("GMT") + 1); 00097 string single_command; 00098 if(nextcmd == string::npos) { 00099 single_command = possible_command; 00100 possible_command = ""; 00101 } else { 00102 single_command = possible_command.substr(0, nextcmd); 00103 possible_command = possible_command.substr(nextcmd); 00104 } 00105 00106 if(!uploading) { 00107 //Prepare gcode for dispatch 00108 Gcode *gcode = new Gcode(single_command, new_message.stream); 00109 00110 if(gcode->has_g) { 00111 last_g= gcode->g; 00112 } 00113 if(gcode->has_m) { 00114 switch (gcode->m) { 00115 case 28: // start upload command 00116 delete gcode; 00117 00118 this->upload_filename = "/sd/" + single_command.substr(4); // rest of line is filename 00119 // open file 00120 upload_fd = fopen(this->upload_filename.c_str(), "w"); 00121 if(upload_fd != NULL) { 00122 this->uploading = true; 00123 new_message.stream->printf("Writing to file: %s\r\n", this->upload_filename.c_str()); 00124 } else { 00125 new_message.stream->printf("open failed, File: %s.\r\n", this->upload_filename.c_str()); 00126 } 00127 //printf("Start Uploading file: %s, %p\n", upload_filename.c_str(), upload_fd); 00128 continue; 00129 00130 case 500: // M500 save volatile settings to config-override 00131 // replace stream with one that writes to config-override file 00132 gcode->stream = new FileStream(THEKERNEL->config_override_filename()); 00133 // dispatch the M500 here so we can free up the stream when done 00134 THEKERNEL->call_event(ON_GCODE_RECEIVED, gcode ); 00135 delete gcode->stream; 00136 delete gcode; 00137 new_message.stream->printf("Settings Stored to %s\r\nok\r\n", THEKERNEL->config_override_filename()); 00138 continue; 00139 00140 case 502: // M502 deletes config-override so everything defaults to what is in config 00141 remove(THEKERNEL->config_override_filename()); 00142 new_message.stream->printf("config override file deleted %s, reboot needed\r\nok\r\n", THEKERNEL->config_override_filename()); 00143 delete gcode; 00144 continue; 00145 00146 case 503: { // M503 display live settings and indicates if there is an override file 00147 FILE *fd = fopen(THEKERNEL->config_override_filename(), "r"); 00148 if(fd != NULL) { 00149 fclose(fd); 00150 new_message.stream->printf("; config override present: %s\n", THEKERNEL->config_override_filename()); 00151 00152 } else { 00153 new_message.stream->printf("; No config override\n"); 00154 } 00155 break; // fall through to process by modules 00156 } 00157 } 00158 } 00159 00160 //printf("dispatch %p: '%s' G%d M%d...", gcode, gcode->command.c_str(), gcode->g, gcode->m); 00161 //Dispatch message! 00162 THEKERNEL->call_event(ON_GCODE_RECEIVED, gcode ); 00163 if(gcode->add_nl) 00164 new_message.stream->printf("\r\n"); 00165 00166 if( return_error_on_unhandled_gcode == true && gcode->accepted_by_module == false) 00167 new_message.stream->printf("ok (command unclaimed)\r\n"); 00168 else if(!gcode->txt_after_ok.empty()) { 00169 new_message.stream->printf("ok %s\r\n", gcode->txt_after_ok.c_str()); 00170 gcode->txt_after_ok.clear(); 00171 } else 00172 new_message.stream->printf("ok\r\n"); 00173 00174 delete gcode; 00175 00176 } else { 00177 // we are uploading a file so save it 00178 if(single_command.substr(0, 3) == "M29") { 00179 // done uploading, close file 00180 fclose(upload_fd); 00181 upload_fd = NULL; 00182 uploading = false; 00183 upload_filename.clear(); 00184 new_message.stream->printf("Done saving file.\r\n"); 00185 continue; 00186 } 00187 00188 if(upload_fd == NULL) { 00189 // error detected writing to file so discard everything until it stops 00190 new_message.stream->printf("ok\r\n"); 00191 continue; 00192 } 00193 00194 single_command.append("\n"); 00195 static int cnt = 0; 00196 if(fwrite(single_command.c_str(), 1, single_command.size(), upload_fd) != single_command.size()) { 00197 // error writing to file 00198 new_message.stream->printf("Error:error writing to file.\r\n"); 00199 fclose(upload_fd); 00200 upload_fd = NULL; 00201 continue; 00202 00203 } else { 00204 cnt += single_command.size(); 00205 if (cnt > 400) { 00206 // HACK ALERT to get around fwrite corruption close and re open for append 00207 fclose(upload_fd); 00208 upload_fd = fopen(upload_filename.c_str(), "a"); 00209 cnt = 0; 00210 } 00211 new_message.stream->printf("ok\r\n"); 00212 //printf("uploading file write ok\n"); 00213 } 00214 } 00215 } 00216 00217 } else { 00218 //Request resend 00219 new_message.stream->printf("rs N%d\r\n", nextline); 00220 } 00221 00222 } else if( (n=possible_command.find_first_of("XYZF")) == 0 || (first_char == ' ' && n != string::npos) ) { 00223 // handle pycam syntax, use last G0 or G1 and resubmit if an X Y Z or F is found on its own line 00224 if(last_g != 0 && last_g != 1) { 00225 //if no last G1 or G0 ignore 00226 //THEKERNEL->streams->printf("ignored: %s\r\n", possible_command.c_str()); 00227 return; 00228 } 00229 char buf[6]; 00230 snprintf(buf, sizeof(buf), "G%d ", last_g); 00231 possible_command.insert(0, buf); 00232 goto try_again; 00233 00234 // Ignore comments and blank lines 00235 } else if ( first_char == ';' || first_char == '(' || first_char == ' ' || first_char == '\n' || first_char == '\r' ) { 00236 new_message.stream->printf("ok\r\n"); 00237 } 00238 } 00239
Generated on Tue Jul 12 2022 20:09:01 by
1.7.2
