// text2code - prepare Morse code bytes from user input text
//
// Started: September 7, 2015  G. D. (Joe) Young <jyoung@islandnet.com>
//
// Revised: Sep 8/15 - use newline for end-of-input instead of \
//          Jan 24/16 - correct size of ihex[ ] allow input >15 characters
//          Aug 14/16 - text2codeUS - measure callsign duration in dots
//          Aug 14/16 - include one spaced item in length (to incl de ...)
//          Aug 27/16 - omit de - US ID only requires bare call sign at end.
//                    - Calc msec at 20 wpm (dot length = 1200/wpm)
//
// A utility to prepare the data required for loading into the eeprom of
// the ATtiny85 minifox controller. Text input using serial monitor.
//
// Be sure the serial monitor is set to 'newline' for input terminator.

#include "codeTable.h"


char inputline[80];

byte lcount = 0;  // count of input characters
byte errfl = 0;   // return from parsing functions

char ihex[ 2*80+10 ];

byte cksum = 0;
byte codeChar;
bool high = true;
bool low = false;
boolean fatalerror = false;
byte calocn = 0;  // location of callsign in input string
byte calocnp = 0; // location of penultimate space
byte nrdots = 0;  // length of callsign in dot durations

char byte2hex( byte b, bool hi ) {
  if( hi ) {
    b = (b>>4)&0x0f;
  } else {
    b = b&0x0f;
  }
  if( b < 10 ) {
    return( 0x30 | b );
  } else {
    return( 0x41 + (b-10) );
  }
} // byte2hex( )

byte mslen( char *as ) {

  byte dots = 0;
  
  if( *as == 0 ) return 0;
  for( byte ix = 0; ix < strlen( as ); ix++ ) {
    char a = toupper(*(as+ix));
//    Serial.print( a );             //view input test
    byte codeChar = morseTable[ a - 0x20 ];
//    Serial.print( ' ' );
//    Serial.print( codeChar, HEX );
//    Serial.print( ' ' );

    if( codeChar == 0 ) {
      dots += 4;          // make letter sp into word sp

    } else {
      
      byte elts = 8;
      byte cmask = 0x80;
      while( elts > 0 ) {   // locate fence bit in codChar
        if( (codeChar & cmask) == 0 ) {
          elts -= 1;
          cmask = cmask>>1;
        } else {
          break;
        }
      } // while no fence bit found
      elts -= 1;
      cmask = cmask>>1;     // skip over fence
      while( elts > 0 ) {   // now add up dot length for each element
        if( (codeChar & cmask) ) {
          dots += 4;
        } else {
          dots += 2;
        }
        elts -= 1;
        cmask = cmask>>1;
      } // while examining codeChar

      dots += 2;      // inter-letter space

    } // if word space
    
  } // for length of input
  
//  return strlen( as );
  return dots;
} // mslen( )


void setup( ) {
  Serial.begin( 9600 );
  inputline[0] = 0;
  Serial.println( "enter text string - example: MOE wb6byu" );
  Serial.println( "" );
} // setup

void loop() {
  if ( Serial.available( ) > 0 ) {
    while ( Serial.available( ) && lcount < (sizeof(inputline)) ) {
      inputline[lcount] = toupper( Serial.read( ) );
      if( inputline[lcount] == ' ' ) {
        calocnp = calocn;
        calocn = lcount;
      }
      if ( inputline[lcount] == '\n' ) break;
      Serial.print( inputline[lcount], HEX );
      Serial.print( ' ' );
      lcount++;
    } // while input
    if ( inputline[lcount] == '\n' ) {
      inputline[lcount] = 0;
      Serial.println( "   input as ASCII hex" );
      //      Serial.println( "" );
      for ( byte ix = 0; ix < lcount; ix++ ) {
        codeChar = morseTable[ inputline[ix] - 0x20 ];
        cksum += codeChar;
        ihex[2 * ix + 9] = byte2hex( codeChar, high ); //build ihex as translating
        ihex[2 * ix + 10] = byte2hex( codeChar, low );
//        Serial.print( codeChar, HEX );
        Serial.print( ihex[2*ix + 9] );
        Serial.print( ihex[2*ix + 10] );
        Serial.print( ' ' );
      }
      Serial.println( "   input as code bytes" );
      size_t ccount = strlen( inputline ); // omits terminator(s)
      Serial.print( inputline );
      Serial.print( "   input line as encoded   char count = " );
      Serial.println( ccount );
      Serial.println( "" );

//      Serial.print( inputline+calocnp+1 );  // to include the de
      Serial.print( inputline+calocn+1 );
      Serial.print( "   callsign, length in dots " );
//      nrdots = mslen( inputline+calocnp+1 );
      nrdots = mslen( inputline+calocn+1 );
      Serial.print( nrdots );
      Serial.print( "  " );
      Serial.print( nrdots * 60 );
      Serial.println( " msec at 20 wpm" );
      Serial.println( "" );

      // Then finally emit intel-hex version
      // finish up the intel-hex string
      ihex[0] = ':';
      ihex[1] = byte2hex( ccount + 2, high ); //+1 to allow for fence, length bytes
      ihex[2] = byte2hex( ccount + 2, low );
      cksum += ccount + 2;
      ihex[3] = '0';
      ihex[4] = '0';
      ihex[5] = '0';
      ihex[6] = '0';
      ihex[7] = '0';
      ihex[8] = '0';
      ihex[2 * ccount + 9] = 'F';    // terminator fence byte in case ee not unprogrammed
      ihex[2 * ccount + 10] = 'F';
      cksum += 0xff;
      ihex[2 * ccount + 11] = byte2hex( nrdots, high );
      ihex[2 * ccount + 12] = byte2hex( nrdots, low );
      cksum += nrdots;
      ihex[13 + 2 * ccount] = byte2hex( ~cksum + 1, high );
      ihex[14 + 2 * ccount] = byte2hex( ~cksum + 1, low );
      ihex[15 + 2 * ccount] = 0;
      Serial.println( "intel-hex file format (with added 0xff terminator):" );
      Serial.println( ihex );

      // emit an end record to complete a valid intel-hex file
      Serial.println( ":00000001FF" );
      Serial.println( "" );
      Serial.println( "" );

      cksum = 0;
      lcount = 0;               // prepare to get a new line
    } // if end of line
  } // if input available


}
