Commit | Line | Data |
---|---|---|
df27a6a3 | 1 | /* |
cc1d3b1f AW |
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. | |
df27a6a3 | 5 | You should have received a copy of the GNU General Public License along with Smoothie. If not, see <http://www.gnu.org/licenses/>. |
cc1d3b1f AW |
6 | */ |
7 | ||
8 | #include "libs/Module.h" | |
9 | #include "libs/Kernel.h" | |
26ef0ec6 | 10 | #include "libs/SerialMessage.h" |
cc1d3b1f AW |
11 | #include <math.h> |
12 | #include "Switch.h" | |
13 | #include "libs/Pin.h" | |
3c4f2dd8 | 14 | #include "modules/robot/Conveyor.h" |
cc1d3b1f | 15 | |
8f91e4e6 MM |
16 | #include "MRI_Hooks.h" |
17 | ||
cc1d3b1f AW |
18 | Switch::Switch(){} |
19 | ||
20 | Switch::Switch(uint16_t name){ | |
21 | this->name_checksum = name; | |
26ef0ec6 | 22 | //this->dummy_stream = &(StreamOutput::NullStream); |
cc1d3b1f AW |
23 | } |
24 | ||
25 | void Switch::on_module_loaded(){ | |
26ef0ec6 L |
26 | this->input_pin_state = true; |
27 | this->switch_state = true; | |
e62e8f7c | 28 | this->switch_changed = false; |
26ef0ec6 | 29 | |
476dcb96 | 30 | register_for_event(ON_CONFIG_RELOAD); |
3c4f2dd8 | 31 | this->register_for_event(ON_GCODE_RECEIVED); |
cc1d3b1f | 32 | this->register_for_event(ON_GCODE_EXECUTE); |
e62e8f7c | 33 | this->register_for_event(ON_MAIN_LOOP); |
bca315cc | 34 | |
cc1d3b1f AW |
35 | // Settings |
36 | this->on_config_reload(this); | |
37 | ||
26ef0ec6 | 38 | // input pin polling |
314ab8f7 | 39 | THEKERNEL->slow_ticker->attach( 100, this, &Switch::pinpoll_tick); |
26ef0ec6 | 40 | |
bca315cc | 41 | // PWM |
314ab8f7 | 42 | THEKERNEL->slow_ticker->attach(1000, &output_pin, &Pwm::on_tick); |
cc1d3b1f AW |
43 | } |
44 | ||
45 | ||
46 | // Get config | |
47 | void Switch::on_config_reload(void* argument){ | |
314ab8f7 MM |
48 | this->input_pin.from_string(THEKERNEL->config->value(switch_checksum, this->name_checksum, input_pin_checksum )->by_default("nc")->as_string())->as_input(); |
49 | this->input_pin_behavior = THEKERNEL->config->value(switch_checksum, this->name_checksum, input_pin_behavior_checksum )->by_default(momentary_checksum)->as_number(); | |
50 | this->input_on_command = THEKERNEL->config->value(switch_checksum, this->name_checksum, input_on_command_checksum )->by_default("")->as_string(); | |
51 | this->input_off_command = THEKERNEL->config->value(switch_checksum, this->name_checksum, input_off_command_checksum )->by_default("")->as_string(); | |
52 | this->output_pin.from_string(THEKERNEL->config->value(switch_checksum, this->name_checksum, output_pin_checksum )->by_default("nc")->as_string())->as_output(); | |
53 | this->output_on_command = THEKERNEL->config->value(switch_checksum, this->name_checksum, output_on_command_checksum )->by_default("")->as_string(); | |
54 | this->output_off_command = THEKERNEL->config->value(switch_checksum, this->name_checksum, output_off_command_checksum )->by_default("")->as_string(); | |
55 | this->switch_state = THEKERNEL->config->value(switch_checksum, this->name_checksum, startup_state_checksum )->by_default(false)->as_bool(); | |
56 | this->switch_value = THEKERNEL->config->value(switch_checksum, this->name_checksum, startup_value_checksum )->by_default(this->output_pin.max_pwm())->as_number(); | |
dc7754dd L |
57 | if(this->switch_state) |
58 | this->output_pin.set(this->switch_value); | |
59 | else | |
60 | this->output_pin.set(0); | |
8f91e4e6 | 61 | |
cb3460e9 | 62 | set_low_on_debug(output_pin.port_number, output_pin.pin); |
cc1d3b1f AW |
63 | } |
64 | ||
3c4f2dd8 AW |
65 | |
66 | void Switch::on_gcode_received(void* argument){ | |
67 | Gcode* gcode = static_cast<Gcode*>(argument); | |
68 | // Add the gcode to the queue ourselves if we need it | |
7cc8dc85 BG |
69 | if( ( input_on_command.length() > 0 && ! gcode->command.compare(0, input_on_command.length(), input_on_command) ) |
70 | || ( input_off_command.length() > 0 && ! gcode->command.compare(0, input_off_command.length(), input_off_command) ) ){ | |
74b6303c | 71 | gcode->mark_as_taken(); |
314ab8f7 MM |
72 | if( THEKERNEL->conveyor->queue.size() == 0 ){ |
73 | THEKERNEL->call_event(ON_GCODE_EXECUTE, gcode ); | |
3c4f2dd8 | 74 | }else{ |
314ab8f7 | 75 | Block* block = THEKERNEL->conveyor->queue.get_ref( THEKERNEL->conveyor->queue.size() - 1 ); |
3c4f2dd8 | 76 | block->append_gcode(gcode); |
3c4f2dd8 AW |
77 | } |
78 | } | |
79 | } | |
80 | ||
cc1d3b1f AW |
81 | // Turn pin on and off |
82 | void Switch::on_gcode_execute(void* argument){ | |
83 | Gcode* gcode = static_cast<Gcode*>(argument); | |
7cc8dc85 | 84 | if(! gcode->command.compare(0, input_on_command.length(), input_on_command)){ |
26ef0ec6 L |
85 | if (gcode->has_letter('S')) |
86 | { | |
87 | int v = gcode->get_value('S') * output_pin.max_pwm() / 256.0; | |
a9a7e30c | 88 | if (v) { |
26ef0ec6 | 89 | this->output_pin.pwm(v); |
e62e8f7c | 90 | this->switch_value = v; |
a9a7e30c L |
91 | this->switch_state = true; |
92 | } | |
93 | else { | |
26ef0ec6 | 94 | this->output_pin.set(0); |
a9a7e30c L |
95 | this->switch_state = false; |
96 | } | |
df27a6a3 | 97 | } |
26ef0ec6 L |
98 | else |
99 | { | |
100 | // Turn pin on | |
e62e8f7c | 101 | this->output_pin.pwm(this->switch_value); |
a9a7e30c | 102 | this->switch_state = true; |
df27a6a3 | 103 | } |
cc1d3b1f | 104 | } |
7cc8dc85 | 105 | else if(! gcode->command.compare(0, input_off_command.length(), input_off_command)){ |
26ef0ec6 L |
106 | // Turn pin off |
107 | this->output_pin.set(0); | |
a9a7e30c | 108 | this->switch_state = false; |
26ef0ec6 | 109 | } |
cc1d3b1f | 110 | } |
26ef0ec6 | 111 | |
e62e8f7c L |
112 | void Switch::on_main_loop(void* argument){ |
113 | if(this->switch_changed){ | |
114 | if(this->switch_state){ | |
115 | this->send_gcode( this->output_on_command, &(StreamOutput::NullStream) ); | |
116 | this->output_pin.pwm(this->switch_value); | |
117 | }else{ | |
118 | this->send_gcode( this->output_off_command, &(StreamOutput::NullStream) ); | |
119 | this->output_pin.set(0); | |
120 | } | |
121 | this->switch_changed=false; | |
122 | } | |
123 | } | |
124 | ||
26ef0ec6 L |
125 | //TODO: Make this use InterruptIn |
126 | //Check the state of the button and act accordingly | |
127 | uint32_t Switch::pinpoll_tick(uint32_t dummy){ | |
128 | // If pin changed | |
e62e8f7c L |
129 | bool current_state = this->input_pin.get(); |
130 | if(this->input_pin_state != current_state){ | |
131 | this->input_pin_state = current_state; | |
26ef0ec6 L |
132 | // If pin high |
133 | if( this->input_pin_state ){ | |
134 | // if switch is a toggle switch | |
135 | if( this->input_pin_behavior == toggle_checksum ){ | |
136 | this->flip(); | |
137 | // else default is momentary | |
138 | } | |
139 | else{ | |
140 | this->flip(); | |
141 | } | |
142 | // else if button released | |
143 | }else{ | |
144 | // if switch is momentary | |
145 | if( !this->input_pin_behavior == toggle_checksum ){ | |
146 | this->flip(); | |
147 | } | |
148 | } | |
149 | } | |
150 | return 0; | |
151 | } | |
152 | ||
153 | void Switch::flip(){ | |
154 | this->switch_state = !this->switch_state; | |
e62e8f7c | 155 | this->switch_changed = true; |
26ef0ec6 L |
156 | } |
157 | ||
158 | void Switch::send_gcode(std::string msg, StreamOutput* stream) { | |
159 | struct SerialMessage message; | |
160 | message.message = msg; | |
161 | message.stream = stream; | |
314ab8f7 | 162 | THEKERNEL->call_event(ON_CONSOLE_LINE_RECEIVED, &message ); |
26ef0ec6 L |
163 | } |
164 |