view Discovery/Src/tComm.c @ 263:a6c0375bc950 IPC_Sync_Improvment_2

Forward 100ms time stamp to RTE and handle logbook in main loop Because of code execution variance between 100ms cycle event and start of SPI communication, the synchronization between Main and RTE may shift. To avoid these shifts the time stamp of the 100ms event is forwarded to the RTE which is now able to adapt to small variations. One variation point was the storage of dive samples within the external flash. Taking a closer look how this function works, moving it from the timer callback to the main loop should not be an issue. A critical point of having the function in the timer call back was the sector clean function which is called (depending on dive data) every ~300minutes and may take 250ms - 1500ms.
author ideenmodellierer
date Sun, 14 Apr 2019 11:38:14 +0200
parents ad6ddc4aabcd
children 4da2bffb07ca
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 <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_TIMEOUT_SECONDS	(120u)		/* Timeout for keeping connection open and waiting for data */

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;

/* Private function prototypes -----------------------------------------------*/

static void tComm_Error_Handler(void);
static uint8_t select_mode(uint8_t aRxByte);
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;
    tCwindow.WindowY0 = 0;
    tCwindow.WindowY1 = 799;

    StartListeningToUART = 1;

/*	WHY?
#ifdef 	BLE_NENABLE_PIN
    HAL_GPIO_WritePin(BLE_NENABLE_GPIO_PORT,BLE_NENABLE_PIN,GPIO_PIN_RESET);
#endif
*/
}

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_DeInit(&UartHandle);
            HAL_Delay(1);
            HAL_UART_Init(&UartHandle);
            HAL_Delay(1);
            UartReady = RESET;
            StartListeningToUART = 1;
            bluetoothActiveLastTime = 0;
            receiveStartByteUart = 0;
        }
        return 0;
    }
    else
    {
        bluetoothActiveLastTime = 1;
    }

#endif

    /*##-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);
        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[display_text[255]] = 0;
        releaseFrame(18,tCscreen.FBStartAdress);
        tCscreen.FBStartAdress = getFrame(18);
        write_content_simple(&tCscreen, 0, 800, 480-24, &FontT24,"Exit",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);
    }
#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
    }
}


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\nOKr\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;
}


uint8_t openComm(uint8_t aRxByte)
{
	SStateList status;
	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
    */

    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);
    }
/*
uint8_t debug[256] = {0};
uint8_t dbgptr = 0;
debug[dbgptr++] = aRxByte;
*/
    while((answer == prompt4D4C(receiveStartByteUart)) && (timeoutCounter < UART_TIMEOUT_SECONDS * 2)) 	/* Split 120 seconds timeout into 240 iterations a 500ms */
    {
    	if(HAL_UART_Receive(&UartHandle, (uint8_t*)&aRxByte, 1, 500)!= HAL_OK) 							/* Timeout half a second */
    	{
    		timeoutCounter++;
    		get_globalStateList(&status);
    		if (status.base != BaseComm)
    		{
    			timeoutCounter = UART_TIMEOUT_SECONDS * 2; /* Abort action triggered outside main loop => exit */
    		}
    	}
    	else
    	{
//		debug[dbgptr++] = aRxByte;
    		answer = select_mode(aRxByte);
    	}
    }
    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;
    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)

#endif
        case 0xC1: // 	Start low-level bootloader
            if(HAL_UART_Transmit(&UartHandle, (uint8_t*)aTxBuffer, 1, 1000)!= 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);
            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);
            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;
#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 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;

    // 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;
        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;
}


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

    length_16_blocks = (uint16_t) (Size / 0xFFFF);
    temp = length_16_blocks;
    temp *= 0xFFFF;
    length_16_remainder = (uint16_t) ( Size - temp);

    pDataLocal = (uint32_t)pData;

    while((result == HAL_OK) && length_16_blocks)
    {
        result = HAL_UART_Receive(&UartHandle, (uint8_t *)pDataLocal, 0xFFFF , 60000);
        pDataLocal += 0xFFFF;
        length_16_blocks--;
    }
    if((result == HAL_OK) && length_16_remainder)
    {
        result = HAL_UART_Receive(&UartHandle, (uint8_t *)pDataLocal, length_16_remainder , 60000);
    }
    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;
    }
}

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