Commit | Line | Data |
---|---|---|
3105a7be | 1 | /* |
35089dc7 JM |
2 | This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/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. | |
3105a7be | 5 | You should have received a copy of the GNU General Public License along with Smoothie. If not, see <http://www.gnu.org/licenses/>. |
35089dc7 JM |
6 | */ |
7 | ||
8 | #include "libs/Kernel.h" | |
9 | #include "Panel.h" | |
10 | #include "PanelScreen.h" | |
11 | #include "MainMenuScreen.h" | |
12 | #include "WatchScreen.h" | |
13 | #include "libs/nuts_bolts.h" | |
14 | #include "libs/utils.h" | |
15 | #include "modules/tools/temperaturecontrol/TemperatureControlPublicAccess.h" | |
16 | #include "modules/robot/RobotPublicAccess.h" | |
691dcad3 | 17 | #include "modules/robot/Conveyor.h" |
35089dc7 | 18 | #include "modules/utils/player/PlayerPublicAccess.h" |
d4ee6ee2 | 19 | #include "NetworkPublicAccess.h" |
61134a65 JM |
20 | #include "PublicData.h" |
21 | #include "checksumm.h" | |
22 | #include "Pauser.h" | |
35089dc7 | 23 | |
61134a65 JM |
24 | #include <math.h> |
25 | #include <string.h> | |
35089dc7 | 26 | #include <string> |
61134a65 | 27 | |
35089dc7 | 28 | using namespace std; |
ebc64506 | 29 | static const uint8_t icons[] = { // 115x19 - 3 bytes each: he1, he2, he3, bed, fan |
862fc625 JM |
30 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, |
31 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0xE0, | |
32 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x0C, 0x60, | |
33 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x0E, 0x20, | |
34 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x0F, 0x20, | |
35 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x0F, 0xA0, | |
36 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5E, 0x07, 0xA0, | |
37 | 0x7F, 0x80, 0x00, 0x3F, 0xC0, 0x00, 0x3F, 0xC0, 0x00, 0x41, 0x04, 0x00, 0x40, 0x60, 0x20, | |
38 | 0xFB, 0xC0, 0x00, 0x79, 0xE0, 0x00, 0x79, 0xE0, 0x00, 0x20, 0x82, 0x00, 0x40, 0xF0, 0x20, | |
39 | 0xF3, 0xC0, 0x00, 0x76, 0xE0, 0x00, 0x76, 0xE0, 0x00, 0x20, 0x82, 0x00, 0x40, 0xF0, 0x20, | |
40 | 0xEB, 0xC0, 0x00, 0x7E, 0xE0, 0x00, 0x7E, 0xE0, 0x00, 0x41, 0x04, 0x00, 0x40, 0x60, 0x20, | |
41 | 0x7B, 0x80, 0x00, 0x3D, 0xC0, 0x00, 0x39, 0xC0, 0x00, 0x82, 0x08, 0x00, 0x5E, 0x07, 0xA0, | |
42 | 0x7B, 0x80, 0x00, 0x3B, 0xC0, 0x00, 0x3E, 0xC0, 0x01, 0x04, 0x10, 0x00, 0x5F, 0x0F, 0xA0, | |
43 | 0xFB, 0xC0, 0x00, 0x77, 0xE0, 0x00, 0x76, 0xE0, 0x01, 0x04, 0x10, 0x00, 0x4F, 0x0F, 0x20, | |
44 | 0xFB, 0xC0, 0x00, 0x70, 0xE0, 0x00, 0x79, 0xE0, 0x00, 0x82, 0x08, 0x00, 0x47, 0x0E, 0x20, | |
45 | 0xFF, 0xC0, 0x00, 0x7F, 0xE0, 0x00, 0x7F, 0xE0, 0x00, 0x41, 0x04, 0x00, 0x63, 0x0C, 0x60, | |
46 | 0x3F, 0x00, 0x00, 0x1F, 0x80, 0x00, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0xE0, | |
47 | 0x1E, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x0F, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0xE0, | |
48 | 0x0C, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00 | |
ebc64506 | 49 | }; |
35089dc7 | 50 | |
deb26bcd JM |
51 | |
52 | ||
862fc625 JM |
53 | WatchScreen::WatchScreen() |
54 | { | |
55 | speed_changed = false; | |
56 | issue_change_speed = false; | |
d4ee6ee2 | 57 | ipstr = NULL; |
dcf86322 | 58 | } |
35089dc7 | 59 | |
862fc625 JM |
60 | void WatchScreen::on_enter() |
61 | { | |
58d6d841 | 62 | this->panel->lcd->clear(); |
f65ce58f | 63 | this->panel->setup_menu(4); |
58d6d841 JM |
64 | get_temp_data(); |
65 | get_current_pos(this->pos); | |
66 | get_sd_play_info(); | |
862fc625 | 67 | this->current_speed = lround(get_current_speed()); |
58d6d841 | 68 | this->refresh_screen(false); |
862fc625 | 69 | this->panel->enter_control_mode(1, 0.5); |
58d6d841 | 70 | this->panel->set_control_value(this->current_speed); |
35089dc7 JM |
71 | } |
72 | ||
862fc625 JM |
73 | void WatchScreen::on_refresh() |
74 | { | |
3105a7be | 75 | // Exit if the button is clicked |
862fc625 | 76 | if ( this->panel->click() ) { |
35089dc7 JM |
77 | this->panel->enter_screen(this->parent); |
78 | return; | |
58d6d841 JM |
79 | } |
80 | ||
81 | // see if speed is being changed | |
862fc625 JM |
82 | if (this->panel->control_value_change()) { |
83 | this->current_speed = this->panel->get_control_value(); | |
84 | if (this->current_speed < 10) { | |
85 | this->current_speed = 10; | |
7a522ccc JM |
86 | this->panel->set_control_value(this->current_speed); |
87 | this->panel->reset_counter(); | |
862fc625 | 88 | } else { |
3f038f58 JM |
89 | // flag the update to change the speed, we don't want to issue hundreds of M220s |
90 | // but we do want to display the change we are going to make | |
862fc625 | 91 | this->speed_changed = true; // flag indicating speed changed |
7a522ccc JM |
92 | this->refresh_screen(false); |
93 | } | |
58d6d841 | 94 | } |
3105a7be | 95 | |
35089dc7 JM |
96 | // Update Only every 20 refreshes, 1 a second |
97 | static int update_counts = 0; | |
98 | update_counts++; | |
862fc625 | 99 | if ( update_counts % 20 == 0 ) { |
58d6d841 JM |
100 | get_sd_play_info(); |
101 | get_current_pos(this->pos); | |
102 | get_temp_data(); | |
862fc625 JM |
103 | if (this->speed_changed) { |
104 | this->issue_change_speed = true; // trigger actual command to change speed | |
105 | this->speed_changed = false; | |
106 | } else if (!this->issue_change_speed) { // change still queued | |
3f038f58 | 107 | // read it in case it was changed via M220 |
862fc625 | 108 | this->current_speed = lround(get_current_speed()); |
3f038f58 JM |
109 | this->panel->set_control_value(this->current_speed); |
110 | this->panel->reset_counter(); | |
111 | } | |
7a522ccc | 112 | |
862fc625 | 113 | this->refresh_screen(this->panel->lcd->hasGraphics() ? true : false); // graphics screens should be cleared |
91c45256 JM |
114 | |
115 | // for LCDs with leds set them according to heater status | |
116 | // TODO should be enabled and disabled and settable from config | |
117 | this->panel->lcd->setLed(LED_BED_ON, this->bedtarget > 0); | |
118 | this->panel->lcd->setLed(LED_HOTEND_ON, this->hotendtarget > 0); | |
119 | //this->panel->lcd->setLed(LED_FAN_ON, this->fanon); | |
ebc64506 | 120 | |
862fc625 | 121 | if (this->panel->lcd->hasGraphics()) { |
ebc64506 JM |
122 | // display the graphical icons below the status are |
123 | //this->panel->lcd->bltGlyph(0, 34, 115, 19, icons); | |
124 | // for (int i = 0; i < 5; ++i) { | |
125 | // this->panel->lcd->bltGlyph(i*24, 38, 23, 19, icons, 15, i*24, 0); | |
126 | // } | |
862fc625 | 127 | if (this->hotendtarget > 0) |
ebc64506 JM |
128 | this->panel->lcd->bltGlyph(8, 38, 20, 19, icons, 15, 0, 0); |
129 | ||
862fc625 | 130 | if (this->bedtarget > 0) |
ebc64506 | 131 | this->panel->lcd->bltGlyph(32, 38, 23, 19, icons, 15, 64, 0); |
3105a7be JM |
132 | |
133 | // fan appears always on for now | |
ebc64506 JM |
134 | this->panel->lcd->bltGlyph(96, 38, 23, 19, icons, 15, 96, 0); |
135 | } | |
35089dc7 JM |
136 | } |
137 | } | |
138 | ||
dcf86322 | 139 | // queuing gcodes needs to be done from main loop |
862fc625 JM |
140 | void WatchScreen::on_main_loop() |
141 | { | |
142 | if (this->issue_change_speed) { | |
143 | this->issue_change_speed = false; | |
3f038f58 JM |
144 | set_speed(); |
145 | } | |
dcf86322 JM |
146 | } |
147 | ||
35089dc7 | 148 | // fetch the data we are displaying |
862fc625 JM |
149 | void WatchScreen::get_temp_data() |
150 | { | |
58d6d841 JM |
151 | void *returned_data; |
152 | bool ok; | |
153 | ||
862fc625 JM |
154 | ok = THEKERNEL->public_data->get_value( temperature_control_checksum, bed_checksum, current_temperature_checksum, &returned_data ); |
155 | if (ok) { | |
156 | struct pad_temperature temp = *static_cast<struct pad_temperature *>(returned_data); | |
157 | this->bedtemp = round(temp.current_temperature); | |
158 | if (this->bedtemp > 100000) this->bedtemp = -2; | |
159 | this->bedtarget = round(temp.target_temperature); | |
58d6d841 | 160 | //this->bedpwm= temp.pwm; |
862fc625 | 161 | } else { |
1c11bb43 | 162 | // temp probably disabled |
862fc625 JM |
163 | this->bedtemp = -1; |
164 | this->bedtarget = -1; | |
58d6d841 JM |
165 | } |
166 | ||
206167cf | 167 | |
862fc625 JM |
168 | ok = THEKERNEL->public_data->get_value( temperature_control_checksum, hotend_checksum, current_temperature_checksum, &returned_data ); |
169 | if (ok) { | |
170 | struct pad_temperature temp = *static_cast<struct pad_temperature *>(returned_data); | |
171 | this->hotendtemp = round(temp.current_temperature); | |
172 | if (this->hotendtemp > 100000) this->hotendtemp = -2; | |
173 | this->hotendtarget = round(temp.target_temperature); | |
58d6d841 | 174 | //this->hotendpwm= temp.pwm; |
862fc625 | 175 | } else { |
1c11bb43 | 176 | // temp probably disabled |
862fc625 JM |
177 | this->hotendtemp = -1; |
178 | this->hotendtarget = -1; | |
58d6d841 | 179 | } |
35089dc7 JM |
180 | } |
181 | ||
182 | // fetch the data we are displaying | |
1ad23cd3 | 183 | float WatchScreen::get_current_speed() |
862fc625 | 184 | { |
58d6d841 | 185 | void *returned_data; |
3105a7be | 186 | |
862fc625 JM |
187 | bool ok = THEKERNEL->public_data->get_value( robot_checksum, speed_override_percent_checksum, &returned_data ); |
188 | if (ok) { | |
1ad23cd3 | 189 | float cs = *static_cast<float *>(returned_data); |
58d6d841 JM |
190 | return cs; |
191 | } | |
192 | return 0.0; | |
35089dc7 JM |
193 | } |
194 | ||
1ad23cd3 | 195 | void WatchScreen::get_current_pos(float *cp) |
862fc625 | 196 | { |
58d6d841 JM |
197 | void *returned_data; |
198 | ||
862fc625 JM |
199 | bool ok = THEKERNEL->public_data->get_value( robot_checksum, current_position_checksum, &returned_data ); |
200 | if (ok) { | |
1ad23cd3 | 201 | float *p = static_cast<float *>(returned_data); |
862fc625 JM |
202 | cp[0] = p[0]; |
203 | cp[1] = p[1]; | |
204 | cp[2] = p[2]; | |
58d6d841 | 205 | } |
35089dc7 JM |
206 | } |
207 | ||
862fc625 JM |
208 | void WatchScreen::get_sd_play_info() |
209 | { | |
58d6d841 | 210 | void *returned_data; |
862fc625 JM |
211 | bool ok = THEKERNEL->public_data->get_value( player_checksum, get_progress_checksum, &returned_data ); |
212 | if (ok) { | |
213 | struct pad_progress p = *static_cast<struct pad_progress *>(returned_data); | |
214 | this->elapsed_time = p.elapsed_secs; | |
215 | this->sd_pcnt_played = p.percent_complete; | |
4c8afa75 JM |
216 | this->panel->set_playing_file(p.filename); |
217 | ||
862fc625 JM |
218 | } else { |
219 | this->elapsed_time = 0; | |
220 | this->sd_pcnt_played = 0; | |
58d6d841 | 221 | } |
35089dc7 JM |
222 | } |
223 | ||
862fc625 JM |
224 | void WatchScreen::display_menu_line(uint16_t line) |
225 | { | |
58d6d841 | 226 | // in menu mode |
862fc625 | 227 | switch ( line ) { |
58d6d841 JM |
228 | case 0: this->panel->lcd->printf("H%03d/%03dc B%03d/%03dc", this->hotendtemp, this->hotendtarget, this->bedtemp, this->bedtarget); break; |
229 | case 1: this->panel->lcd->printf("X%4d Y%4d Z%7.2f", (int)round(this->pos[0]), (int)round(this->pos[1]), this->pos[2]); break; | |
862fc625 | 230 | case 2: this->panel->lcd->printf("%3d%% %2lu:%02lu %3u%% sd", this->current_speed, this->elapsed_time / 60, this->elapsed_time % 60, this->sd_pcnt_played); break; |
84267f43 | 231 | case 3: this->panel->lcd->printf("%19s", this->get_status()); break; |
58d6d841 | 232 | } |
35089dc7 | 233 | } |
84267f43 | 234 | |
862fc625 JM |
235 | const char *WatchScreen::get_status() |
236 | { | |
237 | if (panel->hasMessage()) { | |
399cb110 JM |
238 | return panel->getMessage().c_str(); |
239 | } | |
240 | ||
862fc625 | 241 | if (THEKERNEL->pauser->paused()) |
84267f43 | 242 | return "Paused"; |
3105a7be | 243 | |
862fc625 | 244 | if (panel->is_playing()) |
84267f43 JM |
245 | return panel->get_playing_file(); |
246 | ||
dda52007 | 247 | if (!THEKERNEL->conveyor->queue.is_empty()) { |
691dcad3 JM |
248 | return "Printing"; |
249 | } | |
250 | ||
d4ee6ee2 JM |
251 | const char *ip = get_network(); |
252 | if (ip == NULL) { | |
253 | return "Smoothie ready"; | |
254 | } else { | |
255 | return ip; | |
256 | } | |
84267f43 | 257 | } |
dcf86322 | 258 | |
862fc625 JM |
259 | void WatchScreen::set_speed() |
260 | { | |
dcf86322 JM |
261 | // change pos by issuing a M220 Snnn |
262 | char buf[32]; | |
862fc625 | 263 | int n = snprintf(buf, sizeof(buf), "M220 S%d", this->current_speed); |
dcf86322 JM |
264 | string g(buf, n); |
265 | send_gcode(g); | |
266 | } | |
d4ee6ee2 JM |
267 | |
268 | const char *WatchScreen::get_network() | |
269 | { | |
270 | void *returned_data; | |
271 | ||
272 | bool ok = THEKERNEL->public_data->get_value( network_checksum, get_ip_checksum, &returned_data ); | |
273 | if (ok) { | |
274 | uint8_t *ipaddr = (uint8_t *)returned_data; | |
275 | char buf[20]; | |
276 | int n = snprintf(buf, sizeof(buf), "IP %d.%d.%d.%d", ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); | |
277 | buf[n] = 0; | |
278 | if (this->ipstr == NULL) { | |
279 | this->ipstr = (char *)malloc(n + 1); | |
280 | } | |
281 | strcpy(this->ipstr, buf); | |
282 | ||
283 | return this->ipstr; | |
284 | } | |
285 | ||
286 | return NULL; | |
287 | } |