raspikeyer/src/raspikeyer.cpp

195 lines
5.5 KiB
C++

#include <cmath>
#include <stdio.h>
#include <utility>
#include "bsp/board.h"
#include "hardware/adc.h"
#include "pico/binary_info/code.h"
#include "pico/multicore.h"
#include "pico/stdlib.h"
#include "pico/util/queue.h"
#include "tusb.h"
#include "keyer.h"
#include "settings.h"
#include "tm1637.h"
#include "tusb_config.h"
#include "utils.h"
#include "winkeyer.h"
#include <config.h>
extern constexpr uint LED_PIN = PICO_DEFAULT_LED_PIN;
extern constexpr uint DIT_PADDLE_PIN = 14;
extern constexpr uint DAH_PADDLE_PIN = 15;
// extern const uint AUDIO_OUT_PIN = 16;
extern constexpr uint CW_OUT_PIN = 17;
extern constexpr uint BUZZER_PIN = 18;
constexpr uint DISPLAY_DIO_PIN = 20;
constexpr uint DISPLAY_CLK_PIN = 21;
extern constexpr uint ADC_PIN = 26;
constexpr uint BUTTON_KEYER_MODE = 2;
queue_t keyerQueue;
void setup()
{
stdio_init_all();
gpio_init(LED_PIN);
gpio_set_dir(LED_PIN, GPIO_OUT);
gpio_put(LED_PIN, 0);
// Setup pins for left and right paddles
gpio_init(DIT_PADDLE_PIN);
gpio_set_dir(DIT_PADDLE_PIN, GPIO_IN);
gpio_pull_up(DIT_PADDLE_PIN);
gpio_init(DAH_PADDLE_PIN);
gpio_set_dir(DAH_PADDLE_PIN, GPIO_IN);
gpio_pull_up(DAH_PADDLE_PIN);
gpio_init(CW_OUT_PIN);
gpio_set_dir(CW_OUT_PIN, GPIO_OUT);
gpio_put(CW_OUT_PIN, 0);
// Setup Button Keyer Mode
gpio_init(BUTTON_KEYER_MODE);
gpio_set_dir(BUTTON_KEYER_MODE, GPIO_IN);
gpio_pull_down(BUTTON_KEYER_MODE);
// Setup ADC
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. */
void core1_main()
{
flash_safe_execute_core_init();
KeyerQueueData data;
queue_remove_blocking(&keyerQueue, &data);
Keyer keyer(data.wpm, data.mode);
while (true) {
queue_try_remove(&keyerQueue, &data);
switch (data.cmd) {
case KeyerQueueCommand::Run:
keyer.run();
break;
case KeyerQueueCommand::Stop:
keyer.stop();
data.cmd = KeyerQueueCommand::Run;
break;
case KeyerQueueCommand::Config:
keyer.setSpeed(data.wpm);
keyer.setMode(data.mode);
data.cmd = KeyerQueueCommand::Run;
break;
case KeyerQueueCommand::SendMessage:
keyer.sendCharacter(data.message);
data.cmd = KeyerQueueCommand::Run;
break;
default:
break;
}
}
}
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();
printf("RaspiKeyer Version %s\n", PROJECT_VERSION);
queue_init(&keyerQueue, sizeof(KeyerQueueData), 2);
multicore_reset_core1();
multicore_launch_core1(core1_main);
Settings settings {read_settings()};
uint8_t currentWpm {0};
uint8_t lastWpm {0};
// If WPM in settings is set to 0 -> take speed from poti
if (settings.wpm == 0) {
currentWpm = calcWPM(potiRead(), settings.wpmPotiMin, settings.wpmPotiMax);
} else {
currentWpm = settings.wpm;
}
lastWpm = currentWpm;
KeyerQueueData keyerQueueData {KeyerQueueCommand::Run, currentWpm, settings.mode, 0};
queue_add_blocking(&keyerQueue, &keyerQueueData);
WinKeyer winKeyer;
pio_hw_t *pio = pio0;
TM1637 display {DISPLAY_DIO_PIN, DISPLAY_CLK_PIN, pio};
bi_decl(bi_1pin_with_name(DISPLAY_DIO_PIN, "[DIO] LED segments data pin"));
bi_decl(bi_1pin_with_name(DISPLAY_CLK_PIN, "[CLK] LED segments clock pin"));
display.displayIambicMode(settings.mode);
display.displaySpeed(currentWpm);
auto timestamp = get_absolute_time();
auto ignoreButtonKeyerModeUntil = timestamp;
auto count = std::to_underlying(settings.mode);
while (true) {
timestamp = get_absolute_time();
currentWpm = calcWPM(potiRead(), settings.wpmPotiMin, settings.wpmPotiMax);
// If WPM in settings is set to 0 -> take speed from poti
if (settings.wpm == 0 && (currentWpm != lastWpm)) {
keyerQueueData.cmd = KeyerQueueCommand::Config;
keyerQueueData.wpm = currentWpm;
queue_add_blocking(&keyerQueue, &keyerQueueData);
printf("WPM has changed to: %d\n", currentWpm);
lastWpm = currentWpm;
display.displaySpeed(currentWpm);
}
// If Button for keying mode is pressed, toggle through the possible values (Iambic A, Iambic B, Straight)
if (absolute_time_diff_us(timestamp, ignoreButtonKeyerModeUntil) <= 0 && gpio_get(BUTTON_KEYER_MODE)) {
++count;
count = count % 3;
switch (count) {
case 0:
settings.mode = Mode::IambicA;
break;
case 1:
settings.mode = Mode::IambicB;
break;
case 2:
settings.mode = Mode::Straight;
break;
default:
std::unreachable();
}
keyerQueueData.cmd = KeyerQueueCommand::Config;
keyerQueueData.mode = settings.mode;
queue_add_blocking(&keyerQueue, &keyerQueueData);
display.displayIambicMode(settings.mode);
ignoreButtonKeyerModeUntil = make_timeout_time_us(500'000);
}
tud_task(); // Internal PICO purposes
winKeyer.run(keyerQueue);
}
return 0;
}