Change Conveyor,Planner,Block to use HeapRing
[clinton/Smoothieware.git] / src / modules / robot / Conveyor.cpp
CommitLineData
f80d18b9
L
1/*
2 This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl) with additions from Sungeun K. Jeon (https://github.com/chamnit/grbl)
3 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.
4 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.
5 You should have received a copy of the GNU General Public License along with Smoothie. If not, see <http://www.gnu.org/licenses/>.
6*/
7
8using namespace std;
9#include <vector>
10#include "libs/nuts_bolts.h"
11#include "libs/RingBuffer.h"
12#include "../communication/utils/Gcode.h"
13#include "libs/Module.h"
14#include "libs/Kernel.h"
15#include "Timer.h" // mbed.h lib
16#include "wait_api.h" // mbed.h lib
17#include "Block.h"
18#include "Conveyor.h"
19#include "Planner.h"
20
edac9072
AW
21// The conveyor holds the queue of blocks, takes care of creating them, and starting the executing chain of blocks
22
f80d18b9
L
23Conveyor::Conveyor(){
24 this->current_block = NULL;
25 this->looking_for_new_block = false;
5bd37b4d
MM
26 queue.resize(32);
27 gc_pending = queue.tail_i;
702023f3
MM
28}
29
d149c730 30void Conveyor::on_module_loaded(){
702023f3
MM
31 register_for_event(ON_IDLE);
32}
33
edac9072 34// Delete blocks here, because they can't be deleted in interrupt context ( see Block.cpp:release )
d149c730 35void Conveyor::on_idle(void* argument){
5bd37b4d
MM
36 while (queue.tail_i != gc_pending)
37 {
6bb45cd1 38 // Cleanly delete block
5bd37b4d 39 Block* block = queue.tail_ref();
6bb45cd1 40 block->gcodes.clear();
5bd37b4d 41 queue.consume_tail();
702023f3 42 }
f80d18b9
L
43}
44
e0ee24ed
MM
45void Conveyor::append_gcode(Gcode* gcode)
46{
47 gcode->mark_as_taken();
5bd37b4d 48 if (queue.is_empty())
e0ee24ed
MM
49 THEKERNEL->call_event(ON_GCODE_EXECUTE, gcode);
50 else
5bd37b4d 51 queue.head_ref()->append_gcode(gcode);
e0ee24ed
MM
52}
53
f80d18b9
L
54// Append a block to the list
55Block* Conveyor::new_block(){
56
f80d18b9 57 // Take the next untaken block on the queue ( the one after the last one )
5bd37b4d 58 Block* block = this->queue.head_ref();
f80d18b9 59 // Then clean it up
1cf31736 60 block->clear();
702023f3 61
f80d18b9
L
62 block->initial_rate = -2;
63 block->final_rate = -2;
1cf31736
JM
64
65 // Create a new virgin Block in the queue
5bd37b4d 66 queue.produce_head();
6bb45cd1 67
f80d18b9
L
68 return block;
69}
70
71// Used by blocks to signal when they are ready to be used by the system
72void Conveyor::new_block_added(){
73 if( this->current_block == NULL ){
74 this->pop_and_process_new_block(33);
75 }
76}
77
78// Process a new block in the queue
79void Conveyor::pop_and_process_new_block(int debug){
80 if( this->looking_for_new_block ){ return; }
81 this->looking_for_new_block = true;
82
83 if( this->current_block != NULL ){ this->looking_for_new_block = false; return; }
84
85 // Return if queue is empty
5bd37b4d 86 if( queue.is_empty() ){
f80d18b9
L
87 this->current_block = NULL;
88 // TODO : ON_QUEUE_EMPTY event
89 this->looking_for_new_block = false;
90 return;
91 }
702023f3 92
f80d18b9 93 // Get a new block
5bd37b4d 94 this->current_block = this->queue.tail_ref();
f80d18b9
L
95
96 // Tell all modules about it
314ab8f7 97 THEKERNEL->call_event(ON_BLOCK_BEGIN, this->current_block);
702023f3 98
35089dc7 99 // In case the module was not taken
f80d18b9 100 if( this->current_block->times_taken < 1 ){
6bb45cd1
JM
101 Block* temp = this->current_block;
102 this->current_block = NULL; // It seems this was missing and adding it fixes things, if something breaks, this may be a suspect
103 temp->take();
12800c08 104 temp->release();
f80d18b9
L
105 }
106
107 this->looking_for_new_block = false;
108
109}
110
edac9072 111// Wait for the queue to have a given number of free blocks
5bd37b4d
MM
112void Conveyor::wait_for_queue(int free_blocks)
113{
114 while (queue.is_full())
314ab8f7 115 THEKERNEL->call_event(ON_IDLE);
f80d18b9 116}
17c68379 117
edac9072 118// Wait for the queue to be empty
5bd37b4d
MM
119void Conveyor::wait_for_empty_queue()
120{
121 while (!queue.is_empty())
314ab8f7 122 THEKERNEL->call_event(ON_IDLE);
17c68379
BG
123}
124
68d16168 125// Return true if the queue is empty
5bd37b4d
MM
126bool Conveyor::is_queue_empty()
127{
128 return queue.is_empty();
68d16168
L
129}
130
5bd37b4d
MM
131
132// feels hacky, but apparently the way to do it
133#include "HeapRing.cpp"
134template class HeapRing<Block>;