2015-07-27 00:35:07 +00:00
//
// This file is part of Dire Wolf, an amateur radio packet TNC.
//
2015-07-27 01:17:23 +00:00
// Copyright (C) 2013, 2015 John Langner, WB2OSZ
2015-07-27 00:35:07 +00:00
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
/*------------------------------------------------------------------
*
2015-12-24 20:25:13 +00:00
* Module : tt_text . c
2015-07-27 00:35:07 +00:00
*
* Purpose : Translate between text and touch tone representation .
*
* Description : Letters can be represented by different touch tone
* keypad sequences .
*
* References : This is based upon APRStt ( TM ) documents but not 100 %
* compliant due to ambiguities and inconsistencies in
* the specifications .
*
* http : //www.aprs.org/aprstt.html
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*
* There are two different encodings called :
*
* * Two - key
*
* Digits are represented by a single key press .
* Letters ( or space ) are represented by the corresponding
* key followed by A , B , C , or D depending on the position
* of the letter .
*
* * Multi - press
*
* Letters are represented by one or more key presses
* depending on their position .
* e . g . on 5 / JKL key , J = 1 press , K = 2 , etc .
* The digit is the number of letters plus 1.
* In this case , press 5 key four times to get digit 5.
* When two characters in a row use the same key ,
* use the " A " key as a separator .
*
* Examples :
*
* Character Multipress Two Key Comments
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* 0 00 0 Space is handled like a letter .
* 1 1 1 No letters on 1 button .
* 2 2222 2 3 letters - > 4 key presses
* 9 99999 9
* W 9 9 A
* X 99 9 B
* Y 999 9 C
* Z 9999 9 D
* space 0 0 A 0 A was used in an APRStt comment example .
*
*
* Note that letters can occur in callsigns and comments .
* Everywhere else they are simply digits .
2015-07-27 01:17:23 +00:00
*
*
* * New fixed length callsign format
*
*
* The " QIKcom-2 " project adds a new format where callsigns are represented by
* a fixed length string of only digits . The first 6 digits are the buttons corresponding
* to the letters . The last 4 take a little calculation . Example :
*
* W B 4 A P R original .
* 9 2 4 2 7 7 corresponding button .
* 1 2 0 1 1 2 character position on key . 0 for the digit .
*
* Treat the last line as a base 4 number .
* Convert it to base 10 and we get 1558 for the last four digits .
2015-07-27 00:35:07 +00:00
*/
/*
* Everything is based on this table .
* Changing it will change everything .
2015-07-27 01:17:23 +00:00
* In other words , don ' t mess with it .
* The world will come crumbling down .
2015-07-27 00:35:07 +00:00
*/
static const char translate [ 10 ] [ 4 ] = {
/* A B C D */
/* --- --- --- --- */
/* 0 */ { ' ' , 0 , 0 , 0 } ,
/* 1 */ { 0 , 0 , 0 , 0 } ,
/* 2 */ { ' A ' , ' B ' , ' C ' , 0 } ,
/* 3 */ { ' D ' , ' E ' , ' F ' , 0 } ,
/* 4 */ { ' G ' , ' H ' , ' I ' , 0 } ,
/* 5 */ { ' J ' , ' K ' , ' L ' , 0 } ,
/* 6 */ { ' M ' , ' N ' , ' O ' , 0 } ,
/* 7 */ { ' P ' , ' Q ' , ' R ' , ' S ' } ,
/* 8 */ { ' T ' , ' U ' , ' V ' , 0 } ,
/* 9 */ { ' W ' , ' X ' , ' Y ' , ' Z ' } } ;
2015-07-27 01:17:23 +00:00
/*
* This is for the new 10 character fixed length callsigns for APRStt 3.
* Notice that it uses an old keypad layout with Q & Z on the 1 button .
* The TH - D72A and all telephones that I could find all have
* four letters each on the 7 and 9 buttons .
* This inconsistency is sure to cause confusion but the 6 + 4 scheme won ' t
* be possible with more than 4 characters assigned to one button .
* 4 * * 6 - 1 = 4096 which fits in 4 decimal digits .
* 5 * * 6 - 1 = 15624 would not fit .
*
* The column is a two bit code packed into the last 4 digits .
*/
static const char call10encoding [ 10 ] [ 4 ] = {
/* 0 1 2 3 */
/* --- --- --- --- */
/* 0 */ { ' 0 ' , ' ' , 0 , 0 } ,
/* 1 */ { ' 1 ' , ' Q ' , ' Z ' , 0 } ,
/* 2 */ { ' 2 ' , ' A ' , ' B ' , ' C ' } ,
/* 3 */ { ' 3 ' , ' D ' , ' E ' , ' F ' } ,
/* 4 */ { ' 4 ' , ' G ' , ' H ' , ' I ' } ,
/* 5 */ { ' 5 ' , ' J ' , ' K ' , ' L ' } ,
/* 6 */ { ' 6 ' , ' M ' , ' N ' , ' O ' } ,
/* 7 */ { ' 7 ' , ' P ' , ' R ' , ' S ' } ,
/* 8 */ { ' 8 ' , ' T ' , ' U ' , ' V ' } ,
/* 9 */ { ' 9 ' , ' W ' , ' X ' , ' Y ' } } ;
/*
2015-09-07 23:56:20 +00:00
* Special satellite 4 digit gridsquares to cover " 99.99% of the world's population. "
2015-07-27 01:17:23 +00:00
*/
static const char grid [ 10 ] [ 10 ] [ 3 ] =
{ { " AP " , " BP " , " AO " , " BO " , " CO " , " DO " , " EO " , " FO " , " GO " , " OJ " } , // 0 - Canada
{ " CN " , " DN " , " EN " , " FN " , " GN " , " CM " , " DM " , " EM " , " FM " , " OI " } , // 1 - USA
{ " DL " , " EL " , " FL " , " DK " , " EK " , " FK " , " EJ " , " FJ " , " GJ " , " PI " } , // 2 - C. America
{ " FI " , " GI " , " HI " , " FH " , " GH " , " HH " , " FG " , " GG " , " FF " , " GF " } , // 3 - S. America
{ " JP " , " IO " , " JO " , " KO " , " IN " , " JN " , " KN " , " IM " , " JM " , " KM " } , // 4 - Europe
{ " LO " , " MO " , " NO " , " OO " , " PO " , " QO " , " RO " , " LN " , " MN " , " NN " } , // 5 - Russia
{ " ON " , " PN " , " QN " , " OM " , " PM " , " QM " , " OL " , " PL " , " OK " , " PK " } , // 6 - Japan, China
{ " LM " , " MM " , " NM " , " LL " , " ML " , " NL " , " LK " , " MK " , " NK " , " LJ " } , // 7 - India
{ " PH " , " QH " , " OG " , " PG " , " QG " , " OF " , " PF " , " QF " , " RF " , " RE " } , // 8 - Aus / NZ
{ " IL " , " IK " , " IJ " , " JJ " , " JI " , " JH " , " JG " , " KG " , " JF " , " KF " } } ; // 9 - Africa
2015-07-27 00:35:07 +00:00
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
# include <ctype.h>
# include <assert.h>
# include <stdarg.h>
2015-11-08 01:57:02 +00:00
# include "direwolf.h"
2015-07-27 00:35:07 +00:00
# include "textcolor.h"
2015-07-27 01:17:23 +00:00
# include "tt_text.h"
2015-07-27 00:35:07 +00:00
# if defined(ENC_MAIN) || defined(DEC_MAIN)
void text_color_set ( dw_color_t c ) { return ; }
int dw_printf ( const char * fmt , . . . )
{
va_list args ;
int len ;
va_start ( args , fmt ) ;
len = vprintf ( fmt , args ) ;
va_end ( args ) ;
return ( len ) ;
}
# endif
/*------------------------------------------------------------------
*
* Name : tt_text_to_multipress
*
* Purpose : Convert text to the multi - press representation .
*
* Inputs : text - Input string .
* Should contain only digits , letters , or space .
* All other punctuation is treated as space .
*
* quiet - True to suppress error messages .
*
* Outputs : buttons - Sequence of buttons to press .
*
* Returns : Number of errors detected .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2015-11-08 01:57:02 +00:00
int tt_text_to_multipress ( const char * text , int quiet , char * buttons )
2015-07-27 00:35:07 +00:00
{
2015-11-08 01:57:02 +00:00
const char * t = text ;
2015-07-27 00:35:07 +00:00
char * b = buttons ;
char c ;
int row , col ;
int errors = 0 ;
int found ;
int n ;
* b = ' \0 ' ;
while ( ( c = * t + + ) ! = ' \0 ' ) {
if ( isdigit ( c ) ) {
/* Count number of other characters assigned to this button. */
/* Press that number plus one more. */
n = 1 ;
row = c - ' 0 ' ;
for ( col = 0 ; col < 4 ; col + + ) {
if ( translate [ row ] [ col ] ! = 0 ) {
n + + ;
}
}
if ( buttons [ 0 ] ! = ' \0 ' & & * ( b - 1 ) = = row + ' 0 ' ) {
* b + + = ' A ' ;
}
while ( n - - ) {
* b + + = row + ' 0 ' ;
* b = ' \0 ' ;
}
}
else {
if ( isupper ( c ) ) {
;
}
else if ( islower ( c ) ) {
c = toupper ( c ) ;
}
else if ( c ! = ' ' ) {
errors + + ;
if ( ! quiet ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " Text to multi-press: Only letters, digits, and space allowed. \n " ) ;
}
c = ' ' ;
}
/* Search for everything else in the translation table. */
/* Press number of times depending on column where found. */
found = 0 ;
for ( row = 0 ; row < 10 & & ! found ; row + + ) {
for ( col = 0 ; col < 4 & & ! found ; col + + ) {
if ( c = = translate [ row ] [ col ] ) {
/* Stick in 'A' if previous character used same button. */
if ( buttons [ 0 ] ! = ' \0 ' & & * ( b - 1 ) = = row + ' 0 ' ) {
* b + + = ' A ' ;
}
n = col + 1 ;
while ( n - - ) {
* b + + = row + ' 0 ' ;
* b = ' \0 ' ;
found = 1 ;
}
}
}
}
if ( ! found ) {
errors + + ;
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " Text to multi-press: INTERNAL ERROR. Should not be here. \n " ) ;
}
}
}
return ( errors ) ;
} /* end tt_text_to_multipress */
/*------------------------------------------------------------------
*
* Name : tt_text_to_two_key
*
* Purpose : Convert text to the two - key representation .
*
* Inputs : text - Input string .
* Should contain only digits , letters , or space .
* All other punctuation is treated as space .
*
* quiet - True to suppress error messages .
*
* Outputs : buttons - Sequence of buttons to press .
*
* Returns : Number of errors detected .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2015-11-08 01:57:02 +00:00
int tt_text_to_two_key ( const char * text , int quiet , char * buttons )
2015-07-27 00:35:07 +00:00
{
2015-11-08 01:57:02 +00:00
const char * t = text ;
2015-07-27 00:35:07 +00:00
char * b = buttons ;
char c ;
int row , col ;
int errors = 0 ;
int found ;
* b = ' \0 ' ;
while ( ( c = * t + + ) ! = ' \0 ' ) {
if ( isdigit ( c ) ) {
/* Digit is single key press. */
* b + + = c ;
* b = ' \0 ' ;
}
else {
if ( isupper ( c ) ) {
;
}
else if ( islower ( c ) ) {
c = toupper ( c ) ;
}
else if ( c ! = ' ' ) {
errors + + ;
if ( ! quiet ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " Text to two key: Only letters, digits, and space allowed. \n " ) ;
}
c = ' ' ;
}
/* Search for everything else in the translation table. */
found = 0 ;
for ( row = 0 ; row < 10 & & ! found ; row + + ) {
for ( col = 0 ; col < 4 & & ! found ; col + + ) {
if ( c = = translate [ row ] [ col ] ) {
* b + + = ' 0 ' + row ;
* b + + = ' A ' + col ;
* b = ' \0 ' ;
found = 1 ;
}
}
}
if ( ! found ) {
errors + + ;
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " Text to two-key: INTERNAL ERROR. Should not be here. \n " ) ;
}
}
}
return ( errors ) ;
} /* end tt_text_to_two_key */
2015-09-07 23:56:20 +00:00
/*------------------------------------------------------------------
*
* Name : tt_letter_to_two_digits
*
* Purpose : Convert one letter to 2 digit representation .
*
* Inputs : c - One letter .
*
* quiet - True to suppress error messages .
2015-11-08 01:57:02 +00:00
*
2015-09-07 23:56:20 +00:00
* Outputs : buttons - Sequence of two buttons to press .
* " 00 " for error because this is probably
* being used to build up a fixed length
* string where positions are signficant .
2015-11-08 01:57:02 +00:00
* Must be at least 3 bytes .
2015-09-07 23:56:20 +00:00
*
* Returns : Number of errors detected .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
// TODO: need to test this.
2015-11-08 01:57:02 +00:00
int tt_letter_to_two_digits ( char c , int quiet , char buttons [ 3 ] )
2015-09-07 23:56:20 +00:00
{
int row , col ;
int errors = 0 ;
int found ;
2015-11-08 01:57:02 +00:00
strlcpy ( buttons , " " , 3 ) ;
2015-09-07 23:56:20 +00:00
if ( islower ( c ) ) {
c = toupper ( c ) ;
}
if ( ! isupper ( c ) ) {
errors + + ;
if ( ! quiet ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " Letter to two digits: \" %c \" found where a letter is required. \n " , c ) ;
}
2015-11-08 01:57:02 +00:00
strlcpy ( buttons , " 00 " , 3 ) ;
2015-09-07 23:56:20 +00:00
return ( errors ) ;
}
/* Search in the translation table. */
found = 0 ;
for ( row = 0 ; row < 10 & & ! found ; row + + ) {
for ( col = 0 ; col < 4 & & ! found ; col + + ) {
if ( c = = translate [ row ] [ col ] ) {
2015-11-08 01:57:02 +00:00
buttons [ 0 ] = ' 0 ' + row ;
buttons [ 1 ] = ' 1 ' + col ;
buttons [ 2 ] = ' \0 ' ;
2015-09-07 23:56:20 +00:00
found = 1 ;
}
}
}
if ( ! found ) {
errors + + ;
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " Letter to two digits: INTERNAL ERROR. Should not be here. \n " ) ;
2015-11-08 01:57:02 +00:00
strlcpy ( buttons , " 00 " , 3 ) ;
2015-09-07 23:56:20 +00:00
}
return ( errors ) ;
} /* end tt_letter_to_two_digits */
2015-07-27 01:17:23 +00:00
/*------------------------------------------------------------------
*
* Name : tt_text_to_call10
*
* Purpose : Convert text to the 10 character callsign format .
*
* Inputs : text - Input string .
* Should contain from 1 to 6 letters and digits .
*
* quiet - True to suppress error messages .
*
* Outputs : buttons - Sequence of buttons to press .
* Should be exactly 10 unless error .
*
* Returns : Number of errors detected .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2015-11-08 01:57:02 +00:00
int tt_text_to_call10 ( const char * text , int quiet , char * buttons )
2015-07-27 01:17:23 +00:00
{
2015-11-08 01:57:02 +00:00
const char * t ;
2015-07-27 01:17:23 +00:00
char * b ;
char c ;
int packed ; /* two bits per character */
int row , col ;
int errors = 0 ;
int found ;
char padded [ 8 ] ;
char stemp [ 8 ] ;
strcpy ( buttons , " " ) ;
/* Quick validity check. */
if ( strlen ( text ) < 1 | | strlen ( text ) > 6 ) {
if ( ! quiet ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " Text to callsign 6+4: Callsign \" %s \" not between 1 and 6 characters. \n " , text ) ;
}
errors + + ;
return ( errors ) ;
}
for ( t = text ; * t ! = ' \0 ' ; t + + ) {
if ( ! isalnum ( * t ) ) {
if ( ! quiet ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " Text to callsign 6+4: Callsign \" %s \" can contain only letters and digits. \n " , text ) ;
}
errors + + ;
return ( errors ) ;
}
}
/* Append spaces if less than 6 characters. */
strcpy ( padded , text ) ;
while ( strlen ( padded ) < 6 ) {
strcat ( padded , " " ) ;
}
b = buttons ;
packed = 0 ;
for ( t = padded ; * t ! = ' \0 ' ; t + + ) {
c = * t ;
if ( islower ( c ) ) {
c = toupper ( c ) ;
}
/* Search in the translation table. */
found = 0 ;
for ( row = 0 ; row < 10 & & ! found ; row + + ) {
for ( col = 0 ; col < 4 & & ! found ; col + + ) {
if ( c = = call10encoding [ row ] [ col ] ) {
* b + + = ' 0 ' + row ;
* b = ' \0 ' ;
packed = packed * 4 + col ; /* base 4 to binary */
found = 1 ;
}
}
}
if ( ! found ) {
/* Earlier check should have caught any character not in translation table. */
errors + + ;
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " Text to callsign 6+4: INTERNAL ERROR 0x%02x. Should not be here. \n " , c ) ;
}
}
/* Binary to decimal for the columns. */
2015-11-08 01:57:02 +00:00
snprintf ( stemp , sizeof ( stemp ) , " %04d " , packed ) ;
2015-07-27 01:17:23 +00:00
strcat ( buttons , stemp ) ;
return ( errors ) ;
} /* end tt_text_to_call10 */
/*------------------------------------------------------------------
*
2015-09-07 23:56:20 +00:00
* Name : tt_text_to_satsq
2015-07-27 01:17:23 +00:00
*
2015-09-07 23:56:20 +00:00
* Purpose : Convert Special Satellite Gridsquare to 4 digit DTMF representation .
2015-07-27 01:17:23 +00:00
*
* Inputs : text - Input string .
* Should be two letters ( A thru R ) and two digits .
*
* quiet - True to suppress error messages .
*
* Outputs : buttons - Sequence of buttons to press .
* Should be 4 digits unless error .
*
* Returns : Number of errors detected .
*
* Example : " FM19 " is converted to " 1819. "
* " AA00 " is converted to empty string and error return code .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2015-11-08 01:57:02 +00:00
int tt_text_to_satsq ( const char * text , int quiet , char * buttons , size_t buttonsize )
2015-07-27 01:17:23 +00:00
{
int row , col ;
int errors = 0 ;
int found ;
char uc [ 3 ] ;
2015-11-08 01:57:02 +00:00
strlcpy ( buttons , " " , buttonsize ) ;
2015-07-27 01:17:23 +00:00
/* Quick validity check. */
if ( strlen ( text ) < 1 | | strlen ( text ) > 4 ) {
if ( ! quiet ) {
text_color_set ( DW_COLOR_ERROR ) ;
2015-09-07 23:56:20 +00:00
dw_printf ( " Satellite Gridsquare to DTMF: Gridsquare \" %s \" must be 4 characters. \n " , text ) ;
2015-07-27 01:17:23 +00:00
}
errors + + ;
return ( errors ) ;
}
/* Changing to upper case makes things easier later. */
uc [ 0 ] = islower ( text [ 0 ] ) ? toupper ( text [ 0 ] ) : text [ 0 ] ;
uc [ 1 ] = islower ( text [ 1 ] ) ? toupper ( text [ 1 ] ) : text [ 1 ] ;
uc [ 2 ] = ' \0 ' ;
if ( uc [ 0 ] < ' A ' | | uc [ 0 ] > ' R ' | | uc [ 1 ] < ' A ' | | uc [ 1 ] > ' R ' ) {
if ( ! quiet ) {
text_color_set ( DW_COLOR_ERROR ) ;
2015-09-07 23:56:20 +00:00
dw_printf ( " Satellite Gridsquare to DTMF: First two characters \" %s \" must be letters in range of A to R. \n " , text ) ;
2015-07-27 01:17:23 +00:00
}
errors + + ;
return ( errors ) ;
}
if ( ! isdigit ( text [ 2 ] ) | | ! isdigit ( text [ 3 ] ) ) {
if ( ! quiet ) {
text_color_set ( DW_COLOR_ERROR ) ;
2015-09-07 23:56:20 +00:00
dw_printf ( " Satellite Gridsquare to DTMF: Last two characters \" %s \" must digits. \n " , text ) ;
2015-07-27 01:17:23 +00:00
}
errors + + ;
return ( errors ) ;
}
/* Search in the translation table. */
found = 0 ;
for ( row = 0 ; row < 10 & & ! found ; row + + ) {
for ( col = 0 ; col < 10 & & ! found ; col + + ) {
if ( strcmp ( uc , grid [ row ] [ col ] ) = = 0 ) {
2015-11-08 01:57:02 +00:00
char btemp [ 8 ] ;
btemp [ 0 ] = row + ' 0 ' ;
btemp [ 1 ] = col + ' 0 ' ;
btemp [ 2 ] = text [ 2 ] ;
btemp [ 3 ] = text [ 3 ] ;
btemp [ 4 ] = ' \0 ' ;
strlcpy ( buttons , btemp , buttonsize ) ;
2015-07-27 01:17:23 +00:00
found = 1 ;
}
}
}
if ( ! found ) {
/* Sorry, Greenland, and half of Africa, and ... */
errors + + ;
if ( ! quiet ) {
text_color_set ( DW_COLOR_ERROR ) ;
2015-09-07 23:56:20 +00:00
dw_printf ( " Satellite Gridsquare to DTMF: Sorry, your location can't be converted to DTMF. \n " ) ;
2015-07-27 01:17:23 +00:00
}
}
return ( errors ) ;
2015-09-07 23:56:20 +00:00
} /* end tt_text_to_satsq */
2015-07-27 01:17:23 +00:00
2015-12-06 15:09:27 +00:00
/*------------------------------------------------------------------
*
* Name : tt_text_to_ascii2d
*
* Purpose : Convert text to the two digit per ascii character representation .
*
* Inputs : text - Input string .
* Any printable ASCII characters .
*
* quiet - True to suppress error messages .
*
* Outputs : buttons - Sequence of buttons to press .
*
* Returns : Number of errors detected .
*
* Description : The standard comment format uses the multipress
* encoding which allows only single case letters , digits ,
* and the space character .
* This is a more flexible format that can handle all
* printable ASCII characters . We take the character code ,
* subtract 32 and convert to two decimal digits . i . e .
* space = 00
* ! = 01
* " = 02
* . . .
* ~ = 94
*
* This is mostly for internal use , so macros can generate
* comments with all characters .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int tt_text_to_ascii2d ( const char * text , int quiet , char * buttons )
{
const char * t = text ;
char * b = buttons ;
char c ;
int errors = 0 ;
* b = ' \0 ' ;
while ( ( c = * t + + ) ! = ' \0 ' ) {
int n ;
/* "isprint()" might depend on locale so use brute force. */
if ( c < ' ' | | c > ' ~ ' ) c = ' ? ' ;
n = c - 32 ;
* b + + = ( n / 10 ) + ' 0 ' ;
* b + + = ( n % 10 ) + ' 0 ' ;
* b = ' \0 ' ;
}
return ( errors ) ;
} /* end tt_text_to_ascii2d */
2015-07-27 00:35:07 +00:00
/*------------------------------------------------------------------
*
* Name : tt_multipress_to_text
*
* Purpose : Convert the multi - press representation to text .
*
* Inputs : buttons - Input string .
* Should contain only 01234567 89 A .
*
* quiet - True to suppress error messages .
*
* Outputs : text - Converted to letters , digits , space .
*
* Returns : Number of errors detected .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2015-11-08 01:57:02 +00:00
int tt_multipress_to_text ( const char * buttons , int quiet , char * text )
2015-07-27 00:35:07 +00:00
{
2015-11-08 01:57:02 +00:00
const char * b = buttons ;
2015-07-27 00:35:07 +00:00
char * t = text ;
char c ;
int row , col ;
int errors = 0 ;
int maxspan ;
int n ;
* t = ' \0 ' ;
while ( ( c = * b + + ) ! = ' \0 ' ) {
if ( isdigit ( c ) ) {
/* Determine max that can occur in a row. */
/* = number of other characters assigned to this button + 1. */
maxspan = 1 ;
row = c - ' 0 ' ;
for ( col = 0 ; col < 4 ; col + + ) {
if ( translate [ row ] [ col ] ! = 0 ) {
maxspan + + ;
}
}
/* Count number of consecutive same digits. */
n = 1 ;
while ( c = = * b ) {
b + + ;
n + + ;
}
if ( n < maxspan ) {
* t + + = translate [ row ] [ n - 1 ] ;
* t = ' \0 ' ;
}
else if ( n = = maxspan ) {
* t + + = c ;
* t = ' \0 ' ;
}
else {
errors + + ;
if ( ! quiet ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " Multi-press to text: Maximum of %d \" %c \" can occur in a row. \n " , maxspan , c ) ;
}
/* Treat like the maximum length. */
* t + + = c ;
* t = ' \0 ' ;
}
}
else if ( c = = ' A ' | | c = = ' a ' ) {
/* Separator should occur only if digit before and after are the same. */
if ( b = = buttons + 1 | | * b = = ' \0 ' | | * ( b - 2 ) ! = * b ) {
errors + + ;
if ( ! quiet ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " Multi-press to text: \" A \" can occur only between two same digits. \n " ) ;
}
}
}
else {
/* Completely unexpected character. */
errors + + ;
if ( ! quiet ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " Multi-press to text: \" %c \" not allowed. \n " , c ) ;
}
}
}
return ( errors ) ;
} /* end tt_multipress_to_text */
/*------------------------------------------------------------------
*
* Name : tt_two_key_to_text
*
* Purpose : Convert the two key representation to text .
*
* Inputs : buttons - Input string .
* Should contain only 01234567 89 ABCD .
*
* quiet - True to suppress error messages .
*
* Outputs : text - Converted to letters , digits , space .
*
* Returns : Number of errors detected .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2015-11-08 01:57:02 +00:00
int tt_two_key_to_text ( const char * buttons , int quiet , char * text )
2015-07-27 00:35:07 +00:00
{
2015-11-08 01:57:02 +00:00
const char * b = buttons ;
2015-07-27 00:35:07 +00:00
char * t = text ;
char c ;
int row , col ;
int errors = 0 ;
* t = ' \0 ' ;
while ( ( c = * b + + ) ! = ' \0 ' ) {
if ( isdigit ( c ) ) {
/* Letter (or space) if followed by ABCD. */
row = c - ' 0 ' ;
col = - 1 ;
if ( * b > = ' A ' & & * b < = ' D ' ) {
col = * b + + - ' A ' ;
}
else if ( * b > = ' a ' & & * b < = ' d ' ) {
col = * b + + - ' a ' ;
}
if ( col > = 0 ) {
if ( translate [ row ] [ col ] ! = 0 ) {
* t + + = translate [ row ] [ col ] ;
* t = ' \0 ' ;
}
else {
errors + + ;
if ( ! quiet ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " Two key to text: Invalid combination \" %c%c \" . \n " , c , col + ' A ' ) ;
}
}
}
else {
* t + + = c ;
* t = ' \0 ' ;
}
}
else if ( ( c > = ' A ' & & c < = ' D ' ) | | ( c > = ' a ' & & c < = ' d ' ) ) {
/* ABCD not expected here. */
errors + + ;
if ( ! quiet ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " Two-key to text: A, B, C, or D in unexpected location. \n " ) ;
}
}
else {
/* Completely unexpected character. */
errors + + ;
if ( ! quiet ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " Two-key to text: Invalid character \" %c \" . \n " , c ) ;
}
}
}
return ( errors ) ;
} /* end tt_two_key_to_text */
2015-09-07 23:56:20 +00:00
/*------------------------------------------------------------------
*
* Name : tt_two_digits_to_letter
*
* Purpose : Convert the two digit representation to one letter .
*
* Inputs : buttons - Input string .
* Should contain exactly two digits .
*
* quiet - True to suppress error messages .
2015-11-08 01:57:02 +00:00
*
* textsiz - Size of result storage . Typically 2.
2015-09-07 23:56:20 +00:00
*
* Outputs : text - Converted to string which should contain one upper case letter .
2015-11-08 01:57:02 +00:00
* Empty string on error .
2015-09-07 23:56:20 +00:00
*
* Returns : Number of errors detected .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2015-11-08 01:57:02 +00:00
int tt_two_digits_to_letter ( const char * buttons , int quiet , char * text , size_t textsiz )
2015-09-07 23:56:20 +00:00
{
char c1 = buttons [ 0 ] ;
char c2 = buttons [ 1 ] ;
int row , col ;
int errors = 0 ;
2015-11-08 01:57:02 +00:00
char stemp2 [ 2 ] ;
2015-09-07 23:56:20 +00:00
2015-11-08 01:57:02 +00:00
strlcpy ( text , " " , textsiz ) ;
2015-09-07 23:56:20 +00:00
if ( c1 > = ' 2 ' & & c1 < = ' 9 ' ) {
if ( c2 > = ' 1 ' & & c2 < = ' 4 ' ) {
row = c1 - ' 0 ' ;
col = c2 - ' 1 ' ;
if ( translate [ row ] [ col ] ! = 0 ) {
2015-11-08 01:57:02 +00:00
stemp2 [ 0 ] = translate [ row ] [ col ] ;
stemp2 [ 1 ] = ' \0 ' ;
strlcpy ( text , stemp2 , textsiz ) ;
2015-09-07 23:56:20 +00:00
}
else {
errors + + ;
2015-11-08 01:57:02 +00:00
strlcpy ( text , " " , textsiz ) ;
2015-09-07 23:56:20 +00:00
if ( ! quiet ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " Two digits to letter: Invalid combination \" %c%c \" . \n " , c1 , c2 ) ;
}
}
}
else {
errors + + ;
2015-11-08 01:57:02 +00:00
strlcpy ( text , " " , textsiz ) ;
2015-09-07 23:56:20 +00:00
if ( ! quiet ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " Two digits to letter: Second character \" %c \" must be in range of 1 through 4. \n " , c2 ) ;
}
}
}
else {
errors + + ;
2015-11-08 01:57:02 +00:00
strlcpy ( text , " " , textsiz ) ;
2015-09-07 23:56:20 +00:00
if ( ! quiet ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " Two digits to letter: First character \" %c \" must be in range of 2 through 9. \n " , c1 ) ;
}
}
return ( errors ) ;
} /* end tt_two_digits_to_letter */
2015-07-27 01:17:23 +00:00
/*------------------------------------------------------------------
*
* Name : tt_call10_to_text
*
* Purpose : Convert the 10 digit callsign representation to text .
*
* Inputs : buttons - Input string .
* Should contain only ten digits .
*
* quiet - True to suppress error messages .
*
* Outputs : text - Converted to callsign with upper case letters and digits .
*
* Returns : Number of errors detected .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2015-11-08 01:57:02 +00:00
int tt_call10_to_text ( const char * buttons , int quiet , char * text )
2015-07-27 01:17:23 +00:00
{
2015-11-08 01:57:02 +00:00
const char * b ;
2015-07-27 01:17:23 +00:00
char * t ;
char c ;
int packed ; /* from last 4 digits */
int row , col ;
int errors = 0 ;
int k ;
t = text ;
* t = ' \0 ' ; /* result */
/* Validity check. */
if ( strlen ( buttons ) ! = 10 ) {
if ( ! quiet ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " Callsign 6+4 to text: Encoded Callsign \" %s \" must be exactly 10 digits. \n " , buttons ) ;
}
errors + + ;
return ( errors ) ;
}
for ( b = buttons ; * b ! = ' \0 ' ; b + + ) {
if ( ! isdigit ( * b ) ) {
if ( ! quiet ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " Callsign 6+4 to text: Encoded Callsign \" %s \" can contain only digits. \n " , buttons ) ;
}
errors + + ;
return ( errors ) ;
}
}
packed = atoi ( buttons + 6 ) ;
for ( k = 0 ; k < 6 ; k + + ) {
c = buttons [ k ] ;
row = c - ' 0 ' ;
col = ( packed > > ( ( 5 - k ) * 2 ) ) & 3 ;
if ( row < 0 | | row > 9 | | col < 0 | | col > 3 ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " Callsign 6+4 to text: INTERNAL ERROR %d %d. Should not be here. \n " , row , col ) ;
errors + + ;
row = 0 ;
col = 1 ;
}
if ( call10encoding [ row ] [ col ] ! = 0 ) {
* t + + = call10encoding [ row ] [ col ] ;
* t = ' \0 ' ;
}
else {
errors + + ;
if ( ! quiet ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " Callsign 6+4 to text: Invalid combination: button %d, position %d. \n " , row , col ) ;
}
}
}
/* Trim any trailing spaces. */
k = strlen ( text ) - 1 ; /* should be 6 - 1 = 5 */
while ( k > = 0 & & text [ k ] = = ' ' ) {
text [ k ] = ' \0 ' ;
k - - ;
}
return ( errors ) ;
} /* end tt_call10_to_text */
2015-12-24 20:25:13 +00:00
/*------------------------------------------------------------------
*
* Name : tt_call5_suffix_to_text
*
* Purpose : Convert the 5 digit APRStt 3 style callsign suffix
* representation to text .
*
* Inputs : buttons - Input string .
* Should contain exactly 5 digits .
*
* quiet - True to suppress error messages .
*
* Outputs : text - Converted to 3 upper case letters and / or digits .
*
* Returns : Number of errors detected .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int tt_call5_suffix_to_text ( const char * buttons , int quiet , char * text )
{
const char * b ;
char * t ;
char c ;
int packed ; /* from last 4 digits */
int row , col ;
int errors = 0 ;
int k ;
t = text ;
* t = ' \0 ' ; /* result */
/* Validity check. */
if ( strlen ( buttons ) ! = 5 ) {
if ( ! quiet ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " Callsign 3+2 suffix to text: Encoded Callsign \" %s \" must be exactly 5 digits. \n " , buttons ) ;
}
errors + + ;
return ( errors ) ;
}
for ( b = buttons ; * b ! = ' \0 ' ; b + + ) {
if ( ! isdigit ( * b ) ) {
if ( ! quiet ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " Callsign 3+2 suffix to text: Encoded Callsign \" %s \" can contain only digits. \n " , buttons ) ;
}
errors + + ;
return ( errors ) ;
}
}
packed = atoi ( buttons + 3 ) ;
for ( k = 0 ; k < 3 ; k + + ) {
c = buttons [ k ] ;
row = c - ' 0 ' ;
col = ( packed > > ( ( 2 - k ) * 2 ) ) & 3 ;
if ( row < 0 | | row > 9 | | col < 0 | | col > 3 ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " Callsign 3+2 suffix to text: INTERNAL ERROR %d %d. Should not be here. \n " , row , col ) ;
errors + + ;
row = 0 ;
col = 1 ;
}
if ( call10encoding [ row ] [ col ] ! = 0 ) {
* t + + = call10encoding [ row ] [ col ] ;
* t = ' \0 ' ;
}
else {
errors + + ;
if ( ! quiet ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " Callsign 3+2 suffix to text: Invalid combination: button %d, position %d. \n " , row , col ) ;
}
}
}
if ( errors > 0 ) {
strcpy ( text , " " ) ;
return ( errors ) ;
}
return ( errors ) ;
} /* end tt_call5_suffix_to_text */
2015-07-27 01:17:23 +00:00
/*------------------------------------------------------------------
*
2015-09-07 23:56:20 +00:00
* Name : tt_mhead_to_text
2015-07-27 01:17:23 +00:00
*
2015-11-08 01:57:02 +00:00
* Purpose : Convert the DTMF representation of
* Maidenhead Grid Square Locator to normal text representation .
2015-09-07 23:56:20 +00:00
*
* Inputs : buttons - Input string .
2015-11-08 01:57:02 +00:00
* Must contain 4 , 6 , 10 , or 12 , 16 , or 18 digits .
2015-09-07 23:56:20 +00:00
*
* quiet - True to suppress error messages .
*
* Outputs : text - Converted to gridsquare with upper case letters and digits .
* Length should be 2 , 4 , 6 , or 8 with alternating letter or digit pairs .
2015-11-08 01:57:02 +00:00
* Zero length if any error .
2015-09-07 23:56:20 +00:00
*
* Returns : Number of errors detected .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2015-11-08 01:57:02 +00:00
# define MAXMHPAIRS 6
static const struct {
char * position ;
char min_ch ;
char max_ch ;
} mhpair [ MAXMHPAIRS ] = {
{ " first " , ' A ' , ' R ' } ,
{ " second " , ' 0 ' , ' 9 ' } ,
{ " third " , ' A ' , ' X ' } ,
{ " fourth " , ' 0 ' , ' 9 ' } ,
{ " fifth " , ' A ' , ' X ' } ,
{ " sixth " , ' 0 ' , ' 9 ' }
} ;
2015-09-07 23:56:20 +00:00
2015-11-08 01:57:02 +00:00
int tt_mhead_to_text ( const char * buttons , int quiet , char * text , size_t textsiz )
2015-09-07 23:56:20 +00:00
{
2015-11-08 01:57:02 +00:00
const char * b ;
2015-09-07 23:56:20 +00:00
int errors = 0 ;
2015-11-08 01:57:02 +00:00
strlcpy ( text , " " , textsiz ) ;
2015-09-07 23:56:20 +00:00
/* Validity check. */
2015-11-08 01:57:02 +00:00
if ( strlen ( buttons ) ! = 4 & & strlen ( buttons ) ! = 6 & &
strlen ( buttons ) ! = 10 & & strlen ( buttons ) ! = 12 & &
strlen ( buttons ) ! = 16 & & strlen ( buttons ) ! = 18 ) {
2015-09-07 23:56:20 +00:00
if ( ! quiet ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " DTMF to Maidenhead Gridsquare Locator: Input \" %s \" must be exactly 4, 6, 10, or 12 digits. \n " , buttons ) ;
}
errors + + ;
2015-11-08 01:57:02 +00:00
strlcpy ( text , " " , textsiz ) ;
2015-09-07 23:56:20 +00:00
return ( errors ) ;
}
for ( b = buttons ; * b ! = ' \0 ' ; b + + ) {
if ( ! isdigit ( * b ) ) {
if ( ! quiet ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " DTMF to Maidenhead Gridsquare Locator: Input \" %s \" can contain only digits. \n " , buttons ) ;
}
errors + + ;
2015-11-08 01:57:02 +00:00
strlcpy ( text , " " , textsiz ) ;
2015-09-07 23:56:20 +00:00
return ( errors ) ;
}
}
2015-11-08 01:57:02 +00:00
/* Convert DTMF to normal representation. */
2015-09-07 23:56:20 +00:00
2015-11-08 01:57:02 +00:00
b = buttons ;
2015-09-07 23:56:20 +00:00
2015-11-08 01:57:02 +00:00
int n ;
2015-09-07 23:56:20 +00:00
2015-11-08 01:57:02 +00:00
for ( n = 0 ; n < 6 & & b < buttons + strlen ( buttons ) ; n + + ) {
if ( ( n % 2 ) = = 0 ) {
2015-09-07 23:56:20 +00:00
2015-11-08 01:57:02 +00:00
/* Convert pairs of digits to letter. */
2015-09-07 23:56:20 +00:00
2015-11-08 01:57:02 +00:00
char t2 [ 2 ] ;
errors + = tt_two_digits_to_letter ( b , quiet , t2 , sizeof ( t2 ) ) ;
strlcat ( text , t2 , textsiz ) ;
2015-09-07 23:56:20 +00:00
b + = 2 ;
2015-11-08 01:57:02 +00:00
errors + = tt_two_digits_to_letter ( b , quiet , t2 , sizeof ( t2 ) ) ;
strlcat ( text , t2 , textsiz ) ;
2015-09-07 23:56:20 +00:00
b + = 2 ;
2015-11-08 01:57:02 +00:00
}
else {
2015-09-07 23:56:20 +00:00
2015-11-08 01:57:02 +00:00
/* Copy the digits. */
2015-09-07 23:56:20 +00:00
2015-11-08 01:57:02 +00:00
char d3 [ 3 ] ;
d3 [ 0 ] = * b + + ;
d3 [ 1 ] = * b + + ;
d3 [ 2 ] = ' \0 ' ;
strlcat ( text , d3 , textsiz ) ;
2015-09-07 23:56:20 +00:00
}
}
2015-11-08 01:57:02 +00:00
if ( errors ! = 0 ) {
strlcpy ( text , " " , textsiz ) ;
}
2015-09-07 23:56:20 +00:00
return ( errors ) ;
} /* end tt_mhead_to_text */
/*------------------------------------------------------------------
*
* Name : tt_text_to_mhead
*
2015-11-08 01:57:02 +00:00
* Purpose : Convert normal text Maidenhead Grid Square Locator to DTMF representation .
2015-09-07 23:56:20 +00:00
*
2015-11-08 01:57:02 +00:00
* Inputs : text - Maidenhead Grid Square locator in usual format .
* Length should be 1 to 6 pairs with alternating letter or digit pairs .
2015-09-07 23:56:20 +00:00
*
2015-11-08 01:57:02 +00:00
* quiet - True to suppress error messages .
*
* buttonsize - space available for ' buttons ' result .
*
* Outputs : buttons - Result with 4 , 6 , 10 , 12 , 16 , 18 digits .
2015-09-07 23:56:20 +00:00
* Each letter is replaced by two digits .
2015-11-08 01:57:02 +00:00
* Digits are simply copied .
2015-09-07 23:56:20 +00:00
*
* Returns : Number of errors detected .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2015-11-08 01:57:02 +00:00
int tt_text_to_mhead ( const char * text , int quiet , char * buttons , size_t buttonsize )
2015-09-07 23:56:20 +00:00
{
int errors = 0 ;
2015-11-08 01:57:02 +00:00
int np , i ;
2015-09-07 23:56:20 +00:00
2015-11-08 01:57:02 +00:00
strlcpy ( buttons , " " , buttonsize ) ;
2015-09-07 23:56:20 +00:00
2015-11-08 01:57:02 +00:00
np = strlen ( text ) / 2 ;
2015-09-07 23:56:20 +00:00
2015-11-08 01:57:02 +00:00
if ( ( strlen ( text ) % 2 ) ! = 0 ) {
2015-09-07 23:56:20 +00:00
if ( ! quiet ) {
text_color_set ( DW_COLOR_ERROR ) ;
2015-11-08 01:57:02 +00:00
dw_printf ( " Maidenhead Gridsquare Locator to DTMF: Input \" %s \" must be even number of characters. \n " , text ) ;
2015-09-07 23:56:20 +00:00
}
errors + + ;
return ( errors ) ;
}
2015-11-08 01:57:02 +00:00
if ( np < 1 | | np > MAXMHPAIRS ) {
2015-09-07 23:56:20 +00:00
if ( ! quiet ) {
2015-11-08 01:57:02 +00:00
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " Maidenhead Gridsquare Locator to DTMF: Input \" %s \" must be 1 to %d pairs of characters. \n " , text , np ) ;
2015-09-07 23:56:20 +00:00
}
2015-11-08 01:57:02 +00:00
errors + + ;
return ( errors ) ;
}
2015-09-07 23:56:20 +00:00
2015-11-08 01:57:02 +00:00
for ( i = 0 ; i < np ; i + + ) {
2015-09-07 23:56:20 +00:00
2015-11-08 01:57:02 +00:00
char t0 = text [ i * 2 ] ;
char t1 = text [ i * 2 + 1 ] ;
2015-09-07 23:56:20 +00:00
2015-11-08 01:57:02 +00:00
if ( toupper ( t0 ) < mhpair [ i ] . min_ch | | toupper ( t0 ) > mhpair [ i ] . max_ch | |
toupper ( t1 ) < mhpair [ i ] . min_ch | | toupper ( t1 ) > mhpair [ i ] . max_ch ) {
2015-09-07 23:56:20 +00:00
if ( ! quiet ) {
text_color_set ( DW_COLOR_ERROR ) ;
2015-11-08 01:57:02 +00:00
dw_printf ( " The %s pair of characters in Maidenhead locator \" %s \" must be in range of %c thru %c. \n " ,
mhpair [ i ] . position , text , mhpair [ i ] . min_ch , mhpair [ i ] . max_ch ) ;
2015-09-07 23:56:20 +00:00
}
2015-11-08 01:57:02 +00:00
strlcpy ( buttons , " " , buttonsize ) ;
2015-09-07 23:56:20 +00:00
errors + + ;
return ( errors ) ;
}
2015-11-08 01:57:02 +00:00
if ( mhpair [ i ] . min_ch = = ' A ' ) { /* Should be letters */
2015-09-07 23:56:20 +00:00
2015-11-08 01:57:02 +00:00
char b3 [ 3 ] ;
2015-09-07 23:56:20 +00:00
2015-11-08 01:57:02 +00:00
errors + = tt_letter_to_two_digits ( t0 , quiet , b3 ) ;
strlcat ( buttons , b3 , buttonsize ) ;
2015-09-07 23:56:20 +00:00
2015-11-08 01:57:02 +00:00
errors + = tt_letter_to_two_digits ( t1 , quiet , b3 ) ;
strlcat ( buttons , b3 , buttonsize ) ;
}
else { /* Should be digits */
2015-09-07 23:56:20 +00:00
2015-11-08 01:57:02 +00:00
char b3 [ 3 ] ;
2015-09-07 23:56:20 +00:00
2015-11-08 01:57:02 +00:00
b3 [ 0 ] = t0 ;
b3 [ 1 ] = t1 ;
b3 [ 2 ] = ' \0 ' ;
strlcat ( buttons , b3 , buttonsize ) ;
2015-09-07 23:56:20 +00:00
}
}
2015-11-08 01:57:02 +00:00
if ( errors ! = 0 ) strlcpy ( buttons , " " , buttonsize ) ;
2015-09-07 23:56:20 +00:00
return ( errors ) ;
} /* tt_text_to_mhead */
/*------------------------------------------------------------------
*
* Name : tt_satsq_to_text
*
* Purpose : Convert the 4 digit DTMF special Satellite gridsquare to normal 2 letters and 2 digits .
2015-07-27 01:17:23 +00:00
*
* Inputs : buttons - Input string .
* Should contain 4 digits .
*
* quiet - True to suppress error messages .
*
* Outputs : text - Converted to gridsquare with upper case letters and digits .
*
* Returns : Number of errors detected .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2015-11-08 01:57:02 +00:00
int tt_satsq_to_text ( const char * buttons , int quiet , char * text )
2015-07-27 01:17:23 +00:00
{
2015-11-08 01:57:02 +00:00
const char * b ;
2015-07-27 01:17:23 +00:00
int row , col ;
int errors = 0 ;
strcpy ( text , " " ) ;
/* Validity check. */
if ( strlen ( buttons ) ! = 4 ) {
if ( ! quiet ) {
text_color_set ( DW_COLOR_ERROR ) ;
2015-09-07 23:56:20 +00:00
dw_printf ( " DTMF to Satellite Gridsquare: Input \" %s \" must be exactly 4 digits. \n " , buttons ) ;
2015-07-27 01:17:23 +00:00
}
errors + + ;
return ( errors ) ;
}
for ( b = buttons ; * b ! = ' \0 ' ; b + + ) {
if ( ! isdigit ( * b ) ) {
if ( ! quiet ) {
text_color_set ( DW_COLOR_ERROR ) ;
2015-09-07 23:56:20 +00:00
dw_printf ( " DTMF to Satellite Gridsquare: Input \" %s \" can contain only digits. \n " , buttons ) ;
2015-07-27 01:17:23 +00:00
}
errors + + ;
return ( errors ) ;
}
}
row = buttons [ 0 ] - ' 0 ' ;
col = buttons [ 1 ] - ' 0 ' ;
strcpy ( text , grid [ row ] [ col ] ) ;
strcat ( text , buttons + 2 ) ;
return ( errors ) ;
2015-09-07 23:56:20 +00:00
} /* end tt_satsq_to_text */
2015-07-27 01:17:23 +00:00
2015-12-06 15:09:27 +00:00
/*------------------------------------------------------------------
*
* Name : tt_ascii2d_to_text
*
* Purpose : Convert the two digit ascii representation back to normal text .
*
* Inputs : buttons - Input string .
* Should contain pairs of digits in range 00 to 94.
*
* quiet - True to suppress error messages .
*
* Outputs : text - Converted to any printable ascii characters .
*
* Returns : Number of errors detected .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int tt_ascii2d_to_text ( const char * buttons , int quiet , char * text )
{
const char * b = buttons ;
char * t = text ;
char c1 , c2 ;
int errors = 0 ;
* t = ' \0 ' ;
while ( * b ! = ' \0 ' ) {
c1 = * b + + ;
if ( * b ! = ' \0 ' ) {
c2 = * b + + ;
}
else {
c2 = ' ' ;
}
if ( isdigit ( c1 ) & & isdigit ( c2 ) ) {
int n ;
n = ( c1 - ' 0 ' ) * 10 + ( c2 - ' 0 ' ) ;
* t + + = n + 32 ;
* t = ' \0 ' ;
}
else {
/* Unexpected character. */
errors + + ;
if ( ! quiet ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " ASCII2D to text: Invalid character pair \" %c%c \" . \n " , c1 , c2 ) ;
}
}
}
return ( errors ) ;
} /* end tt_ascii2d_to_text */
2015-07-27 00:35:07 +00:00
/*------------------------------------------------------------------
*
* Name : tt_guess_type
*
* Purpose : Try to guess which encoding we have .
*
* Inputs : buttons - Input string .
* Should contain only 01234567 89 ABCD .
*
* Returns : TT_MULTIPRESS - Looks like multipress .
* TT_TWO_KEY - Looks like two key .
* TT_EITHER - Could be either one .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
typedef enum { TT_EITHER , TT_MULTIPRESS , TT_TWO_KEY } tt_enc_t ;
tt_enc_t tt_guess_type ( char * buttons )
{
char text [ 256 ] ;
int err_mp ;
int err_tk ;
/* If it contains B, C, or D, it can't be multipress. */
if ( strchr ( buttons , ' B ' ) ! = NULL | | strchr ( buttons , ' b ' ) ! = NULL | |
strchr ( buttons , ' C ' ) ! = NULL | | strchr ( buttons , ' c ' ) ! = NULL | |
strchr ( buttons , ' D ' ) ! = NULL | | strchr ( buttons , ' d ' ) ! = NULL ) {
return ( TT_TWO_KEY ) ;
}
/* Try parsing quietly and see if one gets errors and the other doesn't. */
err_mp = tt_multipress_to_text ( buttons , 1 , text ) ;
err_tk = tt_two_key_to_text ( buttons , 1 , text ) ;
if ( err_mp = = 0 & & err_tk > 0 ) {
return ( TT_MULTIPRESS ) ;
}
else if ( err_tk = = 0 & & err_mp > 0 ) {
return ( TT_TWO_KEY ) ;
}
/* Could be either one. */
return ( TT_EITHER ) ;
} /* end tt_guess_type */
/*------------------------------------------------------------------
*
* Name : main
*
* Purpose : Utility program for testing the encoding .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
# if ENC_MAIN
int checksum ( char * tt )
{
int cs = 10 ; /* Assume leading 'A'. */
/* Doesn't matter due to mod 10 at the end. */
char * p ;
for ( p = tt ; * p ! = ' \0 ' ; p + + ) {
if ( isdigit ( * p ) ) {
cs + = * p - ' 0 ' ;
}
else if ( isupper ( * p ) ) {
cs + = * p - ' A ' + 10 ;
}
else if ( islower ( * p ) ) {
cs + = * p - ' a ' + 10 ;
}
}
return ( cs % 10 ) ;
}
int main ( int argc , char * argv [ ] )
{
char text [ 1000 ] , buttons [ 2000 ] ;
int n ;
int cs ;
text_color_set ( DW_COLOR_INFO ) ;
if ( argc < 2 ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " Supply text string on command line. \n " ) ;
exit ( 1 ) ;
}
strcpy ( text , argv [ 1 ] ) ;
for ( n = 2 ; n < argc ; n + + ) {
strcat ( text , " " ) ;
strcat ( text , argv [ n ] ) ;
}
dw_printf ( " Push buttons for multi-press method: \n " ) ;
n = tt_text_to_multipress ( text , 0 , buttons ) ;
cs = checksum ( buttons ) ;
dw_printf ( " \" %s \" checksum for call = %d \n " , buttons , cs ) ;
dw_printf ( " Push buttons for two-key method: \n " ) ;
n = tt_text_to_two_key ( text , 0 , buttons ) ;
cs = checksum ( buttons ) ;
dw_printf ( " \" %s \" checksum for call = %d \n " , buttons , cs ) ;
2015-07-27 01:17:23 +00:00
n = tt_text_to_call10 ( text , 1 , buttons ) ;
if ( n = = 0 ) {
dw_printf ( " Push buttons for fixed length 10 digit callsign: \n " ) ;
dw_printf ( " \" %s \" \n " , buttons ) ;
}
2015-11-08 01:57:02 +00:00
n = tt_text_to_mhead ( text , 1 , buttons , sizeof ( buttons ) ) ;
2015-09-07 23:56:20 +00:00
if ( n = = 0 ) {
dw_printf ( " Push buttons for Maidenhead Grid Square Locator: \n " ) ;
dw_printf ( " \" %s \" \n " , buttons ) ;
}
2015-11-08 01:57:02 +00:00
n = tt_text_to_satsq ( text , 1 , buttons , sizeof ( buttons ) ) ;
2015-07-27 01:17:23 +00:00
if ( n = = 0 ) {
2015-09-07 23:56:20 +00:00
dw_printf ( " Push buttons for satellite gridsquare: \n " ) ;
2015-07-27 01:17:23 +00:00
dw_printf ( " \" %s \" \n " , buttons ) ;
}
2015-07-27 00:35:07 +00:00
return ( 0 ) ;
} /* end main */
# endif /* encoding */
/*------------------------------------------------------------------
*
* Name : main
*
* Purpose : Utility program for testing the decoding .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
# if DEC_MAIN
int main ( int argc , char * argv [ ] )
{
char buttons [ 2000 ] , text [ 1000 ] ;
int n ;
text_color_set ( DW_COLOR_INFO ) ;
if ( argc < 2 ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " Supply button sequence on command line. \n " ) ;
exit ( 1 ) ;
}
strcpy ( buttons , argv [ 1 ] ) ;
for ( n = 2 ; n < argc ; n + + ) {
2015-11-08 01:57:02 +00:00
strlcat ( buttons , argv [ n ] , sizeof ( buttons ) ) ;
2015-07-27 00:35:07 +00:00
}
switch ( tt_guess_type ( buttons ) ) {
case TT_MULTIPRESS :
dw_printf ( " Looks like multi-press encoding. \n " ) ;
break ;
case TT_TWO_KEY :
dw_printf ( " Looks like two-key encoding. \n " ) ;
break ;
default :
dw_printf ( " Could be either type of encoding. \n " ) ;
break ;
}
dw_printf ( " Decoded text from multi-press method: \n " ) ;
n = tt_multipress_to_text ( buttons , 0 , text ) ;
dw_printf ( " \" %s \" \n " , text ) ;
dw_printf ( " Decoded text from two-key method: \n " ) ;
n = tt_two_key_to_text ( buttons , 0 , text ) ;
dw_printf ( " \" %s \" \n " , text ) ;
2015-07-27 01:17:23 +00:00
n = tt_call10_to_text ( buttons , 1 , text ) ;
if ( n = = 0 ) {
dw_printf ( " Decoded callsign from 10 digit method: \n " ) ;
dw_printf ( " \" %s \" \n " , text ) ;
}
2015-11-08 01:57:02 +00:00
n = tt_mhead_to_text ( buttons , 1 , text , sizeof ( text ) ) ;
2015-09-07 23:56:20 +00:00
if ( n = = 0 ) {
dw_printf ( " Decoded Maidenhead Locator from DTMF digits: \n " ) ;
dw_printf ( " \" %s \" \n " , text ) ;
}
n = tt_satsq_to_text ( buttons , 1 , text ) ;
2015-07-27 01:17:23 +00:00
if ( n = = 0 ) {
2015-09-07 23:56:20 +00:00
dw_printf ( " Decoded satellite gridsquare from 4 DTMF digits: \n " ) ;
2015-07-27 01:17:23 +00:00
dw_printf ( " \" %s \" \n " , text ) ;
}
2015-07-27 00:35:07 +00:00
return ( 0 ) ;
} /* end main */
# endif /* decoding */
2015-11-08 01:57:02 +00:00
# if TTT_TEST
/* gcc -g -DTTT_TEST tt_text.c textcolor.o misc.a && ./a.exe */
/* Quick unit test. */
static int error_count ;
static void test_text2tt ( char * text , char * expect_mp , char * expect_2k , char * expect_c10 , char * expect_loc , char * expect_sat )
{
char buttons [ 100 ] ;
text_color_set ( DW_COLOR_INFO ) ;
dw_printf ( " \n Convert from text \" %s \" to tone sequence. \n " , text ) ;
tt_text_to_multipress ( text , 0 , buttons ) ;
if ( strcmp ( buttons , expect_mp ) ! = 0 ) { error_count + + ; text_color_set ( DW_COLOR_ERROR ) ; dw_printf ( " Expected multi-press \" %s \" but got \" %s \" \n " , expect_mp , buttons ) ; }
tt_text_to_two_key ( text , 0 , buttons ) ;
if ( strcmp ( buttons , expect_2k ) ! = 0 ) { error_count + + ; text_color_set ( DW_COLOR_ERROR ) ; dw_printf ( " Expected two-key \" %s \" but got \" %s \" \n " , expect_2k , buttons ) ; }
tt_text_to_call10 ( text , 0 , buttons ) ;
if ( strcmp ( buttons , expect_c10 ) ! = 0 ) { error_count + + ; text_color_set ( DW_COLOR_ERROR ) ; dw_printf ( " Expected call 6+4 \" %s \" but got \" %s \" \n " , expect_c10 , buttons ) ; }
tt_text_to_mhead ( text , 0 , buttons , sizeof ( buttons ) ) ;
if ( strcmp ( buttons , expect_loc ) ! = 0 ) { error_count + + ; text_color_set ( DW_COLOR_ERROR ) ; dw_printf ( " Expected Maidenhead \" %s \" but got \" %s \" \n " , expect_loc , buttons ) ; }
tt_text_to_satsq ( text , 0 , buttons , sizeof ( buttons ) ) ;
if ( strcmp ( buttons , expect_sat ) ! = 0 ) { error_count + + ; text_color_set ( DW_COLOR_ERROR ) ; dw_printf ( " Expected Sat Sq \" %s \" but got \" %s \" \n " , expect_sat , buttons ) ; }
}
static void test_tt2text ( char * buttons , char * expect_mp , char * expect_2k , char * expect_c10 , char * expect_loc , char * expect_sat )
{
char text [ 100 ] ;
text_color_set ( DW_COLOR_INFO ) ;
dw_printf ( " \n Convert tone sequence \" %s \" to text. \n " , buttons ) ;
tt_multipress_to_text ( buttons , 0 , text ) ;
if ( strcmp ( text , expect_mp ) ! = 0 ) { error_count + + ; text_color_set ( DW_COLOR_ERROR ) ; dw_printf ( " Expected multi-press \" %s \" but got \" %s \" \n " , expect_mp , text ) ; }
tt_two_key_to_text ( buttons , 0 , text ) ;
if ( strcmp ( text , expect_2k ) ! = 0 ) { error_count + + ; text_color_set ( DW_COLOR_ERROR ) ; dw_printf ( " Expected two-key \" %s \" but got \" %s \" \n " , expect_2k , text ) ; }
tt_call10_to_text ( buttons , 0 , text ) ;
if ( strcmp ( text , expect_c10 ) ! = 0 ) { error_count + + ; text_color_set ( DW_COLOR_ERROR ) ; dw_printf ( " Expected call 6+4 \" %s \" but got \" %s \" \n " , expect_c10 , text ) ; }
tt_mhead_to_text ( buttons , 0 , text , sizeof ( text ) ) ;
if ( strcmp ( text , expect_loc ) ! = 0 ) { error_count + + ; text_color_set ( DW_COLOR_ERROR ) ; dw_printf ( " Expected Maidenhead \" %s \" but got \" %s \" \n " , expect_loc , text ) ; }
tt_satsq_to_text ( buttons , 0 , text ) ;
if ( strcmp ( text , expect_sat ) ! = 0 ) { error_count + + ; text_color_set ( DW_COLOR_ERROR ) ; dw_printf ( " Expected Sat Sq \" %s \" but got \" %s \" \n " , expect_sat , text ) ; }
}
int main ( int argc , char * argv [ ] )
{
text_color_set ( DW_COLOR_INFO ) ;
dw_printf ( " Test conversions between normal text and DTMF representation. \n " ) ;
dw_printf ( " Some error messages are normal. Just look for number of errors at end. \n " ) ;
error_count = 0 ;
/* original text multipress two-key call10 mhead satsq */
test_text2tt ( " abcdefg 0123 " , " 2A22A2223A33A33340A00122223333 " , " 2A2B2C3A3B3C4A0A0123 " , " " , " " , " " ) ;
test_text2tt ( " WB4APR " , " 922444427A777 " , " 9A2B42A7A7C " , " 9242771558 " , " " , " " ) ;
test_text2tt ( " EM29QE78 " , " 3362222999997733777778888 " , " 3B6A297B3B78 " , " " , " 326129723278 " , " " ) ;
test_text2tt ( " FM19 " , " 3336199999 " , " 3C6A19 " , " 3619003333 " , " 336119 " , " 1819 " ) ;
/* tone_seq multipress two-key call10 mhead satsq */
test_tt2text ( " 2A22A2223A33A33340A00122223333 " , " ABCDEFG 0123 " , " A2A222D3D3334 00122223333 " , " " , " " , " " ) ;
test_tt2text ( " 9242771558 " , " WAGAQ1KT " , " 9242771558 " , " WB4APR " , " " , " " ) ;
test_tt2text ( " 326129723278 " , " DAM1AWPADAPT " , " 326129723278 " , " " , " EM29QE78 " , " " ) ;
test_tt2text ( " 1819 " , " 1T1W " , " 1819 " , " " , " " , " FM19 " ) ;
if ( error_count > 0 ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " \n ERROR: %d tests failed. \n " , error_count ) ;
exit ( EXIT_FAILURE ) ;
}
text_color_set ( DW_COLOR_REC ) ;
dw_printf ( " \n SUCCESS! All tests passed. \n " ) ;
exit ( EXIT_SUCCESS ) ;
} /* end main */
# endif
2015-07-27 00:35:07 +00:00
2015-11-08 01:57:02 +00:00
/* end tt_text.c */
2015-07-27 00:35:07 +00:00