Commit | Line | Data |
---|---|---|
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" |
691dcad3 | 17 | #include "modules/robot/Conveyor.h" |
35089dc7 | 18 | #include "modules/utils/player/PlayerPublicAccess.h" |
d4ee6ee2 | 19 | #include "NetworkPublicAccess.h" |
61134a65 | 20 | #include "PublicData.h" |
f1aac8df | 21 | #include "SwitchPublicAccess.h" |
61134a65 | 22 | #include "checksumm.h" |
8a75ef4a JM |
23 | #include "StepperMotor.h" |
24 | #include "BaseSolution.h" | |
02e4b295 | 25 | |
61134a65 JM |
26 | #include <math.h> |
27 | #include <string.h> | |
35089dc7 | 28 | #include <string> |
383c9c1c | 29 | #include <stdio.h> |
373d0bf1 | 30 | #include <algorithm> |
61134a65 | 31 | |
35089dc7 | 32 | using namespace std; |
21384474 RP |
33 | static const uint8_t icons[] = { // 16x80 - he1, he2, he3, bed, fan |
34 | 0x3f, 0xfc, 0x3f, 0xfc, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0x7f, 0x7f, 0x7e, 0x3f, 0x7c, 0x1f, | |
35 | 0x78, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x01, 0x80, | |
36 | 0x01, 0x80, 0x3f, 0xfc, 0x3f, 0xfc, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0x7f, 0x7c, 0x7e, 0x3d, | |
37 | 0xfc, 0x1c, 0x78, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, | |
38 | 0x01, 0x80, 0x01, 0x80, 0x3f, 0xfc, 0x3f, 0xfc, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0x7f, 0x7c, | |
39 | 0x7e, 0x3f, 0x7c, 0x1c, 0x78, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, | |
40 | 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x00, 0x00, 0x08, 0x88, 0x11, 0x10, 0x22, 0x20, 0x22, | |
41 | 0x20, 0x11, 0x10, 0x08, 0x88, 0x04, 0x44, 0x04, 0x44, 0x08, 0x88, 0x11, 0x10, 0x22, 0x20, | |
42 | 0x00, 0x00, 0x7f, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0x39, 0xec, 0x43, 0xe2, 0x9b, 0xc9, 0xa3, | |
43 | 0x85, 0x03, 0x85, 0xc3, 0x00, 0xe0, 0x3e, 0xf9, 0xbf, 0xfd, 0x9f, 0x7c, 0x07, 0x00, 0xc3, | |
44 | 0xa1, 0xc0, 0xa1, 0xc5, 0x93, 0xd9, 0x47, 0xc2, 0x37, 0x9c | |
ebc64506 | 45 | }; |
35089dc7 | 46 | |
862fc625 JM |
47 | WatchScreen::WatchScreen() |
48 | { | |
49 | speed_changed = false; | |
50 | issue_change_speed = false; | |
383c9c1c | 51 | ipstr = nullptr; |
c77d6dae | 52 | update_counts= 0; |
383c9c1c JM |
53 | } |
54 | ||
55 | WatchScreen::~WatchScreen() | |
56 | { | |
57 | delete[] ipstr; | |
dcf86322 | 58 | } |
35089dc7 | 59 | |
862fc625 JM |
60 | void WatchScreen::on_enter() |
61 | { | |
cee1bb2d | 62 | THEPANEL->lcd->clear(); |
8a75ef4a | 63 | THEPANEL->setup_menu(7); |
c77d6dae | 64 | get_current_status(); |
8a75ef4a | 65 | get_wpos(); |
58d6d841 | 66 | get_sd_play_info(); |
586cc733 | 67 | this->current_speed = lroundf(get_current_speed()); |
58d6d841 | 68 | this->refresh_screen(false); |
cee1bb2d JM |
69 | THEPANEL->enter_control_mode(1, 0.5); |
70 | THEPANEL->set_control_value(this->current_speed); | |
35089dc7 JM |
71 | } |
72 | ||
862fc625 JM |
73 | void WatchScreen::on_refresh() |
74 | { | |
3105a7be | 75 | // Exit if the button is clicked |
cee1bb2d JM |
76 | if ( THEPANEL->click() ) { |
77 | THEPANEL->enter_screen(this->parent); | |
35089dc7 | 78 | return; |
58d6d841 JM |
79 | } |
80 | ||
81 | // see if speed is being changed | |
cee1bb2d JM |
82 | if (THEPANEL->control_value_change()) { |
83 | this->current_speed = THEPANEL->get_control_value(); | |
862fc625 JM |
84 | if (this->current_speed < 10) { |
85 | this->current_speed = 10; | |
cee1bb2d JM |
86 | THEPANEL->set_control_value(this->current_speed); |
87 | THEPANEL->reset_counter(); | |
862fc625 | 88 | } else { |
3f038f58 JM |
89 | // flag the update to change the speed, we don't want to issue hundreds of M220s |
90 | // but we do want to display the change we are going to make | |
862fc625 | 91 | this->speed_changed = true; // flag indicating speed changed |
7a522ccc JM |
92 | this->refresh_screen(false); |
93 | } | |
58d6d841 | 94 | } |
3105a7be | 95 | |
35089dc7 | 96 | // Update Only every 20 refreshes, 1 a second |
35089dc7 | 97 | update_counts++; |
862fc625 | 98 | if ( update_counts % 20 == 0 ) { |
58d6d841 | 99 | get_sd_play_info(); |
8a75ef4a | 100 | get_wpos(); |
c77d6dae | 101 | get_current_status(); |
862fc625 JM |
102 | if (this->speed_changed) { |
103 | this->issue_change_speed = true; // trigger actual command to change speed | |
104 | this->speed_changed = false; | |
105 | } else if (!this->issue_change_speed) { // change still queued | |
3f038f58 | 106 | // read it in case it was changed via M220 |
586cc733 | 107 | this->current_speed = lroundf(get_current_speed()); |
cee1bb2d JM |
108 | THEPANEL->set_control_value(this->current_speed); |
109 | THEPANEL->reset_counter(); | |
3f038f58 | 110 | } |
7a522ccc | 111 | |
cee1bb2d | 112 | this->refresh_screen(THEPANEL->lcd->hasGraphics() ? true : false); // graphics screens should be cleared |
35089dc7 JM |
113 | } |
114 | } | |
115 | ||
8a75ef4a JM |
116 | void WatchScreen::get_wpos() |
117 | { | |
118 | // get real time positions | |
119 | // current actuator position in mm | |
120 | ActuatorCoordinates current_position{ | |
121 | THEKERNEL->robot->actuators[X_AXIS]->get_current_position(), | |
122 | THEKERNEL->robot->actuators[Y_AXIS]->get_current_position(), | |
123 | THEKERNEL->robot->actuators[Z_AXIS]->get_current_position() | |
124 | }; | |
125 | ||
126 | // get machine position from the actuator position using FK | |
127 | float mpos[3]; | |
128 | THEKERNEL->robot->arm_solution->actuator_to_cartesian(current_position, mpos); | |
129 | Robot::wcs_t wpos= THEKERNEL->robot->mcs2wcs(mpos); | |
130 | this->wpos[0]= THEKERNEL->robot->from_millimeters(std::get<X_AXIS>(wpos)); | |
131 | this->wpos[1]= THEKERNEL->robot->from_millimeters(std::get<Y_AXIS>(wpos)); | |
132 | this->wpos[2]= THEKERNEL->robot->from_millimeters(std::get<Z_AXIS>(wpos)); | |
133 | this->mpos[0]= THEKERNEL->robot->from_millimeters(mpos[0]); | |
134 | this->mpos[1]= THEKERNEL->robot->from_millimeters(mpos[1]); | |
135 | this->mpos[2]= THEKERNEL->robot->from_millimeters(mpos[2]); | |
381fbb3b JM |
136 | |
137 | std::vector<Robot::wcs_t> v= THEKERNEL->robot->get_wcs_state(); | |
138 | char current_wcs= std::get<0>(v[0]); | |
139 | this->wcs= wcs2gcode(current_wcs); | |
8a75ef4a JM |
140 | } |
141 | ||
dcf86322 | 142 | // queuing gcodes needs to be done from main loop |
862fc625 JM |
143 | void WatchScreen::on_main_loop() |
144 | { | |
145 | if (this->issue_change_speed) { | |
146 | this->issue_change_speed = false; | |
3f038f58 JM |
147 | set_speed(); |
148 | } | |
f15e6f4b | 149 | PanelScreen::on_main_loop(); // in case any queued commands left |
dcf86322 JM |
150 | } |
151 | ||
c77d6dae JM |
152 | // fetch the data we are displaying |
153 | void WatchScreen::get_current_status() | |
154 | { | |
8a75ef4a | 155 | // get spindle status |
1ae7e276 JM |
156 | struct pad_switch s; |
157 | bool ok = PublicData::get_value( switch_checksum, fan_checksum, 0, &s ); | |
f1aac8df | 158 | if (ok) { |
8a75ef4a | 159 | this->spindle_state = s.state; |
f1aac8df | 160 | } else { |
8a75ef4a JM |
161 | // spindle probably disabled |
162 | this->spindle_state = false; | |
f1aac8df | 163 | } |
35089dc7 JM |
164 | } |
165 | ||
166 | // fetch the data we are displaying | |
1ad23cd3 | 167 | float WatchScreen::get_current_speed() |
862fc625 | 168 | { |
564cf1f0 JM |
169 | // in percent |
170 | return 6000.0F / THEKERNEL->robot->get_seconds_per_minute(); | |
35089dc7 JM |
171 | } |
172 | ||
862fc625 JM |
173 | void WatchScreen::get_sd_play_info() |
174 | { | |
58d6d841 | 175 | void *returned_data; |
75e6428d | 176 | bool ok = PublicData::get_value( player_checksum, get_progress_checksum, &returned_data ); |
862fc625 JM |
177 | if (ok) { |
178 | struct pad_progress p = *static_cast<struct pad_progress *>(returned_data); | |
179 | this->elapsed_time = p.elapsed_secs; | |
180 | this->sd_pcnt_played = p.percent_complete; | |
cee1bb2d | 181 | THEPANEL->set_playing_file(p.filename); |
4c8afa75 | 182 | |
862fc625 JM |
183 | } else { |
184 | this->elapsed_time = 0; | |
185 | this->sd_pcnt_played = 0; | |
58d6d841 | 186 | } |
35089dc7 JM |
187 | } |
188 | ||
862fc625 JM |
189 | void WatchScreen::display_menu_line(uint16_t line) |
190 | { | |
58d6d841 | 191 | // in menu mode |
862fc625 | 192 | switch ( line ) { |
8a75ef4a JM |
193 | case 0: THEPANEL->lcd->printf(" WCS MCS "); break; |
194 | case 1: THEPANEL->lcd->printf("X %8.3f %8.3f", wpos[0], mpos[0]); break; | |
195 | case 2: THEPANEL->lcd->printf("Y %8.3f %8.3f", wpos[1], mpos[1]); break; | |
196 | case 3: THEPANEL->lcd->printf("Z %8.3f %8.3f", wpos[2], mpos[2]); break; | |
381fbb3b JM |
197 | case 4: THEPANEL->lcd->printf("WCS %s FR %6.1f", this->wcs.c_str(), THEKERNEL->robot->get_feed_rate()); break; |
198 | 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; | |
199 | case 6: THEPANEL->lcd->printf("%19s", this->get_status()); break; | |
58d6d841 | 200 | } |
35089dc7 | 201 | } |
84267f43 | 202 | |
862fc625 JM |
203 | const char *WatchScreen::get_status() |
204 | { | |
5f1a896b | 205 | if (THEPANEL->hasMessage()) |
cee1bb2d | 206 | return THEPANEL->getMessage().c_str(); |
399cb110 | 207 | |
73706276 | 208 | if (THEKERNEL->is_halted()) |
8a75ef4a | 209 | return "ALARM"; |
76217df5 | 210 | |
5f1a896b JM |
211 | if (THEPANEL->is_suspended()) |
212 | return "Suspended"; | |
213 | ||
cee1bb2d JM |
214 | if (THEPANEL->is_playing()) |
215 | return THEPANEL->get_playing_file(); | |
84267f43 | 216 | |
5f1a896b | 217 | if (!THEKERNEL->conveyor->is_queue_empty()) |
8a75ef4a | 218 | return "Running"; |
691dcad3 | 219 | |
d4ee6ee2 JM |
220 | const char *ip = get_network(); |
221 | if (ip == NULL) { | |
8a75ef4a | 222 | return "Idle"; |
d4ee6ee2 JM |
223 | } else { |
224 | return ip; | |
225 | } | |
84267f43 | 226 | } |
dcf86322 | 227 | |
862fc625 JM |
228 | void WatchScreen::set_speed() |
229 | { | |
2fa50ca0 | 230 | send_gcode("M220", 'S', this->current_speed); |
dcf86322 | 231 | } |
d4ee6ee2 JM |
232 | |
233 | const char *WatchScreen::get_network() | |
234 | { | |
235 | void *returned_data; | |
236 | ||
75e6428d | 237 | bool ok = PublicData::get_value( network_checksum, get_ip_checksum, &returned_data ); |
d4ee6ee2 JM |
238 | if (ok) { |
239 | uint8_t *ipaddr = (uint8_t *)returned_data; | |
240 | char buf[20]; | |
241 | int n = snprintf(buf, sizeof(buf), "IP %d.%d.%d.%d", ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); | |
242 | buf[n] = 0; | |
383c9c1c JM |
243 | if (this->ipstr == nullptr) { |
244 | this->ipstr = new char[n + 1]; | |
d4ee6ee2 JM |
245 | } |
246 | strcpy(this->ipstr, buf); | |
247 | ||
248 | return this->ipstr; | |
249 | } | |
250 | ||
251 | return NULL; | |
252 | } |