From e8901e514d0b3cc7b64add4283203c5aaa4593ec Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Fri, 23 Feb 2024 14:29:36 +0100 Subject: [PATCH] first attempt to send messages --- src/keyer.cpp | 168 +++++++++++++++++++++++++++++++++++++++----- src/keyer.h | 20 +++++- src/morse.cpp | 48 ++++++++++++- src/morse.h | 2 +- src/raspi_keyer.cpp | 18 ++++- 5 files changed, 230 insertions(+), 26 deletions(-) diff --git a/src/keyer.cpp b/src/keyer.cpp index ecf9d1e..327f9b2 100644 --- a/src/keyer.cpp +++ b/src/keyer.cpp @@ -47,13 +47,147 @@ void Keyer::setSpeed(uint8_t wpm) m_elementDuration = calcElementDurationUs(wpm); } +void Keyer::sendMessage(const std::string &msg) +{ + for (auto c : msg) { + m_messageQueue.push(c); + } +} + void Keyer::run() { auto timestamp = get_absolute_time(); // If there is something to send … - if (!m_messageQueue.empty()) { - // TODO + if (!m_messageQueue.empty() || m_messageKeyingState != MessageState::Wait) { + // Stop all paddle keying, if necessary + if (m_PaddleKeyingState != State::Wait) { + gpio_put(LED_PIN, 0); + gpio_put(CW_OUT_PIN, 0); + m_buzzer.off(); + m_keyNextIambicB = false; + m_currentlyPausing = false; + m_currentlyKeying = false; + m_previousState = State::Abort; + m_PaddleKeyingState = State::Wait; + } + + switch (m_messageKeyingState) { + case MessageState::Wait: + m_messageChar = m_messageQueue.front(); + + switch (m_messageChar) { + case '.': + m_messageKeyingState = MessageState::Dit; + break; + case '-': + m_messageKeyingState = MessageState::Dit; + break; + case 'i': + m_messageKeyingState = MessageState::IntraCharSpace; + break; + case 'c': + m_messageKeyingState = MessageState::InterCharSpace; + break; + case 'w': + m_messageKeyingState = MessageState::InterWordSpace; + break; + } + + break; + case MessageState::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); + } + if (left_paddle_pressed() || right_paddle_pressed()) { + m_messageKeyingState = MessageState::Abort; + } + 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_messageKeyingState = MessageState::Wait; + } + break; + case MessageState::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); + } + if (left_paddle_pressed() || right_paddle_pressed()) { + m_messageKeyingState = MessageState::Abort; + } + 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_messageKeyingState = MessageState::Wait; + } + break; + case MessageState::IntraCharSpace: + if (!m_currentlyPausing) { + m_pausing_until = make_timeout_time_us(m_elementDuration); + m_currentlyPausing = true; + } + if (left_paddle_pressed() || right_paddle_pressed()) { + m_messageKeyingState = MessageState::Abort; + } + if (absolute_time_diff_us(timestamp, m_pausing_until) <= 0) { + m_currentlyPausing = false; + m_messageKeyingState = MessageState::Wait; + } + break; + case MessageState::InterCharSpace: + if (!m_currentlyPausing) { + m_pausing_until = make_timeout_time_us(m_elementDuration * 3); + m_currentlyPausing = true; + } + if (left_paddle_pressed() || right_paddle_pressed()) { + m_messageKeyingState = MessageState::Abort; + } + if (absolute_time_diff_us(timestamp, m_pausing_until) <= 0) { + m_currentlyPausing = false; + m_messageKeyingState = MessageState::Wait; + } + break; + case MessageState::InterWordSpace: + if (!m_currentlyPausing) { + m_pausing_until = make_timeout_time_us(m_elementDuration * 7); + m_currentlyPausing = true; + } + if (left_paddle_pressed() || right_paddle_pressed()) { + m_messageKeyingState = MessageState::Abort; + } + if (absolute_time_diff_us(timestamp, m_pausing_until) <= 0) { + m_currentlyPausing = false; + m_messageKeyingState = MessageState::Wait; + } + break; + case MessageState::Abort: + { + gpio_put(LED_PIN, 0); + gpio_put(CW_OUT_PIN, 0); + m_buzzer.off(); + m_currentlyPausing = false; + m_currentlyKeying = false; + std::queue emptyQueue; + std::swap(m_messageQueue, emptyQueue); + break; + } + default: + break; + } + + return; } // If we are in Straight key mode … @@ -72,20 +206,20 @@ void Keyer::run() } // If we are in IambicA or IambicB-Mode … - switch (m_state) { + switch (m_PaddleKeyingState) { case State::Wait: if (left_paddle_pressed()) { m_keyNextIambicB = false; - m_state = State::Dit; + m_PaddleKeyingState = State::Dit; } else if (right_paddle_pressed()) { m_keyNextIambicB = false; - m_state = State::Dah; + m_PaddleKeyingState = State::Dah; } else { if (m_mode == Mode::IambicB && m_keyNextIambicB) { if (m_previousState == State::Dit) - m_state = State::Dah; + m_PaddleKeyingState = State::Dah; else - m_state = State::Dit; + m_PaddleKeyingState = State::Dit; m_keyNextIambicB = false; } @@ -112,7 +246,7 @@ void Keyer::run() m_buzzer.off(); // m_audioOut.off(); m_previousState = State::Dit; - m_state = State::DitPause; + m_PaddleKeyingState = State::DitPause; } } break; @@ -137,7 +271,7 @@ void Keyer::run() m_buzzer.off(); // m_audioOut.off(); m_previousState = State::Dah; - m_state = State::DahPause; + m_PaddleKeyingState = State::DahPause; } } break; @@ -150,13 +284,13 @@ void Keyer::run() m_currentlyPausing = false; if (right_paddle_pressed()) { - m_state = State::Dah; + m_PaddleKeyingState = State::Dah; m_keyNextIambicB = false; } else if (left_paddle_pressed()) { - m_state = State::Dit; + m_PaddleKeyingState = State::Dit; m_keyNextIambicB = false; } else { - m_state = State::Wait; + m_PaddleKeyingState = State::Wait; } } } @@ -170,13 +304,13 @@ void Keyer::run() m_currentlyPausing = false; if (left_paddle_pressed()) { - m_state = State::Dit; + m_PaddleKeyingState = State::Dit; m_keyNextIambicB = false; } else if (right_paddle_pressed()) { - m_state = State::Dah; + m_PaddleKeyingState = State::Dah; m_keyNextIambicB = false; } else { - m_state = State::Wait; + m_PaddleKeyingState = State::Wait; } } } @@ -190,11 +324,11 @@ void Keyer::run() m_currentlyPausing = false; m_currentlyKeying = false; m_previousState = State::Abort; - m_state = State::Wait; + m_PaddleKeyingState = State::Wait; break; default: break; } } -void Keyer::stop() { m_state = State::Abort; } \ No newline at end of file +void Keyer::stop() { m_PaddleKeyingState = State::Abort; } \ No newline at end of file diff --git a/src/keyer.h b/src/keyer.h index 6bb6726..90cf00d 100644 --- a/src/keyer.h +++ b/src/keyer.h @@ -14,6 +14,7 @@ class Keyer final void setMode(Mode mode) { m_mode = mode; } void setSpeed(uint8_t wpm); + void sendMessage(const std::string &msg); void run(); void stop(); @@ -28,6 +29,16 @@ class Keyer final Abort, }; + enum class MessageState { + Wait, + Dit, + Dah, + IntraCharSpace, + InterCharSpace, + InterWordSpace, + Abort, + }; + uint8_t m_wpm {18}; Mode m_mode {Mode::IambicB}; @@ -37,12 +48,15 @@ class Keyer final Sidetone m_buzzer; // Sidetone m_audioOut; - State m_state {State::Wait}; + State m_PaddleKeyingState {State::Wait}; State m_previousState {State::Wait}; + + std::queue m_messageQueue; + MessageState m_messageKeyingState {MessageState::Wait}; + char m_messageChar; + uint64_t m_elementDuration {0}; bool m_currentlyKeying {false}; bool m_currentlyPausing {false}; bool m_keyNextIambicB {false}; - - std::queue m_messageQueue; }; \ No newline at end of file diff --git a/src/morse.cpp b/src/morse.cpp index 9b8a5ec..57aafb0 100644 --- a/src/morse.cpp +++ b/src/morse.cpp @@ -37,11 +37,55 @@ std::string refurbishMessage(const std::string &msg) // Remove all other unknown characters msgRefurb.erase(remove_if(msgRefurb.begin(), msgRefurb.end(), - [](const char &c) { return c != ' ' && morseCode.find(c) == morseCode.end(); }), - msgRefurb.end()); + [](const char &c) { return c != ' ' && morseCode.find(c) == morseCode.end(); }), + msgRefurb.end()); // Remove spaces, if there are too many of them msgRefurb = std::regex_replace(msgRefurb, std::regex("(\\s+)"), " "); return msgRefurb; +} + +std::string messageToMorse(const std::string &msg) +{ + std::string refMsg = refurbishMessage(msg); + std::string morseString; + + for (unsigned int i = 0; i < refMsg.length(); i++) { + auto c = refMsg[i]; + if (c == ' ') { + // morseString.append(" "); + morseString += 'w'; + continue; + } + + // Ignore and continue with next char, if not found + auto search = morseCode.find(c); + if (search == morseCode.end()) { + continue; + } + + for (unsigned int j = 0; j < morseCode[c].length(); j++) { + auto m = morseCode[c][j]; + if (j == 0 && i > 0 && refMsg[i - 1] != ' ') { + // morseString.append(" "); + morseString += 'c'; + } + + morseString += m; + + if (j < morseCode[c].length() - 1) { + // morseString.append(" "); + morseString += 'i'; + } + } + } + + // Append word space if last char was not a blank + if (refMsg.back() != ' ') { + // morseString.append(" "); + morseString += 'w'; + } + + return morseString; } \ No newline at end of file diff --git a/src/morse.h b/src/morse.h index 9723aa6..a7f0ecd 100644 --- a/src/morse.h +++ b/src/morse.h @@ -2,4 +2,4 @@ #include -std::string refurbishMessage(const std::string msg); \ No newline at end of file +std::string messageToMorse(const std::string &msg); \ No newline at end of file diff --git a/src/raspi_keyer.cpp b/src/raspi_keyer.cpp index cc5f3a8..2ee91e4 100644 --- a/src/raspi_keyer.cpp +++ b/src/raspi_keyer.cpp @@ -31,11 +31,13 @@ enum class KeyerQueueCommand { Stop, Config, Wait, + SendMessage, }; struct KeyerQueueData { KeyerQueueCommand cmd; uint8_t wpm; Mode mode; + std::string message; }; queue_t keyerQueue; @@ -90,6 +92,9 @@ void core1_main() keyer.setMode(data.mode); data.cmd = KeyerQueueCommand::Run; break; + case KeyerQueueCommand::SendMessage: + keyer.sendMessage(data.message); + break; case KeyerQueueCommand::Wait: break; default: @@ -179,9 +184,11 @@ int main() } lastWpm = currentWpm; - KeyerQueueData keyerQueueData {KeyerQueueCommand::Run, currentWpm, settings.mode}; + KeyerQueueData keyerQueueData {KeyerQueueCommand::Run, currentWpm, settings.mode, ""}; queue_add_blocking(&keyerQueue, &keyerQueueData); + static bool used = false; + while (true) { tud_task(); cdc_task(); @@ -190,13 +197,18 @@ int main() // If WPM in settings is set to 0 -> take speed from poti if (settings.wpm == 0 && (currentWpm != lastWpm)) { - KeyerQueueData keyerQueueData {KeyerQueueCommand::Config, currentWpm, settings.mode}; + KeyerQueueData keyerQueueData {KeyerQueueCommand::Config, currentWpm, settings.mode, ""}; queue_add_blocking(&keyerQueue, &keyerQueueData); printf("WPM has changed to: %d\n", currentWpm); lastWpm = currentWpm; } - //busy_wait_ms(1000); + busy_wait_ms(10000); + if (!used) { + KeyerQueueData keyerQueueData {KeyerQueueCommand::SendMessage, 0, settings.mode, "cq cq de dg2smb dg2smb pse k"}; + queue_add_blocking(&keyerQueue, &keyerQueueData); + } + } return 0;