#include "Atm_encoderInt.h" #include // Loosely based on https://www.circuitsathome.com/mcu/reading-rotary-encoder-on-arduino (Oleg Mazurov) const char Atm_encoderInt::enc_states[16] = {0, (char)-1, 1, 0, 1, 0, 0, (char)-1, (char)-1, 0, 0, 1, 0, 1, (char)-1, 0}; Atm_encoderInt& Atm_encoderInt::begin( int pin1, int pin2, int divider /* = 1 */ ) { // clang-format off const static state_t state_table[] PROGMEM = { /* ON_ENTER ON_LOOP ON_EXIT EVT_UP EVT_DOWN ELSE */ /* IDLE */ -1, LP_IDLE, -1, UP, DOWN, -1, /* UP */ ENT_UP, -1, -1, -1, -1, IDLE, /* DOWN */ ENT_DOWN, -1, -1, -1, -1, IDLE, }; // clang-format on Machine::begin( state_table, ELSE ); this->pin1 = pin1; this->pin2 = pin2; this->divider = divider; encoder = new Encoder(pin1, pin2); // pinMode( pin1, INPUT ); // pinMode( pin2, INPUT ); // digitalWrite( pin1, HIGH ); // digitalWrite( pin2, HIGH ); min = INT_MIN; max = INT_MAX; value = 0; return *this; } int Atm_encoderInt::event( int id ) { switch ( id ) { case EVT_UP: return enc_direction == +1 && ( enc_counter % divider == 0 ); case EVT_DOWN: return enc_direction == -1 && ( enc_counter % divider == 0 ); } return 0; } void Atm_encoderInt::action( int id ) { int8_t enc_counter_prev = enc_counter; switch ( id ) { case LP_IDLE: // enc_bits = ( ( enc_bits << 2 ) | ( digitalRead( pin1 ) << 1 ) | ( digitalRead( pin2 ) ) ) & 0x0f; // enc_direction = enc_states[enc_bits]; // if ( enc_direction != 0 ) { // enc_counter = enc_counter + enc_direction; // if ( ( enc_counter != 0 ) && ( enc_counter % divider == 0 ) ) { // if ( !count( enc_direction ) ) { // enc_direction = 0; // } // } // enc_bits = ( ( enc_bits << 2 ) | ( digitalRead( pin1 ) << 1 ) | ( digitalRead( pin2 ) ) ) & 0x0f; // enc_direction = enc_states[enc_bits]; // if ( enc_direction != 0 ) { // enc_counter = enc_counter + enc_direction; // if ( ( enc_counter != 0 ) && ( enc_counter % divider == 0 ) ) { // if ( !count( enc_direction ) ) { // enc_direction = 0; // } // } // } // } enc_counter = encoder->read(); enc_direction = enc_counter > enc_counter_prev ? 1 : -1; enc_direction = enc_counter == enc_counter_prev ? 0 : enc_direction; count(enc_direction); return; case ENT_UP: onup.push( state(), 1 ); return; case ENT_DOWN: ondown.push( state(), 0 ); return; } } Atm_encoderInt& Atm_encoderInt::range( int min, int max, bool wrap /* = false */ ) { if ( min > max ) { range_invert = true; this->min = max; this->max = min; } else { range_invert = false; this->min = min; this->max = max; } this->wrap = wrap; if ( value < min || value > max ) { value = min; } return *this; } Atm_encoderInt& Atm_encoderInt::set( int value ) { this->value = range_invert ? map( value, min, max, max, min ) : value; return *this; } Atm_encoderInt& Atm_encoderInt::onChange( Machine& machine, int event /* = 0 */ ) { onup.set( &machine, event ); ondown.set( &machine, event ); return *this; } Atm_encoderInt& Atm_encoderInt::onChange( atm_cb_push_t callback, int idx /* = 0 */ ) { onup.set( callback, idx ); ondown.set( callback, idx ); return *this; } Atm_encoderInt& Atm_encoderInt::onChange( bool status, Machine& machine, int event /* = 0 */ ) { if ( status ) { onup.set( &machine, event ); } else { ondown.set( &machine, event ); } return *this; } Atm_encoderInt& Atm_encoderInt::onChange( bool status, atm_cb_push_t callback, int idx /* = 0 */ ) { if ( status ) { onup.set( callback, idx ); } else { ondown.set( callback, idx ); } return *this; } int Atm_encoderInt::state( void ) { return range_invert ? map( value, min, max, max, min ) : value; } bool Atm_encoderInt::count( int direction ) { if ( (long)value + direction > max ) { if ( wrap ) { value = min; } else { return false; } } else if ( (long)value + direction < min ) { if ( wrap ) { value = max; } else { return false; } } else { value += direction; } return true; } Atm_encoderInt& Atm_encoderInt::trace( Stream& stream ) { Machine::setTrace( &stream, atm_serial_debug::trace, "ENCODER\0EVT_UP\0EVT_DOWN\0ELSE\0IDLE\0UP\0DOWN" ); return *this; }