view Discovery/Src/tComm.c @ 471:73da921869d9 fix-bat-2

bugfix: implement battery charge percentage in dive header This commit is (much) less trivial than the related 919e5cb51c92. First, rename the CCRmode attribute (corresponding to byte Ox59) of the SLogbookHeaderOSTC3. This byte (according to the hwOS interface document) does not contain any CCR related value, but it contains "battery information". Already since 2017, this byte is used from libdivecomputer to interface the charge percentage. So, its renamed from CCRmode to batteryCharge, to reflect its true purpose. Now, simply add a batteryCharge attribute to the SLogbookHeader (and see below why that is possible, without breaking things). The remaining changes are trivial to implement battery charge percentage in dive header. Caveat: do not get confused by the exact role of the individual logbook header types. SLogbookHeaderOSTC3 is the formal type of the logbook format that the OSTC4 produces. This format is supposed to identical to the format, as is used in hwOS for the series of small OSTCs. Only some values of attributes are different. For example, the OSTC4 supports VPM, so byte 0x79 (deco model used for this dive) also has a value for VPM. But the SLogbookHeader type, despite its name and structure, is *not* a true logbook header, as it includes attributes that are not available in the SLogbookHeaderOSTC3 formal header type. Signed-off-by: Jan Mulder <jan@jlmulder.nl>
author Jan Mulder <jlmulder@xs4all.nl>
date Wed, 22 Apr 2020 13:08:57 +0200
parents 5387e684d797
children 0ad0b26ec56b
line wrap: on
line source

///////////////////////////////////////////////////////////////////////////////
/// -*- coding: UTF-8 -*-
///
/// \file   Discovery/Src/tComm.c
/// \brief  Main file for communication with PC
/// \author heinrichs weikamp gmbh
/// \date   08-Aug-2014
///
/// \details
///
/// $Id$
///////////////////////////////////////////////////////////////////////////////
/// \par Copyright (c) 2014-2018 Heinrichs Weikamp gmbh
///
///     This program is free software: you can redistribute it and/or modify
///     it under the terms of the GNU General Public License as published by
///     the Free Software Foundation, either version 3 of the License, or
///     (at your option) any later version.
///
///     This program is distributed in the hope that it will be useful,
///     but WITHOUT ANY WARRANTY; without even the implied warranty of
///     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
///     GNU General Public License for more details.
///
///     You should have received a copy of the GNU General Public License
///     along with this program.  If not, see <http://www.gnu.org/licenses/>.
//////////////////////////////////////////////////////////////////////////////

/**
  ==============================================================================
                        ##### How to use #####
  ==============================================================================
    ==============================================================================
              ##### History #####
  ==============================================================================
    160211 added 4 bytes Serial in update Files after checksum prior to binary
    160211 0x6B changed to version only
    160623 fixed 0x72 (in V1.0.9)
    160623 fixed rebuild menu (before update) for V1.0.10

    ==============================================================================
              ##### CTS / RTS #####
  ==============================================================================
    RTS is Output, CTS is Input

    BlueMod Pin D7 UART-RTS# is Output
    connected to STM32F429 PA11 CTS (Input)
    also STM32 PA12 RTS is connected to BlueMod UART-CTS# F3

    see BlueMod_SR_HWreference_r06.pdf, page 156
    and MAIN_CPU STM32F4 Reference manual DM00031020.pdf, page 990


    ==============================================================================
              ##### Codes #####
  ==============================================================================
  [0x73] upload CPU2 firmware in SDRAM and update CPU2

  [0x74] upload MainCPU firmware in EEPROM and start bootloader

  */

/* Includes ------------------------------------------------------------------*/

#include "tComm.h"

#include "externCPU2bootloader.h"
#include "externLogbookFlash.h"
#include "gfx_colors.h"
#include "gfx_engine.h"
#include "gfx_fonts.h"
#include "ostc.h"

#ifndef BOOTLOADER_STANDALONE
#	include "base.h"
#	include "tHome.h"
#	include "logbook.h"
#	include "tMenu.h"
#else
#	include "base_bootloader.h"
#	include "firmwareEraseProgram.h"
#endif

#ifdef SPECIALPROGRAMM
#	include "firmwareEraseProgram.h"
#endif
#include <stdlib.h>
#include <string.h>


/* Private variables ---------------------------------------------------------*/
GFX_DrawCfgScreen	tCscreen;
GFX_DrawCfgWindow	tCwindow;

uint8_t receiveStartByteUart = 0;
uint8_t bluetoothActiveLastTime = 0;

uint8_t StartListeningToUART = 0;
char display_text[256] = { 0 };

uint8_t setForcedBluetoothName = 0;

uint8_t updateSettingsAndMenuOnExit = 0;

/* Private types -------------------------------------------------------------*/
#define BYTE_DOWNLOAD_MODE			(0xBB)
#define BYTE_SERVICE_MODE			(0xAA)

#define UART_OPERATION_TIMEOUT		(500u)		/* Timeout for common read / write operations (ms) */
#define UART_TIMEOUT_SECONDS		(120u)		/* Timeout for keeping connection open and waiting for data */
#define UART_TIMEOUT_LARGE_BLOCK 	(6000u)		/* Timeout (ms) for reception of an 16K data block (typical RX time ~4,5seconds) */

#define UART_CMD_BUF_SIZE			(20u)		/* size of buffer for command exchange */

const uint8_t id_Region1_firmware = 0xFF;
const uint8_t id_RTE = 0xFE;
const uint8_t id_FONT = 0x10;
const uint8_t id_FONT_OLD = 0x00;

static BlueModTmpConfig_t BmTmpConfig = BM_CONFIG_OFF;	/* Config BlueMod without storing the changes */
static uint8_t EvaluateBluetoothSignalStrength = 0;
static uint8_t RequestDisconnection = 0; 				/* Disconnection from remote device requested */
/* Private function prototypes -----------------------------------------------*/
static void tComm_Disconnect(void);
static void tComm_Error_Handler(void);
static uint8_t select_mode(uint8_t aRxByte);
static uint8_t tComm_CheckAnswerOK(void);
static uint8_t tComm_HandleBlueModConfig(void);
static void tComm_EvaluateBluetoothStrength(void);
uint8_t receive_update_flex(uint8_t isRTEupdateALLOWED);
uint8_t receive_update_data_flex(uint8_t* pBuffer1, uint8_t* pBuffer2, uint8_t RTEupdateALLOWED);
uint8_t receive_update_data_mainCPU_firmware(void);
uint8_t receive_update_data_mainCPU_variable_firmware(void);
uint8_t receive_update_data_mainCPU_firmware_subroutine(uint8_t region, uint8_t* pBuffer1, uint8_t* pBuffer2);
HAL_StatusTypeDef receive_uart_large_size(UART_HandleTypeDef *huart, uint8_t *pData, uint32_t Size);
static uint8_t openComm(uint8_t aRxByte);
uint8_t HW_Set_Bluetooth_Name(uint16_t serial, uint8_t withEscapeSequence);
uint8_t prompt4D4C(uint8_t mode);

#ifdef BOOTLOADER_STANDALONE
    static uint8_t receive_update_data_cpu2(void);
    uint8_t receive_update_data_cpu2_sub(uint8_t* pBuffer);
#endif

/* Exported functions --------------------------------------------------------*/

void tComm_init(void)
{
    tCscreen.FBStartAdress = 0;
    tCscreen.ImageHeight = 480;
    tCscreen.ImageWidth = 800;
    tCscreen.LayerIndex = 1;

    tCwindow.Image = &tCscreen;
    tCwindow.WindowNumberOfTextLines = 6;
    tCwindow.WindowLineSpacing = 65;
    tCwindow.WindowTab = 400;
    tCwindow.WindowX0 = 20;
    tCwindow.WindowX1 = 779;


    if(!settingsGetPointer()->FlipDisplay)
    {
        tCwindow.WindowY0 = 0;
        tCwindow.WindowY1 = 479;
    }
    else
    {
    	tCwindow.WindowY0 = 479 - 390;
    	tCwindow.WindowY1 = 479 - 25;
    }

    StartListeningToUART = 1;
}

uint8_t tComm_control(void)
{
    uint8_t answer  = 0;
#ifndef BOOTLOADER_STANDALONE

    /* should do something like reset UART ... */
    if(	settingsGetPointer()->bluetoothActive == 0)
    {
        if(bluetoothActiveLastTime)
        {
        	HAL_UART_AbortReceive_IT(&UartHandle);
            HAL_UART_DeInit(&UartHandle);
            HAL_Delay(1);
            UartHandle.Init.BaudRate   = 115200;	/* Module will be operating at default baud rate if powered again */
            BmTmpConfig = BM_CONFIG_OFF;			/* Restart configuration if powered again */
            HAL_UART_Init(&UartHandle);
            HAL_Delay(1);
            UartReady = RESET;
            StartListeningToUART = 1;
            bluetoothActiveLastTime = 0;
            receiveStartByteUart = 0;
            RequestDisconnection = 0;
        }
        return 0;
    }
    else
    {
        bluetoothActiveLastTime = 1;
        if(RequestDisconnection)
        {
        	RequestDisconnection = 0;
            tComm_Disconnect();
        }
    }

#endif

    if(BmTmpConfig != BM_CONFIG_DONE)
    {
    	tComm_HandleBlueModConfig();
    }
    else
    {
    /*##-2- Put UART peripheral in reception process ###########################*/

		if((UartReady == RESET) && StartListeningToUART)
		{
				StartListeningToUART = 0;
				if(HAL_UART_Receive_IT(&UartHandle, &receiveStartByteUart, 1) != HAL_OK)
						tComm_Error_Handler();
		}
		/* Reset transmission flag */
		if(UartReady == SET)
		{
				UartReady = RESET;
				if((receiveStartByteUart == BYTE_DOWNLOAD_MODE) || (receiveStartByteUart == BYTE_SERVICE_MODE))
					answer = openComm(receiveStartByteUart);
				StartListeningToUART = 1;
				return answer;
		}
    }
    return 0;
}


void tComm_refresh(void)
{
    if(tCscreen.FBStartAdress == 0)
    {
        GFX_hwBackgroundOn();
        tCscreen.FBStartAdress = getFrame(18);
        write_content_simple(&tCscreen, 0, 800, 480-24, &FontT24,"Exit",CLUT_ButtonSurfaceScreen);
        write_content_simple(&tCscreen, 800 - 70, 800, 480-24, &FontT24,"Signal",CLUT_ButtonSurfaceScreen);

        if(receiveStartByteUart == BYTE_SERVICE_MODE)
            GFX_write_string(&FontT48, &tCwindow, "Service mode enabled",2);
        else
            GFX_write_string(&FontT48, &tCwindow, "Download mode enabled",2);
        GFX_SetFramesTopBottom(tCscreen.FBStartAdress, 0,480);
        display_text[0] = 0;
        display_text[255] = 0;
    }
    else if(display_text[255])
    {
        display_text[(uint8_t)display_text[255]] = 0;
        releaseFrame(18,tCscreen.FBStartAdress);
        tCscreen.FBStartAdress = getFrame(18);
        write_content_simple(&tCscreen, 0, 800, 480-24, &FontT24,"Exit",CLUT_ButtonSurfaceScreen);
        write_content_simple(&tCscreen, 800 - 70, 800, 480-24, &FontT24,"Signal",CLUT_ButtonSurfaceScreen);
        GFX_write_string(&FontT48, &tCwindow, display_text,2);
        GFX_SetFrameTop(tCscreen.FBStartAdress);
        display_text[0] = 0;
        display_text[255] = 0;
    }
}


void tComm_verlauf(uint8_t percentage_complete)
{
    uint32_t pDestination;

    pDestination = (uint32_t)tCscreen.FBStartAdress;
    pDestination += 150 * tCscreen.ImageHeight * 2;
    pDestination += 100 * 2;

    if(percentage_complete > 100)
        percentage_complete = 100;

    int i = 1;
    while(i<=percentage_complete)
    {
        i += 1;
        for(int y=0;y<4;y++)
        {
            for(int x=0;x<40;x++)
            {
                *(__IO uint16_t*)pDestination = 0xFF00 + 00;
                    pDestination += 2;
            }
            pDestination += (tCscreen.ImageHeight  - 40 )* 2;
        }
        pDestination += tCscreen.ImageHeight * 2; // one spare line
    }
}


void tComm_exit(void)
{
    SStateList status;
    get_globalStateList(&status);

    releaseFrame(18,tCscreen.FBStartAdress);
    tCscreen.FBStartAdress = 0;
    GFX_hwBackgroundOff();

    if(setForcedBluetoothName)
    {
        setForcedBluetoothName = 0;
        MX_Bluetooth_PowerOff();
        HAL_Delay(1000);
        MX_Bluetooth_PowerOn();
        tComm_Set_Bluetooth_Name(1);
        tComm_StartBlueModConfig();
    }
#ifndef BOOTLOADER_STANDALONE
    if(updateSettingsAndMenuOnExit)
    {
        check_and_correct_settings();
        createDiveSettings();
        tM_rebuild_menu_after_tComm();
    }
#endif
    updateSettingsAndMenuOnExit = 0;

    if(status.base == BaseComm)
    {
#ifndef BOOTLOADER_STANDALONE
    set_globalState_tHome();
#else
    set_globalState_Base();
#endif
    }
    settingsGetPointer()->bluetoothActive = 0;
    MX_Bluetooth_PowerOff();						// Power down Bluetooth on the way out
}


uint8_t tComm_Set_Bluetooth_Name(uint8_t force)
{
    uint8_t answer = 0;

    if(hardwareDataGetPointer()->secondarySerial != 0xFFFF)
    {
        if(force || (hardwareDataGetPointer()->secondary_bluetooth_name_set == 0xFF))
            answer = HW_Set_Bluetooth_Name(hardwareDataGetPointer()->secondarySerial, 0);
#ifdef BOOTLOADER_STANDALONE
            if(answer == HAL_OK)
                hardware_programmSecondaryBluetoothNameSet();
#endif
    }
    else
    if(hardwareDataGetPointer()->primarySerial != 0xFFFF)
    {
        if(force || (hardwareDataGetPointer()->production_bluetooth_name_set == 0xFF))
            answer = HW_Set_Bluetooth_Name(hardwareDataGetPointer()->primarySerial, 0);
#ifdef BOOTLOADER_STANDALONE
            if(answer == HAL_OK)
                hardware_programmPrimaryBluetoothNameSet();
#endif
    }
    return answer;
}


uint8_t HW_Set_Bluetooth_Name(uint16_t serial, uint8_t withEscapeSequence)
{
    uint8_t answer = HAL_OK;
    uint8_t aRxBuffer[50];

//	char aTxFactoryDefaults[50] = "AT&F1\r";

    char aTxBufferEscapeSequence[50] = "+++";
    // limit is 19 chars, with 7 chars shown in BLE advertising mode
    //________________________123456789012345678901
    char aTxBufferName[50] = "AT+BNAME=OSTC4-12345\r";
    char answerOkay[6] = "\r\nOK\r\n";

    gfx_number_to_string(5,1,&aTxBufferName[15],serial);

    // store active configuration in non-volatile memory
    char aTxBufferWrite[50] = "AT&W\r";

//	char aTxBufferReset[50] = "AT+RESET\r";


    HAL_Delay(1010);
    if(withEscapeSequence)
    {
        aRxBuffer[0] = 0;
        if(HAL_UART_Transmit(&UartHandle, (uint8_t*)aTxBufferEscapeSequence, 3, 2000)!= HAL_OK)
            answer = HAL_ERROR;
        HAL_UART_Receive(&UartHandle, (uint8_t*)aRxBuffer, 3, 2000);
        HAL_Delay(1010);

        for(int i=0;i<3;i++)
        if(aRxBuffer[i] != '+')
            answer = HAL_ERROR;
    }

    aRxBuffer[0] = 0;
    if(HAL_UART_Transmit(&UartHandle, (uint8_t*)aTxBufferName, 21, 2000)!= HAL_OK)
        answer = HAL_ERROR;
    HAL_UART_Receive(&UartHandle, (uint8_t*)aRxBuffer, 21+6, 2000);

    for(int i=0;i<21;i++)
    if(aRxBuffer[i] != aTxBufferName[i])
        answer = HAL_ERROR;

    for(int i=0;i<6;i++)
    if(aRxBuffer[21+i] != answerOkay[i])
        answer = HAL_ERROR;

    HAL_Delay(200);

    if(HAL_UART_Transmit(&UartHandle, (uint8_t*)aTxBufferWrite, 5, 2000)!= HAL_OK)
        answer = HAL_ERROR;
    HAL_UART_Receive(&UartHandle, (uint8_t*)aRxBuffer, 5+6, 2000);

    for(int i=0;i<5;i++)
    if(aRxBuffer[i] != aTxBufferWrite[i])
        answer = HAL_ERROR;

    for(int i=0;i<6;i++)
    if(aRxBuffer[5+i] != answerOkay[i])
        answer = HAL_ERROR;

    answer = HAL_OK;
    return answer;
}

void tComm_Disconnect()
{
	uint8_t answer;
	uint8_t retrycnt = 3;
	char aTxDisconnect[] ="ATH\r";
	char aTxBufferEnd[] = "ATO\r";
	char aTxBufferEscapeSequence[] = "+++";

	uint8_t sizeDisconnect = sizeof(aTxDisconnect) -1;

	HAL_UART_AbortReceive_IT(&UartHandle);
	do
	{
		HAL_Delay(200);
		if(HAL_UART_Transmit(&UartHandle, (uint8_t*)aTxBufferEscapeSequence, 3, UART_OPERATION_TIMEOUT)== HAL_OK)
		{
			answer = tComm_CheckAnswerOK();
		}
		retrycnt--;
	}
	while((answer != HAL_OK) && (retrycnt > 0));

	if(answer == HAL_OK)
	{
		answer = HAL_ERROR;
		if(HAL_UART_Transmit(&UartHandle, (uint8_t*)aTxDisconnect,sizeDisconnect , UART_OPERATION_TIMEOUT)== HAL_OK)
		{
			answer = HAL_ERROR;
			if(tComm_CheckAnswerOK() == HAL_OK)
			{
				answer = HAL_ERROR;
				if(HAL_UART_Transmit(&UartHandle, (uint8_t*)aTxBufferEnd, 4, UART_OPERATION_TIMEOUT) == HAL_OK)	/* exit terminal mode */
				{
					answer = tComm_CheckAnswerOK();
				}
			}
		}
	}

	if(answer != HAL_OK)		/* we are somehow not able to do a clean disconnect => fallback to "previous" power off implementation" */
	{
		settingsGetPointer()->bluetoothActive = 0;
		MX_Bluetooth_PowerOff();
	}
}


uint8_t openComm(uint8_t aRxByte)
{
	SStateList status;
	uint8_t localRx;
	uint8_t timeoutCounter = 0;
    uint8_t answer = 0;
    uint8_t service_mode_last_three_bytes[3];
    uint8_t service_mode_response[5] =
    {
        0x4B,
        0xAB,
        0xCD,
        0xEF,
        0x4C
    };
    uint8_t download_mode_response[2] =
    {
        0xBB,
        0x4D
    };

    if((aRxByte != BYTE_DOWNLOAD_MODE) && (aRxByte != BYTE_SERVICE_MODE))
        return 0;

    set_globalState(StUART_STANDARD);

    /* service mode is four bytes
    0xAA 0xAB 0xCD 0xEF
    answer is
    */
    localRx = aRxByte;

    if(aRxByte == BYTE_SERVICE_MODE)
    {
        if((HAL_UART_Receive(&UartHandle, (uint8_t*)service_mode_last_three_bytes, 3, 2000)!= HAL_OK))
            answer = 0x00;
        else
        {
            if((service_mode_last_three_bytes[0] != 0xAB) || (service_mode_last_three_bytes[1] != 0xCD) || (service_mode_last_three_bytes[2] != 0xEF))
                answer = 0x00;
            else
            {
                if(HAL_UART_Transmit(&UartHandle, (uint8_t*)service_mode_response, 5, 2000)!= HAL_OK)
                    answer = 0x00;
                else
                    answer = prompt4D4C(receiveStartByteUart);
            }
        }
    }
    else	//if(aRxByte == BYTE_SERVICE_MODE)
    {
        if(HAL_UART_Transmit(&UartHandle, (uint8_t*)download_mode_response, 2, 2000)!= HAL_OK)
            answer = 0x00;
        else
            answer = prompt4D4C(receiveStartByteUart);
    }

    while((answer == prompt4D4C(receiveStartByteUart)) && (timeoutCounter < UART_TIMEOUT_SECONDS)) 	/* try receive once a second */
    {
    	if(HAL_UART_Receive(&UartHandle, (uint8_t*)&localRx, 1, UART_OPERATION_TIMEOUT)!= HAL_OK)
    	{
    		timeoutCounter++;
    		get_globalStateList(&status);
    		if (status.base != BaseComm)
    		{
    			timeoutCounter = UART_TIMEOUT_SECONDS; /* Abort action triggered outside main loop => exit */
    		}
    		if(EvaluateBluetoothSignalStrength)
    		{
    			tComm_EvaluateBluetoothStrength();
    		}
    	}
    	else
    	{
    		answer = select_mode(localRx);
    		timeoutCounter = 0;
    	}
    }
    set_returnFromComm();
    return 1;
}


uint8_t prompt4D4C(uint8_t mode)
{
    if(mode == BYTE_SERVICE_MODE)
        return 0x4C;
    else
        return 0x4D;
}


uint8_t select_mode(uint8_t type)
{
#ifndef BOOTLOADER_STANDALONE
    SLogbookHeader logbookHeader;
    SLogbookHeaderOSTC3 * plogbookHeaderOSTC3;
    SLogbookHeaderOSTC3compact * plogbookHeaderOSTC3compact;
    uint32_t sampleTotalLength;
    SSettings* pSettings = settingsGetPointer();
    RTC_DateTypeDef sdatestructure;
    RTC_TimeTypeDef stimestructure;
#else
    uint8_t dummyForBootloader[256] = {0};
#endif
    uint8_t count;
    uint8_t aTxBuffer[128];
    uint8_t aRxBuffer[68];
    uint8_t answer;
    uint16_t index;
    uint32_t header_profileLength, OSTC3_profileLength;
    aTxBuffer[0] = type;
    aTxBuffer[1] = prompt4D4C(receiveStartByteUart);
    uint8_t tempHigh, tempLow;
    count = 0;

    // service mode only commands
    if(receiveStartByteUart == BYTE_SERVICE_MODE)
    {
        // first part
        switch(type)
        {
        // start communication (again)
        case 0xAA:
            if(HAL_UART_Transmit(&UartHandle, (uint8_t*)aTxBuffer, 2, 1000)!= HAL_OK)
                return 0;
            else
                return prompt4D4C(receiveStartByteUart);

/*
        // update firmware main preparation
        case 0x74:
            ext_flash_erase_firmware_if_not_empty();
            break;

        // update firmware main with variable full access memory location preparation
        case 0x76:
            ext_flash_erase_firmware2_if_not_empty();
            break;
*/
        default:
            break;
        }

#ifndef BOOTLOADER_STANDALONE
        uint32_t logCopyDataPtr = 0;
        convert_Type logCopyDataLength;
        uint32_t logCopyDataPtrTemp = 0;
        uint32_t logCopyDataLengthTemp = 0;
        uint8_t logDummyByte = 0;
        uint8_t logStepBackwards = 0;
        convert16_Type totalDiveCount;
        logCopyDataLength.u32bit = 0;
        totalDiveCount.u16bit = 0;
#endif

        // Exit communication on Text like RING, CONNECT, ... or 0xFF command
        if((type < 0x60) || (type == 0xFF))
            return 0;

        // return of command for (almost) all commands
        switch(type)
        {
        // not supported yet case 0x20: // 	send hi:lo:temp1 bytes starting from ext_flash_address:3
        // not supported yet case 0x22: // 	Resets all logbook pointers and the logbook (!)
        // not supported yet case 0x23: // 	Resets battery gauge registers
        // not supported yet case 0x30: // 	write bytes starting from ext_flash_address:3 (Stop when timeout)
        // not supported yet case 0x40: // 	erases 4kB block from ext_flash_address:3 (Warning: No confirmation or built-in security here...)
        // not supported yet case 0x42: // 	erases range in 4kB steps (Get 3 bytes address and 1byte amount of 4kB blocks)
        // not supported yet case 0x50: // 	sends firmware from external flash from 0x3E0000 to 0x3FD000 (118784bytes) via comm
        case 0xFE: // hw unit_tests
        case 0x71: // hw read manufacturing data
        case 0x73: // hw update FLEX
        case 0x79: // hw read device data
#ifdef BOOTLOADER_STANDALONE
        case 0x74: // hw update Firmware
        case 0x75: // hw update RTE
        case 0x76: // hw update Fonts
        case 0x80: // hw write manufacturing data
        case 0x81: // hw write second serial
        case 0x82: // hw set bluetooth name
#else
        case 0x83: // hw copy logbook entry - read
        case 0x84: // hw copy logbook entry - write
        case 0x85: // hw read entire logbook memory
        case 0x86: // hw overwrite entire logbook memory
        case 0x87: // hw ext_flash_repair_SPECIAL_dive_numbers_starting_count_with memory(x)
        case 0x88: /* read entire sample memory  */
        case 0x89: /* write entire sample memory */

#endif
        case 0xC1: // 	Start low-level bootloader
            if(HAL_UART_Transmit(&UartHandle, (uint8_t*)aTxBuffer, 1, UART_OPERATION_TIMEOUT)!= HAL_OK)
                return 0;
            break;
        default:
            break;
        }

        // now send content or update firmware
        switch(type)
        {
        case 0xFE:
            // work to do :-)  12. Oct. 2015
            // 256 bytes output
            memset(aTxBuffer,0,128);
            if(HAL_UART_Transmit(&UartHandle, (uint8_t*)aTxBuffer, 128,5000)!= HAL_OK)
                return 0;
            if(HAL_UART_Transmit(&UartHandle, (uint8_t*)aTxBuffer, 128,5000)!= HAL_OK)
                return 0;
            aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
            break;

        case 0x71:
            memcpy(aTxBuffer,hardwareDataGetPointer(),64);
            count += 64;
            aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
            break;

        case 0x73:
#ifndef BOOTLOADER_STANDALONE
            answer = receive_update_flex(1);
#else
            answer = receive_update_flex(0);
#endif
            if(answer == 0)
                return 0;
            else if(answer == 2) // 2 = RTE without bootToBootloader
            {
                aTxBuffer[0] = 0xFF;
                HAL_UART_Transmit(&UartHandle, (uint8_t*)aTxBuffer, 1,10000);
                return 0;
            }
            else
            {
                aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
                if(answer == 1) /* 0xFF is checksum error, 2 = RTE without bootToBootloader */
                {
                    extern	uint8_t bootToBootloader;
                    bootToBootloader = 1;
                }
            }
            break;

        case 0x79:
            if(HAL_UART_Transmit(&UartHandle, (uint8_t*)aTxBuffer, 1,10000)!= HAL_OK)
                return 0;
            ext_flash_read_fixed_16_devicedata_blocks_formated_128byte_total(aTxBuffer);
            if(HAL_UART_Transmit(&UartHandle, (uint8_t*)aTxBuffer, 128,5000)!= HAL_OK)
                return 0;
            aTxBuffer[0] = prompt4D4C(receiveStartByteUart);
            if(HAL_UART_Transmit(&UartHandle, (uint8_t*)aTxBuffer, 1,10000)!= HAL_OK)
                return 0;
            else
                return prompt4D4C(receiveStartByteUart);

        case 0x82:
#ifdef BOOTLOADER_STANDALONE
            setForcedBluetoothName = 1;
            return 0;
#else
        settingsGetPointer()->debugModeOnStart = 1;
        extern	uint8_t bootToBootloader;
        bootToBootloader = 1;
        return prompt4D4C(receiveStartByteUart);
#endif

#ifdef BOOTLOADER_STANDALONE
        case 0x74:
            answer = receive_update_data_mainCPU_firmware();
            if(answer != 0)
            {
                aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
                if(answer == 1) // 0xFF is checksum error
                {
                    extern	uint8_t bootToBootloader;
                    bootToBootloader = 1;
                }
            }
            else
                return 0;
            break;

        case 0x75:
            receive_update_data_cpu2();
            aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
            break;

        case 0x76:
            answer = receive_update_data_mainCPU_variable_firmware();
            if(answer != 0)
            {
                aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
                if(answer == 1) // 0xFF is checksum error
                {
                    extern	uint8_t bootToBootloader;
                    bootToBootloader = 1;
                }
            }
            else
                return 0;
            break;

        case 0x80:
            if(HAL_UART_Receive(&UartHandle, (uint8_t*)aRxBuffer,  52, 5000)!= HAL_OK)
                return 0;
            if(hardware_programmProductionData(aRxBuffer) == HAL_OK)
            {
                aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
            }
            else
                return 0;
            break;

        case 0x81:
            if(HAL_UART_Receive(&UartHandle, (uint8_t*)aRxBuffer,  12, 1000)!= HAL_OK)
                return 0;
            if(hardware_programmSecondarySerial(aRxBuffer) == HAL_OK)
            {
                aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
            }
            else
                return 0;
            break;

#else

#ifdef SPECIALPROGRAMM
        case 0x80:
            if(HAL_UART_Receive(&UartHandle, (uint8_t*)aRxBuffer,  52, 5000)!= HAL_OK)
                return 0;
            if(hardware_programmProductionData(aRxBuffer) == HAL_OK)
            {
                aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
            }
            else
                return 0;
            break;
#endif
        case 0x83:
            if(HAL_UART_Receive(&UartHandle, &logStepBackwards,  1, 1000)!= HAL_OK)
                return 0;
            logCopyDataPtr = getFrame(98);
            logCopyDataPtrTemp = logCopyDataPtr;
            logCopyDataLength.u32bit = ext_flash_read_dive_raw_with_double_header_1K((uint8_t *)logCopyDataPtr, 1000000,logStepBackwards);
            answer = HAL_OK;
            if(answer == HAL_OK)
                answer  = HAL_UART_Transmit(&UartHandle, &(logCopyDataLength.u8bit.byteLow), 1,2000);
            if(answer == HAL_OK)
                answer  = HAL_UART_Transmit(&UartHandle, &(logCopyDataLength.u8bit.byteMidLow), 1,2000);
            if(answer == HAL_OK)
                answer  = HAL_UART_Transmit(&UartHandle, &(logCopyDataLength.u8bit.byteMidHigh), 1,2000);
            if(answer == HAL_OK)
                answer  = HAL_UART_Transmit(&UartHandle, &(logCopyDataLength.u8bit.byteHigh), 1,2000);
            logCopyDataLengthTemp = logCopyDataLength.u32bit;
            while((logCopyDataLengthTemp >= 0xFFFF) && (answer == HAL_OK))
            {
                answer  = HAL_UART_Transmit(&UartHandle, (uint8_t *)logCopyDataPtrTemp, 0xFFFF,30000);
                logCopyDataLengthTemp -= 0xFFFF;
                logCopyDataPtrTemp += 0xFFFF;
            }
            if((logCopyDataLengthTemp > 0) && (answer == HAL_OK))
                answer  = HAL_UART_Transmit(&UartHandle, (uint8_t *)logCopyDataPtrTemp, (uint16_t)logCopyDataLengthTemp,30000);
            releaseFrame(98,logCopyDataPtr);
            if(answer == HAL_OK)
                aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
            else
                return 0;
            break;

        case 0x84:
            logCopyDataPtr = getFrame(98);
            logCopyDataPtrTemp = logCopyDataPtr;
            answer = HAL_OK;
            if(answer == HAL_OK)
                    answer  = HAL_UART_Receive(&UartHandle, &logDummyByte, 1,2000);
            if(answer == HAL_OK)
                    answer  = HAL_UART_Receive(&UartHandle, &(logCopyDataLength.u8bit.byteLow), 1,2000);
            if(answer == HAL_OK)
                answer  = HAL_UART_Receive(&UartHandle, &(logCopyDataLength.u8bit.byteMidLow), 1,2000);
            if(answer == HAL_OK)
                answer  = HAL_UART_Receive(&UartHandle, &(logCopyDataLength.u8bit.byteMidHigh), 1,2000);
            if(answer == HAL_OK)
                answer  = HAL_UART_Receive(&UartHandle, &(logCopyDataLength.u8bit.byteHigh), 1,2000);
            logCopyDataLengthTemp = logCopyDataLength.u32bit;
            while((logCopyDataLengthTemp >= 0xFFFF) && (answer == HAL_OK))
            {
                answer  = HAL_UART_Receive(&UartHandle, (uint8_t *)logCopyDataPtrTemp, 0xFFFF,30000);
                logCopyDataLengthTemp -= 0xFFFF;
                logCopyDataPtrTemp += 0xFFFF;
            }
            if((logCopyDataLengthTemp > 0) && (answer == HAL_OK))
                answer  = HAL_UART_Receive(&UartHandle, (uint8_t *)logCopyDataPtrTemp, (uint16_t)logCopyDataLengthTemp,30000);
            if(answer == HAL_OK)
                ext_flash_write_dive_raw_with_double_header_1K((uint8_t *)logCopyDataPtr, logCopyDataLength.u32bit);
            releaseFrame(98,logCopyDataPtr);
            if(answer == HAL_OK)
                aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
            else
                return 0;
            break;

        case 0x85:
            aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
            logCopyDataPtr = getFrame(98);
            ext_flash_read_header_memory((uint8_t *)logCopyDataPtr);
            for(int i=0;i<8;i++)
                HAL_UART_Transmit(&UartHandle, (uint8_t *)(logCopyDataPtr + (0x8000 * i)), (uint16_t)0x8000,60000);
            releaseFrame(98,logCopyDataPtr);
#ifdef SEND_DATA_DETAILS
            HAL_UART_Transmit(&UartHandle, (uint8_t*)&pSettings->lastDiveLogId, 1,60000);
#endif
            break;

        case 0x86:
            aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
            logCopyDataPtr = getFrame(98);
            for(int i=0;i<8;i++)
            {
                HAL_UART_Receive(&UartHandle, (uint8_t *)(logCopyDataPtr + (0x8000 * i)), (uint16_t)0x8000,60000);
            }
            ext_flash_write_header_memory((uint8_t *)logCopyDataPtr);
#ifdef SEND_DATA_DETAILS
            if(HAL_UART_Receive(&UartHandle, (uint8_t *)(logCopyDataPtr + (0x8000 * 8)), (uint16_t)0x01,60000) == HAL_OK)	/* receive lastlogID */
            {
            	pSettings->lastDiveLogId = *(uint8_t*)(logCopyDataPtr + (0x40000));
            }
#endif
            releaseFrame(98,logCopyDataPtr);
            break;

        case 0x87:
            if(HAL_UART_Receive(&UartHandle, (uint8_t*)aRxBuffer,  4, 1000)!= HAL_OK)
                return 0;
            if(((aRxBuffer[0] ^ aRxBuffer[2]) != 0xFF) || ((aRxBuffer[1] ^ aRxBuffer[3]) != 0xFF))
                return 0;
            totalDiveCount.u8bit.byteLow  = aRxBuffer[1];
            totalDiveCount.u8bit.byteHigh = aRxBuffer[0];
            ext_flash_repair_SPECIAL_dive_numbers_starting_count_with(totalDiveCount.u16bit);
            aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
            break;
        case 0x88:
             aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
             logCopyDataPtr = getFrame(98);

             for(index = 0; index <384; index++)		/* transmit in 32k blocks */
             {
            	 ext_flash_read_sample_memory((uint8_t *)logCopyDataPtr, index);
                 if(HAL_UART_Transmit(&UartHandle, (uint8_t *)(logCopyDataPtr), (uint16_t)0x8000,60000) != HAL_OK)
                 {
                	 break;
                 }
             }
             releaseFrame(98,logCopyDataPtr);
             HAL_UART_Transmit(&UartHandle, (uint8_t*)&pSettings->logFlashNextSampleStartAddress, 4,60000);	/* send next sample pos */
        	break;
        case 0x89:
             aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
             logCopyDataPtr = getFrame(98);

             for(index = 0; index <384; index++)		/* transmit in 32k blocks  384*/
             {

                 if(HAL_UART_Receive(&UartHandle, (uint8_t *)(logCopyDataPtr), (uint16_t)0x8000,60000) != HAL_OK)
                 {
                	 break;
                 }
                 ext_flash_write_sample_memory((uint8_t *)logCopyDataPtr, index);
             }

             releaseFrame(98,logCopyDataPtr);
             HAL_UART_Receive(&UartHandle, (uint8_t*)&pSettings->logFlashNextSampleStartAddress, 4,60000);	/* send next sample pos */
        	break;

#endif
        }

        // was service command? Yes, finish and exit
        if(count)
        {
            if(HAL_UART_Transmit(&UartHandle, (uint8_t*)aTxBuffer, count,10000)!= HAL_OK)
                return 0;
            else
                return prompt4D4C(receiveStartByteUart);
        }
    }


    // download mode commands
    switch(type)
    {
    // return of command for almost all commands
    case 0x60: // get model + features
    case 0x61: // get all headers full (256 bytes)
    case 0x62: // set clock
    case 0x63: // set custom text
    case 0x66: // get dive profile
    case 0x69: // get serial, old version numbering, custom text
    case 0x6A: // get model
    case 0x6B: // get specific firmware version
    case 0x6C: /* Display Bluetooth signal strength */
    case 0x6D: // get all compact headers (16 byte)
    case 0x6E: // display text
    case 0x70: // read min, default, max setting
    case 0x72: // read setting
    case 0x77: // write setting
    case 0x78: // reset all settings
        if(HAL_UART_Transmit(&UartHandle, (uint8_t*)aTxBuffer, 1, 1000)!= HAL_OK)
            return 0;
        break;

    // start communication (again)
    case 0xBB:
        if(HAL_UART_Transmit(&UartHandle, (uint8_t*)aTxBuffer, 2, 1000)!= HAL_OK)
            return 0;
        else
            return prompt4D4C(receiveStartByteUart);

    // stop communication
    case 0xFF:
        HAL_UART_Transmit(&UartHandle, (uint8_t*)&aTxBuffer, 1, 1000);
        return 0;

    default:
        aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
        break;
    }

    switch(type)
    {
    case 0x62:
        if(HAL_UART_Receive(&UartHandle, (uint8_t*)aRxBuffer,  6, 2000)!= HAL_OK)
            return 0;
        break;
    case 0x63:
        if(HAL_UART_Receive(&UartHandle, (uint8_t*)aRxBuffer, 60, 5000)!= HAL_OK)
            return 0;
        break;
    case 0x66:
        if(HAL_UART_Receive(&UartHandle, (uint8_t*)aRxBuffer,  1, 1000)!= HAL_OK)
            return 0;
        break;
    case 0x6B:
        if(HAL_UART_Receive(&UartHandle, (uint8_t*)aRxBuffer,  1, 1000)!= HAL_OK)
            return 0;
        break;
    case 0x6E:
        if(HAL_UART_Receive(&UartHandle, (uint8_t*)aRxBuffer, 16, 5000)!= HAL_OK)
            return 0;
        break;
    case 0x77:
  if(HAL_UART_Receive(&UartHandle, (uint8_t*)aRxBuffer, 5, 5000)!= HAL_OK)
            return 0;
  break;
    case 0x72:
  if(HAL_UART_Receive(&UartHandle, (uint8_t*)aRxBuffer, 1, 5000)!= HAL_OK)
            return 0;
        break;
    case 0x70:
  if(HAL_UART_Receive(&UartHandle, (uint8_t*)aRxBuffer, 1, 5000)!= HAL_OK)
            return 0;
        break;
    }

    switch(type)
    {
    /* common to standard and bootloader */

    // get model + features
    case 0x60:
        aTxBuffer[count++] = 0x00; // hardware descriptor HIGH byte
        aTxBuffer[count++] = 0x3B; // hardware descriptor LOW byte // 0x3B is OSTC4 //  0x1A is OTSC3
        aTxBuffer[count++] = 0x00; // feature descriptor HIGH byte
        aTxBuffer[count++] = 0x00; // feature descriptor LOW byte
        aTxBuffer[count++] = 0x43; // model id
        aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
        break;

    // get model
    case 0x6A:
        aTxBuffer[count++] = 0x3B; // 0x3B is OSTC4 //  0x1A is OTSC3
        aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
        break;

    // get all firmware version and status (OSTC4 only)
    case 0x6B:
        switch(*aRxBuffer)
        {
            case 0xFF:
            // firmware
            aTxBuffer[count++] = firmwareDataGetPointer()->versionFirst;
            aTxBuffer[count++] = firmwareDataGetPointer()->versionSecond;
            aTxBuffer[count++] = firmwareDataGetPointer()->versionThird;
            aTxBuffer[count++] = firmwareDataGetPointer()->versionBeta;
            break;
            case 0xFE:
            // RTE
            getActualRTEandFONTversion(&tempHigh, &tempLow, 0, 0); // RTE
            aTxBuffer[count++] = tempHigh;
            aTxBuffer[count++] = tempLow;
            aTxBuffer[count++] = 0;
            aTxBuffer[count++] = 0;
            break;
            case 0x10:
            getActualRTEandFONTversion( 0, 0, &tempHigh, &tempLow); // font
            aTxBuffer[count++] = tempHigh;
            aTxBuffer[count++] = tempLow;
            aTxBuffer[count++] = 0;
            aTxBuffer[count++] = 0;
            break;
            default:
            // not supported
            aTxBuffer[count++] = 0xFF;
            aTxBuffer[count++] = 0xFF;
            aTxBuffer[count++] = 0xFF;
            aTxBuffer[count++] = 0xFF;
            break;
/* Jef Driesen Test
            default:
            // not supported
            aTxBuffer[count++] = 0x1;
            aTxBuffer[count++] = 0x1;
            aTxBuffer[count++] = 0x1;
            aTxBuffer[count++] = 0x1;
            break;
*/
        }
/*
        // serial
        aTxBuffer[count++] = pSettings->serialLow;
        aTxBuffer[count++] = pSettings->serialHigh;
        // batch code (date)
        hardwareBatchCode(&tempHigh, &tempLow);
        aTxBuffer[count++] = tempLow;
        aTxBuffer[count++] = tempHigh;
        // status and status detail (future feature)
        aTxBuffer[count++] = 0;
        aTxBuffer[count++] = 0;
        aTxBuffer[count++] = 0;
        aTxBuffer[count++] = 0;
*/
        // prompt
        aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
        break;

    /* Trigger Bluetooth signal strength evaluation */
    case 0x6C:  tComm_EvaluateBluetoothStrength();
    			aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
    	break;
    // display text
    case 0x6E:
        for(int i=0;i<16;i++)
            display_text[i] = aRxBuffer[i];
        display_text[15] = 0;
        display_text[255] = 16;
        aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
        break;

    // version / identify
    case 0x69:
#ifndef BOOTLOADER_STANDALONE
        aTxBuffer[count++] = pSettings->serialLow;
        aTxBuffer[count++] = pSettings->serialHigh;
        aTxBuffer[count++] = firmwareVersion_16bit_low();
        aTxBuffer[count++] = firmwareVersion_16bit_high();
        memcpy(&aTxBuffer[count], pSettings->customtext, 60);
#else
        aTxBuffer[count++] = 0;//pSettings->serialLow;
        aTxBuffer[count++] = 0;//pSettings->serialHigh;
        aTxBuffer[count++] = 0;//firmwareVersion_16bit_low();
        aTxBuffer[count++] = 0;//firmwareVersion_16bit_high();
        memset(&aTxBuffer[count], 0, 60);
#endif
        count += 60;
        aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
        break;

#ifndef BOOTLOADER_STANDALONE
    //Reset all setting
    case 0x78:
        set_settings_to_Standard();
        updateSettingsAndMenuOnExit = 1;
        aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
        break;
#endif

#ifndef BOOTLOADER_STANDALONE
    // full headers (256 byte)
    case 0x61:
        for(int StepBackwards = 255; StepBackwards > -1; StepBackwards--)
        {
            logbook_getHeader(StepBackwards, &logbookHeader);
            plogbookHeaderOSTC3 = logbook_build_ostc3header(&logbookHeader);
            if(HAL_UART_Transmit(&UartHandle, (uint8_t*)plogbookHeaderOSTC3, 256,5000)!= HAL_OK)
                return 0;
        }
        aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
        break;

        // compact headers (16 byte)
    case 0x6D:
        for(int StepBackwards = 255; StepBackwards > -1; StepBackwards--)
        {
            logbook_getHeader(StepBackwards, &logbookHeader);
            plogbookHeaderOSTC3compact = logbook_build_ostc3header_compact(&logbookHeader);
            if(HAL_UART_Transmit(&UartHandle, (uint8_t*)plogbookHeaderOSTC3compact, 16,5000)!= HAL_OK)
                return 0;
        }
        aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
        break;

    // set clock & date
    case 0x62:
// ToDo
        stimestructure.Hours = aRxBuffer[0];
        stimestructure.Minutes = aRxBuffer[1];
        stimestructure.Seconds = aRxBuffer[2];
        sdatestructure.Month = aRxBuffer[3];
        sdatestructure.Date = aRxBuffer[4];
        sdatestructure.Year = aRxBuffer[5]; // This parameter must be a number between Min_Data = 0 and Max_Data = 99
        setWeekday(&sdatestructure);

        if(		( stimestructure.Hours 		< 24 )
                &&(	stimestructure.Minutes 	< 60 )
                &&(	stimestructure.Seconds 	< 60 )
                &&(	sdatestructure.Month 		< 13 )
                &&(	sdatestructure.Date 		< 32 )
                &&(	sdatestructure.Year 		< 100 ))
        {
            setTime(stimestructure);
            setDate(sdatestructure);
            set_globalState(StUART_RTECONNECT);
            HAL_Delay(1);
            set_globalState(StUART_STANDARD);
        }
        aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
        break;

    case 0x63:
        for(int i=0;i<60;i++)
            pSettings->customtext[i] = aRxBuffer[i];
        pSettings->customtext[59] = 0;
        aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
        break;

    // get dive profile
    case 0x66:
        logbook_getHeader(255 - aRxBuffer[0], &logbookHeader);
        plogbookHeaderOSTC3 = logbook_build_ostc3header(&logbookHeader);
        if(HAL_UART_Transmit(&UartHandle, (uint8_t*)plogbookHeaderOSTC3, 256,5000)!= HAL_OK)
            return 0;

        OSTC3_profileLength = (plogbookHeaderOSTC3->profileLength[2] << 16) + (plogbookHeaderOSTC3->profileLength[1] << 8)
                								    + plogbookHeaderOSTC3->profileLength[0] -3;
        header_profileLength = (logbookHeader.profileLength[2] << 16) + (logbookHeader.profileLength[1] << 8) + logbookHeader.profileLength[0];
       
        if(OSTC3_profileLength != header_profileLength)			/* has headerdata been changed to dummy data? */
        {
        	sampleTotalLength = logbook_fillDummySampleBuffer(&logbookHeader);
			while(sampleTotalLength >= 128)
			{
				logbook_readDummySamples(aTxBuffer,128);
				sampleTotalLength -= 128;
				if(HAL_UART_Transmit(&UartHandle, (uint8_t*)aTxBuffer, 128,5000)!= HAL_OK)
					return 0;
			}
			if(sampleTotalLength)
			{
				logbook_readDummySamples(aTxBuffer,sampleTotalLength);
				if(HAL_UART_Transmit(&UartHandle, (uint8_t*)aTxBuffer, sampleTotalLength,5000)!= HAL_OK)
					return 0;
			}
        }
        else
        {
			ext_flash_open_read_sample(255 - aRxBuffer[0], &sampleTotalLength);
			while(sampleTotalLength >= 128)
			{
				ext_flash_read_next_sample_part(aTxBuffer,128);
				sampleTotalLength -= 128;
				if(HAL_UART_Transmit(&UartHandle, (uint8_t*)aTxBuffer, 128,5000)!= HAL_OK)
					return 0;
			}
			if(sampleTotalLength)
			{
				ext_flash_read_next_sample_part(aTxBuffer,sampleTotalLength);
				if(HAL_UART_Transmit(&UartHandle, (uint8_t*)aTxBuffer, sampleTotalLength,5000)!= HAL_OK)
					return 0;
			}
        }
		aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
        break;

        // read min,default,max setting
    case 0x70:
    count += readDataLimits__8and16BitValues_4and7BytesOutput(aRxBuffer[0],&aTxBuffer[count]);
        aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
        break;

    // read setting
    case 0x72:
        readData(aRxBuffer[0],&aTxBuffer[count]);
        count += 4;
        aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
        break;

    // write setting
    case 0x77:
        writeData(aRxBuffer);
        updateSettingsAndMenuOnExit = 1;
        aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
        break;
#else
    /* bootloader dummies */
    // full headers (256 byte)
    case 0x61:
        for(int StepBackwards = 0;StepBackwards<256;StepBackwards++)
        {
            if(HAL_UART_Transmit(&UartHandle, (uint8_t*)dummyForBootloader, 256,5000)!= HAL_OK)
                return 0;
        }
        aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
        break;
    // compact headers (16 byte)
    case 0x6D:
        for(int StepBackwards = 0;StepBackwards<256;StepBackwards++)
        {
            if(HAL_UART_Transmit(&UartHandle, (uint8_t*)dummyForBootloader, 16,5000)!= HAL_OK)
                return 0;
        }
        aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
        break;
    // set clock & date
    case 0x62:
        aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
        break;
    // set custom text
    case 0x63:
        aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
        break;
    // get dive profile
    case 0x66:
        if(HAL_UART_Transmit(&UartHandle, (uint8_t*)dummyForBootloader, 256,5000)!= HAL_OK)
            return 0;
        aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
        break;
    // read min,default,max setting
    // read settings


    case 0x72:
        memcpy(&aTxBuffer[count], dummyForBootloader, 4);
  count += 4;
        aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
        break;
    // write settings
    case 0x77:
        aTxBuffer[count++] = prompt4D4C(receiveStartByteUart);
        break;
#endif
    }

    if(count)
    {
        if(HAL_UART_Transmit(&UartHandle, (uint8_t*)aTxBuffer, count,10000)!= HAL_OK)
            return 0;
        else
            return prompt4D4C(receiveStartByteUart);
    }
    return 0;
}

#define BLOCKSIZE 0x1000

HAL_StatusTypeDef receive_uart_large_size(UART_HandleTypeDef *huart, uint8_t *pData, uint32_t Size)
{
    uint16_t length_4k_blocks;
    uint16_t length_4k_remainder;
    uint32_t temp;
    HAL_StatusTypeDef result = HAL_OK;
    uint32_t pDataLocal;

    length_4k_blocks = (uint16_t) (Size / BLOCKSIZE);
    temp = length_4k_blocks;
    temp *= BLOCKSIZE;
    length_4k_remainder = (uint16_t) ( Size - temp);

    pDataLocal = (uint32_t)pData;


    while((result == HAL_OK) && length_4k_blocks)
    {
        result = HAL_UART_Receive(&UartHandle, (uint8_t *)pDataLocal, BLOCKSIZE , UART_TIMEOUT_LARGE_BLOCK);
        pDataLocal += BLOCKSIZE;
        length_4k_blocks--;
    }

    if((result == HAL_OK) && length_4k_remainder)
    {
        result = HAL_UART_Receive(&UartHandle, (uint8_t *)pDataLocal, length_4k_remainder , UART_TIMEOUT_LARGE_BLOCK);
    }
    return result;
}


/* for safety reason (memory blocking this code is main and sub */

#ifdef BOOTLOADER_STANDALONE

uint8_t receive_update_data_cpu2(void)
{
    uint8_t answer;

    uint8_t* pBuffer = (uint8_t*)getFrame(20);
    answer = receive_update_data_cpu2_sub(pBuffer);
    releaseFrame(20,(uint32_t)pBuffer);
    return answer;
}


uint8_t receive_update_data_cpu2_sub(uint8_t* pBuffer)
{
    uint8_t sBuffer[10];
    uint32_t length, offsetTotal, checksum, checksumCalc;
    uint8_t id;
    const uint8_t id_RTE = 0xFE;

    //Get length
    if(HAL_UART_Receive(&UartHandle, pBuffer, 4,5000)!= HAL_OK) // 58000
    {
        return 0;
    }
    length = 256  * 256 * 256 * (uint32_t)pBuffer[0] +  256 * 256 * (uint32_t)pBuffer[1] + 256 * (uint32_t)pBuffer[2] + pBuffer[3];

    //Get id
    if(HAL_UART_Receive(&UartHandle, pBuffer, 4,5000)!= HAL_OK) // 58000
    {
        return 0;
    }
    id = pBuffer[0];
    offsetTotal = 256  * 256 * 256 * (uint32_t)pBuffer[0] +  256 * 256 * (uint32_t)pBuffer[1] + 256 * (uint32_t)pBuffer[2] + pBuffer[3];

    // get checksum, bytes are in different order on Dev C++ code!!!
    if(HAL_UART_Receive(&UartHandle, sBuffer, 4,5000)!= HAL_OK) // 58000
    {
        return 0;
    }
    checksum = 256  * 256 * 256 * (uint32_t)sBuffer[3] +  256 * 256 * (uint32_t)sBuffer[2] + 256 * (uint32_t)sBuffer[1] + sBuffer[0];
    checksumCalc = length + offsetTotal;

    // no need to get code if checksum == length is wrong
    if(checksumCalc != checksum)
    {
        return 0;
    }

    //get Code
    if(receive_uart_large_size(&UartHandle, pBuffer, length)!= HAL_OK)
    {
        return 0;
    }

    //get Checksum
    if(HAL_UART_Receive(&UartHandle, sBuffer, 4,5000)!= HAL_OK) // 580000
    {
        return 0;
    }
    uint32_t checksum = 256  * 256 * 256 *(uint32_t)sBuffer[0] + 256 * 256 *  (uint32_t)sBuffer[1] + 256 *  (uint32_t)sBuffer[2] + sBuffer[3];
//  uint32_t checksumCalc = crc32c_checksum(pBuffer, length,0,0);
    uint32_t checksumCalc = CRC_CalcBlockCRC((uint32_t*)pBuffer, length/4);

    if(checksum !=  checksumCalc)
    {
        return 0;
    }

    if(id != id_RTE)
    {
        strcpy(display_text,"wrong data.");
        display_text[255] = 32;
        return 0;
    }

    strcpy(display_text,"  RTE update.");
    display_text[255] = 32;

    return extCPU2bootloader(pBuffer,length,display_text);
}
#endif // BOOTLOADER_STANDALONE



uint8_t receive_update_flex(uint8_t isRTEupdateALLOWED)
{
    uint8_t answer;

    uint8_t* pBuffer1 = (uint8_t*)getFrame(20);
    uint8_t* pBuffer2 = (uint8_t*)getFrame(20);

    answer = receive_update_data_flex(pBuffer1, pBuffer2, isRTEupdateALLOWED);

    releaseFrame(20,(uint32_t)pBuffer1);
    releaseFrame(20,(uint32_t)pBuffer2);

    return answer;
}

uint8_t receive_update_data_mainCPU_firmware(void)
{
    uint8_t answer;

    uint8_t* pBuffer1 = (uint8_t*)getFrame(20);

    answer = receive_update_data_mainCPU_firmware_subroutine(1, pBuffer1, 0);

    releaseFrame(20,(uint32_t)pBuffer1);

    return answer;
}

/* multi buffer (long data) not tested yet */
uint8_t receive_update_data_mainCPU_variable_firmware(void)
{
    uint8_t answer;

    uint8_t* pBuffer1 = (uint8_t*)getFrame(20);
    uint8_t* pBuffer2 = (uint8_t*)getFrame(20);

    answer = receive_update_data_mainCPU_firmware_subroutine(2, pBuffer1, pBuffer2);

    releaseFrame(20,(uint32_t)pBuffer1);
    releaseFrame(20,(uint32_t)pBuffer2);

    return answer;
}

uint8_t receive_update_data_flex(uint8_t* pBuffer1, uint8_t* pBuffer2, uint8_t RTEupdateALLOWED)
{
    uint8_t sBuffer[10];
    uint8_t serialBuffer[10];
    uint32_t length1, length2, lengthCompare, offsetCompare, ByteCompareStatus;
    uint32_t lengthTotal, offsetTotal;
    uint32_t checksum, checksumCalc = 0;
    uint8_t id;
    const uint8_t id_Region1_firmware = 0xFF;
    const uint8_t id_RTE = 0xFE;
    uint8_t textpointer = 0;

    //Get length
    if(HAL_UART_Receive(&UartHandle, sBuffer, 4,5000)!= HAL_OK) // 58000
    {
        return 0;
    }
    lengthTotal = 256 * 256 * 256 * (uint32_t)sBuffer[0] +  256 * 256 * (uint32_t)sBuffer[1] + 256 * (uint32_t)sBuffer[2] + sBuffer[3];

    //Get offset and/or id (id is 0xFF for RTE, 0xFE for firmware and offset if var)
    if(HAL_UART_Receive(&UartHandle, sBuffer, 4,5000)!= HAL_OK) // 58000
    {
        return 0;
    }
    id = sBuffer[0];

    checksumCalc = 256 * 256 * 256 * (uint32_t)sBuffer[0] +  256 * 256 * (uint32_t)sBuffer[1] + 256 * (uint32_t)sBuffer[2] + sBuffer[3];
    checksumCalc += lengthTotal;
    //old, does no longer work because of the fonts: checksumCalc = lengthTotal + offsetTotal;

    if((id != id_Region1_firmware) && (id != id_RTE) && (id != id_FONT) && (id != id_FONT_OLD))
    {
        return 0;
    }

    // neu 110212
    if(id == id_FONT)
        offsetTotal = 256 * 256 * 256 * (uint32_t)sBuffer[1] +  256 * 256 * (uint32_t)sBuffer[2] + 256 * (uint32_t)sBuffer[3];
    else
        offsetTotal = 256 * 256 * 256 * (uint32_t)sBuffer[0] +  256 * 256 * (uint32_t)sBuffer[1] + 256 * (uint32_t)sBuffer[2] + sBuffer[3];

    // get checksum, bytes are in different order on Dev C++ code!!!
    if(HAL_UART_Receive(&UartHandle, sBuffer, 4,5000)!= HAL_OK) // 58000
    {
        return 0;
    }
    checksum = 256 * 256 * 256 * (uint32_t)sBuffer[3] +  256 * 256 * (uint32_t)sBuffer[2] + 256 * (uint32_t)sBuffer[1] + sBuffer[0];


    if(checksumCalc != checksum)
    {
        uint8_t ptr = 0;
        strcpy(&display_text[ptr]," checksum error");
        ptr += 15;
        strcpy(&display_text[ptr],"\n\r");
        ptr += 2;
        ptr += gfx_number_to_string(10,0,&display_text[ptr],checksumCalc);
        display_text[ptr] = 0;
        display_text[255] = ptr + 1;
        return 0xFF;
    }

    //Get serial (new since 160211)
    if(HAL_UART_Receive(&UartHandle, serialBuffer, 4,5000)!= HAL_OK)
    {
        return 0;
    }

    if(lengthTotal > 768000)
    {
        length1 = 768000;
        length2 = lengthTotal - length1;
    }
    else
    {
        length1 = lengthTotal;
        length2 = 0;
    }

    if((pBuffer2 == 0) && (length2 != 0))
        return 0;

    //get Code
    if(receive_uart_large_size(&UartHandle, pBuffer1, length1)!= HAL_OK)
        return 0;

    if(length2)
        if(receive_uart_large_size(&UartHandle, pBuffer2, length2)!= HAL_OK)
            return 0;

    //get Checksum
    if(HAL_UART_Receive(&UartHandle, sBuffer, 4,5000)!= HAL_OK) // 58000
        return 0;

    checksum = 256  * 256 * 256 *(uint32_t)sBuffer[0] + 256 * 256 *  (uint32_t)sBuffer[1] + 256 *  (uint32_t)sBuffer[2] + sBuffer[3];
//  uint32_t checksumCalc = crc32c_checksum(pBuffer1, length1, pBuffer2, length2);
    if(length2)
        checksumCalc = CRC_CalcBlockCRC_moreThan768000((uint32_t*)pBuffer1, (uint32_t*)pBuffer2, lengthTotal/4);
    else
        checksumCalc = CRC_CalcBlockCRC((uint32_t*)pBuffer1, length1/4);

    /* check id now */
    /*
    if(region == 2)
    {
        if((id == id_Region1_firmware) || (id == id_RTE))
        {
            strcpy(display_text,"wrong data.");
            display_text[255] = 32;
            return 0;
        }
    }
    else
    {
        if(id != id_Region1_firmware)
        {
            strcpy(display_text,"wrong data.");
            display_text[255] = 32;
            return 0;
        }
    }
    */
    /* test checksum */
    if(checksum !=  checksumCalc)
    {
        uint8_t ptr = 0;
        strcpy(&display_text[ptr]," checksum error");
        ptr += 15;
        strcpy(&display_text[ptr],"\n\r");
        display_text[ptr] = 0;
        display_text[255] = ptr + 1;
        return 0xFF;
    }

    if(id == id_Region1_firmware)
    {
        uint8_t ptr = 0;
        display_text[ptr++] = 'V';
        ptr += gfx_number_to_string(2,0,&display_text[ptr],pBuffer1[0x10000] & 0x1F);
        display_text[ptr++] = '.';
        ptr += gfx_number_to_string(2,0,&display_text[ptr],pBuffer1[0x10001] & 0x1F);
        display_text[ptr++] = '.';
        ptr += gfx_number_to_string(2,0,&display_text[ptr],pBuffer1[0x10002] & 0x1F);
        display_text[ptr++] = ' ';
        if(pBuffer1[0x10003])
        {
            strcpy(&display_text[ptr],"beta ");
            ptr +=5;
        }
        strcpy(&display_text[ptr],"\n\rpreparing for install.");
        ptr += 25;
        display_text[255] = ptr + 1;
    }
    else if(id == id_RTE)
    {
        if(RTEupdateALLOWED)
        {
            strcpy(display_text,"  RTE update.\n\r");
            textpointer = 0;
            while((display_text[textpointer] != 0) && (textpointer < 50))
                textpointer++;
#ifndef BOOTLOADER_STANDALONE
            if(textpointer < 50)
            {
//				display_text[textpointer++] =
                display_text[textpointer++] = '\025';
                display_text[textpointer++] = TXT_2BYTE;
                display_text[textpointer++] = TXT2BYTE_DecoDataLost;
                display_text[textpointer] = 0;
            }
#endif
            display_text[255] = textpointer+1;
            return extCPU2bootloader(pBuffer1,length1,display_text);
        }
        else
            return 0xFF;
    }
    else
    //if(region == 2)
    {
        uint8_t ptr = 0;
        ptr += gfx_number_to_string(7,0,&display_text[ptr],lengthTotal);
        strcpy(&display_text[ptr]," bytes with ");
        ptr += 12;
        ptr += gfx_number_to_string(7,0,&display_text[ptr],offsetTotal);
        strcpy(&display_text[ptr]," offset");
        ptr += 7;
        strcpy(&display_text[ptr],"\n\rpreparing for install.");
        ptr += 25;
        display_text[255] = ptr + 1;
    }


    // only non RTE !!
    uint8_t* pBufferCompare = (uint8_t*)getFrame(20);
    ByteCompareStatus = 0;

    if(id == id_Region1_firmware)
    {
        /* standard firmware limited to 768000 */
        if(ext_flash_read_firmware(pBufferCompare,4,0) != 0xFFFFFFFF)
            ext_flash_erase_firmware();
        ext_flash_write_firmware(pBuffer1, length1);
        lengthCompare = ext_flash_read_firmware(pBufferCompare,768000,0);

        if(lengthCompare != length1)
            ByteCompareStatus = 10000;
        for(int i = 0; i < length1; i++)
        {
            if(pBuffer1[0] != pBufferCompare[0])
                ByteCompareStatus++;
        }
    }
    else
    //if(region == 2)
    {
        /* upper region firmware can be larger (1MB) */
        if(ext_flash_read_firmware2(0, pBufferCompare,4, 0,0) != 0xFFFFFFFF)
            ext_flash_erase_firmware2();
        ext_flash_write_firmware2(offsetTotal, pBuffer1, length1, pBuffer2, length2);
        lengthCompare = ext_flash_read_firmware2(&offsetCompare, pBufferCompare,768000, 0,768000);

        if(lengthCompare != length1 + length2)
            ByteCompareStatus = 10000;
        if(offsetTotal != offsetCompare)
            ByteCompareStatus += 20000;
        for(int i = 0; i < length1; i++)
        {
            if(pBuffer1[0] != pBufferCompare[0])
                ByteCompareStatus++;
        }

        lengthCompare = ext_flash_read_firmware2(0, 0,768000, pBufferCompare,768000);
        for(int i = 0; i < length2; i++)
        {
            if(pBuffer2[0] != pBufferCompare[0])
                ByteCompareStatus++;
        }
    }

    releaseFrame(20,(uint32_t)pBufferCompare);

    if(ByteCompareStatus != 0)
    {
        strcpy(&display_text[0],"\n\rcopy error.");
        display_text[255] = 21;
        return 0;
    }
    else
    {
        strcpy(&display_text[0],"\n\rready to install.");
        display_text[255] = 21;
        return 1;
    }
}


uint8_t receive_update_data_mainCPU_firmware_subroutine(uint8_t region, uint8_t* pBuffer1, uint8_t* pBuffer2)
{
    uint8_t sBuffer[10];
    uint32_t length1, length2, lengthCompare, offsetCompare, ByteCompareStatus;
    uint32_t lengthTotal, offsetTotal, checksum, checksumCalc = 0;
    uint8_t id;

    //Get length
    if(HAL_UART_Receive(&UartHandle, sBuffer, 4,5000)!= HAL_OK) // 58000
        return 0;

    lengthTotal = 256  * 256 * 256 * (uint32_t)sBuffer[0] +  256 * 256 * (uint32_t)sBuffer[1] + 256 * (uint32_t)sBuffer[2] + sBuffer[3];

    //Get offset and/or id (id is 0xFF for RTE, 0xFE for firmware and offset if var)
    if(HAL_UART_Receive(&UartHandle, sBuffer, 4,5000)!= HAL_OK) // 58000
        return 0;

    id = sBuffer[0];

    checksumCalc = 256 * 256 * 256 * (uint32_t)sBuffer[0] +  256 * 256 * (uint32_t)sBuffer[1] + 256 * (uint32_t)sBuffer[2] + sBuffer[3];
    checksumCalc += lengthTotal;

    if((id != id_Region1_firmware) && (id != id_RTE) && (id != id_FONT) && (id != id_FONT_OLD))
        return 0;

    if(id == id_FONT)
        offsetTotal = 256 * 256 * 256 * (uint32_t)sBuffer[1] +  256 * 256 * (uint32_t)sBuffer[2] + 256 * (uint32_t)sBuffer[3];
        // alt, prior to id for font
    else
        offsetTotal = 256 * 256 * 256 * (uint32_t)sBuffer[0] +  256 * 256 * (uint32_t)sBuffer[1] + 256 * (uint32_t)sBuffer[2] + sBuffer[3];

    // get checksum, bytes are in different order on Dev C++ code!!!
    if(HAL_UART_Receive(&UartHandle, sBuffer, 4,5000)!= HAL_OK) // 58000
        return 0;

    checksum = 256  * 256 * 256 * (uint32_t)sBuffer[3] +  256 * 256 * (uint32_t)sBuffer[2] + 256 * (uint32_t)sBuffer[1] + sBuffer[0];

    //old: checksumCalc = lengthTotal + offsetTotal;

    if(checksumCalc != checksum)
    {
        uint8_t ptr = 0;
        strcpy(&display_text[ptr]," checksum error");
        ptr += 15;
        strcpy(&display_text[ptr],"\n\r");
        ptr += 2;
        ptr += gfx_number_to_string(10,0,&display_text[ptr],checksumCalc);
        display_text[ptr] = 0;
        display_text[255] = ptr + 1;
        return 0xFF;
    }

    if(lengthTotal > 768000)
    {
        length1 = 768000;
        length2 = lengthTotal - length1;
    }
    else
    {
        length1 = lengthTotal;
        length2 = 0;
    }

    if((pBuffer2 == 0) && (length2 != 0))
        return 0;

    //get Code
    if(receive_uart_large_size(&UartHandle, pBuffer1, length1)!= HAL_OK)
        return 0;

    if(length2)
        if(receive_uart_large_size(&UartHandle, pBuffer2, length2)!= HAL_OK)
            return 0;

    //get Checksum
    if(HAL_UART_Receive(&UartHandle, sBuffer, 4,5000)!= HAL_OK) // 58000
        return 0;

    checksum = 256  * 256 * 256 *(uint32_t)sBuffer[0] + 256 * 256 *  (uint32_t)sBuffer[1] + 256 *  (uint32_t)sBuffer[2] + sBuffer[3];
//  uint32_t checksumCalc = crc32c_checksum(pBuffer1, length1, pBuffer2, length2);
    if(length2)
        checksumCalc = CRC_CalcBlockCRC_moreThan768000((uint32_t*)pBuffer1, (uint32_t*)pBuffer2, lengthTotal/4);
    else
        checksumCalc = CRC_CalcBlockCRC((uint32_t*)pBuffer1, length1/4);

    /* check id now */
    if(region == 2)
    {
        if((id == id_Region1_firmware) || (id == id_RTE))
        {
            strcpy(display_text,"wrong data.");
            display_text[255] = 32;
            return 0;
        }
    }
    else
    {
        if(id != id_Region1_firmware)
        {
            strcpy(display_text,"wrong data.");
            display_text[255] = 32;
            return 0;
        }
    }

    /* test checksum */
    if(checksum !=  checksumCalc)
    {
        uint8_t ptr = 0;
        strcpy(&display_text[ptr]," pruefsummen error");
        ptr += 15;
        strcpy(&display_text[ptr],"\n\r");
        display_text[ptr] = 0;
        display_text[255] = ptr + 1;
        return 0xFF;
    }

    if(region == 2)
    {
        uint8_t ptr = 0;
        ptr += gfx_number_to_string(7,0,&display_text[ptr],lengthTotal);
        strcpy(&display_text[ptr]," bytes with ");
        ptr += 12;
        ptr += gfx_number_to_string(7,0,&display_text[ptr],offsetTotal);
        strcpy(&display_text[ptr]," offset");
        ptr += 7;
        strcpy(&display_text[ptr],"\n\rpreparing for install.");
        ptr += 25;
        display_text[255] = ptr + 1;

    }
    else
    {
        uint8_t ptr = 0;
        display_text[ptr++] = 'V';
        ptr += gfx_number_to_string(2,0,&display_text[ptr],pBuffer1[0x10000] & 0x1F);
        display_text[ptr++] = '.';
        ptr += gfx_number_to_string(2,0,&display_text[ptr],pBuffer1[0x10001] & 0x1F);
        display_text[ptr++] = '.';
        ptr += gfx_number_to_string(2,0,&display_text[ptr],pBuffer1[0x10002] & 0x1F);
        display_text[ptr++] = ' ';
        if(pBuffer1[0x10003])
        {
            strcpy(&display_text[ptr],"beta ");
            ptr +=5;
        }
        strcpy(&display_text[ptr],"\n\rpreparing for install.");
        ptr += 25;
        display_text[255] = ptr + 1;
    }

    uint8_t* pBufferCompare = (uint8_t*)getFrame(20);
    ByteCompareStatus = 0;

    if(region == 2)
    {
        /* upper region firmware can be larger (1MB) */
        if(ext_flash_read_firmware2(0, pBufferCompare,4, 0,0) != 0xFFFFFFFF)
            ext_flash_erase_firmware2();
        ext_flash_write_firmware2(offsetTotal, pBuffer1, length1, pBuffer2, length2);
        lengthCompare = ext_flash_read_firmware2(&offsetCompare, pBufferCompare,768000, 0,768000);

        if(lengthCompare != length1 + length2)
            ByteCompareStatus = 10000;
        if(offsetTotal != offsetCompare)
            ByteCompareStatus += 20000;
        for(int i = 0; i < length1; i++)
        {
            if(pBuffer1[0] != pBufferCompare[0])
                ByteCompareStatus++;
        }

        lengthCompare = ext_flash_read_firmware2(0, 0,768000, pBufferCompare,768000);
        for(int i = 0; i < length2; i++)
        {
            if(pBuffer2[0] != pBufferCompare[0])
                ByteCompareStatus++;
        }
    }
    else
    {
        /* standard firmware limited to 768000 */
        if(ext_flash_read_firmware(pBufferCompare,4,0) != 0xFFFFFFFF)
            ext_flash_erase_firmware();
        ext_flash_write_firmware(pBuffer1, length1);
        lengthCompare = ext_flash_read_firmware(pBufferCompare,768000,0);

        if(lengthCompare != length1)
            ByteCompareStatus = 10000;
        for(int i = 0; i < length1; i++)
        {
            if(pBuffer1[0] != pBufferCompare[0])
                ByteCompareStatus++;
        }
    }

    releaseFrame(20,(uint32_t)pBufferCompare);

    if(ByteCompareStatus != 0)
    {
        strcpy(&display_text[0],"\n\rcopy error.");
        display_text[255] = 21;
        return 0;
    }
    else
    {
        strcpy(&display_text[0],"\n\rready to install.");
        display_text[255] = 21;
        return 1;
    }
}

void tComm_RequestBluetoothStrength(void)
{
	EvaluateBluetoothSignalStrength = 1;
}

/* read, validate the modul answer and flush rx que if necessary */
uint8_t tComm_CheckAnswerOK()
{
    char answerOkay[] = "\r\nOK\r\n";
    char aRxBuffer[UART_CMD_BUF_SIZE];
    uint8_t sizeAnswer = sizeof(answerOkay) -1;
	uint8_t result = HAL_OK;
	uint8_t index = 0;
	uint8_t answer;

	memset(aRxBuffer,0,UART_CMD_BUF_SIZE);
	if(HAL_UART_Receive(&UartHandle, (uint8_t*)aRxBuffer, sizeAnswer, UART_OPERATION_TIMEOUT) == HAL_OK)
	{
		do
		{
			if(answerOkay[index] != aRxBuffer[index])
			{
				index = sizeAnswer;
				result = HAL_ERROR;		/* unexpected answer => there might be characters left in RX que => read and discard all rx bytes */
				do
				{
					answer = HAL_UART_Receive(&UartHandle, (uint8_t*)&aRxBuffer[index], 1, 10);
					if (index < UART_CMD_BUF_SIZE) 
					{
						index++;
					}
				}while(answer == HAL_OK);
				index = sizeAnswer;
			}
			else
			{
				index++;
			}
		}while(index < sizeAnswer);
	}
	else
	{
		result = HAL_ERROR;
	}
	return result;

}


void tComm_EvaluateBluetoothStrength(void)
{
	char aTxBufferBarSSI[] = "AT+BARSSI\r";
	char aTxBufferEscapeSequence[] = "+++";
	char aTxBufferEnd[] = "ATO\r";
    uint8_t sizeRequest = sizeof(aTxBufferBarSSI) -1;

    uint8_t answer = HAL_OK;
    char aRxBuffer[UART_CMD_BUF_SIZE];
	char SignalStr[UART_CMD_BUF_SIZE];
    uint8_t index = 0;
    uint8_t strindex = 0;
    int8_t sigqual = 0;

    HAL_Delay(200);
    if(HAL_UART_Transmit(&UartHandle, (uint8_t*)aTxBufferEscapeSequence, 3, 2000)== HAL_OK)
    {
    	if(tComm_CheckAnswerOK() == HAL_OK)
		{
			HAL_UART_Transmit(&UartHandle, (uint8_t*)aTxBufferBarSSI,sizeRequest , 2000);
			{
				index = 0;
				do						/* Answer is not the common one. Instead the signal strength is received => read all available bytes one by one*/
				{
					answer = HAL_UART_Receive(&UartHandle, (uint8_t*)&aRxBuffer[index], 1, 100);
					if(index < UART_CMD_BUF_SIZE) 
					{
						index++;
					}
				}while(answer == HAL_OK);

				if((aRxBuffer[index] != 'E') && (aRxBuffer[index] != 0))		/* E represents the first letter of the string ERROR */
				{
					index = 0;
					strindex = 0;
					do
					{
						SignalStr[strindex++] = aRxBuffer[index++];
					}while ((index < UART_CMD_BUF_SIZE - 1) && (aRxBuffer[index] != '\r'));
					SignalStr[strindex] = 0;	/* terminate String */
					sigqual = strtol(SignalStr,NULL,0);
					/* Map db to abstract Bargraph */
					if(sigqual > 0)
					{
						sprintf(SignalStr,"Bluetooth ||||||||");
					}
					else
					{
						sprintf(SignalStr,"Bluetooth |");
						strindex = strlen(SignalStr);
						sigqual *=-1;
						sigqual = 100 - sigqual;	/* invert because of negative db value */
						while(sigqual / 10 > 0 )
						{
							SignalStr[strindex++] = '|';
							sigqual -= 10;
						}
						SignalStr[strindex] = 0;
					}
					strcpy(display_text,SignalStr);
					display_text[255] = strlen(SignalStr);
					EvaluateBluetoothSignalStrength = 0;
				}
			}
			HAL_UART_Transmit(&UartHandle, (uint8_t*)aTxBufferEnd, 4, 2000);	/* exit terminal mode */
			index = 0;
			do	/* module will answer with current connection state */
			{
				answer = HAL_UART_Receive(&UartHandle, (uint8_t*)&aRxBuffer[index], 1, 100);
				if(index < UART_CMD_BUF_SIZE)
				{
					index++;
				}
			}while(answer == HAL_OK);
		}
    }
}

void tComm_StartBlueModConfig()
{
	uint8_t answer = HAL_OK;
	uint8_t RxBuffer[UART_CMD_BUF_SIZE];
	uint8_t index = 0;

	BmTmpConfig = BM_CONFIG_ECHO;
	do	/* flush RX buffer */
	{
		answer = HAL_UART_Receive(&UartHandle, (uint8_t*)&RxBuffer[index], 1, 10);
		if(index < UART_CMD_BUF_SIZE) index++;
	}while(answer == HAL_OK);
}

uint8_t tComm_HandleBlueModConfig()
{
	static uint8_t RestartModule = 1; 		/* used to do power off / on cycle */
	static uint8_t ConfigRetryCnt = 0;		/* Retry count without power cycle */

	char TxBuffer[UART_CMD_BUF_SIZE];
	uint8_t CmdSize = 0;

	uint8_t result = HAL_OK;

	TxBuffer[0] = 0;

	switch (BmTmpConfig)
	{
		case BM_CONFIG_ECHO: 			sprintf(TxBuffer,"ATE0\r");
			break;
		case BM_CONFIG_SILENCE:			sprintf(TxBuffer,"ATS30=0\r");
			break;
		case BM_CONFIG_ESCAPE_DELAY:	sprintf(TxBuffer,"ATS12=10\r");
			break;
		case BM_CONFIG_SIGNAL_POLL:		sprintf(TxBuffer,"AT+BSTPOLL=100\r");
			break;
		case BM_CONFIG_BAUD:			sprintf(TxBuffer,"AT%%B22\r");
			break;
		case BM_CONFIG_RETRY:			ConfigRetryCnt--;
										HAL_Delay(1);
										if(ConfigRetryCnt == 0)
										{
											MX_Bluetooth_PowerOn();
											tComm_StartBlueModConfig();
										}
			break;
		case BM_CONFIG_DONE:
		case BM_CONFIG_OFF:
			ConfigRetryCnt = 0;
			RestartModule = 1;
			break;
		default:
			break;
	}
	if(TxBuffer[0] != 0)		/* forward command to module */
	{
		CmdSize = strlen(TxBuffer);
		if(HAL_UART_Transmit(&UartHandle, (uint8_t*)TxBuffer,CmdSize, 2000) == HAL_OK)
		{
			if(BmTmpConfig == BM_CONFIG_ECHO)	/* echo is not yet turned off => read and discard echo */
			{
				HAL_UART_Receive(&UartHandle, (uint8_t*)TxBuffer, CmdSize, UART_OPERATION_TIMEOUT);
			}

			result = tComm_CheckAnswerOK();


			if((BmTmpConfig == BM_CONFIG_BAUD) && (result == HAL_OK) && (UartHandle.Init.BaudRate != 460800)) /* is com already switched to fast speed? */
			{
				HAL_UART_DeInit(&UartHandle);
				HAL_Delay(1);
				UartHandle.Init.BaudRate   = 460800;
				HAL_UART_Init(&UartHandle);
			}
			if(result == HAL_OK)
			{
				BmTmpConfig++;
			}
			if(BmTmpConfig == BM_CONFIG_DONE)
			{
				ConfigRetryCnt = 0;
			}
		}
	}
	if(result != HAL_OK)
	{
		ConfigRetryCnt++;
		if(ConfigRetryCnt > 3)		/* Configuration failed => switch off module */
		{
			MX_Bluetooth_PowerOff();
			if(RestartModule)
			{
				RestartModule = 0;      /* only one try */
				ConfigRetryCnt = 200;	/* used for delay to startup module again */
				BmTmpConfig = BM_CONFIG_RETRY;
			}
			else						/* even restarting module failed => switch bluetooth off */
			{
				ConfigRetryCnt = 0;
				BmTmpConfig = BM_CONFIG_OFF;
				settingsGetPointer()->bluetoothActive = 0;
			}
		}
	}
	return result;
}

static void tComm_Error_Handler(void)
{
  while(1)
  {}
}