#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; extern const uint BUZZER_PIN; extern const uint CW_OUT_PIN; extern const uint AUDIO_OUT_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_buzzer(BUZZER_PIN), m_audioOut(AUDIO_OUT_PIN) { 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 (m_state) { case State::Wait: if (left_paddle_pressed()) { m_keyNextIambicB = false; m_state = State::Dit; } else if (right_paddle_pressed()) { m_keyNextIambicB = false; m_state = State::Dah; } else { if (m_mode == Mode::IAMBIC_B && m_keyNextIambicB) { if (m_previousState == State::Dit) m_state = State::Dah; else m_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); gpio_put(CW_OUT_PIN, 1); m_buzzer.on(SIDETONE_FREQ); m_audioOut.on(SIDETONE_FREQ); } else { // If right paddle üressed -> note for Iambic B if (right_paddle_pressed() && !m_keyNextIambicB) { printf("Iambic B -> lang\n"); m_keyNextIambicB = true; } if (absolute_time_diff_us(timestamp, m_keying_until) <= 0) { m_currentlyKeying = false; gpio_put(LED_PIN, 0); gpio_put(CW_OUT_PIN, 0); m_buzzer.off(); m_audioOut.off(); m_previousState = State::Dit; m_state = State::DitPause; } } 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); gpio_put(CW_OUT_PIN, 1); m_buzzer.on(SIDETONE_FREQ); m_audioOut.on(SIDETONE_FREQ); } else { // If left paddle pressed -> Note for Iambic B if (left_paddle_pressed() && !m_keyNextIambicB) { printf("Iambic B -> kurz\n"); m_keyNextIambicB = true; } if (absolute_time_diff_us(timestamp, m_keying_until) <= 0) { m_currentlyKeying = false; gpio_put(LED_PIN, 0); gpio_put(CW_OUT_PIN, 0); m_buzzer.off(); m_audioOut.off(); m_previousState = State::Dah; m_state = State::DahPause; } } break; case State::DitPause: if (!m_currentlyPausing) { m_pausing_until = make_timeout_time_us(m_elementDuration); m_currentlyPausing = true; } else { if (absolute_time_diff_us(timestamp, m_pausing_until) <= 0) { m_currentlyPausing = false; if (right_paddle_pressed()) { m_state = State::Dah; m_keyNextIambicB = false; } else if (left_paddle_pressed()) { m_state = State::Dit; m_keyNextIambicB = false; } else { m_state = State::Wait; } } } break; case State::DahPause: if (!m_currentlyPausing) { m_pausing_until = make_timeout_time_us(m_elementDuration); m_currentlyPausing = true; } else { if (absolute_time_diff_us(timestamp, m_pausing_until) <= 0) { m_currentlyPausing = false; if (left_paddle_pressed()) { m_state = State::Dit; m_keyNextIambicB = false; } else if (right_paddle_pressed()) { m_state = State::Dah; m_keyNextIambicB = false; } else { m_state = State::Wait; } } } break; case State::Abort: gpio_put(LED_PIN, 0); gpio_put(CW_OUT_PIN, 0); m_buzzer.off(); m_audioOut.off(); m_keyNextIambicB = false; m_currentlyPausing = false; m_currentlyKeying = false; m_previousState = State::Abort; m_state = State::Wait; break; default: break; } } void Keyer::stop() { m_state = State::Abort; }