-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathkeyer.cpp
199 lines (185 loc) · 6.96 KB
/
keyer.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include <cstring>
#include <cstdlib>
#include "pico/stdlib.h"
#include "hardware/uart.h"
#include "hardware/gpio.h"
#include <queue>
#include "alphabet.h"
// Carriage Return is the send trigger via UART
#define CR 13u
// // the data will reside on UART 0
#define DATA uart0
// NOTE: to build for the Seeed XIAO RP2040 define XIAO2040 here,
#undef XIAO2040
// otherwise it will build for the RaspberryPi Pico
#ifdef XIAO2040
// physical pin 6 on in XIAO 2040
#define UART_DATA_TX_PIN 6u
// physical pin 7 on the XIAO
#define UART_DATA_RX_PIN 7u
//physical pin 8 on the XIAO to key radio/oscillator
#define KEYER 8u
#else
// physical pin 1 on the Pico
#define UART_DATA_TX_PIN 0u
// physical pin 2 on the Pico
#define UART_DATA_RX_PIN 1u
// physical pin 9 on the Pico to key radio/oscillator
#define KEYER 6u
#endif
// modem baud rate
#define DATA_BAUD 115200u
// Use the on-board Pico LED to display ready and report speed changes
// the same GPIO pin number is used for Pico and XIAO RP2040 (25)
const uint LED = PICO_DEFAULT_LED_PIN;
// Morse standard timing is Dot = 1, Dash = 3, Between dots/dashes = 1, between letters = 3, and between words = 7
// Wet dit (dot) time to determine the speed
uint dit = 80u; // dit length ms which is 80 ms dir = 15 PARIS WPM
bool b_fullcmd = false; // we have gathered a full command from the USB
bool b_keyit = true; // true send OTA, false, only flash LED
std::queue<char> tokey; // input byte queue from the DATA UART
char inbyte, keychar, kc;
int j = 0; // string loop counter
void loop() {
// here is where we continually read the serial port
// for ascii to convert to Morse and manage the GPIO
// pin to key the radio. The Carriage Return is the
// line terminator, so we build a vector of chars
// and then send each one to the KEYER GPIO when the user
// sends the Carriage Return
while(uart_is_readable(DATA)) {
// read the byte, store it and look out for CR (0x0D)
inbyte = uart_getc(DATA);
//printf("%c", inbyte); // debug echo so we can see exactly what was sent from UART
if(inbyte == CR) {
b_fullcmd = true; // we got the frame end ok
//printf("\r\nQUEUE: %d", tokey.size());
break;
}
else { // add to the queue
tokey.emplace(inbyte); // in place push with no copying
}
}
// we read the stdin from the USB port to get speed command
// or text to send. once a CR is reached, perform the speed
// change or key the characters
// while(true) {
// int in = getchar_timeout_us(100);
// if(in != PICO_ERROR_TIMEOUT) {
// inbyte = (in & 0xFF); // ensure only one byte from the int is in play
// //printf("%c", inbyte); // echo the byte for the user
// if(inbyte == CR) {
// b_fullcmd = true; // we found an input line marker (CR)
// break;
// }
// else { // otherwise add this character to the work queue
// tokey.emplace(inbyte);
// }
// }
// }
if(b_fullcmd == true) { // should be a fully formed sentence to key
//printf("Full Cmd\r\n");
// here we process the full command from the UART
// and key the transmitter via GPIO KEYER
printf("\r\n");
b_keyit = true; // send this data over the air
const int end = tokey.size(); // so when we pop this doesn't change
for(uint i = 0; i < end; i++) {
keychar = tokey.front();
if(keychar == '@') {
// this is a speed command so take the rest of the digits the WPM speed
tokey.pop(); // pop the @
int paris = atoi(&tokey.front()); // represents 0x00 terminated string pointer
if(paris < 5) paris = 5;
dit = (int) 1200/paris;
printf("%02d WPM %dms dot\r\n", paris, dit);
//b_keyit = false; // only flash the LED
while(tokey.size() > 0) { // empty this vector
tokey.pop();
}
break;
}
printf("%c", (int)keychar);
tokey.pop(); // remove last used item
char * keystr = alphabet[keychar]; // look up the keying pattern by ASCII char value
if(keystr == "") {
sleep_ms(dit * 3);
continue; // skip the unknown char
}
if(keystr == " ") {
printf("%s", " ");
sleep_ms(dit * 6); // inter-word space = 7, so 1 dit time from end of word + 6 * dit times
continue;
}
// one string of dits and dahs makes ONE character
j = 0; // index in keystr
kc = keystr[j]; // DIT or DAH
while (kc != 0x00) {
if(b_keyit) gpio_put(KEYER, 1); // key on
gpio_put(LED, 1);
if(kc == '.') {
sleep_ms(dit); // a DIT length
}
else {
sleep_ms(dit * 3); // DAH is 3 dit lengths
}
if(b_keyit) gpio_put(KEYER, 0); // key off
gpio_put(LED, 0);
sleep_ms(dit); // intra-key delay
j++;
kc = keystr[j];
}
sleep_ms(dit * 3); // wait 3 dit lengths between characters
}
}
b_fullcmd = false;
}
int main() {
stdio_init_all();
// Set up the DATA UART interface
uart_init(DATA, DATA_BAUD);
// turn off RTS/CTS flow control
uart_set_hw_flow(DATA, false, false); // defaults not specified
uart_set_format(DATA, 8, 1, UART_PARITY_NONE); // default values
uart_set_translate_crlf(DATA, false); // default value
uart_set_fifo_enabled(DATA, false); // default value
// DATA Physical Pico Pins 1, 2 (GPIO0, GPIO1)
gpio_set_function(UART_DATA_TX_PIN, GPIO_FUNC_UART);
gpio_set_function(UART_DATA_RX_PIN, GPIO_FUNC_UART);
stdio_uart_init();
// Set up the USB as the stdio interface
//stdio_usb_init();
sleep_ms(1000); // give it a sec to catch up before printf's begin
//while(!stdio_usb_connected) {;}
// initialize GPIO as the output pin
gpio_init(KEYER); // sets GPIO function to SIO
gpio_init(LED);
// set mode to OUTPUT
gpio_set_dir(KEYER, GPIO_OUT);
gpio_set_dir(LED, GPIO_OUT);
// set pull-ups to avoid float keying
// and always leave the GPIO pin in low state when finished
gpio_set_pulls(KEYER, true, true);
// send the letter "R" on power up
gpio_put(LED, 1); // one flash at start so set to ON
sleep_ms(100); // on duration ms
gpio_put(LED, 0); // set the GPIO to low KEY OFF
sleep_ms(100); // on duration ms
gpio_put(LED, 1); // one flash at start so set to ON
sleep_ms(300); // on duration ms
gpio_put(LED, 0); // set the GPIO to low KEY OFF
sleep_ms(100); // on duration ms
gpio_put(LED, 1); // one flash at start so set to ON
sleep_ms(100); // on duration ms
gpio_put(LED, 0); // set the GPIO to low KEY OFF
// Start the main loop
while (true) {
loop();
}
}