ignore ! and ~ as pause and resume do not work
[clinton/Smoothieware.git] / src / modules / utils / panel / screens / cnc / 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 "LcdBase.h"
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 "Robot.h"
17 #include "Conveyor.h"
18 #include "modules/robot/Conveyor.h"
19 #include "modules/utils/player/PlayerPublicAccess.h"
20 #include "NetworkPublicAccess.h"
21 #include "PublicData.h"
22 #include "SwitchPublicAccess.h"
23 #include "checksumm.h"
24 #include "StepperMotor.h"
25 #include "BaseSolution.h"
26
27 #ifndef NO_TOOLS_LASER
28 #include "Laser.h"
29 #endif
30
31 #include <math.h>
32 #include <string.h>
33 #include <string>
34 #include <stdio.h>
35 #include <algorithm>
36
37 using namespace std;
38
39 #define laser_checksum CHECKSUM("laser")
40
41 WatchScreen::WatchScreen()
42 {
43 speed_changed = false;
44 issue_change_speed = false;
45 ipstr = nullptr;
46 update_counts= 0;
47 }
48
49 WatchScreen::~WatchScreen()
50 {
51 delete[] ipstr;
52 }
53
54 void WatchScreen::on_enter()
55 {
56 THEPANEL->lcd->clear();
57 THEPANEL->setup_menu(8);
58 get_current_status();
59 get_wpos();
60 get_sd_play_info();
61 this->current_speed = lroundf(get_current_speed());
62 this->refresh_screen(false);
63 THEPANEL->enter_control_mode(1, 0.5);
64 THEPANEL->set_control_value(this->current_speed);
65 }
66
67 void WatchScreen::on_refresh()
68 {
69 // Exit if the button is clicked
70 if ( THEPANEL->click() ) {
71 THEPANEL->enter_screen(this->parent);
72 return;
73 }
74
75 // see if speed is being changed
76 if (THEPANEL->control_value_change()) {
77 this->current_speed = THEPANEL->get_control_value();
78 if (this->current_speed < 10) {
79 this->current_speed = 10;
80 THEPANEL->set_control_value(this->current_speed);
81 THEPANEL->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 update_counts++;
92 if ( update_counts % 20 == 0 ) {
93 get_sd_play_info();
94 get_wpos();
95 get_current_status();
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 = lroundf(get_current_speed());
102 THEPANEL->set_control_value(this->current_speed);
103 THEPANEL->reset_counter();
104 }
105
106 this->refresh_screen(THEPANEL->lcd->hasGraphics() ? true : false); // graphics screens should be cleared
107 }
108 }
109
110 void WatchScreen::get_wpos()
111 {
112 // get real time positions
113 // current actuator position in mm
114 ActuatorCoordinates current_position{
115 THEROBOT->actuators[X_AXIS]->get_current_position(),
116 THEROBOT->actuators[Y_AXIS]->get_current_position(),
117 THEROBOT->actuators[Z_AXIS]->get_current_position()
118 };
119
120 // get machine position from the actuator position using FK
121 float mpos[3];
122 THEROBOT->arm_solution->actuator_to_cartesian(current_position, mpos);
123 Robot::wcs_t wpos= THEROBOT->mcs2wcs(mpos);
124 this->wpos[0]= THEROBOT->from_millimeters(std::get<X_AXIS>(wpos));
125 this->wpos[1]= THEROBOT->from_millimeters(std::get<Y_AXIS>(wpos));
126 this->wpos[2]= THEROBOT->from_millimeters(std::get<Z_AXIS>(wpos));
127 this->mpos[0]= THEROBOT->from_millimeters(mpos[0]);
128 this->mpos[1]= THEROBOT->from_millimeters(mpos[1]);
129 this->mpos[2]= THEROBOT->from_millimeters(mpos[2]);
130
131 std::vector<Robot::wcs_t> v= THEROBOT->get_wcs_state();
132 char current_wcs= std::get<0>(v[0]);
133 this->wcs= wcs2gcode(current_wcs);
134 }
135
136 // queuing gcodes needs to be done from main loop
137 void WatchScreen::on_main_loop()
138 {
139 if (this->issue_change_speed) {
140 this->issue_change_speed = false;
141 set_speed();
142 }
143 PanelScreen::on_main_loop(); // in case any queued commands left
144 }
145
146 // fetch the data we are displaying
147 void WatchScreen::get_current_status()
148 {
149 // get spindle status
150 struct pad_switch s;
151 bool ok = PublicData::get_value( switch_checksum, fan_checksum, 0, &s );
152 if (ok) {
153 this->spindle_state = s.state;
154 } else {
155 // spindle probably disabled
156 this->spindle_state = false;
157 }
158 }
159
160 // fetch the data we are displaying
161 float WatchScreen::get_current_speed()
162 {
163 // in percent
164 return 6000.0F / THEROBOT->get_seconds_per_minute();
165 }
166
167 void WatchScreen::get_sd_play_info()
168 {
169 void *returned_data;
170 bool ok = PublicData::get_value( player_checksum, get_progress_checksum, &returned_data );
171 if (ok) {
172 struct pad_progress p = *static_cast<struct pad_progress *>(returned_data);
173 this->elapsed_time = p.elapsed_secs;
174 this->sd_pcnt_played = p.percent_complete;
175 THEPANEL->set_playing_file(p.filename);
176
177 } else {
178 this->elapsed_time = 0;
179 this->sd_pcnt_played = 0;
180 }
181 }
182
183 void WatchScreen::display_menu_line(uint16_t line)
184 {
185 // in menu mode
186 switch ( line ) {
187 case 0: THEPANEL->lcd->printf(" WCS MCS %s", THEROBOT->inch_mode ? "in" : "mm"); break;
188 case 1: THEPANEL->lcd->printf("X %8.3f %8.3f", wpos[0], mpos[0]); break;
189 case 2: THEPANEL->lcd->printf("Y %8.3f %8.3f", wpos[1], mpos[1]); break;
190 case 3: THEPANEL->lcd->printf("Z %8.3f %8.3f", wpos[2], mpos[2]); break;
191 case 4: THEPANEL->lcd->printf("%s F%6.1f/%6.1f", this->wcs.c_str(), // display requested feedrate and actual feedrate
192 THEROBOT->from_millimeters(THEROBOT->get_feed_rate()),
193 THEROBOT->from_millimeters(THEKERNEL->conveyor->get_current_feedrate()*60.0F));
194 break;
195 case 5: THEPANEL->lcd->printf("%3d%% %2lu:%02lu %3u%% sd", this->current_speed, this->elapsed_time / 60, this->elapsed_time % 60, this->sd_pcnt_played); break;
196 case 6:
197 if(THEPANEL->has_laser()){
198 #ifndef NO_TOOLS_LASER
199 Laser *plaser= nullptr;
200 if(PublicData::get_value(laser_checksum, (void *)&plaser) && plaser != nullptr) {
201 THEPANEL->lcd->printf("Laser S%1.4f/%1.2f%%", THEROBOT->get_s_value(), plaser->get_current_power());
202 }
203 #endif
204 }
205 break;
206 case 7: THEPANEL->lcd->printf("%19s", this->get_status()); break;
207 }
208 }
209
210 const char *WatchScreen::get_status()
211 {
212 if (THEPANEL->hasMessage())
213 return THEPANEL->getMessage().c_str();
214
215 if (THEKERNEL->is_halted())
216 return "ALARM";
217
218 if (THEPANEL->is_suspended() /*|| THEKERNEL->get_feed_hold()*/)
219 return "Suspended";
220
221 if (THEPANEL->is_playing())
222 return THEPANEL->get_playing_file();
223
224 if (!THECONVEYOR->is_idle())
225 return "Running";
226
227 const char *ip = get_network();
228 if (ip == NULL) {
229 return "Idle";
230 } else {
231 return ip;
232 }
233 }
234
235 void WatchScreen::set_speed()
236 {
237 send_gcode("M220", 'S', this->current_speed);
238 }
239
240 const char *WatchScreen::get_network()
241 {
242 void *returned_data;
243
244 bool ok = PublicData::get_value( network_checksum, get_ip_checksum, &returned_data );
245 if (ok) {
246 uint8_t *ipaddr = (uint8_t *)returned_data;
247 char buf[20];
248 int n = snprintf(buf, sizeof(buf), "IP %d.%d.%d.%d", ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]);
249 buf[n] = 0;
250 if (this->ipstr == nullptr) {
251 this->ipstr = new char[n + 1];
252 }
253 strcpy(this->ipstr, buf);
254
255 return this->ipstr;
256 }
257
258 return NULL;
259 }