/******************** (C) COPYRIGHT 2012 STMicroelectronics ********************
* File Name          : STUARTBLLIB.cpp
* Author             : MCD Application Team
* Version            : v2.6.0
* Date               : 07-November-2012
* Description        : Implements the UART boot loader protocol interface
********************************************************************************
* THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
********************************************************************************
* FOR MORE INFORMATION PLEASE CAREFULLY READ THE LICENSE AGREEMENT FILE
* "MCD-ST Liberty SW License Agreement V2.pdf"
*******************************************************************************/


#include <malloc.h>
//#include <mem.h>
#include "stdafx.h"
#include "STUARTBLLIB.h"

/* Options Bytes Areas*/

DWORD ADDR_F1_OPB     = 0x1FFFF800;
DWORD ADDR_F2_OPB     = 0x1FFFC000;
DWORD ADDR_L1_OPB     = 0x1FF80000;
 
/* STM32F1 Series*/
DWORD ADDR_USER_OPB    = 0x1FFFF800;
DWORD ADDR_DATA_OPB    = 0x1FFFF804;
DWORD ADDR_RDP_OPB     = 0x1FFFF800;
DWORD ADDR_WRP0_OPB    = 0x1FFFF808;
DWORD ADDR_WRP2_OPB    = 0x1FFFF80C;



DWORD  MAX_DATA_SIZE      = 0xFF;  // Packet size(in byte)
BYTE   ACK                 = 0x79 ;
BYTE   NACK                = 0x1F ;

ACKS ACK_VALUE          = ST79;
LPTARGET_DESCRIPTOR Target;
CRS232 Cur_COM;
ACKS   McuTarget;
DWORD  Progress;
DWORD  ActivityTime ;


BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
					 )
{
    switch (ul_reason_for_call)
	{
		case DLL_PROCESS_ATTACH :{
			                        McuTarget = UNDEFINED;
								    Target = (LPTARGET_DESCRIPTOR)malloc(sizeof(TARGET_DESCRIPTOR));
								    
									Target->Version                    = 0x00;
									Target->CmdCount                   = 0x00;
									Target->PIDLen                     = 0x00;
									Target->PID                        = (LPBYTE)malloc(1);
									Target->ROPE                       = 0x00;
									Target->ROPD                       = 0x00; 

									Target->GET_CMD                    = FALSE    ; //Get the version and the allowed commands supported by the current version of the boot loader
									Target->GET_VER_ROPS_CMD           = FALSE    ; //Get the BL version and the Read Protection status of the NVM
									Target->GET_ID_CMD                 = FALSE    ; //Get the chip ID
									Target->READ_CMD                   = FALSE    ; //Read up to 256 bytes of memory starting from an address specified by the user
									Target->GO_CMD                     = FALSE    ; //Jump to an address specified by the user to execute (a loaded) code
									Target->WRITE_CMD                  = FALSE    ; //Write maximum 256 bytes to the RAM or the NVM starting from an address specified by the user
									Target->ERASE_CMD                  = FALSE    ; //Erase from one to all the NVM sectors
									Target->ERASE_EXT_CMD              = FALSE    ; //Erase from one to all the NVM sectors
									Target->WRITE_PROTECT_CMD          = FALSE    ; //Enable the write protection in a permanent way for some sectors
									Target->WRITE_TEMP_UNPROTECT_CMD   = FALSE    ; //Disable the write protection in a temporary way for all NVM sectors
									Target->WRITE_PERM_UNPROTECT_CMD   = FALSE    ; //Disable the write protection in a permanent way for all NVM sectors
									Target->READOUT_PERM_PROTECT_CMD   = FALSE    ; //Enable the readout protection in a permanent way
									Target->READOUT_TEMP_UNPROTECT_CMD = FALSE    ; //Disable the readout protection in a temporary way
									Target->READOUT_PERM_UNPROTECT_CMD = FALSE    ; //Disable the readout protection in a permanent way
								 }break;
		case DLL_THREAD_ATTACH  :{ 
			                        /*McuTarget = UNDEFINED;
								    Target = (LPTARGET_DESCRIPTOR)malloc(sizeof(TARGET_DESCRIPTOR));

								   	Target->Version                    = 0x00;
									Target->CmdCount                   = 0x00;
									Target->PIDLen                     = 0x00;
									Target->PID                        = (LPBYTE)malloc(1);
									Target->ROPE                       = 0x00;
									Target->ROPD                       = 0x00; 

									Target->GET_CMD                    = FALSE    ; //Get the version and the allowed commands supported by the current version of the boot loader
									Target->GET_VER_ROPS_CMD           = FALSE    ; //Get the BL version and the Read Protection status of the NVM
									Target->GET_ID_CMD                 = FALSE    ; //Get the chip ID
									Target->READ_CMD                   = FALSE    ; //Read up to 256 bytes of memory starting from an address specified by the user
									Target->GO_CMD                     = FALSE    ; //Jump to an address specified by the user to execute (a loaded) code
									Target->WRITE_CMD                  = FALSE    ; //Write maximum 256 bytes to the RAM or the NVM starting from an address specified by the user
									Target->ERASE_CMD                  = FALSE    ; //Erase from one to all the NVM sectors
									Target->WRITE_PROTECT_CMD          = FALSE    ; //Enable the write protection in a permanent way for some sectors
									Target->WRITE_TEMP_UNPROTECT_CMD   = FALSE    ; //Disable the write protection in a temporary way for all NVM sectors
									Target->WRITE_PERM_UNPROTECT_CMD   = FALSE    ; //Disable the write protection in a permanent way for all NVM sectors
									Target->READOUT_PERM_PROTECT_CMD   = FALSE    ; //Enable the readout protection in a permanent way
									Target->READOUT_TEMP_UNPROTECT_CMD = FALSE    ; //Disable the readout protection in a temporary way
									Target->READOUT_PERM_UNPROTECT_CMD = FALSE    ; //Disable the readout protection in a permanent way
								 */}break;
		case DLL_THREAD_DETACH  :{}break;
		case DLL_PROCESS_DETACH :{}break;
    }
    return TRUE;
}


/************************************************************************************/
/* SET COMMUNICATION INTERFACE TYPE
/* UART - ...
/*
/************************************************************************************/
STUARTBLLIB_API BYTE TARGET_SetComIntType(BYTE com_int_type)
{
	return 0;
}
/************************************************************************************/
/*
/*
/*
/************************************************************************************/
STUARTBLLIB_API BYTE SetCOMSettings(int numPort, long speedInBaud, int nbBit,
	                            int parity, float nbStopBit)
{
	if (Cur_COM.isConnected)  return COM_ALREADY_OPENED; 
    
	if(numPort<1 || numPort>99)		
		return INPUT_PARAMS_ERROR;

	if(speedInBaud<1)		
		return INPUT_PARAMS_ERROR;

	if(nbBit<5 || nbBit > 9)
		return INPUT_PARAMS_ERROR;

	if(parity<0 || parity > 2)
		return INPUT_PARAMS_ERROR;

	if(nbStopBit<1 || nbStopBit > 2)
		return INPUT_PARAMS_ERROR;

	Cur_COM.numPort      = numPort;
	Cur_COM.speedInBaud  = speedInBaud;
	Cur_COM.nbBit	     = nbBit;                      
	Cur_COM.parity       = parity;
	Cur_COM.nbStopBit    = nbStopBit;

	return SUCCESS; 
}

STUARTBLLIB_API BYTE Send_RQ(LPSTBL_Request pRQ)
{
	BYTE DataSize = 1;

    if (!Cur_COM.isConnected)  return NO_CON_AVAILABLE; 

	if (!Target) Target = (LPTARGET_DESCRIPTOR)malloc(sizeof(TARGET_DESCRIPTOR));  

	LPBYTE RQ_Buffer = (LPBYTE) malloc(2);
   
	// put command code in the buffer
	
    RQ_Buffer[0] = pRQ->_cmd;    
	
	if (ACK_VALUE == ST79)
	{
	  // put XOR command code in the buffer
	  RQ_Buffer[1] = ~pRQ->_cmd;
      DataSize = 2;
	}

	BYTE auxcmd = RQ_Buffer[0];
	BYTE auxxorcmd = RQ_Buffer[1];

    // Send command code (and its XOR value) 
    if (Cur_COM.sendData(DataSize, RQ_Buffer) != DataSize)
		return SEND_FAIL; 

	free(RQ_Buffer);
	DataSize = 1;

    // Get ACK (verify if the command was accepted)
	if (/*ACK_VALUE == ST79) */!((ACK_VALUE == ST75) && (pRQ->_cmd == GET_VER_ROPS_CMD)))
	{
	  RQ_Buffer = (LPBYTE) malloc(1);
	  if (Cur_COM.receiveData(1, RQ_Buffer) != 1)
 		return READ_FAIL; 

	  if(RQ_Buffer[0] != ACK)
  		return CMD_NOT_ALLOWED;
	}

    switch (pRQ->_cmd)  
	{
        case GET_CMD                   : //Get the version and the allowed commands supported by the current version of the boot loader
										{
											memset(pRQ->_target, 0x00, sizeof(TARGET_DESCRIPTOR));
                                            // Get number of bytes (Version + commands)
											RQ_Buffer = (LPBYTE) malloc(1);
	                                        if (Cur_COM.receiveData(1, RQ_Buffer) != 1)
		                                       return READ_FAIL;

                                            pRQ->_target->CmdCount = RQ_Buffer[0];

                                            // Get boot loader version
											if (Cur_COM.receiveData(1, RQ_Buffer) != 1)
		                                       return READ_FAIL;

											pRQ->_target->Version = RQ_Buffer[0];
                                            free(RQ_Buffer);

                                            // Get supported commands
											RQ_Buffer = (LPBYTE) malloc(pRQ->_target->CmdCount);
	                                        if (Cur_COM.receiveData(pRQ->_target->CmdCount, RQ_Buffer) != pRQ->_target->CmdCount)
		                                       return READ_FAIL;

                                            for (int i = 0; i<pRQ->_target->CmdCount; i++)
											{
												switch (RQ_Buffer[i]) 
												{
											      case GET_CMD                   :  pRQ->_target->GET_CMD = TRUE; 
													  break;
                                                  case GET_VER_ROPS_CMD          :  pRQ->_target->GET_VER_ROPS_CMD = TRUE; 
													  break;
                                                  case GET_ID_CMD                :  pRQ->_target->GET_ID_CMD = TRUE; 
													  break;
                                                  case READ_CMD                  :  pRQ->_target->READ_CMD = TRUE; 
													  break;
                                                  case GO_CMD                    :  pRQ->_target->GO_CMD = TRUE; 
													  break;
                                                  case WRITE_CMD                 :  pRQ->_target->WRITE_CMD = TRUE; 
													  break;
                                                  case ERASE_CMD                 :  pRQ->_target->ERASE_CMD = TRUE; 
													  break;
												  case ERASE_EXT_CMD             :  pRQ->_target->ERASE_EXT_CMD  = TRUE; 
													  break;
                                                  case WRITE_PROTECT_CMD         :  pRQ->_target->WRITE_PROTECT_CMD = TRUE; 
													  break;
                                                  case WRITE_TEMP_UNPROTECT_CMD  :  pRQ->_target->WRITE_TEMP_UNPROTECT_CMD = TRUE; 
													  break;
                                                  case WRITE_PERM_UNPROTECT_CMD  :  pRQ->_target->WRITE_PERM_UNPROTECT_CMD = TRUE; 
													  break;
                                                  case READOUT_PROTECT_CMD  :  pRQ->_target->READOUT_PERM_PROTECT_CMD = TRUE; 
													  break;
                                                  case READOUT_TEMP_UNPROTECT_CMD:  pRQ->_target->READOUT_TEMP_UNPROTECT_CMD = TRUE; 
													  break;
                                                  case READOUT_PERM_UNPROTECT_CMD:  pRQ->_target->READOUT_PERM_UNPROTECT_CMD = TRUE; 
													  break;
												}
											}
											free(RQ_Buffer);

                                            // Get ACK byte
											RQ_Buffer = (LPBYTE) malloc(1);
	                                        if (Cur_COM.receiveData(1, RQ_Buffer) != 1)
		                                       return READ_FAIL;

											if(RQ_Buffer[0] != ACK)
		                                       return CMD_FAIL; 

											memcpy(Target, pRQ->_target, sizeof(TARGET_DESCRIPTOR));
											free(RQ_Buffer);
										}break;
        case GET_VER_ROPS_CMD          : //Get the BL version and the Read Protection status of the NVM
        								{
											memcpy(pRQ->_target, Target, sizeof(TARGET_DESCRIPTOR));
											// Get Version
											RQ_Buffer = (LPBYTE) malloc(1);
	                                        if (Cur_COM.receiveData(1, RQ_Buffer) != 1)
		                                       return READ_FAIL;
                                            
                                            pRQ->_target->Version = RQ_Buffer[0];
                                            
											// Get ROPE
	                                        if (Cur_COM.receiveData(1, RQ_Buffer) != 1)
		                                       return READ_FAIL;
                                            
                                            pRQ->_target->ROPE = RQ_Buffer[0];

											// Get ROPD
	                                        if (Cur_COM.receiveData(1, RQ_Buffer) != 1)
		                                       return READ_FAIL;
                                            
                                            pRQ->_target->ROPD = RQ_Buffer[0];

											// Get ACK
	                                        if (Cur_COM.receiveData(1, RQ_Buffer) != 1)
		                                       return READ_FAIL;

											if (RQ_Buffer[0] != ACK )
											   return CMD_FAIL; 

											memcpy(Target, pRQ->_target, sizeof(TARGET_DESCRIPTOR));
											free(RQ_Buffer);
										}break;
        case GET_ID_CMD                : //Get the chip ID
        								{
											memcpy(pRQ->_target, Target, sizeof(TARGET_DESCRIPTOR));
											// Get PID Length
											RQ_Buffer = (LPBYTE) malloc(1);
	                                        if (Cur_COM.receiveData(1, RQ_Buffer) != 1)
		                                       return READ_FAIL;
                                            
                                            pRQ->_target->PIDLen = RQ_Buffer[0] + 1;
                                            
											// Get PID
                                            RQ_Buffer = (LPBYTE) malloc(pRQ->_target->PIDLen);
	                                        if (Cur_COM.receiveData(pRQ->_target->PIDLen, RQ_Buffer) != pRQ->_target->PIDLen)
		                                       return READ_FAIL;

											pRQ->_target->PID = (BYTE*)malloc(sizeof(pRQ->_target->PIDLen)); 
											memcpy(pRQ->_target->PID, RQ_Buffer, pRQ->_target->PIDLen);

											// Get ACK
	                                        if (Cur_COM.receiveData(1, RQ_Buffer) != 1)
		                                       return READ_FAIL;

											if (RQ_Buffer[0] != ACK )
											   return CMD_FAIL; 

											memcpy(Target, pRQ->_target, sizeof(TARGET_DESCRIPTOR)); 
											free(RQ_Buffer);
										}break;
        case READ_CMD                  : //Read up to 256 bytes of memory starting from an address specified by the user
        								{
											memcpy(pRQ->_target, Target, sizeof(TARGET_DESCRIPTOR));

											// Send Read address and checksum
											if (ACK_VALUE == ST79) DataSize = 5;
											else DataSize = 4;

											RQ_Buffer = (LPBYTE) malloc(5);
											BYTE Checksum = 0x00;

                                            RQ_Buffer[0] = (pRQ->_address >> 24) & 0x000000FF; Checksum= Checksum ^ RQ_Buffer[0];
											RQ_Buffer[1] = (pRQ->_address >> 16) & 0x000000FF; Checksum= Checksum ^ RQ_Buffer[1];
											RQ_Buffer[2] = (pRQ->_address >> 8 ) & 0x000000FF; Checksum= Checksum ^ RQ_Buffer[2];
											RQ_Buffer[3] = (pRQ->_address      ) & 0x000000FF; Checksum= Checksum ^ RQ_Buffer[3];
											RQ_Buffer[4] = Checksum;

	                                        if (Cur_COM.sendData(DataSize, RQ_Buffer) != DataSize)
		                                       return SEND_FAIL;

											// Get ACK
	                                        if (Cur_COM.receiveData(1, RQ_Buffer) != 1)
		                                       return READ_FAIL;

											if (RQ_Buffer[0] != ACK )
											   return CMD_FAIL;
											
											// send data size to be read
											RQ_Buffer[0] = pRQ->_length-1;
											RQ_Buffer[1] = ~(pRQ->_length-1);

											if (ACK_VALUE == ST79) DataSize = 2;
											else DataSize = 1;

											if (Cur_COM.sendData(DataSize, RQ_Buffer) != DataSize)
		                                       return SEND_FAIL;

											// Get ACK
											if (ACK_VALUE == ST79)
											{
												if (Cur_COM.receiveData(1, RQ_Buffer) != 1)
												   return READ_FAIL;

												if (RQ_Buffer[0] != ACK )
												   return CMD_FAIL;
											}

											free(RQ_Buffer);

											// Get data
											if (Cur_COM.receiveData(pRQ->_length, pRQ->_data)!= pRQ->_length )
		                                       return READ_FAIL;

											

										}break;
        case GO_CMD                    : //Jump to an address specified by the user to execute (a loaded) code
        								{
											memcpy(pRQ->_target, Target, sizeof(TARGET_DESCRIPTOR));
                                            // Send Go address and checksum
											BYTE Checksum = 0x00;

											if (ACK_VALUE == ST79) DataSize = 5;
											else DataSize = 4;


											RQ_Buffer = (LPBYTE) malloc(5);

                                            RQ_Buffer[0] = (pRQ->_address >> 24) & 0x000000FF; Checksum= Checksum ^ RQ_Buffer[0];
											RQ_Buffer[1] = (pRQ->_address >> 16) & 0x000000FF; Checksum= Checksum ^ RQ_Buffer[1];
											RQ_Buffer[2] = (pRQ->_address >> 8 ) & 0x000000FF; Checksum= Checksum ^ RQ_Buffer[2];
											RQ_Buffer[3] = (pRQ->_address      ) & 0x000000FF; Checksum= Checksum ^ RQ_Buffer[3];
											RQ_Buffer[4] = Checksum;

	                                        if (Cur_COM.sendData(DataSize, RQ_Buffer) != DataSize)
		                                       return SEND_FAIL;

											// Get ACK
	                                        if (Cur_COM.receiveData(1, RQ_Buffer) != 1)
		                                       return READ_FAIL;

											// to be added when Go command can return ACK when performed
											//if (RQ_Buffer[0] != ACK )
											   //return CMD_FAIL; 

											free(RQ_Buffer);
										}break;
        case WRITE_CMD                 : //Write maximum 256 bytes to the RAM or the NVM starting from an address specified by the user
        								{
                                            memcpy(pRQ->_target, Target, sizeof(TARGET_DESCRIPTOR));

											// Send Read address and checksum
											BYTE Checksum = 0x00;

											if (ACK_VALUE == ST79) DataSize = 5;
											else DataSize = 4;

											RQ_Buffer = (LPBYTE) malloc(5);


                                            RQ_Buffer[0] = (pRQ->_address >> 24) & 0x000000FF; Checksum= Checksum ^ RQ_Buffer[0];
											RQ_Buffer[1] = (pRQ->_address >> 16) & 0x000000FF; Checksum= Checksum ^ RQ_Buffer[1];
											RQ_Buffer[2] = (pRQ->_address >> 8 ) & 0x000000FF; Checksum= Checksum ^ RQ_Buffer[2];
											RQ_Buffer[3] = (pRQ->_address      ) & 0x000000FF; Checksum= Checksum ^ RQ_Buffer[3];
											RQ_Buffer[4] = Checksum;

	                                        if (Cur_COM.sendData(DataSize, RQ_Buffer) != DataSize)
		                                       return SEND_FAIL;

											// Get ACK
	                                        if (Cur_COM.receiveData(1, RQ_Buffer) != 1)
		                                       return READ_FAIL;

											if (RQ_Buffer[0] != ACK )
											   return CMD_FAIL;

											BYTE checksum = 0x00;
											
											// send data size to be writen
											RQ_Buffer[0] = pRQ->_length-1;
											checksum = /*checksum ^*/ RQ_Buffer[0];

											if (Cur_COM.sendData(1, RQ_Buffer) != 1)
		                                       return SEND_FAIL;

											if (ACK_VALUE == ST79)
											{
											  for (int i = 0; i< pRQ->_length; i++)
												 checksum = checksum ^ pRQ->_data[i];
											}

											// Send data
											if (Cur_COM.sendData(pRQ->_length, pRQ->_data)!= pRQ->_length )
		                                       return SEND_FAIL;

											if (ACK_VALUE == ST79) 
											{
											  // send checksum
											  RQ_Buffer[0] = checksum;

											  if (Cur_COM.sendData(1, RQ_Buffer) != 1)
		                                         return SEND_FAIL;
											}

                                            // Get ACK
	                                        if (Cur_COM.receiveData(1, RQ_Buffer) != 1)
		                                       return READ_FAIL;

											if (RQ_Buffer[0] != ACK )
											   return CMD_FAIL; 

											/*if (ACK_VALUE == ST79)
											{
												if (Cur_COM.receiveData(1, RQ_Buffer) != 1);
												   //return READ_FAIL;

												if (RQ_Buffer[0] != ACK );
												   //return CMD_FAIL; 
											}*/

											//free(RQ_Buffer);
										}break;


										/* TO DO */


        case ERASE_EXT_CMD                 : //Erase from one to all the NVM sectors
        								{
											memcpy(pRQ->_target, Target, sizeof(TARGET_DESCRIPTOR));
																																
											if ((pRQ->_wbSectors  & 0xFF00 ) != 0xFF00)
											{
											  BYTE checksum = ((pRQ->_wbSectors)-1) >> 8 ;
                                              checksum = checksum ^ ((pRQ->_wbSectors)-1) ;

											  RQ_Buffer = (LPBYTE) malloc(pRQ->_length*2 + 3);  /* N ( 2 bytes)  and Checksum */
											  memset(RQ_Buffer,0xFF, pRQ->_length*2 + 3);
											  
											  RQ_Buffer[0] = ((pRQ->_wbSectors)-1) >> 8;
                                              RQ_Buffer[1] = ((pRQ->_wbSectors)-1);

                                              for (int i = 2; i<= pRQ->_wbSectors*2 ;i+=2)
											  {
												  RQ_Buffer[i] = pRQ->_data[i-1];
												  RQ_Buffer[i+1] = pRQ->_data[i-2];


												  checksum = checksum ^ pRQ->_data[i-1];
												  checksum = checksum ^ pRQ->_data[i-2];


											  }
                                              RQ_Buffer[pRQ->_wbSectors*2 + 2] = checksum;
											}
											else
											{
												RQ_Buffer = (LPBYTE) malloc(3);

											    RQ_Buffer[0] = pRQ->_wbSectors >> 8;
												RQ_Buffer[1] = pRQ->_wbSectors;
												RQ_Buffer[2] = RQ_Buffer[0] ^ RQ_Buffer[1];
											}

											if (ACK_VALUE == ST79) DataSize = 3;
											else DataSize = 1;


                                            if (Cur_COM.sendData(pRQ->_length*2 + DataSize, RQ_Buffer) != pRQ->_length*2 + DataSize)
		                                       return SEND_FAIL;

											// Get ACK
	                                        if (Cur_COM.receiveData(1, RQ_Buffer) != 1)
		                                       return READ_FAIL;

											if (RQ_Buffer[0] != ACK )
											   return CMD_FAIL; 

											/*if (ACK_VALUE == ST79)
											{
												// Get ACK
												if (Cur_COM.receiveData(1, RQ_Buffer) != 1);
												   //return READ_FAIL;

												if (RQ_Buffer[0] != ACK );
												   //return CMD_FAIL; 
											}*/

											free(RQ_Buffer);

										}break;
		case ERASE_CMD                 : //Erase from one to all the NVM sectors
        								{
											memcpy(pRQ->_target, Target, sizeof(TARGET_DESCRIPTOR));
																																
											if (pRQ->_nbSectors != 0xFF)
											{
											  BYTE checksum = /*0x00 ^ */(pRQ->_nbSectors-1);

											  RQ_Buffer = (LPBYTE) malloc(pRQ->_length + 2);
											  memset(RQ_Buffer,0xFF, pRQ->_length + 2);
											  
											  RQ_Buffer[0] = pRQ->_nbSectors - 1;
                                              for (int i = 1; i<= pRQ->_nbSectors ;i++)
											  {
												  RQ_Buffer[i] = pRQ->_data[i-1];
												  checksum = checksum ^ pRQ->_data[i-1]; 
											  }
                                              RQ_Buffer[pRQ->_nbSectors + 1] = checksum;
											}
											else
											{
												RQ_Buffer = (LPBYTE) malloc(2);

											    RQ_Buffer[0] = pRQ->_nbSectors;
												RQ_Buffer[1] = ~pRQ->_nbSectors;
											}

											if (ACK_VALUE == ST79) DataSize = 2;
											else DataSize = 1;


                                            if (Cur_COM.sendData(pRQ->_length + DataSize, RQ_Buffer) != pRQ->_length + DataSize)
		                                       return SEND_FAIL;

											// Get ACK
	                                        if (Cur_COM.receiveData(1, RQ_Buffer) != 1)
		                                       return READ_FAIL;

											if (RQ_Buffer[0] != ACK )
											   return CMD_FAIL; 

											/*if (ACK_VALUE == ST79)
											{
												// Get ACK
												if (Cur_COM.receiveData(1, RQ_Buffer) != 1);
												   //return READ_FAIL;

												if (RQ_Buffer[0] != ACK );
												   //return CMD_FAIL; 
											}*/

											free(RQ_Buffer);

										}break;
        case WRITE_PROTECT_CMD         : //Enable the write protection in a permanent way for some sectors
        								{
											memcpy(pRQ->_target, Target, sizeof(TARGET_DESCRIPTOR));
																																				
											BYTE checksum = 0x00 ^ (pRQ->_nbSectors-1);

											RQ_Buffer = (LPBYTE) malloc(pRQ->_length + 2);
											RQ_Buffer[0] = pRQ->_nbSectors - 1;
                                            for (int i = 1; i<=pRQ->_nbSectors ;i++)
											{
											  RQ_Buffer[i] = pRQ->_data[i-1];
											  checksum = checksum ^ pRQ->_data[i-1]; 
											}
                                            RQ_Buffer[pRQ->_nbSectors + 1] = checksum;
										

                                            if (Cur_COM.sendData(pRQ->_length + 2, RQ_Buffer) != pRQ->_length + 2)
		                                       return SEND_FAIL;

											// Get ACK
	                                        if (Cur_COM.receiveData(1, RQ_Buffer) != 1)
		                                       return READ_FAIL;

											if (RQ_Buffer[0] != ACK )
											   return CMD_FAIL; 

											free(RQ_Buffer);
										}break;
        case WRITE_TEMP_UNPROTECT_CMD   :{
											// Get ACK
	                                        if (Cur_COM.receiveData(1, RQ_Buffer) != 1)
		                                       return READ_FAIL;

											if (RQ_Buffer[0] != ACK )
											   return CMD_FAIL; 

											free(RQ_Buffer);
										}break; //Disable the write protection in a temporary way for all NVM sectors 
		case WRITE_PERM_UNPROTECT_CMD   :{
											// Get ACK
	                                        if (Cur_COM.receiveData(1, RQ_Buffer) != 1)
		                                       return READ_FAIL;

											if (RQ_Buffer[0] != ACK )
											   return CMD_FAIL; 

											free(RQ_Buffer);
										}break; //Disable the write protection in a permanent way for all NVM sectors
		case READOUT_PROTECT_CMD        :{
											// Get ACK
	                                        if (Cur_COM.receiveData(1, RQ_Buffer) != 1)
		                                       return READ_FAIL;

											if (RQ_Buffer[0] != ACK )
											   return CMD_FAIL; 

											free(RQ_Buffer);
										}break; //Disable the readout protection in a temporary way
		case READOUT_TEMP_UNPROTECT_CMD :{
											// Get ACK
	                                        if (Cur_COM.receiveData(1, RQ_Buffer) != 1)
		                                       return READ_FAIL;

											if (RQ_Buffer[0] != ACK )
											   return CMD_FAIL; 

											free(RQ_Buffer);
										}break; //Disable the readout protection in a permanent way
        case READOUT_PERM_UNPROTECT_CMD :{
											// Get ACK
	                                        if (Cur_COM.receiveData(1, RQ_Buffer) != 1)
		                                       return READ_FAIL;

											if (RQ_Buffer[0] != ACK )
											   return CMD_FAIL; 

											free(RQ_Buffer);
										}break; 
	}

	return SUCCESS;
}

STUARTBLLIB_API BYTE COM_Open()
{
	if (Cur_COM.isConnected)  return COM_ALREADY_OPENED;
	
	if (Cur_COM.open())
		return SUCCESS;
	else
		return CANT_OPEN_COM;
}

STUARTBLLIB_API BYTE COM_Close()
{
	if (!Cur_COM.isConnected)  return NO_CON_AVAILABLE;

	Cur_COM.closeCom();

	return SUCCESS;
}

STUARTBLLIB_API BYTE STBL_SetSpeed(DWORD speed)
{
	return CMD_NOT_ALLOWED;
}

STUARTBLLIB_API BYTE STBL_Init_BL()
{
	if (!Cur_COM.isConnected)  return NO_CON_AVAILABLE;

	
	
	LPBYTE RQ_Buffer = (LPBYTE) malloc(1);

    RQ_Buffer[0] = INIT_CON; 
	//if (Cur_COM.setTxd(FALSE)) _sleep(100);

    if (Cur_COM.sendData(1, RQ_Buffer) != 1)
		return SEND_FAIL; 
	if (Cur_COM.receiveData(1, RQ_Buffer) != 1)
		return READ_FAIL;

   
	
	//Work-Around : in case of the device send a 0x00 value 
	//after system reset , we reveive  again the real ack
	
	if(RQ_Buffer[0] == 0x00)
		if (Cur_COM.receiveData(1, RQ_Buffer) != 1)
			return READ_FAIL;

	//if (Cur_COM.setTxd(FALSE)) 
	//_sleep(100);

	switch (RQ_Buffer[0])
	{
	  case 0x75:{ // STR750 used
		          ACK_VALUE = ST75;
		          ACK  = 0x75;
                  NACK = 0x3F;
				  // Commented to avoid DTR/RTS reset signals Cur_COM.SetParity(0); // Set NONE parity  
				}break;
	  case 0x79:{ // STM32, STR911 or STM8 used
		          ACK_VALUE = ST79;
		          ACK  = 0x79;
                  NACK = 0x1F;
				  // Commented to avoid DTR/RTS reset signalsCur_COM.SetParity(2); // Set EVEN parity
				}break;
	  default:  { // Undefined device
		          ACK_VALUE = UNDEFINED;
				  ACK  = RQ_Buffer[0];
		          return UNREOGNIZED_DEVICE;
				}break;
	}

	return SUCCESS;
}
/******************************************************************************************/
/* Boot Loader commands implementation                     
/******************************************************************************************/                                                                                   
STUARTBLLIB_API BYTE STBL_GET(LPBYTE Version, LPCommands pCmds)
{
	if (!Cur_COM.isConnected)  return NO_CON_AVAILABLE;

	if (!Version || !pCmds) return INPUT_PARAMS_MEMORY_ALLOCATION_ERROR;

	if(ACK_VALUE == ST75)
	{
		pCmds->GET_CMD                    = TRUE    ; //Get the version and the allowed commands supported by the current version of the boot loader
		pCmds->GET_VER_ROPS_CMD           = TRUE    ; //Get the BL version and the Read Protection status of the NVM
		pCmds->GET_ID_CMD                 = TRUE    ; //Get the chip ID
		pCmds->READ_CMD                   = TRUE    ; //Read up to 256 bytes of memory starting from an address specified by the user
		pCmds->GO_CMD                     = TRUE    ; //Jump to an address specified by the user to execute (a loaded) code
		pCmds->WRITE_CMD                  = TRUE    ; //Write maximum 256 bytes to the RAM or the NVM starting from an address specified by the user
		pCmds->ERASE_CMD                  = TRUE    ; //Erase from one to all the NVM sectors
		pCmds->WRITE_PROTECT_CMD          = TRUE    ; //Enable the write protection in a permanent way for some sectors
		pCmds->WRITE_TEMP_UNPROTECT_CMD   = TRUE    ; //Disable the write protection in a temporary way for all NVM sectors
		pCmds->WRITE_PERM_UNPROTECT_CMD   = TRUE    ; //Disable the write protection in a permanent way for all NVM sectors
		pCmds->READOUT_PROTECT_CMD        = TRUE    ; //Enable the readout protection in a permanent way
		pCmds->READOUT_TEMP_UNPROTECT_CMD = TRUE    ; //Disable the readout protection in a temporary way
		pCmds->READOUT_PERM_UNPROTECT_CMD = TRUE    ; //Disable the readout protection in a permanent way

		Target->GET_CMD                    = TRUE    ; //Get the version and the allowed commands supported by the current version of the boot loader
		Target->GET_VER_ROPS_CMD           = TRUE    ; //Get the BL version and the Read Protection status of the NVM
		Target->GET_ID_CMD                 = TRUE    ; //Get the chip ID
		Target->READ_CMD                   = TRUE    ; //Read up to 256 bytes of memory starting from an address specified by the user
		Target->GO_CMD                     = TRUE    ; //Jump to an address specified by the user to execute (a loaded) code
		Target->WRITE_CMD                  = TRUE    ; //Write maximum 256 bytes to the RAM or the NVM starting from an address specified by the user
		Target->ERASE_CMD                  = TRUE    ; //Erase from one to all the NVM sectors
		Target->WRITE_PROTECT_CMD          = TRUE    ; //Enable the write protection in a permanent way for some sectors
		Target->WRITE_TEMP_UNPROTECT_CMD   = TRUE    ; //Disable the write protection in a temporary way for all NVM sectors
		Target->WRITE_PERM_UNPROTECT_CMD   = TRUE    ; //Disable the write protection in a permanent way for all NVM sectors
		Target->READOUT_PERM_PROTECT_CMD   = TRUE    ; //Enable the readout protection in a permanent way
		Target->READOUT_TEMP_UNPROTECT_CMD = TRUE    ; //Disable the readout protection in a temporary way
		Target->READOUT_PERM_UNPROTECT_CMD = TRUE    ; //Disable the readout protection in a permanent way

		BYTE Ver; BYTE ROPEnabled; BYTE ROPDisabled;
		BYTE Result = STBL_GET_VER_ROPS(&Ver, &ROPEnabled, &ROPDisabled);
		if (Result != SUCCESS) return Result;
		memcpy(Version, &Ver,1);
	}
	else if(ACK_VALUE = ST79)
	{

		LPSTBL_Request pRQ = (LPSTBL_Request)malloc(sizeof(STBL_Request));
		pRQ->_target = (LPTARGET_DESCRIPTOR)malloc(sizeof(TARGET_DESCRIPTOR));

		pRQ->_cmd = GET_CMD;

		BYTE Result = Send_RQ(pRQ);
		if (Result != SUCCESS) return Result;

		memcpy(Version, &pRQ->_target->Version,1);

		pCmds->GET_CMD                    = pRQ->_target->GET_CMD                    ; //Get the version and the allowed commands supported by the current version of the boot loader
		pCmds->GET_VER_ROPS_CMD           = pRQ->_target->GET_VER_ROPS_CMD           ; //Get the BL version and the Read Protection status of the NVM
		pCmds->GET_ID_CMD                 = pRQ->_target->GET_ID_CMD                 ; //Get the chip ID
		pCmds->READ_CMD                   = pRQ->_target->READ_CMD                   ; //Read up to 256 bytes of memory starting from an address specified by the user
		pCmds->GO_CMD                     = pRQ->_target->GO_CMD                     ; //Jump to an address specified by the user to execute (a loaded) code
		pCmds->WRITE_CMD                  = pRQ->_target->WRITE_CMD                  ; //Write maximum 256 bytes to the RAM or the NVM starting from an address specified by the user
		pCmds->ERASE_CMD                  = pRQ->_target->ERASE_CMD                  ; //Erase from one to all the NVM sectors
		pCmds->ERASE_EXT_CMD              = pRQ->_target->ERASE_EXT_CMD              ; //Erase from one to all the NVM sectors
		pCmds->WRITE_PROTECT_CMD          = pRQ->_target->WRITE_PROTECT_CMD          ; //Enable the write protection in a permanent way for some sectors
		pCmds->WRITE_TEMP_UNPROTECT_CMD   = pRQ->_target->WRITE_TEMP_UNPROTECT_CMD   ; //Disable the write protection in a temporary way for all NVM sectors
		pCmds->WRITE_PERM_UNPROTECT_CMD   = pRQ->_target->WRITE_PERM_UNPROTECT_CMD   ; //Disable the write protection in a permanent way for all NVM sectors
		pCmds->READOUT_PROTECT_CMD   = pRQ->_target->READOUT_PERM_PROTECT_CMD   ; //Enable the readout protection in a permanent way
		pCmds->READOUT_TEMP_UNPROTECT_CMD = pRQ->_target->READOUT_TEMP_UNPROTECT_CMD ; //Disable the readout protection in a temporary way
		pCmds->READOUT_PERM_UNPROTECT_CMD = pRQ->_target->READOUT_PERM_UNPROTECT_CMD ; //Disable the readout protection in a permanent way
	   
	    free(pRQ);
	}
	return SUCCESS;
}
                                                                                    
STUARTBLLIB_API BYTE STBL_GET_VER_ROPS(LPBYTE Version, LPBYTE ROPEnabled, LPBYTE ROPDisabled)
{
	if (!Cur_COM.isConnected)  return NO_CON_AVAILABLE;
	if (!Target->GET_VER_ROPS_CMD) return CMD_NOT_ALLOWED;

	if (!Version || !ROPEnabled || !ROPDisabled) return INPUT_PARAMS_MEMORY_ALLOCATION_ERROR;

	LPSTBL_Request pRQ = (LPSTBL_Request)malloc(sizeof(STBL_Request));
    pRQ->_target = (LPTARGET_DESCRIPTOR)malloc(sizeof(TARGET_DESCRIPTOR));

    pRQ->_cmd = GET_VER_ROPS_CMD;

	BYTE Result = Send_RQ(pRQ) ;
	if (Result != SUCCESS) return Result;

    memcpy(ROPEnabled, &pRQ->_target->ROPD, 1);  
	memcpy(ROPDisabled, &pRQ->_target->ROPE, 1);
	memcpy(Version, &Target->Version, 1);
	
	free(pRQ);

	return SUCCESS;
}              
                                                                                    
STUARTBLLIB_API BYTE STBL_GET_ID(LPBYTE size, LPBYTE pID) 
{
	if (!Cur_COM.isConnected)  return NO_CON_AVAILABLE;
	if (!Target->GET_ID_CMD) return CMD_NOT_ALLOWED;

	//if (!pID) return INPUT_PARAMS_MEMORY_ALLOCATION_ERROR;

	LPSTBL_Request pRQ = (LPSTBL_Request)malloc(sizeof(STBL_Request));
    pRQ->_target = (LPTARGET_DESCRIPTOR)malloc(sizeof(TARGET_DESCRIPTOR));

    pRQ->_cmd = GET_ID_CMD;

	BYTE Result = Send_RQ(pRQ) ;
	if (Result != SUCCESS) return Result;

	memcpy(size, &pRQ->_target->PIDLen, 1);

	if (pID) memcpy(pID, pRQ->_target->PID, *size);	                   ;                
	
	free(pRQ);

	return SUCCESS;
}                   
                                                                                     
STUARTBLLIB_API BYTE STBL_READ(DWORD Address, BYTE Size, LPBYTE pData) 
{
	if (!Cur_COM.isConnected)  return NO_CON_AVAILABLE;
	if (!Target->READ_CMD) return CMD_NOT_ALLOWED;

	if (!pData) return INPUT_PARAMS_MEMORY_ALLOCATION_ERROR;

	LPSTBL_Request pRQ = (LPSTBL_Request)malloc(sizeof(STBL_Request));
    pRQ->_target = (LPTARGET_DESCRIPTOR)malloc(sizeof(TARGET_DESCRIPTOR));

    pRQ->_cmd = READ_CMD;
    pRQ->_address = Address;

	if((Size%2) != 0) Size++;
	pRQ->_length  = Size ;

	pRQ->_data    = (LPBYTE) malloc(MAX_DATA_SIZE);
	memset(pRQ->_data, 0xFF, MAX_DATA_SIZE);   

	BYTE Result = Send_RQ(pRQ);

	if (Result != SUCCESS) 
		return Result;

	memcpy(pData, pRQ->_data, Size);
		
	free(pRQ);

	return SUCCESS;
}                     
                                                                                    
STUARTBLLIB_API BYTE STBL_GO(DWORD Address) 
{
	if (!Cur_COM.isConnected)  return NO_CON_AVAILABLE;
	if (!Target->GO_CMD) return CMD_NOT_ALLOWED;

	LPSTBL_Request pRQ = (LPSTBL_Request)malloc(sizeof(STBL_Request));
    pRQ->_target = (LPTARGET_DESCRIPTOR)malloc(sizeof(TARGET_DESCRIPTOR));

    pRQ->_cmd = GO_CMD;
	
    pRQ->_address = Address;

	BYTE Result = Send_RQ(pRQ);
	if (Result != SUCCESS) return Result;
	
	free(pRQ);

	return SUCCESS;
}                       
                                                                                     
STUARTBLLIB_API BYTE STBL_WRITE(DWORD address, BYTE size, LPBYTE pData)
{
	if (!Cur_COM.isConnected)  return NO_CON_AVAILABLE;
	if (!Target->WRITE_CMD) return CMD_NOT_ALLOWED;

	if (!pData) return INPUT_PARAMS_MEMORY_ALLOCATION_ERROR;

	LPSTBL_Request pRQ = (LPSTBL_Request)malloc(sizeof(STBL_Request));
    pRQ->_target   = (LPTARGET_DESCRIPTOR)malloc(sizeof(TARGET_DESCRIPTOR));

    pRQ->_cmd     = WRITE_CMD;
    pRQ->_address = address;

	if((size%2) != 0) size++;
	pRQ->_length  = size;
	
	pRQ->_data    = (LPBYTE) malloc(MAX_DATA_SIZE);
	memset(pRQ->_data, 0xFF, MAX_DATA_SIZE); 
	memcpy(pRQ->_data, pData, size);

	BYTE Result = Send_RQ(pRQ);

	if (Result != SUCCESS)  
	{
		return Result;
	}
	 
	free(pRQ);

	return SUCCESS;
}                     
                                                                                    
STUARTBLLIB_API BYTE STBL_ERASE(WORD NbSectors, LPBYTE pSectors)
{
	if (!Cur_COM.isConnected)  return NO_CON_AVAILABLE;
	if ((Target->ERASE_CMD == 0) && ( Target->ERASE_EXT_CMD == 0 )) return CMD_NOT_ALLOWED;

	if ((Target->ERASE_CMD))
	{
	
	
	
			if ((!pSectors) && (NbSectors != 0xFFFF)) return INPUT_PARAMS_MEMORY_ALLOCATION_ERROR;

			LPSTBL_Request pRQ = (LPSTBL_Request)malloc(sizeof(STBL_Request));
			pRQ->_target   = (LPTARGET_DESCRIPTOR)malloc(sizeof(TARGET_DESCRIPTOR));

			pRQ->_cmd = ERASE_CMD;


			if (NbSectors == 0xFFFF)
			{
			   pRQ->_nbSectors = 0xFF;
			   pRQ->_length = 0;

			   BYTE Result = Send_RQ(pRQ);
			   if (Result != SUCCESS) return Result;

			   Progress = 0xFF / 10;
			}
			else
			{
			   WORD nErase = NbSectors / 10;
			   WORD Remain = NbSectors % 10;

			   int i = 0;
			   int j = 0; /*  This is for WORD */


			   if (nErase > 0)
			   {
				   for (i = 0; i< nErase; i++)
				   {
					   pRQ->_length = 10; 
					   pRQ->_nbSectors = 10; 
					   pRQ->_data = (LPBYTE)malloc(10);


					   BYTE Convert[0xFF];


				       for (j = 0; j< 10; j++)
					   {
					   
					     Convert[j]=  pSectors [i*10*2+j*2];
					   
					   }



					   /*memcpy(pRQ->_data, pSectors+(i*10), 10);*/

					   memcpy(pRQ->_data, Convert, 10);

					   BYTE Result = Send_RQ(pRQ);
					   if (Result != SUCCESS) return Result;

					   Progress ++;
				   }
			   }

				if (Remain > 0)
			   {
				   pRQ->_length = Remain; 
				   pRQ->_nbSectors = Remain; 
				   pRQ->_data = (LPBYTE)malloc(Remain);

                   BYTE Convert[0xFF];


				   for (j = 0; j< Remain; j++)
				   {
					   
					   Convert[j]=  pSectors [i*10*2+j*2];
					   
				   }

				   /*memcpy(pRQ->_data, pSectors+(i*10), Remain);*/

				   memcpy(pRQ->_data, Convert, Remain);


				   
				   

				   BYTE Result = Send_RQ(pRQ);
				   if (Result != SUCCESS) return Result;
				   
				   Progress ++;
			   }

			   
			}

				free(pRQ);


	}


	if ((Target->ERASE_EXT_CMD))
	{
	
	
	if ((!pSectors) && (NbSectors != 0xFFFF)) return INPUT_PARAMS_MEMORY_ALLOCATION_ERROR;

			LPSTBL_Request pRQ = (LPSTBL_Request)malloc(sizeof(STBL_Request));
			pRQ->_target   = (LPTARGET_DESCRIPTOR)malloc(sizeof(TARGET_DESCRIPTOR));

			pRQ->_cmd = ERASE_EXT_CMD;


			if (NbSectors == 0xFFFF)
			{
			   pRQ->_wbSectors = 0xFFFF;
			   pRQ->_length = 0;

			   BYTE Result = Send_RQ(pRQ);
			   if (Result != SUCCESS) return Result;

			   Progress = 0xFF / 10;
			}
			else
			{
			   WORD nErase = NbSectors / 10;
			   WORD Remain = NbSectors % 10;

			   int i = 0;
			   int j = 0; /*  This is for WORD */


			   if (nErase > 0)
			   {
				   for (i = 0; i< nErase; i++)
				   {
					   pRQ->_length = 10; 
					   pRQ->_wbSectors = 10; 
					   pRQ->_data = (LPBYTE)malloc(10*2);


					   BYTE Convert[0xFF];


				       for (j = 0; j< 10*2; j++)
					   {
					   
					     Convert[j]=  pSectors [i*10*2+ j];
					   
					   }



					   /*memcpy(pRQ->_data, pSectors+(i*10), 10);*/

					   memcpy(pRQ->_data, Convert, 10*2);

					   BYTE Result = Send_RQ(pRQ);
					   if (Result != SUCCESS) return Result;

					   Progress ++;
				   }
			   }

				if (Remain > 0)
			   {
				   pRQ->_length = Remain; 
				   pRQ->_wbSectors = Remain; 
				   pRQ->_data = (LPBYTE)malloc(Remain*2);

                   BYTE Convert[0xFF];


				   for (j = 0; j< Remain*2; j++)
				   {
					   
					   Convert[j]=  pSectors [i*10*2+j];
					   
				   }

				   /*memcpy(pRQ->_data, pSectors+(i*10), Remain);*/

				   memcpy(pRQ->_data, Convert, Remain*2);


				   
				   

				   BYTE Result = Send_RQ(pRQ);
				   if (Result != SUCCESS) return Result;
				   
				   Progress ++;
			   }

			   
			}

				free(pRQ);
	}


	return SUCCESS;
}                     
    
                                                                               
STUARTBLLIB_API BYTE STBL_WRITE_PROTECT(BYTE NbSectors, LPBYTE pSectors)
{
	if (!Cur_COM.isConnected)  return NO_CON_AVAILABLE;
	if (!Target->WRITE_PROTECT_CMD) return CMD_NOT_ALLOWED;

    if (!pSectors) return INPUT_PARAMS_MEMORY_ALLOCATION_ERROR;

	LPSTBL_Request pRQ = (LPSTBL_Request)malloc(sizeof(STBL_Request));
    pRQ->_target   = (LPTARGET_DESCRIPTOR)malloc(sizeof(TARGET_DESCRIPTOR));

    pRQ->_cmd = WRITE_PROTECT_CMD;
	pRQ->_length = NbSectors; 
	pRQ->_nbSectors = NbSectors; 
	pRQ->_data = (LPBYTE)malloc(NbSectors);
	memcpy(pRQ->_data, pSectors, NbSectors);

	BYTE Result = Send_RQ(pRQ);
	if (Result != SUCCESS) return Result;

	free(pRQ);

	Progress ++;
	return SUCCESS;
}             
                                                                                    
STUARTBLLIB_API BYTE STBL_WRITE_TEMP_UNPROTECT() 
{
	//to be used only with STR750
	if (!Cur_COM.isConnected)  return NO_CON_AVAILABLE;
	if (!Target->WRITE_TEMP_UNPROTECT_CMD) return CMD_NOT_ALLOWED;

	LPSTBL_Request pRQ = (LPSTBL_Request)malloc(sizeof(STBL_Request));
    pRQ->_target   = (LPTARGET_DESCRIPTOR)malloc(sizeof(TARGET_DESCRIPTOR));

    pRQ->_cmd = WRITE_TEMP_UNPROTECT_CMD;


	BYTE Result = Send_RQ(pRQ);
	if (Result != SUCCESS) return Result;
	
	free(pRQ);

	Progress ++;
	return SUCCESS;
}     
                                                                                    
STUARTBLLIB_API BYTE STBL_WRITE_PERM_UNPROTECT() 
{
	if (!Cur_COM.isConnected)  return NO_CON_AVAILABLE;
	if (!Target->WRITE_PERM_UNPROTECT_CMD) return CMD_NOT_ALLOWED;

	if (GetAckValue() == 0x75)
		return STBL_WRITE_TEMP_UNPROTECT();

	LPSTBL_Request pRQ = (LPSTBL_Request)malloc(sizeof(STBL_Request));
    pRQ->_target   = (LPTARGET_DESCRIPTOR)malloc(sizeof(TARGET_DESCRIPTOR));

    pRQ->_cmd = WRITE_PERM_UNPROTECT_CMD;


	BYTE Result = Send_RQ(pRQ);
	if (Result != SUCCESS) return Result;
	
	free(pRQ);

	Progress ++;
	return SUCCESS;
}     
                                                                                    
STUARTBLLIB_API BYTE STBL_READOUT_PROTECT() 
{
	if (!Cur_COM.isConnected)  return NO_CON_AVAILABLE;
	if (!Target->READOUT_PERM_PROTECT_CMD) return CMD_NOT_ALLOWED;

	LPSTBL_Request pRQ = (LPSTBL_Request)malloc(sizeof(STBL_Request));
    pRQ->_target   = (LPTARGET_DESCRIPTOR)malloc(sizeof(TARGET_DESCRIPTOR));

    pRQ->_cmd = READOUT_PROTECT_CMD;


	BYTE Result = Send_RQ(pRQ);
	if (Result != SUCCESS) return Result;
	
	free(pRQ);

	Progress++;
	return SUCCESS;
}     
                                                                                    
STUARTBLLIB_API BYTE STBL_READOUT_TEMP_UNPROTECT()  
{
	// to be used only with STR750
    if (!Cur_COM.isConnected)  return NO_CON_AVAILABLE;
	if (!Target->READOUT_TEMP_UNPROTECT_CMD) return CMD_NOT_ALLOWED;

	LPSTBL_Request pRQ = (LPSTBL_Request)malloc(sizeof(STBL_Request));
    pRQ->_target   = (LPTARGET_DESCRIPTOR)malloc(sizeof(TARGET_DESCRIPTOR));

    pRQ->_cmd = READOUT_TEMP_UNPROTECT_CMD;


	BYTE Result = Send_RQ(pRQ);
	if (Result != SUCCESS) return Result;
	
	free(pRQ);

	Progress ++;
	return SUCCESS;
}  
    
/************************************************************************************/
/* READOUT_PERM_UNPROTECT
/*
/*
/************************************************************************************/                                                                                 
STUARTBLLIB_API BYTE STBL_READOUT_PERM_UNPROTECT()  
{
    if (!Cur_COM.isConnected)  return NO_CON_AVAILABLE;
	if (!Target->READOUT_PERM_UNPROTECT_CMD) return CMD_NOT_ALLOWED;

	LPSTBL_Request pRQ = (LPSTBL_Request)malloc(sizeof(STBL_Request));
    pRQ->_target   = (LPTARGET_DESCRIPTOR)malloc(sizeof(TARGET_DESCRIPTOR));

    pRQ->_cmd = READOUT_PERM_UNPROTECT_CMD;


	BYTE Result = Send_RQ(pRQ);
	if (Result != SUCCESS) return Result;
	
	free(pRQ);

	Progress++;
	return SUCCESS;
}

/************************************************************************************/
/* UPLOAD
/*
/*
/************************************************************************************/
STUARTBLLIB_API BYTE STBL_UPLOAD(DWORD Address, LPBYTE pData, DWORD Length)
{
	if (!Cur_COM.isConnected)  return NO_CON_AVAILABLE;
	if (!Target->READ_CMD) return CMD_NOT_ALLOWED;

	LPBYTE Holder = pData;
	BYTE   Result = SUCCESS;
	LPBYTE buffer = (LPBYTE) malloc(MAX_DATA_SIZE);

    DWORD nbuffer = Length / MAX_DATA_SIZE;
	DWORD ramain  = Length % MAX_DATA_SIZE;

	if (nbuffer > 0)
	{
	  for(int i=1; i<=nbuffer; i++)
	  {
		memset(buffer, 0xFF, MAX_DATA_SIZE);
        Result = STBL_READ(Address, MAX_DATA_SIZE, buffer);
		if (Result != SUCCESS) return Result;
		memcpy(pData, buffer, MAX_DATA_SIZE);
		pData = pData + MAX_DATA_SIZE;
		Address += MAX_DATA_SIZE;

		Progress++;
	  }
	}

	if (ramain > 0)
	{
		memset(buffer, 0xFF, MAX_DATA_SIZE);
        Result = STBL_READ(Address, ramain, buffer);
		if (Result != SUCCESS) return Result; 
		memcpy(pData, buffer, ramain);

		Progress++;
	}

	free(buffer);
	pData = Holder;
	return Result;
}

/************************************************************************************/
/* VERIFY
/*
/*
/************************************************************************************/
STUARTBLLIB_API BYTE STBL_VERIFY(DWORD Address, LPBYTE pData, DWORD Length,BOOL bTruncateLeadFFForDnLoad)
{
	if (!Cur_COM.isConnected)  return NO_CON_AVAILABLE;
	if (!Target->READ_CMD) return CMD_NOT_ALLOWED;

	LPBYTE Holder = pData;
	BYTE   Result = SUCCESS;
	LPBYTE buffer = (LPBYTE) malloc(MAX_DATA_SIZE);

    DWORD nbuffer = Length / MAX_DATA_SIZE;
	DWORD ramain  = Length % MAX_DATA_SIZE;

	LPBYTE Empty=new BYTE[MAX_DATA_SIZE];
	memset(Empty, 0xFF, MAX_DATA_SIZE);

	if (nbuffer > 0)
	{
	  for(int i=1; i<=nbuffer; i++)
	  {
		BOOL AllFFs = FALSE;
		if((memcmp(Empty, pData, MAX_DATA_SIZE) == 0) && bTruncateLeadFFForDnLoad)
		{
           AllFFs = TRUE;
		   //_sleep(1);
		}

		if(!AllFFs)
		{
			memset(buffer, 0xFF, MAX_DATA_SIZE);
			Result = STBL_READ(Address, MAX_DATA_SIZE, buffer);
			if (Result != SUCCESS) return Result;
			if (memcmp(pData, buffer, MAX_DATA_SIZE) != 0)
			{
				return CMD_NOT_ALLOWED; // verify fail
			}
		}
		pData = pData + MAX_DATA_SIZE;
		Address += MAX_DATA_SIZE;

		Progress++;
	  }
	}

	if (ramain > 0)
	{
		BOOL AllFFs = FALSE;
		if((memcmp(Empty, pData, ramain) == 0) && bTruncateLeadFFForDnLoad)
           AllFFs = TRUE;

		if(!AllFFs) 
		{
			memset(buffer, 0xFF, MAX_DATA_SIZE);
			Result = STBL_READ(Address, ramain, buffer);
			if (Result != SUCCESS) return Result; 
			if (memcmp(pData, buffer, ramain) != 0)
			{
				return CMD_NOT_ALLOWED; // verify fail
			}
		}
		Progress++;
	}

	free(buffer);
	pData = Holder;
	return Result;
}
/************************************************************************************/
/* DNLOAD
/*
/*
/************************************************************************************/
STUARTBLLIB_API BYTE STBL_DNLOAD(DWORD Address, LPBYTE pData, DWORD Length,BOOL bTruncateLeadFFForDnLoad)
{
	if (!Cur_COM.isConnected)  return NO_CON_AVAILABLE;
	if (!Target->WRITE_CMD) return CMD_NOT_ALLOWED;

	//Progress = 0;
	LPBYTE Holder = pData;
	BYTE   Result = SUCCESS;
	LPBYTE buffer = (LPBYTE) malloc(MAX_DATA_SIZE);

    DWORD nbuffer = (DWORD)(Length / MAX_DATA_SIZE);
	DWORD ramain  = (DWORD)(Length % MAX_DATA_SIZE);

	DWORD Newramain = ramain;

	LPBYTE Empty=new BYTE[MAX_DATA_SIZE];
	memset(Empty, 0xFF, MAX_DATA_SIZE);

	if (nbuffer > 0)
	{
	  for(int i=1; i<=nbuffer; i++)
	  {
		memset(buffer, 0xFF, MAX_DATA_SIZE);
        memcpy(buffer, pData, MAX_DATA_SIZE);

		BOOL AllFFs = FALSE;
		if((memcmp(Empty, buffer, MAX_DATA_SIZE) == 0) && bTruncateLeadFFForDnLoad)
		{
           AllFFs = TRUE;
		   //_sleep(1);
		}

		if(!AllFFs)
		{
          Result = STBL_WRITE(Address, MAX_DATA_SIZE, buffer);
		  if (Result != SUCCESS) return Result;
		}

		pData = pData + MAX_DATA_SIZE;

		Address += MAX_DATA_SIZE;

		Progress++;
	  }
	}

	if (ramain > 0)
	{
		memset(buffer, 0xFF, MAX_DATA_SIZE);


		/* This is a workaround for an issue on STM32 Boot-loader to be verified in v2.3.0*/

	    DWORD newdiv  = (DWORD)(ramain % 4);

	    /*if((ramain%2) != 0) Newramain++;
	    if((ramain%4) != 0) Newramain+=4;*/

        Newramain += 4-newdiv;


		/* end of */

		Result = STBL_READ(Address,  Newramain, buffer);
		if (Result != SUCCESS) return Result;

		
		memcpy(buffer, pData, ramain);

		BOOL AllFFs = FALSE;
		if((memcmp(Empty, buffer, ramain) == 0) && bTruncateLeadFFForDnLoad)
           AllFFs = TRUE;

		if(!AllFFs)
		{
	      
			Result = STBL_WRITE(Address, /*Newramain*/ ramain, buffer);
	      if (Result != SUCCESS) return Result;
		}
		Progress++;
	}

	free(buffer);
	pData = Holder;
	return Result;
}
/************************************************************************************/
/* SET PACKET SIZE
/*
/*
/************************************************************************************/
STUARTBLLIB_API BYTE SetPaketSize(BYTE size)
{
	MAX_DATA_SIZE = (int)(size / 4) * 4 ;
	return SUCCESS;
}
 
/************************************************************************************/
/* GET PACKET SIZE
/*
/*
/************************************************************************************/
STUARTBLLIB_API BYTE GetPaketSize(LPBYTE size)
{
	*size = MAX_DATA_SIZE;
	return SUCCESS;
}

/************************************************************************************/
/* GetAckValue
/*
/*
/************************************************************************************/
STUARTBLLIB_API ACKS GetAckValue()
{
  return ACK_VALUE;  	
}

/************************************************************************************/
/* IsConnected
/*
/*
/************************************************************************************/
STUARTBLLIB_API BOOL COM_is_Open()
{
	return Cur_COM.isConnected;
}

/************************************************************************************/
/* SetTimeOut
/*
/*
/************************************************************************************/
STUARTBLLIB_API BYTE SetTimeOut(DWORD vms)
{
    if (!Cur_COM.isConnected)  return NO_CON_AVAILABLE;
    Cur_COM.setTimeOut(vms);
	return SUCCESS;
}

/************************************************************************************/
/* GetFlashSize
/*
/*
/************************************************************************************/
STUARTBLLIB_API BYTE TARGET_GetFlashSize(DWORD Addr, LPWORD val)
{
	if (!Cur_COM.isConnected)  return NO_CON_AVAILABLE;
	if (!Target->READ_CMD) return CMD_NOT_ALLOWED;

	LPBYTE pData = new BYTE[sizeof(*val)];
	memset(pData, 0xFF, sizeof(*val));

	BYTE Result = STBL_READ(Addr/*ADDR_FLASH_SIZE*/, sizeof(*val),pData);
	if (Result != SUCCESS) return Result;
	else memcpy(val, pData, sizeof(*val));
    
	return SUCCESS;  
}

/************************************************************************************/
/* GetMemoryAddress
/*
/*
/************************************************************************************/
STUARTBLLIB_API BYTE TARGET_GetMemoryAddress(DWORD Addr, LPBYTE val)
{
	if (!Cur_COM.isConnected)  return NO_CON_AVAILABLE;
	if (!Target->READ_CMD) return CMD_NOT_ALLOWED;

	LPBYTE pData = new BYTE[sizeof(*val)];
	memset(pData, 0xFF, sizeof(*val));

	BYTE Result = STBL_READ(Addr/*ADDR_RAM_SIZE*/, sizeof(*val),pData);
	if (Result != SUCCESS) return Result;
	else memcpy(val, pData, sizeof(*val));
    
	return SUCCESS;
}

/************************************************************************************/
/* GetRDPOptionByte
/*
/*
/************************************************************************************/
STUARTBLLIB_API BYTE TARGET_GetRDPOptionByte(LPBYTE RDP)
{
	if (!Cur_COM.isConnected)  return NO_CON_AVAILABLE;
	if (!Target->READ_CMD) return CMD_NOT_ALLOWED;

	LPBYTE pData = new BYTE[sizeof(DWORD)];
	memset(pData, 0xFF, sizeof(DWORD));

	BYTE Result = STBL_READ(ADDR_RDP_OPB, sizeof(DWORD),pData);
	if (Result != SUCCESS) return Result;
	else 
	{
	   if ((BYTE) pData[0] == 0xFF && (BYTE) pData[1] == 0xFF)
          *RDP = 0xFF;
	   else if ( ((BYTE) pData[0] + (BYTE) pData[1]) != 0xFF )
		  *RDP = 0xFF;
	   else if ( ((BYTE) pData[0] + (BYTE) pData[1]) == 0xFF )
		  *RDP = 0xA5; 
	}
    
	return SUCCESS; 
}

/************************************************************************************/
/* GetWRPOptionBytes
/*
/*
/************************************************************************************/
STUARTBLLIB_API BYTE TARGET_GetWRPOptionBytes(LPBYTE WRP0, LPBYTE WRP1, LPBYTE WRP2, LPBYTE WRP3)
{
	if (!Cur_COM.isConnected)  return NO_CON_AVAILABLE;
	if (!Target->READ_CMD) return CMD_NOT_ALLOWED;

	LPBYTE pData = new BYTE[sizeof(DWORD)];
	memset(pData, 0xFF, sizeof(DWORD));

	BYTE Result;

	if (GetAckValue() == 0x79)
	   Result = STBL_READ(ADDR_WRP0_OPB, sizeof(DWORD),pData);
	else if (GetAckValue() == 0x75)
       Result = STBL_READ(0x2010DFB0 /*ADDR_WRP0_OPB*/, sizeof(DWORD),pData);

	if (Result != SUCCESS) return Result;
	else 
	{
		if (GetAckValue() == 0x79)
		{
		   *WRP0 = (BYTE) pData[0];
		   *WRP1 = (BYTE) pData[2];
		}
		else if (GetAckValue() == 0x75)
		{
		   *WRP0 = (BYTE) pData[0];
		   *WRP1 = (BYTE) pData[1];
		   *WRP2 = (BYTE) pData[2];
		   *WRP3 = (BYTE) pData[3];
		}
	}

	memset(pData, 0xFF, sizeof(DWORD));

	if (GetAckValue() == 0x79)
	{
		Result = STBL_READ(ADDR_WRP2_OPB, sizeof(DWORD),pData);
		if (Result != SUCCESS) return Result;
		else 
		{
			*WRP2 = (BYTE) pData[0];
			*WRP3 = (BYTE) pData[2];
		}
	}
    
	return SUCCESS;  
}

/************************************************************************************/
/* GetUserOptionByte
/*
/*
/************************************************************************************/
STUARTBLLIB_API BYTE TARGET_GetUserOptionByte(LPBYTE User)
{
	if (!Cur_COM.isConnected)  return NO_CON_AVAILABLE;
	if (!Target->READ_CMD) return CMD_NOT_ALLOWED;

	LPBYTE pData = new BYTE[sizeof(DWORD)];
	memset(pData, 0xFF, sizeof(DWORD));

	BYTE Result = STBL_READ(ADDR_USER_OPB, sizeof(DWORD),pData);
	if (Result != SUCCESS) return Result;
	else *User = (BYTE) pData[2];
    
	return SUCCESS;  
}

/************************************************************************************/
/* GetDataOptionByte
/*
/*
/************************************************************************************/
STUARTBLLIB_API BYTE TARGET_GetDataOptionByte(LPBYTE Data0, LPBYTE Data1)
{
	if (!Cur_COM.isConnected)  return NO_CON_AVAILABLE;
	if (!Target->READ_CMD) return CMD_NOT_ALLOWED;

	LPBYTE pData = new BYTE[sizeof(DWORD)];
	memset(pData, 0xFF, sizeof(DWORD));

	BYTE Result = STBL_READ(ADDR_DATA_OPB, sizeof(DWORD),pData);
	if (Result != SUCCESS) return Result;
	else 
	{
		*Data0 = (BYTE) pData[0];
		*Data1 = (BYTE) pData[2];
	}
    
	return SUCCESS; 
}

/************************************************************************************/
/* SetOptionBytes
/*
/*
/************************************************************************************/
STUARTBLLIB_API BYTE TARGET_SetOptionBytes(DWORD Addr,BYTE User, BYTE RDP, BYTE Data0, BYTE Data1, 
								   BYTE WRP0, BYTE WRP1, BYTE WRP2, BYTE WRP3)
{
	if (!Cur_COM.isConnected)  return NO_CON_AVAILABLE;
	if (!Target->READ_CMD) return CMD_NOT_ALLOWED;

	LPBYTE pData = new BYTE[MAX_DATA_SIZE];
	memset(pData, 0xFF, MAX_DATA_SIZE);


	if ( Addr == ADDR_F1_OPB )
	{

	pData[0]  = RDP;
	pData[1]  = ~RDP;
	pData[2]  = User;
	pData[3]  = ~User;
	pData[4]  = Data0;
	pData[5]  = ~Data0;
	pData[6]  = Data1;
	pData[7]  = ~Data1;
	pData[8]  = WRP0;
	pData[9]  = ~WRP0;
	pData[10] = WRP1;
	pData[11] = ~WRP1;
	pData[12] = WRP2;
	pData[13] = ~WRP2;
	pData[14] = WRP3;
	pData[15] = ~WRP3;

	} else

	if ( Addr == ADDR_L1_OPB )
	{

	pData[0]  = RDP;
	pData[1]  = 0x00;
	pData[2]  = ~RDP;
	pData[3]  = 0x00;
	pData[4]  = User;
	pData[5]  = 0x00;
	pData[6]  = ~User;
	pData[7]  = 0x00;
	pData[8]  = WRP0;
	pData[9]  = WRP1;
	pData[10] = ~WRP0;
	pData[11] = ~WRP1;
	pData[12] = WRP2;
	pData[13] = WRP3;
	pData[14] = ~WRP2;
	pData[15] = ~WRP3;

	} else

	if ( Addr == ADDR_F2_OPB )
	{

	pData[0]  = User;
	pData[1]  = RDP;
	pData[2]  = 0xFF;
	pData[3]  = 0xFF;
	pData[4]  = 0xFF;
	pData[5]  = 0xFF;
	pData[6]  = 0xFF;
	pData[7]  = 0xFF;
	pData[8]  = WRP0;
	pData[9]  = WRP1;
	pData[10] = 0xFF;
	pData[11] = 0xFF;
	pData[12] = 0xFF;
	pData[13] = 0xFF;
	pData[14] = 0xFF;
	pData[15] = 0xFF;

	}


	BYTE Result = STBL_WRITE(Addr, 16,pData);
	if (Result != SUCCESS) return Result;
    
	return SUCCESS; 
}

/************************************************************************************/
/* SetSIFData
/*
/*
/************************************************************************************/
STUARTBLLIB_API BYTE TARGET_GetOptionBytes(DWORD Addr,LPBYTE User, LPBYTE RDP, LPBYTE Data0, LPBYTE Data1, 
								   LPBYTE WRP0, LPBYTE WRP1, LPBYTE WRP2, LPBYTE WRP3)
{
	if (!Cur_COM.isConnected)  return NO_CON_AVAILABLE;
	if (!Target->READ_CMD) return CMD_NOT_ALLOWED;

	LPBYTE pData = new BYTE[MAX_DATA_SIZE];
	memset(pData, 0xFF, MAX_DATA_SIZE);

	BYTE Result = STBL_READ(Addr, 16,pData);
	if (Result != SUCCESS) return Result;

	if ( Addr == ADDR_F1_OPB )
	{

	*RDP   = pData[0] ;
	*User  = pData[2];
    *Data0 = pData[4];
	*Data1 = pData[6];
	*WRP0  = pData[8];
	*WRP1  = pData[10];
	*WRP2  = pData[12];
	*WRP3  = pData[14];
	}
	else if  ( Addr == ADDR_L1_OPB )
	{
	*RDP   = pData[0] ;
	*User  = pData[4];
    *Data0 = 0x00;
	*Data1 = 0x00;
	*WRP0  = pData[8];
	*WRP1  = pData[9];
	*WRP2  = pData[12];
	*WRP3  = pData[13];

	}
	else if  ( Addr == ADDR_F2_OPB )
	{
	*RDP   = pData[1] ;
	*User  = pData[0];
    *Data0 = 0xFF;
	*Data1 = 0xFF;
	*WRP0  = pData[8];
	*WRP1  = pData[9];
	*WRP2  = 0xFF;
	*WRP3  = 0xFF;

	}

    
	return SUCCESS; 
}

/************************************************************************************/
/* GET PROGRESS STATE
/*
/*
/************************************************************************************/
STUARTBLLIB_API BYTE GetProgress(LPBYTE progress)
{
   if (ActivityTime == 0) ActivityTime = 1;

   int prog = (Progress*100)/ActivityTime;
   if (prog > 100) 
	   prog = 100;

   *progress = prog;
   return SUCCESS;
}
/************************************************************************************/
/* Get activity time
/*
/*
/************************************************************************************/
STUARTBLLIB_API BYTE GetActivityTime(LPDWORD time)
{
   *time = ActivityTime;
   return SUCCESS;
}  

/************************************************************************************/
/* Set activity time
/*
/*
/************************************************************************************/
STUARTBLLIB_API BYTE SetActivityTime(DWORD time)
{
   Progress = 0;
   ActivityTime = time;
   return SUCCESS;
}

/************************************************************************************/
/*   Set Rts Line State
/*   High = TRUE
/*   Low  = FALSE
/************************************************************************************/
STUARTBLLIB_API BYTE STBL_SetRts(bool Val)
{
	Cur_COM.setRts(Val);
	return SUCCESS;
}

/************************************************************************************/
/*   Set Dtr Line State
/*   High = TRUE
/*   Low  = FALSE
/************************************************************************************/
STUARTBLLIB_API BYTE STBL_SetDtr(BOOL Val)
{
    Cur_COM.setDtr(Val);
	return SUCCESS;
}

/************************************************************************************/
/*   Set the state of TXD. Return: true if success.
/*   High = TRUE
/*   Low  = FALSE
/************************************************************************************/
STUARTBLLIB_API BYTE STBL_setTxd(BOOL val)
{
	Cur_COM.setTxd(val);
	return SUCCESS;
}
		
/************************************************************************************/
/*   Return: The state of CTS.
/*   High = TRUE
/*   Low  = FALSE
/************************************************************************************/
STUARTBLLIB_API BYTE STBL_getCts(BOOL* pval)	
{
   *pval = Cur_COM.getCts();
   return SUCCESS;
}				
			
/************************************************************************************/
/*   Return: The state of DTR.
/*   High = TRUE
/*   Low  = FALSE
/************************************************************************************/
STUARTBLLIB_API BYTE STBL_getDtr(BOOL* pval)	
{
   *pval = Cur_COM.getDtr();
   return SUCCESS;
}
					
/************************************************************************************/
/*   Return: The state of RI.
/*   High = TRUE
/*   Low  = FALSE
/************************************************************************************/
STUARTBLLIB_API BYTE STBL_getRi(BOOL* pval)
{
   *pval = Cur_COM.getRi();
   return SUCCESS;
}					
	
/************************************************************************************/
/*   Return: The state of DTR.
/*   High = TRUE
/*   Low  = FALSE
/************************************************************************************/
STUARTBLLIB_API BYTE STBL_getCd(BOOL* pval)	
{
   *pval = Cur_COM.getCd();
   return SUCCESS;
}


/************************************************************************************/
/* Set Echo Mode
/*   0   =  Echo Disabled
/*   1   =  Echo Back Enabled
/*   2   =  Listen Echo Enabled
/************************************************************************************/
STUARTBLLIB_API  BYTE STBL_SetEcho(int val)
{
	Cur_COM.bEcho= val;
	return SUCCESS;

}


/************************************************************************************/
/* SetFlowControl : Enable/Disable Flow Control of DTR and RTS
/* FALSE   =   Disabled
/* TRUE    =   Enabled
/************************************************************************************/
STUARTBLLIB_API  BYTE STBL_SetFlowControl(bool val)
{
	Cur_COM.FlowControl= val;
	return SUCCESS;
}
/******************* (C) COPYRIGHT 2012 STMicroelectronics *****END OF FILE******/

