add suspended status to panel
[clinton/Smoothieware.git] / src / modules / utils / panel / screens / WatchScreen.cpp
index ea8d38a..c83b363 100644 (file)
@@ -6,6 +6,7 @@
 */
 
 #include "libs/Kernel.h"
+#include "LcdBase.h"
 #include "Panel.h"
 #include "PanelScreen.h"
 #include "MainMenuScreen.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
@@ -55,14 +60,20 @@ WatchScreen::WatchScreen()
 {
     speed_changed = false;
     issue_change_speed = false;
-    ipstr = NULL;
+    ipstr = nullptr;
+    update_counts= 0;
+}
+
+WatchScreen::~WatchScreen()
+{
+    delete[] ipstr;
 }
 
 void WatchScreen::on_enter()
 {
     THEPANEL->lcd->clear();
     THEPANEL->setup_menu(4);
-    get_temp_data();
+    get_current_status();
     get_current_pos(this->pos);
     get_sd_play_info();
     this->current_speed = lround(get_current_speed());
@@ -95,12 +106,11 @@ 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;
@@ -114,9 +124,28 @@ void WatchScreen::on_refresh()
         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
-        THEPANEL->lcd->setLed(LED_BED_ON, this->bedtarget > 0);
-        THEPANEL->lcd->setLed(LED_HOTEND_ON, this->hotendtarget > 0);
+        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);
+
         THEPANEL->lcd->setLed(LED_FAN_ON, this->fan_state);
 
         if (THEPANEL->lcd->hasGraphics()) {
@@ -125,11 +154,12 @@ void WatchScreen::on_refresh()
             // for (int i = 0; i < 5; ++i) {
             //     THEPANEL->lcd->bltGlyph(i*24, 38, 23, 19, icons, 15, i*24, 0);
             // }
-            if (this->hotendtarget > 0)
-                THEPANEL->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)
-                THEPANEL->lcd->bltGlyph(32, 38, 23, 19, icons, 15, 64, 0);
+            if (bed_on)
+                THEPANEL->lcd->bltGlyph(60, 38, 23, 19, icons, 15, 64, 0);
 
             if(this->fan_state)
                 THEPANEL->lcd->bltGlyph(96, 38, 23, 19, icons, 15, 96, 0);
@@ -144,43 +174,29 @@ 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 );
-    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;
-    } else {
-        // temp probably disabled
-        this->hotendtemp = -1;
-        this->hotendtarget = -1;
-    }
+// fetch the data we are displaying
+void WatchScreen::get_current_status()
+{
+    void *returned_data;
+    bool ok;
 
     // get fan status
-    ok = THEKERNEL->public_data->get_value( switch_checksum, fan_checksum, 0, &returned_data );
+    ok = PublicData::get_value( switch_checksum, fan_checksum, 0, &returned_data );
     if (ok) {
         struct pad_switch s = *static_cast<struct pad_switch *>(returned_data);
         this->fan_state = s.state;
@@ -195,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;
@@ -207,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];
@@ -219,7 +235,7 @@ 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;
@@ -236,7 +252,36 @@ void WatchScreen::display_menu_line(uint16_t line)
 {
     // in menu mode
     switch ( line ) {
-        case 0: THEPANEL->lcd->printf("H%03d/%03dc B%03d/%03dc", this->hotendtemp, this->hotendtarget, this->bedtemp, this->bedtarget); 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;
@@ -245,19 +290,23 @@ void WatchScreen::display_menu_line(uint16_t line)
 
 const char *WatchScreen::get_status()
 {
-    if (THEPANEL->hasMessage()) {
+    if (THEPANEL->hasMessage())
         return THEPANEL->getMessage().c_str();
-    }
+
+    if (THEPANEL->is_halted())
+        return "HALTED Reset or M999";
 
     if (THEKERNEL->pauser->paused())
         return "Paused";
 
+    if (THEPANEL->is_suspended())
+        return "Suspended";
+
     if (THEPANEL->is_playing())
         return THEPANEL->get_playing_file();
 
-    if (!THEKERNEL->conveyor->is_queue_empty()) {
+    if (!THEKERNEL->conveyor->is_queue_empty())
         return "Printing";
-    }
 
     const char *ip = get_network();
     if (ip == NULL) {
@@ -276,14 +325,14 @@ 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);