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" |
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 | 33 | using namespace std; |
21384474 RP |
34 | static 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 |
48 | WatchScreen::WatchScreen() |
49 | { | |
50 | speed_changed = false; | |
51 | issue_change_speed = false; | |
383c9c1c | 52 | ipstr = nullptr; |
c77d6dae | 53 | update_counts= 0; |
383c9c1c JM |
54 | } |
55 | ||
56 | WatchScreen::~WatchScreen() | |
57 | { | |
58 | delete[] ipstr; | |
dcf86322 | 59 | } |
35089dc7 | 60 | |
862fc625 JM |
61 | void 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 |
74 | void 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 |
117 | void WatchScreen::get_wpos() |
118 | { | |
119 | // get real time positions | |
120 | // current actuator position in mm | |
121 | ActuatorCoordinates current_position{ | |
122 | THEKERNEL->robot->actuators[X_AXIS]->get_current_position(), | |
123 | THEKERNEL->robot->actuators[Y_AXIS]->get_current_position(), | |
124 | THEKERNEL->robot->actuators[Z_AXIS]->get_current_position() | |
125 | }; | |
126 | ||
127 | // get machine position from the actuator position using FK | |
128 | float mpos[3]; | |
129 | THEKERNEL->robot->arm_solution->actuator_to_cartesian(current_position, mpos); | |
130 | Robot::wcs_t wpos= THEKERNEL->robot->mcs2wcs(mpos); | |
131 | this->wpos[0]= THEKERNEL->robot->from_millimeters(std::get<X_AXIS>(wpos)); | |
132 | this->wpos[1]= THEKERNEL->robot->from_millimeters(std::get<Y_AXIS>(wpos)); | |
133 | this->wpos[2]= THEKERNEL->robot->from_millimeters(std::get<Z_AXIS>(wpos)); | |
134 | this->mpos[0]= THEKERNEL->robot->from_millimeters(mpos[0]); | |
135 | this->mpos[1]= THEKERNEL->robot->from_millimeters(mpos[1]); | |
136 | this->mpos[2]= THEKERNEL->robot->from_millimeters(mpos[2]); | |
381fbb3b JM |
137 | |
138 | std::vector<Robot::wcs_t> v= THEKERNEL->robot->get_wcs_state(); | |
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 |
144 | void 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 |
154 | void 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 | 168 | float WatchScreen::get_current_speed() |
862fc625 | 169 | { |
564cf1f0 JM |
170 | // in percent |
171 | return 6000.0F / THEKERNEL->robot->get_seconds_per_minute(); | |
35089dc7 JM |
172 | } |
173 | ||
862fc625 JM |
174 | void 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 |
190 | void WatchScreen::display_menu_line(uint16_t line) |
191 | { | |
58d6d841 | 192 | // in menu mode |
862fc625 | 193 | switch ( line ) { |
4d5a49bd | 194 | case 0: THEPANEL->lcd->printf(" WCS MCS %s", THEKERNEL->robot->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 JM |
198 | case 4: THEPANEL->lcd->printf("%s F%6.1f/%6.1f", this->wcs.c_str(), // display requested feedrate and actual feedrate |
199 | THEKERNEL->robot->from_millimeters(THEKERNEL->robot->get_feed_rate()), | |
788e5809 | 200 | THEKERNEL->robot->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 |
207 | const 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 | |
5f1a896b | 221 | if (!THEKERNEL->conveyor->is_queue_empty()) |
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 |
232 | void WatchScreen::set_speed() |
233 | { | |
2fa50ca0 | 234 | send_gcode("M220", 'S', this->current_speed); |
dcf86322 | 235 | } |
d4ee6ee2 JM |
236 | |
237 | const 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 | } |