#include #include "pico/stdlib.h" #include "keyer.h" #include "sidetone.h" extern const uint LED_PIN; extern const uint LEFT_PADDLE_PIN; extern const uint RIGHT_PADDLE_PIN; const uint SIDETONE_FREQ = 622; bool left_paddle_pressed() { if (!gpio_get(LEFT_PADDLE_PIN)) { return true; } return false; } bool right_paddle_pressed() { if (!gpio_get(RIGHT_PADDLE_PIN)) { return true; } return false; } uint64_t calcElementDurationUs(uint8_t wpm) { uint64_t duration = static_cast(1.2 / static_cast(wpm) * 1000 * 1000); return duration; } Keyer::Keyer(uint8_t wpm, Mode mode) : m_wpm(wpm), m_mode(mode) { m_elementDuration = calcElementDurationUs(m_wpm); } void Keyer::setSpeed(uint8_t wpm) { m_wpm = wpm; m_elementDuration = calcElementDurationUs(wpm); } void Keyer::run() { auto timestamp = get_absolute_time(); switch (state) { case State::Wait: if (left_paddle_pressed() && right_paddle_pressed()) { m_keyNextIambicB = false; if (m_previousState == State::Dit) { state = State::Dah; } else if (m_previousState == State::Dah) { state = State::Dit; } } else if (left_paddle_pressed()) { m_keyNextIambicB = false; state = State::Dit; } else if (right_paddle_pressed()) { m_keyNextIambicB = false; state = State::Dah; } else { if (m_mode == Mode::IAMBIC_B && m_keyNextIambicB) { if (m_previousState == State::Dit) state = State::Dah; else state = State::Dit; m_keyNextIambicB = false; } } break; case State::Dit: if (!m_currentlyKeying) { m_currentlyKeying = true; m_keying_until = make_timeout_time_us(m_elementDuration); gpio_put(LED_PIN, 1); m_Sidetone.on(SIDETONE_FREQ); } else { if (right_paddle_pressed() && !m_keyNextIambicB) m_keyNextIambicB = true; if (absolute_time_diff_us(timestamp, m_keying_until) <= 0) { m_currentlyKeying = false; gpio_put(LED_PIN, 0); m_Sidetone.off(); m_previousState = State::Dit; state = State::InterCharSpace; } } break; case State::Dah: if (!m_currentlyKeying) { m_currentlyKeying = true; m_keying_until = make_timeout_time_us(m_elementDuration * 3); gpio_put(LED_PIN, 1); m_Sidetone.on(SIDETONE_FREQ); } else { if (left_paddle_pressed() && !m_keyNextIambicB) m_keyNextIambicB = true; if (absolute_time_diff_us(timestamp, m_keying_until) <= 0) { m_currentlyKeying = false; gpio_put(LED_PIN, 0); m_Sidetone.off(); m_previousState = State::Dah; state = State::InterCharSpace; } } break; case State::InterCharSpace: if (!m_currentlyPausing) { m_pausing_until = make_timeout_time_us(m_elementDuration); m_currentlyPausing = true; } if (absolute_time_diff_us(timestamp, m_pausing_until) <= 0) { m_currentlyPausing = false; state = State::Wait; } break; case State::Abort: gpio_put(LED_PIN, 0); m_Sidetone.off(); m_keyNextIambicB = false; m_currentlyPausing = false; m_currentlyKeying = false; m_previousState = State::Abort; state = State::Wait; break; default: break; } } void Keyer::stop() { state = State::Abort; }