128 lines
No EOL
3 KiB
C++
128 lines
No EOL
3 KiB
C++
#include <stdio.h>
|
|
|
|
#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<uint64_t>(1.2 / static_cast<uint64_t>(wpm) * 1000 * 1000);
|
|
return duration;
|
|
}
|
|
|
|
Keyer::Keyer(uint8_t wpm) : m_wpm(wpm)
|
|
{
|
|
m_elementDuration = calcElementDurationUs(m_wpm);
|
|
}
|
|
|
|
void Keyer::run()
|
|
{
|
|
auto timestamp = get_absolute_time();
|
|
|
|
switch (state)
|
|
{
|
|
case State::Wait:
|
|
if (left_paddle_pressed() && right_paddle_pressed())
|
|
{
|
|
if (m_lastSymbolWas == Symbol::Dit) {
|
|
state = State::Dah;
|
|
} else if (m_lastSymbolWas == Symbol::Dah) {
|
|
state = State::Dit;
|
|
}
|
|
break;
|
|
}
|
|
if (left_paddle_pressed())
|
|
{
|
|
state = State::Dit;
|
|
}
|
|
else if (right_paddle_pressed())
|
|
{
|
|
state = State::Dah;
|
|
}
|
|
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);
|
|
m_lastSymbolWas = Symbol::Dit;
|
|
}
|
|
else
|
|
{
|
|
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);
|
|
m_lastSymbolWas = Symbol::Dah;
|
|
}
|
|
else
|
|
{
|
|
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_previousState != State::InterCharSpace)
|
|
{
|
|
m_pausing_until = make_timeout_time_us(m_elementDuration);
|
|
m_previousState = State::InterCharSpace;
|
|
}
|
|
|
|
if (absolute_time_diff_us(timestamp, m_pausing_until) <= 0)
|
|
{
|
|
state = State::Wait;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
} |