most probably corrected the Extruder bug, which was actually a much deeper problem...
authorArthur Wolf <wolf.arthur@gmail.com>
Tue, 5 Mar 2013 22:02:31 +0000 (23:02 +0100)
committerArthur Wolf <wolf.arthur@gmail.com>
Tue, 5 Mar 2013 22:02:31 +0000 (23:02 +0100)
12 files changed:
src/libs/SlowTicker.cpp
src/makefile
src/modules/communication/GcodeDispatch.cpp
src/modules/communication/utils/Gcode.cpp
src/modules/communication/utils/Gcode.h
src/modules/robot/Block.cpp
src/modules/robot/Conveyor.cpp
src/modules/robot/Robot.cpp
src/modules/robot/Robot.h
src/modules/tools/extruder/Extruder.cpp
src/modules/tools/switch/Switch.cpp
src/modules/tools/temperaturecontrol/TemperatureControl.cpp

index 0d7e8ea..73b1b7a 100644 (file)
@@ -124,7 +124,6 @@ void SlowTicker::on_gcode_received(void* argument){
         }else{
             Block* block = this->kernel->conveyor->queue.get_ref( this->kernel->conveyor->queue.size() - 1 );
             block->append_gcode(gcode);
-            gcode->queued++;
         }
     }
 }    
index d95c2dc..8976baf 100644 (file)
@@ -6,7 +6,7 @@ DEVICES=lpc1768
 #  Checked - Optimizations enabled with MRI debug monitor support. (Recommended Type)\r
 #  Release - Optimizations enabled.\r
 #  Debug - Optimization disabled with MRI debug monitor support.\r
-BUILD_TYPE=Checked\r
+BUILD_TYPE=Debug\r
 \r
 # Set to 1 to tag each heap allocation with the caller's return address.\r
 # NOTE: Can't be enabled with latest build as not compatible with newlib nano.\r
index d7f51e6..1c931da 100644 (file)
@@ -102,8 +102,13 @@ void GcodeDispatch::on_console_line_received(void * line){
                     new_message.stream->printf("\r\n");
                 new_message.stream->printf("ok\r\n");
 
-                if (gcode->queued == 0)
+                // This is part of a pretty complicated thing, see Gcode.h for a long explanation
+                if( gcode->will_go_thru_new_block_context == true && gcode->passed_thru_new_block_context_without_deleting == true ){
                     delete gcode;
+                }else{
+                    gcode->passed_thru_all_blocks_added_context_without_deleting = true;
+                }
+            
             }
         }else{
             //Request resend
index 0d8d32d..689d745 100644 (file)
@@ -15,11 +15,9 @@ using std::string;
 #include <stdlib.h>
 
 
-Gcode::Gcode(const string& command, StreamOutput* stream) :
-  command(command), m(0), g(0), add_nl(false),
-  queued(0), stream(stream)
-{
+Gcode::Gcode(const string& command, StreamOutput* stream) : command(command), m(0), g(0), add_nl(false), will_go_thru_new_block_context(false), stream(stream), passed_thru_all_blocks_added_context_without_deleting(false), passed_thru_new_block_context_without_deleting(false){
     prepare_cached_values();
+    this->millimeters_of_travel = 0L;
 }
 
 // Whether or not a Gcode has a letter
index e0a6589..6aed1a6 100644 (file)
@@ -39,9 +39,42 @@ class Gcode {
         unsigned int g;
 
         bool add_nl;
+        StreamOutput* stream;
+        
+        // This requires a long explanation, unfortunately. We have the hard job to delete the gcode at the right momont.
+        // The problem is that we can not delete the gcode before no modules wants to use/read it anymore. This gets complicated because there are actually two possible end moments 
+        // of the life of the gcode, and they can happen in either order. So if one deletes it first, the other can not access it. The last context to use it is the one that must delete it, 
+        // but it's not always the same.
+        // Here is a resume of the life of a Gcode object : 
+        // * Gets created inside GcodeDispatch
+        // * Is passed along with the on_gcode_received event to all modules. We'll ignore all other modules and just concentrate on Robot
+        // * Robot computes the distance for this gcode, if there is none, it just returns, otherwise : 
+        // * If the queue is empty, we execute the gcode right away ( on_gcode_execute ), it is not attached to the queue, then we add blocks to the queue and they start getting executed
+        // * If the queue is not empty however, we attach the gcode to the last block on the queue, then start adding blocks to the queue. This does the same as the line above, but with the queue already running, things happen later instead of immediately.
+        // * Now we return to GcodeDispatch. 
+        // The problem when we get there is this : if we attached the Gcode to a block in the Queue, We don't know now if it has been executed or not. Usually, it hasn't : we just added it to the queue and the queue has not gotton to it yet.
+        // In that case, we can obviously not delete it right here : the queue still needs it to execute it. So why not delete it when it gets executed ?
+        // Because there is one case with which we can get here, and the gcode *has* been executed already. That's in the case this gcode string appened so many blocks to the queue, that in order to make room for the later blocks
+        // we waited for the earlier ones to get consumed. In that case, the gcode will get executed when we get to it doing that.
+        // So, we can't *always* delete the gcode when it gets executed, and we can't *always* delete the gcode when we get back to GcodeDispatch.
+        // So, there are two places we can delete the Gcode, let's call them : 
+        // * NEW BLOCK CONTEXT ( when the queue has executed this gcode and can delete it ( actually two places, one in on_idle, the other when recycling a block for re-use, see Conveyor.cpp )
+        // * ALL BLOCKS ADDED CONTEXT ( when we return to GcodeDispatch after the on_gcode_received call, we know all blocks that would be added for this gcode have been )
+        // Now the trick here is basically : In any given context, we want to delete the gcode 
+        // * If we reach the current context and the other context was not supposed to happen
+        // * If we reach the current context and the other context did happen
+        // In either of these cases, we want delete the gcode, otherwise, we want to mark the gcode as having passed thru the current context so that when we reach that other context, the gcode gets deleted
+        // There is a complication/simplification here : the ALL_BLOCKS_ADDED context will always occur for a given gcode. That's a condition that will always be true, and a flag we don't need to keep track of.
+        // The other one however, will only occur if the block is added to the queue. It will not otherwise.
+        // So we use a flag to keep track of that
+        bool will_go_thru_new_block_context;               // Defaults to false
+        // Now for each context, we need a flag ( defaulting to false ) that is set to true when we go thru that context without deleting the Gcode.
+        bool passed_thru_new_block_context_without_deleting;
+        bool passed_thru_all_blocks_added_context_without_deleting;
+
+
+
 
-        int queued;
 
-        StreamOutput* stream;
 };
 #endif
index f0f8e2d..5e248d3 100644 (file)
@@ -166,6 +166,7 @@ void Block::forward_pass(Block* previous, Block* next){
 // Gcodes are attached to their respective blocks so that on_gcode_execute can be called with it
 void Block::append_gcode(Gcode* gcode){
    __disable_irq();
+   gcode->will_go_thru_new_block_context = true;
    this->gcodes.push_back(gcode);
    __enable_irq();
 }
index 88b2ccb..0fcd9a5 100644 (file)
@@ -24,22 +24,26 @@ Conveyor::Conveyor(){
     flush_blocks = 0;
 }
 
-void Conveyor::on_module_loaded()
-{
+void Conveyor::on_module_loaded(){
     register_for_event(ON_IDLE);
 }
 
-void Conveyor::on_idle(void* argument)
-{
-    if (flush_blocks)
-    {
+void Conveyor::on_idle(void* argument){
+    if (flush_blocks){
+
         Block* block = queue.get_tail_ref();
-//         printf("Block: clean %p\n", block);
-        while (block->gcodes.size())
-        {
-            Gcode* g = block->gcodes.back();
+        while (block->gcodes.size()){
+            Gcode* gcode = block->gcodes.back();
             block->gcodes.pop_back();
-            delete g;
+        
+            // Do we just delete this gcode from this vector, or do we also actually delete the gcode ?
+            // This is pretty complex and explained in detail in Gcode.h 
+            if( gcode->passed_thru_all_blocks_added_context_without_deleting == true ){
+                delete gcode;
+            }else{
+                gcode->passed_thru_new_block_context_without_deleting = false;
+            }
+        
         }
         queue.delete_first();
 
@@ -61,9 +65,17 @@ Block* Conveyor::new_block(){
     // Then clean it up
     if( block->conveyor == this ){
         for(; block->gcodes.size(); ){
-            Gcode* g = block->gcodes.back();
+            Gcode* gcode = block->gcodes.back();
             block->gcodes.pop_back();
-            delete g;
+        
+            // Do we just delete this gcode from this vector, or do we also actually delete the gcode ?
+            // This is pretty complex and explained in detail in Gcode.h 
+            if( gcode->passed_thru_all_blocks_added_context_without_deleting == true ){
+                delete gcode;
+            }else{
+                gcode->passed_thru_new_block_context_without_deleting = false;
+            }
+       
         }
     }
 
index 7855f64..9a16461 100644 (file)
@@ -52,23 +52,20 @@ void Robot::on_config_reload(void* argument){
     if (this->arm_solution) delete this->arm_solution;
     int solution_checksum = get_checksum(this->kernel->config->value(arm_solution_checksum)->by_default("cartesian")->as_string());
 
-       // Note checksums are not const expressions when in debug mode, so don't use switch
-       if(solution_checksum == rostock_checksum) {
-               this->arm_solution = new RostockSolution(this->kernel->config);
-
-       }else if(solution_checksum ==  delta_checksum) {
-               // place holder for now
-               this->arm_solution = new RostockSolution(this->kernel->config);
-
+    // Note checksums are not const expressions when in debug mode, so don't use switch
+    if(solution_checksum == rostock_checksum) {
+            this->arm_solution = new RostockSolution(this->kernel->config);
+    }else if(solution_checksum ==  delta_checksum) {
+            // place holder for now
+            this->arm_solution = new RostockSolution(this->kernel->config);
     }else if(solution_checksum == rotatable_cartesian_checksum) {
         this->arm_solution = new RotatableCartesianSolution(this->kernel->config);
 
-       }else if(solution_checksum == cartesian_checksum) {
-               this->arm_solution = new CartesianSolution(this->kernel->config);
-
-       }else{
-               this->arm_solution = new CartesianSolution(this->kernel->config);
-       }
+    }else if(solution_checksum == cartesian_checksum) {
+            this->arm_solution = new CartesianSolution(this->kernel->config);
+    }else{
+            this->arm_solution = new CartesianSolution(this->kernel->config);
+    }
 
 
     this->feed_rate           = this->kernel->config->value(default_feed_rate_checksum   )->by_default(100    )->as_number() / 60;
@@ -91,34 +88,32 @@ void Robot::on_config_reload(void* argument){
 
 }
 
+//#pragma GCC push_options
+//#pragma GCC optimize ("O0")
+
+
 //A GCode has been received
 void Robot::on_gcode_received(void * argument){
     Gcode* gcode = static_cast<Gcode*>(argument);
+    this->process_gcode(gcode);
+}
 
-    // If this gcode is a movement gcode
-    if( gcode->has_g && gcode->g < 4 && ( gcode->has_letter('X') || gcode->has_letter('Y') || gcode->has_letter('Z') ) ){
-        gcode->call_on_gcode_execute_event_immediatly = false;
-        gcode->on_gcode_execute_event_called = false;
-        //If the queue is empty, execute immediatly, otherwise attach to the last added block
-        if( this->kernel->conveyor->queue.size() == 0 ){
-            gcode->call_on_gcode_execute_event_immediatly = true;
-            this->process_gcode(gcode);
-            if( gcode->on_gcode_execute_event_called == false ){
-                //printf("GCODE A: %s \r\n", gcode->command.c_str() );
-                this->kernel->call_event(ON_GCODE_EXECUTE, gcode );
-            }
-        }else{
-            Block* block = this->kernel->conveyor->queue.get_ref( this->kernel->conveyor->queue.size() - 1 );
-            this->process_gcode(gcode);
-            block->append_gcode(gcode);
-            gcode->queued++;
-        }
+// We called process_gcode with a new gcode, and one of the functions 
+// determined the distance for that given gcode. So now we can attach this gcode to the right block
+// and continue
+void Robot::distance_in_gcode_is_known(Gcode* gcode){
 
+    //If the queue is empty, execute immediatly, otherwise attach to the last added block
+    if( this->kernel->conveyor->queue.size() == 0 ){
+        this->kernel->call_event(ON_GCODE_EXECUTE, gcode );
     }else{
-        this->process_gcode(gcode);
+        Block* block = this->kernel->conveyor->queue.get_ref( this->kernel->conveyor->queue.size() - 1 );
+        block->append_gcode(gcode);
     }
+
 }
 
+//#pragma GCC pop_options
 
 void Robot::reset_axis_position(double position, int axis) {
     this->last_milestone[axis] = this->current_position[axis] = position;
@@ -270,16 +265,13 @@ void Robot::append_line(Gcode* gcode, double target[], double rate ){
     // In cartesian robot, a high "mm_per_line_segment" setting will prevent waste.
     gcode->millimeters_of_travel = sqrt( pow( target[X_AXIS]-this->current_position[X_AXIS], 2 ) +  pow( target[Y_AXIS]-this->current_position[Y_AXIS], 2 ) +  pow( target[Z_AXIS]-this->current_position[Z_AXIS], 2 ) );
 
-    if( gcode->call_on_gcode_execute_event_immediatly == true ){
+    //if( gcode->call_on_gcode_execute_event_immediatly == true ){
             //printf("GCODE B: %s \r\n", gcode->command.c_str() );
-            this->kernel->call_event(ON_GCODE_EXECUTE, gcode );
-            gcode->on_gcode_execute_event_called = true;
-    }
+    //        this->kernel->call_event(ON_GCODE_EXECUTE, gcode );
+    //        gcode->on_gcode_execute_event_called = true;
+    //}
+    this->distance_in_gcode_is_known( gcode );
 
-    if (gcode->millimeters_of_travel == 0.0) {
-        this->append_milestone(this->current_position, 0.0);
-        return;
-    }
 
     uint16_t segments = ceil( gcode->millimeters_of_travel/ this->mm_per_line_segment);
     // A vector to keep track of the endpoint of each segment
@@ -313,16 +305,20 @@ void Robot::append_arc(Gcode* gcode, double target[], double offset[], double ra
 
     gcode->millimeters_of_travel = hypot(angular_travel*radius, fabs(linear_travel));
 
-    if( gcode->call_on_gcode_execute_event_immediatly == true ){
+    //if( gcode->call_on_gcode_execute_event_immediatly == true ){
             //printf("GCODE C: %s \r\n", gcode->command.c_str() );
-            this->kernel->call_event(ON_GCODE_EXECUTE, gcode );
-            gcode->on_gcode_execute_event_called = true;
-    }
+    //        this->kernel->call_event(ON_GCODE_EXECUTE, gcode );
+    //        gcode->on_gcode_execute_event_called = true;
+    //}
 
+    this->distance_in_gcode_is_known( gcode );
+    
+    /* 
     if (gcode->millimeters_of_travel == 0.0) {
         this->append_milestone(this->current_position, 0.0);
         return;
     }
+    */
 
     uint16_t segments = floor(gcode->millimeters_of_travel/this->mm_per_arc_segment);
 
index 123d13b..a4b4425 100644 (file)
@@ -65,6 +65,7 @@ class Robot : public Module {
         void reset_axis_position(double position, int axis);
 
     private:
+        void distance_in_gcode_is_known(Gcode* gcode);
         void process_gcode(Gcode* gcode);
         void append_milestone( double target[], double feed_rate);
         void append_line( Gcode* gcode, double target[], double feed_rate);
index 5c92613..f2d2343 100644 (file)
@@ -113,7 +113,6 @@ void Extruder::on_gcode_received(void *argument)
         }else{
             Block* block = this->kernel->conveyor->queue.get_ref( this->kernel->conveyor->queue.size() - 1 );
             block->append_gcode(gcode);
-            gcode->queued++;
         }
     }
 
@@ -126,12 +125,15 @@ void Extruder::on_gcode_received(void *argument)
                 this->kernel->call_event(ON_GCODE_EXECUTE, gcode );
                 this->append_empty_block();
             }else{
-                Block* block = this->kernel->conveyor->queue.get_ref( this->kernel->conveyor->queue.size() - 1 );
                 this->append_empty_block();
+                Block* block = this->kernel->conveyor->queue.get_ref( this->kernel->conveyor->queue.size() - 1 );
                 block->append_gcode(gcode);
-                gcode->queued++;
             }
         }
+    }else{
+        // This is for follow move
+
+
     }
 }
 
@@ -148,6 +150,8 @@ void Extruder::append_empty_block(){
     block->ready();
 }
 
+//#pragma GCC push_options
+//#pragma GCC optimize ("O0")
 
 // Compute extrusion speed based on parameters and gcode distance of travel
 void Extruder::on_gcode_execute(void* argument){
@@ -210,6 +214,8 @@ void Extruder::on_gcode_execute(void* argument){
     }
 }
 
+//#pragma GCC pop_options
+
 // When a new block begins, either follow the robot, or step by ourselves ( or stay back and do nothing )
 void Extruder::on_block_begin(void* argument){
     Block* block = static_cast<Block*>(argument);
@@ -236,40 +242,30 @@ void Extruder::on_block_begin(void* argument){
             this->stepper_motor->steps_per_second = 0;
             this->stepper_motor->move( ( this->travel_distance > 0 ), steps_to_step);
 
+        }else{
+            this->current_block = NULL;
         }
 
-
     }else if( this->mode == FOLLOW ){
         // In non-solo mode, we just follow the stepper module
-
         this->current_block = block;
         this->target_position =  this->current_position + ( this->current_block->millimeters * this->travel_ratio );
 
-        //int32_t steps_to_step = abs( int( floor(this->steps_per_millimeter*this->target_position) - floor(this->steps_per_millimeter*this->current_position) ) );
-
         int old_steps = this->current_steps;
         int target_steps = int( floor(this->steps_per_millimeter*this->target_position) );
         int steps_to_step = target_steps - old_steps ;
         this->current_steps = target_steps;
 
-
         if( steps_to_step != 0 ){
-
-            //printf("taken for extruder: %u \r\n", steps_to_step);
-
             block->take();
-
-            //printf("spm:%f td:%f steps:%d ( %f - %f ) \r\n", this->steps_per_millimeter, this->travel_distance,  steps_to_step, this->target_position, this->current_position  );
-
             this->stepper_motor->move( ( steps_to_step > 0 ), abs(steps_to_step) );
-
-
-
+        }else{
+            this->current_block = NULL;
         }
 
     }else if( this->mode == OFF ){
         // No movement means we must reset our speed
-
+        this->current_block = NULL;
         //this->stepper_motor->set_speed(0);
 
     }
@@ -329,8 +325,11 @@ uint32_t Extruder::stepper_motor_finished_move(uint32_t dummy){
 
     this->current_position = this->target_position;
 
-    if (this->current_block) // this should always be true, but sometimes it isn't. TODO: find out why
-        this->current_block->release();
+    if (this->current_block){ // this should always be true, but sometimes it isn't. TODO: find out why
+        Block* block = this->current_block; 
+        this->current_block = NULL;
+        block->release();
+    } 
     return 0;
 
 }
index 0c4acc4..3aae715 100644 (file)
@@ -53,7 +53,6 @@ void Switch::on_gcode_received(void* argument){
         }else{
             Block* block = this->kernel->conveyor->queue.get_ref( this->kernel->conveyor->queue.size() - 1 );
             block->append_gcode(gcode);
-            gcode->queued++;
         }
     }
 }
index fe758d7..d8df67c 100644 (file)
@@ -160,8 +160,8 @@ void TemperatureControl::on_gcode_received(void* argument){
             }else{
                 Block* block = this->kernel->conveyor->queue.get_ref( this->kernel->conveyor->queue.size() - 1 );
                 block->append_gcode(gcode);
-                gcode->queued++;
             }
+            
         }
     }
 }