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