Moderation: Please use Code quotes
C-like:
#include <string.h> //for memset
#include "W25Qxx.h"
//#include "safe_string.h"
#include "ext_flash.h"
#include "w25qxxConfig.h"
#include <stdio.h> // For printf
#include <stdbool.h> // For bool_t replacement
#include "FreeRTOS.h" // For pvPortMalloc/vPortFree
#include "task.h" // For configASSERT
/*#include "crc32.h"
#include "internal_eeprom.h"*/
static uint32_t _write_to_single_sector(uint8_t * log_line, uint16_t length_including_meta, uint32_t next_write_addr, bool_t is_first, uint8_t log_meta);
static uint32_t _write_to_multiple_sectors(uint8_t * log_line, uint16_t length, uint32_t next_write_addr, bool_t from_beginning, uint8_t log_meta);
static uint32_t _find_next_valid_read_start_addr(uint32_t current_write_addr);
static void _turn_on_flash();
static void _turn_off_flash();
static void _read_bytes_from_ext_flash(uint8_t * buff, uint16_t max_buff_len, uint32_t addr, uint16_t length);
bool_t init_ext_flash (){
bool_t res = FALSE;
//_turn_on_flash();
res = (W25qxx_Init() == true) ? TRUE : FALSE;
//_turn_off_flash();
return res;
}
void erase_ext_flash(){
//TODO uncomment it after changing the conf storage to flash;
W25qxx_EraseChip();
//_handle_factory_reset();
//_save_settings_file();
}
void save_fw_chunk_addr_to_storage(uint16_t bit_number, uint16_t data_start, uint32_t new_offset) {
//if (unlock_flash(TRUE)){
__set_offset_in_external_storage(bit_number, FALSE);
__save_32bit_cfg_data_to_external_storage(data_start, new_offset, TRUE, FALSE);
_save_config_to_external_flash();
//lock_flash(TRUE);
//}
}
bool_t save_chunk_to_storage(uint8_t * rx_buff, uint16_t data_length, uint16_t bit_number, uint16_t data_start, uint32_t update_location, uint32_t data_offset, uint8_t type, bool_t need_checking){
//type = 0 store the fw chunk
// 1 store the log chunk
// 2 update the history read address
// 3 update the history read address before history logs are overflows
bool_t res = TRUE;
//_turn_on_flash();
uint32_t next_write_addr;
if(type == 0){
next_write_addr = update_location + data_offset + MAX_FIRMWARE_SIZE_BYTES_LENGTH;
}else if(type == 1){
next_write_addr = __get_32bit_cfg_data_from_storage(NXT_LOG_WRITE_ADDR, TRUE) + data_offset;
if(rx_buff[2] != '$' && rx_buff[3] != ',' && need_checking == TRUE){
DEVELOPER_PRINT("=================Log doesnt have $ and , so not storing...\n");
DEVELOPER_PRINT("--> %s\n",rx_buff+2);
return res;
}
}else if(type == 2){
next_write_addr = __get_32bit_cfg_data_from_storage(NXT_LOG_WRITE_ADDR, TRUE) + data_offset;
next_write_addr = next_write_addr -12; //to read the log addrs of next oldest log.
}else{
next_write_addr = MAX_LOG_WRITABLE_LOCATION - 12;
}
//DEVELOPER_PRINT("Log to be saved at: %ld with length: %ld\n",next_write_addr,data_length);
uint16_t write_sector = next_write_addr / TOTAL_SECTORS;
uint16_t write_sector_byte_offset = (next_write_addr % SECTOR_SIZE);
uint8_t * sector_buff = (uint8_t *) pvPortMalloc(SECTOR_SIZE);
if (sector_buff != NULL){
uint16_t i;
W25qxx_ReadSector(sector_buff, write_sector, 0, SECTOR_SIZE);
for (i = 0; i < data_length; i++) {
if (write_sector_byte_offset + i < SECTOR_SIZE){
sector_buff[write_sector_byte_offset + i] = rx_buff;
} else {
break;
}
}
W25qxx_EraseSector(write_sector);
uint8_t try_count =0;
bool_t is_successful = TRUE;
while(TRUE){
is_successful = FALSE;
if(is_successful == TRUE){
break;
}else{
try_count++;
if(try_count == 2){
break;
}
}
W25qxx_WriteSector(sector_buff, write_sector, 0, SECTOR_SIZE);
/* Verifying the data in the sector */
W25qxx_ReadSector(sector_buff, write_sector, 0, SECTOR_SIZE);
for (uint16_t j = 0; j < i; j++){
if (sector_buff[write_sector_byte_offset + j] != rx_buff[j]){
res = FALSE;
is_successful = FALSE;
DEVELOPER_PRINT("Flash saving failed-----------------\n");
break;
}
}
}
vPortFree(sector_buff);
if (res == TRUE){
if (i < data_length){
res = save_chunk_to_storage(rx_buff + i, data_length - i, bit_number, data_start, update_location, data_offset + i, type, FALSE);
} else {
if(type == 0){
save_fw_chunk_addr_to_storage(bit_number, data_start, data_offset + data_length);
}else if(type == 1){
__save_32bit_cfg_data_to_external_storage(NXT_LOG_WRITE_ADDR, next_write_addr + data_length, FALSE, FALSE);
//USER_PRINT("----------> Next Log storage address after %d\n--------------------->\n",__get_32bit_cfg_data_from_storage(NXT_LOG_WRITE_ADDR, TRUE));
//DEVELOPER_PRINT("------Will store the external_flash config... Comment this as it will happen every 10 mins.");
//_save_config_to_external_flash(); //will be stored every 10 min
}
}
}
}
//_turn_off_flash();
return res;
}
bool_t is_factory_default_firmware_present() {
uint8_t data;
_read_bytes_from_ext_flash(&data, 1, FIRMWARE_FACTORY_START_ADDR, 1);
return (data == FACTORY_DEFAULT_FW_INSTALLED_FLAG) ? TRUE : FALSE;
}
bool_t set_factory_default_firmware_present_value() {
//_turn_on_flash();
uint16_t write_sector = FIRMWARE_FACTORY_START_ADDR / TOTAL_SECTORS;
uint16_t write_sector_byte_offset = (FIRMWARE_FACTORY_START_ADDR % SECTOR_SIZE);
uint8_t * sector_buff = (uint8_t *) pvPortMalloc(SECTOR_SIZE);
if (sector_buff != NULL){
W25qxx_ReadSector(sector_buff, write_sector, 0, SECTOR_SIZE);
sector_buff[write_sector_byte_offset] = FACTORY_DEFAULT_FW_INSTALLED_FLAG;
W25qxx_EraseSector(write_sector);
W25qxx_WriteSector(sector_buff, write_sector, 0, SECTOR_SIZE);
vPortFree(sector_buff);
}
//_turn_off_flash();
return is_factory_default_firmware_present();
}
bool_t erase_ext_flash_sector(uint32_t address) {
uint16_t erase_sector_num = address / TOTAL_SECTORS;
//_turn_on_flash();
W25qxx_EraseSector(erase_sector_num);
//_turn_off_flash();
return TRUE;
}
void read_update_data(uint8_t * buff, uint16_t max_len, uint32_t addr) {
//_turn_on_flash();
int32_t tmp_length = (max_len > SECTOR_SIZE) ? SECTOR_SIZE : max_len;
int32_t bytes_cnt = 0;
while (bytes_cnt < max_len){
_read_bytes_from_ext_flash(buff + bytes_cnt, max_len - bytes_cnt, addr + bytes_cnt, tmp_length);
bytes_cnt += tmp_length;
if (bytes_cnt + SECTOR_SIZE > max_len){
tmp_length = max_len - bytes_cnt;
} else {
tmp_length = SECTOR_SIZE;
}
}
//_turn_off_flash();
}
void save_configuration_to_storage(uint8_t * conf_buffer, uint16_t bytes_to_write,uint16_t sector_address)
{
W25qxx_EraseSector(sector_address);
W25qxx_WriteSector(conf_buffer,sector_address,0,bytes_to_write);
#ifdef BOOTLOADERPROJECT
uint8_t sector_buff[2048];
#else
uint8_t * sector_buff = (uint8_t *) pvPortMalloc(bytes_to_write);
#endif
if (sector_buff != NULL){
bool_t res = FALSE;
W25qxx_ReadSector(sector_buff, sector_address, 0, bytes_to_write);
for (uint16_t j = 0; j < bytes_to_write-1; j++){
if (sector_buff[j] != conf_buffer[j]){
res = TRUE;
break;
}
}
if(res == TRUE){
DEVELOPER_PRINT("Flash Data mismatch, rewriting the same data...\n");
W25qxx_EraseSector(sector_address);
W25qxx_WriteSector(conf_buffer,sector_address,0,bytes_to_write);
}else{
//DEVELOPER_PRINT("Data written to flash successfully...\n");
}
// vPortFree(sector_buff);
#ifndef BOOTLOADERPROJECT
vPortFree(sector_buff);
#endif
}
}
void read_configuration_from_storage(uint8_t * conf_buffer, uint16_t bytes_to_read, uint16_t sector_address){
W25qxx_ReadSector(conf_buffer,sector_address,0,bytes_to_read);
}
static void _turn_on_flash(){
//HAL_GPIO_WritePin(Flash_Ctrl_GPIO_Port, Flash_Ctrl_Pin, GPIO_PIN_SET);
}
static void _turn_off_flash(){
//HAL_GPIO_WritePin(Flash_Ctrl_GPIO_Port, Flash_Ctrl_Pin, GPIO_PIN_RESET);
}
static uint32_t _write_to_multiple_sectors(uint8_t * log_line, uint16_t log_length, uint32_t next_write_addr, bool_t from_beginning, uint8_t log_meta) {
/* Multi sector write */
uint32_t free_in_last_sector;
uint32_t additional_sectors_needed;
uint16_t remaining_data_length;
uint16_t last_wrote_length = 0;
free_in_last_sector = (SECTOR_SIZE - (next_write_addr % SECTOR_SIZE));
if (free_in_last_sector > log_length + ((from_beginning == TRUE) ? 2 : 0)){
free_in_last_sector = log_length + ((from_beginning == TRUE) ? 2 : 0);
}
if (free_in_last_sector > 2){
next_write_addr = _write_to_single_sector(log_line, free_in_last_sector, next_write_addr, from_beginning, log_meta);
last_wrote_length = free_in_last_sector - ((from_beginning == TRUE) ? 2 : 0);
if (free_in_last_sector == log_length + ((from_beginning == TRUE) ? 2 : 0)){
log_length = 0;
} else {
log_length -= (free_in_last_sector - ((from_beginning == TRUE) ? 2 : 0));
}
from_beginning = FALSE;
} else if (free_in_last_sector == 2) {
next_write_addr = _write_to_single_sector(log_line, 2, next_write_addr, from_beginning, log_meta);
from_beginning = FALSE;
}
additional_sectors_needed = log_length / SECTOR_SIZE;
remaining_data_length = log_length % SECTOR_SIZE;
for (uint8_t i = 0; i < additional_sectors_needed; i++) {
uint16_t tmp_length = 0;
if (log_length > SECTOR_SIZE){
tmp_length = log_length - SECTOR_SIZE;
} else {
tmp_length = SECTOR_SIZE - log_length;
if (tmp_length > log_length){
tmp_length = log_length;
}
}
next_write_addr = _write_to_single_sector(log_line + last_wrote_length, tmp_length, next_write_addr, ((i == 0) ? from_beginning : FALSE), log_meta);
last_wrote_length += tmp_length;
log_length -= tmp_length;
from_beginning = FALSE;
}
if (remaining_data_length > 0){
next_write_addr = _write_to_single_sector(log_line + last_wrote_length, remaining_data_length, next_write_addr, from_beginning, log_meta);
}
return next_write_addr;
}
void test_read_flash(){
uint8_t * sector_buff = (uint8_t *) pvPortMalloc(SECTOR_SIZE);
if (sector_buff != NULL){
//W25qxx_EraseSector(0);
memset(sector_buff, 0, SECTOR_SIZE);
printf("sector_buff before: %lx\n",sector_buff);
memset(sector_buff, 0, SECTOR_SIZE);
W25qxx_ReadSector(sector_buff, 0, 0, SECTOR_SIZE);
printf("sector_buff after: %lx\n",sector_buff);
vPortFree(sector_buff);
}
}
static uint32_t _write_to_single_sector(uint8_t * log_line, uint16_t length_including_meta, uint32_t next_write_addr, bool_t is_first, uint8_t log_meta){
//_turn_on_flash();
uint8_t * sector_buff = (uint8_t *) pvPortMalloc(SECTOR_SIZE);
if (sector_buff != NULL){
uint16_t write_sector = next_write_addr / TOTAL_SECTORS;
uint16_t write_sector_byte_offset = (next_write_addr % SECTOR_SIZE);
uint8_t write_start_idx;
uint16_t i = 0;
memset(sector_buff, 0, SECTOR_SIZE);
W25qxx_ReadSector(sector_buff, write_sector, 0, SECTOR_SIZE);
//printf("sector_buff after: %lx\n",sector_buff);
//printf("Data already in sector: %s\n",(char *) sector_buff);
if (is_first == TRUE){
sector_buff[write_sector_byte_offset] = START_OF_TEXT;
sector_buff[write_sector_byte_offset + 1] = log_meta;
write_start_idx = LOG_META_BYTES_LENGTH;
} else {
write_start_idx = 0;
}
for (i = write_start_idx; i < length_including_meta; i++) {
sector_buff[write_sector_byte_offset + i] = log_line[i - write_start_idx];
}
//printf("Data appended to sector before: %s\n",(char *) sector_buff);
next_write_addr += i;
W25qxx_EraseSector(write_sector);
W25qxx_WriteSector(sector_buff, write_sector, 0, SECTOR_SIZE);
//printf("Data appended to sector after: %s\n",(char *) sector_buff);
vPortFree(sector_buff);
if (next_write_addr > MAX_LOG_WRITABLE_LOCATION){
next_write_addr = 0;
}
}
//_turn_off_flash();
return next_write_addr;
}
static uint32_t _find_next_valid_read_start_addr(uint32_t current_write_addr){
//_turn_on_flash();
uint8_t * buff = (uint8_t *) pvPortMalloc(SPI_MAX_WRITE_PER_CALL);
uint32_t new_read_addr = -1;
if (buff != NULL){
uint32_t read_bytes = 0;
while (read_bytes < TOTAL_BYTES && new_read_addr == -1) {
uint16_t temp_read_len = SPI_MAX_WRITE_PER_CALL;
if (current_write_addr + SPI_MAX_WRITE_PER_CALL > MAX_LOG_WRITABLE_LOCATION) {
temp_read_len = (current_write_addr + SPI_MAX_WRITE_PER_CALL) - MAX_LOG_WRITABLE_LOCATION;
}
_read_bytes_from_ext_flash(buff, SPI_MAX_WRITE_PER_CALL, current_write_addr, temp_read_len);
for (uint16_t i = 0; i < SPI_MAX_WRITE_PER_CALL; i++){
if (buff == START_OF_TEXT){
new_read_addr = current_write_addr + i;
break;
}
}
read_bytes += temp_read_len;
current_write_addr += SPI_MAX_WRITE_PER_CALL;
if (current_write_addr > MAX_LOG_WRITABLE_LOCATION){
current_write_addr = 0;
}
}
if (new_read_addr == -1){
new_read_addr = 0;
}
vPortFree(buff);
}
//_turn_off_flash();
return new_read_addr;
}
static void _read_bytes_from_ext_flash(uint8_t * buff, uint16_t max_buff_len, uint32_t addr, uint16_t length) {
HAL_Delay(100);
uint16_t read_sector = addr / TOTAL_SECTORS;
uint16_t read_sector_byte_offset = (addr % SECTOR_SIZE);
configASSERT((length <= SECTOR_SIZE) && (length <= max_buff_len));
if((read_sector_byte_offset + length) > SECTOR_SIZE) {
uint16_t tmp_length = SECTOR_SIZE - read_sector_byte_offset;
if (tmp_length > max_buff_len){
tmp_length = max_buff_len;
}
printf("reading 1\n");
W25qxx_ReadSector(buff, read_sector, read_sector_byte_offset, tmp_length);
length -= tmp_length;
configASSERT((tmp_length + length) <= max_buff_len);
W25qxx_ReadSector(buff + tmp_length, read_sector + 1, 0, length);
} else {
printf("reading 2\n");
W25qxx_ReadSector(buff, read_sector, read_sector_byte_offset, length);
}
printf("the flash data : %s \n",buff);
}
uint32_t flashWriteData(uint8_t *pBuffer, uint32_t writeAddress, uint32_t noOfBytes) {
//W25qxx_WriteSector(pBuffer);
uint32_t noOfBytesWrittenSoFar = 0;
uint32_t tmpnoOfBytes = noOfBytes;
//printf("write buff %s\n",pBuffer);
while (noOfBytesWrittenSoFar < noOfBytes) {
uint32_t write_sector = writeAddress / TOTAL_SECTORS;
uint32_t write_offset = writeAddress % SECTOR_SIZE;
uint32_t noOfBytesToWrite;
if ((write_offset + tmpnoOfBytes) > SECTOR_SIZE) {
noOfBytesToWrite = SECTOR_SIZE - write_offset;
} else {
noOfBytesToWrite = tmpnoOfBytes;
}
/*HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_SET);
HAL_Delay(500);*/
/*printf("--------Writing------\n");
printf("%d\n",write_sector);
printf("%d\n",write_offset);
printf("%d\n",noOfBytesToWrite);
printf("------Wrote--------\n");*/
W25qxx_WriteSector(pBuffer + noOfBytesWrittenSoFar ,write_sector,write_offset,noOfBytesToWrite);
/*HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_RESET);
HAL_Delay(500);*/
noOfBytesWrittenSoFar += noOfBytesToWrite;
writeAddress += noOfBytesToWrite;
tmpnoOfBytes -= noOfBytesToWrite;
//break;
}
return 0;
}
uint32_t storeLog(uint8_t *TxData, uint32_t currentLogStorageAddress)
{
char buffer[45];
memcpy(buffer, TxData, 45);
//sprintf(buffer, "%s", TxData);
printf("FLASH write DATA: %s\n",buffer);
flashWriteData((uint8_t*)buffer, currentLogStorageAddress, 45);
// Update the current log storage address
char read_buffer[45];
test_read_flash();
printf("FLASH READ DATA: %s\n",read_buffer);
currentLogStorageAddress += 45;
return currentLogStorageAddress;
}
Last edited by a moderator:
