Fork of Smoothie to port to mbed non-LPC targets.

Dependencies:   mbed

Fork of Smoothie by Stéphane Cachat

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers WatchScreen.cpp Source File

WatchScreen.cpp

00001 /*
00002       This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
00003       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.
00004       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.
00005       You should have received a copy of the GNU General Public License along with Smoothie. If not, see <http://www.gnu.org/licenses/>.
00006 */
00007 
00008 #include "libs/Kernel.h"
00009 #include "Panel.h"
00010 #include "PanelScreen.h"
00011 #include "MainMenuScreen.h"
00012 #include "WatchScreen.h"
00013 #include "libs/nuts_bolts.h"
00014 #include "libs/utils.h"
00015 #include "modules/tools/temperaturecontrol/TemperatureControlPublicAccess.h"
00016 #include "modules/robot/RobotPublicAccess.h"
00017 #include "modules/robot/Conveyor.h"
00018 #include "modules/utils/player/PlayerPublicAccess.h"
00019 #include "NetworkPublicAccess.h"
00020 
00021 #include <string>
00022 using namespace std;
00023 static const uint8_t icons[] = { // 115x19 - 3 bytes each: he1, he2, he3, bed, fan
00024     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0,
00025     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0xE0,
00026     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x0C, 0x60,
00027     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x0E, 0x20,
00028     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x0F, 0x20,
00029     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x0F, 0xA0,
00030     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5E, 0x07, 0xA0,
00031     0x7F, 0x80, 0x00, 0x3F, 0xC0, 0x00, 0x3F, 0xC0, 0x00, 0x41, 0x04, 0x00, 0x40, 0x60, 0x20,
00032     0xFB, 0xC0, 0x00, 0x79, 0xE0, 0x00, 0x79, 0xE0, 0x00, 0x20, 0x82, 0x00, 0x40, 0xF0, 0x20,
00033     0xF3, 0xC0, 0x00, 0x76, 0xE0, 0x00, 0x76, 0xE0, 0x00, 0x20, 0x82, 0x00, 0x40, 0xF0, 0x20,
00034     0xEB, 0xC0, 0x00, 0x7E, 0xE0, 0x00, 0x7E, 0xE0, 0x00, 0x41, 0x04, 0x00, 0x40, 0x60, 0x20,
00035     0x7B, 0x80, 0x00, 0x3D, 0xC0, 0x00, 0x39, 0xC0, 0x00, 0x82, 0x08, 0x00, 0x5E, 0x07, 0xA0,
00036     0x7B, 0x80, 0x00, 0x3B, 0xC0, 0x00, 0x3E, 0xC0, 0x01, 0x04, 0x10, 0x00, 0x5F, 0x0F, 0xA0,
00037     0xFB, 0xC0, 0x00, 0x77, 0xE0, 0x00, 0x76, 0xE0, 0x01, 0x04, 0x10, 0x00, 0x4F, 0x0F, 0x20,
00038     0xFB, 0xC0, 0x00, 0x70, 0xE0, 0x00, 0x79, 0xE0, 0x00, 0x82, 0x08, 0x00, 0x47, 0x0E, 0x20,
00039     0xFF, 0xC0, 0x00, 0x7F, 0xE0, 0x00, 0x7F, 0xE0, 0x00, 0x41, 0x04, 0x00, 0x63, 0x0C, 0x60,
00040     0x3F, 0x00, 0x00, 0x1F, 0x80, 0x00, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0xE0,
00041     0x1E, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x0F, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0xE0,
00042     0x0C, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00
00043 };
00044 
00045 
00046 
00047 WatchScreen::WatchScreen()
00048 {
00049     speed_changed = false;
00050     issue_change_speed = false;
00051     ipstr = NULL;
00052 }
00053 
00054 void WatchScreen::on_enter()
00055 {
00056     this->panel->lcd->clear();
00057     this->panel->setup_menu(4);
00058     get_temp_data();
00059     get_current_pos(this->pos);
00060     get_sd_play_info();
00061     this->current_speed = lround(get_current_speed());
00062     this->refresh_screen(false);
00063     this->panel->enter_control_mode(1, 0.5);
00064     this->panel->set_control_value(this->current_speed);
00065 }
00066 
00067 void WatchScreen::on_refresh()
00068 {
00069     // Exit if the button is clicked
00070     if ( this->panel->click() ) {
00071         this->panel->enter_screen(this->parent);
00072         return;
00073     }
00074 
00075     // see if speed is being changed
00076     if (this->panel->control_value_change()) {
00077         this->current_speed = this->panel->get_control_value();
00078         if (this->current_speed < 10) {
00079             this->current_speed = 10;
00080             this->panel->set_control_value(this->current_speed);
00081             this->panel->reset_counter();
00082         } else {
00083             // flag the update to change the speed, we don't want to issue hundreds of M220s
00084             // but we do want to display the change we are going to make
00085             this->speed_changed = true; // flag indicating speed changed
00086             this->refresh_screen(false);
00087         }
00088     }
00089 
00090     // Update Only every 20 refreshes, 1 a second
00091     static int update_counts = 0;
00092     update_counts++;
00093     if ( update_counts % 20 == 0 ) {
00094         get_sd_play_info();
00095         get_current_pos(this->pos);
00096         get_temp_data();
00097         if (this->speed_changed) {
00098             this->issue_change_speed = true; // trigger actual command to change speed
00099             this->speed_changed = false;
00100         } else if (!this->issue_change_speed) { // change still queued
00101             // read it in case it was changed via M220
00102             this->current_speed = lround(get_current_speed());
00103             this->panel->set_control_value(this->current_speed);
00104             this->panel->reset_counter();
00105         }
00106 
00107         this->refresh_screen(this->panel->lcd->hasGraphics() ? true : false); // graphics screens should be cleared
00108 
00109         // for LCDs with leds set them according to heater status
00110         // TODO should be enabled and disabled and settable from config
00111         this->panel->lcd->setLed(LED_BED_ON, this->bedtarget > 0);
00112         this->panel->lcd->setLed(LED_HOTEND_ON, this->hotendtarget > 0);
00113         //this->panel->lcd->setLed(LED_FAN_ON, this->fanon);
00114 
00115         if (this->panel->lcd->hasGraphics()) {
00116             // display the graphical icons below the status are
00117             //this->panel->lcd->bltGlyph(0, 34, 115, 19, icons);
00118             // for (int i = 0; i < 5; ++i) {
00119             //     this->panel->lcd->bltGlyph(i*24, 38, 23, 19, icons, 15, i*24, 0);
00120             // }
00121             if (this->hotendtarget > 0)
00122                 this->panel->lcd->bltGlyph(8, 38, 20, 19, icons, 15, 0, 0);
00123 
00124             if (this->bedtarget > 0)
00125                 this->panel->lcd->bltGlyph(32, 38, 23, 19, icons, 15, 64, 0);
00126 
00127             // fan appears always on for now
00128             this->panel->lcd->bltGlyph(96, 38, 23, 19, icons, 15, 96, 0);
00129         }
00130     }
00131 }
00132 
00133 // queuing gcodes needs to be done from main loop
00134 void WatchScreen::on_main_loop()
00135 {
00136     if (this->issue_change_speed) {
00137         this->issue_change_speed = false;
00138         set_speed();
00139     }
00140 }
00141 
00142 // fetch the data we are displaying
00143 void WatchScreen::get_temp_data()
00144 {
00145     void *returned_data;
00146     bool ok;
00147 
00148     ok = THEKERNEL->public_data->get_value( temperature_control_checksum, bed_checksum, current_temperature_checksum, &returned_data );
00149     if (ok) {
00150         struct pad_temperature temp =  *static_cast<struct pad_temperature *>(returned_data);
00151         this->bedtemp = round(temp.current_temperature);
00152         if (this->bedtemp > 100000) this->bedtemp = -2;
00153         this->bedtarget = round(temp.target_temperature);
00154         //this->bedpwm= temp.pwm;
00155     } else {
00156         // temp probably disabled
00157         this->bedtemp = -1;
00158         this->bedtarget = -1;
00159     }
00160 
00161 
00162     ok = THEKERNEL->public_data->get_value( temperature_control_checksum, hotend_checksum, current_temperature_checksum, &returned_data );
00163     if (ok) {
00164         struct pad_temperature temp =  *static_cast<struct pad_temperature *>(returned_data);
00165         this->hotendtemp = round(temp.current_temperature);
00166         if (this->hotendtemp > 100000) this->hotendtemp = -2;
00167         this->hotendtarget = round(temp.target_temperature);
00168         //this->hotendpwm= temp.pwm;
00169     } else {
00170         // temp probably disabled
00171         this->hotendtemp = -1;
00172         this->hotendtarget = -1;
00173     }
00174 }
00175 
00176 // fetch the data we are displaying
00177 float WatchScreen::get_current_speed()
00178 {
00179     void *returned_data;
00180 
00181     bool ok = THEKERNEL->public_data->get_value( robot_checksum, speed_override_percent_checksum, &returned_data );
00182     if (ok) {
00183         float cs = *static_cast<float *>(returned_data);
00184         return cs;
00185     }
00186     return 0.0;
00187 }
00188 
00189 void WatchScreen::get_current_pos(float *cp)
00190 {
00191     void *returned_data;
00192 
00193     bool ok = THEKERNEL->public_data->get_value( robot_checksum, current_position_checksum, &returned_data );
00194     if (ok) {
00195         float *p = static_cast<float *>(returned_data);
00196         cp[0] = p[0];
00197         cp[1] = p[1];
00198         cp[2] = p[2];
00199     }
00200 }
00201 
00202 void WatchScreen::get_sd_play_info()
00203 {
00204     void *returned_data;
00205     bool ok = THEKERNEL->public_data->get_value( player_checksum, get_progress_checksum, &returned_data );
00206     if (ok) {
00207         struct pad_progress p =  *static_cast<struct pad_progress *>(returned_data);
00208         this->elapsed_time = p.elapsed_secs;
00209         this->sd_pcnt_played = p.percent_complete;
00210         this->panel->set_playing_file(p.filename);
00211 
00212     } else {
00213         this->elapsed_time = 0;
00214         this->sd_pcnt_played = 0;
00215     }
00216 }
00217 
00218 void WatchScreen::display_menu_line(uint16_t line)
00219 {
00220     // in menu mode
00221     switch ( line ) {
00222         case 0: this->panel->lcd->printf("H%03d/%03dc B%03d/%03dc", this->hotendtemp, this->hotendtarget, this->bedtemp, this->bedtarget); break;
00223         case 1: this->panel->lcd->printf("X%4d Y%4d Z%7.2f", (int)round(this->pos[0]), (int)round(this->pos[1]), this->pos[2]); break;
00224         case 2: this->panel->lcd->printf("%3d%% %2lu:%02lu %3u%% sd", this->current_speed, this->elapsed_time / 60, this->elapsed_time % 60, this->sd_pcnt_played); break;
00225         case 3: this->panel->lcd->printf("%19s", this->get_status()); break;
00226     }
00227 }
00228 
00229 const char *WatchScreen::get_status()
00230 {
00231     if (panel->hasMessage()) {
00232         return panel->getMessage().c_str();
00233     }
00234 
00235     if (THEKERNEL->pauser->paused())
00236         return "Paused";
00237 
00238     if (panel->is_playing())
00239         return panel->get_playing_file();
00240 
00241     if (!THEKERNEL->conveyor->queue.is_empty()) {
00242         return "Printing";
00243     }
00244 
00245     const char *ip = get_network();
00246     if (ip == NULL) {
00247         return "Smoothie ready";
00248     } else {
00249         return ip;
00250     }
00251 }
00252 
00253 void WatchScreen::set_speed()
00254 {
00255     // change pos by issuing a M220 Snnn
00256     char buf[32];
00257     int n = snprintf(buf, sizeof(buf), "M220 S%d", this->current_speed);
00258     string g(buf, n);
00259     send_gcode(g);
00260 }
00261 
00262 const char *WatchScreen::get_network()
00263 {
00264     void *returned_data;
00265 
00266     bool ok = THEKERNEL->public_data->get_value( network_checksum, get_ip_checksum, &returned_data );
00267     if (ok) {
00268         uint8_t *ipaddr = (uint8_t *)returned_data;
00269         char buf[20];
00270         int n = snprintf(buf, sizeof(buf), "IP %d.%d.%d.%d", ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]);
00271         buf[n] = 0;
00272         if (this->ipstr == NULL) {
00273             this->ipstr = (char *)malloc(n + 1);
00274         }
00275         strcpy(this->ipstr, buf);
00276 
00277         return this->ipstr;
00278     }
00279 
00280     return NULL;
00281 }