Block: if no-one takes our block, release immediately
[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);
0b3e628f
MM
33 register_for_event(ON_CONFIG_RELOAD);
34
35 on_config_reload(this);
702023f3
MM
36}
37
edac9072 38// Delete blocks here, because they can't be deleted in interrupt context ( see Block.cpp:release )
d149c730 39void Conveyor::on_idle(void* argument){
55456577 40 if (queue.tail_i != gc_pending)
c501670b 41 {
55456577
MM
42 if (queue.is_empty())
43 __debugbreak();
44 else
45 {
46 // Cleanly delete block
47 Block* block = queue.tail_ref();
48 block->gcodes.clear();
49 queue.consume_tail();
50 }
702023f3 51 }
f80d18b9
L
52}
53
0b3e628f
MM
54void Conveyor::on_config_reload(void* argument)
55{
56 queue.resize(THEKERNEL->config->value(planner_queue_size_checksum)->by_default(32)->as_number());
57}
58
e0ee24ed
MM
59void Conveyor::append_gcode(Gcode* gcode)
60{
61 gcode->mark_as_taken();
c87f8e07 62 queue.head_ref()->append_gcode(gcode);
e0ee24ed
MM
63}
64
f80d18b9 65// Process a new block in the queue
2134bcf2
MM
66void Conveyor::on_block_end(void* block)
67{
55456577
MM
68 if (queue.is_empty())
69 __debugbreak();
0b3e628f 70
2134bcf2 71 gc_pending = queue.next(gc_pending);
f80d18b9
L
72
73 // Return if queue is empty
2134bcf2
MM
74 if (gc_pending == queue.head_i)
75 {
76 running = false;
f80d18b9
L
77 return;
78 }
702023f3 79
f80d18b9 80 // Get a new block
2134bcf2 81 Block* next = this->queue.item_ref(gc_pending);
f80d18b9 82
2134bcf2 83 next->begin();
f80d18b9
L
84}
85
edac9072 86// Wait for the queue to have a given number of free blocks
c501670b
MM
87void Conveyor::wait_for_queue(int free_blocks)
88{
89 while (queue.is_full())
2134bcf2
MM
90 {
91 ensure_running();
314ab8f7 92 THEKERNEL->call_event(ON_IDLE);
2134bcf2 93 }
f80d18b9 94}
17c68379 95
edac9072 96// Wait for the queue to be empty
c501670b
MM
97void Conveyor::wait_for_empty_queue()
98{
99 while (!queue.is_empty())
2134bcf2
MM
100 {
101 ensure_running();
314ab8f7 102 THEKERNEL->call_event(ON_IDLE);
2134bcf2 103 }
17c68379
BG
104}
105
68d16168 106// Return true if the queue is empty
c501670b
MM
107bool Conveyor::is_queue_empty()
108{
109 return queue.is_empty();
68d16168
L
110}
111
2134bcf2
MM
112void Conveyor::queue_head_block()
113{
114 while (queue.is_full())
115 {
116 ensure_running();
117 THEKERNEL->call_event(ON_IDLE, this);
118 }
119
120 queue.produce_head();
c87f8e07 121 ensure_running();
2134bcf2
MM
122}
123
124void Conveyor::ensure_running()
125{
126 if (!running)
127 {
128 running = true;
129 queue.tail_ref()->begin();
130 }
131}
c501670b 132
a617ac35
MM
133// Debug function
134void Conveyor::dump_queue()
135{
136 for (unsigned int index = queue.tail_i, i = 0; true; index = queue.next(index), i++ )
137 {
138 THEKERNEL->streams->printf("block %03d > ", i);
139 queue.item_ref(index)->debug();
140
141 if (index == queue.head_i)
142 break;
143 }
144}
145
c501670b
MM
146// feels hacky, but apparently the way to do it
147#include "HeapRing.cpp"
148template class HeapRing<Block>;