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