Planner: make comments around recalculate() even more verbose
[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"
55456577 20#include "mri.h"
f80d18b9 21
0b3e628f
MM
22#define planner_queue_size_checksum CHECKSUM("planner_queue_size")
23
edac9072
AW
24// The conveyor holds the queue of blocks, takes care of creating them, and starting the executing chain of blocks
25
f80d18b9 26Conveyor::Conveyor(){
c501670b 27 gc_pending = queue.tail_i;
2134bcf2 28 running = false;
702023f3
MM
29}
30
d149c730 31void Conveyor::on_module_loaded(){
702023f3 32 register_for_event(ON_IDLE);
01b69353 33 register_for_event(ON_MAIN_LOOP);
0b3e628f
MM
34 register_for_event(ON_CONFIG_RELOAD);
35
36 on_config_reload(this);
702023f3
MM
37}
38
edac9072 39// Delete blocks here, because they can't be deleted in interrupt context ( see Block.cpp:release )
d149c730 40void Conveyor::on_idle(void* argument){
55456577 41 if (queue.tail_i != gc_pending)
c501670b 42 {
55456577
MM
43 if (queue.is_empty())
44 __debugbreak();
45 else
46 {
47 // Cleanly delete block
48 Block* block = queue.tail_ref();
9d005957 49// block->debug();
3ac0b99e 50 block->clear();
55456577
MM
51 queue.consume_tail();
52 }
702023f3 53 }
01b69353
MM
54}
55
56void Conveyor::on_main_loop(void*)
57{
58 if (running)
59 return;
60
61 if (queue.is_empty())
3facc890 62 {
3facc890
MM
63 if (queue.head_ref()->gcodes.size())
64 {
65 queue_head_block();
66 ensure_running();
67 }
68 }
36aca284
MM
69 else
70 // queue not empty
71 ensure_running();
f80d18b9
L
72}
73
0b3e628f
MM
74void Conveyor::on_config_reload(void* argument)
75{
76 queue.resize(THEKERNEL->config->value(planner_queue_size_checksum)->by_default(32)->as_number());
77}
78
e0ee24ed
MM
79void Conveyor::append_gcode(Gcode* gcode)
80{
81 gcode->mark_as_taken();
c87f8e07 82 queue.head_ref()->append_gcode(gcode);
e0ee24ed
MM
83}
84
f80d18b9 85// Process a new block in the queue
2134bcf2
MM
86void Conveyor::on_block_end(void* block)
87{
55456577
MM
88 if (queue.is_empty())
89 __debugbreak();
0b3e628f 90
2134bcf2 91 gc_pending = queue.next(gc_pending);
f80d18b9
L
92
93 // Return if queue is empty
2134bcf2
MM
94 if (gc_pending == queue.head_i)
95 {
96 running = false;
f80d18b9
L
97 return;
98 }
702023f3 99
f80d18b9 100 // Get a new block
2134bcf2 101 Block* next = this->queue.item_ref(gc_pending);
f80d18b9 102
2134bcf2 103 next->begin();
f80d18b9
L
104}
105
edac9072 106// Wait for the queue to have a given number of free blocks
c501670b
MM
107void Conveyor::wait_for_queue(int free_blocks)
108{
109 while (queue.is_full())
2134bcf2
MM
110 {
111 ensure_running();
314ab8f7 112 THEKERNEL->call_event(ON_IDLE);
2134bcf2 113 }
f80d18b9 114}
17c68379 115
edac9072 116// Wait for the queue to be empty
c501670b
MM
117void Conveyor::wait_for_empty_queue()
118{
119 while (!queue.is_empty())
2134bcf2
MM
120 {
121 ensure_running();
314ab8f7 122 THEKERNEL->call_event(ON_IDLE);
2134bcf2 123 }
17c68379
BG
124}
125
68d16168 126// Return true if the queue is empty
c501670b
MM
127bool Conveyor::is_queue_empty()
128{
129 return queue.is_empty();
68d16168
L
130}
131
2134bcf2
MM
132void Conveyor::queue_head_block()
133{
134 while (queue.is_full())
135 {
136 ensure_running();
137 THEKERNEL->call_event(ON_IDLE, this);
138 }
139
9d005957 140 queue.head_ref()->ready();
2134bcf2
MM
141 queue.produce_head();
142}
143
144void Conveyor::ensure_running()
145{
146 if (!running)
147 {
56a3ab89
MM
148 if (gc_pending == queue.head_i)
149 return;
150
2134bcf2 151 running = true;
56a3ab89 152 queue.item_ref(gc_pending)->begin();
2134bcf2
MM
153 }
154}
c501670b 155
a617ac35
MM
156// Debug function
157void Conveyor::dump_queue()
158{
159 for (unsigned int index = queue.tail_i, i = 0; true; index = queue.next(index), i++ )
160 {
161 THEKERNEL->streams->printf("block %03d > ", i);
162 queue.item_ref(index)->debug();
163
164 if (index == queue.head_i)
165 break;
166 }
167}
168
c501670b
MM
169// feels hacky, but apparently the way to do it
170#include "HeapRing.cpp"
171template class HeapRing<Block>;