1 #include "libs/Kernel.h"
2 #include "PauseButton.h"
3 #include "libs/nuts_bolts.h"
4 #include "libs/utils.h"
6 #include "SlowTicker.h"
7 #include "libs/SerialMessage.h"
8 #include "libs/StreamOutput.h"
10 #include "checksumm.h"
11 #include "ConfigValue.h"
12 #include "StreamOutputPool.h"
16 #define pause_button_enable_checksum CHECKSUM("pause_button_enable")
17 #define kill_button_enable_checksum CHECKSUM("kill_button_enable")
18 #define pause_button_pin_checksum CHECKSUM("pause_button_pin")
19 #define kill_button_pin_checksum CHECKSUM("kill_button_pin")
21 PauseButton::PauseButton()
23 this->button_state
= true;
28 void PauseButton::on_module_loaded()
30 this->pause_enable
= THEKERNEL
->config
->value( pause_button_enable_checksum
)->by_default(false)->as_bool();
31 this->kill_enable
= THEKERNEL
->config
->value( kill_button_enable_checksum
)->by_default(false)->as_bool();
32 this->pause_button
.from_string( THEKERNEL
->config
->value( pause_button_pin_checksum
)->by_default("2.12")->as_string())->as_input();
33 this->kill_button
.from_string( THEKERNEL
->config
->value( kill_button_pin_checksum
)->by_default("nc")->as_string())->as_input();
35 if(this->kill_enable
&& this->kill_button
.connected() && pause_button
.equals(kill_button
)) {
36 // kill button takes priority
37 this->pause_enable
= false;
39 } else if(this->kill_enable
&& !this->kill_button
.connected() && !this->pause_enable
&& pause_button
.connected()) {
40 // use pause button for kill button if kill buttin not specifically defined
41 this->kill_button
= this->pause_button
;
44 this->register_for_event(ON_CONSOLE_LINE_RECEIVED
);
46 if( (this->pause_enable
&& this->pause_button
.connected()) || (this->kill_enable
&& this->kill_button
.connected()) ) {
47 THEKERNEL
->slow_ticker
->attach( 10, this, &PauseButton::button_tick
);
48 this->register_for_event(ON_IDLE
);
52 void PauseButton::on_idle(void *argument
)
56 THEKERNEL
->call_event(ON_HALT
, nullptr);
57 THEKERNEL
->streams
->printf("Kill button pressed - reset or M999 to continue\r\n");
61 //TODO: Make this use InterruptIn
62 //Check the state of the button and act accordingly based on current pause state
63 // Note this is ISR so don't do anything nasty in here
64 uint32_t PauseButton::button_tick(uint32_t dummy
)
66 // If pause button changed
67 if(this->pause_enable
&& this->pause_button
.connected()) {
68 bool newstate
= this->pause_button
.get();
69 if(this->button_state
!= newstate
) {
70 this->button_state
= newstate
;
72 if( this->button_state
) {
73 if( THEKERNEL
->pauser
->paused() ) {
74 THEKERNEL
->pauser
->release();
76 THEKERNEL
->pauser
->take();
82 if(!this->killed
&& this->kill_enable
&& this->kill_button
.connected() && !this->kill_button
.get()) {
84 // we can't call this in ISR, and we need to block on_main_loop so do it in on_idle
85 // THEKERNEL->call_event(ON_HALT);
92 // When a new line is received, check if it is a command, and if it is, act upon it
93 void PauseButton::on_console_line_received( void *argument
)
95 SerialMessage new_message
= *static_cast<SerialMessage
*>(argument
);
97 if(this->killed
&& new_message
.message
== "M999") {
102 // ignore comments and blank lines and if this is a G code then also ignore it
103 char first_char
= new_message
.message
[0];
104 if(strchr(";( \n\rGMTN", first_char
) != NULL
) return;
106 string cmd
= shift_parameter(new_message
.message
);
108 if (cmd
== "freeze") {
109 if( !THEKERNEL
->pauser
->paused() ) {
110 THEKERNEL
->pauser
->take();
113 } else if (cmd
== "unfreeze") {
114 if( THEKERNEL
->pauser
->paused() ) {
115 THEKERNEL
->pauser
->release();