diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 887f394..6985f83 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -17,5 +17,7 @@ target_sources(raspi_keyer PRIVATE keyer.cpp sidetone.cpp morse.cpp + winkeyer.cpp + utils.cpp usb_descriptors.c ) diff --git a/src/raspi_keyer.cpp b/src/raspi_keyer.cpp index 1d223ed..5ba5906 100644 --- a/src/raspi_keyer.cpp +++ b/src/raspi_keyer.cpp @@ -12,11 +12,8 @@ #include "settings.h" #include #include "tusb_config.h" - -namespace -{ - -} +#include "utils.h" +#include "winkeyer.h" extern const uint LED_PIN = PICO_DEFAULT_LED_PIN; extern const uint LEFT_PADDLE_PIN = 14; @@ -26,21 +23,6 @@ extern const uint CW_OUT_PIN = 17; // extern const uint AUDIO_OUT_PIN = 16; extern const uint ADC_PIN = 26; -// Stuff for communicating between cores -enum class KeyerQueueCommand { - Run, - Stop, - Config, - Wait, - SendMessage, -}; -struct KeyerQueueData { - KeyerQueueCommand cmd; - uint8_t wpm; - Mode mode; - char message; -}; - queue_t keyerQueue; void setup() @@ -65,6 +47,10 @@ void setup() adc_init(); gpio_init(ADC_PIN); adc_select_input(0); + + // Setup USB + board_init(); + tud_init(BOARD_TUD_RHPORT); } /* Let's do all the keying stuff in the second core, so there are no timing problems. */ @@ -105,100 +91,12 @@ void core1_main() } } -static void usbSend(uint8_t itf, uint8_t buf[], uint32_t count) -{ - for (uint32_t i = 0; i < count; i++) { - tud_cdc_n_write_char(itf, buf[i]); - } - - tud_cdc_n_write_flush(itf); -} - -static void usbSend(uint8_t itf, uint8_t value) -{ - tud_cdc_n_write_char(itf, value); - tud_cdc_n_write_flush(itf); -} - -void cdc_task() -{ - const uint8_t USB_IF = 0; - - if (tud_cdc_n_available(USB_IF)) { - uint8_t buf[64]; - - //printf("AHA!!! %d\n", (int)tud_cdc_n_available(USB_IF)); - uint32_t count = tud_cdc_n_read(USB_IF, buf, sizeof(buf)); - - if (count > 0) { - switch (buf[0]) { - case 'a' ... 'z': - [[fallthrough]]; - case 'A' ... 'Z': - [[fallthrough]]; - case '0' ... '9': - [[fallthrough]]; - case ' ': - [[fallthrough]]; - case '+': - [[fallthrough]]; - case '=': - [[fallthrough]]; - case '?': - [[fallthrough]]; - case ',': - [[fallthrough]]; - case '.': - { - KeyerQueueData keyerQueueData {KeyerQueueCommand::SendMessage, 0, Mode::IambicB, buf[0]}; - queue_add_blocking(&keyerQueue, &keyerQueueData); - break; - } - case 0x00: // ADMIN COMMAND - switch (buf[1]) { - case 0x02: // HOST OPEN - usbSend(USB_IF, 9); // Send WK1 (v9) for now (no WinKeyer PTT control) - break; - case 0x04: // ECHO TEST - usbSend(USB_IF, &buf[2], 1); // Send the received byte back - break; - default: - printf("Unknown admin command: %x\n", buf[1]); - } - break; - default: - printf("Unknown command: %d.\n", buf[0]); - } - } - } -} - -/* Returns the voltage level in percent (3,3V == 100%) */ -float potiRead() -{ - // 12-bit conversion, assume max value == ADC_VREF == 3.3 V - const float conversion_factor = 3.3f / (1 << 12); - float voltage = adc_read() * conversion_factor; - - return voltage * 100 / 3.3; -} - -/* Calculates the WPM speed from the volt percentage */ -uint8_t calcWPM(float percent, uint8_t wpmMin, uint8_t wpmMax) -{ - auto wpm = (percent * (wpmMax - wpmMin) / 100) + wpmMin; - uint8_t result = static_cast(std::round(wpm)); - return result; -} - int main() { timer_hw->dbgpause = 0; // workaround for problem with debug and sleep_ms // https://github.com/raspberrypi/pico-sdk/issues/1152#issuecomment-1418248639 setup(); - board_init(); - tud_init(BOARD_TUD_RHPORT); printf("RaspiKeyer Version %s\n", PROJECT_VERSION); @@ -222,6 +120,8 @@ int main() KeyerQueueData keyerQueueData {KeyerQueueCommand::Run, currentWpm, settings.mode, 0}; queue_add_blocking(&keyerQueue, &keyerQueueData); + WinKeyer winKeyer; + while (true) { currentWpm = calcWPM(potiRead(), settings.wpmPotiMin, settings.wpmPotiMax); @@ -233,8 +133,9 @@ int main() lastWpm = currentWpm; } - tud_task(); - cdc_task(); + tud_task(); // Internal PICO purposes + + winKeyer.run(keyerQueue); } return 0; diff --git a/src/utils.cpp b/src/utils.cpp new file mode 100644 index 0000000..617b7ba --- /dev/null +++ b/src/utils.cpp @@ -0,0 +1,38 @@ +#include + +#include "hardware/adc.h" +#include "pico/stdlib.h" +#include "tusb.h" + +#include "utils.h" + +uint8_t calcWPM(float percent, uint8_t wpmMin, uint8_t wpmMax) +{ + auto wpm = (percent * (wpmMax - wpmMin) / 100) + wpmMin; + uint8_t result = static_cast(std::round(wpm)); + return result; +} + +float potiRead() +{ + // 12-bit conversion, assume max value == ADC_VREF == 3.3 V + const float conversion_factor = 3.3f / (1 << 12); + float voltage = adc_read() * conversion_factor; + + return voltage * 100 / 3.3; +} + +void usbSend(uint8_t itf, uint8_t buf[], uint32_t count) +{ + for (uint32_t i = 0; i < count; i++) { + tud_cdc_n_write_char(itf, buf[i]); + } + + tud_cdc_n_write_flush(itf); +} + +void usbSend(uint8_t itf, uint8_t value) +{ + tud_cdc_n_write_char(itf, value); + tud_cdc_n_write_flush(itf); +} \ No newline at end of file diff --git a/src/utils.h b/src/utils.h new file mode 100644 index 0000000..5bf3153 --- /dev/null +++ b/src/utils.h @@ -0,0 +1,29 @@ +#pragma once + +#include "settings.h" + +// Stuff for communicating between cores +enum class KeyerQueueCommand { + Run, + Stop, + Config, + Wait, + SendMessage, +}; + +struct KeyerQueueData { + KeyerQueueCommand cmd; + uint8_t wpm; + Mode mode; + uint8_t message; +}; + +/* Calculates the WPM speed from the volt percentage */ +uint8_t calcWPM(float percent, uint8_t wpmMin, uint8_t wpmMax); + +/* Returns the voltage level in percent (3,3V == 100%) */ +float potiRead(); + +// Sending bytes over USB +void usbSend(uint8_t itf, uint8_t buf[], uint32_t count); +void usbSend(uint8_t itf, uint8_t value); \ No newline at end of file diff --git a/src/winkeyer.cpp b/src/winkeyer.cpp new file mode 100644 index 0000000..1eb2ff2 --- /dev/null +++ b/src/winkeyer.cpp @@ -0,0 +1,58 @@ +#include "pico/stdlib.h" +#include "tusb.h" + +#include "utils.h" + +#include "winkeyer.h" + +void WinKeyer::run(queue_t &queue) +{ + const uint8_t USB_IF = 0; + + if (tud_cdc_n_available(USB_IF)) { + uint8_t buf[64]; + + // printf("AHA!!! %d\n", (int)tud_cdc_n_available(USB_IF)); + uint32_t count = tud_cdc_n_read(USB_IF, buf, sizeof(buf)); + + if (count > 0) { + switch (buf[0]) { + case 'a' ... 'z': + [[fallthrough]]; + case 'A' ... 'Z': + [[fallthrough]]; + case '0' ... '9': + [[fallthrough]]; + case ' ': + [[fallthrough]]; + case '+': + [[fallthrough]]; + case '=': + [[fallthrough]]; + case '?': + [[fallthrough]]; + case ',': + [[fallthrough]]; + case '.': { + KeyerQueueData keyerQueueData {KeyerQueueCommand::SendMessage, 0, Mode::IambicB, buf[0]}; + queue_add_blocking(&queue, &keyerQueueData); + break; + } + case 0x00: // ADMIN COMMAND + switch (buf[1]) { + case 0x02: // HOST OPEN + usbSend(USB_IF, 9); // Send WK1 (v9) for now (no WinKeyer PTT control) + break; + case 0x04: // ECHO TEST + usbSend(USB_IF, &buf[2], 1); // Send the received byte back + break; + default: + printf("Unknown admin command: %x\n", buf[1]); + } + break; + default: + printf("Unknown command: %d.\n", buf[0]); + } + } + } +} \ No newline at end of file diff --git a/src/winkeyer.h b/src/winkeyer.h new file mode 100644 index 0000000..a4afaaa --- /dev/null +++ b/src/winkeyer.h @@ -0,0 +1,11 @@ +#pragma once + +#include "pico/util/queue.h" + +class WinKeyer final +{ + public: + void run(queue_t &queue); + + private: +}; \ No newline at end of file