fix using is queue empty when it should be is_idle
[clinton/Smoothieware.git] / src / modules / utils / panel / screens / cnc / 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"
564cf1f0 16#include "Robot.h"
c7f4902c 17#include "Conveyor.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"
8a75ef4a
JM
24#include "StepperMotor.h"
25#include "BaseSolution.h"
02e4b295 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 63 THEPANEL->lcd->clear();
8a75ef4a 64 THEPANEL->setup_menu(7);
c77d6dae 65 get_current_status();
8a75ef4a 66 get_wpos();
58d6d841 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);
35089dc7
JM
72}
73
862fc625
JM
74void WatchScreen::on_refresh()
75{
3105a7be 76 // Exit if the button is clicked
cee1bb2d
JM
77 if ( THEPANEL->click() ) {
78 THEPANEL->enter_screen(this->parent);
35089dc7 79 return;
58d6d841
JM
80 }
81
82 // see if speed is being changed
cee1bb2d
JM
83 if (THEPANEL->control_value_change()) {
84 this->current_speed = THEPANEL->get_control_value();
862fc625
JM
85 if (this->current_speed < 10) {
86 this->current_speed = 10;
cee1bb2d
JM
87 THEPANEL->set_control_value(this->current_speed);
88 THEPANEL->reset_counter();
862fc625 89 } else {
3f038f58
JM
90 // flag the update to change the speed, we don't want to issue hundreds of M220s
91 // but we do want to display the change we are going to make
862fc625 92 this->speed_changed = true; // flag indicating speed changed
7a522ccc
JM
93 this->refresh_screen(false);
94 }
58d6d841 95 }
3105a7be 96
35089dc7 97 // Update Only every 20 refreshes, 1 a second
35089dc7 98 update_counts++;
862fc625 99 if ( update_counts % 20 == 0 ) {
58d6d841 100 get_sd_play_info();
8a75ef4a 101 get_wpos();
c77d6dae 102 get_current_status();
862fc625
JM
103 if (this->speed_changed) {
104 this->issue_change_speed = true; // trigger actual command to change speed
105 this->speed_changed = false;
106 } else if (!this->issue_change_speed) { // change still queued
3f038f58 107 // read it in case it was changed via M220
586cc733 108 this->current_speed = lroundf(get_current_speed());
cee1bb2d
JM
109 THEPANEL->set_control_value(this->current_speed);
110 THEPANEL->reset_counter();
3f038f58 111 }
7a522ccc 112
cee1bb2d 113 this->refresh_screen(THEPANEL->lcd->hasGraphics() ? true : false); // graphics screens should be cleared
35089dc7
JM
114 }
115}
116
8a75ef4a
JM
117void WatchScreen::get_wpos()
118{
119 // get real time positions
120 // current actuator position in mm
121 ActuatorCoordinates current_position{
c8bac202
JM
122 THEROBOT->actuators[X_AXIS]->get_current_position(),
123 THEROBOT->actuators[Y_AXIS]->get_current_position(),
124 THEROBOT->actuators[Z_AXIS]->get_current_position()
8a75ef4a
JM
125 };
126
127 // get machine position from the actuator position using FK
128 float mpos[3];
c8bac202
JM
129 THEROBOT->arm_solution->actuator_to_cartesian(current_position, mpos);
130 Robot::wcs_t wpos= THEROBOT->mcs2wcs(mpos);
131 this->wpos[0]= THEROBOT->from_millimeters(std::get<X_AXIS>(wpos));
132 this->wpos[1]= THEROBOT->from_millimeters(std::get<Y_AXIS>(wpos));
133 this->wpos[2]= THEROBOT->from_millimeters(std::get<Z_AXIS>(wpos));
134 this->mpos[0]= THEROBOT->from_millimeters(mpos[0]);
135 this->mpos[1]= THEROBOT->from_millimeters(mpos[1]);
136 this->mpos[2]= THEROBOT->from_millimeters(mpos[2]);
137
138 std::vector<Robot::wcs_t> v= THEROBOT->get_wcs_state();
381fbb3b
JM
139 char current_wcs= std::get<0>(v[0]);
140 this->wcs= wcs2gcode(current_wcs);
8a75ef4a
JM
141}
142
dcf86322 143// queuing gcodes needs to be done from main loop
862fc625
JM
144void WatchScreen::on_main_loop()
145{
146 if (this->issue_change_speed) {
147 this->issue_change_speed = false;
3f038f58
JM
148 set_speed();
149 }
f15e6f4b 150 PanelScreen::on_main_loop(); // in case any queued commands left
dcf86322
JM
151}
152
c77d6dae
JM
153// fetch the data we are displaying
154void WatchScreen::get_current_status()
155{
8a75ef4a 156 // get spindle status
1ae7e276
JM
157 struct pad_switch s;
158 bool ok = PublicData::get_value( switch_checksum, fan_checksum, 0, &s );
f1aac8df 159 if (ok) {
8a75ef4a 160 this->spindle_state = s.state;
f1aac8df 161 } else {
8a75ef4a
JM
162 // spindle probably disabled
163 this->spindle_state = false;
f1aac8df 164 }
35089dc7
JM
165}
166
167// fetch the data we are displaying
1ad23cd3 168float WatchScreen::get_current_speed()
862fc625 169{
564cf1f0 170 // in percent
c8bac202 171 return 6000.0F / THEROBOT->get_seconds_per_minute();
35089dc7
JM
172}
173
862fc625
JM
174void WatchScreen::get_sd_play_info()
175{
58d6d841 176 void *returned_data;
75e6428d 177 bool ok = PublicData::get_value( player_checksum, get_progress_checksum, &returned_data );
862fc625
JM
178 if (ok) {
179 struct pad_progress p = *static_cast<struct pad_progress *>(returned_data);
180 this->elapsed_time = p.elapsed_secs;
181 this->sd_pcnt_played = p.percent_complete;
cee1bb2d 182 THEPANEL->set_playing_file(p.filename);
4c8afa75 183
862fc625
JM
184 } else {
185 this->elapsed_time = 0;
186 this->sd_pcnt_played = 0;
58d6d841 187 }
35089dc7
JM
188}
189
862fc625
JM
190void WatchScreen::display_menu_line(uint16_t line)
191{
58d6d841 192 // in menu mode
862fc625 193 switch ( line ) {
c8bac202 194 case 0: THEPANEL->lcd->printf(" WCS MCS %s", THEROBOT->inch_mode ? "in" : "mm"); break;
8a75ef4a
JM
195 case 1: THEPANEL->lcd->printf("X %8.3f %8.3f", wpos[0], mpos[0]); break;
196 case 2: THEPANEL->lcd->printf("Y %8.3f %8.3f", wpos[1], mpos[1]); break;
197 case 3: THEPANEL->lcd->printf("Z %8.3f %8.3f", wpos[2], mpos[2]); break;
c7f4902c 198 case 4: THEPANEL->lcd->printf("%s F%6.1f/%6.1f", this->wcs.c_str(), // display requested feedrate and actual feedrate
c8bac202
JM
199 THEROBOT->from_millimeters(THEROBOT->get_feed_rate()),
200 THEROBOT->from_millimeters(THEKERNEL->conveyor->get_current_feedrate()*60.0F));
c7f4902c 201 break;
381fbb3b
JM
202 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;
203 case 6: THEPANEL->lcd->printf("%19s", this->get_status()); break;
58d6d841 204 }
35089dc7 205}
84267f43 206
862fc625
JM
207const char *WatchScreen::get_status()
208{
5f1a896b 209 if (THEPANEL->hasMessage())
cee1bb2d 210 return THEPANEL->getMessage().c_str();
399cb110 211
73706276 212 if (THEKERNEL->is_halted())
8a75ef4a 213 return "ALARM";
76217df5 214
6589da62
JM
215 if (THEPANEL->is_suspended() || THEKERNEL->get_feed_hold())
216 return "Feed Hold";
5f1a896b 217
cee1bb2d
JM
218 if (THEPANEL->is_playing())
219 return THEPANEL->get_playing_file();
84267f43 220
7baa50df 221 if (!THECONVEYOR->is_idle())
8a75ef4a 222 return "Running";
691dcad3 223
d4ee6ee2
JM
224 const char *ip = get_network();
225 if (ip == NULL) {
8a75ef4a 226 return "Idle";
d4ee6ee2
JM
227 } else {
228 return ip;
229 }
84267f43 230}
dcf86322 231
862fc625
JM
232void WatchScreen::set_speed()
233{
2fa50ca0 234 send_gcode("M220", 'S', this->current_speed);
dcf86322 235}
d4ee6ee2
JM
236
237const char *WatchScreen::get_network()
238{
239 void *returned_data;
240
75e6428d 241 bool ok = PublicData::get_value( network_checksum, get_ip_checksum, &returned_data );
d4ee6ee2
JM
242 if (ok) {
243 uint8_t *ipaddr = (uint8_t *)returned_data;
244 char buf[20];
245 int n = snprintf(buf, sizeof(buf), "IP %d.%d.%d.%d", ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]);
246 buf[n] = 0;
383c9c1c
JM
247 if (this->ipstr == nullptr) {
248 this->ipstr = new char[n + 1];
d4ee6ee2
JM
249 }
250 strcpy(this->ipstr, buf);
251
252 return this->ipstr;
253 }
254
255 return NULL;
256}