Claan up and refactor new edge detection actions for TemperatureSwitch.
authorJim Morris <morris@wolfman.com>
Thu, 10 Sep 2015 06:44:21 +0000 (23:44 -0700)
committerJim Morris <morris@wolfman.com>
Thu, 10 Sep 2015 06:44:21 +0000 (23:44 -0700)
src/modules/tools/temperatureswitch/TemperatureSwitch.cpp
src/modules/tools/temperatureswitch/TemperatureSwitch.h

index d6a5724..7355372 100755 (executable)
@@ -43,8 +43,6 @@ Author: Michael Hackney, mhackney@eclecticangler.com
 
 TemperatureSwitch::TemperatureSwitch()
 {
-    this->temperatureswitch_state = false;
-    this->second_counter = 0;
 }
 
 // Load module
@@ -131,15 +129,6 @@ bool TemperatureSwitch::load_config(uint16_t modcs)
 
     // the mcode used to arm the switch
     ts->arm_mcode = THEKERNEL->config->value(temperatureswitch_checksum, modcs, temperatureswitch_arm_command_checksum)->by_default(0)->as_number();
-    // if not defined then always armed, otherwise start out disarmed
-    if(ts->arm_mcode == 0){
-        ts->armed= true;
-        ts->one_shot= false;
-
-    }else{
-        ts->armed= false;
-        ts->one_shot= true;
-    }
 
     ts->temperatureswitch_switch_cs= get_checksum(s); // checksum of the switch to use
 
@@ -151,19 +140,22 @@ bool TemperatureSwitch::load_config(uint16_t modcs)
     ts->current_delay = ts->temperatureswitch_heatup_poll;
 
     // set initial state
-    float current_temp = ts->get_highest_temperature();
-    ts->lower= current_temp < ts->temperatureswitch_threshold_temp;
+    ts->current_state= NONE;
+    this->second_counter = ts->current_delay; // do test immediately on first second_tick
+    // if not defined then always armed, otherwise start out disarmed
+    ts->armed= (ts->arm_mcode == 0);
 
     // Register for events
     ts->register_for_event(ON_SECOND_TICK);
-    ts->register_for_event(ON_GCODE_RECEIVED);
+
+    if(this->arm_mcode != 0) {
+        ts->register_for_event(ON_GCODE_RECEIVED);
+    }
     return true;
 }
 
 void TemperatureSwitch::on_gcode_received(void *argument)
 {
-    if(this->arm_mcode == 0) return;
-
     Gcode *gcode = static_cast<Gcode *>(argument);
     if(gcode->has_m && gcode->m == this->arm_mcode) {
         this->armed= (gcode->has_letter('S') && gcode->get_value('S') != 0);
@@ -175,36 +167,43 @@ void TemperatureSwitch::on_gcode_received(void *argument)
 void TemperatureSwitch::on_second_tick(void *argument)
 {
     second_counter++;
-    if (second_counter < current_delay) {
-        return;
+    if (second_counter < current_delay) return;
+
+    second_counter = 0;
+    float current_temp = this->get_highest_temperature();
+
+    if (current_temp >= this->temperatureswitch_threshold_temp) {
+        set_state(HIGH_TEMP);
 
     } else {
-        second_counter = 0;
-        float current_temp = this->get_highest_temperature();
-
-        if (current_temp >= this->temperatureswitch_threshold_temp) {
-            // temp >= threshold temp, call set_switch if trigger is LEVEL, or if we were lower and RISING
-            if (this->trigger == LEVEL || (this->lower && this->trigger == RISING)) {
-                this->lower= false;
-                set_switch(true);
-                current_delay = temperatureswitch_cooldown_poll;
-            }
-            if(this->lower && this->trigger == FALLING) {
-                this->lower= false;
-            }
+        set_state(LOW_TEMP);
+   }
+}
 
-        } else {
-            // temp < threshold temp, call set_switch if trigger is LEVEL, or if we were not lower and FALLING
-            if (this->trigger == LEVEL || (!this->lower && this->trigger == FALLING)) {
-                this->lower= true;
-                set_switch(false);
-                current_delay = temperatureswitch_heatup_poll;
-            }
-            if(!this->lower && this->trigger == RISING) {
-                this->lower= true;
-            }
-       }
+void TemperatureSwitch::set_state(STATE state)
+{
+    if(state == this->current_state) return; // state did not change
+
+    // state has changed
+    switch(this->trigger) {
+        case LEVEL:
+            // switch on or off depending on HIGH or LOW
+            set_switch(state == HIGH_TEMP);
+            break;
+
+        case RISING:
+            // switch on if rising edge
+            if(this->current_state == LOW_TEMP && state == HIGH_TEMP) set_switch(true);
+            break;
+
+        case FALLING:
+            // switch off if falling edge
+            if(this->current_state == HIGH_TEMP && state == LOW_TEMP) set_switch(false);
+            break;
     }
+
+    this->current_delay = state == HIGH_TEMP ? this->temperatureswitch_cooldown_poll : this->temperatureswitch_heatup_poll;
+    this->current_state= state;
 }
 
 // Get the highest temperature from the set of temperature controllers
@@ -229,20 +228,26 @@ float TemperatureSwitch::get_highest_temperature()
 // Turn the switch on (true) or off (false)
 void TemperatureSwitch::set_switch(bool switch_state)
 {
-    if(this->one_shot) {
-        // if one shot we only trigger once per arming
-        if(!this->armed) return; // do not actually switch anything if not armed, but we do need to keep the state
-        this->armed= false;
+    if(!this->armed) return; // do not actually switch anything if not armed
 
-    }else{
-        // we do not check the existing state for one shots
-        if(this->temperatureswitch_state == switch_state) return;
-        this->temperatureswitch_state = switch_state;
+    if(this->arm_mcode != 0 && this->trigger != LEVEL) {
+        // if edge triggered we only trigger once per arming, if level triggered we switch as long as we are armed
+        this->armed= false;
     }
 
     if(this->inverted) switch_state= !switch_state; // turn switch on or off inverted
 
-    bool ok = PublicData::set_value(switch_checksum, this->temperatureswitch_switch_cs, state_checksum, &switch_state);
+    // get current switch state
+    struct pad_switch *pad;
+    bool ok = PublicData::get_value(switch_checksum, this->temperatureswitch_switch_cs, 0, (void **)&pad);
+    if (!ok) {
+        THEKERNEL->streams->printf("// Failed to get switch state.\r\n");
+        return;
+    }
+
+    if(pad->state == switch_state) return; // switch is already in the requested state
+
+    ok = PublicData::set_value(switch_checksum, this->temperatureswitch_switch_cs, state_checksum, &switch_state);
     if (!ok) {
         THEKERNEL->streams->printf("// Failed changing switch state.\r\n");
     }
index 873c26f..4750cbb 100755 (executable)
@@ -31,6 +31,9 @@ class TemperatureSwitch : public Module
         void on_gcode_received(void *argument);
 
     private:
+        enum TRIGGER_TYPE {LEVEL, RISING, FALLING};
+        enum STATE {NONE, HIGH_TEMP, LOW_TEMP};
+
         bool load_config(uint16_t modcs);
 
         // get the highest temperature from the set of configured temperature controllers
@@ -39,6 +42,9 @@ class TemperatureSwitch : public Module
         // turn the switch on or off
         void set_switch(bool cooler_state);
 
+        // temperature has changed state
+        void set_state(STATE state);
+
         // the set of temperature controllers that match the required designator prefix
         vector<uint16_t> temp_controllers;
 
@@ -65,16 +71,11 @@ class TemperatureSwitch : public Module
         // the mcode that will arm the switch, 0 means always armed
         uint16_t arm_mcode;
 
-        enum TRIGGER_TYPE {LEVEL, RISING, FALLING };
-
-        // is the switch currently on (1) or off (0)?
         struct {
-            bool temperatureswitch_state:1;
             bool inverted:1;
-            bool lower:1;
             bool armed:1;
-            bool one_shot:1;
             TRIGGER_TYPE trigger:2;
+            STATE current_state:2;
         };
 };