SpeakJet /TTS Serial Question

I have searched and can't figure this out

I have a basic sketch for reading from the serial port and sending it to the TTS chip which sends to the speakjet. I am using the sparkfun voice shield with the TTS chip in the proto area.

Problem is I can't send commands from serial. It works if I do a println but not from the serial.

For example speakjet.println("Test\375"); that works but if i type Test\375 from the serial monitor it speaks the \ 3 7 5. (375 is the code for 253 for gunshot sound per example in http://www.sparkfun.com/datasheets/Components/General/TTS256_Datasheet_prelim.pdf

It doesn't read the escape character correctly.

Below is my code. This is based on the Sparkfun example, I removed my LCD code.

/*
Testing Sketch for Robot
*/

//Soft serial library used to send serial commands on pin 2 instead of regular serial pin.
#include <SoftwareSerial.h>

//Define the Pin Numbers of the Voicebox shield for the sketch.
#define E0  5
#define E1  6
#define E2  7
#define E3  8
#define E4  9
#define E5  10
#define E6  11
#define E7  12

#define RDY  13
#define RES  3
#define SPK  4

//Pin 2 of the shield should be wired to the TTS256 chip.
#define txPin  2

//Create a SoftSerial Object to send strings to the TTS256 chip.
SoftwareSerial speakjet = SoftwareSerial(0, txPin);

//Create a message buffer to hold the ascii message to be converted to sound
char message[128]="";

void setup()  
{
  //Configure the pins for the SpeakJet module
  pinMode(txPin, OUTPUT);
  pinMode(SPK, INPUT);
  
  //Set up a serial port to talk from Arduino to the SpeakJet module on pin 3.
  speakjet.begin(9600);    
  
  //Set up a serial port to get the ascii message from the host
  Serial.begin(9600);
  
  //Configure the Ready pin as an input
  pinMode(RDY, INPUT);
  
  //Configure Reset line as an output
  pinMode(RES, OUTPUT);
       
  //Configure all of the Event pins as outputs from Arduino, and set them Low.
  for(int i=E0; i<=E7; i++)
  {
    pinMode(i, OUTPUT);
    digitalWrite(i, LOW);
  }
  
  //All I/O pins are configured. Reset the SpeakJet module
  digitalWrite(RES, LOW);
  delay(100);
  digitalWrite(RES, HIGH);
  delay(1000);
  char sounds[] = {200, 201, 202, 203, 220, 221, 222};
  speakjet.println(sounds);
  //speakjet.println("Test\375"); // This works for sending commands inline
  
}

void loop()
{  
  //Get a message from the serial port
  getMessage(message);
  
  //Send the message to the TTS256
  speakjet.println(message);
  Serial.println(message);
  print(message);
  print(" ");
  
  
  //Wait 12ms before checking the ready line (specified in TTS256 datasheet)
  delay(12);
  //Wait for the Speakjet to become 'ready' before sending more text.
  while(digitalRead(RDY)==0);
}

//Function: getMessage(char *)
//Description: Retrieves a string from the Serial port. Doesn't return the string until a carriage return character is detected.
//Inputs: None
//Outputs: char * message - The message received on the serial port.
//Returns: Nothing
//usage: getMessage(english_sentance);
void getMessage(char * message)
{
    char in_char=0;    //Create a character to store the incoming byte from the serial port.
    //Wait for a character to come into the serial port
    while(Serial.available() <=0);
    //Copy the incoming character to our variable.
    in_char=Serial.read();
    //Keep retreiving characters until the 'end of sentance(0x0D)' character is received.
    while(in_char != 0x0D){
        *message++=in_char;    //Every time we receive a character we should add the character to the message string.
        while(Serial.available() <=0);    //Now wait for the next character...
        in_char = Serial.read();            //and copy it to the variable again.
    }
   *message='\0';    //Strings must end with a Null terminator so we need to add this to our message.
    return;
}

Thanks.

For example speakjet.println("Test\375"); that works but if i type Test\375 from the serial monitor it speaks the \ 3 7 5.

When the compiler runs, it sees the \375 in the string, and substitutes a different value. The string that is passed to the speakjet.println function does not contain a \ and the characters 3, 7, and 5.

In your code to read from the serial port, you need to make that same substitution. The value following the \ is an octal value.

375 base 8 is 253 base 10.

I had tried that as well as other codes it still just speaks it instead of the making the sound for the code. Any more ideas?

I had tried that as well as other codes it still just speaks it instead of the making the sound for the code. Any more ideas?

Where is the code that converts \375 to 253 for sending to the speaker chip?

That happens on the TTS per the linked documentation above. Either way if I type in the actually code it doesn't work. The TTS has to read that and send it to the speakjet as a code.

ASCII code 253 (375 in base 8) does not correspond to a key you can type, like A, f, 5, or @. So, you have to define the code as \375, which is not the same as '', '3', '7', '5'.

When the Arduino reads '', '3', '7', and '5' from the serial port, it needs to see that as an escape sequence, and print something different to the speaker chip.

You keep saying "yeah, I know that", but you have not shown any code that understands that \ is the start of an escape sequence, rather than just another character.

Do you have such code that you are unwilling to share, or do you not understand that YOU have to write such code?

I guess I am not understanding correctly. So I have to parse the array and look for \ and interpret it that? I thought the TTS would take care of that since the direct println works.

I thought the TTS would take care of that since the direct println works.

No, the compiler does the parsing when storing the data in memory. You need to do the parsing in your code for the serial input.

What would I convert it to?

What would I convert it to?

Probably from octal to decimal, and use the speaker.write() function (hopefully there is one) to send the decimal value.

See if there is a write() function. If there is, try writing 253 to the chip, in setup() or loop(), to see that it processes the value correctly.

Looks like write() isn't available in the software serial. Any other ideas?

I am using a Mega2560 so I could try and reroute the TTS RX to the one of the real Serial ports. Only want to do that if that will solve my problem though.

Does the speakjet class derive from Serial or Print? Does the print() method support optional 2nd arguments, like Serial.print() does? If so, speakjet.print(val, BYTE); could be used.

Thanks that might work.

On a side note I haven't done C++ in so long I am having a hard time reading though the array to search for \ (hex 0x5C).

After the getmessage routine get the all the characters I cycle through it again to look for it. But doesn't seem to work. The way the char array is setup can you use message[x] to search each position?

Thanks

I tested using BYTE and that will work if I can separate out the '\200' from the message.

Thanks.

I am going to try to separate out the code while they they being read from serial.

I got it to work! Thanks for all the help. Here is the new code if anyone ever needs it.

As part of testing I switched to Newsoftserial, but both work. Not sure which I should stay with. I read something about it and servos which i will be using.

/*
Testing Sketch for Robot
*/

//Soft serial library used to send serial commands on pin 2 instead of regular serial pin.
#include <NewSoftSerial.h>

//Define the Pin Numbers of the Voicebox shield for the sketch.
#define E0  5
#define E1  6
#define E2  7
#define E3  8
#define E4  9
#define E5  10
#define E6  11
#define E7  12

#define RDY  13
#define RES  3
#define SPK  4

//Pin 2 of the shield should be wired to the TTS256 chip.
#define txPin  2

//Create a SoftSerial Object to send strings to the TTS256 chip.
NewSoftSerial speakjet(0, txPin);

//Create a message buffer to hold the ascii message to be converted to sound
char message[128]="";
char cmd[3]="";
int cmdCode;

void setup()  
{
  //Configure the pins for the SpeakJet module
  pinMode(txPin, OUTPUT);
  pinMode(SPK, INPUT);
  
  //Set up a serial port to talk from Arduino to the SpeakJet module on pin 3.
  speakjet.begin(9600);    
  
  //Set up a serial port to get the ascii message from the host
  Serial.begin(9600);
  
  //Configure the Ready pin as an input
  pinMode(RDY, INPUT);
  
  //Configure Reset line as an output
  pinMode(RES, OUTPUT);
       
  //Configure all of the Event pins as outputs from Arduino, and set them Low.
  for(int i=E0; i<=E7; i++)
  {
    pinMode(i, OUTPUT);
    digitalWrite(i, LOW);
  }
  
  //All I/O pins are configured. Reset the SpeakJet module
  digitalWrite(RES, LOW);
  delay(100);
  digitalWrite(RES, HIGH);
  delay(1000);
  char sounds[] = {200, 201, 202, 203, 220, 221, 222};
  speakjet.println(sounds);

  

 
  
}

void loop()
{  
  //Get a message from the serial port
  getMessage(message, cmd);
  
  //Convert cmd from char to int
  cmdCode = atoi(cmd);
    
  //Send the message to the TTS256
  speakjet.println(message);
  delay(1000);
  while(digitalRead(RDY)==0);
  speakjet.println(cmdCode, BYTE);
  Serial.println(message);

  
  
  //Wait 12ms before checking the ready line (specified in TTS256 datasheet)
  delay(12);
  //Wait for the Speakjet to become 'ready' before sending more text.
  while(digitalRead(RDY)==0);
  
}

//Function: getMessage(char *)
//Description: Retrieves a string from the Serial port. Doesn't return the string until a carriage return character is detected.
//Inputs: None
//Outputs: char * message - The message received on the serial port.
//Returns: Nothing
//usage: getMessage(english_sentance);
void getMessage(char * message, char * cmd)
{
    char in_char=0;    //Create a character to store the incoming byte from the serial port.
    //Wait for a character to come into the serial port
    while(Serial.available() <=0);
    //Copy the incoming character to our variable.
    in_char=Serial.read();
    //Keep retreiving characters until the 'end of sentance(0x0D)' character is received.
    while(in_char != 0x0D){
        if (in_char == 0x5C)
        {
          while (in_char != 0x0D){
          while(Serial.available() <=0);    //Now wait for the next character...
          in_char = Serial.read();     
          *cmd++=in_char;
          }
        }
        else {
        *message++=in_char;    //Every time we receive a character we should add the character to the message string.
        while(Serial.available() <=0);    //Now wait for the next character...
        in_char = Serial.read();            //and copy it to the variable again.
    }
    }
   *message='\0';    //Strings must end with a Null terminator so we need to add this to our message.
   *cmd='\0';
   
   
  
    return;
}

I thought I would take it step further and try to handle multiple codes. So much for that. I changed the while loop to a for loop since all codes are 3 digits.

Is it possible to convert the code to a BYTE and insert it into the message char array so that it is sent inline? So that it is all sent at once and not to prints to serial?

EDIT: I figured it out, now I can read codes and insert then into the message array as a int, therefore having multiples codes and they are inline when it speaks back.

Here is the fine code

/*
Testing Sketch for Robot
*/

//Soft serial library used to send serial commands on pin 2 instead of regular serial pin.
#include <NewSoftSerial.h>

//Define the Pin Numbers of the Voicebox shield for the sketch.
#define E0  5
#define E1  6
#define E2  7
#define E3  8
#define E4  9
#define E5  10
#define E6  11
#define E7  12

#define RDY  13
#define RES  3
#define SPK  4

//Pin 2 of the shield should be wired to the TTS256 chip.
#define txPin  2

//Create a SoftSerial Object to send strings to the TTS256 chip.
NewSoftSerial speakjet(0, txPin);

//Create a message buffer to hold the ascii message to be converted to sound
char message[128]="";
char message2[128]="";

void setup()  
{
  //Configure the pins for the SpeakJet module
  pinMode(txPin, OUTPUT);
  pinMode(SPK, INPUT);
  
  //Set up a serial port to talk from Arduino to the SpeakJet module on pin 3.
  speakjet.begin(9600);    
  
  //Set up a serial port to get the ascii message from the host
  Serial.begin(9600);
  
  //Configure the Ready pin as an input
  pinMode(RDY, INPUT);
  
  //Configure Reset line as an output
  pinMode(RES, OUTPUT);
       
  //Configure all of the Event pins as outputs from Arduino, and set them Low.
  for(int i=E0; i<=E7; i++)
  {
    pinMode(i, OUTPUT);
    digitalWrite(i, LOW);
  }
  
  //All I/O pins are configured. Reset the SpeakJet module
  digitalWrite(RES, LOW);
  delay(100);
  digitalWrite(RES, HIGH);
  delay(1000);
  char sounds[] = {200, 201, 202, 203, 220, 221, 222};
  speakjet.println(sounds);

  

 
  
}

void loop()
{  
  //Get a message from the serial port
  getMessage(message, message2);
  
  //Send the message to the TTS256
  speakjet.println(message);
  Serial.println(message2);
  print(message2);
  print(" ");
  
  
  //Wait 12ms before checking the ready line (specified in TTS256 datasheet)
  delay(12);
  //Wait for the Speakjet to become 'ready' before sending more text.
  while(digitalRead(RDY)==0);
  
}

//Function: getMessage(char *)
//Description: Retrieves a string from the Serial port. Doesn't return the string until a carriage return character is detected.
//Inputs: None
//Outputs: char * message - The message received on the serial port.
//Returns: Nothing
//usage: getMessage(english_sentance);
void getMessage(char * message, char * message2)
{
    char cmd[4]="";
    char in_char=0;    //Create a character to store the incoming byte from the serial port.
    //Wait for a character to come into the serial port
    while(Serial.available() <=0);
    //Copy the incoming character to our variable.
    in_char=Serial.read();
    //Keep retreiving characters until the 'end of sentance(0x0D)' character is received.
    while(in_char != 0x0D){
        if (in_char == 0x5C)
        {
          for(int i = 0; i <= 2; i++){
          while(Serial.available() <=0);    //Now wait for the next character...
          in_char = Serial.read();     
          cmd[i]=in_char;
          }
        
         int code = atoi(cmd);
         Serial.println(code);
         *message++=code;
          while(Serial.available() <=0);
          in_char = Serial.read();
        }
        else {
        *message++=in_char;    //Every time we receive a character we should add the character to the message string.
        *message2++=in_char;
        while(Serial.available() <=0);    //Now wait for the next character...
        in_char = Serial.read();            //and copy it to the variable again.
    }
    }
   *message='\0';    //Strings must end with a Null terminator so we need to add this to our message.
   *message2='\0';

   
   
  
    return;
}

The 2nd message array is so I can display the text to the serial and lcd without the codes.