718 wiersze
14 KiB
C++
718 wiersze
14 KiB
C++
/*
|
|
* MIT License
|
|
*
|
|
* Copyright (c) 2020 DigitalConfections
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*/
|
|
|
|
#include "morse.h"
|
|
#include <stddef.h>
|
|
|
|
MorseCharacter getMorseChar(char c);
|
|
|
|
#define SOLID_KEYDOWN 0xFF
|
|
#define INTER_CHAR_SPACE 0xFE
|
|
#define INTER_WORD_SPACE 0xFD
|
|
|
|
/*
|
|
* Load a string to send by passing in a pointer via the first argument.
|
|
* Call this function with a NULL argument at intervals of 1 element of time to generate Morse code.
|
|
* Once loaded with a string each call to this function returns a BOOL indicating whether a CW carrier should be sent
|
|
* Pass in a pointer to a BOOL in the second and third arguments:
|
|
*/
|
|
BOOL makeMorse(char* s, BOOL* repeating, BOOL* finished)
|
|
{
|
|
static char* str = NULL;
|
|
static char c = ' ';
|
|
static BOOL repeat = TRUE;
|
|
static MorseCharacter morseInProgress;
|
|
static uint8_t charIndex; /* letters, numbers, punctuation */
|
|
static uint8_t symbolIndex; /* dits and dahs */
|
|
static uint8_t elementIndex; /* units of time: dit = 1, dah = 3, intersymbol = 1, intercharacter = 3, etc. */
|
|
static uint8_t addedSpace; /* adds additional time to make an inter-character space */
|
|
static BOOL completedString = FALSE;
|
|
static BOOL carrierOn = FALSE;
|
|
static BOOL holdKeyDown = FALSE;
|
|
|
|
if(s) /* load a new NULL-terminated string to send */
|
|
{
|
|
holdKeyDown = FALSE;
|
|
|
|
if(repeating)
|
|
{
|
|
repeat = *repeating;
|
|
}
|
|
|
|
if(*s)
|
|
{
|
|
str = s;
|
|
c = ' ';
|
|
morseInProgress = getMorseChar(*str);
|
|
charIndex = 0;
|
|
symbolIndex = 0;
|
|
elementIndex = 0;
|
|
addedSpace = 0;
|
|
completedString = FALSE;
|
|
}
|
|
else /* a zero-length string shuts down makeMorse */
|
|
{
|
|
str = NULL;
|
|
completedString = TRUE;
|
|
if(finished)
|
|
{
|
|
*finished = TRUE;
|
|
}
|
|
}
|
|
|
|
carrierOn = OFF;
|
|
return( OFF);
|
|
}
|
|
else if(str)
|
|
{
|
|
if(repeating)
|
|
{
|
|
*repeating = repeat;
|
|
}
|
|
|
|
if(completedString)
|
|
{
|
|
if(finished)
|
|
{
|
|
*finished = TRUE;
|
|
holdKeyDown = FALSE;
|
|
}
|
|
return( OFF);
|
|
}
|
|
|
|
if(elementIndex)
|
|
{
|
|
elementIndex--;
|
|
}
|
|
else if(carrierOn && !holdKeyDown) /* carrier is on, so turn it off and wait appropriate amount of space */
|
|
{
|
|
carrierOn = FALSE;
|
|
/* wait one element = inter-symbol space */
|
|
if(addedSpace)
|
|
{
|
|
elementIndex = addedSpace;
|
|
addedSpace = 0;
|
|
}
|
|
/* wait inter-character space */
|
|
}
|
|
else /* carrier is off, so turn it on and get next symbol */
|
|
{
|
|
if(symbolIndex >= morseInProgress.lengthInSymbols)
|
|
{
|
|
c = (*(str + ++charIndex));
|
|
|
|
if(!c) /* wrap to beginning of text */
|
|
{
|
|
if(repeat)
|
|
{
|
|
c = *str;
|
|
charIndex = 0;
|
|
}
|
|
else
|
|
{
|
|
str = NULL;
|
|
carrierOn = OFF;
|
|
completedString = TRUE;
|
|
if(finished)
|
|
{
|
|
*finished = TRUE;
|
|
}
|
|
holdKeyDown = FALSE;
|
|
return( OFF );
|
|
}
|
|
}
|
|
|
|
morseInProgress = getMorseChar(c);
|
|
symbolIndex = 0;
|
|
}
|
|
|
|
if(morseInProgress.pattern < INTER_WORD_SPACE)
|
|
{
|
|
BOOL isDah = morseInProgress.pattern & (1 << symbolIndex++);
|
|
|
|
if(isDah)
|
|
{
|
|
elementIndex = 2;
|
|
}
|
|
else
|
|
{
|
|
elementIndex = 0;
|
|
}
|
|
|
|
carrierOn = TRUE;
|
|
|
|
if(symbolIndex >= morseInProgress.lengthInSymbols)
|
|
{
|
|
addedSpace = 2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uint8_t sym = morseInProgress.lengthInSymbols;
|
|
symbolIndex = 255; /* ensure the next character gets read */
|
|
carrierOn = FALSE;
|
|
if(sym >= 4 )
|
|
{
|
|
elementIndex = morseInProgress.lengthInSymbols - 4;
|
|
}
|
|
else
|
|
{
|
|
elementIndex = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Overrides for key on and key off special characters */
|
|
if(c == '<') /* constant tone */
|
|
{
|
|
holdKeyDown = TRUE;
|
|
}
|
|
else
|
|
{
|
|
holdKeyDown = FALSE;
|
|
}
|
|
}
|
|
|
|
if(finished)
|
|
{
|
|
*finished = completedString;
|
|
}
|
|
|
|
if(holdKeyDown)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
else
|
|
{
|
|
return( carrierOn);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the number of milliseconds required to send the string pointed to by the first argument at the WPM code speed
|
|
* passed in the second argument.
|
|
*/
|
|
uint16_t timeRequiredToSendStrAtWPM(char* str, uint16_t spd)
|
|
{
|
|
uint8_t elements = 0;
|
|
MorseCharacter m;
|
|
char c;
|
|
|
|
for(int i = 0; i < 20; i++)
|
|
{
|
|
c = str[i];
|
|
if(!c)
|
|
{
|
|
break;
|
|
}
|
|
m = getMorseChar(c);
|
|
if(m.pattern < INTER_WORD_SPACE)
|
|
{
|
|
elements += 3;
|
|
}
|
|
elements += m.lengthInElements;
|
|
}
|
|
|
|
return(elements * WPM_TO_MS_PER_DOT(spd));
|
|
}
|
|
|
|
/**
|
|
* Morse Code characters are defined as having three attributes:
|
|
* pattern = a sequence of up to 8 dit and dah symbols contained in an unsigned byte, sequentially read from LSB to MSB (first symbol is bit 0)
|
|
* lengthInSymbols = how many symbols (dits and dahs) the character contains; this is how many pattern bits are used to represent the character
|
|
* lengthInElements = how long (measured in "dit lengths") is the total character including all inter-symbol spaces.
|
|
*/
|
|
MorseCharacter getMorseChar(char c)
|
|
{
|
|
MorseCharacter morse;
|
|
|
|
switch( c )
|
|
{
|
|
case 'A':
|
|
{
|
|
morse.pattern = 0x02; /* 0000 0010; */
|
|
morse.lengthInSymbols = 2;
|
|
morse.lengthInElements = 5;
|
|
}
|
|
break;
|
|
|
|
case 'B':
|
|
{
|
|
morse.pattern = 0x01; /* 0000 0001; */
|
|
morse.lengthInSymbols = 4;
|
|
morse.lengthInElements = 9;
|
|
}
|
|
break;
|
|
|
|
case 'C':
|
|
{
|
|
morse.pattern = 0x05; /* 0000 0101; */
|
|
morse.lengthInSymbols = 4;
|
|
morse.lengthInElements = 11;
|
|
}
|
|
break;
|
|
|
|
case 'D':
|
|
{
|
|
morse.pattern = 0x01; /* 0000 0001; */
|
|
morse.lengthInSymbols = 3;
|
|
morse.lengthInElements = 7;
|
|
}
|
|
break;
|
|
|
|
case 'E':
|
|
{
|
|
morse.pattern = 0x00; /* 0000 0000; */
|
|
morse.lengthInSymbols = 1;
|
|
morse.lengthInElements = 1;
|
|
}
|
|
break;
|
|
|
|
case 'F':
|
|
{
|
|
morse.pattern = 0x04; /* 0000 0100; */
|
|
morse.lengthInSymbols = 4;
|
|
morse.lengthInElements = 9;
|
|
}
|
|
break;
|
|
|
|
case 'G':
|
|
{
|
|
morse.pattern = 0x03; /* 0000 0011; */
|
|
morse.lengthInSymbols = 3;
|
|
morse.lengthInElements = 9;
|
|
}
|
|
break;
|
|
|
|
case 'H':
|
|
{
|
|
morse.pattern = 0x00; /* 0000 0000; */
|
|
morse.lengthInSymbols = 4;
|
|
morse.lengthInElements = 7;
|
|
}
|
|
break;
|
|
|
|
case 'I':
|
|
{
|
|
morse.pattern = 0x00; /* 0000 0000; */
|
|
morse.lengthInSymbols = 2;
|
|
morse.lengthInElements = 3;
|
|
}
|
|
break;
|
|
|
|
case 'J':
|
|
{
|
|
morse.pattern = 0x0e; /* 0000 1110; */
|
|
morse.lengthInSymbols = 4;
|
|
morse.lengthInElements = 13;
|
|
}
|
|
break;
|
|
|
|
case 'K':
|
|
{
|
|
morse.pattern = 0x05; /* 0000 0101; */
|
|
morse.lengthInSymbols = 3;
|
|
morse.lengthInElements = 9;
|
|
}
|
|
break;
|
|
|
|
case 'L':
|
|
{
|
|
morse.pattern = 0x02; /* 0000 0010; */
|
|
morse.lengthInSymbols = 4;
|
|
morse.lengthInElements = 9;
|
|
}
|
|
break;
|
|
|
|
case 'M':
|
|
{
|
|
morse.pattern = 0x03; /* 0000 0011; */
|
|
morse.lengthInSymbols = 2;
|
|
morse.lengthInElements = 7;
|
|
}
|
|
break;
|
|
|
|
case 'N':
|
|
{
|
|
morse.pattern = 0x01; /* 0000 0001; */
|
|
morse.lengthInSymbols = 2;
|
|
morse.lengthInElements = 5;
|
|
}
|
|
break;
|
|
|
|
case 'O':
|
|
{
|
|
morse.pattern = 0x07; /* 0000 0111; */
|
|
morse.lengthInSymbols = 3;
|
|
morse.lengthInElements = 11;
|
|
}
|
|
break;
|
|
|
|
case 'P':
|
|
{
|
|
morse.pattern = 0x06; /* 0000 0110; */
|
|
morse.lengthInSymbols = 4;
|
|
morse.lengthInElements = 11;
|
|
}
|
|
break;
|
|
|
|
case 'Q':
|
|
{
|
|
morse.pattern = 0x0b; /* 0000 1011; */
|
|
morse.lengthInSymbols = 4;
|
|
morse.lengthInElements = 13;
|
|
}
|
|
break;
|
|
|
|
case 'R':
|
|
{
|
|
morse.pattern = 0x02; /* 0000 0010; */
|
|
morse.lengthInSymbols = 3;
|
|
morse.lengthInElements = 7;
|
|
}
|
|
break;
|
|
|
|
case 'S':
|
|
{
|
|
morse.pattern = 0x00; /* 0000 0000; */
|
|
morse.lengthInSymbols = 3;
|
|
morse.lengthInElements = 5;
|
|
}
|
|
break;
|
|
|
|
case 'T':
|
|
{
|
|
morse.pattern = 0x01; /* 0000 0001; */
|
|
morse.lengthInSymbols = 1;
|
|
morse.lengthInElements = 3;
|
|
}
|
|
break;
|
|
|
|
case 'U':
|
|
{
|
|
morse.pattern = 0x04; /* 0000 0100; */
|
|
morse.lengthInSymbols = 3;
|
|
morse.lengthInElements = 7;
|
|
}
|
|
break;
|
|
|
|
case 'V':
|
|
{
|
|
morse.pattern = 0x08; /* 0000 1000; */
|
|
morse.lengthInSymbols = 4;
|
|
morse.lengthInElements = 9;
|
|
}
|
|
break;
|
|
|
|
case 'W':
|
|
{
|
|
morse.pattern = 0x06; /* 0000 0110; */
|
|
morse.lengthInSymbols = 3;
|
|
morse.lengthInElements = 9;
|
|
}
|
|
break;
|
|
|
|
case 'X':
|
|
{
|
|
morse.pattern = 0x09; /* 0000 1001; */
|
|
morse.lengthInSymbols = 4;
|
|
morse.lengthInElements = 11;
|
|
}
|
|
break;
|
|
|
|
case 'Y':
|
|
{
|
|
morse.pattern = 0x0d; /* 0000 1101; */
|
|
morse.lengthInSymbols = 4;
|
|
morse.lengthInElements = 13;
|
|
}
|
|
break;
|
|
|
|
case 'Z':
|
|
{
|
|
morse.pattern = 0x03; /* 0000 0011; */
|
|
morse.lengthInSymbols = 4;
|
|
morse.lengthInElements = 11;
|
|
}
|
|
break;
|
|
|
|
case '0':
|
|
{
|
|
morse.pattern = 0x1f; /* 0001 1111; */
|
|
morse.lengthInSymbols = 5;
|
|
morse.lengthInElements = 19;
|
|
}
|
|
break;
|
|
|
|
case '1':
|
|
{
|
|
morse.pattern = 0x1e; /* 0001 1110; */
|
|
morse.lengthInSymbols = 5;
|
|
morse.lengthInElements = 17;
|
|
}
|
|
break;
|
|
|
|
case '2':
|
|
{
|
|
morse.pattern = 0x1c; /* 0001 1100; */
|
|
morse.lengthInSymbols = 5;
|
|
morse.lengthInElements = 15;
|
|
}
|
|
break;
|
|
|
|
case '3':
|
|
{
|
|
morse.pattern = 0x18; /* 0001 1000; */
|
|
morse.lengthInSymbols = 5;
|
|
morse.lengthInElements = 13;
|
|
}
|
|
break;
|
|
|
|
case '4':
|
|
{
|
|
morse.pattern = 0x10; /* 0001 0000; */
|
|
morse.lengthInSymbols = 5;
|
|
morse.lengthInElements = 11;
|
|
}
|
|
break;
|
|
|
|
case '5':
|
|
{
|
|
morse.pattern = 0x00; /* 0000 0000; */
|
|
morse.lengthInSymbols = 5;
|
|
morse.lengthInElements = 9;
|
|
}
|
|
break;
|
|
|
|
case '6':
|
|
{
|
|
morse.pattern = 0x01; /* 0000 0001; */
|
|
morse.lengthInSymbols = 5;
|
|
morse.lengthInElements = 11;
|
|
}
|
|
break;
|
|
|
|
case '7':
|
|
{
|
|
morse.pattern = 0x03; /* 0000 0011; */
|
|
morse.lengthInSymbols = 5;
|
|
morse.lengthInElements = 13;
|
|
}
|
|
break;
|
|
|
|
case '8':
|
|
{
|
|
morse.pattern = 0x07; /* 0000 0111; */
|
|
morse.lengthInSymbols = 5;
|
|
morse.lengthInElements = 15;
|
|
}
|
|
break;
|
|
|
|
case '9':
|
|
{
|
|
morse.pattern = 0x0f; /* 0000 1111; */
|
|
morse.lengthInSymbols = 5;
|
|
morse.lengthInElements = 17;
|
|
}
|
|
break;
|
|
|
|
case '.':
|
|
{
|
|
morse.pattern = 0x2a; /* 0010 1010; */
|
|
morse.lengthInSymbols = 6;
|
|
morse.lengthInElements = 17;
|
|
}
|
|
break;
|
|
|
|
case ',':
|
|
{
|
|
morse.pattern = 0x33; /* 0011 0011; */
|
|
morse.lengthInSymbols = 6;
|
|
morse.lengthInElements = 19;
|
|
}
|
|
break;
|
|
|
|
case '?':
|
|
{
|
|
morse.pattern = 0x0c; /* 0000 1100; */
|
|
morse.lengthInSymbols = 6;
|
|
morse.lengthInElements = 15;
|
|
}
|
|
break;
|
|
|
|
case '\'':
|
|
{
|
|
morse.pattern = 0x1e; /* 0001 1110; */
|
|
morse.lengthInSymbols = 6;
|
|
morse.lengthInElements = 19;
|
|
}
|
|
break;
|
|
|
|
case '!':
|
|
{
|
|
morse.pattern = 0x35; /* 0011 0101; */
|
|
morse.lengthInSymbols = 6;
|
|
morse.lengthInElements = 19;
|
|
}
|
|
break;
|
|
|
|
case '/':
|
|
{
|
|
morse.pattern = 0x09; /* 0000 1001; */
|
|
morse.lengthInSymbols = 5;
|
|
morse.lengthInElements = 13;
|
|
}
|
|
break;
|
|
|
|
case '(':
|
|
{
|
|
morse.pattern = 0x0d; /* 0000 1101; */
|
|
morse.lengthInSymbols = 5;
|
|
morse.lengthInElements = 15;
|
|
}
|
|
break;
|
|
|
|
case ')':
|
|
{
|
|
morse.pattern = 0x2d; /* 0010 1101; */
|
|
morse.lengthInSymbols = 6;
|
|
morse.lengthInElements = 19;
|
|
}
|
|
break;
|
|
|
|
case '&':
|
|
{
|
|
morse.pattern = 0x02; /* 0000 0010; */
|
|
morse.lengthInSymbols = 5;
|
|
morse.lengthInElements = 11;
|
|
}
|
|
break;
|
|
|
|
case ':':
|
|
{
|
|
morse.pattern = 0x07; /* 0000 0111; */
|
|
morse.lengthInSymbols = 6;
|
|
morse.lengthInElements = 17;
|
|
}
|
|
break;
|
|
|
|
case ';':
|
|
{
|
|
morse.pattern = 0x15; /* 0001 0101; */
|
|
morse.lengthInSymbols = 6;
|
|
morse.lengthInElements = 12;
|
|
}
|
|
break;
|
|
|
|
case '=':
|
|
{
|
|
morse.pattern = 0x11; /* 0001 0001; */
|
|
morse.lengthInSymbols = 5;
|
|
morse.lengthInElements = 13;
|
|
}
|
|
break;
|
|
|
|
case '+':
|
|
{
|
|
morse.pattern = 0x0a; /* 0000 1010; */
|
|
morse.lengthInSymbols = 5;
|
|
morse.lengthInElements = 13;
|
|
}
|
|
break;
|
|
|
|
case '-':
|
|
{
|
|
morse.pattern = 0x21; /* 0010 0001; */
|
|
morse.lengthInSymbols = 6;
|
|
morse.lengthInElements = 15;
|
|
}
|
|
break;
|
|
|
|
case '_':
|
|
{
|
|
morse.pattern = 0x2c; /* 0010 1100; */
|
|
morse.lengthInSymbols = 6;
|
|
morse.lengthInElements = 17;
|
|
}
|
|
break;
|
|
|
|
case '"':
|
|
{
|
|
morse.pattern = 0x12; /* 0001 0010; */
|
|
morse.lengthInSymbols = 6;
|
|
morse.lengthInElements = 15;
|
|
}
|
|
break;
|
|
|
|
case '$':
|
|
{
|
|
morse.pattern = 0x48; /* 0100 1000; */
|
|
morse.lengthInSymbols = 7;
|
|
morse.lengthInElements = 17;
|
|
}
|
|
break;
|
|
|
|
case '@':
|
|
{
|
|
morse.pattern = 0x16; /* 0001 0110; */
|
|
morse.lengthInSymbols = 6;
|
|
morse.lengthInElements = 17;
|
|
}
|
|
break;
|
|
|
|
case '|': /* inter-word space */
|
|
{ morse.pattern = 0xff; /* 1000 0000; */
|
|
morse.lengthInSymbols = 7;
|
|
morse.lengthInElements = 4; /* adjusted by -3 to account for inter-character space */
|
|
}
|
|
break;
|
|
|
|
case ' ': /* inter-word space */
|
|
{ morse.pattern = 0xfe; /* 1000 0000; */
|
|
morse.lengthInSymbols = 7;
|
|
morse.lengthInElements = 7; /* 4 + 3 (character space) = 7 */
|
|
}
|
|
break;
|
|
|
|
case '<': /* long keydown */
|
|
{
|
|
morse.pattern = 0x1f; /* 0001 1111; */
|
|
morse.lengthInSymbols = 5;
|
|
morse.lengthInElements = 19;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
morse.pattern = 0x0000; /* 0000 0000; */
|
|
morse.lengthInSymbols = 0;
|
|
morse.lengthInElements = 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return( morse);
|
|
}
|
|
|