Allow TABS in config
[clinton/Smoothieware.git] / src / modules / utils / panel / screens / WatchScreen.cpp
CommitLineData
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 28using namespace std;
ebc64506 29static 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
53WatchScreen::WatchScreen()
54{
55 speed_changed = false;
56 issue_change_speed = false;
d4ee6ee2 57 ipstr = NULL;
dcf86322 58}
35089dc7 59
862fc625
JM
60void 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
73void 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
140void 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
149void 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 183float 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 195void 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
208void 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
224void 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
235const 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
259void 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
268const 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}