change the temperature public data access to pass in the pad_temp for the result...
[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"
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"
17#include "modules/robot/RobotPublicAccess.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
JM
23#include "checksumm.h"
24#include "Pauser.h"
02e4b295
JM
25#include "TemperatureControlPool.h"
26
27
61134a65
JM
28#include <math.h>
29#include <string.h>
35089dc7 30#include <string>
383c9c1c 31#include <stdio.h>
373d0bf1 32#include <algorithm>
61134a65 33
35089dc7 34using namespace std;
ebc64506 35static const uint8_t icons[] = { // 115x19 - 3 bytes each: he1, he2, he3, bed, fan
862fc625
JM
36 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0,
37 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0xE0,
38 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x0C, 0x60,
39 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x0E, 0x20,
40 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x0F, 0x20,
41 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x0F, 0xA0,
42 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5E, 0x07, 0xA0,
43 0x7F, 0x80, 0x00, 0x3F, 0xC0, 0x00, 0x3F, 0xC0, 0x00, 0x41, 0x04, 0x00, 0x40, 0x60, 0x20,
44 0xFB, 0xC0, 0x00, 0x79, 0xE0, 0x00, 0x79, 0xE0, 0x00, 0x20, 0x82, 0x00, 0x40, 0xF0, 0x20,
45 0xF3, 0xC0, 0x00, 0x76, 0xE0, 0x00, 0x76, 0xE0, 0x00, 0x20, 0x82, 0x00, 0x40, 0xF0, 0x20,
46 0xEB, 0xC0, 0x00, 0x7E, 0xE0, 0x00, 0x7E, 0xE0, 0x00, 0x41, 0x04, 0x00, 0x40, 0x60, 0x20,
47 0x7B, 0x80, 0x00, 0x3D, 0xC0, 0x00, 0x39, 0xC0, 0x00, 0x82, 0x08, 0x00, 0x5E, 0x07, 0xA0,
48 0x7B, 0x80, 0x00, 0x3B, 0xC0, 0x00, 0x3E, 0xC0, 0x01, 0x04, 0x10, 0x00, 0x5F, 0x0F, 0xA0,
49 0xFB, 0xC0, 0x00, 0x77, 0xE0, 0x00, 0x76, 0xE0, 0x01, 0x04, 0x10, 0x00, 0x4F, 0x0F, 0x20,
50 0xFB, 0xC0, 0x00, 0x70, 0xE0, 0x00, 0x79, 0xE0, 0x00, 0x82, 0x08, 0x00, 0x47, 0x0E, 0x20,
51 0xFF, 0xC0, 0x00, 0x7F, 0xE0, 0x00, 0x7F, 0xE0, 0x00, 0x41, 0x04, 0x00, 0x63, 0x0C, 0x60,
52 0x3F, 0x00, 0x00, 0x1F, 0x80, 0x00, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0xE0,
53 0x1E, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x0F, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0xE0,
54 0x0C, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00
ebc64506 55};
35089dc7 56
deb26bcd
JM
57
58
862fc625
JM
59WatchScreen::WatchScreen()
60{
61 speed_changed = false;
62 issue_change_speed = false;
383c9c1c 63 ipstr = nullptr;
c77d6dae 64 update_counts= 0;
383c9c1c
JM
65}
66
67WatchScreen::~WatchScreen()
68{
69 delete[] ipstr;
dcf86322 70}
35089dc7 71
862fc625
JM
72void WatchScreen::on_enter()
73{
cee1bb2d
JM
74 THEPANEL->lcd->clear();
75 THEPANEL->setup_menu(4);
c77d6dae 76 get_current_status();
58d6d841
JM
77 get_current_pos(this->pos);
78 get_sd_play_info();
862fc625 79 this->current_speed = lround(get_current_speed());
58d6d841 80 this->refresh_screen(false);
cee1bb2d
JM
81 THEPANEL->enter_control_mode(1, 0.5);
82 THEPANEL->set_control_value(this->current_speed);
35089dc7
JM
83}
84
862fc625
JM
85void WatchScreen::on_refresh()
86{
3105a7be 87 // Exit if the button is clicked
cee1bb2d
JM
88 if ( THEPANEL->click() ) {
89 THEPANEL->enter_screen(this->parent);
35089dc7 90 return;
58d6d841
JM
91 }
92
93 // see if speed is being changed
cee1bb2d
JM
94 if (THEPANEL->control_value_change()) {
95 this->current_speed = THEPANEL->get_control_value();
862fc625
JM
96 if (this->current_speed < 10) {
97 this->current_speed = 10;
cee1bb2d
JM
98 THEPANEL->set_control_value(this->current_speed);
99 THEPANEL->reset_counter();
862fc625 100 } else {
3f038f58
JM
101 // flag the update to change the speed, we don't want to issue hundreds of M220s
102 // but we do want to display the change we are going to make
862fc625 103 this->speed_changed = true; // flag indicating speed changed
7a522ccc
JM
104 this->refresh_screen(false);
105 }
58d6d841 106 }
3105a7be 107
35089dc7 108 // Update Only every 20 refreshes, 1 a second
35089dc7 109 update_counts++;
862fc625 110 if ( update_counts % 20 == 0 ) {
58d6d841
JM
111 get_sd_play_info();
112 get_current_pos(this->pos);
c77d6dae 113 get_current_status();
862fc625
JM
114 if (this->speed_changed) {
115 this->issue_change_speed = true; // trigger actual command to change speed
116 this->speed_changed = false;
117 } else if (!this->issue_change_speed) { // change still queued
3f038f58 118 // read it in case it was changed via M220
862fc625 119 this->current_speed = lround(get_current_speed());
cee1bb2d
JM
120 THEPANEL->set_control_value(this->current_speed);
121 THEPANEL->reset_counter();
3f038f58 122 }
7a522ccc 123
cee1bb2d 124 this->refresh_screen(THEPANEL->lcd->hasGraphics() ? true : false); // graphics screens should be cleared
91c45256
JM
125
126 // for LCDs with leds set them according to heater status
c77d6dae 127 bool bed_on= false, hotend_on= false, is_hot= false;
226d08ee 128 uint8_t heon=0, hemsk= 0x01; // bit set for which hotend is on bit0: hotend1, bit1: hotend2 etc
bab4e1bd 129 temp_controllers.clear();
3bfb2639
JM
130 std::vector<struct pad_temperature> controllers;
131 bool ok = PublicData::get_value(temperature_control_checksum, poll_controls_checksum, &controllers);
bab4e1bd 132 if (ok) {
3bfb2639
JM
133 for (auto &c : controllers) {
134 temp_controllers.push_back(c.id);
135 if(c.current_temperature > 50) is_hot= true; // anything is hot
136 if(c.designator.front() == 'B' && c.target_temperature > 0) bed_on= true; // bed on/off
137 if(c.designator.front() == 'T') { // a hotend by convention
138 if(c.target_temperature > 0){
226d08ee
JM
139 hotend_on= true;// hotend on/off (anyone)
140 heon |= hemsk;
141 }
142 hemsk <<= 1;
143 }
c77d6dae
JM
144 }
145 }
146 THEPANEL->lcd->setLed(LED_BED_ON, bed_on);
147 THEPANEL->lcd->setLed(LED_HOTEND_ON, hotend_on);
148 THEPANEL->lcd->setLed(LED_HOT, is_hot);
149
cee1bb2d 150 THEPANEL->lcd->setLed(LED_FAN_ON, this->fan_state);
ebc64506 151
cee1bb2d 152 if (THEPANEL->lcd->hasGraphics()) {
ebc64506 153 // display the graphical icons below the status are
cee1bb2d 154 //THEPANEL->lcd->bltGlyph(0, 34, 115, 19, icons);
ebc64506 155 // for (int i = 0; i < 5; ++i) {
cee1bb2d 156 // THEPANEL->lcd->bltGlyph(i*24, 38, 23, 19, icons, 15, i*24, 0);
ebc64506 157 // }
226d08ee
JM
158 if(heon&0x01) THEPANEL->lcd->bltGlyph(0, 38, 20, 19, icons, 15, 0, 0);
159 if(heon&0x02) THEPANEL->lcd->bltGlyph(20, 38, 20, 19, icons, 15, 24, 0);
160 if(heon&0x04) THEPANEL->lcd->bltGlyph(40, 38, 20, 19, icons, 15, 48, 0);
ebc64506 161
c77d6dae 162 if (bed_on)
226d08ee 163 THEPANEL->lcd->bltGlyph(60, 38, 23, 19, icons, 15, 64, 0);
3105a7be 164
f1aac8df 165 if(this->fan_state)
cee1bb2d 166 THEPANEL->lcd->bltGlyph(96, 38, 23, 19, icons, 15, 96, 0);
ebc64506 167 }
35089dc7
JM
168 }
169}
170
dcf86322 171// queuing gcodes needs to be done from main loop
862fc625
JM
172void WatchScreen::on_main_loop()
173{
174 if (this->issue_change_speed) {
175 this->issue_change_speed = false;
3f038f58
JM
176 set_speed();
177 }
f15e6f4b 178 PanelScreen::on_main_loop(); // in case any queued commands left
dcf86322
JM
179}
180
c77d6dae
JM
181// fetch the data we are displaying
182void WatchScreen::get_current_status()
183{
184 void *returned_data;
185 bool ok;
f1aac8df
JM
186
187 // get fan status
75e6428d 188 ok = PublicData::get_value( switch_checksum, fan_checksum, 0, &returned_data );
f1aac8df
JM
189 if (ok) {
190 struct pad_switch s = *static_cast<struct pad_switch *>(returned_data);
191 this->fan_state = s.state;
192 } else {
193 // fan probably disabled
194 this->fan_state = false;
195 }
35089dc7
JM
196}
197
198// fetch the data we are displaying
1ad23cd3 199float WatchScreen::get_current_speed()
862fc625 200{
58d6d841 201 void *returned_data;
3105a7be 202
75e6428d 203 bool ok = PublicData::get_value( robot_checksum, speed_override_percent_checksum, &returned_data );
862fc625 204 if (ok) {
1ad23cd3 205 float cs = *static_cast<float *>(returned_data);
58d6d841
JM
206 return cs;
207 }
208 return 0.0;
35089dc7
JM
209}
210
1ad23cd3 211void WatchScreen::get_current_pos(float *cp)
862fc625 212{
58d6d841
JM
213 void *returned_data;
214
75e6428d 215 bool ok = PublicData::get_value( robot_checksum, current_position_checksum, &returned_data );
862fc625 216 if (ok) {
1ad23cd3 217 float *p = static_cast<float *>(returned_data);
862fc625
JM
218 cp[0] = p[0];
219 cp[1] = p[1];
220 cp[2] = p[2];
58d6d841 221 }
35089dc7
JM
222}
223
862fc625
JM
224void WatchScreen::get_sd_play_info()
225{
58d6d841 226 void *returned_data;
75e6428d 227 bool ok = PublicData::get_value( player_checksum, get_progress_checksum, &returned_data );
862fc625
JM
228 if (ok) {
229 struct pad_progress p = *static_cast<struct pad_progress *>(returned_data);
230 this->elapsed_time = p.elapsed_secs;
231 this->sd_pcnt_played = p.percent_complete;
cee1bb2d 232 THEPANEL->set_playing_file(p.filename);
4c8afa75 233
862fc625
JM
234 } else {
235 this->elapsed_time = 0;
236 this->sd_pcnt_played = 0;
58d6d841 237 }
35089dc7
JM
238}
239
3bfb2639
JM
240static struct pad_temperature getTemperatures(uint16_t heater_cs)
241{
242 struct pad_temperature temp;
243 PublicData::get_value( temperature_control_checksum, heater_cs, current_temperature_checksum, &temp );
244 return temp;
245}
246
862fc625
JM
247void WatchScreen::display_menu_line(uint16_t line)
248{
58d6d841 249 // in menu mode
862fc625 250 switch ( line ) {
e0437082 251 case 0:
02e4b295 252 {
bab4e1bd 253 auto& tm= this->temp_controllers;
02e4b295 254 if(tm.size() > 0) {
e0437082 255 // only if we detected heaters in config
c77d6dae
JM
256 int n= 0;
257 if(tm.size() > 2) {
258 // more than two temps we need to cycle between them
259 n= update_counts/100; // increments every 5 seconds
260 int ntemps= (tm.size()+1)/2;
261 n= n%ntemps; // which of the pairs of temps to display
262 }
263
264 int off= 0;
265 for (size_t i = 0; i < 2; ++i) {
266 size_t o= i+(n*2);
267 if(o>tm.size()-1) break;
3bfb2639
JM
268 struct pad_temperature temp= getTemperatures(tm[o]);
269 int t= std::min(999, (int)roundf(temp.current_temperature));
270 int tt= roundf(temp.target_temperature);
c77d6dae 271 THEPANEL->lcd->setCursor(off, 0); // col, row
3bfb2639 272 off += THEPANEL->lcd->printf("%s:%03d/%03d ", temp.designator.substr(0, 2).c_str(), t, tt);
c77d6dae
JM
273 }
274
e0437082
JM
275 }else{
276 //THEPANEL->lcd->printf("No Heaters");
277 }
278 break;
02e4b295 279 }
cee1bb2d
JM
280 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;
281 case 2: THEPANEL->lcd->printf("%3d%% %2lu:%02lu %3u%% sd", this->current_speed, this->elapsed_time / 60, this->elapsed_time % 60, this->sd_pcnt_played); break;
282 case 3: THEPANEL->lcd->printf("%19s", this->get_status()); break;
58d6d841 283 }
35089dc7 284}
84267f43 285
862fc625
JM
286const char *WatchScreen::get_status()
287{
5f1a896b 288 if (THEPANEL->hasMessage())
cee1bb2d 289 return THEPANEL->getMessage().c_str();
399cb110 290
5f1a896b 291 if (THEPANEL->is_halted())
76217df5 292 return "HALTED Reset or M999";
76217df5 293
862fc625 294 if (THEKERNEL->pauser->paused())
84267f43 295 return "Paused";
3105a7be 296
5f1a896b
JM
297 if (THEPANEL->is_suspended())
298 return "Suspended";
299
cee1bb2d
JM
300 if (THEPANEL->is_playing())
301 return THEPANEL->get_playing_file();
84267f43 302
5f1a896b 303 if (!THEKERNEL->conveyor->is_queue_empty())
691dcad3 304 return "Printing";
691dcad3 305
d4ee6ee2
JM
306 const char *ip = get_network();
307 if (ip == NULL) {
308 return "Smoothie ready";
309 } else {
310 return ip;
311 }
84267f43 312}
dcf86322 313
862fc625
JM
314void WatchScreen::set_speed()
315{
2fa50ca0 316 send_gcode("M220", 'S', this->current_speed);
dcf86322 317}
d4ee6ee2
JM
318
319const char *WatchScreen::get_network()
320{
321 void *returned_data;
322
75e6428d 323 bool ok = PublicData::get_value( network_checksum, get_ip_checksum, &returned_data );
d4ee6ee2
JM
324 if (ok) {
325 uint8_t *ipaddr = (uint8_t *)returned_data;
326 char buf[20];
327 int n = snprintf(buf, sizeof(buf), "IP %d.%d.%d.%d", ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]);
328 buf[n] = 0;
383c9c1c
JM
329 if (this->ipstr == nullptr) {
330 this->ipstr = new char[n + 1];
d4ee6ee2
JM
331 }
332 strcpy(this->ipstr, buf);
333
334 return this->ipstr;
335 }
336
337 return NULL;
338}