CW Extended char set

* update to CW decoder to provide encode and
    decode a subset of extended UTF-8 characters.
This commit is contained in:
David Freese 2017-05-24 06:56:16 -05:00
parent ad8e33ead4
commit c2c9f38de1
11 changed files with 857 additions and 382 deletions

View file

@ -62,70 +62,80 @@ using namespace std;
const cw::SOM_TABLE cw::som_table[] = {
/* Prosigns */
{'=', "<BT>", {1.0, 0.33, 0.33, 0.33, 1.0, 0, 0} }, // 0
{'~', "<AA>", { 0.33, 1.0, 0.33, 1.0, 0, 0, 0} }, // 1
{'%', "<AS>", { 0.33, 1.0, 0.33, 0.33, 0.33, 0, 0} }, // 2
{'+', "<AR>", { 0.33, 1.0, 0.33, 1.0, 0.33, 0, 0} }, // 3
{'>', "<SK>", { 0.33, 0.33, 0.33, 1.0, 0.33, 1.0, 0} }, // 4
{'<', "<KN>", {1.0, 0.33, 1.0, 1.0, 0.33, 0, 0} }, // 5
{'&', "<INT>", { 0.33, 0.33, 1.0, 0.33, 1.0, 0, 0} }, // 6
{'}', "<HM>", { 0.33, 0.33, 0.33, 0.33, 1.0, 1.0, 0} }, // 7
{'{', "<VE>", { 0.33, 0.33, 0.33, 1.0, 0.33, 0, 0} }, // 8
{"-...-", {1.0, 0.33, 0.33, 0.33, 1.0, 0, 0} },
{".-.-", { 0.33, 1.0, 0.33, 1.0, 0, 0, 0} },
{".-...", { 0.33, 1.0, 0.33, 0.33, 0.33, 0, 0} },
{".-.-.", { 0.33, 1.0, 0.33, 1.0, 0.33, 0, 0} },
{"...-.-", { 0.33, 0.33, 0.33, 1.0, 0.33, 1.0, 0} },
{"-.--.", {1.0, 0.33, 1.0, 1.0, 0.33, 0, 0} },
{"..-.-", { 0.33, 0.33, 1.0, 0.33, 1.0, 0, 0} },
{"....--", { 0.33, 0.33, 0.33, 0.33, 1.0, 1.0, 0} },
{"...-.", { 0.33, 0.33, 0.33, 1.0, 0.33, 0, 0} },
/* ASCII 7bit letters */
{'A', "A", { 0.33, 1.0, 0, 0, 0, 0, 0} },
{'B', "B", {1.0, 0.33, 0.33, 0.33, 0, 0, 0} },
{'C', "C", {1.0, 0.33, 1.0, 0.33, 0, 0, 0} },
{'D', "D", {1.0, 0.33, 0.33, 0, 0, 0, 0} },
{'E', "E", { 0.33, 0, 0, 0, 0, 0, 0} },
{'F', "F", { 0.33, 0.33, 1.0, 0.33, 0, 0, 0} },
{'G', "G", {1.0, 1.0, 0.33, 0, 0, 0, 0} },
{'H', "H", { 0.33, 0.33, 0.33, 0.33, 0, 0, 0} },
{'I', "I", { 0.33, 0.33, 0, 0, 0, 0, 0} },
{'J', "J", { 0.33, 1.0, 1.0, 1.0, 0, 0, 0} },
{'K', "K", {1.0, 0.33, 1.0, 0, 0, 0, 0} },
{'L', "L", { 0.33, 1.0, 0.33, 0.33, 0, 0, 0} },
{'M', "M", {1.0, 1.0, 0, 0, 0, 0, 0} },
{'N', "N", {1.0, 0.33, 0, 0, 0, 0, 0} },
{'O', "O", {1.0, 1.0, 1.0, 0, 0, 0, 0} },
{'P', "P", { 0.33, 1.0, 1.0, 0.33, 0, 0, 0} },
{'Q', "Q", {1.0, 1.0, 0.33, 1.0, 0, 0, 0} },
{'R', "R", { 0.33, 1.0, 0.33, 0, 0, 0, 0} },
{'S', "S", { 0.33, 0.33, 0.33, 0, 0, 0, 0} },
{'T', "T", {1.0, 0, 0, 0, 0, 0, 0} },
{'U', "U", { 0.33, 0.33, 1.0, 0, 0, 0, 0} },
{'V', "V", { 0.33, 0.33, 0.33, 1.0, 0, 0, 0} },
{'W', "W", { 0.33, 1.0, 1.0, 0, 0, 0, 0} },
{'X', "X", {1.0, 0.33, 0.33, 1.0, 0, 0, 0} },
{'Y', "Y", {1.0, 0.33, 1.0, 1.0, 0, 0, 0} },
{'Z', "Z", {1.0, 1.0, 0.33, 0.33, 0, 0, 0} },
{".-", { 0.33, 1.0, 0, 0, 0, 0, 0} },
{"-...", {1.0, 0.33, 0.33, 0.33, 0, 0, 0} },
{"-.-.", {1.0, 0.33, 1.0, 0.33, 0, 0, 0} },
{"-..", {1.0, 0.33, 0.33, 0, 0, 0, 0} },
{".", { 0.33, 0, 0, 0, 0, 0, 0} },
{"..-.", { 0.33, 0.33, 1.0, 0.33, 0, 0, 0} },
{"--.", {1.0, 1.0, 0.33, 0, 0, 0, 0} },
{"....", { 0.33, 0.33, 0.33, 0.33, 0, 0, 0} },
{"..", { 0.33, 0.33, 0, 0, 0, 0, 0} },
{".---J", { 0.33, 1.0, 1.0, 1.0, 0, 0, 0} },
{"-.-", {1.0, 0.33, 1.0, 0, 0, 0, 0} },
{".-..", { 0.33, 1.0, 0.33, 0.33, 0, 0, 0} },
{"--", {1.0, 1.0, 0, 0, 0, 0, 0} },
{"-.", {1.0, 0.33, 0, 0, 0, 0, 0} },
{"---", {1.0, 1.0, 1.0, 0, 0, 0, 0} },
{".--.", { 0.33, 1.0, 1.0, 0.33, 0, 0, 0} },
{"--.-", {1.0, 1.0, 0.33, 1.0, 0, 0, 0} },
{".-.", { 0.33, 1.0, 0.33, 0, 0, 0, 0} },
{"...", { 0.33, 0.33, 0.33, 0, 0, 0, 0} },
{"-", {1.0, 0, 0, 0, 0, 0, 0} },
{"..-", { 0.33, 0.33, 1.0, 0, 0, 0, 0} },
{"...-", { 0.33, 0.33, 0.33, 1.0, 0, 0, 0} },
{".--", { 0.33, 1.0, 1.0, 0, 0, 0, 0} },
{"-..-", {1.0, 0.33, 0.33, 1.0, 0, 0, 0} },
{"-.--", {1.0, 0.33, 1.0, 1.0, 0, 0, 0} },
{"--..", {1.0, 1.0, 0.33, 0.33, 0, 0, 0} },
/* Numerals */
{'0', "0", {1.0, 1.0, 1.0, 1.0, 1.0, 0, 0} },
{'1', "1", { 0.33, 1.0, 1.0, 1.0, 1.0, 0, 0} },
{'2', "2", { 0.33, 0.33, 1.0, 1.0, 1.0, 0, 0} },
{'3', "3", { 0.33, 0.33, 0.33, 1.0, 1.0, 0, 0} },
{'4', "4", { 0.33, 0.33, 0.33, 0.33, 1.0, 0, 0} },
{'5', "5", { 0.33, 0.33, 0.33, 0.33, 0.33, 0, 0} },
{'6', "6", {1.0, 0.33, 0.33, 0.33, 0.33, 0, 0} },
{'7', "7", {1.0, 1.0, 0.33, 0.33, 0.33, 0, 0} },
{'8', "8", {1.0, 1.0, 1.0, 0.33, 0.33, 0, 0} },
{'9', "9", {1.0, 1.0, 1.0, 1.0, 0.33, 0, 0} },
{"-----", {1.0, 1.0, 1.0, 1.0, 1.0, 0, 0} },
{".----", { 0.33, 1.0, 1.0, 1.0, 1.0, 0, 0} },
{"..---", { 0.33, 0.33, 1.0, 1.0, 1.0, 0, 0} },
{"...--", { 0.33, 0.33, 0.33, 1.0, 1.0, 0, 0} },
{"....-", { 0.33, 0.33, 0.33, 0.33, 1.0, 0, 0} },
{".....", { 0.33, 0.33, 0.33, 0.33, 0.33, 0, 0} },
{"-....", {1.0, 0.33, 0.33, 0.33, 0.33, 0, 0} },
{"--...", {1.0, 1.0, 0.33, 0.33, 0.33, 0, 0} },
{"---..", {1.0, 1.0, 1.0, 0.33, 0.33, 0, 0} },
{"----.", {1.0, 1.0, 1.0, 1.0, 0.33, 0, 0} },
/* Punctuation */
{'\\', "\\", { 0.33, 1.0, 0.33, 0.33, 1.0, 0.33, 0} },
{'\'', "'", { 0.33, 1.0, 1.0, 1.0, 1.0, 0.33, 0} },
{'$', "$", { 0.33, 0.33, 0.33, 1.0, 0.33, 0.33,1.0} },
{'(', "(", {1.0, 0.33, 1.0, 1.0, 0.33, 0, 0} },
{')', ")", {1.0, 0.33, 1.0, 1.0, 0.33, 1.0, 0} },
{',', ",", {1.0, 1.0, 0.33, 0.33, 1.0, 1.0, 0} },
{'-', "-", {1.0, 0.33, 0.33, 0.33, 0.33, 1.0, 0} },
{'.', ".", { 0.33, 1.0, 0.33, 1.0, 0.33, 1.0, 0} },
{'/', "/", {1.0, 0.33, 0.33, 1.0, 0.33, 0, 0} },
{':', ":", {1.0, 1.0, 1.0, 0.33, 0.33, 0.33, 0} },
{';', ";", {1.0, 0.33, 1.0, 0.33, 1.0, 0.33, 0} },
{'?', "?", { 0.33, 0.33, 1.0, 1.0, 0.33, 0.33, 0} },
{'_', "_", { 0.33, 0.33, 1.0, 1.0, 0.33, 1.0, 0} },
{'@', "@", { 0.33, 1.0, 1.0, 0.33, 1.0, 0.33, 0} },
{'!', "!", {1.0, 0.33, 1.0, 0.33, 1.0, 1.0, 0} },
{0, NULL, {0.0}}
{".-..-.", { 0.33, 1.0, 0.33, 0.33, 1.0, 0.33, 0} },
{".----.", { 0.33, 1.0, 1.0, 1.0, 1.0, 0.33, 0} },
{"...-..-", { 0.33, 0.33, 0.33, 1.0, 0.33, 0.33, 1.0} },
{"-.---.", {1.0, 0.33, 1.0, 1.0, 0.33, 0, 0} },
{"-.--.-", {1.0, 0.33, 1.0, 1.0, 0.33, 1.0, 0} },
{"--..--", {1.0, 1.0, 0.33, 0.33, 1.0, 1.0, 0} },
{"-....-", {1.0, 0.33, 0.33, 0.33, 0.33, 1.0, 0} },
{".-.-.-", { 0.33, 1.0, 0.33, 1.0, 0.33, 1.0, 0} },
{"-..-.", {1.0, 0.33, 0.33, 1.0, 0.33, 0, 0} },
{"---...", {1.0, 1.0, 1.0, 0.33, 0.33, 0.33, 0} },
{"-.-.-.", {1.0, 0.33, 1.0, 0.33, 1.0, 0.33, 0} },
{"..--..", { 0.33, 0.33, 1.0, 1.0, 0.33, 0.33, 0} },
{"..--.-", { 0.33, 0.33, 1.0, 1.0, 0.33, 1.0, 0} },
{".--.-.", { 0.33, 1.0, 1.0, 0.33, 1.0, 0.33, 0} },
{"-.-.--", {1.0, 0.33, 1.0, 0.33, 1.0, 1.0, 0} },
{".-.-", {0.33, 1.0, 0.33, 1.0, 0, 0 , 0} }, // A umlaut, A aelig
{".--.-", {0.33, 1.0, 1.0, 0.33, 1.0, 0, 0 } }, // A ring
{"-.-..", {1.0, 0.33, 1.0, 0.33, 0.33, 0, 0} }, // C cedilla
{".-..-", {0.33, 1.0, 0.33, 0.33, 1.0, 0, 0} }, // E grave
{"..-..", {0.33, 0.33, 1.0, 0.33, 0.33, 0, 0} }, // E acute
{"---.", {1.0, 1.0, 1.0, 0.33, 0, 0, 0} }, // O acute, O umlat, O slash
{"--.--", {1.0, 1.0, 0.33, 1.0, 1.0, 0, 0} }, // N tilde
{"..--", {0.33, 0.33, 1.0, 1.0, 0, 0, 0} }, // U umlaut, U circ
{"", {0.0}}
};
int cw::normalize(float *v, int n, int twodots)
@ -153,33 +163,35 @@ int cw::normalize(float *v, int n, int twodots)
}
const char * cw::find_winner (float *inbuf, int twodots)
std::string cw::find_winner (float *inbuf, int twodots)
{
float diffsf = 999999999999.0;
if ( normalize (inbuf, WGT_SIZE, twodots) == 0) return NULL;
if ( normalize (inbuf, WGT_SIZE, twodots) == 0) return " ";
const SOM_TABLE * winner = NULL;
for ( const SOM_TABLE * som = som_table; som->chr != 0; som++) {
int winner = -1;
for ( int n = 0; som_table[n].rpr.length(); n++) {
/* Compute the distance between codebook and input entry */
float difference = 0.0;
for (int i = 0; i < WGT_SIZE; i++) {
float diff = (inbuf[i] - som->wgt[i]);
float diff = (inbuf[i] - som_table[n].wgt[i]);
difference += diff * diff;
if (difference > diffsf) break;
}
/* If distance is smaller than previous distances */
if (difference < diffsf) {
winner = som;
winner = n;
diffsf = difference;
}
}
if (winner != NULL)
return winner->prt;
else
return NULL;
if (!som_table[winner].rpr.empty()) {
string sc = morse.rx_lookup(som_table[winner].rpr);
if (sc.empty()) return "*";
else return sc;
} else
return "*";
}
void cw::tx_init()
@ -548,8 +560,8 @@ cmplx cw::mixer(cmplx in)
void cw::decode_stream(double value)
{
const char *c, *somc;
char *cptr;
std::string sc;
std::string somc;
sig_avg = decayavg(sig_avg, value, 1000);
@ -591,33 +603,31 @@ void cw::decode_stream(double value)
// Power detection using hysterisis detector
// upward trend means tone starting
if ((value > progdefaults.CWupper) && (cw_receive_state != RS_IN_TONE)) {
handle_event(CW_KEYDOWN_EVENT, NULL);
handle_event(CW_KEYDOWN_EVENT, sc);
}
// downward trend means tone stopping
if ((value < progdefaults.CWlower) && (cw_receive_state == RS_IN_TONE)) {
handle_event(CW_KEYUP_EVENT, NULL);
handle_event(CW_KEYUP_EVENT, sc);
}
}
if (handle_event(CW_QUERY_EVENT, &c) == CW_SUCCESS) {
if (handle_event(CW_QUERY_EVENT, sc) == CW_SUCCESS) {
update_syncscope();
synchscope = 100;
if (progdefaults.CWuseSOMdecoding) {
somc = find_winner(cw_buffer, two_dots);
cptr = (char*)somc;
if (somc != NULL) {
while (*cptr != '\0')
put_rx_char(progdefaults.rx_lowercase ? tolower(*cptr++) : *cptr++,FTextBase::CTRL);
}
if (strlen(c) == 1 && *c == ' ')
put_rx_char(progdefaults.rx_lowercase ? tolower(*c) : *c);
if (!somc.empty())
for (size_t n = 0; n < somc.length(); n++)
put_echo_char(
somc[n],
somc[0] == '<' ? FTextBase::CTRL : FTextBase::RECV);
cw_ptr = 0;
memset(cw_buffer, 0, sizeof(cw_buffer));
} else {
if (strlen(c) == 1)
put_rx_char(progdefaults.rx_lowercase ? tolower(*c) : *c);
else while (*c)
put_rx_char(progdefaults.rx_lowercase ? tolower(*c++) : *c++, FTextBase::CTRL);
for (size_t n = 0; n < sc.length(); n++)
put_echo_char(
sc[n],
sc[0] == '<' ? FTextBase::CTRL : FTextBase::RECV);
}
} else if (--synchscope == 0) {
synchscope = 25;
@ -707,7 +717,7 @@ inline int cw::usec_diff(unsigned int earlier, unsigned int later)
// If there is no data ready, CW_ERROR is returned.
//=======================================================================
int cw::handle_event(int cw_event, const char **c)
int cw::handle_event(int cw_event, string &sc)
{
static int space_sent = true; // for word space logic
static int last_element = 0; // length of last dot/dash
@ -815,15 +825,6 @@ int cw::handle_event(int cw_event, const char **c)
// CW_SUCCESS is returned when there is a printable character. Nothing to do if we are in a tone
if (cw_receive_state == RS_IN_TONE)
return CW_ERROR;
// in this call we expect a pointer to a char to be valid
if (c == NULL) {
// else we had no place to put character...
cw_receive_state = RS_IDLE;
cw_rr_current = 0;
cw_ptr = 0;
// reset decoding pointer
return CW_ERROR;
}
// compute length of silence so far
sync_parameters();
element_usec = usec_diff(cw_rr_end_timestamp, smpl_ctr);
@ -837,11 +838,10 @@ int cw::handle_event(int cw_event, const char **c)
element_usec <= (4 * cw_receive_dot_length) &&
cw_receive_state == RS_AFTER_TONE) {
// Look up the representation
*c = morse.rx_lookup(rx_rep_buf.c_str());
//cout <<": " << *c <<flush;
if (*c == NULL) {
sc = morse.rx_lookup(rx_rep_buf);
if (sc.empty()) {
// invalid decode... let user see error
*c = "*";
sc = "*";
}
rx_rep_buf.clear();
cw_receive_state = RS_IDLE;
@ -854,7 +854,7 @@ int cw::handle_event(int cw_event, const char **c)
// LONG time since keyup... check for a word space
// FARNSWOTH MOD HERE -->
if ((element_usec > (4 * cw_receive_dot_length)) && !space_sent) {
*c = " ";
sc = " ";
space_sent = true;
return CW_SUCCESS;
}
@ -872,11 +872,11 @@ int cw::handle_event(int cw_event, const char **c)
// this is 1/2 cycle of a raised cosine
//===========================================================================
double keyshape[KNUM];
double keyshape[CWKNUM];
void cw::makeshape()
{
for (int i = 0; i < KNUM; i++) keyshape[i] = 1.0;
for (int i = 0; i < CWKNUM; i++) keyshape[i] = 1.0;
switch (QSKshape) {
case 1: // blackman
@ -1160,7 +1160,7 @@ void cw::send_symbol(int bits, int len)
void cw::send_ch(int ch)
{
int code;
string code;
int chout = ch;
int flen;
@ -1180,29 +1180,44 @@ void cw::send_ch(int ch)
return;
}
// convert character code to a morse representation
if ((chout < 256) && (chout >= 0)) {
code = morse.tx_lookup(chout); //cw_tx_lookup(ch);
firstelement = true;
} else {
code = 0x04; // two extra dot spaces
firstelement = false;
}
// loop sending out binary bits of cw character at WPM or Farnsworth rate
// loop sending out binary bits of cw character
// at WPM or Farnsworth rate
if (progdefaults.CWusefarnsworth && (progdefaults.CWspeed <= progdefaults.CWfarnsworth))
flen = fsymlen;
else
flen = symbollen;
int charlen = 0;
while (code > 1) {
send_symbol(code, flen);
charlen++;
code = code >> 1;
int charlen = 0; // used for Farsnworth timing adjustment
if (chout <= 0) {
send_symbol(0, flen);
send_symbol(0, flen);
firstelement = false;
return;
}
code = morse.tx_lookup(chout);
if (!code.length()) {
return;
}
firstelement = true;
// while (code.length()) {
for (size_t n = 0; n < code.length(); n++) {
send_symbol(0, flen);
send_symbol(1, flen);
charlen += 2;
if (code[n] == '-') {
send_symbol( 1, flen );
send_symbol( 1, flen );
charlen += 2;
}
}
send_symbol(0, flen);
send_symbol(0, flen);
charlen += 2;
// inter character space at WPM/FWPM rate
flen = symbollen;
if (progdefaults.CWusefarnsworth && (progdefaults.CWspeed <= progdefaults.CWfarnsworth))
@ -1214,15 +1229,12 @@ void cw::send_ch(int ch)
}
if (flen) send_symbol(0, flen);
FL_AWAKE();
if (ch != -1) {
string prtstr = morse.tx_print(ch);
if (prtstr.length() == 1)
put_echo_char(progdefaults.rx_lowercase ? tolower(prtstr[0]) : prtstr[0]);
else
for (size_t n = 0; n < prtstr.length(); n++)
put_echo_char(progdefaults.rx_lowercase ? tolower(prtstr[n]) : prtstr[n], FTextBase::CTRL);
string prtstr = morse.tx_print();
for (size_t n = 0; n < prtstr.length(); n++)
put_echo_char(
prtstr[n],
prtstr[0] == '<' ? FTextBase::CTRL : FTextBase::XMIT);
}
}
@ -1274,6 +1286,7 @@ int cw::tx_process()
}
acc_symbols = 0;
send_ch(c);
FL_AWAKE();
xmt_samples = char_samples = acc_symbols;

View file

@ -1,15 +1,7 @@
/*
* morse.c -- morse code tables
*
* Copyright (C) 2004
* Lawrence Glaister (ve7it@shaw.ca)
* This modem borrowed heavily from other gmfsk modems and
* also from the unix-cw project. I would like to thank those
* authors for enriching my coding experience by providing
* and supporting open source.
*
* This file is part of fldigi. Copied from the gMFSK source code
* distribution.
* Copyright (C) 2017
*
* Fldigi is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -38,223 +30,241 @@
/*
* Morse code characters table. This table allows lookup of the Morse
* shape of a given alphanumeric character. Shapes are held as a string,
* with '-' representing dash, and '.' representing dot. The table ends
* with "-' representing dash, and ".' representing dot. The table ends
* with a NULL entry.
*
* This is the main table from which the other tables are computed.
*
*
* The Prosigns are also defined in the configuration.h file
* The user can specify the character which substitutes for the prosign
*/
static CW_TABLE cw_table[] = {
/* Prosigns */
{'=', "<BT>", "-...-" }, // 0
{'~', "<AA>", ".-.-" }, // 1
{'<', "<AS>", ".-..." }, // 2
{'>', "<AR>", ".-.-." }, // 3
{'%', "<SK>", "...-.-" }, // 4
{'+', "<KN>", "-.--." }, // 5
{'&', "<INT>", "..-.-" }, // 6
{'{', "<HM>", "....--" }, // 7
{'}', "<VE>", "...-." }, // 8
/* ASCII 7bit letters */
{'A', "A", ".-" },
{'B', "B", "-..." },
{'C', "C", "-.-." },
{'D', "D", "-.." },
{'E', "E", "." },
{'F', "F", "..-." },
{'G', "G", "--." },
{'H', "H", "...." },
{'I', "I", ".." },
{'J', "J", ".---" },
{'K', "K", "-.-" },
{'L', "L", ".-.." },
{'M', "M", "--" },
{'N', "N", "-." },
{'O', "O", "---" },
{'P', "P", ".--." },
{'Q', "Q", "--.-" },
{'R', "R", ".-." },
{'S', "S", "..." },
{'T', "T", "-" },
{'U', "U", "..-" },
{'V', "V", "...-" },
{'W', "W", ".--" },
{'X', "X", "-..-" },
{'Y', "Y", "-.--" },
{'Z', "Z", "--.." },
/* Numerals */
{'0', "0", "-----" },
{'1', "1", ".----" },
{'2', "2", "..---" },
{'3', "3", "...--" },
{'4', "4", "....-" },
{'5', "5", "....." },
{'6', "6", "-...." },
{'7', "7", "--..." },
{'8', "8", "---.." },
{'9', "9", "----." },
/* Punctuation */
{'\\', "\\", ".-..-." },
{'\'', "'", ".----." },
{'$', "$", "...-..-" },
{'(', "(", "-.--." },
{')', ")", "-.--.-" },
{',', ",", "--..--" },
{'-', "-", "-....-" },
{'.', ".", ".-.-.-" },
{'/', "/", "-..-." },
{':', ":", "---..." },
{';', ";", "-.-.-." },
{'?', "?", "..--.." },
{'_', "_", "..--.-" },
{'@', "@", ".--.-." },
{'!', "!", "-.-.--" },
{0, NULL, NULL}
bool CW_table_changed = false;
CWstruct cMorse::cw_table[] = {
// Prosigns
{1, "=", "<BT>", "-...-" }, // 0
{0, "~", "<AA>", ".-.-" }, // 1
{1, "<", "<AS>", ".-..." }, // 2
{1, ">", "<AR>", ".-.-." }, // 3
{1, "%", "<SK>", "...-.-" }, // 4
{1, "+", "<KN>", "-.--." }, // 5
{1, "&", "<INT>", "..-.-" }, // 6
{1, "{", "<HM>", "....--" }, // 7
{1, "}", "<VE>", "...-." }, // 8
// ASCII 7bit letters
{1, "A", "A", ".-" },
{1, "B", "B", "-..." },
{1, "C", "C", "-.-." },
{1, "D", "D", "-.." },
{1, "E", "E", "." },
{1, "F", "F", "..-." },
{1, "G", "G", "--." },
{1, "H", "H", "...." },
{1, "I", "I", ".." },
{1, "J", "J", ".---" },
{1, "K", "K", "-.-" },
{1, "L", "L", ".-.." },
{1, "M", "M", "--" },
{1, "N", "N", "-." },
{1, "O", "O", "---" },
{1, "P", "P", ".--." },
{1, "Q", "Q", "--.-" },
{1, "R", "R", ".-." },
{1, "S", "S", "..." },
{1, "T", "T", "-" },
{1, "U", "U", "..-" },
{1, "V", "V", "...-" },
{1, "W", "W", ".--" },
{1, "X", "X", "-..-" },
{1, "Y", "Y", "-.--" },
{1, "Z", "Z", "--.." },
//
{1, "a", "A", ".-" },
{1, "b", "B", "-..." },
{1, "c", "C", "-.-." },
{1, "d", "D", "-.." },
{1, "e", "E", "." },
{1, "f", "F", "..-." },
{1, "g", "G", "--." },
{1, "h", "H", "...." },
{1, "i", "I", ".." },
{1, "j", "J", ".---" },
{1, "k", "K", "-.-" },
{1, "l", "L", ".-.." },
{1, "m", "M", "--" },
{1, "n", "N", "-." },
{1, "o", "O", "---" },
{1, "p", "P", ".--." },
{1, "q", "Q", "--.-" },
{1, "r", "R", ".-." },
{1, "s", "S", "..." },
{1, "t", "T", "-" },
{1, "u", "U", "..-" },
{1, "v", "V", "...-" },
{1, "w", "W", ".--" },
{1, "x", "X", "-..-" },
{1, "y", "Y", "-.--" },
{1, "z", "Z", "--.." },
// Numerals
{1, "0", "0", "-----" },
{1, "1", "1", ".----" },
{1, "2", "2", "..---" },
{1, "3", "3", "...--" },
{1, "4", "4", "....-" },
{1, "5", "5", "....." },
{1, "6", "6", "-...." },
{1, "7", "7", "--..." },
{1, "8", "8", "---.." },
{1, "9", "9", "----." },
// Punctuation
{1, "\\", "\\", ".-..-." },
{1, "\'", "'", ".----." },
{1, "$", "$", "...-..-" },
{1, "(", "(", "-.--." },
{1, ")", ")", "-.--.-" },
{1, ",", ",", "--..--" },
{1, "-", "-", "-....-" },
{1, ".", ".", ".-.-.-" },
{1, "/", "/", "-..-." },
{1, ":", ":", "---..." },
{1, ";", ";", "-.-.-." },
{1, "?", "?", "..--.." },
{1, "_", "_", "..--.-" },
{1, "@", "@", ".--.-." },
{1, "!", "!", "-.-.--" },
// accented characters
{1, "Ä", "Ä", ".-.-" }, // A umlaut
{1, "ä", "Ä", ".-.-" }, // A umlaut
{0, "Æ", "Æ", ".-.-" }, // A aelig
{0, "æ", "Æ", ".-.-" }, // A aelig
{0, "Å", "Å", ".--.-" }, // A ring
{0, "å", "Å", ".--.-" }, // A ring
{1, "Ç", "Ç", "-.-.." }, // C cedilla
{1, "ç", "Ç", "-.-.." }, // C cedilla
{0, "È", "È", ".-..-" }, // E grave
{0, "è", "È", ".-..-" }, // E grave
{1, "É", "É", "..-.." }, // E acute
{1, "é", "É", "..-.." }, // E acute
{0, "Ó", "Ó", "---." }, // O acute
{0, "ó", "Ó", "---." }, // O acute
{1, "Ö", "Ö", "---." }, // O umlaut
{1, "ö", "Ö", "---." }, // O umlaut
{0, "Ø", "Ø", "---." }, // O slash
{0, "ø", "Ø", "---." }, // O slash
{1, "Ñ", "Ñ", "--.--" }, // N tilde
{1, "ñ", "Ñ", "--.--" }, // N tilde
{1, "Ü", "Ü", "..--" }, // U umlaut
{1, "ü", "Ü", "..--" }, // U umlaut
{0, "Û", "Û", "..--" }, // U circ
{0, "û", "Û", "..--" }, // U circ
// array termination
{0, "", "", ""}
};
// ISO 8859-1 accented characters
// {"\334\374", "\334\374", "..--"}, // U diaeresis
// {"\304\344", "\304\344", ".-.-"}, // A diaeresis
// {"\307\347", "\307\347", "-.-.."}, // C cedilla
// {"\326\366", "\325\366", "---."}, // O diaeresis
// {"\311\351", "\311\351", "..-.."}, // E acute
// {"\310\350", "\310\350",".-..-"}, // E grave
// {"\305\345", "\305\345", ".--.-"}, // A ring
// {"\321\361", "\321\361", "--.--"}, // N tilde
// ISO 8859-2 accented characters
// {"\252", "\252", "----" }, // S cedilla
// {"\256", "\256", "--..-"}, // Z dot above
/**
* cw_tokenize_representation()
*
* Return a token value, in the range 2-255, for a lookup table representation.
* The routine returns 0 if no valid token could be made from the string. To
* avoid casting the value a lot in the caller (we want to use it as an array
* index), we actually return an unsigned int.
*
* This token algorithm is designed ONLY for valid CW representations; that is,
* strings composed of only '.' and '-', and in this case, strings shorter than
* eight characters. The algorithm simply turns the representation into a
* 'bitmask', based on occurrences of '.' and '-'. The first bit set in the
* mask indicates the start of data (hence the 7-character limit). This mask
* is viewable as an integer in the range 2 (".") to 255 ("-------"), and can
* be used as an index into a fast lookup array.
*/
unsigned int cMorse::tokenize_representation(const char *representation)
{
unsigned int token; /* Return token value */
const char *sptr; /* Pointer through string */
/*
* Our algorithm can handle only 6 characters of representation.
* And we insist on there being at least one character, too.
*/
if (strlen(representation) > 6 || strlen(representation) < 1)
return 0;
/*
* Build up the token value based on the dots and dashes. Start the
* token at 1 - the sentinel (start) bit.
*/
for (sptr = representation, token = 1; *sptr != 0; sptr++) {
/*
* Left-shift the sentinel (start) bit.
*/
token <<= 1;
/*
* If the next element is a dash, OR in another bit. If it is
* not a dash or a dot, then there is an error in the repres-
* entation string.
*/
if (*sptr == CW_DASH_REPRESENTATION)
token |= 1;
else if (*sptr != CW_DOT_REPRESENTATION)
return 0;
}
/* Return the value resulting from our tokenization of the string. */
return token;
}
/* ---------------------------------------------------------------------- */
void cMorse::enable(std::string s, bool val)
{
for (int i = 0; cw_table[i].rpr.length(); i++) {
if (cw_table[i].chr == s) {
cw_table[i].enabled = val;
return;
}
}
}
void cMorse::init()
{
CW_TABLE *cw; /* Pointer to table entry */
unsigned int i;
long code;
int len;
// Update the char / prosign relationship
if (progdefaults.CW_prosigns.length() == 9) {
for (int i = 0; i < 9; i++) {
cw_table[i].chr = progdefaults.CW_prosigns[i];
}
}
// Clear the RX & TX tables
for (i = 0; i < MorseTableSize; i++) {
cw_tx_lookup[i].code = 0x04;
cw_tx_lookup[i].prt = 0;
cw_rx_lookup[i] = 0;
}
// For each main table entry, create a token entry.
for (cw = cw_table; cw->chr != 0; cw++) {
if ((cw->chr == '(') && !progdefaults.CW_use_paren) continue;
if ((cw->chr == '<') && progdefaults.CW_use_paren) continue;
i = tokenize_representation(cw->rpr);
if (i != 0)
cw_rx_lookup[i] = cw;
}
// Build TX table
for (cw = cw_table; cw->chr != 0; cw++) {
if ((cw->chr == '(') && !progdefaults.CW_use_paren) continue;
if ((cw->chr == '<') && progdefaults.CW_use_paren) continue;
len = strlen(cw->rpr);
code = 0x04;
while (len-- > 0) {
if (cw->rpr[len] == CW_DASH_REPRESENTATION) {
code = (code << 1) | 1;
code = (code << 1) | 1;
code = (code << 1) | 1;
} else
code = (code << 1) | 1;
code <<= 1;
enable("<AA>", 1);
enable("Ä", 0); enable("ä", 0);
enable("Æ", 0); enable("æ", 0);
enable("Å", 0); enable("å", 0);
enable("Ç", 0); enable("ç", 0);
enable("È", 0); enable("è", 0);
enable("É", 0); enable("é", 0);
enable("Ó", 0); enable("ó", 0);
enable("Ö", 0); enable("ö", 0);
enable("Ø", 0); enable("ø", 0);
enable("Ñ", 0); enable("ñ", 0);
enable("Ü", 0); enable("ü", 0);
enable("Û", 0); enable("û", 0);
if (progdefaults.A_umlaut)
{ enable("Ä", 1); enable("ä", 1); enable("<AA>", 0); }
if (progdefaults.A_aelig)
{ enable("Æ", 1); enable("æ", 1); enable("<AA>", 0); }
if (progdefaults.A_ring)
{ enable("Å", 1); enable("å", 1); }
if (progdefaults.C_cedilla)
{ enable("Ç", 1); enable("ç", 1); }
if (progdefaults.E_grave)
{ enable("È", 1); enable("è", 1); }
if (progdefaults.E_acute)
{ enable("É", 1); enable("é", 1); }
if (progdefaults.O_acute)
{ enable("Ó", 1); enable("ó", 1); }
if (progdefaults.O_umlaut)
{ enable("Ö", 1); enable("ö", 1); }
if (progdefaults.O_slash)
{ enable("Ø", 1); enable("ø", 1); }
if (progdefaults.N_tilde)
{ enable("Ñ", 1); enable("ñ", 1); }
if (progdefaults.U_umlaut)
{ enable("Ü", 1); enable("ü", 1); }
if (progdefaults.U_circ)
{ enable("Û", 1); enable("û", 1); }
CW_table_changed = false;
utf8.clear();
toprint.clear();
}
std::string cMorse::rx_lookup(std::string rx)
{
if (CW_table_changed) init();
for (int i = 0; cw_table[i].rpr.length(); i++) {
if (rx == cw_table[i].rpr) {
if (cw_table[i].enabled) {
return cw_table[i].prt;
}
}
cw_tx_lookup[(int)cw->chr].code = code;
cw_tx_lookup[(int)cw->chr].prt = cw->prt;
}
return "";
}
const char *cMorse::rx_lookup(const char *r)
std::string cMorse::tx_lookup(int c)
{
int token;
CW_TABLE *cw;
if (CW_table_changed) init();
if ((token = tokenize_representation(r)) == 0)
return NULL;
c &= 0xFF;
utf8 += c;
toprint.clear();
if ((cw = cw_rx_lookup[token]) == NULL)
return NULL;
return cw->prt;
}
const char *cMorse::tx_print(int c)
{
if (cw_tx_lookup[toupper(c)].prt)
return cw_tx_lookup[toupper(c)].prt;
else
if (((utf8[0] & 0xFF) > 0x7F) && (utf8.length() == 1)) {
return "";
}
}
for (int i = 0; cw_table[i].rpr.length(); i++) {
if (utf8 == cw_table[i].chr) {
if (!cw_table[i].enabled) {
utf8.clear();
return "";
}
toprint = cw_table[i].prt;
utf8.clear();
return cw_table[i].rpr;
}
}
utf8.clear();
return "";
unsigned long cMorse::tx_lookup(int c)
{
return cw_tx_lookup[toupper(c)].code;
}

View file

@ -213,8 +213,8 @@ int CW_CHANNEL::decode_state(int cw_state)
&& (curr_element < 2 * two_dots) ) {
// && cw_receive_state == POST_TONE) {
const char * code = morse->rx_lookup(rx_rep_buf.c_str());
if (code == NULL) {
std::string code = morse->rx_lookup(rx_rep_buf);
if (code.length()) {
decode_str.clear();
cw_receive_state = KEYUP;
rx_rep_buf.clear();

View file

@ -234,12 +234,11 @@ int WK_send_char(int c)
int n = 0;
int code = wkmorse->tx_lookup(c & 0xFF);
if (c != ' ') {
while (code > 1) {
if (code & 0x01) n += 4;
else n += 2;
code = code >> 1;
std::string code = wkmorse->tx_lookup(c);
for (size_t i = 0; i < code.length(); i++) {
n += 2;
if (code[i] == '-') n += 2;
}
} else n = 7;
n += 4;

View file

@ -3360,6 +3360,148 @@ static void cb_btn_WK_use_pot(Fl_Check_Button*, void*) {
Fl_Output *txt_WK_wpm=(Fl_Output *)0;
Fl_Group *tabsCW_ext_chars=(Fl_Group *)0;
Fl_Check_Button *btn_A_aelig=(Fl_Check_Button *)0;
static void cb_btn_A_aelig(Fl_Check_Button* o, void*) {
progdefaults.A_aelig = o->value();
if (progdefaults.A_aelig) {
progdefaults.A_umlaut = false;
btn_A_umlaut->value(0);
}
btn_A_umlaut->redraw();
progdefaults.changed = true;
CW_table_changed = true;
}
Fl_Check_Button *btn_A_umlaut=(Fl_Check_Button *)0;
static void cb_btn_A_umlaut(Fl_Check_Button* o, void*) {
progdefaults.A_umlaut = o->value();
if (progdefaults.A_umlaut) {
progdefaults.A_aelig = false;
btn_A_aelig->value(0);
}
btn_A_aelig->redraw();
progdefaults.changed = true;
CW_table_changed = true;
}
Fl_Check_Button *btn_A_ring=(Fl_Check_Button *)0;
static void cb_btn_A_ring(Fl_Check_Button* o, void*) {
progdefaults.A_ring = o->value();
progdefaults.changed = true;
CW_table_changed = true;
}
Fl_Check_Button *btn_O_acute=(Fl_Check_Button *)0;
static void cb_btn_O_acute(Fl_Check_Button* o, void*) {
progdefaults.O_acute = o->value();
if (progdefaults.O_acute) {
progdefaults.O_umlaut = false;
btn_O_umlaut->value(0);
progdefaults.O_slash = false;
btn_O_slash->value(0);
}
btn_O_umlaut->redraw();
btn_O_slash->redraw();
progdefaults.changed = true;
CW_table_changed = true;
}
Fl_Check_Button *btn_O_slash=(Fl_Check_Button *)0;
static void cb_btn_O_slash(Fl_Check_Button* o, void*) {
progdefaults.O_slash = o->value();
if (progdefaults.O_slash) {
progdefaults.O_umlaut = false;
btn_O_umlaut->value(0);
progdefaults.O_acute = false;
btn_O_acute->value(0);
}
btn_O_umlaut->redraw();
btn_O_acute->redraw();
progdefaults.changed = true;
CW_table_changed = true;
}
Fl_Check_Button *btn_O_umlaut=(Fl_Check_Button *)0;
static void cb_btn_O_umlaut(Fl_Check_Button* o, void*) {
progdefaults.O_umlaut = o->value();
if (progdefaults.O_umlaut) {
progdefaults.O_acute = false;
btn_O_acute->value(0);
progdefaults.O_slash = false;
btn_O_slash->value(0);
}
btn_O_acute->redraw();
btn_O_slash->redraw();
progdefaults.changed = true;
CW_table_changed = true;
}
Fl_Check_Button *btn_C_cedilla=(Fl_Check_Button *)0;
static void cb_btn_C_cedilla(Fl_Check_Button* o, void*) {
progdefaults.C_cedilla = o->value();
progdefaults.changed = true;
CW_table_changed = true;
}
Fl_Check_Button *btn_E_grave=(Fl_Check_Button *)0;
static void cb_btn_E_grave(Fl_Check_Button* o, void*) {
progdefaults.E_grave = o->value();
progdefaults.changed = true;
CW_table_changed = true;
}
Fl_Check_Button *btn_E_acute=(Fl_Check_Button *)0;
static void cb_btn_E_acute(Fl_Check_Button* o, void*) {
progdefaults.E_acute = o->value();
progdefaults.changed = true;
CW_table_changed = true;
}
Fl_Check_Button *btn_N_tilde=(Fl_Check_Button *)0;
static void cb_btn_N_tilde(Fl_Check_Button* o, void*) {
progdefaults.N_tilde = o->value();
progdefaults.changed = true;
CW_table_changed = true;
}
Fl_Check_Button *btn_U_umlaut=(Fl_Check_Button *)0;
static void cb_btn_U_umlaut(Fl_Check_Button* o, void*) {
progdefaults.U_umlaut = o->value();
if (progdefaults.U_umlaut) {
progdefaults.U_circ = false;
btn_U_circ->value(0);
}
btn_U_circ->redraw();
progdefaults.changed = true;
CW_table_changed = true;
}
Fl_Check_Button *btn_U_circ=(Fl_Check_Button *)0;
static void cb_btn_U_circ(Fl_Check_Button* o, void*) {
progdefaults.U_circ = o->value();
if (progdefaults.U_circ) {
progdefaults.U_umlaut = false;
btn_U_umlaut->value(0);
}
btn_U_umlaut->redraw();
progdefaults.changed = true;
CW_table_changed = true;
}
Fl_Group *tabDomEX=(Fl_Group *)0;
Fl_Input2 *txtSecondary=(Fl_Input2 *)0;
@ -9240,7 +9382,6 @@ i on a\ntouch screen device such as a tablet."));
tabWaterfall->end();
} // Fl_Group* tabWaterfall
{ tabModems = new Fl_Group(0, 25, 605, 365, _("Modems"));
tabModems->hide();
{ tabsModems = new Fl_Tabs(0, 25, 605, 365);
tabsModems->selection_color(FL_LIGHT1);
tabsModems->align(Fl_Align(FL_ALIGN_TOP_RIGHT));
@ -10104,6 +10245,105 @@ i on a\ntouch screen device such as a tablet."));
} // Fl_Output* txt_WK_wpm
tabsCW_winkeyer->end();
} // Fl_Group* tabsCW_winkeyer
{ tabsCW_ext_chars = new Fl_Group(0, 75, 600, 315, _("Ext. Chars."));
tabsCW_ext_chars->align(Fl_Align(FL_ALIGN_TOP_LEFT));
tabsCW_ext_chars->hide();
{ Fl_Group* o = new Fl_Group(5, 85, 590, 266, _("Check to enable character encode/decode\nSelect one character from each group"));
o->box(FL_EMBOSSED_FRAME);
o->align(Fl_Align(FL_ALIGN_TOP|FL_ALIGN_INSIDE));
{ Fl_Group* o = new Fl_Group(10, 140, 99, 80);
o->box(FL_ENGRAVED_FRAME);
{ Fl_Check_Button* o = btn_A_aelig = new Fl_Check_Button(16, 156, 70, 15, _("A aelig"));
btn_A_aelig->tooltip(_("Swap left/right keyer contacts"));
btn_A_aelig->down_box(FL_DOWN_BOX);
btn_A_aelig->callback((Fl_Callback*)cb_btn_A_aelig);
o->value(progdefaults.A_aelig);
} // Fl_Check_Button* btn_A_aelig
{ Fl_Check_Button* o = btn_A_umlaut = new Fl_Check_Button(16, 193, 70, 15, _(" A umlaut"));
btn_A_umlaut->tooltip(_("Swap left/right keyer contacts"));
btn_A_umlaut->down_box(FL_DOWN_BOX);
btn_A_umlaut->callback((Fl_Callback*)cb_btn_A_umlaut);
o->value(progdefaults.A_umlaut);
} // Fl_Check_Button* btn_A_umlaut
o->end();
} // Fl_Group* o
{ Fl_Check_Button* o = btn_A_ring = new Fl_Check_Button(16, 230, 70, 15, _(" A ring"));
btn_A_ring->tooltip(_("Swap left/right keyer contacts"));
btn_A_ring->down_box(FL_DOWN_BOX);
btn_A_ring->callback((Fl_Callback*)cb_btn_A_ring);
o->value(progdefaults.A_ring);
} // Fl_Check_Button* btn_A_ring
{ Fl_Group* o = new Fl_Group(111, 140, 99, 120);
o->box(FL_ENGRAVED_FRAME);
{ Fl_Check_Button* o = btn_O_acute = new Fl_Check_Button(116, 156, 70, 15, _(" O acute"));
btn_O_acute->tooltip(_("Swap left/right keyer contacts"));
btn_O_acute->down_box(FL_DOWN_BOX);
btn_O_acute->callback((Fl_Callback*)cb_btn_O_acute);
o->value(progdefaults.O_acute);
} // Fl_Check_Button* btn_O_acute
{ Fl_Check_Button* o = btn_O_slash = new Fl_Check_Button(116, 230, 70, 15, _(" O slash"));
btn_O_slash->tooltip(_("Swap left/right keyer contacts"));
btn_O_slash->down_box(FL_DOWN_BOX);
btn_O_slash->callback((Fl_Callback*)cb_btn_O_slash);
o->value(progdefaults.O_slash);
} // Fl_Check_Button* btn_O_slash
{ Fl_Check_Button* o = btn_O_umlaut = new Fl_Check_Button(116, 193, 70, 15, _(" O umlaut"));
btn_O_umlaut->tooltip(_("Swap left/right keyer contacts"));
btn_O_umlaut->down_box(FL_DOWN_BOX);
btn_O_umlaut->callback((Fl_Callback*)cb_btn_O_umlaut);
o->value(progdefaults.O_umlaut);
} // Fl_Check_Button* btn_O_umlaut
o->end();
} // Fl_Group* o
{ Fl_Check_Button* o = btn_C_cedilla = new Fl_Check_Button(213, 156, 70, 15, _(" C cedilla"));
btn_C_cedilla->tooltip(_("Swap left/right keyer contacts"));
btn_C_cedilla->down_box(FL_DOWN_BOX);
btn_C_cedilla->callback((Fl_Callback*)cb_btn_C_cedilla);
o->value(progdefaults.C_cedilla);
} // Fl_Check_Button* btn_C_cedilla
{ Fl_Check_Button* o = btn_E_grave = new Fl_Check_Button(311, 156, 70, 15, _(" E grave"));
btn_E_grave->tooltip(_("Swap left/right keyer contacts"));
btn_E_grave->down_box(FL_DOWN_BOX);
btn_E_grave->callback((Fl_Callback*)cb_btn_E_grave);
o->value(progdefaults.E_grave);
} // Fl_Check_Button* btn_E_grave
{ Fl_Check_Button* o = btn_E_acute = new Fl_Check_Button(311, 193, 70, 15, _(" E acute"));
btn_E_acute->tooltip(_("Swap left/right keyer contacts"));
btn_E_acute->down_box(FL_DOWN_BOX);
btn_E_acute->callback((Fl_Callback*)cb_btn_E_acute);
o->value(progdefaults.E_acute);
} // Fl_Check_Button* btn_E_acute
{ Fl_Check_Button* o = btn_N_tilde = new Fl_Check_Button(404, 156, 70, 15, _(" N tilde"));
btn_N_tilde->tooltip(_("Swap left/right keyer contacts"));
btn_N_tilde->down_box(FL_DOWN_BOX);
btn_N_tilde->callback((Fl_Callback*)cb_btn_N_tilde);
o->value(progdefaults.N_tilde);
} // Fl_Check_Button* btn_N_tilde
{ Fl_Group* o = new Fl_Group(490, 140, 99, 80);
o->box(FL_ENGRAVED_FRAME);
{ Fl_Check_Button* o = btn_U_umlaut = new Fl_Check_Button(495, 156, 70, 15, _(" U umlaut"));
btn_U_umlaut->tooltip(_("Swap left/right keyer contacts"));
btn_U_umlaut->down_box(FL_DOWN_BOX);
btn_U_umlaut->callback((Fl_Callback*)cb_btn_U_umlaut);
o->value(progdefaults.U_umlaut);
} // Fl_Check_Button* btn_U_umlaut
{ Fl_Check_Button* o = btn_U_circ = new Fl_Check_Button(495, 193, 70, 15, _(" U circ"));
btn_U_circ->tooltip(_("Swap left/right keyer contacts"));
btn_U_circ->down_box(FL_DOWN_BOX);
btn_U_circ->callback((Fl_Callback*)cb_btn_U_circ);
o->value(progdefaults.U_circ);
} // Fl_Check_Button* btn_U_circ
o->end();
} // Fl_Group* o
{ Fl_Group* o = new Fl_Group(110, 280, 403, 45, _("See https://en.wikipedia.org/wiki/Morse_code\nfor information regarding exten\
ded Morse characters."));
o->align(Fl_Align(FL_ALIGN_TOP|FL_ALIGN_INSIDE));
o->end();
} // Fl_Group* o
o->end();
} // Fl_Group* o
tabsCW_ext_chars->end();
} // Fl_Group* tabsCW_ext_chars
tabsCW->end();
} // Fl_Tabs* tabsCW
tabCW->end();
@ -13991,6 +14231,7 @@ work!"));
{ tabAutoStart = new Fl_Group(0, 25, 600, 365, _("Autostart"));
tabAutoStart->callback((Fl_Callback*)cb_tabAutoStart);
tabAutoStart->when(FL_WHEN_CHANGED);
tabAutoStart->hide();
{ Fl_Group* o = new Fl_Group(2, 32, 596, 335, _("Auto start programs with fldigi"));
o->box(FL_ENGRAVED_BOX);
o->align(Fl_Align(FL_ALIGN_TOP|FL_ALIGN_INSIDE));

View file

@ -427,7 +427,7 @@ static const char szBaudRates[] = "300|600|1200|2400|4800|9600|19200|38400|57600
static const char szProsigns[] = "~|%|&|+|=|{|}|<|>|[|]| ";} {}
Fl_Window {} {
label {Fldigi configuration} open
xywh {675 24 600 425} type Double color 45 selection_color 51 labelsize 18 align 80 non_modal visible
xywh {957 41 600 425} type Double color 45 selection_color 51 labelsize 18 align 80 non_modal visible
} {
Fl_Tabs tabsConfigure {open
xywh {0 0 605 390} color 50 selection_color 50
@ -3406,7 +3406,7 @@ behaves inside the waterfall} xywh {65 207 150 22} box DOWN_BOX color 7 align 8
}
Fl_Group tabModems {
label Modems open
xywh {0 25 605 365} hide
xywh {0 25 605 365}
} {
Fl_Tabs tabsModems {open
xywh {0 25 605 365} selection_color 50 align 9
@ -3419,7 +3419,7 @@ behaves inside the waterfall} xywh {65 207 150 22} box DOWN_BOX color 7 align 8
xywh {0 50 605 340} selection_color 50
} {
Fl_Group tabsCW_general {
label General open
label General open selected
xywh {0 75 600 315} align 5
} {
Fl_Group {} {
@ -3921,7 +3921,7 @@ progdefaults.changed = true;} open
} {}
}
Fl_Group tabsCW_winkeyer {
label WinKeyer open
label WinKeyer
xywh {0 75 600 315} align 5 hide
} {
Fl_Group select_WK_CommPort {
@ -4140,6 +4140,175 @@ default = 0} xywh {513 300 64 22} type Simple
tooltip {WPM setting} xywh {505 114 50 22}
}
}
Fl_Group tabsCW_ext_chars {
label {Ext. Chars.} open
xywh {0 75 600 315} align 5 hide
} {
Fl_Group {} {
label {Check to enable character encode/decode
Select one character from each group} open
xywh {5 85 590 266} box EMBOSSED_FRAME align 17
} {
Fl_Group {} {open
xywh {10 140 99 80} box ENGRAVED_FRAME
} {
Fl_Check_Button btn_A_aelig {
label {A aelig}
callback {progdefaults.A_aelig = o->value();
if (progdefaults.A_aelig) {
progdefaults.A_umlaut = false;
btn_A_umlaut->value(0);
}
btn_A_umlaut->redraw();
progdefaults.changed = true;
CW_table_changed = true;}
tooltip {Swap left/right keyer contacts} xywh {16 156 70 15} down_box DOWN_BOX
code0 {\#include "cw.h"}
code1 {o->value(progdefaults.A_aelig);}
}
Fl_Check_Button btn_A_umlaut {
label { A umlaut}
callback {progdefaults.A_umlaut = o->value();
if (progdefaults.A_umlaut) {
progdefaults.A_aelig = false;
btn_A_aelig->value(0);
}
btn_A_aelig->redraw();
progdefaults.changed = true;
CW_table_changed = true;}
tooltip {Swap left/right keyer contacts} xywh {16 193 70 15} down_box DOWN_BOX
code0 {o->value(progdefaults.A_umlaut);}
}
}
Fl_Check_Button btn_A_ring {
label { A ring}
callback {progdefaults.A_ring = o->value();
progdefaults.changed = true;
CW_table_changed = true;}
tooltip {Swap left/right keyer contacts} xywh {16 230 70 15} down_box DOWN_BOX
code0 {o->value(progdefaults.A_ring);}
}
Fl_Group {} {open
xywh {111 140 99 120} box ENGRAVED_FRAME
} {
Fl_Check_Button btn_O_acute {
label { O acute}
callback {progdefaults.O_acute = o->value();
if (progdefaults.O_acute) {
progdefaults.O_umlaut = false;
btn_O_umlaut->value(0);
progdefaults.O_slash = false;
btn_O_slash->value(0);
}
btn_O_umlaut->redraw();
btn_O_slash->redraw();
progdefaults.changed = true;
CW_table_changed = true;}
tooltip {Swap left/right keyer contacts} xywh {116 156 70 15} down_box DOWN_BOX
code0 {o->value(progdefaults.O_acute);}
}
Fl_Check_Button btn_O_slash {
label { O slash}
callback {progdefaults.O_slash = o->value();
if (progdefaults.O_slash) {
progdefaults.O_umlaut = false;
btn_O_umlaut->value(0);
progdefaults.O_acute = false;
btn_O_acute->value(0);
}
btn_O_umlaut->redraw();
btn_O_acute->redraw();
progdefaults.changed = true;
CW_table_changed = true;}
tooltip {Swap left/right keyer contacts} xywh {116 230 70 15} down_box DOWN_BOX
code0 {o->value(progdefaults.O_slash);}
}
Fl_Check_Button btn_O_umlaut {
label { O umlaut}
callback {progdefaults.O_umlaut = o->value();
if (progdefaults.O_umlaut) {
progdefaults.O_acute = false;
btn_O_acute->value(0);
progdefaults.O_slash = false;
btn_O_slash->value(0);
}
btn_O_acute->redraw();
btn_O_slash->redraw();
progdefaults.changed = true;
CW_table_changed = true;}
tooltip {Swap left/right keyer contacts} xywh {116 193 70 15} down_box DOWN_BOX
code0 {o->value(progdefaults.O_umlaut);}
}
}
Fl_Check_Button btn_C_cedilla {
label { C cedilla}
callback {progdefaults.C_cedilla = o->value();
progdefaults.changed = true;
CW_table_changed = true;}
tooltip {Swap left/right keyer contacts} xywh {213 156 70 15} down_box DOWN_BOX
code0 {o->value(progdefaults.C_cedilla);}
}
Fl_Check_Button btn_E_grave {
label { E grave}
callback {progdefaults.E_grave = o->value();
progdefaults.changed = true;
CW_table_changed = true;}
tooltip {Swap left/right keyer contacts} xywh {311 156 70 15} down_box DOWN_BOX
code0 {o->value(progdefaults.E_grave);}
}
Fl_Check_Button btn_E_acute {
label { E acute}
callback {progdefaults.E_acute = o->value();
progdefaults.changed = true;
CW_table_changed = true;}
tooltip {Swap left/right keyer contacts} xywh {311 193 70 15} down_box DOWN_BOX
code0 {o->value(progdefaults.E_acute);}
}
Fl_Check_Button btn_N_tilde {
label { N tilde}
callback {progdefaults.N_tilde = o->value();
progdefaults.changed = true;
CW_table_changed = true;}
tooltip {Swap left/right keyer contacts} xywh {404 156 70 15} down_box DOWN_BOX
code0 {o->value(progdefaults.N_tilde);}
}
Fl_Group {} {open
xywh {490 140 99 80} box ENGRAVED_FRAME
} {
Fl_Check_Button btn_U_umlaut {
label { U umlaut}
callback {progdefaults.U_umlaut = o->value();
if (progdefaults.U_umlaut) {
progdefaults.U_circ = false;
btn_U_circ->value(0);
}
btn_U_circ->redraw();
progdefaults.changed = true;
CW_table_changed = true;}
tooltip {Swap left/right keyer contacts} xywh {495 156 70 15} down_box DOWN_BOX
code0 {o->value(progdefaults.U_umlaut);}
}
Fl_Check_Button btn_U_circ {
label { U circ}
callback {progdefaults.U_circ = o->value();
if (progdefaults.U_circ) {
progdefaults.U_umlaut = false;
btn_U_umlaut->value(0);
}
btn_U_umlaut->redraw();
progdefaults.changed = true;
CW_table_changed = true;}
tooltip {Swap left/right keyer contacts} xywh {495 193 70 15} down_box DOWN_BOX
code0 {o->value(progdefaults.U_circ);}
}
}
Fl_Group {} {
label {See https://en.wikipedia.org/wiki/Morse_code
for information regarding extended Morse characters.} open
xywh {110 280 403 45} align 17
} {}
}
}
}
}
Fl_Group tabDomEX {
@ -8197,7 +8366,7 @@ o->label((inpLOTW_pwd->type() & FL_SECRET_INPUT) ? _("Show") : _("Hide"));}
Fl_Group tabAutoStart {
label Autostart
callback {progdefaults.changed = true;} open
xywh {0 25 600 365} when 1
xywh {0 25 600 365} when 1 hide
} {
Fl_Group {} {
label {Auto start programs with fldigi} open
@ -8238,7 +8407,7 @@ progdefaults.changed = true;}
Fl_Input txt_auto_flnet_pathname {
label {flnet:}
callback {progdefaults.auto_flnet_pathname = o->value();
progdefaults.changed = true;} selected
progdefaults.changed = true;}
tooltip {Enter full path-filename for flnet} xywh {63 147 310 24} when 1
code0 {o->value(progdefaults.auto_flnet_pathname.c_str());}
class Fl_Input2

View file

@ -381,6 +381,20 @@ extern Fl_Box *box_WK_xoff;
extern Fl_Box *box_WK_keydown;
extern Fl_Check_Button *btn_WK_use_pot;
extern Fl_Output *txt_WK_wpm;
extern Fl_Group *tabsCW_ext_chars;
#include "cw.h"
extern Fl_Check_Button *btn_A_aelig;
extern Fl_Check_Button *btn_A_umlaut;
extern Fl_Check_Button *btn_A_ring;
extern Fl_Check_Button *btn_O_acute;
extern Fl_Check_Button *btn_O_slash;
extern Fl_Check_Button *btn_O_umlaut;
extern Fl_Check_Button *btn_C_cedilla;
extern Fl_Check_Button *btn_E_grave;
extern Fl_Check_Button *btn_E_acute;
extern Fl_Check_Button *btn_N_tilde;
extern Fl_Check_Button *btn_U_umlaut;
extern Fl_Check_Button *btn_U_circ;
extern Fl_Group *tabDomEX;
extern Fl_Input2 *txtSecondary;
extern Fl_Check_Button *valDominoEX_FILTER;

View file

@ -473,6 +473,42 @@
ELEM_(std::string, CW_prosigns, "CWPROSIGNS", \
"CW prosigns BT AA AS AR SK KN INT HM VE", \
"=~<>%+&{}") \
ELEM_(bool, A_umlaut, "A_umlaut", \
"Use Ä extended CW character", \
true) \
ELEM_(bool, A_aelig, "A_aelig", \
"Use Æ extended CW character", \
false) \
ELEM_(bool, A_ring, "A_ring", \
"Use Ä extended CW character", \
true) \
ELEM_(bool, C_cedilla, "C_cedilla", \
"Use Ç extended CW character", \
true) \
ELEM_(bool, E_grave, "E_grave", \
"Use È extended CW character", \
true) \
ELEM_(bool, E_acute, "E_acute", \
"Use É extended CW character", \
true) \
ELEM_(bool, O_acute, "O_acute", \
"Use Ó extended CW character", \
false) \
ELEM_(bool, O_umlaut, "O_umlaut", \
"Use Ö extended CW character", \
true) \
ELEM_(bool, O_slash, "O_slash", \
"Use Ø extended CW character", \
false) \
ELEM_(bool, N_tilde, "N_tilde", \
"Use Ñ extended CW character", \
true) \
ELEM_(bool, U_umlaut, "U_umlaut", \
"Use Ü extended CW character", \
true) \
ELEM_(bool, U_circ, "U_circ", \
"Use Û extended CW character", \
false) \
/* FELD HELL */ \
ELEM_(double, HELL_BW, "HELL_BW0", "Feld Hell working bandwidth", 245.0) \
ELEM_(double, HELL_BW_FH, "HELL_BW1", "FH bandwidth", 245.0) \

View file

@ -40,7 +40,7 @@
#define CW_SAMPLERATE 8000
#define CWMaxSymLen 4096 // AG1LE: - was 4096
#define KNUM 640 // 1/2 dot length at 5 wpm
#define CWKNUM 640 // 1/2 dot length at 5 wpm
#define MAX_MORSE_ELEMENTS 6 // maximum of 6 elements in a Morse character 256
@ -91,9 +91,8 @@ class cw : public modem {
#define WGT_SIZE 7
struct SOM_TABLE {
char chr; /* The character(s) represented */
const char *prt; /* The printable representation of the character */
float wgt[WGT_SIZE]; /* Dot-dash weight vector */
std::string rpr; // The printable representation of the character
float wgt[WGT_SIZE]; // Dot-dash weight vector
};
protected:
@ -180,7 +179,7 @@ protected:
void update_Status();
void sync_parameters();
void reset_rx_filter();
int handle_event(int cw_event, const char **c);
int handle_event(int cw_event, std::string &sc);
inline int usec_diff(unsigned int earlier, unsigned int later);
void send_symbol(int symbol, int len);
void send_ch(int c);
@ -246,8 +245,10 @@ public:
void toggleWPM();
int normalize(float *v, int n, int twodots);
const char *find_winner (float *inbuf, int twodots);
std::string find_winner (float *inbuf, int twodots);
};
extern bool CW_table_changed;
#endif

View file

@ -1,16 +1,7 @@
/*
* morse.h -- morse code tables
*
* Copyright (C) 2004
* Lawrence Glaister (ve7it@shaw.ca)
* Tomi Manninen (oh2bns@sral.fi)
*
* This modem borrowed heavily from other gmfsk modems and
* also from the unix-cw project. I would like to thank those
* authors for enriching my coding experience by providing
* and supporting open source.
*
* This file is part of fldigi.
* Copyright (C) 2017
*
* Fldigi is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -30,28 +21,25 @@
#ifndef _MORSE_H
#define _MORSE_H
#include <string>
#define MorseTableSize 256
#define CW_DOT_REPRESENTATION '.'
#define CW_DASH_REPRESENTATION '-'
struct CW_TABLE {
char chr; /* The character(s) represented */
const char *prt; /* The printable representation of the character */
const char *rpr; /* Dot-dash shape of the character */
};
struct CW_XMT_TABLE {
unsigned long code;
const char *prt;
struct CWstruct {
bool enabled; // true if character is active
std::string chr; // utf-8 string representation of character
std::string prt; // utf-8 printable representation
std::string rpr; // Dot-dash code representation
};
class cMorse {
private:
CW_TABLE *cw_rx_lookup[256];
CW_XMT_TABLE cw_tx_lookup[256];
unsigned int tokenize_representation(const char *representation);
static CWstruct cw_table[];
std::string utf8;
std::string toprint;
public:
cMorse() {
init();
@ -59,9 +47,10 @@ public:
~cMorse() {
}
void init();
const char *rx_lookup(const char *r);
unsigned long tx_lookup(int c);
const char *tx_print(int c);
void enable(std::string, bool);
std::string rx_lookup(std::string);
std::string tx_lookup(int);
std::string tx_print() { return toprint; }
};
#endif

View file

@ -769,7 +769,7 @@ void modem::cwid_send_symbol(int bits)
void modem::cwid_send_ch(int ch)
{
int code;
std::string code;
// handle word space separately (7 dots spacing)
// last char already had 2 elements of inter-character spacing
@ -785,17 +785,20 @@ void modem::cwid_send_ch(int ch)
}
// convert character code to a morse representation
if ((ch < 256) && (ch >= 0)) {
code = morse.tx_lookup(ch); //cw_tx_lookup(ch);
} else {
code = 0x04; // two extra dot spaces
}
code = morse.tx_lookup(ch); //cw_tx_lookup(ch);
if (!code.length())
return;
// loop sending out binary bits of cw character
while (code > 1) {
cwid_send_symbol(code);// & 1);
code = code >> 1;
for (size_t n = 0; n < code.length(); n++) {
cwid_send_symbol(0);
cwid_send_symbol(1);
if (code[n] == '-') {
cwid_send_symbol(1);
cwid_send_symbol(1);
}
}
cwid_send_symbol(0);
cwid_send_symbol(0);
}