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/>.
8 #include "libs/Kernel.h"
11 #include "PanelScreen.h"
12 #include "MainMenuScreen.h"
13 #include "WatchScreen.h"
14 #include "libs/nuts_bolts.h"
15 #include "libs/utils.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"
27 #ifndef NO_TOOLS_LASER
39 #define laser_checksum CHECKSUM("laser")
41 WatchScreen::WatchScreen()
43 speed_changed
= false;
44 issue_change_speed
= false;
49 WatchScreen::~WatchScreen()
54 void WatchScreen::on_enter()
56 THEPANEL
->lcd
->clear();
57 THEPANEL
->setup_menu(8);
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
);
67 void WatchScreen::on_refresh()
69 // Exit if the button is clicked
70 if ( THEPANEL
->click() ) {
71 THEPANEL
->enter_screen(this->parent
);
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();
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);
90 // Update Only every 20 refreshes, 1 a second
92 if ( update_counts
% 20 == 0 ) {
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();
106 this->refresh_screen(THEPANEL
->lcd
->hasGraphics() ? true : false); // graphics screens should be cleared
110 void WatchScreen::get_wpos()
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()
120 // get machine position from the actuator position using FK
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]);
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
);
136 // queuing gcodes needs to be done from main loop
137 void WatchScreen::on_main_loop()
139 if (this->issue_change_speed
) {
140 this->issue_change_speed
= false;
143 PanelScreen::on_main_loop(); // in case any queued commands left
146 // fetch the data we are displaying
147 void WatchScreen::get_current_status()
149 // get spindle status
151 bool ok
= PublicData::get_value( switch_checksum
, fan_checksum
, 0, &s
);
153 this->spindle_state
= s
.state
;
155 // spindle probably disabled
156 this->spindle_state
= false;
160 // fetch the data we are displaying
161 float WatchScreen::get_current_speed()
164 return 6000.0F
/ THEROBOT
->get_seconds_per_minute();
167 void WatchScreen::get_sd_play_info()
170 bool ok
= PublicData::get_value( player_checksum
, get_progress_checksum
, &returned_data
);
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
);
178 this->elapsed_time
= 0;
179 this->sd_pcnt_played
= 0;
183 void WatchScreen::display_menu_line(uint16_t 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
));
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;
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());
206 case 7: THEPANEL
->lcd
->printf("%19s", this->get_status()); break;
210 const char *WatchScreen::get_status()
212 if (THEPANEL
->hasMessage())
213 return THEPANEL
->getMessage().c_str();
215 if (THEKERNEL
->is_halted())
218 if (THEPANEL
->is_suspended() /*|| THEKERNEL->get_feed_hold()*/)
221 if (THEPANEL
->is_playing())
222 return THEPANEL
->get_playing_file();
224 if (!THECONVEYOR
->is_idle())
227 const char *ip
= get_network();
235 void WatchScreen::set_speed()
237 send_gcode("M220", 'S', this->current_speed
);
240 const char *WatchScreen::get_network()
244 bool ok
= PublicData::get_value( network_checksum
, get_ip_checksum
, &returned_data
);
246 uint8_t *ipaddr
= (uint8_t *)returned_data
;
248 int n
= snprintf(buf
, sizeof(buf
), "IP %d.%d.%d.%d", ipaddr
[0], ipaddr
[1], ipaddr
[2], ipaddr
[3]);
250 if (this->ipstr
== nullptr) {
251 this->ipstr
= new char[n
+ 1];
253 strcpy(this->ipstr
, buf
);