Merge remote-tracking branch 'upstream/edge' into upstreamedge
authorJim Morris <morris@wolfman.com>
Wed, 3 Oct 2018 17:31:05 +0000 (18:31 +0100)
committerJim Morris <morris@wolfman.com>
Wed, 3 Oct 2018 17:31:05 +0000 (18:31 +0100)
src/libs/USBDevice/USBSerial/USBSerial.cpp
src/libs/USBDevice/USBSerial/USBSerial.h
src/modules/communication/GcodeDispatch.cpp
src/modules/robot/Conveyor.h
src/modules/utils/player/Player.cpp
src/modules/utils/simpleshell/SimpleShell.cpp
src/modules/utils/simpleshell/SimpleShell.h

index c308d67..95fc8f3 100644 (file)
@@ -25,6 +25,8 @@
 #include "libs/SerialMessage.h"
 #include "StreamOutputPool.h"
 
+#include "mbed.h"
+
 // extern void setled(int, bool);
 #define setled(a, b) do {} while (0)
 
@@ -41,20 +43,28 @@ USBSerial::USBSerial(USB *u): USBCDC(u), rxbuf(256 + 8), txbuf(128 + 8)
     last_char_was_dollar = false;
 }
 
-void USBSerial::ensure_tx_space(int space)
+bool USBSerial::ensure_tx_space(int space)
 {
+    // we need some kind of timeout here or it will hang if upstream stalls
+    uint32_t start = us_ticker_read();
     while (txbuf.free() < space) {
+        if((us_ticker_read() - start) > 1000000) {
+            // 1 second timeout
+            return false;
+        }
         usb->endpointSetInterrupt(CDC_BulkIn.bEndpointAddress, true);
         usb->usbisr();
     }
+    return true;
 }
 
 int USBSerial::_putc(int c)
 {
     if (!attached)
         return 1;
-    ensure_tx_space(1);
-    txbuf.queue(c);
+    if(ensure_tx_space(1)) {
+        txbuf.queue(c);
+    }
 
     usb->endpointSetInterrupt(CDC_BulkIn.bEndpointAddress, true);
     return 1;
@@ -91,7 +101,7 @@ int USBSerial::puts(const char *str)
         return strlen(str);
     int i = 0;
     while (*str) {
-        ensure_tx_space(1);
+        if(!ensure_tx_space(1)) break;
         txbuf.queue(*str);
         if ((txbuf.available() % 64) == 0)
             usb->endpointSetInterrupt(CDC_BulkIn.bEndpointAddress, true);
index bf4669a..ec4b126 100644 (file)
@@ -61,7 +61,7 @@ protected:
     virtual void on_attach(void);\r
     virtual void on_detach(void);\r
 \r
-    void ensure_tx_space(int);\r
+    bool ensure_tx_space(int);\r
 \r
     // keep track of number of newlines in the buffer\r
     // this makes it trivial to detect if there's a new line available\r
index 566df56..a2f78ed 100644 (file)
@@ -31,7 +31,7 @@
 #define panel_checksum             CHECKSUM("panel")
 
 // goes in Flash, list of Mxxx codes that are allowed when in Halted state
-static const int allowed_mcodes[]= {2,5,9,30,105,114,119,80,81,911,503,106,107}; // get temp, get pos, get endstops etc
+static const int allowed_mcodes[]= {2,5,9,30,105,114,115,119,80,81,911,503,106,107}; // get temp, get pos, get endstops etc
 static bool is_allowed_mcode(int m) {
     for (size_t i = 0; i < sizeof(allowed_mcodes)/sizeof(int); ++i) {
         if(allowed_mcodes[i] == m) return true;
@@ -461,6 +461,10 @@ try_again:
             new_message.stream->printf("rs N%d\r\n", nextline);
         }
 
+    } else if ( first_char == ';' || first_char == '(' || first_char == '\n' || first_char == '\r' ) {
+        // Ignore comments and blank lines
+        new_message.stream->printf("ok\n");
+
     } else if( (n=possible_command.find_first_of("XYZF")) == 0 || (first_char == ' ' && n != string::npos) ) {
         // handle pycam syntax, use last modal group 1 command and resubmit if an X Y Z or F is found on its own line
         char buf[6];
@@ -468,9 +472,6 @@ try_again:
         possible_command.insert(0, buf);
         goto try_again;
 
-    } else if ( first_char == ';' || first_char == '(' || first_char == ' ' || first_char == '\n' || first_char == '\r' ) {
-        // Ignore comments and blank lines
-        new_message.stream->printf("ok\n");
 
     } else {
         // an uppercase non command word on its own (except XYZF) just returns ok, we could add an error but no hosts expect that.
index 9bfbb54..1418188 100644 (file)
@@ -34,6 +34,7 @@ public:
     void dump_queue(void);
     void flush_queue(void);
     float get_current_feedrate() const { return current_feedrate; }
+    void force_queue() { check_queue(true); }
 
     friend class Planner; // for queue
 
index a1dacef..fe35307 100644 (file)
@@ -80,7 +80,7 @@ void Player::on_halt(void* argument)
     if(argument == nullptr && this->playing_file ) {
         abort_command("1", &(StreamOutput::NullStream));
        }
-       
+
        if(argument == nullptr && this->suspended) {
                // clean up from suspend
                this->suspended= false;
@@ -88,6 +88,7 @@ void Player::on_halt(void* argument)
                this->saved_temperatures.clear();
                this->was_playing_file= false;
                this->suspend_loops= 0;
+               THEKERNEL->streams->printf("// Suspend cleared\n");
        }
 }
 
@@ -520,7 +521,7 @@ void Player::suspend_command(string parameters, StreamOutput *stream )
         return;
     }
 
-    stream->printf("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");
@@ -548,6 +549,12 @@ void Player::suspend_part2()
     // wait for queue to empty
     THEKERNEL->conveyor->wait_for_idle();
 
+    if(THEKERNEL->is_halted()) {
+        THEKERNEL->streams->printf("Suspend aborted by kill\n");
+        suspended= false;
+        return;
+    }
+
     THEKERNEL->streams->printf("// Saving current state...\n");
 
     // save current XYZ position
@@ -608,7 +615,7 @@ void Player::resume_command(string parameters, StreamOutput *stream )
         return;
     }
 
-    stream->printf("resuming print...\n");
+    stream->printf("// resuming print...\n");
 
     // wait for them to reach temp
     if(!this->saved_temperatures.empty()) {
@@ -617,7 +624,7 @@ void Player::resume_command(string parameters, StreamOutput *stream )
             float t= h.second;
             PublicData::set_value( temperature_control_checksum, h.first, &t );
         }
-        stream->printf("Waiting for heaters...\n");
+        stream->printf("// Waiting for heaters...\n");
         bool wait= true;
         uint32_t tus= us_ticker_read(); // mbed call
         while(wait) {
@@ -653,9 +660,19 @@ void Player::resume_command(string parameters, StreamOutput *stream )
         }
     }
 
+    // clean up
+    this->saved_temperatures.clear();
+
+    if(THEKERNEL->is_halted()) {
+        THEKERNEL->streams->printf("Resume aborted by kill\n");
+        THEROBOT->pop_state();
+        suspended= false;
+        return;
+    }
+
     // execute optional gcode if defined
     if(!before_resume_gcode.empty()) {
-        stream->printf("Executing before resume gcode...\n");
+        stream->printf("// Executing before resume gcode...\n");
         struct SerialMessage message;
         message.message = before_resume_gcode;
         message.stream = &(StreamOutput::NullStream);
@@ -663,7 +680,7 @@ void Player::resume_command(string parameters, StreamOutput *stream )
     }
 
     // Restore position
-    stream->printf("Restoring saved XYZ positions and state...\n");
+    stream->printf("// Restoring saved XYZ positions and state...\n");
     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
@@ -682,7 +699,13 @@ void Player::resume_command(string parameters, StreamOutput *stream )
     // restore extruder state
     PublicData::set_value( extruder_checksum, restore_state_checksum, nullptr );
 
-    stream->printf("Resuming print\n");
+   if(THEKERNEL->is_halted()) {
+        THEKERNEL->streams->printf("Resume aborted by kill\n");
+        suspended= false;
+        return;
+    }
+
+    stream->printf("// Resuming print\n");
 
     if(this->was_playing_file) {
         this->playing_file = true;
@@ -692,7 +715,5 @@ void Player::resume_command(string parameters, StreamOutput *stream )
         THEKERNEL->streams->printf("// action:resume\r\n");
     }
 
-    // clean up
-    this->saved_temperatures.clear();
-    suspended= false;
+   suspended= false;
 }
index 3821d14..b11f031 100644 (file)
@@ -12,7 +12,7 @@
 #include "libs/utils.h"
 #include "libs/SerialMessage.h"
 #include "libs/StreamOutput.h"
-#include "modules/robot/Conveyor.h"
+#include "Conveyor.h"
 #include "DirHandle.h"
 #include "mri.h"
 #include "version.h"
@@ -216,7 +216,7 @@ void SimpleShell::on_console_line_received( void *argument )
             case 'G':
                 // issue get state
                 get_command("state", new_message.stream);
-                new_message.stream->printf("ok\n");
+                //new_message.stream->printf("ok\n"); // sending this while printing will cause ok count to get out of sync
                 break;
 
             case 'X':
@@ -244,6 +244,11 @@ void SimpleShell::on_console_line_received( void *argument )
                 new_message.stream->printf("ok\n");
                 break;
 
+            case 'J':
+                // instant jog command
+                jog(possible_command, new_message.stream);
+                break;
+
             default:
                 new_message.stream->printf("error:Invalid statement\n");
                 break;
@@ -1131,6 +1136,56 @@ void SimpleShell::test_command( string parameters, StreamOutput *stream)
     }
 }
 
+void SimpleShell::jog(string parameters, StreamOutput *stream)
+{
+    // $J X0.1 F0.5
+    int n_motors= THEROBOT->get_number_registered_motors();
+
+    // get axis to move and amount (X0.1)
+    // for now always 1 axis
+    size_t npos= parameters.find_first_of("XYZABC");
+    if(npos == string::npos) {
+        stream->printf("usage: $J X|Y|Z|A|B|C 0.01 [F0.5]\n");
+        return;
+    }
+
+    string s = parameters.substr(npos);
+    if(s.empty() || s.size() < 2) {
+        stream->printf("usage: $J X0.01 [F0.5]\n");
+        return;
+    }
+    char ax= toupper(s[0]);
+    uint8_t a= ax >= 'X' ? ax - 'X' : ax - 'A' + 3;
+    if(a >= n_motors) {
+        stream->printf("error:bad axis\n");
+        return;
+    }
+
+    float d= strtof(s.substr(1).c_str(), NULL);
+
+    float delta[n_motors];
+    for (int i = 0; i < n_motors; ++i) {
+        delta[i]= 0;
+    }
+    delta[a]= d;
+
+    // get speed scale
+    float scale= 1.0F;
+    npos= parameters.find_first_of("F");
+    if(npos != string::npos && npos+1 < parameters.size()) {
+        scale= strtof(parameters.substr(npos+1).c_str(), NULL);
+    }
+
+    THEROBOT->push_state();
+    float rate_mm_s= THEROBOT->actuators[a]->get_max_rate() * scale;
+    THEROBOT->delta_move(delta, rate_mm_s, n_motors);
+
+    // turn off queue delay and run it now
+    THECONVEYOR->force_queue();
+    THEROBOT->pop_state();
+    //stream->printf("Jog: %c%f F%f\n", ax, d, scale);
+}
+
 void SimpleShell::help_command( string parameters, StreamOutput *stream )
 {
     stream->printf("Commands:\r\n");
index a1d3be3..5f85346 100644 (file)
@@ -29,6 +29,9 @@ public:
     static void version_command(string parameters, StreamOutput *stream );
 
 private:
+
+    void jog(string params, StreamOutput *stream);
+
     static void ls_command(string parameters, StreamOutput *stream );
     static void cd_command(string parameters, StreamOutput *stream );
     static void delete_file_command(string parameters, StreamOutput *stream );