OpenARDF-WB8WFK-ARDF-Foxori.../Arduino-microfox/morse.cpp

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);
}