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