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); |
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 | 39 | void 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 | } |
3facc890 MM |
52 | else if (queue.is_empty()) |
53 | { | |
54 | // if someone has appended gcodes but the queue is stopped | |
55 | // make sure they get executed in a timely fashion | |
56 | if (queue.head_ref()->gcodes.size()) | |
57 | { | |
58 | queue_head_block(); | |
59 | ensure_running(); | |
60 | } | |
61 | } | |
36aca284 MM |
62 | else |
63 | // queue not empty | |
64 | ensure_running(); | |
f80d18b9 L |
65 | } |
66 | ||
0b3e628f MM |
67 | void Conveyor::on_config_reload(void* argument) |
68 | { | |
69 | queue.resize(THEKERNEL->config->value(planner_queue_size_checksum)->by_default(32)->as_number()); | |
70 | } | |
71 | ||
e0ee24ed MM |
72 | void Conveyor::append_gcode(Gcode* gcode) |
73 | { | |
74 | gcode->mark_as_taken(); | |
c87f8e07 | 75 | queue.head_ref()->append_gcode(gcode); |
e0ee24ed MM |
76 | } |
77 | ||
f80d18b9 | 78 | // Process a new block in the queue |
2134bcf2 MM |
79 | void Conveyor::on_block_end(void* block) |
80 | { | |
55456577 MM |
81 | if (queue.is_empty()) |
82 | __debugbreak(); | |
0b3e628f | 83 | |
2134bcf2 | 84 | gc_pending = queue.next(gc_pending); |
f80d18b9 L |
85 | |
86 | // Return if queue is empty | |
2134bcf2 MM |
87 | if (gc_pending == queue.head_i) |
88 | { | |
89 | running = false; | |
f80d18b9 L |
90 | return; |
91 | } | |
702023f3 | 92 | |
f80d18b9 | 93 | // Get a new block |
2134bcf2 | 94 | Block* next = this->queue.item_ref(gc_pending); |
f80d18b9 | 95 | |
2134bcf2 | 96 | next->begin(); |
f80d18b9 L |
97 | } |
98 | ||
edac9072 | 99 | // Wait for the queue to have a given number of free blocks |
c501670b MM |
100 | void Conveyor::wait_for_queue(int free_blocks) |
101 | { | |
102 | while (queue.is_full()) | |
2134bcf2 MM |
103 | { |
104 | ensure_running(); | |
314ab8f7 | 105 | THEKERNEL->call_event(ON_IDLE); |
2134bcf2 | 106 | } |
f80d18b9 | 107 | } |
17c68379 | 108 | |
edac9072 | 109 | // Wait for the queue to be empty |
c501670b MM |
110 | void Conveyor::wait_for_empty_queue() |
111 | { | |
112 | while (!queue.is_empty()) | |
2134bcf2 MM |
113 | { |
114 | ensure_running(); | |
314ab8f7 | 115 | THEKERNEL->call_event(ON_IDLE); |
2134bcf2 | 116 | } |
17c68379 BG |
117 | } |
118 | ||
68d16168 | 119 | // Return true if the queue is empty |
c501670b MM |
120 | bool Conveyor::is_queue_empty() |
121 | { | |
122 | return queue.is_empty(); | |
68d16168 L |
123 | } |
124 | ||
2134bcf2 MM |
125 | void Conveyor::queue_head_block() |
126 | { | |
127 | while (queue.is_full()) | |
128 | { | |
129 | ensure_running(); | |
130 | THEKERNEL->call_event(ON_IDLE, this); | |
131 | } | |
132 | ||
133 | queue.produce_head(); | |
134 | } | |
135 | ||
136 | void Conveyor::ensure_running() | |
137 | { | |
138 | if (!running) | |
139 | { | |
140 | running = true; | |
141 | queue.tail_ref()->begin(); | |
142 | } | |
143 | } | |
c501670b | 144 | |
a617ac35 MM |
145 | // Debug function |
146 | void Conveyor::dump_queue() | |
147 | { | |
148 | for (unsigned int index = queue.tail_i, i = 0; true; index = queue.next(index), i++ ) | |
149 | { | |
150 | THEKERNEL->streams->printf("block %03d > ", i); | |
151 | queue.item_ref(index)->debug(); | |
152 | ||
153 | if (index == queue.head_i) | |
154 | break; | |
155 | } | |
156 | } | |
157 | ||
c501670b MM |
158 | // feels hacky, but apparently the way to do it |
159 | #include "HeapRing.cpp" | |
160 | template class HeapRing<Block>; |