fixed whitespace issue and removed 'sd' to correct spacing.
[clinton/Smoothieware.git] / src / modules / utils / panel / screens / 3dprinter / 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"
383c9c1c 9#include "LcdBase.h"
35089dc7
JM
10#include "Panel.h"
11#include "PanelScreen.h"
12#include "MainMenuScreen.h"
13#include "WatchScreen.h"
14#include "libs/nuts_bolts.h"
15#include "libs/utils.h"
16#include "modules/tools/temperaturecontrol/TemperatureControlPublicAccess.h"
564cf1f0 17#include "Robot.h"
691dcad3 18#include "modules/robot/Conveyor.h"
35089dc7 19#include "modules/utils/player/PlayerPublicAccess.h"
d4ee6ee2 20#include "NetworkPublicAccess.h"
61134a65 21#include "PublicData.h"
f1aac8df 22#include "SwitchPublicAccess.h"
61134a65 23#include "checksumm.h"
02e4b295
JM
24#include "TemperatureControlPool.h"
25
26
61134a65
JM
27#include <math.h>
28#include <string.h>
35089dc7 29#include <string>
383c9c1c 30#include <stdio.h>
373d0bf1 31#include <algorithm>
61134a65 32
35089dc7 33using namespace std;
21384474
RP
34static const uint8_t icons[] = { // 16x80 - he1, he2, he3, bed, fan
35 0x3f, 0xfc, 0x3f, 0xfc, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0x7f, 0x7f, 0x7e, 0x3f, 0x7c, 0x1f,
36 0x78, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x01, 0x80,
37 0x01, 0x80, 0x3f, 0xfc, 0x3f, 0xfc, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0x7f, 0x7c, 0x7e, 0x3d,
38 0xfc, 0x1c, 0x78, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80,
39 0x01, 0x80, 0x01, 0x80, 0x3f, 0xfc, 0x3f, 0xfc, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0x7f, 0x7c,
40 0x7e, 0x3f, 0x7c, 0x1c, 0x78, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00,
41 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x00, 0x00, 0x08, 0x88, 0x11, 0x10, 0x22, 0x20, 0x22,
42 0x20, 0x11, 0x10, 0x08, 0x88, 0x04, 0x44, 0x04, 0x44, 0x08, 0x88, 0x11, 0x10, 0x22, 0x20,
43 0x00, 0x00, 0x7f, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0x39, 0xec, 0x43, 0xe2, 0x9b, 0xc9, 0xa3,
44 0x85, 0x03, 0x85, 0xc3, 0x00, 0xe0, 0x3e, 0xf9, 0xbf, 0xfd, 0x9f, 0x7c, 0x07, 0x00, 0xc3,
45 0xa1, 0xc0, 0xa1, 0xc5, 0x93, 0xd9, 0x47, 0xc2, 0x37, 0x9c
ebc64506 46};
35089dc7 47
862fc625
JM
48WatchScreen::WatchScreen()
49{
50 speed_changed = false;
51 issue_change_speed = false;
383c9c1c 52 ipstr = nullptr;
c77d6dae 53 update_counts= 0;
383c9c1c
JM
54}
55
56WatchScreen::~WatchScreen()
57{
58 delete[] ipstr;
dcf86322 59}
35089dc7 60
862fc625
JM
61void WatchScreen::on_enter()
62{
cee1bb2d
JM
63 THEPANEL->lcd->clear();
64 THEPANEL->setup_menu(4);
c77d6dae 65 get_current_status();
58d6d841
JM
66 get_current_pos(this->pos);
67 get_sd_play_info();
586cc733 68 this->current_speed = lroundf(get_current_speed());
58d6d841 69 this->refresh_screen(false);
cee1bb2d
JM
70 THEPANEL->enter_control_mode(1, 0.5);
71 THEPANEL->set_control_value(this->current_speed);
56a6c8c1
JM
72
73 // enumerate temperature controls
74 temp_controllers.clear();
75 std::vector<struct pad_temperature> controllers;
76 bool ok = PublicData::get_value(temperature_control_checksum, poll_controls_checksum, &controllers);
77 if (ok) {
78 for (auto &c : controllers) {
79 temp_controllers.push_back(c.id);
80 }
81 }
82}
83
84static struct pad_temperature getTemperatures(uint16_t heater_cs)
85{
86 struct pad_temperature temp;
87 PublicData::get_value( temperature_control_checksum, current_temperature_checksum, heater_cs, &temp );
88 return temp;
35089dc7
JM
89}
90
862fc625
JM
91void WatchScreen::on_refresh()
92{
3105a7be 93 // Exit if the button is clicked
cee1bb2d
JM
94 if ( THEPANEL->click() ) {
95 THEPANEL->enter_screen(this->parent);
35089dc7 96 return;
58d6d841
JM
97 }
98
99 // see if speed is being changed
cee1bb2d
JM
100 if (THEPANEL->control_value_change()) {
101 this->current_speed = THEPANEL->get_control_value();
862fc625
JM
102 if (this->current_speed < 10) {
103 this->current_speed = 10;
cee1bb2d
JM
104 THEPANEL->set_control_value(this->current_speed);
105 THEPANEL->reset_counter();
862fc625 106 } else {
3f038f58
JM
107 // flag the update to change the speed, we don't want to issue hundreds of M220s
108 // but we do want to display the change we are going to make
862fc625 109 this->speed_changed = true; // flag indicating speed changed
7a522ccc
JM
110 this->refresh_screen(false);
111 }
58d6d841 112 }
3105a7be 113
35089dc7 114 // Update Only every 20 refreshes, 1 a second
35089dc7 115 update_counts++;
862fc625 116 if ( update_counts % 20 == 0 ) {
58d6d841
JM
117 get_sd_play_info();
118 get_current_pos(this->pos);
c77d6dae 119 get_current_status();
862fc625
JM
120 if (this->speed_changed) {
121 this->issue_change_speed = true; // trigger actual command to change speed
122 this->speed_changed = false;
123 } else if (!this->issue_change_speed) { // change still queued
3f038f58 124 // read it in case it was changed via M220
586cc733 125 this->current_speed = lroundf(get_current_speed());
cee1bb2d
JM
126 THEPANEL->set_control_value(this->current_speed);
127 THEPANEL->reset_counter();
3f038f58 128 }
7a522ccc 129
cee1bb2d 130 this->refresh_screen(THEPANEL->lcd->hasGraphics() ? true : false); // graphics screens should be cleared
91c45256
JM
131
132 // for LCDs with leds set them according to heater status
c77d6dae 133 bool bed_on= false, hotend_on= false, is_hot= false;
226d08ee 134 uint8_t heon=0, hemsk= 0x01; // bit set for which hotend is on bit0: hotend1, bit1: hotend2 etc
56a6c8c1
JM
135 for(auto id : temp_controllers) {
136 struct pad_temperature c= getTemperatures(id);
137 if(c.current_temperature > 50) is_hot= true; // anything is hot
138 if(c.designator.front() == 'B' && c.target_temperature > 0) bed_on= true; // bed on/off
139 if(c.designator.front() == 'T') { // a hotend by convention
140 if(c.target_temperature > 0){
141 hotend_on= true;// hotend on/off (anyone)
142 heon |= hemsk;
226d08ee 143 }
56a6c8c1 144 hemsk <<= 1;
c77d6dae
JM
145 }
146 }
56a6c8c1 147
c77d6dae
JM
148 THEPANEL->lcd->setLed(LED_BED_ON, bed_on);
149 THEPANEL->lcd->setLed(LED_HOTEND_ON, hotend_on);
150 THEPANEL->lcd->setLed(LED_HOT, is_hot);
151
cee1bb2d 152 THEPANEL->lcd->setLed(LED_FAN_ON, this->fan_state);
ebc64506 153
cee1bb2d 154 if (THEPANEL->lcd->hasGraphics()) {
ebc64506 155 // display the graphical icons below the status are
ebc64506 156 // for (int i = 0; i < 5; ++i) {
21384474 157 // THEPANEL->lcd->bltGlyph(i*24, 42, 16, 16, icons, 15, i*24, 0);
ebc64506 158 // }
21384474
RP
159 if(heon&0x01) THEPANEL->lcd->bltGlyph(0, 42, 16, 16, icons, 2, 0, 0);
160 if(heon&0x02) THEPANEL->lcd->bltGlyph(27, 42, 16, 16, icons, 2, 0, 16);
161 if(heon&0x04) THEPANEL->lcd->bltGlyph(55, 42, 16, 16, icons, 2, 0, 32);
ebc64506 162
c77d6dae 163 if (bed_on)
21384474 164 THEPANEL->lcd->bltGlyph(83, 42, 16, 16, icons, 2, 0, 48);
3105a7be 165
f1aac8df 166 if(this->fan_state)
21384474 167 THEPANEL->lcd->bltGlyph(111, 42, 16, 16, icons, 2, 0, 64);
ebc64506 168 }
35089dc7
JM
169 }
170}
171
dcf86322 172// queuing gcodes needs to be done from main loop
862fc625
JM
173void WatchScreen::on_main_loop()
174{
175 if (this->issue_change_speed) {
176 this->issue_change_speed = false;
3f038f58
JM
177 set_speed();
178 }
f15e6f4b 179 PanelScreen::on_main_loop(); // in case any queued commands left
dcf86322
JM
180}
181
c77d6dae
JM
182// fetch the data we are displaying
183void WatchScreen::get_current_status()
184{
f1aac8df 185 // get fan status
1ae7e276
JM
186 struct pad_switch s;
187 bool ok = PublicData::get_value( switch_checksum, fan_checksum, 0, &s );
f1aac8df 188 if (ok) {
f1aac8df
JM
189 this->fan_state = s.state;
190 } else {
191 // fan probably disabled
192 this->fan_state = false;
193 }
35089dc7
JM
194}
195
196// fetch the data we are displaying
1ad23cd3 197float WatchScreen::get_current_speed()
862fc625 198{
564cf1f0 199 // in percent
c8bac202 200 return 6000.0F / THEROBOT->get_seconds_per_minute();
35089dc7
JM
201}
202
862fc625
JM
203void WatchScreen::get_sd_play_info()
204{
58d6d841 205 void *returned_data;
75e6428d 206 bool ok = PublicData::get_value( player_checksum, get_progress_checksum, &returned_data );
862fc625
JM
207 if (ok) {
208 struct pad_progress p = *static_cast<struct pad_progress *>(returned_data);
209 this->elapsed_time = p.elapsed_secs;
210 this->sd_pcnt_played = p.percent_complete;
cee1bb2d 211 THEPANEL->set_playing_file(p.filename);
4c8afa75 212
862fc625
JM
213 } else {
214 this->elapsed_time = 0;
215 this->sd_pcnt_played = 0;
58d6d841 216 }
35089dc7
JM
217}
218
862fc625
JM
219void WatchScreen::display_menu_line(uint16_t line)
220{
58d6d841 221 // in menu mode
862fc625 222 switch ( line ) {
e0437082 223 case 0:
02e4b295 224 {
bab4e1bd 225 auto& tm= this->temp_controllers;
02e4b295 226 if(tm.size() > 0) {
e0437082 227 // only if we detected heaters in config
c77d6dae
JM
228 int n= 0;
229 if(tm.size() > 2) {
230 // more than two temps we need to cycle between them
231 n= update_counts/100; // increments every 5 seconds
232 int ntemps= (tm.size()+1)/2;
233 n= n%ntemps; // which of the pairs of temps to display
234 }
235
236 int off= 0;
237 for (size_t i = 0; i < 2; ++i) {
238 size_t o= i+(n*2);
239 if(o>tm.size()-1) break;
3bfb2639
JM
240 struct pad_temperature temp= getTemperatures(tm[o]);
241 int t= std::min(999, (int)roundf(temp.current_temperature));
242 int tt= roundf(temp.target_temperature);
c77d6dae 243 THEPANEL->lcd->setCursor(off, 0); // col, row
3bfb2639 244 off += THEPANEL->lcd->printf("%s:%03d/%03d ", temp.designator.substr(0, 2).c_str(), t, tt);
c77d6dae
JM
245 }
246
e0437082
JM
247 }else{
248 //THEPANEL->lcd->printf("No Heaters");
249 }
250 break;
02e4b295 251 }
cee1bb2d 252 case 1: THEPANEL->lcd->printf("X%4d Y%4d Z%7.2f", (int)round(this->pos[0]), (int)round(this->pos[1]), this->pos[2]); break;
604cffcb 253 case 2: THEPANEL->lcd->printf("%3d%% %02lu:%02lu:%02lu %3u%%", this->current_speed, this->elapsed_time / 3600, (this->elapsed_time % 3600) / 60, this->elapsed_time % 60, this->sd_pcnt_played); break;
cee1bb2d 254 case 3: THEPANEL->lcd->printf("%19s", this->get_status()); break;
58d6d841 255 }
35089dc7 256}
84267f43 257
862fc625
JM
258const char *WatchScreen::get_status()
259{
5f1a896b 260 if (THEPANEL->hasMessage())
cee1bb2d 261 return THEPANEL->getMessage().c_str();
399cb110 262
73706276 263 if (THEKERNEL->is_halted())
76217df5 264 return "HALTED Reset or M999";
76217df5 265
5f1a896b
JM
266 if (THEPANEL->is_suspended())
267 return "Suspended";
268
cee1bb2d
JM
269 if (THEPANEL->is_playing())
270 return THEPANEL->get_playing_file();
84267f43 271
7baa50df 272 if (!THECONVEYOR->is_idle())
691dcad3 273 return "Printing";
691dcad3 274
d4ee6ee2
JM
275 const char *ip = get_network();
276 if (ip == NULL) {
277 return "Smoothie ready";
278 } else {
279 return ip;
280 }
84267f43 281}
dcf86322 282
862fc625
JM
283void WatchScreen::set_speed()
284{
2fa50ca0 285 send_gcode("M220", 'S', this->current_speed);
dcf86322 286}
d4ee6ee2
JM
287
288const char *WatchScreen::get_network()
289{
290 void *returned_data;
291
75e6428d 292 bool ok = PublicData::get_value( network_checksum, get_ip_checksum, &returned_data );
d4ee6ee2
JM
293 if (ok) {
294 uint8_t *ipaddr = (uint8_t *)returned_data;
295 char buf[20];
296 int n = snprintf(buf, sizeof(buf), "IP %d.%d.%d.%d", ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]);
297 buf[n] = 0;
383c9c1c
JM
298 if (this->ipstr == nullptr) {
299 this->ipstr = new char[n + 1];
d4ee6ee2
JM
300 }
301 strcpy(this->ipstr, buf);
302
303 return this->ipstr;
304 }
305
306 return NULL;
307}