first attempt to send messages

This commit is contained in:
Martin Brodbeck 2024-02-23 14:29:36 +01:00
parent c57f9251c2
commit e8901e514d
5 changed files with 230 additions and 26 deletions

View file

@ -47,13 +47,147 @@ void Keyer::setSpeed(uint8_t wpm)
m_elementDuration = calcElementDurationUs(wpm); m_elementDuration = calcElementDurationUs(wpm);
} }
void Keyer::sendMessage(const std::string &msg)
{
for (auto c : msg) {
m_messageQueue.push(c);
}
}
void Keyer::run() void Keyer::run()
{ {
auto timestamp = get_absolute_time(); auto timestamp = get_absolute_time();
// If there is something to send … // If there is something to send …
if (!m_messageQueue.empty()) { if (!m_messageQueue.empty() || m_messageKeyingState != MessageState::Wait) {
// TODO // 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<char> emptyQueue;
std::swap(m_messageQueue, emptyQueue);
break;
}
default:
break;
}
return;
} }
// If we are in Straight key mode … // If we are in Straight key mode …
@ -72,20 +206,20 @@ void Keyer::run()
} }
// If we are in IambicA or IambicB-Mode … // If we are in IambicA or IambicB-Mode …
switch (m_state) { switch (m_PaddleKeyingState) {
case State::Wait: case State::Wait:
if (left_paddle_pressed()) { if (left_paddle_pressed()) {
m_keyNextIambicB = false; m_keyNextIambicB = false;
m_state = State::Dit; m_PaddleKeyingState = State::Dit;
} else if (right_paddle_pressed()) { } else if (right_paddle_pressed()) {
m_keyNextIambicB = false; m_keyNextIambicB = false;
m_state = State::Dah; m_PaddleKeyingState = State::Dah;
} else { } else {
if (m_mode == Mode::IambicB && m_keyNextIambicB) { if (m_mode == Mode::IambicB && m_keyNextIambicB) {
if (m_previousState == State::Dit) if (m_previousState == State::Dit)
m_state = State::Dah; m_PaddleKeyingState = State::Dah;
else else
m_state = State::Dit; m_PaddleKeyingState = State::Dit;
m_keyNextIambicB = false; m_keyNextIambicB = false;
} }
@ -112,7 +246,7 @@ void Keyer::run()
m_buzzer.off(); m_buzzer.off();
// m_audioOut.off(); // m_audioOut.off();
m_previousState = State::Dit; m_previousState = State::Dit;
m_state = State::DitPause; m_PaddleKeyingState = State::DitPause;
} }
} }
break; break;
@ -137,7 +271,7 @@ void Keyer::run()
m_buzzer.off(); m_buzzer.off();
// m_audioOut.off(); // m_audioOut.off();
m_previousState = State::Dah; m_previousState = State::Dah;
m_state = State::DahPause; m_PaddleKeyingState = State::DahPause;
} }
} }
break; break;
@ -150,13 +284,13 @@ void Keyer::run()
m_currentlyPausing = false; m_currentlyPausing = false;
if (right_paddle_pressed()) { if (right_paddle_pressed()) {
m_state = State::Dah; m_PaddleKeyingState = State::Dah;
m_keyNextIambicB = false; m_keyNextIambicB = false;
} else if (left_paddle_pressed()) { } else if (left_paddle_pressed()) {
m_state = State::Dit; m_PaddleKeyingState = State::Dit;
m_keyNextIambicB = false; m_keyNextIambicB = false;
} else { } else {
m_state = State::Wait; m_PaddleKeyingState = State::Wait;
} }
} }
} }
@ -170,13 +304,13 @@ void Keyer::run()
m_currentlyPausing = false; m_currentlyPausing = false;
if (left_paddle_pressed()) { if (left_paddle_pressed()) {
m_state = State::Dit; m_PaddleKeyingState = State::Dit;
m_keyNextIambicB = false; m_keyNextIambicB = false;
} else if (right_paddle_pressed()) { } else if (right_paddle_pressed()) {
m_state = State::Dah; m_PaddleKeyingState = State::Dah;
m_keyNextIambicB = false; m_keyNextIambicB = false;
} else { } else {
m_state = State::Wait; m_PaddleKeyingState = State::Wait;
} }
} }
} }
@ -190,11 +324,11 @@ void Keyer::run()
m_currentlyPausing = false; m_currentlyPausing = false;
m_currentlyKeying = false; m_currentlyKeying = false;
m_previousState = State::Abort; m_previousState = State::Abort;
m_state = State::Wait; m_PaddleKeyingState = State::Wait;
break; break;
default: default:
break; break;
} }
} }
void Keyer::stop() { m_state = State::Abort; } void Keyer::stop() { m_PaddleKeyingState = State::Abort; }

View file

@ -14,6 +14,7 @@ class Keyer final
void setMode(Mode mode) { m_mode = mode; } void setMode(Mode mode) { m_mode = mode; }
void setSpeed(uint8_t wpm); void setSpeed(uint8_t wpm);
void sendMessage(const std::string &msg);
void run(); void run();
void stop(); void stop();
@ -28,6 +29,16 @@ class Keyer final
Abort, Abort,
}; };
enum class MessageState {
Wait,
Dit,
Dah,
IntraCharSpace,
InterCharSpace,
InterWordSpace,
Abort,
};
uint8_t m_wpm {18}; uint8_t m_wpm {18};
Mode m_mode {Mode::IambicB}; Mode m_mode {Mode::IambicB};
@ -37,12 +48,15 @@ class Keyer final
Sidetone m_buzzer; Sidetone m_buzzer;
// Sidetone m_audioOut; // Sidetone m_audioOut;
State m_state {State::Wait}; State m_PaddleKeyingState {State::Wait};
State m_previousState {State::Wait}; State m_previousState {State::Wait};
std::queue<char> m_messageQueue;
MessageState m_messageKeyingState {MessageState::Wait};
char m_messageChar;
uint64_t m_elementDuration {0}; uint64_t m_elementDuration {0};
bool m_currentlyKeying {false}; bool m_currentlyKeying {false};
bool m_currentlyPausing {false}; bool m_currentlyPausing {false};
bool m_keyNextIambicB {false}; bool m_keyNextIambicB {false};
std::queue<std::string> m_messageQueue;
}; };

View file

@ -37,11 +37,55 @@ std::string refurbishMessage(const std::string &msg)
// Remove all other unknown characters // Remove all other unknown characters
msgRefurb.erase(remove_if(msgRefurb.begin(), msgRefurb.end(), msgRefurb.erase(remove_if(msgRefurb.begin(), msgRefurb.end(),
[](const char &c) { return c != ' ' && morseCode.find(c) == morseCode.end(); }), [](const char &c) { return c != ' ' && morseCode.find(c) == morseCode.end(); }),
msgRefurb.end()); msgRefurb.end());
// Remove spaces, if there are too many of them // Remove spaces, if there are too many of them
msgRefurb = std::regex_replace(msgRefurb, std::regex("(\\s+)"), " "); msgRefurb = std::regex_replace(msgRefurb, std::regex("(\\s+)"), " ");
return msgRefurb; 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;
} }

View file

@ -2,4 +2,4 @@
#include <string> #include <string>
std::string refurbishMessage(const std::string msg); std::string messageToMorse(const std::string &msg);

View file

@ -31,11 +31,13 @@ enum class KeyerQueueCommand {
Stop, Stop,
Config, Config,
Wait, Wait,
SendMessage,
}; };
struct KeyerQueueData { struct KeyerQueueData {
KeyerQueueCommand cmd; KeyerQueueCommand cmd;
uint8_t wpm; uint8_t wpm;
Mode mode; Mode mode;
std::string message;
}; };
queue_t keyerQueue; queue_t keyerQueue;
@ -90,6 +92,9 @@ void core1_main()
keyer.setMode(data.mode); keyer.setMode(data.mode);
data.cmd = KeyerQueueCommand::Run; data.cmd = KeyerQueueCommand::Run;
break; break;
case KeyerQueueCommand::SendMessage:
keyer.sendMessage(data.message);
break;
case KeyerQueueCommand::Wait: case KeyerQueueCommand::Wait:
break; break;
default: default:
@ -179,9 +184,11 @@ int main()
} }
lastWpm = currentWpm; lastWpm = currentWpm;
KeyerQueueData keyerQueueData {KeyerQueueCommand::Run, currentWpm, settings.mode}; KeyerQueueData keyerQueueData {KeyerQueueCommand::Run, currentWpm, settings.mode, ""};
queue_add_blocking(&keyerQueue, &keyerQueueData); queue_add_blocking(&keyerQueue, &keyerQueueData);
static bool used = false;
while (true) { while (true) {
tud_task(); tud_task();
cdc_task(); cdc_task();
@ -190,13 +197,18 @@ int main()
// If WPM in settings is set to 0 -> take speed from poti // If WPM in settings is set to 0 -> take speed from poti
if (settings.wpm == 0 && (currentWpm != lastWpm)) { 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); queue_add_blocking(&keyerQueue, &keyerQueueData);
printf("WPM has changed to: %d\n", currentWpm); printf("WPM has changed to: %d\n", currentWpm);
lastWpm = 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; return 0;