Commit | Line | Data |
---|---|---|
abe97b79 | 1 | /* |
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. | |
5 | You should have received a copy of the GNU General Public License along with Smoothie. If not, see <http://www.gnu.org/licenses/>. | |
6 | */ | |
7 | ||
8 | /* | |
9 | TemperatureSwitch is an optional module that will automatically turn on or off a switch | |
10 | based on a setpoint temperature. It is commonly used to turn on/off a cooling fan or water pump | |
11 | to cool the hot end's cold zone. Specifically, it turns one of the small MOSFETs on or off. | |
12 | ||
13 | Author: Michael Hackney, mhackney@eclecticangler.com | |
14 | */ | |
15 | ||
16 | #include "TemperatureSwitch.h" | |
17 | #include "libs/Module.h" | |
18 | #include "libs/Kernel.h" | |
19 | #include "modules/tools/temperaturecontrol/TemperatureControlPublicAccess.h" | |
20 | #include "SwitchPublicAccess.h" | |
21 | ||
22 | #include "utils.h" | |
23 | #include "Gcode.h" | |
24 | #include "Config.h" | |
25 | #include "ConfigValue.h" | |
26 | #include "checksumm.h" | |
27 | #include "PublicData.h" | |
28 | #include "StreamOutputPool.h" | |
29 | ||
1dc339ee | 30 | #define temperatureswitch_checksum CHECKSUM("temperatureswitch") |
5cbf2253 | 31 | #define enable_checksum CHECKSUM("enable") |
1dc339ee | 32 | #define temperatureswitch_hotend_checksum CHECKSUM("hotend") |
33 | #define temperatureswitch_threshold_temp_checksum CHECKSUM("threshold_temp") | |
34 | #define temperatureswitch_type_checksum CHECKSUM("type") | |
fe3323e7 | 35 | #define temperatureswitch_switch_checksum CHECKSUM("switch") |
1dc339ee | 36 | #define temperatureswitch_heatup_poll_checksum CHECKSUM("heatup_poll") |
37 | #define temperatureswitch_cooldown_poll_checksum CHECKSUM("cooldown_poll") | |
5cbf2253 | 38 | #define designator_checksum CHECKSUM("designator") |
1dc339ee | 39 | |
abe97b79 | 40 | TemperatureSwitch::TemperatureSwitch() |
41 | { | |
5cbf2253 JM |
42 | this->temperatureswitch_state = false; |
43 | this->second_counter = 0; | |
abe97b79 | 44 | } |
45 | ||
46 | // Load module | |
47 | void TemperatureSwitch::on_module_loaded() | |
48 | { | |
5cbf2253 JM |
49 | vector<uint16_t> modulist; |
50 | // allow for multiple temperature switches | |
51 | THEKERNEL->config->get_module_list(&modulist, temperatureswitch_checksum); | |
52 | for (auto m : modulist) { | |
53 | load_config(m); | |
54 | } | |
e6b0fc38 | 55 | |
5cbf2253 JM |
56 | // no longer need this instance as it is just used to load the other instances |
57 | delete this; | |
58 | } | |
59 | ||
60 | ||
61 | bool TemperatureSwitch::load_config(uint16_t modcs) | |
62 | { | |
63 | // see if enabled | |
64 | if (!THEKERNEL->config->value(temperatureswitch_checksum, modcs, enable_checksum)->by_default(false)->as_bool()) { | |
65 | return false; | |
abe97b79 | 66 | } |
67 | ||
5cbf2253 JM |
68 | // create a temperature control and load settings |
69 | ||
70 | char designator= 0; | |
71 | string s= THEKERNEL->config->value(temperatureswitch_checksum, modcs, designator_checksum)->by_default("")->as_string(); | |
72 | if(s.empty()){ | |
73 | // for backward compatibility temperatureswitch.hotend will need designator 'T' by default | |
74 | if(modcs == temperatureswitch_hotend_checksum) designator= 'T'; | |
75 | ||
76 | }else{ | |
77 | designator= s[0]; | |
78 | } | |
abe97b79 | 79 | |
5cbf2253 | 80 | if(designator == 0) return false; // no designator then not valid |
57235957 | 81 | |
5cbf2253 JM |
82 | // create a new temperature switch module |
83 | TemperatureSwitch *ts= new TemperatureSwitch(); | |
84 | ||
85 | // get the list of temperature controllers and remove any that don't have designator == specified designator | |
86 | vector<uint16_t> tempcontrollers; | |
87 | THEKERNEL->config->get_module_list(&tempcontrollers, temperature_control_checksum); | |
88 | ||
89 | // see what its designator is and add to list of it the one we specified | |
f53fe49d | 90 | void *returned_temp; |
5cbf2253 | 91 | for (auto controller : tempcontrollers) { |
f53fe49d | 92 | bool temp_ok = PublicData::get_value(temperature_control_checksum, controller, current_temperature_checksum, &returned_temp); |
93 | if (temp_ok) { | |
94 | struct pad_temperature temp = *static_cast<struct pad_temperature *>(returned_temp); | |
5cbf2253 JM |
95 | if (temp.designator[0] == designator) { |
96 | ts->temp_controllers.push_back(controller); | |
f53fe49d | 97 | } |
98 | } | |
99 | } | |
57235957 | 100 | |
5cbf2253 JM |
101 | // if we don't have any matching controllers, then not valid |
102 | if (ts->temp_controllers.empty()) { | |
103 | delete ts; | |
104 | return false; | |
57235957 JM |
105 | } |
106 | ||
abe97b79 | 107 | // load settings from config file |
fe3323e7 | 108 | s = THEKERNEL->config->value(temperatureswitch_checksum, modcs, temperatureswitch_switch_checksum)->by_default("")->as_string(); |
5cbf2253 | 109 | if(s.empty()) { |
fe3323e7 JM |
110 | // handle old configs where this was called type @DEPRECATED |
111 | s = THEKERNEL->config->value(temperatureswitch_checksum, modcs, temperatureswitch_type_checksum)->by_default("")->as_string(); | |
112 | if(s.empty()) { | |
113 | // no switch specified so invalid entry | |
114 | delete this; | |
115 | return false; | |
116 | } | |
5cbf2253 | 117 | } |
fe3323e7 | 118 | ts->temperatureswitch_switch_cs= get_checksum(s); // checksum of the switch to use |
abe97b79 | 119 | |
5cbf2253 | 120 | ts->temperatureswitch_threshold_temp = THEKERNEL->config->value(temperatureswitch_checksum, modcs, temperatureswitch_threshold_temp_checksum)->by_default(50.0f)->as_number(); |
abe97b79 | 121 | |
5cbf2253 JM |
122 | // these are to tune the heatup and cooldown polling frequencies |
123 | ts->temperatureswitch_heatup_poll = THEKERNEL->config->value(temperatureswitch_checksum, modcs, temperatureswitch_heatup_poll_checksum)->by_default(15)->as_number(); | |
124 | ts->temperatureswitch_cooldown_poll = THEKERNEL->config->value(temperatureswitch_checksum, modcs, temperatureswitch_cooldown_poll_checksum)->by_default(60)->as_number(); | |
125 | ts->current_delay = ts->temperatureswitch_heatup_poll; | |
f53fe49d | 126 | |
127 | // Register for events | |
5cbf2253 JM |
128 | ts->register_for_event(ON_SECOND_TICK); |
129 | ||
130 | return true; | |
abe97b79 | 131 | } |
132 | ||
133 | // Called once a second but we only need to service on the cooldown and heatup poll intervals | |
134 | void TemperatureSwitch::on_second_tick(void *argument) | |
135 | { | |
136 | second_counter++; | |
137 | if (second_counter < current_delay) { | |
138 | return; | |
139 | } else { | |
140 | second_counter = 0; | |
141 | float current_temp = this->get_highest_temperature(); | |
57235957 | 142 | |
abe97b79 | 143 | if (current_temp >= this->temperatureswitch_threshold_temp) { |
144 | // temp >= threshold temp, turn the cooler switch on if it isn't already | |
145 | if (!temperatureswitch_state) { | |
146 | set_switch(true); | |
57235957 | 147 | current_delay = temperatureswitch_cooldown_poll; |
abe97b79 | 148 | } |
149 | } else { | |
150 | // temp < threshold temp, turn the cooler switch off if it isn't already | |
151 | if (temperatureswitch_state) { | |
152 | set_switch(false); | |
153 | current_delay = temperatureswitch_heatup_poll; | |
154 | } | |
57235957 | 155 | } |
abe97b79 | 156 | } |
157 | } | |
158 | ||
159 | // Get the highest temperature from the set of temperature controllers | |
160 | float TemperatureSwitch::get_highest_temperature() | |
161 | { | |
162 | void *returned_temp; | |
163 | float high_temp = 0.0; | |
164 | ||
165 | for (auto controller : temp_controllers) { | |
166 | bool temp_ok = PublicData::get_value(temperature_control_checksum, controller, current_temperature_checksum, &returned_temp); | |
167 | if (temp_ok) { | |
168 | struct pad_temperature temp = *static_cast<struct pad_temperature *>(returned_temp); | |
169 | // check if this controller's temp is the highest and save it if so | |
57235957 | 170 | if (temp.current_temperature > high_temp) { |
abe97b79 | 171 | high_temp = temp.current_temperature; |
abe97b79 | 172 | } |
173 | } | |
174 | } | |
175 | return high_temp; | |
176 | } | |
177 | ||
178 | // Turn the switch on (true) or off (false) | |
179 | void TemperatureSwitch::set_switch(bool switch_state) | |
180 | { | |
181 | this->temperatureswitch_state = switch_state; | |
fe3323e7 | 182 | bool ok = PublicData::set_value(switch_checksum, this->temperatureswitch_switch_cs, state_checksum, &this->temperatureswitch_state); |
abe97b79 | 183 | if (!ok) { |
184 | THEKERNEL->streams->printf("Failed changing switch state.\r\n"); | |
185 | } | |
186 | } |