Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 44 additions & 1 deletion scripts/autokey.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
_ASCII_BACKSPACE = 0x08
_ASCII_NEWLINE = 0x0D
_ASCII_ESCAPE = 0x1B
_ASCII_BACKSLASH = 0x5C

# ----------------------------------------------------- PROCEDURES -----------------------------------------------------

Expand Down Expand Up @@ -73,6 +74,11 @@ def _immediate_mode(port: str = SUPERKEY_DEFAULT_PORT,
# Open interface
with Interface(port=port, baudrate=baudrate, timeout=timeout) as intf:

# Tracking variables
last_char_was_backslash = False
prosign_count = 0
prosign_string = ''

# Loop until commanded to quit
while True:

Expand All @@ -88,8 +94,30 @@ def _immediate_mode(port: str = SUPERKEY_DEFAULT_PORT,
# Panic if the user pressed backspace key
if code == _ASCII_BACKSPACE:
intf.panic()
prosign_count = 0
prosign_string = ''
last_char_was_backslash = False
continue

# Start a prosign if the user pressed backslash key
if code == _ASCII_BACKSLASH:
print(chr(_ASCII_BACKSLASH), end='', flush=True)
prosign_count = 2
prosign_string = ''
last_char_was_backslash = True
continue

# If the last character was a backslash, and the next character is a digit from 2 to 9, then change the
# number of characters we're expecting for the prosign
if last_char_was_backslash and code >= 0x32 and code <= 0x39:
print(chr(code), end='', flush=True)
prosign_count = code - 0x30
last_char_was_backslash = False
continue

# Unconditionally clear flag
last_char_was_backslash = False

# Ignore unknown characters, but allow newlines to print
should_autokey = _should_autokey(code)
should_print = should_autokey or code == _ASCII_NEWLINE
Expand All @@ -106,7 +134,22 @@ def _immediate_mode(port: str = SUPERKEY_DEFAULT_PORT,

# Send character to keyer
if should_autokey:
intf.autokey(char)

# Handle prosigns
if prosign_count != 0:
if len(prosign_string) < prosign_count:
prosign_string += char
if len(prosign_string) == prosign_count:
intf.autokey(prosign_string[:-1], [AutokeyFlag.NO_LETTER_SPACE])
intf.autokey(prosign_string[-1])
prosign_count = 0
prosign_string = ''

# Otherwise, key normally
else:
intf.autokey(char)

# Send character to console
if echo and should_print:
print(char, end='', flush=True)

Expand Down
9 changes: 9 additions & 0 deletions scripts/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@ The following command line arguments are supported:
- `--timeout` - Serial port timeout, in seconds.
- `--silent` - If specified, input will not be echoed back to the console.

### Notes

- Characters are queued for transmission as they are typed.
- Newlines may be typed to help separate messages, but are ignored by the keyer.
- Prosigns may be entered by preceding the characters with a backslash
- (e.g., entering `\ar` will result in the prosign `· — · — ·` being keyed).
- Prosigns with between 2 and 9 characters are supported by immediately following the backslash with a digit.
- (e.g., entering `\3sos` will result in the prosign `· · · — — — · · ·` being keyed).

## Interactive Python Environment

The `interactive.py` script can be used to quickly enter a REPL-like environment for interfacing with your SuperKey. It
Expand Down
19 changes: 15 additions & 4 deletions scripts/superkey/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

import serial
import struct
from typing import Optional, Tuple
from typing import Iterable, Optional, Tuple

from .constants import *
from .types import *
Expand Down Expand Up @@ -110,11 +110,22 @@ def __exit__(self, exc_type, exc_value, traceback):
if self.serial is not None and self.serial.is_open:
self.serial.close()

def autokey(self, string: str):
def autokey(self, string: str, flags: Iterable[AutokeyFlag] = []):
"""
Sends the `REQUEST_AUTOKEY` command. Queues the specified string to be automatically keyed.
Sends the `REQUEST_AUTOKEY_EX` command. Queues the specified string to be automatically keyed.
"""
self.__send_packet(MessageID.REQUEST_AUTOKEY, bytes(string, encoding='ascii') + b'\x00')
# Get flag byte, setting each bit individually
flag_byte = 0
for flag in flags:
flag_byte = flag_byte | (1 << int(flag))

# Assemble payload
payload = (struct.pack('<B', flag_byte) + # First byte is flags
bytes(string, encoding='ascii') + # Then the string
b'\x00') # Null terminator needs to be added manually

# Send packet and check reply
self.__send_packet(MessageID.REQUEST_AUTOKEY_EX, payload)
self.__check_reply_empty()

def get_buzzer_enabled(self) -> bool:
Expand Down
11 changes: 11 additions & 0 deletions scripts/superkey/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
# ------------------------------------------------------ EXPORTS -------------------------------------------------------

__all__ = [
'AutokeyFlag',
'CodeElement',
'IOPin',
'IOPolarity',
Expand All @@ -25,6 +26,15 @@

# ------------------------------------------------------- TYPES --------------------------------------------------------

# Autokey option flags (corresponds to keyer_autokey_flag_t)
AutokeyFlag = IntEnum(
'AutokeyFlag',
[
'NO_LETTER_SPACE',
],
start = 0
)

# Morse code elements (corresponds to wpm_element_t)
CodeElement = IntEnum(
'CodeElement',
Expand Down Expand Up @@ -94,6 +104,7 @@
[
# Requests
'REQUEST_AUTOKEY',
'REQUEST_AUTOKEY_EX',
'REQUEST_GET_BUZZER_ENABLED',
'REQUEST_GET_BUZZER_FREQUENCY',
'REQUEST_GET_INVERT_PADDLES',
Expand Down
43 changes: 41 additions & 2 deletions src/main/application/intf_port.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,12 @@ static void process_message( intf_header_t const * header, void const * payload
*/
static void process_message_request_autokey( intf_header_t const * header, void const * payload );

/**
* @fn process_message_request_autokey_ex( intf_header_t const *, void const * )
* @brief Processes the specified interface message with the `INTF_MESSAGE_REQUEST_AUTOKEY_EX` message ID.
*/
static void process_message_request_autokey_ex( intf_header_t const * header, void const * payload );

/**
* @fn process_message_request_get_buzzer_enabled( intf_header_t const *, void const * )
* @brief Processes the specified interface message with the `INTF_MESSAGE_REQUEST_GET_BUZZER_ENABLED` message ID.
Expand Down Expand Up @@ -386,6 +392,10 @@ static void process_message( intf_header_t const * header, void const * payload
process_message_request_autokey( header, payload );
break;

case INTF_MESSAGE_REQUEST_AUTOKEY_EX:
process_message_request_autokey_ex( header, payload );
break;

case INTF_MESSAGE_REQUEST_GET_BUZZER_ENABLED:
process_message_request_get_buzzer_enabled( header, payload );
break;
Expand Down Expand Up @@ -501,9 +511,10 @@ static void process_message( intf_header_t const * header, void const * payload

static void process_message_request_autokey( intf_header_t const * header, void const * payload )
{
// Ensure string is null terminated
char const * str = ( char const * )payload;
if( str[ header->size - 1 ] != NULL_CHAR )

// Ensure we have enough data and string is null terminated
if( header->size == 0 || str[ header->size - 1 ] != NULL_CHAR )
{
send_empty_packet( INTF_MESSAGE_REPLY_INVALID_PAYLOAD );
return;
Expand All @@ -518,6 +529,34 @@ static void process_message_request_autokey( intf_header_t const * header, void
} /* process_message_request_autokey() */


static void process_message_request_autokey_ex( intf_header_t const * header, void const * payload )
{
typedef struct
{
keyer_autokey_flag_field_t flags;
char c;
} format_t;

format_t const * pkt = ( format_t const * )payload;
char const * str = ( char const * )( & pkt->c );

// Ensure we have enough data and string is null terminated
if( header->size < sizeof( format_t ) ||
str[ header->size - sizeof( keyer_autokey_flag_field_t ) - 1 ] != NULL_CHAR )
{
send_empty_packet( INTF_MESSAGE_REPLY_INVALID_PAYLOAD );
return;
}

// Key string
keyer_autokey_str_ex( str, pkt->flags );

// Send reply
send_empty_packet( INTF_MESSAGE_REPLY_SUCCESS );

} /* process_message_request_autokey_ex() */


static void process_message_request_get_buzzer_enabled( intf_header_t const * header, void const * payload )
{
( void )payload;
Expand Down
1 change: 1 addition & 0 deletions src/main/application/intf_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ typedef uint16_t intf_message_t;
enum
{
INTF_MESSAGE_REQUEST_AUTOKEY, /**< Queues a string to be autokeyed. */
INTF_MESSAGE_REQUEST_AUTOKEY_EX, /**< Queues a string to be autokeyed with flags. */
INTF_MESSAGE_REQUEST_GET_BUZZER_ENABLED,/**< Get buzzer enablement. */
INTF_MESSAGE_REQUEST_GET_BUZZER_FREQUENCY,/**< Get buzzer frequency. */
INTF_MESSAGE_REQUEST_GET_INVERT_PADDLES,/**< Gets paddle inversion setting. */
Expand Down
Loading