add suspended status to panel
[clinton/Smoothieware.git] / src / modules / utils / panel / screens / WatchScreen.cpp
index 836b201..c83b363 100644 (file)
@@ -6,6 +6,7 @@
 */
 
 #include "libs/Kernel.h"
+#include "LcdBase.h"
 #include "Panel.h"
 #include "PanelScreen.h"
 #include "MainMenuScreen.h"
 #include "modules/robot/Conveyor.h"
 #include "modules/utils/player/PlayerPublicAccess.h"
 #include "NetworkPublicAccess.h"
+#include "PublicData.h"
+#include "SwitchPublicAccess.h"
+#include "checksumm.h"
+#include "Pauser.h"
+#include "TemperatureControlPool.h"
 
+
+#include <math.h>
+#include <string.h>
 #include <string>
+#include <stdio.h>
+#include <algorithm>
+
 using namespace std;
 static const uint8_t icons[] = { // 115x19 - 3 bytes each: he1, he2, he3, bed, fan
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0,
@@ -48,37 +60,43 @@ WatchScreen::WatchScreen()
 {
     speed_changed = false;
     issue_change_speed = false;
-    ipstr = NULL;
+    ipstr = nullptr;
+    update_counts= 0;
+}
+
+WatchScreen::~WatchScreen()
+{
+    delete[] ipstr;
 }
 
 void WatchScreen::on_enter()
 {
-    this->panel->lcd->clear();
-    this->panel->setup_menu(4);
-    get_temp_data();
+    THEPANEL->lcd->clear();
+    THEPANEL->setup_menu(4);
+    get_current_status();
     get_current_pos(this->pos);
     get_sd_play_info();
     this->current_speed = lround(get_current_speed());
     this->refresh_screen(false);
-    this->panel->enter_control_mode(1, 0.5);
-    this->panel->set_control_value(this->current_speed);
+    THEPANEL->enter_control_mode(1, 0.5);
+    THEPANEL->set_control_value(this->current_speed);
 }
 
 void WatchScreen::on_refresh()
 {
     // Exit if the button is clicked
-    if ( this->panel->click() ) {
-        this->panel->enter_screen(this->parent);
+    if ( THEPANEL->click() ) {
+        THEPANEL->enter_screen(this->parent);
         return;
     }
 
     // see if speed is being changed
-    if (this->panel->control_value_change()) {
-        this->current_speed = this->panel->get_control_value();
+    if (THEPANEL->control_value_change()) {
+        this->current_speed = THEPANEL->get_control_value();
         if (this->current_speed < 10) {
             this->current_speed = 10;
-            this->panel->set_control_value(this->current_speed);
-            this->panel->reset_counter();
+            THEPANEL->set_control_value(this->current_speed);
+            THEPANEL->reset_counter();
         } else {
             // flag the update to change the speed, we don't want to issue hundreds of M220s
             // but we do want to display the change we are going to make
@@ -88,44 +106,63 @@ void WatchScreen::on_refresh()
     }
 
     // Update Only every 20 refreshes, 1 a second
-    static int update_counts = 0;
     update_counts++;
     if ( update_counts % 20 == 0 ) {
         get_sd_play_info();
         get_current_pos(this->pos);
-        get_temp_data();
+        get_current_status();
         if (this->speed_changed) {
             this->issue_change_speed = true; // trigger actual command to change speed
             this->speed_changed = false;
         } else if (!this->issue_change_speed) { // change still queued
             // read it in case it was changed via M220
             this->current_speed = lround(get_current_speed());
-            this->panel->set_control_value(this->current_speed);
-            this->panel->reset_counter();
+            THEPANEL->set_control_value(this->current_speed);
+            THEPANEL->reset_counter();
         }
 
-        this->refresh_screen(this->panel->lcd->hasGraphics() ? true : false); // graphics screens should be cleared
+        this->refresh_screen(THEPANEL->lcd->hasGraphics() ? true : false); // graphics screens should be cleared
 
         // for LCDs with leds set them according to heater status
-        // TODO should be enabled and disabled and settable from config
-        this->panel->lcd->setLed(LED_BED_ON, this->bedtarget > 0);
-        this->panel->lcd->setLed(LED_HOTEND_ON, this->hotendtarget > 0);
-        //this->panel->lcd->setLed(LED_FAN_ON, this->fanon);
+        bool bed_on= false, hotend_on= false, is_hot= false;
+        uint8_t heon=0, hemsk= 0x01; // bit set for which hotend is on bit0: hotend1, bit1: hotend2 etc
+        for(auto m : THEKERNEL->temperature_control_pool->get_controllers()) {
+            // query each heater
+            void *p= getTemperatures(m);
+            struct pad_temperature *temp= static_cast<struct pad_temperature *>(p);
+            if(temp != nullptr) {
+                if(temp->current_temperature > 50) is_hot= true; // anything is hot
+                if(temp->designator.front() == 'B' && temp->target_temperature > 0) bed_on= true;   // bed on/off
+                if(temp->designator.front() == 'T') { // a hotend by convention
+                    if(temp->target_temperature > 0){
+                        hotend_on= true;// hotend on/off (anyone)
+                        heon |= hemsk;
+                    }
+                    hemsk <<= 1;
+                }
+            }
+        }
+        THEPANEL->lcd->setLed(LED_BED_ON, bed_on);
+        THEPANEL->lcd->setLed(LED_HOTEND_ON, hotend_on);
+        THEPANEL->lcd->setLed(LED_HOT, is_hot);
 
-        if (this->panel->lcd->hasGraphics()) {
+        THEPANEL->lcd->setLed(LED_FAN_ON, this->fan_state);
+
+        if (THEPANEL->lcd->hasGraphics()) {
             // display the graphical icons below the status are
-            //this->panel->lcd->bltGlyph(0, 34, 115, 19, icons);
+            //THEPANEL->lcd->bltGlyph(0, 34, 115, 19, icons);
             // for (int i = 0; i < 5; ++i) {
-            //     this->panel->lcd->bltGlyph(i*24, 38, 23, 19, icons, 15, i*24, 0);
+            //     THEPANEL->lcd->bltGlyph(i*24, 38, 23, 19, icons, 15, i*24, 0);
             // }
-            if (this->hotendtarget > 0)
-                this->panel->lcd->bltGlyph(8, 38, 20, 19, icons, 15, 0, 0);
+            if(heon&0x01) THEPANEL->lcd->bltGlyph(0, 38, 20, 19, icons, 15, 0, 0);
+            if(heon&0x02) THEPANEL->lcd->bltGlyph(20, 38, 20, 19, icons, 15, 24, 0);
+            if(heon&0x04) THEPANEL->lcd->bltGlyph(40, 38, 20, 19, icons, 15, 48, 0);
 
-            if (this->bedtarget > 0)
-                this->panel->lcd->bltGlyph(32, 38, 23, 19, icons, 15, 64, 0);
+            if (bed_on)
+                THEPANEL->lcd->bltGlyph(60, 38, 23, 19, icons, 15, 64, 0);
 
-            // fan appears always on for now
-            this->panel->lcd->bltGlyph(96, 38, 23, 19, icons, 15, 96, 0);
+            if(this->fan_state)
+                THEPANEL->lcd->bltGlyph(96, 38, 23, 19, icons, 15, 96, 0);
         }
     }
 }
@@ -137,39 +174,35 @@ void WatchScreen::on_main_loop()
         this->issue_change_speed = false;
         set_speed();
     }
+    PanelScreen::on_main_loop(); // in case any queued commands left
 }
 
-// fetch the data we are displaying
-void WatchScreen::get_temp_data()
+void *WatchScreen::getTemperatures(uint16_t heater_cs)
 {
     void *returned_data;
-    bool ok;
+    bool ok = PublicData::get_value( temperature_control_checksum, heater_cs, current_temperature_checksum, &returned_data );
 
-    ok = THEKERNEL->public_data->get_value( temperature_control_checksum, bed_checksum, current_temperature_checksum, &returned_data );
     if (ok) {
-        struct pad_temperature temp =  *static_cast<struct pad_temperature *>(returned_data);
-        this->bedtemp = round(temp.current_temperature);
-        if (this->bedtemp > 100000) this->bedtemp = -2;
-        this->bedtarget = round(temp.target_temperature);
-        //this->bedpwm= temp.pwm;
-    } else {
-        // temp probably disabled
-        this->bedtemp = -1;
-        this->bedtarget = -1;
+        return returned_data;
     }
 
+    return nullptr;
+}
 
-    ok = THEKERNEL->public_data->get_value( temperature_control_checksum, hotend_checksum, current_temperature_checksum, &returned_data );
+// fetch the data we are displaying
+void WatchScreen::get_current_status()
+{
+    void *returned_data;
+    bool ok;
+
+    // get fan status
+    ok = PublicData::get_value( switch_checksum, fan_checksum, 0, &returned_data );
     if (ok) {
-        struct pad_temperature temp =  *static_cast<struct pad_temperature *>(returned_data);
-        this->hotendtemp = round(temp.current_temperature);
-        if (this->hotendtemp > 100000) this->hotendtemp = -2;
-        this->hotendtarget = round(temp.target_temperature);
-        //this->hotendpwm= temp.pwm;
+        struct pad_switch s = *static_cast<struct pad_switch *>(returned_data);
+        this->fan_state = s.state;
     } else {
-        // temp probably disabled
-        this->hotendtemp = -1;
-        this->hotendtarget = -1;
+        // fan probably disabled
+        this->fan_state = false;
     }
 }
 
@@ -178,7 +211,7 @@ float WatchScreen::get_current_speed()
 {
     void *returned_data;
 
-    bool ok = THEKERNEL->public_data->get_value( robot_checksum, speed_override_percent_checksum, &returned_data );
+    bool ok = PublicData::get_value( robot_checksum, speed_override_percent_checksum, &returned_data );
     if (ok) {
         float cs = *static_cast<float *>(returned_data);
         return cs;
@@ -190,7 +223,7 @@ void WatchScreen::get_current_pos(float *cp)
 {
     void *returned_data;
 
-    bool ok = THEKERNEL->public_data->get_value( robot_checksum, current_position_checksum, &returned_data );
+    bool ok = PublicData::get_value( robot_checksum, current_position_checksum, &returned_data );
     if (ok) {
         float *p = static_cast<float *>(returned_data);
         cp[0] = p[0];
@@ -202,12 +235,12 @@ void WatchScreen::get_current_pos(float *cp)
 void WatchScreen::get_sd_play_info()
 {
     void *returned_data;
-    bool ok = THEKERNEL->public_data->get_value( player_checksum, get_progress_checksum, &returned_data );
+    bool ok = PublicData::get_value( player_checksum, get_progress_checksum, &returned_data );
     if (ok) {
         struct pad_progress p =  *static_cast<struct pad_progress *>(returned_data);
         this->elapsed_time = p.elapsed_secs;
         this->sd_pcnt_played = p.percent_complete;
-        this->panel->set_playing_file(p.filename);
+        THEPANEL->set_playing_file(p.filename);
 
     } else {
         this->elapsed_time = 0;
@@ -219,28 +252,61 @@ void WatchScreen::display_menu_line(uint16_t line)
 {
     // in menu mode
     switch ( line ) {
-        case 0: this->panel->lcd->printf("H%03d/%03dc B%03d/%03dc", this->hotendtemp, this->hotendtarget, this->bedtemp, this->bedtarget); break;
-        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;
-        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;
-        case 3: this->panel->lcd->printf("%19s", this->get_status()); break;
+        case 0:
+        {
+            auto& tm= THEKERNEL->temperature_control_pool->get_controllers();
+            if(tm.size() > 0) {
+                // only if we detected heaters in config
+                int n= 0;
+                if(tm.size() > 2) {
+                    // more than two temps we need to cycle between them
+                    n= update_counts/100; // increments every 5 seconds
+                    int ntemps= (tm.size()+1)/2;
+                    n= n%ntemps; // which of the pairs of temps to display
+                }
+
+                int off= 0;
+                for (size_t i = 0; i < 2; ++i) {
+                    size_t o= i+(n*2);
+                    if(o>tm.size()-1) break;
+                    struct pad_temperature *temp= static_cast<struct pad_temperature *>(getTemperatures(tm[o]));
+                    if(temp == nullptr) continue;
+                    int t= std::min(999, (int)roundf(temp->current_temperature));
+                    int tt= roundf(temp->target_temperature);
+                    THEPANEL->lcd->setCursor(off, 0); // col, row
+                    off += THEPANEL->lcd->printf("%s:%03d/%03d ", temp->designator.substr(0, 2).c_str(), t, tt);
+                }
+
+            }else{
+                //THEPANEL->lcd->printf("No Heaters");
+            }
+            break;
+        }
+        case 1: THEPANEL->lcd->printf("X%4d Y%4d Z%7.2f", (int)round(this->pos[0]), (int)round(this->pos[1]), this->pos[2]); break;
+        case 2: THEPANEL->lcd->printf("%3d%% %2lu:%02lu %3u%% sd", this->current_speed, this->elapsed_time / 60, this->elapsed_time % 60, this->sd_pcnt_played); break;
+        case 3: THEPANEL->lcd->printf("%19s", this->get_status()); break;
     }
 }
 
 const char *WatchScreen::get_status()
 {
-    if (panel->hasMessage()) {
-        return panel->getMessage().c_str();
-    }
+    if (THEPANEL->hasMessage())
+        return THEPANEL->getMessage().c_str();
+
+    if (THEPANEL->is_halted())
+        return "HALTED Reset or M999";
 
     if (THEKERNEL->pauser->paused())
         return "Paused";
 
-    if (panel->is_playing())
-        return panel->get_playing_file();
+    if (THEPANEL->is_suspended())
+        return "Suspended";
 
-    if (!THEKERNEL->conveyor->queue.is_empty()) {
+    if (THEPANEL->is_playing())
+        return THEPANEL->get_playing_file();
+
+    if (!THEKERNEL->conveyor->is_queue_empty())
         return "Printing";
-    }
 
     const char *ip = get_network();
     if (ip == NULL) {
@@ -252,25 +318,21 @@ const char *WatchScreen::get_status()
 
 void WatchScreen::set_speed()
 {
-    // change pos by issuing a M220 Snnn
-    char buf[32];
-    int n = snprintf(buf, sizeof(buf), "M220 S%d", this->current_speed);
-    string g(buf, n);
-    send_gcode(g);
+    send_gcode("M220", 'S', this->current_speed);
 }
 
 const char *WatchScreen::get_network()
 {
     void *returned_data;
 
-    bool ok = THEKERNEL->public_data->get_value( network_checksum, get_ip_checksum, &returned_data );
+    bool ok = PublicData::get_value( network_checksum, get_ip_checksum, &returned_data );
     if (ok) {
         uint8_t *ipaddr = (uint8_t *)returned_data;
         char buf[20];
         int n = snprintf(buf, sizeof(buf), "IP %d.%d.%d.%d", ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]);
         buf[n] = 0;
-        if (this->ipstr == NULL) {
-            this->ipstr = (char *)malloc(n + 1);
+        if (this->ipstr == nullptr) {
+            this->ipstr = new char[n + 1];
         }
         strcpy(this->ipstr, buf);