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 | } |
f80d18b9 L |
52 | } |
53 | ||
0b3e628f MM |
54 | void 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 |
59 | void 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 |
66 | void 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 |
87 | void 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 |
97 | void 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 |
107 | bool Conveyor::is_queue_empty() |
108 | { | |
109 | return queue.is_empty(); | |
68d16168 L |
110 | } |
111 | ||
2134bcf2 MM |
112 | void 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 | ||
124 | void 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 |
134 | void 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" | |
148 | template class HeapRing<Block>; |