Commit | Line | Data |
---|---|---|
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 | ||
8 | using 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 | 26 | Conveyor::Conveyor(){ |
c501670b | 27 | gc_pending = queue.tail_i; |
2134bcf2 | 28 | running = false; |
702023f3 MM |
29 | } |
30 | ||
d149c730 | 31 | void 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 | 40 | void 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 | ||
56 | void 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 |
74 | void 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 |
79 | void 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 |
86 | void 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 |
107 | void 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 |
117 | void 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 |
127 | bool Conveyor::is_queue_empty() |
128 | { | |
129 | return queue.is_empty(); | |
68d16168 L |
130 | } |
131 | ||
2134bcf2 MM |
132 | void 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 | ||
144 | void 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 |
157 | void 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" | |
171 | template class HeapRing<Block>; |