Mercurial > public > ostc4
diff Discovery/Src/externLogbookFlash.c @ 38:5f11787b4f42
include in ostc4 repository
author | heinrichsweikamp |
---|---|
date | Sat, 28 Apr 2018 11:52:34 +0200 |
parents | |
children | 2bb1db22b5f5 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Discovery/Src/externLogbookFlash.c Sat Apr 28 11:52:34 2018 +0200 @@ -0,0 +1,2079 @@ +/** + ****************************************************************************** + * @copyright heinrichs weikamp + * @file externLogbookFlash.c + * @author heinrichs weikamp gmbh + * @date 07-Aug-2014 + * @version V0.0.4 + * @since 29-Sept-2015 + * @brief Main File to access the new 1.8 Volt Spansion S25FS256S 256 Mbit (32 Mbyte) + * @bug + * @warning + * + @verbatim + ============================================================================== + ##### Logbook Header (TOC) ##### + ============================================================================== + [..] Memory useage: + NEW: Spansion S25FS-S256S + + only 8x 4KB and 1x 32KB, remaining is 64KB or 256KB + Sector Size (kbyte) Sector Count Sector Range Address Range (Byte Address) Notes + 4 8 SA00 00000000h-00000FFFh + : : + SA07 00007000h-00007FFFh + + 32 1 SA08 00008000h-0000FFFFh + + 64 511 SA09 00010000h-0001FFFFh + : : + SA519 01FF0000h-01FFFFFFh + OLD: + 1kB each header + with predive header at beginning + and postdive header with 0x400 HEADER2OFFSET + 4kB (one erase) has two dives with 4 headers total + total of 512 kB (with 256 header ids (8 bit)) + Size is 280 Byte (as of 25.Nov. 2014) + + [..] Output to PC / UART is postdive header + + [..] Block Protection Lock-Down is to erase logbook only + + [..] Timing (see page 137 of LOGBOOK_V3_S25FS-S_00-271247.pdf + bulk erase is 2 minutes typ., 6 minutes max. + + ============================================================================== + ##### DEMOMODE ##### + ============================================================================== + 151215: ext_flash_write_settings() is DISABLED! + + ============================================================================== + ##### bug fixes ##### + ============================================================================== + 150917: end in header and length of sample was one byte too long + as stated by Jef Driesen email 15.09.2015 + + @endverbatim + ****************************************************************************** + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 heinrichs weikamp</center></h2> + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_hal.h" +#include "externLogbookFlash.h" +#include "ostc.h" +#include "settings.h" +#include "gfx_engine.h" + +#ifndef BOOTLOADER_STANDALONE +#include "logbook.h" +#endif + +/* Private types -------------------------------------------------------------*/ +#define FLASHSTART 0x000000 +//#define FLASHSTOP 0x01FFFFFF all 32 MB with 4byte addressing +#define FLASHSTOP 0x00FFFFFF +//#define FLASHSTOP 0x3FFFFF +#define RELEASE 1 +#define HOLDCS 0 + +#define HEADER2OFFSET 0x400 + +typedef enum{ + EF_HEADER, + EF_SAMPLE, + EF_DEVICEDATA, + EF_VPMDATA, + EF_SETTINGS, + EF_FIRMWARE, + EF_FIRMWARE2, +}which_ring_enum; + + +typedef struct{ +uint8_t IsBusy:1; +uint8_t IsWriteEnabled:1; +uint8_t BlockProtect0:1; +uint8_t BlockProtect1:1; +uint8_t BlockProtect2:1; +uint8_t BlockProtect3:1; +uint8_t IsAutoAddressIncMode:1; +uint8_t BlockProtectL:1; +} extFlashStatusUbit8_t; + +typedef union{ +extFlashStatusUbit8_t ub; +uint8_t uw; +} extFlashStatusBit8_Type; + + +/* Exported variables --------------------------------------------------------*/ + +/* Private variables ---------------------------------------------------------*/ +uint32_t actualAddress = 0; +uint32_t entryPoint = 0; + +uint32_t actualPointerHeader = 0; +uint32_t actualPointerSample = 0; +uint32_t LengthLeftSampleRead = 0; +uint32_t actualPointerDevicedata = 0; +uint32_t actualPointerVPM = 0; +uint32_t actualPointerSettings = 0; +uint32_t actualPointerFirmware = 0; +uint32_t actualPointerFirmware2 = 0; + +/* Private function prototypes -----------------------------------------------*/ +void chip_unselect(void); +void chip_select(void); +void error_led_on(void); +void error_led_off(void); + +void write_spi(uint8_t data, uint8_t unselect_CS_afterwards); +uint8_t read_spi(uint8_t unselect_CS_afterwards); +void write_address(uint8_t unselect_CS_afterwards); +static void Error_Handler_extflash(void); +static void wait_chip_not_busy(void); +void ext_flash_incf_address(uint8_t type); +//void ext_flash_incf_address_ring(void); +void ext_flash_decf_address_ring(uint8_t type); + +void ext_flash_erase4kB(void); +void ext_flash_erase32kB(void); +void ext_flash_erase64kB(void); +uint8_t ext_flash_erase_if_on_page_start(void); + +void ef_write_block(uint8_t * sendByte, uint32_t length, uint8_t type, uint8_t do_not_erase); + +void ext_flash_read_block(uint8_t *getByte, uint8_t type); +void ext_flash_read_block_multi(void *getByte, uint32_t size, uint8_t type); +void ext_flash_read_block_stop(void); + +static void ef_hw_rough_delay_us(uint32_t delayUs); +static void ef_erase_64K(uint32_t blocks); + +void ext_flash_overwrite_sample_without_erase(uint8_t *pSample, uint16_t length); + +void ext_flash_disable_protection(void); + +_Bool ext_flash_test_remaining_space_of_page_empty(uint32_t pointer, uint16_t length); +void ext_flash_set_to_begin_of_next_page(uint32_t *pointer, uint8_t type); + + +/* Exported functions --------------------------------------------------------*/ + +void ext_flash_write_firmware(uint8_t *pSample1, uint32_t length1)//, uint8_t *pSample2, uint32_t length2) +{ + general32to8_Type lengthTransform; + + lengthTransform.u32 = length1; + + actualPointerFirmware = FWSTART; + ef_write_block(lengthTransform.u8,4, EF_FIRMWARE, 1); + ef_write_block(pSample1,length1, EF_FIRMWARE, 1); + +// if(length2) +// ef_write_block(pSample2,length2, EF_FIRMWARE, 1); +} + +uint8_t ext_flash_read_firmware_version(char *text) +{ + uint32_t backup = actualAddress; + uint8_t buffer[4]; + + // + 4 for length data, see ext_flash_write_firmware + actualAddress = FWSTART + 4 + 0x10000; + ext_flash_read_block_start(); + ext_flash_read_block(&buffer[0], EF_FIRMWARE); + ext_flash_read_block(&buffer[1], EF_FIRMWARE); + ext_flash_read_block(&buffer[2], EF_FIRMWARE); + ext_flash_read_block(&buffer[3], EF_FIRMWARE); + + ext_flash_read_block_stop(); + actualAddress = backup; + + uint8_t ptr = 0; + text[ptr++] = 'V'; + ptr += gfx_number_to_string(2,0,&text[ptr],buffer[0] & 0x3F); + text[ptr++] = '.'; + ptr += gfx_number_to_string(2,0,&text[ptr],buffer[1] & 0x3F); + text[ptr++] = '.'; + ptr += gfx_number_to_string(2,0,&text[ptr],buffer[2] & 0x3F); + text[ptr++] = ' '; + if(buffer[3]) + { + text[ptr++] = 'b'; + text[ptr++] = 'e'; + text[ptr++] = 't'; + text[ptr++] = 'a'; + text[ptr++] = ' '; + } + return ptr; +} + + +uint32_t ext_flash_read_firmware(uint8_t *pSample1, uint32_t max_length, uint8_t *magicByte) +{ + uint32_t backup = actualAddress; + general32to8_Type lengthTransform; + + actualAddress = FWSTART; + ext_flash_read_block_start(); + + ext_flash_read_block(&lengthTransform.u8[0], EF_FIRMWARE); + ext_flash_read_block(&lengthTransform.u8[1], EF_FIRMWARE); + ext_flash_read_block(&lengthTransform.u8[2], EF_FIRMWARE); + ext_flash_read_block(&lengthTransform.u8[3], EF_FIRMWARE); + + + if(lengthTransform.u32 == 0xFFFFFFFF) + { + lengthTransform.u32 = 0xFFFFFFFF; + } + else + if(lengthTransform.u32 > max_length) + { + lengthTransform.u32 = 0xFF000000; + } + else + { + for(uint32_t i = 0; i<lengthTransform.u32; i++) + { + ext_flash_read_block(&pSample1[i], EF_FIRMWARE); + } + + } + + ext_flash_read_block_stop(); + + if(magicByte) + { + *magicByte = pSample1[0x10000 + 0x3E]; // 0x3E == 62 + } + + actualAddress = backup; + return lengthTransform.u32; +} + + +void ext_flash_write_firmware2(uint32_t offset, uint8_t *pSample1, uint32_t length1, uint8_t *pSample2, uint32_t length2) +{ + general32to8_Type lengthTransform, offsetTransform; + + lengthTransform.u32 = length1 + length2; + offsetTransform.u32 = offset; + + actualPointerFirmware2 = FWSTART2; + ef_write_block(lengthTransform.u8,4, EF_FIRMWARE2, 1); + ef_write_block(offsetTransform.u8,4, EF_FIRMWARE2, 1); + ef_write_block(pSample1,length1, EF_FIRMWARE2, 1); + if(length2) + ef_write_block(pSample2,length2, EF_FIRMWARE2, 1); +} + + +uint32_t ext_flash_read_firmware2(uint32_t *offset, uint8_t *pSample1, uint32_t max_length1, uint8_t *pSample2, uint32_t max_length2) +{ + uint32_t backup = actualAddress; + uint32_t length1, length2; + general32to8_Type lengthTransform, offsetTransform; + + actualAddress = FWSTART2; + ext_flash_read_block_start(); + + ext_flash_read_block(&lengthTransform.u8[0], EF_FIRMWARE2); + ext_flash_read_block(&lengthTransform.u8[1], EF_FIRMWARE2); + ext_flash_read_block(&lengthTransform.u8[2], EF_FIRMWARE2); + ext_flash_read_block(&lengthTransform.u8[3], EF_FIRMWARE2); + + ext_flash_read_block(&offsetTransform.u8[0], EF_FIRMWARE2); + ext_flash_read_block(&offsetTransform.u8[1], EF_FIRMWARE2); + ext_flash_read_block(&offsetTransform.u8[2], EF_FIRMWARE2); + ext_flash_read_block(&offsetTransform.u8[3], EF_FIRMWARE2); + + *offset = offsetTransform.u32; + + if(lengthTransform.u32 == 0xFFFFFFFF) + { + lengthTransform.u32 = 0xFFFFFFFF; + } + else + if(lengthTransform.u32 > max_length1 + max_length2) + { + lengthTransform.u32 = 0xFF000000; + } + else + { + if(lengthTransform.u32 < max_length1) + { + length1 = lengthTransform.u32; + length2 = 0; + } + else + { + length1 = max_length1; + length2 = lengthTransform.u32 - max_length1; + } + + if(pSample1) + { + for(uint32_t i = 0; i<length1; i++) + { + ext_flash_read_block(&pSample1[i], EF_FIRMWARE2); + } + if(pSample2) + { + for(uint32_t i = 0; i<length2; i++) + { + ext_flash_read_block(&pSample2[i], EF_FIRMWARE2); + } + } + } + else if(pSample2) + { + actualAddress += length1; + for(uint32_t i = 0; i<length2; i++) + { + ext_flash_read_block(&pSample2[i], EF_FIRMWARE2); + } + } + } + ext_flash_read_block_stop(); + actualAddress = backup; + return lengthTransform.u32; +} + + +void ext_flash_read_fixed_16_devicedata_blocks_formated_128byte_total(uint8_t *buffer) +{ + SDeviceLine data[16]; + uint8_t tempLengthIngnore; + uint16_t count; + uint8_t transfer; + + RTC_DateTypeDef Sdate; + RTC_TimeTypeDef Stime; + + actualAddress = DDSTART; + + ext_flash_read_block_start(); + ext_flash_read_block(&tempLengthIngnore, EF_DEVICEDATA); + ext_flash_read_block(&tempLengthIngnore, EF_DEVICEDATA); + + ext_flash_read_block_multi((uint8_t *)data,16*3*4, EF_DEVICEDATA); + ext_flash_read_block_stop(); + + count = 0; + for(int i=0;i<16;i++) + { + transfer = (data[i].value_int32 >> 24) & 0xFF; + buffer[count++] = transfer; + transfer = (data[i].value_int32 >> 16) & 0xFF; + buffer[count++] = transfer; + transfer = (data[i].value_int32 >> 8) & 0xFF; + buffer[count++] = transfer; + transfer = (data[i].value_int32) & 0xFF; + buffer[count++] = transfer; + + translateDate(data[i].date_rtc_dr, &Sdate); + translateTime(data[i].time_rtc_tr, &Stime); + buffer[count++] = Sdate.Year; + buffer[count++] = Sdate.Month; + buffer[count++] = Sdate.Date; + buffer[count++] = Stime.Hours; + } +} + + +#ifndef BOOTLOADER_STANDALONE + +void ext_flash_write_devicedata(void) +{ + uint8_t *pData; + const uint16_t length = sizeof(SDevice); + uint8_t length_lo, length_hi; + uint8_t dataLength[2] = { 0 }; + + ext_flash_disable_protection(); + + pData = (uint8_t *)stateDeviceGetPointer(); + + actualPointerDevicedata = DDSTART; + + length_lo = (uint8_t)(length & 0xFF); + length_hi = (uint8_t)(length >> 8); + dataLength[0] = length_lo; + dataLength[1] = length_hi; + + ef_write_block(dataLength,2, EF_DEVICEDATA, 0); + ef_write_block(pData,length, EF_DEVICEDATA, 0); +} + + +uint16_t ext_flash_read_devicedata(uint8_t *buffer, uint16_t max_length) +{ + uint16_t length; + uint8_t length_lo, length_hi; + + actualAddress = DDSTART; + + ext_flash_read_block_start(); + ext_flash_read_block(&length_lo, EF_DEVICEDATA); + ext_flash_read_block(&length_hi, EF_DEVICEDATA); + + length = (length_hi * 256) + length_lo; + + if(length > max_length) + return 0; + + ext_flash_read_block_multi(buffer,length,EF_DEVICEDATA); + ext_flash_read_block_stop(); + + return length; +} + + +void ext_flash_write_vpm(SVpm *vpmInput) +{ + uint8_t *pData; + const uint16_t length = sizeof(SVpm); + + uint8_t length_lo, length_hi; + uint8_t dataLength[2] = { 0 }; + + pData = (uint8_t *)vpmInput; + + actualPointerVPM = VPMSTART; + + length_lo = (uint8_t)(length & 0xFF); + length_hi = (uint8_t)(length >> 8); + dataLength[0] = length_lo; + dataLength[1] = length_hi; + + ef_write_block(dataLength,2, EF_VPMDATA, 0); + ef_write_block(pData,length, EF_VPMDATA, 0); +} + + +int ext_flash_read_vpm(SVpm *vpmOutput) +{ + uint8_t *pData; + const uint16_t length = sizeof(SVpm); + uint8_t length_lo, length_hi; + int output; + + actualAddress = VPMSTART; + + ext_flash_read_block_start(); + ext_flash_read_block(&length_lo, EF_VPMDATA); + ext_flash_read_block(&length_hi, EF_VPMDATA); + if((length_lo == (uint8_t)(length & 0xFF)) + &&(length_hi == (uint8_t)(length >> 8))) + { + pData = (uint8_t *)vpmOutput; + for(uint16_t i = 0; i < length; i++) + ext_flash_read_block(&pData[i], EF_VPMDATA); + output = length; + } + else + output = 0; + + ext_flash_read_block_stop(); + return output; +} + +#ifdef DEMOMODE +void ext_flash_write_settings(void) +{ + return; +} +#else +void ext_flash_write_settings(void) +{ + uint8_t *pData; + const uint16_t length = sizeof(SSettings); + uint8_t length_lo, length_hi; + uint8_t dataLength[2] = { 0 }; + + ext_flash_disable_protection(); + + if(stateRealGetPointer()->lastKnownBatteryPercentage) + { + settingsGetPointer()->lastKnownBatteryPercentage = stateRealGetPointer()->lastKnownBatteryPercentage; + } + settingsGetPointer()->backup_localtime_rtc_tr = stateRealGetPointer()->lifeData.timeBinaryFormat; + settingsGetPointer()->backup_localtime_rtc_dr = stateRealGetPointer()->lifeData.dateBinaryFormat; + + pData = (uint8_t *)settingsGetPointer(); + + actualPointerSettings = SETTINGSSTART; + + length_lo = (uint8_t)(length & 0xFF); + length_hi = (uint8_t)(length >> 8); + dataLength[0] = length_lo; + dataLength[1] = length_hi; + + ef_write_block(dataLength,2, EF_SETTINGS, 0); + ef_write_block(pData,length, EF_SETTINGS, 0); +// ext_flash_enable_protection(); +} +#endif + + +/* CHANGES 150929 hw + * this now allows to read old settings too + * but make sure that everything is fixed in + * set_new_settings_missing_in_ext_flash + * new settings should be fine as they are added + * and loaded before calling this function + */ +uint8_t ext_flash_read_settings(void) +{ + uint8_t returnValue = HAL_BUSY; + uint8_t *pData; + const uint16_t lengthStandardNow = sizeof(SSettings); + uint8_t length_lo, length_hi; + uint16_t lengthOnEEPROM; + uint32_t header; + SSettings *pSettings = settingsGetPointer(); + + actualAddress = SETTINGSSTART; + + ext_flash_read_block_start(); + ext_flash_read_block(&length_lo, EF_SETTINGS); + ext_flash_read_block(&length_hi, EF_SETTINGS); + + lengthOnEEPROM = length_hi * 256; + lengthOnEEPROM += length_lo; + if(lengthOnEEPROM <= lengthStandardNow) + { + ext_flash_read_block_multi(&header, 4, EF_SETTINGS); + if((header <= pSettings->header) && (header >= pSettings->updateSettingsAllowedFromHeader)) + { + returnValue = HAL_OK; + pSettings->header = header; + pData = (uint8_t *)pSettings + 4; /* header */ + for(uint16_t i = 0; i < (lengthOnEEPROM-4); i++) + ext_flash_read_block(&pData[i], EF_SETTINGS); + } + else + { + returnValue = HAL_ERROR; + } + } + ext_flash_read_block_stop(); + return returnValue; +} + + + + + /* ext_flash_start_new_dive_log_and_set_actualPointerSample + * prepares the write sample pointer + * to be used by ext_flash_write_sample() + * to be set in the * pHeaderPreDive + * for write with ext_flash_create_new_dive_log() and ext_flash_close_new_dive_log() + */ +void ext_flash_start_new_dive_log_and_set_actualPointerSample(uint8_t *pHeaderPreDive) +{ + convert_Type data; + SSettings *settings = settingsGetPointer(); + + /* new 5. Jan. 2015 */ + actualPointerSample = settings->logFlashNextSampleStartAddress; + + if(!ext_flash_test_remaining_space_of_page_empty(actualPointerSample, 4)) + ext_flash_set_to_begin_of_next_page(&actualPointerSample, EF_SAMPLE); + + if((actualPointerSample < SAMPLESTART) || (actualPointerSample > SAMPLESTOP)) + actualPointerSample = SAMPLESTART; + + data.u32bit = actualPointerSample; + pHeaderPreDive[2] = data.u8bit.byteLow; + pHeaderPreDive[3] = data.u8bit.byteMidLow; + pHeaderPreDive[4] = data.u8bit.byteMidHigh; + /* to start sample writing and header etc. pp. */ + ext_flash_disable_protection_for_logbook(); +} + + + /* ext_flash_create_new_dive_log + * uses the first header without HEADER2OFFSET + * for the header it is not important to be complete + * and can be reconstructed + * ext_flash_start_new_dive_log_and_set_actualPointerSample() + * has to be called before to set the actualPointerSample + * in the header + * the following func writes to header to the ext_flash + */ +void ext_flash_create_new_dive_log(uint8_t *pHeaderPreDive) +{ + SSettings *settings; + uint8_t id, id_next; + uint8_t header1, header2; + + settings = settingsGetPointer(); + id = settings->lastDiveLogId; + + actualAddress = HEADERSTART + (0x800 * id); + ext_flash_read_block_start(); + ext_flash_read_block(&header1, EF_SAMPLE); + ext_flash_read_block(&header2, EF_SAMPLE); + ext_flash_read_block_stop(); + + if((header1 == 0xFA) && (header2 == 0xFA)) + { + id += 1; /* 0-255, auto rollover */ + if(id & 1) + { + actualAddress = HEADERSTART + (0x800 * id); + ext_flash_read_block_start(); + ext_flash_read_block(&header1, EF_SAMPLE); + ext_flash_read_block(&header2, EF_SAMPLE); + ext_flash_read_block_stop(); + if((header1 == 0xFA) && (header2 == 0xFA)) + id += 1; + } + } + else + { + id = 0; + } + + /* delete next header */ + id_next = id + 1; + actualPointerHeader = HEADERSTART + (0x800 * id_next); + ef_write_block(0,0, EF_HEADER, 0); + + settings->lastDiveLogId = id; + actualPointerHeader = HEADERSTART + (0x800 * id); + + if(pHeaderPreDive != 0) + ef_write_block(pHeaderPreDive,HEADERSIZE, EF_HEADER, 0); +} + + +void ext_flash_close_new_dive_log(uint8_t *pHeaderPostDive ) +{ + SSettings * settings = settingsGetPointer(); + uint8_t id; + convert_Type startAddress; + convert_Type data; + uint32_t backup; + + uint8_t sampleData[3]; + actualAddress = actualPointerSample; + sampleData[0] = 0xFD; + sampleData[1] = 0xFD; + ext_flash_write_sample(sampleData, 2); + + /* end of sample data, pointing to the last sample 0xFD + */ + actualAddress = actualPointerSample; // change hw 17.09.2015 + ext_flash_decf_address_ring(EF_SAMPLE); // 17.09.2015: this decf actualAddress only!! + actualPointerSample = actualAddress; // change hw 17.09.2015 + data.u32bit = actualPointerSample; + + pHeaderPostDive[5] = data.u8bit.byteLow; + pHeaderPostDive[6] = data.u8bit.byteMidLow; + pHeaderPostDive[7] = data.u8bit.byteMidHigh; + + /* take data written before, calculate length and write + SLogbookHeader has different order: length (byte# 8,9,10) prior to profile version (byte# 11) + */ + startAddress.u8bit.byteLow = pHeaderPostDive[2]; + startAddress.u8bit.byteMidLow = pHeaderPostDive[3]; + startAddress.u8bit.byteMidHigh = pHeaderPostDive[4]; + startAddress.u8bit.byteHigh = 0; + + if(startAddress.u32bit < actualPointerSample) + data.u32bit = 1 + actualPointerSample - startAddress.u32bit; + else + data.u32bit = 2 + (actualPointerSample - SAMPLESTART) + (SAMPLESTOP - startAddress.u32bit); + + pHeaderPostDive[8] = data.u8bit.byteLow; + pHeaderPostDive[9] = data.u8bit.byteMidLow; + pHeaderPostDive[10] = data.u8bit.byteMidHigh; + + /* set id and write post-dive-header + */ + id = settings->lastDiveLogId; + actualPointerHeader = HEADERSTART + (0x800 * id) + HEADER2OFFSET; + + ef_write_block(pHeaderPostDive,HEADERSIZE, EF_HEADER, 0); + + /* write length at beginning of sample + and write proper beginning for next dive to actualPointerSample + */ + backup = actualPointerSample; + actualPointerSample = startAddress.u32bit; // is still 0xFF + sampleData[0] = data.u8bit.byteLow; + sampleData[1] = data.u8bit.byteMidLow; + sampleData[2] = data.u8bit.byteMidHigh; + ext_flash_overwrite_sample_without_erase(sampleData, 3); + + actualAddress = backup; + ext_flash_incf_address(EF_SAMPLE); + actualPointerSample = actualAddress; + ext_flash_enable_protection(); +} + + +void ext_flash_write_sample(uint8_t *pSample, uint16_t length) +{ + ef_write_block(pSample,length, EF_SAMPLE, 0); + + SSettings *settings = settingsGetPointer(); + settings->logFlashNextSampleStartAddress = actualPointerSample; +} + +void ext_flash_overwrite_sample_without_erase(uint8_t *pSample, uint16_t length) +{ + ef_write_block(pSample,length, EF_SAMPLE, 1); +} + + +uint8_t ext_flash_count_dive_headers(void) +{ + uint8_t id = 0; + uint8_t counter = 0; + uint16_t headerStartData = 0x0000; + + id = settingsGetPointer()->lastDiveLogId; + + do + { + actualAddress = HEADERSTART + (0x800 * id) + HEADER2OFFSET; + ext_flash_read_block_start(); + ext_flash_read_block_multi((uint8_t *)&headerStartData, 2, EF_HEADER); + ext_flash_read_block_stop(); + counter++; + id -=1; + } while((headerStartData == 0xFAFA) && (counter < 255)); + return (counter - 1); +} + + +void ext_flash_read_dive_header(uint8_t *pHeaderToFill, uint8_t StepBackwards) +{ + SSettings *settings; + uint8_t id; + uint16_t i; + + settings = settingsGetPointer(); + id = settings->lastDiveLogId; + id -= StepBackwards; /* 0-255, auto rollover */ + + actualAddress = HEADERSTART + (0x800 * id) + HEADER2OFFSET; + ext_flash_read_block_start(); + for(i = 0; i < HEADERSIZE; i++) + ext_flash_read_block(&pHeaderToFill[i], EF_HEADER); + ext_flash_read_block_stop(); + +} + +void ext_flash_read_dive_header2(uint8_t *pHeaderToFill, uint8_t id, _Bool bOffset) +{ + + uint16_t i; + actualAddress = HEADERSTART + (0x800 * id) ; + + if(bOffset) + actualAddress += HEADER2OFFSET; + ext_flash_read_block_start(); + for(i = 0; i < HEADERSIZE; i++) + ext_flash_read_block(&pHeaderToFill[i], EF_HEADER); + ext_flash_read_block_stop(); +} + + +uint32_t ext_flash_read_dive_raw_with_double_header_1K(uint8_t *data, uint32_t max_size, uint8_t StepBackwards) +{ + if(max_size < 0x800) + return 0; + + uint8_t id; + convert_Type dataStart, dataEnd; + uint32_t LengthAll = 0; + + id = settingsGetPointer()->lastDiveLogId; + id -= StepBackwards; /* 0-255, auto rollover */ + + // clear data + for(int i=0;i<0x800;i++) + data[i] = 0xFF; + + // copy primary/pre-dive + actualAddress = HEADERSTART + (0x800 * id); + ext_flash_read_block_start(); + for(int i = 0; i < HEADERSIZE; i++) + ext_flash_read_block(&data[i], EF_HEADER); + ext_flash_read_block_stop(); + + // copy main/secondary/post-dive + actualAddress = HEADERSTART + (0x800 * id) + HEADER2OFFSET; + ext_flash_read_block_start(); + for(int i = 0x400; i < HEADERSIZE+0x400; i++) + ext_flash_read_block(&data[i], EF_HEADER); + ext_flash_read_block_stop(); + + // data + + dataStart.u8bit.byteHigh = 0; + dataStart.u8bit.byteLow = data[0x402]; + dataStart.u8bit.byteMidLow = data[0x403]; + dataStart.u8bit.byteMidHigh = data[0x404]; + + dataEnd.u8bit.byteHigh = 0; + dataEnd.u8bit.byteLow = data[0x405]; + dataEnd.u8bit.byteMidLow = data[0x406]; + dataEnd.u8bit.byteMidHigh = data[0x407]; + + actualPointerSample = dataStart.u32bit; + if(dataEnd.u32bit >= dataStart.u32bit) + LengthAll = 1 + dataEnd.u32bit - dataStart.u32bit; + else + LengthAll = 2 + (dataStart.u32bit - SAMPLESTART) + (SAMPLESTOP - dataEnd.u32bit); + + LengthAll += 0x800; + + if(LengthAll > max_size) + return 0x800; + + actualAddress = actualPointerSample; + ext_flash_read_block_start(); + for(uint32_t i = 0x800; i < LengthAll; i++) + ext_flash_read_block(&data[i], EF_SAMPLE); + ext_flash_read_block_stop(); + return LengthAll; +} + +void ext_flash_write_dive_raw_with_double_header_1K(uint8_t *data, uint32_t length) +{ + convert_Type dataStart, dataEnd; + SLogbookHeader headerTemp; + + // set actualPointerSample and get pointer to sample storage and disable flash write protect + ext_flash_start_new_dive_log_and_set_actualPointerSample((uint8_t *)&headerTemp); + + dataStart.u8bit.byteHigh = 0; + dataStart.u8bit.byteLow = headerTemp.pBeginProfileData[0]; + dataStart.u8bit.byteMidLow = headerTemp.pBeginProfileData[1]; + dataStart.u8bit.byteMidHigh = headerTemp.pBeginProfileData[2]; + + dataEnd.u32bit = dataStart.u32bit + length - 0x801; + if(dataEnd.u32bit > SAMPLESTOP) + dataEnd.u32bit -= SAMPLESTOP + SAMPLESTART - 1; + + data[0x002] = data[0x402] = dataStart.u8bit.byteLow; + data[0x003] = data[0x403] = dataStart.u8bit.byteMidLow; + data[0x004] = data[0x404] = dataStart.u8bit.byteMidHigh; + data[0x005] = data[0x405] = dataEnd.u8bit.byteLow; + data[0x006] = data[0x406] = dataEnd.u8bit.byteMidLow; + data[0x007] = data[0x407] = dataEnd.u8bit.byteMidHigh; + + // set actualPointerHeader to next free header and update lastDiveLogId + ext_flash_create_new_dive_log(0); + + // copy header data + ef_write_block(data,0x800,EF_HEADER, 1); + + // copy sample data + ef_write_block(&data[0x800], length-0x800, EF_SAMPLE, 1); + + // update logFlashNextSampleStartAddress + settingsGetPointer()->logFlashNextSampleStartAddress = actualPointerSample; +} + + +// =============================================================================== +// ext_flash_read_header_memory +/// @brief This function returns the entire header space 1:1 +/// @date 04-April-2016 +/// +/// @param *data 256KB output +// =============================================================================== +void ext_flash_read_header_memory(uint8_t *data) +{ + actualAddress = HEADERSTART; + actualPointerHeader = actualAddress; + ext_flash_read_block_start(); + for(int i=0;i<8;i++) + ext_flash_read_block_multi(&data[0x8000 * i], 0x8000, EF_HEADER); + ext_flash_read_block_stop(); +} + + +// =============================================================================== +// ext_flash_read_header_memory +/// @brief This function erases and overwrites the entire logbook header block +/// @date 04-April-2016 +/// +/// @param *data 256KB input of header memory 1:1 +// =============================================================================== +void ext_flash_write_header_memory(uint8_t *data) +{ + actualAddress = HEADERSTART; + actualPointerHeader = actualAddress; + ef_write_block(data, 0x40000, EF_HEADER, 0); +} + + +void ext_flash_open_read_sample(uint8_t StepBackwards, uint32_t *totalNumberOfBytes) +{ + SSettings *settings = settingsGetPointer(); + uint8_t id; + convert_Type dataStart, dataEnd; + uint8_t header1, header2; + + id = settings->lastDiveLogId; + id -= StepBackwards; /* 0-255, auto rollover */ +# + actualAddress = HEADERSTART + (0x800 * id) + HEADER2OFFSET; + actualPointerHeader = actualAddress; + + ext_flash_read_block_start(); + /* little endian */ + ext_flash_read_block(&header1, EF_HEADER); + ext_flash_read_block(&header2, EF_HEADER); + dataStart.u8bit.byteHigh = 0; + ext_flash_read_block(&dataStart.u8bit.byteLow, EF_HEADER); + ext_flash_read_block(&dataStart.u8bit.byteMidLow, EF_HEADER); + ext_flash_read_block(&dataStart.u8bit.byteMidHigh, EF_HEADER); + dataEnd.u8bit.byteHigh = 0; + ext_flash_read_block(&dataEnd.u8bit.byteLow, EF_HEADER); + ext_flash_read_block(&dataEnd.u8bit.byteMidLow, EF_HEADER); + ext_flash_read_block(&dataEnd.u8bit.byteMidHigh, EF_HEADER); + ext_flash_read_block_stop(); + + actualPointerSample = dataStart.u32bit; + if(dataEnd.u32bit >= dataStart.u32bit) + LengthLeftSampleRead = 1 + dataEnd.u32bit - dataStart.u32bit; + else + LengthLeftSampleRead = 2 + (dataStart.u32bit - SAMPLESTART) + (SAMPLESTOP - dataEnd.u32bit); + *totalNumberOfBytes = LengthLeftSampleRead; + + actualAddress = actualPointerSample; + ext_flash_read_block_start(); +} + + +void ext_flash_read_next_sample_part(uint8_t *pSample, uint8_t length) +{ + for(uint16_t i = 0; i < length; i++) + ext_flash_read_block(&pSample[i], EF_SAMPLE); +} + + +void ext_flash_close_read_sample(void) +{ + actualPointerSample = actualAddress; + ext_flash_read_block_stop(); +} + + +void ext_flash_set_entry_point(void) +{ + entryPoint = actualAddress; +} + + +void ext_flash_reopen_read_sample_at_entry_point(void) +{ + error_led_on(); + chip_unselect(); + wait_chip_not_busy(); + + actualAddress = entryPoint; + ext_flash_read_block_start(); + error_led_off(); +} + +/* +uint8_t ext_flash_point_to_64k_block_in_headerSpace(uint8_t logId) +{ + uint32_t pointerToData = logId * 0x800; + + return pointerToData / 0x10000; +} +*/ + + +// =============================================================================== +// ext_flash_repair_dive_numbers_starting_count_helper +/// @brief +/// @date 22-June-2016 + +// =============================================================================== +uint16_t ext_flash_repair_dive_numbers_starting_count_helper(uint8_t *data, uint8_t *change64k, uint16_t startNumber, uint8_t lastLogId) +{ + const uint32_t headerStep = 0x800; + uint8_t actualLogId = 0; + uint16_t oldNumber = 0; + uint16_t actualNumber = 0; + SLogbookHeader *ptrLogbookHeader = 0; + + if(startNumber == 0) + return 0; + + actualNumber = startNumber - 1; + + // wo ist der �lteste Tauchgang (der, der startNumber bekommt) + // use first header for ease (without HEADER2OFFSET for end of dive header) + // compare for lastLogId to prevent endless loop + + if(*(uint16_t*)&data[lastLogId * headerStep] != 0xFAFA) + return 0; + + actualLogId = lastLogId - 1; + while((*(uint16_t*)&data[actualLogId * headerStep] == 0xFAFA) && (actualLogId != lastLogId)) + { + actualLogId--; + } + + // now pointing to one behind the last + while(actualLogId != lastLogId) + { + actualLogId++; + actualNumber++; + ptrLogbookHeader = (SLogbookHeader *)&data[actualLogId * headerStep]; + + oldNumber = ptrLogbookHeader->diveNumber; + if(oldNumber != actualNumber) + { +// change64k[ext_flash_point_to_64k_block_in_headerSpace(actualLogId )] = 1; + change64k[(actualLogId * 0x800)/0x10000] = 1; + ptrLogbookHeader->diveNumber = actualNumber; + ptrLogbookHeader = (SLogbookHeader *)(&data[actualLogId * headerStep] + HEADER2OFFSET); + ptrLogbookHeader->diveNumber = actualNumber; + } + } + + return actualNumber; +} + + // =============================================================================== +// ext_flash_repair_SPECIAL_dive_numbers_starting_count_with +/// @brief This function +/// @date 04-April-2016 +/// problem (160621): 64K Bl�cke (32 Tauchg�nge) weil neuer Flash Chip. +/// Dieser Bereich muss auf einmal gel�scht werden. +/// Vorher waren es 4K Bl�cke. +/// @output endCount, last diveNumber + +// =============================================================================== +uint16_t ext_flash_repair_SPECIAL_dive_numbers_starting_count_with(uint16_t startCount) +{ + uint32_t logCopyDataPtr = 0; + uint8_t *data; + uint16_t lastCount; + uint8_t listOfChanged64kBlocks[8]; // 32 Tauchg�nge pro 64K + + logCopyDataPtr = getFrame(97); + data = (uint8_t *)logCopyDataPtr; + + for(int i=0;i<8;i++) + listOfChanged64kBlocks[i] = 0; + + actualAddress = HEADERSTART; + ext_flash_read_block_start(); + ext_flash_read_block_multi(data,0x100000,EF_HEADER); + ext_flash_read_block_stop(); + + lastCount = ext_flash_repair_dive_numbers_starting_count_helper(data, listOfChanged64kBlocks, startCount, settingsGetPointer()->lastDiveLogId); + + for(int i=0;i<8;i++) + { + if(listOfChanged64kBlocks[i] != 0) + { + actualPointerHeader = HEADERSTART + (i * 0x10000); + ef_write_block(&data[i * 0x10000], 0x10000, EF_HEADER, 0); + } + } + + releaseFrame(97,logCopyDataPtr); + if(settingsGetPointer()->totalDiveCounter < lastCount) + { + settingsGetPointer()->totalDiveCounter = lastCount; + } + return lastCount; +} + + +void OLD_ext_flash_repair_SPECIAL_dive_numbers_starting_count_with(uint16_t startCount) +{ + uint16_t counterStorage[256]; + uint8_t start = 0xFF; + uint32_t logCopyDataPtr = 0; + uint8_t *data; + uint8_t startAbsolute = 0; + int16_t count = 0; + _Bool repair = 0; + uint8_t startBackup = 0; + + SLogbookHeader tempLogbookHeader; + SLogbookHeader *ptrHeaderInData1a; + SLogbookHeader *ptrHeaderInData1b; + SLogbookHeader *ptrHeaderInData2a; + SLogbookHeader *ptrHeaderInData2b; + + logCopyDataPtr = getFrame(97); + data = (uint8_t *)logCopyDataPtr; + ptrHeaderInData1a = (SLogbookHeader *)logCopyDataPtr; + ptrHeaderInData1b = (SLogbookHeader *)(logCopyDataPtr + HEADER2OFFSET); + ptrHeaderInData2a = (SLogbookHeader *)(logCopyDataPtr + 0x800); + ptrHeaderInData2b = (SLogbookHeader *)(logCopyDataPtr + 0x800 + HEADER2OFFSET); + + // get data + for(int StepBackwards = 0; StepBackwards < 255; StepBackwards++) + { + logbook_getHeader(StepBackwards, &tempLogbookHeader); + counterStorage[StepBackwards+1] = tempLogbookHeader.diveNumber; + if(tempLogbookHeader.diveHeaderStart == 0xFAFA) + start = StepBackwards; + else + break; + } + + if(start == 0xFF) + return; + + count = start + 1; + startAbsolute = settingsGetPointer()->lastDiveLogId; + + +/* + if(start%2) + { + if(counterStorage[start] != startCount) + { + // clear data + for(int i=0;i<0x800*2;i++) + data[i] = 0xFF; + + uint8_t id = settingsGetPointer()->lastDiveLogId; + id -= start; // 0-255, auto rollover + + // copy primary/pre-dive + actualAddress = HEADERSTART + (0x800 * id); + ext_flash_read_block_start(); + for(int i = 0; i < HEADERSIZE; i++) + ext_flash_read_block(&data[i], EF_HEADER); + ext_flash_read_block_stop(); + + // copy main/secondary/post-dive + actualAddress = HEADERSTART + (0x800 * id) + HEADER2OFFSET; + ext_flash_read_block_start(); + for(int i = 0x400; i < HEADERSIZE+0x400; i++) + ext_flash_read_block(&data[i], EF_HEADER); + ext_flash_read_block_stop(); + + // repair + ptrHeaderInData2a->diveNumber = startCount; + ptrHeaderInData2b->diveNumber = startCount; + startCount++; + + // write + actualAddress = HEADERSTART + (0x800 * (id-1)); + ef_write_block(data,0x800*2,EF_HEADER, 0); + } + start--; + } +*/ +// for(int count = start; count > -1; count -= 2) + + while(count > 0) + { + // clear data + for(int i=0;i<0x1000;i++) + data[i] = 0xFF; + + repair = 0; + + startBackup = startAbsolute; + + if(startAbsolute%2) // 0x800 to 0x1000 + { + // copy second pre-dive + actualAddress = HEADERSTART + (0x800 * startAbsolute); + ext_flash_read_block_start(); + for(int i = 0x800; i < HEADERSIZE+0x800; i++) + ext_flash_read_block(&data[i], EF_HEADER); + ext_flash_read_block_stop(); + + // copy second post-dive + actualAddress = HEADERSTART + HEADER2OFFSET + (0x800 * startAbsolute); + ext_flash_read_block_start(); + for(int i = 0xC00; i < HEADERSIZE+0xC00; i++) + ext_flash_read_block(&data[i], EF_HEADER); + ext_flash_read_block_stop(); + + if(counterStorage[count] != startCount) + { + ptrHeaderInData2a->diveNumber = startCount; + ptrHeaderInData2b->diveNumber = startCount; + repair = 1; + } + startCount += 1; + + startAbsolute -= 1; + count -= 1; + + if(count > 0) + { + // copy first pre-dive + actualAddress = HEADERSTART + (0x800 * startAbsolute); + ext_flash_read_block_start(); + for(int i = 0; i < HEADERSIZE; i++) + ext_flash_read_block(&data[i], EF_HEADER); + ext_flash_read_block_stop(); + + // copy first post-dive + actualAddress = HEADERSTART + (0x800 * startAbsolute); + ext_flash_read_block_start(); + for(int i = 0x400; i < HEADERSIZE+0x400; i++) + ext_flash_read_block(&data[i], EF_HEADER); + ext_flash_read_block_stop(); + + if(counterStorage[count] != startCount) + { + ptrHeaderInData1a->diveNumber = startCount; + ptrHeaderInData1b->diveNumber = startCount; + repair = 1; + } + startCount += 1; + + startAbsolute -= 1; + count -= 1; + } + } + else + { + // copy first pre-dive + actualAddress = HEADERSTART + (0x800 * startAbsolute); + ext_flash_read_block_start(); + for(int i = 0; i < HEADERSIZE; i++) + ext_flash_read_block(&data[i], EF_HEADER); + ext_flash_read_block_stop(); + + // copy first post-dive + actualAddress = HEADERSTART + (0x800 * startAbsolute); + ext_flash_read_block_start(); + for(int i = 0x400; i < HEADERSIZE+0x400; i++) + ext_flash_read_block(&data[i], EF_HEADER); + ext_flash_read_block_stop(); + + if(counterStorage[count] != startCount) + { + ptrHeaderInData1a->diveNumber = startCount; + ptrHeaderInData1b->diveNumber = startCount; + repair = 1; + } + startCount += 1; + + startAbsolute -= 1; + count -= 1; + } + + // write + if(repair) + { + actualPointerHeader = HEADERSTART + (0x1000 * startBackup%2); + ef_write_block(data,0x1000,EF_HEADER, 0); + } + } + releaseFrame(97,logCopyDataPtr); + settingsGetPointer()->totalDiveCounter = startCount; +} + + +// =============================================================================== +// ext_flash_repair_dive_log +/// @brief This function +/// does set +/// logFlashNextSampleStartAddress +/// and +/// lastDiveLogId +/// +void ext_flash_repair_dive_log(void) +{ + uint8_t header1, header2; + convert_Type dataStart; + + for(int id = 0; id < 255;id++) + { + actualAddress = HEADERSTART + (0x800 * id); + ext_flash_read_block_start(); + ext_flash_read_block(&header1, EF_HEADER); + ext_flash_read_block(&header2, EF_HEADER); + dataStart.u8bit.byteHigh = 0; + ext_flash_read_block(&dataStart.u8bit.byteLow, EF_HEADER); + ext_flash_read_block(&dataStart.u8bit.byteMidLow, EF_HEADER); + ext_flash_read_block(&dataStart.u8bit.byteMidHigh, EF_HEADER); + ext_flash_read_block_stop(); + if((header1 == 0xFA) && (header2 == 0xFA)) + { + actualAddress = HEADERSTART + (0x800 * id) + HEADER2OFFSET; + ext_flash_read_block_start(); + ext_flash_read_block(&header1, EF_HEADER); + ext_flash_read_block(&header2, EF_HEADER); + ext_flash_read_block_stop(); + if((header1 != 0xFA) || (header2 != 0xFA)) + { + actualPointerSample = dataStart.u32bit; + actualAddress = actualPointerSample; + logbook_recover_brokenlog(id); + SSettings *settings = settingsGetPointer(); + settings->logFlashNextSampleStartAddress = actualPointerSample; + } + } + } + ext_flash_find_start(); +} + + +void ext_flash_find_start(void) +{ + uint8_t id; + uint8_t header1, header2; + convert_Type dataStart, dataEnd; + + for(id = 0; id < 255;id++) + { + actualAddress = HEADERSTART + (0x800 * id) + HEADER2OFFSET; + ext_flash_read_block_start(); + ext_flash_read_block(&header1, EF_HEADER); + ext_flash_read_block(&header2, EF_HEADER); + dataStart.u8bit.byteHigh = 0; + ext_flash_read_block(&dataStart.u8bit.byteLow, EF_HEADER); + ext_flash_read_block(&dataStart.u8bit.byteMidLow, EF_HEADER); + ext_flash_read_block(&dataStart.u8bit.byteMidHigh, EF_HEADER); + ext_flash_read_block_stop(); + if((header1 == 0xFF) && (header2 == 0xFF)) + { + break; + } + } + id--; + SSettings *settings = settingsGetPointer(); + settings->lastDiveLogId = id; + + actualAddress = HEADERSTART + (0x800 * id) + HEADER2OFFSET; + actualPointerHeader = actualAddress; + + ext_flash_read_block_start(); + + ext_flash_read_block(&header1, EF_HEADER); + ext_flash_read_block(&header2, EF_HEADER); + dataStart.u8bit.byteHigh = 0; + ext_flash_read_block(&dataStart.u8bit.byteLow, EF_HEADER); + ext_flash_read_block(&dataStart.u8bit.byteMidLow, EF_HEADER); + ext_flash_read_block(&dataStart.u8bit.byteMidHigh, EF_HEADER); + dataEnd.u8bit.byteHigh = 0; + ext_flash_read_block(&dataEnd.u8bit.byteLow, EF_HEADER); + ext_flash_read_block(&dataEnd.u8bit.byteMidLow, EF_HEADER); + ext_flash_read_block(&dataEnd.u8bit.byteMidHigh, EF_HEADER); + ext_flash_read_block_stop(); + + //Find free space + if((header1 == 0xFA) && (header2 == 0xFA)) + { + uint8_t uiRead = 0; + int countFF = 0; + //End of last complete dive + actualPointerSample = dataEnd.u32bit ; + actualAddress = actualPointerSample; + //Check if there are samples of dives with less than half a minute + while(true) + { + ext_flash_read_block_start(); + ext_flash_read_block(&uiRead, EF_SAMPLE); + if(uiRead == 0xFF) + countFF++; + else + countFF = 0; + + + + if(countFF == 10) + { + actualAddress -= 10; + break; + } + + //New page: clear + if(ext_flash_erase_if_on_page_start()) + break; + } + // Set new start address + actualPointerSample = actualAddress; + settings->logFlashNextSampleStartAddress = actualPointerSample; + } + else + { + settings->logFlashNextSampleStartAddress = SAMPLESTART; + } +} + + +#endif + +void ext_flash_disable_protection(void) +{ +/* + extFlashStatusBit8_Type status; + + status.uw = 0; + + wait_chip_not_busy(); + write_spi(0x50,RELEASE); // EWSR + write_spi(0x01,HOLDCS); // WRSR + write_spi(status.uw,RELEASE); // new status +*/ +} + + +void ext_flash_disable_protection_for_logbook(void) +{ + /* + extFlashStatusBit8_Type status; + + status.uw = 0; + status.ub.BlockProtect0 = 1; + status.ub.BlockProtect1 = 0; + status.ub.BlockProtect2 = 1; + status.ub.BlockProtect3 = 0; // not set in OSTC3. Why? + + wait_chip_not_busy(); + write_spi(0x50,RELEASE); // EWSR + write_spi(0x01,HOLDCS); // WRSR + write_spi(status.uw,RELEASE); // new status +*/ +} + + +void ext_flash_enable_protection(void) +{ +/* + extFlashStatusBit8_Type status; + + status.uw = 0; + status.ub.BlockProtect0 = 1; + status.ub.BlockProtect1 = 1; + status.ub.BlockProtect2 = 1; + status.ub.BlockProtect3 = 1; // not set in OSTC3. Why? + + wait_chip_not_busy(); + write_spi(0x50,RELEASE); // EWSR + write_spi(0x01,HOLDCS); // WRSR + write_spi(status.uw,RELEASE); // new status +*/ +} + + +void ext_flash_erase_chip(void) +{ + wait_chip_not_busy(); + write_spi(0x06,RELEASE); + write_spi(0x60,RELEASE); + wait_chip_not_busy(); +} + +void ext_flash_erase_firmware(void) +{ + uint32_t size, blocks_64k; + + actualAddress = FWSTART; + size = 1 + FWSTOP - FWSTART; + blocks_64k = size / 0x10000; + ef_erase_64K(blocks_64k); +} + +void ext_flash_erase_firmware2(void) +{ + uint32_t size, blocks_64k; + + actualAddress = FWSTART2; + size = 1 + FWSTOP2 - FWSTART2; + blocks_64k = size / 0x10000; + ef_erase_64K(blocks_64k); +} + + + +void ext_flash_erase_logbook(void) +{ + uint32_t size, blocks_64k; + + ext_flash_disable_protection_for_logbook(); + + actualAddress = SAMPLESTART; + size = 1 + SAMPLESTOP - SAMPLESTART; + blocks_64k = size / 0x10000; + ef_erase_64K(blocks_64k); + + actualAddress = HEADERSTART; + size = 1 + HEADERSTOP - HEADERSTART; + blocks_64k = size / 0x10000; + ef_erase_64K(blocks_64k); + + ext_flash_enable_protection(); +} + + +void ext_flash_erase4kB(void) +{ + wait_chip_not_busy(); + write_spi(0x06,RELEASE);/* WREN */ + write_spi(0x20,HOLDCS);/* sector erase cmd */ + write_address(RELEASE); +} + +/* be carefull - might not work with entire family and other products + * see page 14 of LOGBOOK_V3_S25FS-S_00-271247.pdf + */ +void ext_flash_erase32kB(void) +{ + uint32_t actualAddress_backup; + + actualAddress_backup = actualAddress; + actualAddress = 0; + wait_chip_not_busy(); + write_spi(0x06,RELEASE);/* WREN */ + write_spi(0xD8,HOLDCS);/* sector erase cmd */ + write_address(RELEASE); + actualAddress = actualAddress_backup; +} + + +void ext_flash_erase64kB(void) +{ + wait_chip_not_busy(); + write_spi(0x06,RELEASE);/* WREN */ + write_spi(0xD8,HOLDCS);/* sector erase cmd */ + write_address(RELEASE); +} + + +void ext_flash_read_block_start(void) +{ + wait_chip_not_busy(); + write_spi(0x03,HOLDCS); /* WREN */ + write_address(HOLDCS); +} + +/* 4KB, 32KB, 64 KB, not the upper 16 MB with 4 Byte address at the moment */ +uint8_t ext_flash_erase_if_on_page_start(void) +{ + if(actualAddress < 0x00008000) + { + /* 4K Byte is 0x1000 */ + if((actualAddress & 0xFFF) == 0) + { + ext_flash_erase4kB(); + return 1; + } + } + else + if(actualAddress < 0x00010000) + { + /* 32K Byte is only one page */ + if(actualAddress == 0x00010000) + { + ext_flash_erase32kB(); + return 1; + } + } + else + { + /* 64K Byte is 0x10000 */ + if((actualAddress & 0xFFFF) == 0) + { + ext_flash_erase64kB(); + return 1; + } + } + return 0; +} + + +void ext_flash_read_block(uint8_t *getByte, uint8_t type) +{ + *getByte = read_spi(HOLDCS);/* read data */ + ext_flash_incf_address(type); +} + + +void ext_flash_read_block_multi(void *getByte, uint32_t size, uint8_t type) +{ + uint8_t *data; + data = getByte; + + for(uint32_t i=0;i<size;i++) + { + data[i] = read_spi(HOLDCS);/* read data */ + ext_flash_incf_address(type); + } +} + + +void ext_flash_read_block_stop(void) +{ + chip_unselect(); +} + + +/* Private functions ---------------------------------------------------------*/ + +void ef_write_block(uint8_t * sendByte, uint32_t length, uint8_t type, uint8_t do_not_erase) +{ + uint32_t remaining_page_size, remaining_length, remaining_space_to_ring_end; + + if(!length) + return; + + uint32_t ringStart, ringStop; + + switch(type) + { + case EF_HEADER: + actualAddress = actualPointerHeader; + ringStart = HEADERSTART; + ringStop = HEADERSTOP; + break; + case EF_SAMPLE: + actualAddress = actualPointerSample; + ringStart = SAMPLESTART; + ringStop = SAMPLESTOP; + break; + case EF_DEVICEDATA: + actualAddress = actualPointerDevicedata; + ringStart = DDSTART; + ringStop = DDSTOP; + break; + case EF_VPMDATA: + actualAddress = actualPointerVPM; + ringStart = VPMSTART; + ringStop = VPMSTOP; + break; + case EF_SETTINGS: + actualAddress = actualPointerSettings; + ringStart = SETTINGSSTART; + ringStop = SETTINGSSTOP; + break; + case EF_FIRMWARE: + actualAddress = actualPointerFirmware; + ringStart = FWSTART; + ringStop = FWSTOP; + break; + case EF_FIRMWARE2: + actualAddress = actualPointerFirmware2; + ringStart = FWSTART2; + ringStop = FWSTOP2; + break; + default: + ringStart = FLASHSTART; + ringStop = FLASHSTOP; + break; + } + /* safety */ + if(actualAddress < ringStart) + actualAddress = ringStart; + + if(do_not_erase == 0) + ext_flash_erase_if_on_page_start(); + + for(uint32_t i=0;i<length;i++) + { + ef_hw_rough_delay_us(5); + wait_chip_not_busy(); + write_spi(0x06,RELEASE); /* WREN */ + write_spi(0x02,HOLDCS); /* write cmd */ + write_address(HOLDCS); + + remaining_length = length - i; + remaining_page_size = actualAddress & 0xFF; + remaining_space_to_ring_end = ringStop - actualAddress; + + if((remaining_page_size == 0) && (remaining_length >= 256) && (remaining_space_to_ring_end >= 256)) + { + for(int j=0; j<255; j++) + { + write_spi(sendByte[i],HOLDCS);/* write data */ + actualAddress++; + i++; + } + } + /* byte with RELEASE */ + write_spi(sendByte[i],RELEASE);/* write data */ + actualAddress++; + if(actualAddress > ringStop) + actualAddress = ringStart; + if(do_not_erase == 0) + ext_flash_erase_if_on_page_start(); + } + switch(type) + { + case EF_HEADER: + actualPointerHeader = actualAddress; + break; + case EF_SAMPLE: + actualPointerSample = actualAddress; + break; + case EF_DEVICEDATA: + actualPointerDevicedata = actualAddress; + break; + case EF_VPMDATA: + actualPointerVPM = actualAddress; + break; + case EF_SETTINGS: + actualPointerSettings = actualAddress; + break; + case EF_FIRMWARE: + actualPointerFirmware = actualAddress; + break; + case EF_FIRMWARE2: + actualPointerFirmware2 = actualAddress; + break; + default: + break; + } +} + + +_Bool ext_flash_test_remaining_space_of_page_empty(uint32_t pointer, uint16_t length) +{ + if((pointer & 0xFFF) == 0) + return 1; + + uint32_t backup = actualAddress; + uint8_t data; + uint32_t size_to_page_end; + + size_to_page_end = 0x1000 - (pointer & 0xFFF); + if(length > size_to_page_end) + length = size_to_page_end; + + actualAddress = pointer; + ext_flash_read_block_start(); + + for(uint16_t i = 0; i<length; i++) + { + ext_flash_read_block(&data, 255); // 255 = ENTIRE FLASH + if(data != 0xFF) + { + ext_flash_read_block_stop(); + actualAddress = backup; + return 0; + } + } + ext_flash_read_block_stop(); + actualAddress = backup; + return 1; +} + + +void ext_flash_set_to_begin_of_next_page(uint32_t *pointer, uint8_t type) +{ + uint32_t ringStart, ringStop; + + switch(type) + { + case EF_HEADER: + ringStart = HEADERSTART; + ringStop = HEADERSTOP; + break; + case EF_SAMPLE: + ringStart = SAMPLESTART; + ringStop = SAMPLESTOP; + break; + case EF_DEVICEDATA: + ringStart = DDSTART; + ringStop = DDSTOP; + break; + case EF_VPMDATA: + ringStart = VPMSTART; + ringStop = VPMSTOP; + break; + case EF_SETTINGS: + ringStart = SETTINGSSTART; + ringStop = SETTINGSSTOP; + break; + default: + ringStart = FLASHSTART; + ringStop = FLASHSTOP; + break; + } + + *pointer = (*pointer & 0xFFF) + 0x1000; + + if((*pointer < ringStart) || (*pointer >= ringStop)) + *pointer = ringStart; +} + + +static void ef_erase_64K(uint32_t blocks) +{ + for(uint32_t i = 0; i < blocks; i++) + { + wait_chip_not_busy(); + write_spi(0x06,RELEASE);/* WREN */ + write_spi(0xD8,HOLDCS);/* 64k erase cmd */ + write_address(RELEASE); + actualAddress += 0x10000; + HAL_Delay(25); + } +} + + +void chip_unselect(void) +{ + HAL_GPIO_WritePin(EXTFLASH_CSB_GPIO_PORT,EXTFLASH_CSB_PIN,GPIO_PIN_SET); // chip select +} + +void chip_select(void) +{ + HAL_GPIO_WritePin(EXTFLASH_CSB_GPIO_PORT,EXTFLASH_CSB_PIN,GPIO_PIN_RESET); // chip select +} + +void error_led_on(void) +{ + HAL_GPIO_WritePin(OSCILLOSCOPE_GPIO_PORT,OSCILLOSCOPE_PIN,GPIO_PIN_SET); +} + +void error_led_off(void) +{ + HAL_GPIO_WritePin(OSCILLOSCOPE_GPIO_PORT,OSCILLOSCOPE_PIN,GPIO_PIN_RESET); +} + + +uint8_t read_spi(uint8_t unselect_CS_afterwards) +{ + uint8_t byte; + + chip_select(); + + if(HAL_SPI_Receive(&hspiDisplay, &byte, 1, 10000) != HAL_OK) + Error_Handler_extflash(); + + while (HAL_SPI_GetState(&hspiDisplay) != HAL_SPI_STATE_READY) + { + } + if(unselect_CS_afterwards) + chip_unselect(); + + return byte; +} + + +void write_spi(uint8_t data, uint8_t unselect_CS_afterwards) +{ + chip_select(); + + if(HAL_SPI_Transmit(&hspiDisplay, &data, 1, 10000) != HAL_OK) + Error_Handler_extflash(); + + while (HAL_SPI_GetState(&hspiDisplay) != HAL_SPI_STATE_READY) + { + } + if(unselect_CS_afterwards) + chip_unselect(); +} + + +void write_address(uint8_t unselect_CS_afterwards) +{ + uint8_t hi, med ,lo; + + hi = (actualAddress >> 16) & 0xFF; + med = (actualAddress >> 8) & 0xFF; + lo = actualAddress & 0xFF; + + write_spi(hi, HOLDCS); + write_spi(med, HOLDCS); + write_spi(lo, unselect_CS_afterwards); +} + + +static void wait_chip_not_busy(void) +{ + uint8_t status; + + chip_unselect(); + + write_spi(0x05,HOLDCS); /* RDSR */ + status = read_spi(HOLDCS);/* read status */ + while(status & 0x01) + { + HAL_Delay(1); + status = read_spi(HOLDCS);/* read status */ + } + chip_unselect(); +} + + +void ext_flash_incf_address(uint8_t type) +{ + uint32_t ringStart, ringStop; + + actualAddress += 1; + + switch(type) + { + case EF_HEADER: + ringStart = HEADERSTART; + ringStop = HEADERSTOP; + break; + case EF_SAMPLE: + ringStart = SAMPLESTART; + ringStop = SAMPLESTOP; + break; + case EF_DEVICEDATA: + ringStart = DDSTART; + ringStop = DDSTOP; + break; + case EF_VPMDATA: + ringStart = VPMSTART; + ringStop = VPMSTOP; + break; + case EF_SETTINGS: + ringStart = SETTINGSSTART; + ringStop = SETTINGSSTOP; + break; + case EF_FIRMWARE: + ringStart = FWSTART; + ringStop = FWSTOP; + break; + case EF_FIRMWARE2: + ringStart = FWSTART2; + ringStop = FWSTOP2; + break; + default: + ringStart = FLASHSTART; + ringStop = FLASHSTOP; + break; + } + + if((actualAddress < ringStart) || (actualAddress > ringStop)) + actualAddress = ringStart; +} + + +void ext_flash_decf_address_ring(uint8_t type) +{ + uint32_t ringStart, ringStop; + + switch(type) + { + case EF_HEADER: + ringStart = HEADERSTART; + ringStop = HEADERSTOP; + break; + case EF_SAMPLE: + ringStart = SAMPLESTART; + ringStop = SAMPLESTOP; + break; + case EF_DEVICEDATA: + ringStart = DDSTART; + ringStop = DDSTOP; + break; + case EF_VPMDATA: + ringStart = VPMSTART; + ringStop = VPMSTOP; + break; + case EF_SETTINGS: + ringStart = SETTINGSSTART; + ringStop = SETTINGSSTOP; + break; + case EF_FIRMWARE: + ringStart = FWSTART; + ringStop = FWSTOP; + break; + case EF_FIRMWARE2: + ringStart = FWSTART2; + ringStop = FWSTOP2; + break; + default: + ringStart = FLASHSTART; + ringStop = FLASHSTOP; + break; + } + + if((actualAddress <= ringStart) || (actualAddress > ringStop)) + actualAddress = ringStop; + else + actualAddress -= 1; +} + + +static void ef_hw_rough_delay_us(uint32_t delayUs) +{ + if(!delayUs) + return; + delayUs*= 12; + while(delayUs--); + return; +} + +static void Error_Handler_extflash(void) +{ + while(1) + { + } +} + +uint8_t ext_flash_erase_firmware_if_not_empty(void) +{ + const uint8_t TESTSIZE_FW = 4; + + uint8_t data[TESTSIZE_FW]; + uint8_t notEmpty = 0; + + actualAddress = FWSTART; + ext_flash_read_block_start(); + for(int i = 0; i < TESTSIZE_FW; i++) + { + ext_flash_read_block(&data[i], EF_FIRMWARE); + if(data[i] != 0xFF) + notEmpty = 1; + } + ext_flash_read_block_stop(); + + if(notEmpty) + { + ext_flash_erase_firmware(); + return 1; + } + else + return 0; +} + +uint8_t ext_flash_erase_firmware2_if_not_empty(void) +{ + const uint8_t TESTSIZE_FW = 4; + + uint8_t data[TESTSIZE_FW]; + uint8_t notEmpty = 0; + + actualAddress = FWSTART2; + ext_flash_read_block_start(); + for(int i = 0; i < TESTSIZE_FW; i++) + { + ext_flash_read_block(&data[i], EF_FIRMWARE2); + if(data[i] != 0xFF) + notEmpty = 1; + } + ext_flash_read_block_stop(); + + if(notEmpty) + { + ext_flash_erase_firmware2(); + return 1; + } + else + return 0; +}