// Rename a file void SimpleShell::mv_command( string parameters, StreamOutput *stream ) { string from = absolute_from_relative(shift_parameter( parameters )); string to = absolute_from_relative(shift_parameter(parameters)); int s = rename(from.c_str(), to.c_str()); if (s != 0) stream->printf("Could not rename %s to %s\r\n", from.c_str(), to.c_str()); else stream->printf("renamed %s to %s\r\n", from.c_str(), to.c_str()); }
// saves the specified config-override file void SimpleShell::save_command( string parameters, StreamOutput *stream ) { // Get parameters ( filename ) string filename = absolute_from_relative(parameters); if(filename == "/") { filename = THEKERNEL->config_override_filename(); } THEKERNEL->conveyor->wait_for_empty_queue(); //just to be safe as it can take a while to run //remove(filename.c_str()); // seems to cause a hang every now and then { FileStream fs(filename.c_str()); fs.printf("; DO NOT EDIT THIS FILE\n"); // this also will truncate the existing file instead of deleting it } // stream that appends to file AppendFileStream *gs = new AppendFileStream(filename.c_str()); // if(!gs->is_open()) { // stream->printf("Unable to open File %s for write\n", filename.c_str()); // return; // } __disable_irq(); // issue a M500 which will store values in the file stream Gcode *gcode = new Gcode("M500", gs); THEKERNEL->call_event(ON_GCODE_RECEIVED, gcode ); delete gs; delete gcode; __enable_irq(); stream->printf("Settings Stored to %s\r\n", filename.c_str()); }
// loads the specified config-override file void SimpleShell::load_command( string parameters, StreamOutput *stream ) { // Get parameters ( filename ) string filename = absolute_from_relative(parameters); if(filename == "/") { filename = THEKERNEL->config_override_filename(); } FILE *fp = fopen(filename.c_str(), "r"); if(fp != NULL) { char buf[132]; stream->printf("Loading config override file: %s...\n", filename.c_str()); while(fgets(buf, sizeof buf, fp) != NULL) { stream->printf(" %s", buf); if(buf[0] == ';') continue; // skip the comments struct SerialMessage message = {&(StreamOutput::NullStream), buf}; THEKERNEL->call_event(ON_CONSOLE_LINE_RECEIVED, &message); } stream->printf("config override file executed\n"); fclose(fp); } else { stream->printf("File not found: %s\n", filename.c_str()); } }
// Change current absolute path to provided path void SimpleShell::cd_command( string parameters, StreamOutput *stream ) { string folder = absolute_from_relative( parameters ); DIR *d; d = opendir(folder.c_str()); if (d == NULL) { stream->printf("Could not open directory %s \r\n", folder.c_str() ); } else { THEKERNEL->current_path = folder; closedir(d); } }
// Play a gcode file by considering each line as if it was received on the serial console void Player::play_command( string parameters, StreamOutput *stream ) { // extract any options from the line and terminate the line there string options= extract_options(parameters); // Get filename which is the entire parameter line upto any options found or entire line this->filename = absolute_from_relative(parameters); if(this->playing_file || this->suspended) { stream->printf("Currently printing, abort print first\r\n"); return; } if(this->current_file_handler != NULL) { // must have been a paused print fclose(this->current_file_handler); } this->current_file_handler = fopen( this->filename.c_str(), "r"); if(this->current_file_handler == NULL) { stream->printf("File not found: %s\r\n", this->filename.c_str()); return; } stream->printf("Playing %s\r\n", this->filename.c_str()); this->playing_file = true; // Output to the current stream if we were passed the -v ( verbose ) option if( options.find_first_of("Vv") == string::npos ) { this->current_stream = nullptr; } else { // we send to the kernels stream as it cannot go away this->current_stream = THEKERNEL->streams; } // get size of file int result = fseek(this->current_file_handler, 0, SEEK_END); if (0 != result) { stream->printf("WARNING - Could not get file size\r\n"); file_size = 0; } else { file_size = ftell(this->current_file_handler); fseek(this->current_file_handler, 0, SEEK_SET); stream->printf(" File size %ld\r\n", file_size); } this->played_cnt = 0; this->elapsed_secs = 0; }
void SimpleShell::md5sum_command( string parameters, StreamOutput *stream ) { string filename = absolute_from_relative(parameters); // Open file FILE *lp = fopen(filename.c_str(), "r"); if (lp == NULL) { stream->printf("File not found: %s\r\n", filename.c_str()); return; } MD5 md5; uint8_t buf[64]; do { size_t n= fread(buf, 1, sizeof buf, lp); if(n > 0) md5.update(buf, n); THEKERNEL->call_event(ON_IDLE); } while(!feof(lp)); stream->printf("%s %s\n", md5.finalize().hexdigest().c_str(), filename.c_str()); fclose(lp); }
// Act upon an ls command // Convert the first parameter into an absolute path, then list the files in that path void SimpleShell::ls_command( string parameters, StreamOutput *stream ) { string path, opts; while(!parameters.empty()) { string s = shift_parameter( parameters ); if(s.front() == '-') { opts.append(s); } else { path = s; if(!parameters.empty()) { path.append(" "); path.append(parameters); } break; } } path = absolute_from_relative(path); DIR *d; struct dirent *p; d = opendir(path.c_str()); if (d != NULL) { while ((p = readdir(d)) != NULL) { stream->printf("%s", lc(string(p->d_name)).c_str()); if(p->d_isdir) { stream->printf("/"); } else if(opts.find("-s", 0, 2) != string::npos) { stream->printf(" %d", p->d_fsize); } stream->printf("\r\n"); } closedir(d); } else { stream->printf("Could not open directory %s\r\n", path.c_str()); } }
void SimpleShell::upload_command( string parameters, StreamOutput *stream ) { // this needs to be a hack. it needs to read direct from serial and not allow on_main_loop run until done // NOTE this will block all operation until the upload is complete, so do not do while printing if(!THEKERNEL->conveyor->is_queue_empty()) { stream->printf("upload not allowed while printing or busy\n"); return; } // open file to upload to string upload_filename = absolute_from_relative( parameters ); FILE *fd = fopen(upload_filename.c_str(), "w"); if(fd != NULL) { stream->printf("uploading to file: %s, send control-D or control-Z to finish\r\n", upload_filename.c_str()); } else { stream->printf("failed to open file: %s.\r\n", upload_filename.c_str()); return; } int cnt = 0; bool uploading = true; while(uploading) { if(!stream->ready()) { // we need to kick things or they die THEKERNEL->call_event(ON_IDLE); continue; } char c = stream->_getc(); if( c == 4 || c == 26) { // ctrl-D or ctrl-Z uploading = false; // close file fclose(fd); stream->printf("uploaded %d bytes\n", cnt); return; } else { // write character to file cnt++; if(fputc(c, fd) != c) { // error writing to file stream->printf("error writing to file. ignoring all characters until EOF\r\n"); fclose(fd); fd = NULL; uploading= false; } else { if ((cnt%400) == 0) { // HACK ALERT to get around fwrite corruption close and re open for append fclose(fd); fd = fopen(upload_filename.c_str(), "a"); // we need to kick things or they die THEKERNEL->call_event(ON_IDLE); } } } } // we got an error so ignore everything until EOF char c; do { if(stream->ready()) { c= stream->_getc(); }else{ THEKERNEL->call_event(ON_IDLE); c= 0; } } while(c != 4 && c != 26); }
// Output the contents of a file, first parameter is the filename, second is the limit ( in number of lines to output ) void SimpleShell::cat_command( string parameters, StreamOutput *stream ) { // Get parameters ( filename and line limit ) string filename = absolute_from_relative(shift_parameter( parameters )); string limit_parameter = shift_parameter( parameters ); int limit = -1; int delay= 0; bool send_eof= false; if ( limit_parameter == "-d" ) { string d= shift_parameter( parameters ); char *e = NULL; delay = strtol(d.c_str(), &e, 10); if (e <= d.c_str()) { delay = 0; } else { send_eof= true; // we need to terminate file send with an eof } }else if ( limit_parameter != "" ) { char *e = NULL; limit = strtol(limit_parameter.c_str(), &e, 10); if (e <= limit_parameter.c_str()) limit = -1; } // we have been asked to delay before cat, probably to allow time to issue upload command if(delay > 0) { safe_delay(delay*1000); } // Open file FILE *lp = fopen(filename.c_str(), "r"); if (lp == NULL) { stream->printf("File not found: %s\r\n", filename.c_str()); return; } string buffer; int c; int newlines = 0; int linecnt = 0; // Print each line of the file while ((c = fgetc (lp)) != EOF) { buffer.append((char *)&c, 1); if ( c == '\n' || ++linecnt > 80) { if(c == '\n') newlines++; stream->puts(buffer.c_str()); buffer.clear(); if(linecnt > 80) linecnt = 0; // we need to kick things or they die THEKERNEL->call_event(ON_IDLE); } if ( newlines == limit ) { break; } }; fclose(lp); if(send_eof) { stream->puts("\032"); // ^Z terminates the upload } }
// Delete a file void SimpleShell::rm_command( string parameters, StreamOutput *stream ) { const char *fn = absolute_from_relative(shift_parameter( parameters )).c_str(); int s = remove(fn); if (s != 0) stream->printf("Could not delete %s \r\n", fn); }