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