iBreathe Breathalyzer can now talk thanks to the Text to Speech Click Board

Dependencies:   Hexi_KW40Z Hexi_OLED_SSD1351 text_to_speak_mbed

Fork of iBreathe_Breathalyzer by Dave Clarke

Revision:
9:fe5114551ec3
Parent:
7:5d272a0e250b
--- a/main.cpp	Wed Sep 28 11:12:05 2016 +0000
+++ b/main.cpp	Fri Oct 07 20:09:39 2016 +0000
@@ -1,14 +1,16 @@
 /****************************************************************************
 * Title                 :   iBreathe Breathalyzer
-* Filename              :   breathalyzer
+* Filename              :   Talking_breathalyzer
 * Author                :   Dave Clarke
 * Origin Date           :   27/09/2016
-* Notes                 :   Breathalyzer utilizing Hexiware, Alcohol click and Wolksense
+* Notes                 :   Breathalyzer utilizing Hexiware, Alcohol click and 
+                            Wolksense. Now with added voice thanks to the 
+                            Text-To-Speech Click board
 *****************************************************************************/
 /**************************CHANGE LIST **************************************
 *
 *    Date    Software Version    Initials       Description
-*  27/09/16       1.0.0            DC        Interface Created.
+*  07/10/16       1.0.0            DC        Interface Created.
 *
 *****************************************************************************/
 
@@ -21,6 +23,7 @@
  * <li><b> Dev. Board    </b> :      HEXIWEAR                     </li>
  * <li><b> Oscillator    </b> :      12 MHz external              </li>
  * <li><b> Ext. Modules  </b> :      Alcohol Click on mikroBUS 1  </li>
+ * <li><b> Ext. Modules  </b> :      TTS Click on mikroBUS 2      </li>
  * <li><b> SW            </b> :      mBed OS5    </li>
  * </ul>
  */
@@ -31,9 +34,10 @@
  * @par This will show you how much you've drunk and tell you with an Emoticon if
  * you're too hammered to even consider driving. Using the Hexiware app the readings
  * are transmitted to the cloud via bluetooth. Is it time to give up drinking yet?!
+ * It now talks to you! 
  
  * <h3> Alcohol Features </h3>
- * @par Alcohol click, Hexiwear docking station, Hexiware
+ * @par Text to Speech Click, Alcohol click, Hexiwear docking station, Hexiware
  */
 
 /******************************************************************************
@@ -47,6 +51,11 @@
 #include "OpenSans_Font.h"
 #include "string.h"
 #include "iBreatheImages.h"
+#include "text_to_speech.h"
+#include "text_to_speech_hal.h"
+#include "text_to_speech_hw.h"
+#include "text_to_speech_img.h"
+
 
 /******************************************************************************
 * Module Variable Definitions
@@ -87,12 +96,49 @@
                 value1[20]; // initial sensor set up values
 
 bool            isFirstBoot = true;                   
-                
+              
+
+/* Indication Flags */
+static volatile bool        _tts_rdy_f;
+static volatile bool        _spc_rdy_f;
+static volatile bool        _tts_fin_f;
+static volatile bool        _spc_fin_f;
+
+/* Error Buffers */
+static uint16_t             _req_err;
+static uint16_t             _err_code;
 
+/* Default Configuration */
+static ACONF_t              _audio_conf;
+static TTSCONF_t            _tts_conf;
+static PMANCONF_t           _pman_conf;
+
+static bool                 _flush_enable;
+
+/* Timer flag and counter */
+static volatile bool        _ticker_f;
+static volatile uint16_t    _ticker;
+
+/* Input and output buffers */
+static  ISC_REQ_t   _last_req;
+static  ISC_RESP_t  _last_rsp;
+
+static uint8_t test[ 8 ] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+int frequency = 750000;
+VER_t *version;
 /******************************************************************************
 * Function Prototypes
 *******************************************************************************/
+/* Checks for indications */
+static int _parse_ind( void );
 
+/* Message block and error callback function pointers */
+static void ( *_fatal_err_callback )( uint16_t *err_code );
+static void ( *_err_callback )( uint16_t *err_code );
+static void ( *_msg_block_callback )( uint16_t *msg_code,
+                                      uint16_t *err_code ); 
+
+void voiceinit(void);
 void sysinit(void);
 void ReadSensor();
 void CalculatePPM(int times, bool amb);
@@ -101,10 +147,14 @@
 void StopHaptic(void const *n);
 void ButtonUp(void);
 void txTask(void);
+void fatal_err( uint16_t *err );
+void msg_blk( uint16_t *req, uint16_t *err );
 
 /******************************************************************************
 * Instance setups
 *******************************************************************************/
+
+
 /* Define timer for haptic feedback */
 RtosTimer hapticTimer(StopHaptic, osTimerOnce);
 
@@ -126,6 +176,18 @@
 DigitalOut blueLed(LED3);
 DigitalOut haptic(PTB9);
 
+/* Instantiate the Click Text to Speech pinout */ 
+DigitalOut TTS_RST(PTB19);
+DigitalOut TTS_CS(PTC3);
+DigitalOut TTS_MUTE(PTB3);
+DigitalIn  TTS_RDY(PTB8);
+
+//Instantiate SPI for comms with Speak module
+SPI TextToSpeech(PTC6, PTC7, PTC5); // MOSI, MISO, SCK
+
+// Debug Serial
+Serial pc(USBTX, USBRX);
+
 /******************************************************************************
 * Bluetooth button functions and passkey function
 *******************************************************************************/
@@ -167,6 +229,8 @@
 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
 int main()
 {
+   
+     
      /* Set pointers to the BMPs stored in  iBreatheImages.c */
      welcome = iBreatheWS_bmp;    // Welcome screen image 
      blank = iBreatheBlank_bmp;   // blank image
@@ -176,9 +240,17 @@
      hang = iBreatheHang_bmp;    // You'll have a hangover image
      ini = iBreatheini_bmp;     // Initialising image
      sober = iBreatheSober_bmp;   // Sober as a judge image
-       
-     /* Set initial Values */
-     sysinit();
+     
+    /* Set initial Values */
+     sysinit(); 
+    
+    /* initialise voice engine */  
+     voiceinit();
+     
+    /* Welcome message on reset */    
+     tts_speak( "Hello, welcome to the eye brethalizer " );
+     wait(0.5);
+     tts_speak( "please press start.  " ); 
 }
 
 /******************************************************************************
@@ -363,14 +435,16 @@
         isFirstBoot = false;
     }
     
+    
     /*read ambient atmosphere levels with 10 samples and set flag to show it's ambient basline figure*/
+    tts_speak( "initializing" );
     ambient(10);
     CalculatePPM(10,Ref);
     
     
     /* Fill 96px by 96px Screen with 96px by 96px Blowing Image starting at x=0,y=0 */  
     oled.DrawImage(blow,0,0);
-    
+    tts_speak( "please blow until buzzing stops" );
     /*read breathe alcohol levels with 10 samples and set flag to show it's breathilyzer test figure*/
     CalculatePPM(10,Test);
     
@@ -385,12 +459,18 @@
     
     /* Fill 96px by 96px Screen with 96px by 96px Blank Background Image starting at x=0,y=0 */
     oled.DrawImage(blank,0,0);     
-    
+    tts_speak( "Test Complete" );
+    Thread::wait(500);
     /* Show Calculated alcohol level in PPM and send data via bluetooth to the cloud */
     oled.SetTextProperties(&textProperties);
     oled.Label(ppmText,20,36);
+    tts_speak( "you blew" );
     sprintf(text,"%.2f",ppm);
+    Thread::wait(50);
+    tts_speak( text );
     oled.Label((uint8_t *)text,50,36);
+    Thread::wait(50);
+    tts_speak( "pee pee emm" );
     Thread::wait(1000);
     
     /* Currently sending to the Pressure variable as a temp place holder */
@@ -401,6 +481,7 @@
     /* You've got a Hangover coming!*/
     if ( ppm > 200)
     {
+        tts_speak("you have got a hang over coming");
         redLed      = LED_ON;
         greenLed    = LED_OFF;
         blueLed     = LED_OFF;
@@ -414,6 +495,7 @@
     /* You Shouldn't drive */
     else if (ppm < 200 && ppm > 150)
     {
+        tts_speak("you shouldn't drive");
         redLed      = LED_ON;
         greenLed    = LED_OFF;
         blueLed     = LED_ON;
@@ -427,6 +509,7 @@
     /* You've had a drink */
     else if (ppm < 150 && ppm > 50)
     {
+        tts_speak("you have had a drinky");
         redLed      = LED_OFF;
         greenLed    = LED_ON;
         blueLed     = LED_ON;
@@ -440,6 +523,7 @@
     /* Sober as a judge*/   
     else
     {
+        tts_speak("you are as sober as a judge");
         redLed      = LED_OFF;
         greenLed    = LED_ON;
         blueLed     = LED_OFF;
@@ -465,7 +549,7 @@
 **************************************************************************************************/
 void sysinit(void)
 {
-    /* Set LED to Blue by default*/      
+     /* Set LED to Blue by default*/      
     redLed      = LED_OFF;
     greenLed    = LED_OFF;
     blueLed     = LED_ON;
@@ -489,4 +573,1269 @@
     oled.GetTextProperties(&textProperties); 
     textProperties.fontColor   = COLOR_WHITE;
     oled.SetTextProperties(&textProperties);
-}
\ No newline at end of file
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**************************************************************************************************
+* Function void voiceinit(void)
+* -------------------------------------------------------------------------------------------------
+* Overview: initialise voice engine
+* Input: None
+* Output: None
+**************************************************************************************************/
+void voiceinit(void)
+{
+    
+    /*setting up the SPI defaults*/
+    TextToSpeech.lock();
+    TextToSpeech.format(8,3);
+    TextToSpeech.frequency(frequency);
+    TextToSpeech.unlock();
+    
+    /* initialise voice */
+    pc.printf("System Init Done!\r\n");
+    tts_init();
+    pc.printf("tts Init Done!\r\n");
+    tts_setup();
+    pc.printf("tts setup Done!\r\n");
+    tts_msg_block_callback( msg_blk );
+    tts_fatal_err_callback( fatal_err );
+    tts_config( 0x10, false, TTSV_US, 0x0080 );
+    tts_unmute();
+    
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**************************************************************************************************
+* Function msg_blk( uint16_t *req, uint16_t *err )
+* -------------------------------------------------------------------------------------------------
+* Overview: receive a blocked message from  S1V30120;
+**************************************************************************************************/
+void msg_blk( uint16_t *req, uint16_t *err )
+{
+    char txt[ 6 ];
+    
+    pc.printf( " MSG BLOCKED \r\n" );
+    sprintf( txt, "%x\r\n", *req );
+    pc.printf( txt );
+    sprintf( txt, "%x\r\n", *err );
+    pc.printf( txt );
+}
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**************************************************************************************************
+* Function fatal_err( uint16_t *err )
+* -------------------------------------------------------------------------------------------------
+* Overview: error detected
+**************************************************************************************************/
+void fatal_err( uint16_t *err )
+{
+    pc.printf( "Fatal Error Detected" );
+    tts_init();
+    tts_fatal_err_callback( fatal_err );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**************************************************************************************************
+* text_to_speech_hal.c
+* -------------------------------------------------------------------------------------------------
+* Overview: Functions to control SPI interface.
+**************************************************************************************************/
+
+void tts_hal_cs_high()
+{
+    
+    TTS_CS = 1;
+}
+
+void tts_hal_cs_low()
+{
+    TTS_CS = 0;
+    
+}
+
+void tts_hal_mut_high()
+{
+    TTS_MUTE = 1;
+}
+
+void tts_hal_mut_low()
+{
+    TTS_MUTE = 0;
+}
+
+void tts_hal_reset( void )
+{
+    tts_hal_cs_high();
+    TTS_RST = 0;
+    tts_hal_write_pad(1);
+    wait(0.01);
+    TTS_RST = 1;
+    wait(POR_TIME);
+}
+
+bool tts_hal_msg_rdy( void )
+{
+    return TTS_RDY;
+}
+
+void tts_hal_init()
+{
+    tts_hal_reset();
+    tts_hal_cs_high();
+    tts_hal_mut_low();
+}
+
+void tts_hal_write( uint8_t *buffer,
+                    uint16_t count, bool boot )
+{
+    TextToSpeech.lock();
+    while( count-- )
+    {
+        if(!boot)
+            pc.printf("%02X\r\n", *buffer);
+        
+        TextToSpeech.write( *buffer++  );
+        
+     }   
+    TextToSpeech.unlock();
+}
+
+
+void tts_hal_write_pad( int cnt )
+{
+    TextToSpeech.lock();
+    tts_hal_cs_low();
+    while(cnt--)
+    {
+         TextToSpeech.write( PADDING_BYTE );
+    }  
+
+    tts_hal_cs_high();
+    TextToSpeech.unlock();
+}
+
+void tts_hal_read( uint8_t *buffer,
+                   uint16_t count )
+{
+    TextToSpeech.lock();
+    while(count--)
+    {   
+        *buffer++ = TextToSpeech.write( DUMMY_BYTE ); //read spi bus
+      
+       
+        //pc.printf("buffer = %X\n\r", *buffer);
+    }
+    TextToSpeech.unlock();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**************************************************************************************************
+* text_to_speech.c
+* -------------------------------------------------------------------------------------------------
+* Overview: Functions to control the setup and speech controls
+**************************************************************************************************/
+
+static int _parse_ind( void )
+{
+    uint16_t rsp_idx = tts_rsp_idx();
+    if ( rsp_idx == ISC_MSG_BLOCKED_RESP )
+    {
+        uint8_t rsp_data[ 4 ] = { 0 };
+
+        _req_err = 0;
+        _err_code = 0;
+
+        tts_rsp_data( rsp_data );
+
+        _req_err |= rsp_data[ 0 ];
+        _req_err |= rsp_data[ 1 ] << 8;
+        _err_code |= rsp_data[ 2 ];
+        _err_code |= rsp_data[ 3 ] << 8;
+
+        if( _msg_block_callback != NULL )
+            _msg_block_callback( &_req_err, &_err_code );
+
+        return 1;
+
+    } else if ( rsp_idx == ISC_ERROR_IND ) {
+
+         uint8_t rsp_data[ 4 ] = { 0 };
+
+        _req_err = 0;
+        _err_code = 0;
+
+        tts_rsp_data( rsp_data );
+
+        _err_code |= rsp_data[ 0 ];
+        _err_code |= rsp_data[ 1 ] << 8;
+
+        if ( _err_code && _err_code < 0x8000 )
+        {
+            if( _err_callback != NULL )
+                _err_callback( &_err_code );
+
+        } else if ( _err_code && _err_code > 0x7FFF ) {
+
+            if( _fatal_err_callback != NULL )
+                _fatal_err_callback( &_err_code );
+        }
+
+        return 1;
+
+    } else if ( rsp_idx == ISC_TTS_READY_IND ) {
+
+        _tts_rdy_f = 1;
+
+    } else if ( rsp_idx == ISC_SPCODEC_READY_IND ) {
+
+        _spc_rdy_f = 1;
+
+    } else if ( rsp_idx == ISC_TTS_FINISHED_IND ) {
+
+        _tts_fin_f = 1;
+
+    } else if ( rsp_idx == ISC_SPCODEC_FINISHED_IND ) {
+
+        _spc_fin_f = 1;
+    }
+
+    return 0;
+}
+
+void tts_init()
+{
+    _req_err = 0;
+    _err_code = 0;
+
+    _tts_rdy_f = true;
+    _spc_rdy_f = true;
+    _tts_fin_f = true;
+    _spc_fin_f = true;
+
+    _audio_conf.as = 0x00;
+    _audio_conf.ag = 0x43;
+    _audio_conf.amp = 0x00;
+    _audio_conf.asr = ASR_11KHZ;
+    _audio_conf.ar = 0x00;
+    _audio_conf.atc = 0x00;
+    _audio_conf.acs = 0x00;
+    _audio_conf.dc = 0x00;
+
+    _tts_conf.sr = 0x01;
+    _tts_conf.voice = 0x00;
+    _tts_conf.ep = 0x00;
+    _tts_conf.lang = TTSV_US;
+    _tts_conf.sr_wpm_lsb = 0xc8;
+    _tts_conf.sr_wpm_msb = 0x00;
+    _tts_conf.ds = 0x00;
+    _tts_conf.res = 0x00;
+
+    _pman_conf.am_lsb = 0x01;
+    _pman_conf.am_msb = 0x00;
+    _pman_conf.spi_clk = 0x01;
+    _pman_conf.pad = PADDING_BYTE;
+
+    _flush_enable = false;
+
+    _msg_block_callback = NULL;
+    _fatal_err_callback = NULL;
+    _err_callback = NULL;
+
+    tts_hw_init();
+}
+
+void tts_msg_block_callback( void( *msg_blk_ptr )( uint16_t *req_ptr,
+                                                   uint16_t *err_ptr ) )
+{
+    _msg_block_callback = msg_blk_ptr;
+}
+
+void tts_fatal_err_callback( void( *fatal_err_ptr )( uint16_t *err_ptr ) )
+{
+    _fatal_err_callback = fatal_err_ptr;
+}
+
+void tts_err_callback( void( *error_ptr )( uint16_t *err_ptr ) )
+{
+    _err_callback = error_ptr;
+}
+
+void tts_mute()
+{
+    tts_mute_cmd( true );
+}
+
+void tts_unmute()
+{
+    tts_mute_cmd( false );
+}
+
+
+void tts_setup()
+{
+    //check HW version
+    tts_version_boot(); 
+    
+    int succ = tts_image_load( (uint8_t*)TTS_INIT_DATA, sizeof( TTS_INIT_DATA ) );
+   
+    if ( succ != 0x0001 )
+    {
+            // image load failed, try turning it off and on again
+            pc.printf("tts init data failed!\n\r");
+            pc.printf("returned value: %X\n\r", succ);
+            while(1);
+    }        
+    pc.printf("tts image load done\n\r"); 
+    succ =  tts_image_exec();
+    
+    if ( succ != 0x0001 )
+    {
+        // image boot failed, try turning it off and on again
+        pc.printf("tts image exec failed!\n\r");
+        pc.printf("returned value: %X\n\r", succ);
+        while(1);
+    } 
+    pc.printf("tts image exec done\n\r");
+    
+    tts_interface_test();
+    pc.printf("tts interface test done\n\r");
+    
+    tts_power_default_config();
+    pc.printf("tts power default done\n\r");
+    
+    tts_audio_default_config();
+    pc.printf("tts audio default done\n\r");
+    
+    tts_volume_set( 0 );
+    pc.printf("tts volume set done\n\r");
+    
+    tts_default_config();
+    pc.printf("tts default config done\n\r");
+}
+
+void tts_version_boot( void )
+{
+    
+    uint8_t tmp_resp[ 16 ] = { 0 };
+
+    wait( RESET_TO_BOOT_TIME );
+   
+    tts_parse_req( ISC_VERSION_REQ_BOOT, NULL, 0 );
+   
+    while( !tts_rsp_chk( ISC_VERSION_RESP_BOOT ) )
+    {
+        tts_get_resp();
+    }
+    tts_hal_write_pad( 16);
+    tts_rsp_data( tmp_resp );
+    pc.printf("hwver0 %X \n\r", tmp_resp[ 0 ]);
+    pc.printf("hwver1 %X \n\r", tmp_resp[ 1 ]);
+}
+
+uint16_t tts_image_load(const uint8_t *image,
+                         uint16_t count )
+{
+    uint16_t tmp_resp = 0;
+    uint16_t index = 0;
+    uint8_t raw_resp[ 2 ] = { 0 };
+   
+    while ( ( count - index ) > ( BOOT_MESSAGE_MAX - 4  ) )
+    {
+       
+       tts_parse_boot_img( image + index, BOOT_MESSAGE_MAX - 4  );
+       wait(0.01);
+       index += ( BOOT_MESSAGE_MAX - 4 );
+    }
+    tts_parse_boot_img( image + index, count - index );
+    wait(0.01);           
+    
+    while( !tts_rsp_chk( ISC_BOOT_LOAD_RESP ) )
+    {
+        tts_get_resp();
+          
+        if( _parse_ind() )
+            return _err_code;
+    }
+    tts_rsp_data( raw_resp );
+
+    tmp_resp |= raw_resp[ 0 ];
+    tmp_resp |= raw_resp[ 1 ] << 8;
+  
+    return tmp_resp;
+}
+
+uint16_t tts_image_exec()
+{
+    uint16_t tmp_resp = 0;
+    uint8_t raw_resp[ 2 ] = { 0 };
+
+    tts_parse_req( ISC_BOOT_RUN_REQ, NULL, 0 );
+     
+    while( !tts_rsp_chk( ISC_BOOT_RUN_RESP ) )
+    {
+       tts_get_resp();
+       
+        if( _parse_ind() )
+            return _err_code;
+    }
+    tts_rsp_data( raw_resp );
+
+    tmp_resp |= raw_resp[ 0 ];
+    tmp_resp |= raw_resp[ 1 ] << 8;
+
+    return  tmp_resp;
+}
+
+uint16_t tts_interface_test()
+{
+    uint16_t tmp_resp = 0;
+    uint8_t raw_resp[ 2 ] = { 0 };
+    
+    wait( BOOT_TO_MAIN_MODE );
+    
+    tts_parse_req( ISC_TEST_REQ, test, 8 );
+           
+    while( !tts_rsp_chk( ISC_TEST_RESP ) )
+    {
+        tts_get_resp();
+      
+        if( _parse_ind() )
+            return _err_code;
+    }
+
+    tts_rsp_data( raw_resp );
+
+    tmp_resp |= raw_resp[ 0 ];
+    tmp_resp |= raw_resp[ 1 ] << 8;
+
+    return tmp_resp;
+}
+
+ uint16_t tts_version_main( VER_t *buffer )
+{
+    char tmp_char[ 3 ] = { 0 };
+    uint32_t tmp_fwf = 0;
+    uint32_t tmp_fwef = 0;
+    uint8_t tmp_resp[ 20 ] = { 0 };
+
+    tts_parse_req( ISC_VERSION_REQ_MAIN, NULL, 0 );
+
+    while( !tts_rsp_chk( ISC_VERSION_RESP_MAIN ) )
+    {
+        tts_get_resp();
+
+        if( _parse_ind() )
+            return _err_code;
+    }
+
+    tts_rsp_data( tmp_resp );
+    sprintf(tmp_char, "%c", tmp_resp[ 0 ]);
+    strcpy( buffer->hwver, tmp_char );
+    strcat( buffer->hwver, "." );
+    sprintf(tmp_char, "%c", tmp_resp[ 1 ]);
+    strcat( buffer->hwver, tmp_char );
+    sprintf(tmp_char, "%c", tmp_resp[ 2 ]);
+    strcpy( buffer->fwver, tmp_char );
+    strcat( buffer->fwver, "." );
+    sprintf(tmp_char, "%c", tmp_resp[ 3 ]);
+    strcat( buffer->fwver, tmp_char );
+    strcat( buffer->fwver, "." );
+    sprintf(tmp_char, "%c", tmp_resp[ 12 ]);
+    strcat( buffer->fwver, tmp_char );
+
+    tmp_fwf |= tmp_resp[ 4 ];
+    tmp_fwf |= tmp_resp[ 5 ] << 8;
+    tmp_fwf |= tmp_resp[ 6 ] << 16;
+    tmp_fwf |= tmp_resp[ 7 ] << 24;
+    buffer->fwf = (FF_t)tmp_fwf;
+    tmp_fwef |= tmp_resp[ 8 ];
+    tmp_fwef |= tmp_resp[ 9 ] << 8;
+    tmp_fwef |= tmp_resp[ 10 ] << 16;
+    tmp_fwef |= tmp_resp[ 11 ] << 24;
+    buffer->fwef = (EFF_t)tmp_fwef;
+
+    return 0x0000;
+}
+
+uint16_t tts_power_default_config()
+{
+    uint16_t tmp_resp = 0;
+    uint8_t raw_resp[ 2 ] = { 0 };
+
+    tts_parse_req( ISC_PMAN_CONFIG_REQ, ( uint8_t* )&_pman_conf, 4 );
+
+    while( !tts_rsp_chk( ISC_PMAN_CONFIG_RESP ) )
+    {
+        tts_get_resp();
+
+        if( _parse_ind() )
+            return _err_code;
+    }
+
+    tts_rsp_data( raw_resp );
+
+    tmp_resp |= raw_resp[ 0 ];
+    tmp_resp |= raw_resp[ 1 ] << 8;
+
+    return tmp_resp;
+}
+
+uint16_t tts_standby_enter()
+{
+    uint16_t tmp_resp = 0;
+    uint8_t raw_resp[ 2 ] = { 0 };
+
+    tts_parse_req( ISC_PMAN_STANDBY_ENTRY_REQ, NULL, 0 );
+
+    while( !tts_rsp_chk( ISC_PMAN_STANDBY_ENTRY_RESP ) )
+    {
+        tts_get_resp();
+
+        if( _parse_ind() )
+            return _err_code;
+    }
+
+    tts_rsp_data( raw_resp );
+
+    tmp_resp |= raw_resp[ 0 ];
+    tmp_resp |= raw_resp[ 1 ] << 8;
+
+    return tmp_resp;
+}
+
+uint16_t tts_standby_exit()
+{
+    wait( STBY_MODE_ENTERY );
+    tts_parse_req( ISC_PMAN_STANDBY_EXIT_IND, NULL, 0 );
+
+    while( !tts_rsp_chk( ISC_PMAN_STANDBY_EXIT_IND ) )
+    {
+        tts_get_resp();
+
+        if( _parse_ind() )
+            return _err_code;
+    }
+
+    return 0x0000;
+}
+
+uint16_t tts_audio_default_config()
+{
+    uint16_t tmp_resp = 0;
+    uint8_t raw_resp[ 2 ] = { 0 };
+
+    tts_parse_req( ISC_AUDIO_CONFIG_REQ, ( uint8_t* )&_audio_conf, 8 );
+
+    while( !tts_rsp_chk( ISC_AUDIO_CONFIG_RESP ) )
+    {
+        tts_get_resp();
+
+        if( _parse_ind() )
+            return _err_code;
+    }
+
+    tts_rsp_data( raw_resp );
+
+    tmp_resp |= raw_resp[ 0 ];
+    tmp_resp |= raw_resp[ 1 ] << 8;
+
+    return tmp_resp;
+}
+
+uint16_t tts_audio_config( int8_t audio_gain,
+                           ASR_t sample_rate,
+                           bool dac_control )
+{
+    ACONF_t audio_conf;
+    uint16_t tmp_resp = 0;
+    uint8_t raw_resp[ 2 ] = { 0 };
+
+    if ( audio_gain < -48 || audio_gain > 18 )
+        return 0xFFFF;
+
+    if ( sample_rate != 0 || sample_rate != 1 || sample_rate != 3 )
+        return 0xFFFF;
+
+    audio_conf.ag = ( uint8_t )audio_gain;
+    audio_conf.asr = sample_rate;
+    audio_conf.dc = dac_control;
+
+    tts_parse_req( ISC_AUDIO_CONFIG_REQ, ( uint8_t* )&audio_conf, 8 );
+
+    while( !tts_rsp_chk( ISC_AUDIO_CONFIG_RESP ) )
+    {
+        tts_get_resp();
+
+        if( _parse_ind() )
+            return _err_code;
+    }
+
+    tts_rsp_data( raw_resp );
+
+    tmp_resp |= raw_resp[ 0 ];
+    tmp_resp |= raw_resp[ 1 ] << 8;
+
+    return tmp_resp;
+}
+
+uint16_t tts_volume_set( int16_t gain )
+{
+    uint16_t tmp_resp = 0;
+    uint8_t raw_resp[ 2 ] = { 0 };
+    uint8_t tmp_gain[ 2 ] = { 0 };
+
+    tmp_gain[ 0 ] = gain & 0x00FF;
+    tmp_gain[ 1 ] = ( gain & 0xFF00 ) >> 8;
+
+    tts_parse_req( ISC_AUDIO_VOULME_REQ, tmp_gain, 2 );
+
+    while( !tts_rsp_chk( ISC_AUDIO_VOLUME_RESP ) )
+    {
+        tts_get_resp();
+
+        if( _parse_ind() )
+            return _err_code;
+    }
+
+    tts_rsp_data( raw_resp );
+
+    tmp_resp |= raw_resp[ 0 ];
+    tmp_resp |= raw_resp[ 1 ] << 8;
+
+    return tmp_resp;
+}
+
+uint16_t tts_audio_mute()
+{
+    uint16_t tmp_resp = 0;
+    uint8_t raw_resp[ 2 ] = { 0 };
+    uint8_t tmp_mute[ 2 ] = { 1, 0 };
+
+    tts_parse_req( ISC_AUDIO_MUTE_REQ, tmp_mute, 2 );
+
+    while( !tts_rsp_chk( ISC_AUDIO_MUTE_RESP ) )
+    {
+        tts_get_resp();
+
+        if( _parse_ind() )
+            return _err_code;
+    }
+
+    tts_rsp_data( raw_resp );
+
+    tmp_resp |= raw_resp[ 0 ];
+    tmp_resp |= raw_resp[ 1 ] << 8;
+
+    return tmp_resp;
+}
+
+uint16_t tts_audio_unmute()
+{
+    uint16_t tmp_resp = 0;
+    uint8_t raw_resp[ 2 ] = { 0 };
+    uint8_t tmp_mute[ 2 ] = { 0, 0 };
+
+    tts_parse_req( ISC_AUDIO_MUTE_REQ, tmp_mute, 2 );
+
+    while( !tts_rsp_chk( ISC_AUDIO_MUTE_RESP ) )
+    {
+        tts_get_resp();
+
+        if( _parse_ind() )
+            return _err_code;
+    }
+
+    tts_rsp_data( raw_resp );
+
+    tmp_resp |= raw_resp[ 0 ];
+    tmp_resp |= raw_resp[ 1 ] << 8;
+
+    return tmp_resp;
+}
+
+uint16_t tts_default_config()
+{
+    uint16_t tmp_resp = 0;
+    uint8_t raw_resp[ 2 ] = { 0 };
+
+    tts_parse_req( ISC_TTS_CONFIG_REQ, ( uint8_t* )&_tts_conf, 8 );
+
+    while( !tts_rsp_chk( ISC_TTS_CONFIG_RESP ) )
+    {
+        tts_get_resp();
+
+        if( _parse_ind() )
+            return _err_code;
+    }
+
+    tts_rsp_data( raw_resp );
+
+    tmp_resp |= raw_resp[ 0 ];
+    tmp_resp |= raw_resp[ 1 ] << 8;
+
+    return tmp_resp;
+}
+
+uint16_t tts_config( uint8_t voice_type,
+                     bool epson_parse,
+                     TTSV_t language,
+                     uint16_t speaking_rate )
+{
+    TTSCONF_t tts_conf;
+    uint16_t tmp_resp = 0;
+    uint8_t raw_resp[ 2 ] = { 0 };
+
+    if ( voice_type > 8 )
+        return 0xFFFF;
+
+    if ( language > 4 )
+        return 0xFFFF;
+
+    if ( speaking_rate < 0x004B || speaking_rate > 0x0258 )
+        return 0xFFFF;
+
+    tts_conf.voice = voice_type;
+    tts_conf.ep = epson_parse;
+    tts_conf.lang = language;
+    tts_conf.sr_wpm_lsb = ( speaking_rate & 0x00FF );
+    tts_conf.sr_wpm_msb = ( speaking_rate & 0xFF00 ) >> 8;
+
+    tts_parse_req( ISC_TTS_CONFIG_REQ, ( uint8_t* )&tts_conf, 8 );
+
+    while( !tts_rsp_chk( ISC_TTS_CONFIG_RESP ) )
+    {
+        tts_get_resp();
+
+        if( _parse_ind() )
+            return _err_code;
+    }
+
+    tts_rsp_data( raw_resp );
+
+    tmp_resp |= raw_resp[ 0 ];
+    tmp_resp |= raw_resp[ 1 ] << 8;
+
+    return tmp_resp;
+}
+
+uint16_t tts_speak( char *word )
+{
+    bool tmp_f              = false;
+    char *wptr              = word;
+    uint8_t raw_resp[ 2 ]   = { 0 };
+    uint16_t tmp_resp       = 0;
+    uint32_t wlen           = strlen( wptr );
+
+    tts_parse_speak_req( ISC_TTS_SPEAK_REQ, _flush_enable, wptr, wlen );
+
+    _tts_rdy_f = 0;
+    _tts_fin_f = 0;
+
+    while( !( tmp_f && _tts_rdy_f ) )
+    {
+        tts_get_resp();
+
+        if( _parse_ind() )
+            return _err_code;
+
+        if( tts_rsp_chk( ISC_TTS_SPEAK_RESP ) )
+        {
+            tts_rsp_data( raw_resp );
+
+            tmp_resp |= raw_resp[ 0 ];
+            tmp_resp |= raw_resp[ 1 ] << 8;
+            tmp_f = true;
+        }
+    }
+
+    return tmp_resp;
+}
+
+uint16_t tts_pause( void )
+{
+    uint16_t tmp_resp = 0;
+    uint8_t raw_resp[ 2 ] = { 0 };
+    uint8_t tmp_pause[ 2 ] = { 1, 0 };
+
+    tts_parse_req( ISC_TTS_PAUSE_REQ, tmp_pause, 2 );
+
+    while( !tts_rsp_chk( ISC_TTS_PAUSE_RESP ) )
+    {
+        tts_get_resp();
+
+        if( _parse_ind() )
+            return _err_code;
+    }
+
+    tts_rsp_data( raw_resp );
+
+    tmp_resp |= raw_resp[ 0 ];
+    tmp_resp |= raw_resp[ 1 ] << 8;
+
+    return tmp_resp;
+}
+
+uint16_t tts_unpause( void )
+{
+    uint16_t tmp_resp = 0;
+    uint8_t raw_resp[ 2 ] = { 0 };
+    uint8_t tmp_pause[ 2 ] = { 0 };
+
+    tts_parse_req( ISC_TTS_PAUSE_REQ, tmp_pause, 2 );
+
+    while( !tts_rsp_chk( ISC_TTS_PAUSE_RESP ) )
+    {
+        tts_get_resp();
+
+        if( _parse_ind() )
+            return _err_code;
+    }
+
+    tts_rsp_data( raw_resp );
+
+    tmp_resp |= raw_resp[ 0 ];
+    tmp_resp |= raw_resp[ 1 ] << 8;
+
+    return tmp_resp;
+}
+
+uint16_t tts_stop( bool reset )
+{
+    uint16_t tmp_resp = 0;
+    uint8_t raw_resp[ 2 ] = { 0 };
+    uint8_t tmp_reset[ 2 ] = { 0 };
+
+    if( reset )
+        tmp_reset[ 0 ] = 0x01;
+
+    tts_parse_req( ISC_TTS_STOP_REQ, tmp_reset, 2 );
+
+    while( !tts_rsp_chk( ISC_TTS_STOP_RESP ) )
+    {
+        tts_get_resp();
+
+        if( _parse_ind() )
+            return _err_code;
+    }
+
+    tts_rsp_data( raw_resp );
+
+    tmp_resp |= raw_resp[ 0 ];
+    tmp_resp |= raw_resp[ 1 ] << 8;
+
+    return tmp_resp;
+}
+
+uint16_t tts_user_dict( bool erase,
+                        uint8_t *udict_data,
+                        uint16_t count )
+{
+    uint16_t cnt = 2;
+    uint16_t tmp_rsp = 0;
+    uint8_t rsp_data[ 2 ] = { 0 };
+    uint8_t tmp_data[ BOOT_MESSAGE_MAX ] = { 0 };
+
+    if ( erase )
+        tmp_data[ 0 ] = 1;
+
+    while ( count-- )
+        tmp_data[ cnt ++ ] = *( udict_data++ );
+
+    tts_parse_req( ISC_TTS_UDICT_DATA_REQ, tmp_data, count + 2 );
+
+    while( !tts_rsp_chk( ISC_TTS_UDICT_DATA_RESP ) )
+    {
+        tts_get_resp();
+
+        if( _parse_ind() )
+            return _err_code;
+    }
+
+    tts_rsp_data( rsp_data );
+
+    tmp_rsp |= rsp_data[ 0 ];
+    tmp_rsp |= rsp_data[ 1 ] << 8;
+
+    return tmp_rsp;
+}
+
+uint16_t tts_codec_configure()
+{
+    uint16_t tmp_resp = 0;
+    uint8_t raw_resp[ 2 ] = { 0 };
+    uint8_t tmp_codec[ 32 ] = { 0 };
+
+    tmp_codec[ 0 ] = 0x01;
+    tmp_codec[ 1 ] = 0x01;
+    tmp_codec[ 24 ] = 0x02;
+
+    tts_parse_req( ISC_SPCODEC_CONFIG_REQ , tmp_codec, 32 );
+
+    while( !tts_rsp_chk( ISC_SPCODEC_CONFIG_RESP ) )
+    {
+        tts_get_resp();
+
+        if( _parse_ind() )
+            return _err_code;
+    }
+
+    tts_rsp_data( raw_resp );
+
+    tmp_resp |= raw_resp[ 0 ];
+    tmp_resp |= raw_resp[ 1 ] << 8;
+
+    return tmp_resp;
+}
+
+uint16_t tts_codec_start( uint8_t *codec_data,
+                          uint16_t count )
+{
+    bool tmp_f = false;
+    uint16_t tmp_resp = 0;
+    uint8_t raw_resp[ 2 ] = { 0 };
+
+    if ( count != 512 || count != 1024 || count != 2048 )
+        return 0xFFFF;
+
+    while( !_spc_fin_f )
+    {
+        tts_get_resp();
+
+        if( _parse_ind() )
+            return _err_code;
+    }
+
+    tts_parse_req( ISC_SPCODEC_START_REQ , codec_data, count );
+
+    _spc_rdy_f = 0;
+    _spc_fin_f = 0;
+
+    while( !( tmp_f && _spc_rdy_f ) )
+    {
+        tts_get_resp();
+
+        if( _parse_ind() )
+            return _err_code;
+
+        if( tts_rsp_chk( ISC_TTS_SPEAK_RESP ) )
+        {
+            tts_rsp_data( raw_resp );
+
+            tmp_resp |= raw_resp[ 0 ];
+            tmp_resp |= raw_resp[ 1 ] << 8;
+            tmp_f = true;
+        }
+    }
+
+    return tmp_resp;
+}
+
+uint16_t tts_codec_pause()
+{
+    uint16_t tmp_resp = 0;
+    uint8_t raw_resp[ 2 ] = { 0 };
+    uint8_t tmp_data[ 2 ] = { 1, 0 };
+
+    tts_parse_req( ISC_SPCODEC_PAUSE_REQ , tmp_data, 2 );
+
+    while( !tts_rsp_chk( ISC_SPCODEC_PAUSE_RESP ) )
+    {
+        tts_get_resp();
+
+        if( _parse_ind() )
+            return _err_code;
+    }
+
+    tts_rsp_data( raw_resp );
+
+    tmp_resp |= raw_resp[ 0 ];
+    tmp_resp |= raw_resp[ 1 ] << 8;
+
+    return tmp_resp;
+}
+
+uint16_t tts_codec_unpause()
+{
+    uint16_t tmp_resp = 0;
+    uint8_t raw_resp[ 2 ] = { 0 };
+    uint8_t tmp_data[ 2 ] = { 0 };
+
+    tts_parse_req( ISC_SPCODEC_PAUSE_REQ , tmp_data, 2 );
+
+    while( !tts_rsp_chk( ISC_SPCODEC_PAUSE_RESP ) )
+    {
+        tts_get_resp();
+
+        if( _parse_ind() )
+            return _err_code;
+    }
+
+    tts_rsp_data( raw_resp );
+
+    tmp_resp |= raw_resp[ 0 ];
+    tmp_resp |= raw_resp[ 1 ] << 8;
+
+    return tmp_resp;
+}
+
+uint16_t tts_codec_stop( bool reset )
+{
+    uint16_t tmp_resp = 0;
+    uint8_t raw_resp[ 2 ] = { 0 };
+    uint8_t tmp_data[ 2 ] = { 0 };
+
+    if( reset )
+        tmp_data[ 0 ] = 1;
+
+    tts_parse_req( ISC_SPCODEC_STOP_REQ, tmp_data, 2 );
+
+    while( !tts_rsp_chk( ISC_SPCODEC_PAUSE_RESP ) )
+    {
+        tts_get_resp();
+
+        if( _parse_ind() )
+            return _err_code;
+    }
+
+    tts_rsp_data( raw_resp );
+
+    tmp_resp |= raw_resp[ 0 ];
+    tmp_resp |= raw_resp[ 1 ] << 8;
+
+    return tmp_resp;
+}
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**************************************************************************************************
+* text_to_speech_hw.c
+* -------------------------------------------------------------------------------------------------
+* Overview: Mainly read and write functions with parsing
+**************************************************************************************************/
+
+void _read_rsp()
+{
+    uint8_t tmp_byte = 0;
+    uint16_t tmp_len = 0;
+
+    tts_hal_cs_low();
+    
+    tts_hal_read( &tmp_byte, 1 );
+
+    if( tmp_byte == START_MESSAGE )
+    {
+        tts_hal_read( ( uint8_t* )&_last_rsp, 2 );
+        tmp_len |= _last_rsp.len[ 0 ];
+        tmp_len |= _last_rsp.len[ 1 ] << 8;
+        tts_hal_read( ( uint8_t* )&_last_rsp + 2, tmp_len );
+        
+    } else {
+
+        wait( 0.005 );
+    }
+   
+    tts_hal_cs_high();
+}
+
+void _write_req(bool boot)
+{
+    uint16_t cnt = 0;
+    uint8_t start = START_MESSAGE;
+
+    cnt |= _last_req.len[ 0 ];
+    cnt |= _last_req.len[ 1 ] << 8;
+    
+    tts_hal_cs_low();
+    
+    
+    if(boot) // use for debug - displays the current buffer on serial
+    {
+        tts_hal_write( &start, 1, true );
+        tts_hal_write( ( uint8_t* )&_last_req, cnt, true);
+    }
+    else
+    {
+        tts_hal_write( &start, 1, false );
+        tts_hal_write( ( uint8_t* ) &_last_req, cnt, false );
+    }    
+   
+    tts_hal_cs_high();
+    
+}
+
+/******************************************************************************
+* Public Function Definitions
+*******************************************************************************/
+void tts_hw_init( void )
+{
+    tts_hal_init();
+
+    _ticker_f = false;
+    _ticker = 0;
+
+    _last_req.idx[ 0 ] = 0;
+    _last_req.idx[ 1 ] = 0;
+    _last_req.len[ 0 ] = 0;
+    _last_req.len[ 1 ] = 0;
+    memset( _last_req.payload, 0, MAIN_MESSAGE_MAX );
+
+    _last_rsp.idx[ 0 ] = 255;
+    _last_rsp.idx[ 1 ] = 255;
+    _last_rsp.len[ 0 ] = 0;
+    _last_rsp.len[ 1 ] = 0;
+    memset( _last_rsp.payload, 0, RESP_MESSAGE_MAX );
+}
+
+void tts_tick_isr()
+{
+    _ticker++;
+
+    if( _ticker > 500 )
+        _ticker_f == true;
+}
+
+void tts_mute_cmd( bool cmd )
+{
+    if( cmd )
+        tts_hal_mut_high();
+    else
+        tts_hal_mut_low();
+}
+
+void tts_parse_req( uint16_t req,
+                    uint8_t *payload,
+                    uint16_t pl_len )
+{
+    uint8_t *pl = payload;
+    uint16_t i = 0;
+    uint16_t tmp = pl_len + 4;
+     
+    _last_req.len[ 0 ] = tmp & 0x00FF;
+    _last_req.len[ 1 ] = ( tmp & 0xFF00 ) >> 8;
+    _last_req.idx[ 0 ] = req & 0x00FF;
+    _last_req.idx[ 1 ] = ( req & 0xFF00 ) >> 8;
+    _last_rsp.idx[ 0 ] = 0xFF;
+    _last_rsp.idx[ 1 ] = 0xFF;
+    
+    if ( payload != NULL )
+    {
+        while ( pl_len-- )
+            _last_req.payload[ i++ ] = *( pl++ );
+           
+    }
+    
+    _write_req(true);
+}
+
+void tts_parse_boot_img( const uint8_t *payload,
+                         uint16_t pl_len )
+{
+    uint16_t i = 0;
+    uint16_t tmp = pl_len + 0x04;
+    
+    _last_req.len[ 0 ] = tmp & 0x00FF;
+    _last_req.len[ 1 ] = ( tmp & 0xFF00 ) >> 8;
+    _last_req.idx[ 0 ] = 0x00;
+    _last_req.idx[ 1 ] = 0x10;
+    _last_rsp.idx[ 0 ] = 0xFF;
+    _last_rsp.idx[ 1 ] = 0xFF;
+
+    if ( payload != NULL )
+    {
+        while ( pl_len-- )
+            _last_req.payload[ i++ ] = payload[ i ];  
+    }
+
+    _write_req(true);
+}
+
+void tts_parse_speak_req( uint16_t req,
+                          uint8_t flush_en,
+                          char *word,
+                          uint16_t word_len )
+{
+    char *ptr = word;
+    uint16_t i = 1;
+    uint16_t tmp = word_len;
+
+    word_len += 7;
+
+    _last_req.len[ 0 ] = word_len & 0x00FF;
+    _last_req.len[ 1 ] = ( word_len & 0xFF00 ) >> 8;
+    _last_req.idx[ 0 ] = req & 0x00FF;
+    _last_req.idx[ 1 ] = ( req & 0xFF00 ) >> 8;
+    _last_rsp.idx[ 0 ] = 0xFF;
+    _last_rsp.idx[ 1 ] = 0xFF;
+
+    if( flush_en )
+    {
+        _last_req.payload[ 0 ] = 1;
+
+    } else {
+
+        _last_req.payload[ 0 ] = 0;
+    }
+
+    while( tmp-- )
+        _last_req.payload[ i++ ] = *( ptr++ );
+
+    _last_req.payload[ i++ ] = 0x20;
+    _last_req.payload[ i ] =   0x00;
+
+    _write_req(true);
+}
+
+void tts_get_resp()
+{
+    // only read if ready
+    if( tts_hal_msg_rdy() )
+    {
+        _read_rsp();
+    }
+}
+
+bool tts_rsp_chk( uint16_t idx )
+{
+    uint16_t tmp = 0;
+
+    tmp |= _last_rsp.idx[ 0 ];
+    tmp |= _last_rsp.idx[ 1 ] << 8;
+ 
+   return ( idx == tmp ) ? true : false;
+}
+
+uint16_t tts_rsp_idx()
+{
+    uint16_t tmp = 0;
+
+    tmp |= _last_rsp.idx[ 0 ];
+    tmp |= _last_rsp.idx[ 1 ] << 8;
+
+    return tmp;
+}
+
+void tts_rsp_data( uint8_t *buffer )
+{
+    uint8_t *bfr = buffer;
+    uint16_t cnt = 0;
+    uint8_t *ptr = _last_rsp.payload;
+
+    cnt |= _last_rsp.len[ 0 ];
+    cnt |= _last_rsp.len[ 1 ] << 8;
+    cnt -= 4;
+
+    while( cnt-- )
+        *( bfr++ ) = *( ptr++ );
+}
+
+/*************** END OF FUNCTIONS *********************************************/
\ No newline at end of file