/**************************************************************************************** | Description: bootloader file system interface source file | File Name: file.c | |---------------------------------------------------------------------------------------- | C O P Y R I G H T |---------------------------------------------------------------------------------------- | Copyright (c) 2013 by Feaser http://www.feaser.com All rights reserved | |---------------------------------------------------------------------------------------- | L I C E N S E |---------------------------------------------------------------------------------------- | This file is part of OpenBLT. OpenBLT 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. | | OpenBLT 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 OpenBLT. | If not, see . | | A special exception to the GPL is included to allow you to distribute a combined work | that includes OpenBLT without being obliged to provide the source code for any | proprietary components. The exception text is included at the bottom of the license | file . | ****************************************************************************************/ /**************************************************************************************** * Include files ****************************************************************************************/ #include "boot.h" /* bootloader generic header */ #include /* for strcpy etc. */ #include /* for toupper() etc. */ #if (BOOT_FILE_SYS_ENABLE > 0) /**************************************************************************************** * Defines ****************************************************************************************/ /* array size configurators */ #define MAX_CHARS_PER_LINE (256) #define MAX_DATA_BYTES_PER_LINE (MAX_CHARS_PER_LINE/2) /* error codes */ #define ERROR_SREC_INVALID_CHECKSUM (-1) /**************************************************************************************** * Type definitions ****************************************************************************************/ typedef enum { FIRMWARE_UPDATE_STATE_IDLE, /* idle state */ FIRMWARE_UPDATE_STATE_ERASING, /* erasing state */ FIRMWARE_UPDATE_STATE_PROGRAMMING /* programming state */ } tFirmwareUpdateState; /* state identifier type */ typedef enum { LINE_TYPE_S1, /* 16-bit address line */ LINE_TYPE_S2, /* 24-bit address line */ LINE_TYPE_S3, /* 32-bit address line */ LINE_TYPE_UNSUPPORTED /* unsupported line */ } tSrecLineType; /* S-Record line type */ typedef struct { blt_addr start_address; /* erase start address */ blt_int32u total_size; /* total number of bytes to erase */ } tFileEraseInfo; /* erase info structure */ typedef struct { FATFS fs; /* file system object for mouting */ FIL file; /* file object for firmware file */ } tFatFsObjects; /* grouped FATFS objects */ typedef struct { blt_char line[MAX_CHARS_PER_LINE]; /* string buffer for the line chars */ blt_int8u data[MAX_DATA_BYTES_PER_LINE]; /* array for S1, S2 or S3 data bytes */ blt_addr address; /* address found on S1, S2 or S3 line */ } tSrecLineParseObject; /**************************************************************************************** * Function prototypes ****************************************************************************************/ static tSrecLineType SrecGetLineType(const blt_char *line); static blt_bool SrecVerifyChecksum(const blt_char *line); static blt_int16s SrecParseLine(const blt_char *line, blt_addr *address, blt_int8u *data); #if (BOOT_FILE_LOGGING_ENABLE > 0) static blt_char FileLibByteNibbleToChar(blt_int8u nibble); static blt_char *FileLibByteToHexString(blt_int8u byte_val, blt_char *destination); static blt_char *FileLibLongToIntString(blt_int32u long_val, blt_char *destination); #endif static blt_int8u FileLibHexStringToByte(const blt_char *hexstring); /**************************************************************************************** * Hook functions ****************************************************************************************/ extern blt_bool FileIsFirmwareUpdateRequestedHook(void); extern const blt_char *FileGetFirmwareFilenameHook(void); extern void FileFirmwareUpdateStartedHook(void); extern void FileFirmwareUpdateCompletedHook(void); extern void FileFirmwareUpdateErrorHook(blt_int8u error_code); extern void FileFirmwareUpdateLogHook(blt_char *info_string); /**************************************************************************************** * Local data declarations ****************************************************************************************/ static tFirmwareUpdateState firmwareUpdateState; static tFatFsObjects fatFsObjects; static tSrecLineParseObject lineParseObject; static tFileEraseInfo eraseInfo; #if (BOOT_FILE_LOGGING_ENABLE > 0) static blt_char loggingStr[64]; #endif /**************************************************************************************** ** NAME: FileInit ** PARAMETER: none ** RETURN VALUE: none ** DESCRIPTION: Initializes the file system interface module. The initial firmware ** update state is set to idle and the file system is mounted as ** logical disk 0. ** ****************************************************************************************/ void FileInit(void) { FRESULT fresult; /* set the initial state */ firmwareUpdateState = FIRMWARE_UPDATE_STATE_IDLE; /* mount the file system, using logical disk 0 */ fresult = f_mount(0, &fatFsObjects.fs); /* mounting does not access the disk and should succeed unless misconfigured */ ASSERT_RT(fresult == FR_OK); } /*** end of FileInit ***/ /**************************************************************************************** ** NAME: FileIsIdle ** PARAMETER: none ** RETURN VALUE: BLT_TRUE when in idle state, BLT_FALSE otherwise. ** DESCRIPTION: This function checks if a firmware update through the locally attached ** storage is in progress or not (idle). ** ****************************************************************************************/ blt_bool FileIsIdle(void) { if (firmwareUpdateState == FIRMWARE_UPDATE_STATE_IDLE) { return BLT_TRUE; } return BLT_FALSE; } /*** end of FileIsIdle ***/ /**************************************************************************************** ** NAME: FileTask ** PARAMETER: none ** RETURN VALUE: none ** DESCRIPTION: File system task function for managing the firmware updates from ** locally attached storage. ** ****************************************************************************************/ void FileTask(void) { blt_int16s parse_result; blt_char *read_line_ptr; /* ------------------------------- idle -------------------------------------------- */ if (firmwareUpdateState == FIRMWARE_UPDATE_STATE_IDLE) { #if (BOOT_COM_ENABLE > 0) /* make sure that there is no connection with a remote host to prevent two firmware * updates happening at the same time */ if (ComIsConnected() == BLT_TRUE) { return; } #endif /* check if a firmware update is requested */ if (FileIsFirmwareUpdateRequestedHook() == BLT_TRUE) { #if (BOOT_FILE_STARTED_HOOK_ENABLE > 0) /* inform application about update started event via hook function */ FileFirmwareUpdateStartedHook(); #endif #if (BOOT_FILE_LOGGING_ENABLE > 0) FileFirmwareUpdateLogHook("Firmware update request detected\n\r"); FileFirmwareUpdateLogHook("Opening firmware file for reading..."); #endif /* attempt to obtain a file object for the firmware file */ if (f_open(&fatFsObjects.file, FileGetFirmwareFilenameHook(), FA_OPEN_EXISTING | FA_READ) != FR_OK) { /* can't open file */ #if (BOOT_FILE_LOGGING_ENABLE > 0) FileFirmwareUpdateLogHook("ERROR\n\r"); #endif #if (BOOT_FILE_ERROR_HOOK_ENABLE > 0) FileFirmwareUpdateErrorHook(FILE_ERROR_CANNOT_OPEN_FIRMWARE_FILE); #endif /* nothing left to do now */ return; } #if (BOOT_FILE_LOGGING_ENABLE > 0) FileFirmwareUpdateLogHook("OK\n\r"); FileFirmwareUpdateLogHook("Starting the programming sequence\n\r"); FileFirmwareUpdateLogHook("Parsing firmware file to obtain erase size..."); #endif /* prepare data objects for the erasing state */ eraseInfo.start_address = 0; eraseInfo.total_size = 0; /* transition from idle to erasing state */ firmwareUpdateState = FIRMWARE_UPDATE_STATE_ERASING; } } /* ------------------------------- erasing ----------------------------------------- */ else if (firmwareUpdateState == FIRMWARE_UPDATE_STATE_ERASING) { /* read a line from the file */ read_line_ptr = f_gets(lineParseObject.line, sizeof(lineParseObject.line), &fatFsObjects.file); /* check if an error occurred */ if (f_error(&fatFsObjects.file) > 0) { #if (BOOT_FILE_LOGGING_ENABLE > 0) FileFirmwareUpdateLogHook("ERROR\n\r"); #endif #if (BOOT_FILE_ERROR_HOOK_ENABLE > 0) FileFirmwareUpdateErrorHook(FILE_ERROR_CANNOT_READ_FROM_FILE); #endif /* close the file */ f_close(&fatFsObjects.file); /* cannot continue with firmware update so go back to idle state */ firmwareUpdateState = FIRMWARE_UPDATE_STATE_IDLE; return; } /* parse the S-Record line without copying the data values if the line is not empty */ if (read_line_ptr != BLT_NULL) { parse_result = SrecParseLine(lineParseObject.line, &lineParseObject.address, BLT_NULL); /* check parsing result */ if (parse_result == ERROR_SREC_INVALID_CHECKSUM) { #if (BOOT_FILE_LOGGING_ENABLE > 0) FileFirmwareUpdateLogHook("ERROR\n\r"); #endif #if (BOOT_FILE_ERROR_HOOK_ENABLE > 0) FileFirmwareUpdateErrorHook(FILE_ERROR_INVALID_CHECKSUM_IN_FILE); #endif /* close the file */ f_close(&fatFsObjects.file); /* cannot continue with firmware update so go back to idle state */ firmwareUpdateState = FIRMWARE_UPDATE_STATE_IDLE; return; } } /* only process parsing results if the line contained address/data info */ if (parse_result > 0) { /* is this the first address/data info we encountered? */ if (eraseInfo.total_size == 0) { /* store the start_address and byte count */ eraseInfo.start_address = lineParseObject.address; eraseInfo.total_size = parse_result; } else { /* update the start_address and byte count */ if (lineParseObject.address < eraseInfo.start_address) { eraseInfo.start_address = lineParseObject.address; } eraseInfo.total_size += parse_result; } } /* check if the end of the file was reached */ if (f_eof(&fatFsObjects.file) > 0) { /* rewind the file in preparation for the programming state */ if (f_lseek(&fatFsObjects.file, 0) != FR_OK) { #if (BOOT_FILE_LOGGING_ENABLE > 0) FileFirmwareUpdateLogHook("ERROR\n\r"); #endif #if (BOOT_FILE_ERROR_HOOK_ENABLE > 0) FileFirmwareUpdateErrorHook(FILE_ERROR_REWINDING_FILE_READ_POINTER); #endif /* close the file */ f_close(&fatFsObjects.file); /* cannot continue with firmware update so go back to idle state */ firmwareUpdateState = FIRMWARE_UPDATE_STATE_IDLE; return; } #if (BOOT_FILE_LOGGING_ENABLE > 0) FileFirmwareUpdateLogHook("OK\n\r"); FileFirmwareUpdateLogHook("Erasing "); /* convert size to string */ FileLibLongToIntString(eraseInfo.total_size, loggingStr); FileFirmwareUpdateLogHook(loggingStr); FileFirmwareUpdateLogHook(" bytes from memory at 0x"); /* convert address to hex-string */ FileLibByteToHexString((blt_int8u)(eraseInfo.start_address >> 24), &loggingStr[0]); FileLibByteToHexString((blt_int8u)(eraseInfo.start_address >> 16), &loggingStr[2]); FileLibByteToHexString((blt_int8u)(eraseInfo.start_address >> 8), &loggingStr[4]); FileLibByteToHexString((blt_int8u)eraseInfo.start_address, &loggingStr[6]); FileFirmwareUpdateLogHook(loggingStr); FileFirmwareUpdateLogHook("..."); #endif /* still here so we are ready to perform the memory erase operation */ if (NvmErase(eraseInfo.start_address, eraseInfo.total_size) == BLT_FALSE) { #if (BOOT_FILE_LOGGING_ENABLE > 0) FileFirmwareUpdateLogHook("ERROR\n\r"); #endif #if (BOOT_FILE_ERROR_HOOK_ENABLE > 0) FileFirmwareUpdateErrorHook(FILE_ERROR_CANNOT_ERASE_MEMORY); #endif /* close the file */ f_close(&fatFsObjects.file); /* cannot continue with firmware update so go back to idle state */ firmwareUpdateState = FIRMWARE_UPDATE_STATE_IDLE; return; } #if (BOOT_FILE_LOGGING_ENABLE > 0) FileFirmwareUpdateLogHook("OK\n\r"); #endif /* all okay, then go to programming state */ firmwareUpdateState = FIRMWARE_UPDATE_STATE_PROGRAMMING; } } /* ------------------------------- programming ------------------------------------- */ else if (firmwareUpdateState == FIRMWARE_UPDATE_STATE_PROGRAMMING) { /* read a line from the file */ read_line_ptr = f_gets(lineParseObject.line, sizeof(lineParseObject.line), &fatFsObjects.file); /* check if an error occurred */ if (f_error(&fatFsObjects.file) > 0) { #if (BOOT_FILE_LOGGING_ENABLE > 0) FileFirmwareUpdateLogHook("Reading line from file...ERROR\n\r"); #endif #if (BOOT_FILE_ERROR_HOOK_ENABLE > 0) FileFirmwareUpdateErrorHook(FILE_ERROR_CANNOT_READ_FROM_FILE); #endif /* close the file */ f_close(&fatFsObjects.file); /* cannot continue with firmware update so go back to idle state */ firmwareUpdateState = FIRMWARE_UPDATE_STATE_IDLE; return; } /* parse the S-Record line if the line is not empty */ if (read_line_ptr != BLT_NULL) { parse_result = SrecParseLine(lineParseObject.line, &lineParseObject.address, lineParseObject.data); /* check parsing result */ if (parse_result == ERROR_SREC_INVALID_CHECKSUM) { #if (BOOT_FILE_LOGGING_ENABLE > 0) FileFirmwareUpdateLogHook("Invalid checksum found...ERROR\n\r"); #endif #if (BOOT_FILE_ERROR_HOOK_ENABLE > 0) FileFirmwareUpdateErrorHook(FILE_ERROR_INVALID_CHECKSUM_IN_FILE); #endif /* close the file */ f_close(&fatFsObjects.file); /* cannot continue with firmware update so go back to idle state */ firmwareUpdateState = FIRMWARE_UPDATE_STATE_IDLE; return; } } /* only process parsing results if the line contained address/data info */ if (parse_result > 0) { #if (BOOT_FILE_LOGGING_ENABLE > 0) FileFirmwareUpdateLogHook("Programming "); /* convert size to string */ FileLibLongToIntString(parse_result, loggingStr); FileFirmwareUpdateLogHook(loggingStr); FileFirmwareUpdateLogHook(" bytes to memory at 0x"); /* convert address to hex-string */ FileLibByteToHexString((blt_int8u)(lineParseObject.address >> 24), &loggingStr[0]); FileLibByteToHexString((blt_int8u)(lineParseObject.address >> 16), &loggingStr[2]); FileLibByteToHexString((blt_int8u)(lineParseObject.address >> 8), &loggingStr[4]); FileLibByteToHexString((blt_int8u)lineParseObject.address, &loggingStr[6]); FileFirmwareUpdateLogHook(loggingStr); FileFirmwareUpdateLogHook("..."); #endif /* program the data */ if (NvmWrite(lineParseObject.address, parse_result, lineParseObject.data) == BLT_FALSE) { #if (BOOT_FILE_LOGGING_ENABLE > 0) FileFirmwareUpdateLogHook("ERROR\n\r"); #endif #if (BOOT_FILE_ERROR_HOOK_ENABLE > 0) FileFirmwareUpdateErrorHook(FILE_ERROR_CANNOT_PROGRAM_MEMORY); #endif /* close the file */ f_close(&fatFsObjects.file); /* cannot continue with firmware update so go back to idle state */ firmwareUpdateState = FIRMWARE_UPDATE_STATE_IDLE; return; } #if (BOOT_FILE_LOGGING_ENABLE > 0) FileFirmwareUpdateLogHook("OK\n\r"); #endif } /* check if the end of the file was reached */ if (f_eof(&fatFsObjects.file) > 0) { #if (BOOT_FILE_LOGGING_ENABLE > 0) FileFirmwareUpdateLogHook("Writing program checksum..."); #endif /* finish the programming by writing the checksum */ if (NvmDone() == BLT_FALSE) { #if (BOOT_FILE_LOGGING_ENABLE > 0) FileFirmwareUpdateLogHook("ERROR\n\r"); #endif #if (BOOT_FILE_ERROR_HOOK_ENABLE > 0) FileFirmwareUpdateErrorHook(FILE_ERROR_CANNOT_WRITE_CHECKSUM); #endif /* close the file */ f_close(&fatFsObjects.file); /* cannot continue with firmware update so go back to idle state */ firmwareUpdateState = FIRMWARE_UPDATE_STATE_IDLE; return; } #if (BOOT_FILE_LOGGING_ENABLE > 0) FileFirmwareUpdateLogHook("OK\n\r"); FileFirmwareUpdateLogHook("Closing firmware file\n\r"); #endif /* close the file */ f_close(&fatFsObjects.file); #if (BOOT_FILE_LOGGING_ENABLE > 0) FileFirmwareUpdateLogHook("Firmware update successfully completed\n\r"); #endif /* all done so transistion back to idle mode */ firmwareUpdateState = FIRMWARE_UPDATE_STATE_IDLE; #if (BOOT_FILE_COMPLETED_HOOK_ENABLE > 0) /* inform application about update completed event via hook function */ FileFirmwareUpdateCompletedHook(); #endif /* attempt to start the user program now that programming is done. note that * a call to CpuReset() won't work correctly here, because if the same firmware * file is still on the locally attached storage, it will just restart the * firmware update again and again.. */ CpuStartUserProgram(); } } } /*** end of FileTask ***/ /**************************************************************************************** ** NAME: SrecGetLineType ** PARAMETER: line a line from the S-Record ** RETURN VALUE: the S-Record line type. ** DESCRIPTION: Inspects a line from a Motorola S-Record file to determine its type. ** ****************************************************************************************/ static tSrecLineType SrecGetLineType(const blt_char *line) { /* check if the line starts with the 'S' character, followed by a digit */ if ( (toupper(line[0]) != 'S') || (isdigit(line[1]) == 0) ) { /* not a valid S-Record line type */ return LINE_TYPE_UNSUPPORTED; } /* determine the line type */ if (line[1] == '1') { return LINE_TYPE_S1; } if (line[1] == '2') { return LINE_TYPE_S2; } if (line[1] == '3') { return LINE_TYPE_S3; } /* still here so not a supported line type found */ return LINE_TYPE_UNSUPPORTED; } /*** end of SrecGetLineType ***/ /**************************************************************************************** ** NAME: SrecVerifyChecksum ** PARAMETER: line an S1, S2 or S3 line from the S-Record ** RETURN VALUE: BLT_TRUE if the checksum is correct, BLT_FALSE otherwise. ** DESCRIPTION: Inspects an S1, S2 or S3 line from a Motorola S-Record file to ** determine if the checksum at the end is corrrect. ** ****************************************************************************************/ static blt_bool SrecVerifyChecksum(const blt_char *line) { blt_int16u bytes_on_line; blt_int8u checksum = 0; /* adjust pointer to point to byte count value */ line += 2; /* read out the number of byte values that follow on the line */ bytes_on_line = FileLibHexStringToByte(line); /* byte count is part of checksum */ checksum += bytes_on_line; /* adjust pointer to the first byte of the address */ line += 2; /* add byte values of address and data, but not the final checksum */ do { /* add the next byte value to the checksum */ checksum += FileLibHexStringToByte(line); /* update counter */ bytes_on_line--; /* point to next hex string in the line */ line += 2; } while (bytes_on_line > 1); /* the checksum is calculated by summing up the values of the byte count, address and * databytes and then taking the 1-complement of the sum's least signigicant byte */ checksum = ~checksum; /* finally verify the calculated checksum with the one at the end of the line */ if (checksum != FileLibHexStringToByte(line)) { /* checksum incorrect */ return BLT_FALSE; } /* still here so the checksum was correct */ return BLT_TRUE; } /*** end of SrecVerifyChecksum ***/ /**************************************************************************************** ** NAME: SrecParseLine ** PARAMETER: line a line from the S-Record ** address address found in the S-Record data line ** data byte array where the data bytes from the S-Record data line ** are stored. ** RETURN VALUE: the number of data bytes found on the S-record data line, 0 in case ** the line is not an S1, S2 or S3 line or ERROR_SREC_INVALID_CHECKSUM ** in case the checksum validation failed. ** DESCRIPTION: Parses a line from a Motorola S-Record file and looks for S1, S2 or S3 ** lines with data. Note that if a null pointer is passed as the data ** parameter, then no data is extracted from the line. ** ****************************************************************************************/ static blt_int16s SrecParseLine(const blt_char *line, blt_addr *address, blt_int8u *data) { tSrecLineType lineType; blt_int16s data_byte_count = 0; blt_int16u bytes_on_line; blt_int16u i; /* check pointers and not that data can be a null pointer */ ASSERT_RT((address != BLT_NULL) && (line != BLT_NULL)); /* figure out what type of line we are dealing with */ lineType = SrecGetLineType(line); /* make sure it is one that we can parse */ if (lineType == LINE_TYPE_UNSUPPORTED) { /* not a parsing error, but simply no data on this line */ return 0; } /* verify the checksum */ if (SrecVerifyChecksum(line) == BLT_FALSE) { /* error on data line encountered */ return ERROR_SREC_INVALID_CHECKSUM; } /* all good so far, now read out the address and databytes for the line */ switch (lineType) { /* ---------------------------- S1 line type ------------------------------------- */ case LINE_TYPE_S1: /* adjust pointer to point to byte count value */ line += 2; /* read out the number of byte values that follow on the line */ bytes_on_line = FileLibHexStringToByte(line); /* read out the 16-bit address */ line += 2; *address = FileLibHexStringToByte(line) << 8; line += 2; *address += FileLibHexStringToByte(line); /* adjust pointer to point to the first data byte after the address */ line += 2; /* determine how many data bytes are on the line */ data_byte_count = bytes_on_line - 3; /* -2 bytes address, -1 byte checksum */ /* read and store data bytes if requested */ if (data != BLT_NULL) { for (i=0; i 0) /**************************************************************************************** ** NAME: FileLibByteNibbleToChar ** PARAMETER: nibble 4-bit value to convert ** RETURN VALUE: The resulting byte value ** DESCRIPTION: Helper function to convert a 4-bit value to a character that repre- ** sents its value in hexadecimal format. ** Example: FileLibByteNibbleToChar(11) --> returns 'B'. ** ****************************************************************************************/ static blt_char FileLibByteNibbleToChar(blt_int8u nibble) { blt_char c; /* convert to ASCII value */ c = (nibble & 0x0f) + '0'; if (nibble > 9) { c += 7; } else { c = toupper(c); } /* return the character */ return c; } /*** end of FileLibByteNibbleToChar ***/ /**************************************************************************************** ** NAME: FileLibByteToHexString ** PARAMETER: byte_val 8-bit value to convert ** destination pointer to character buffer for storing the results. ** RETURN VALUE: The resulting string ** DESCRIPTION: Helper function to convert a byte value to a string representing the ** value in hexadecimal format. ** Example: FileLibByteToHexString(28, strBuffer) --> returns "1C". ** ****************************************************************************************/ static blt_char *FileLibByteToHexString(blt_int8u byte_val, blt_char *destination) { /* first the most significant n-bit nibble */ destination[0] = FileLibByteNibbleToChar(byte_val >> 4); /* next the least significant n-bit nibble */ destination[1] = FileLibByteNibbleToChar(byte_val & 0x0f); /* add string termination */ destination[2] = '\0'; /* return pointer to resulting string */ return destination; } /*** end of FileLibByteToHexString ***/ /**************************************************************************************** ** NAME: FileLibLongToIntString ** PARAMETER: hexstring string beginning with 2 characters that represent a hexa- ** decimal value ** RETURN VALUE: The resulting string ** DESCRIPTION: Helper function to convert a 32-bit unsigned number to a string that ** represents its decimal value. ** Example: FileLibLongToIntString(1234, strBuffer) --> returns "1234". ** ****************************************************************************************/ static blt_char *FileLibLongToIntString(blt_int32u long_val, blt_char *destination) { blt_int32u long_val_cpy = long_val; /* first determine how many digits there will be */ do { destination++; long_val_cpy /= 10; } while (long_val_cpy > 0); /* add space for the string termination and add it */ *destination = '\0'; /* now add the digits from right to left */ long_val_cpy = long_val; do { /* set write pointer to where the next character should go */ destination--; /* write digit in ASCII format */ *destination = long_val_cpy % 10 + '0'; /* move on to the next digit */ long_val_cpy /= 10; } while (long_val_cpy > 0); return destination; } /*** end of FileLibLongToIntString ***/ #endif /* (BOOT_FILE_LOGGING_ENABLE > 0) */ /**************************************************************************************** ** NAME: FileLibHexStringToByte ** PARAMETER: hexstring string beginning with 2 characters that represent a hexa- ** decimal value ** RETURN VALUE: The resulting byte value ** DESCRIPTION: Helper function to convert a sequence of 2 characters that represent ** a hexadecimal value to the actual byte value. ** Example: FileLibHexStringToByte("2f") --> returns 47. ** ****************************************************************************************/ static blt_int8u FileLibHexStringToByte(const blt_char *hexstring) { blt_int8u result = 0; blt_char c; blt_int8u counter; /* a hexadecimal character is 2 characters long (i.e 0x4F minus the 0x part) */ for (counter=0; counter < 2; counter++) { /* read out the character */ c = toupper(hexstring[counter]); /* check that the character is 0..9 or A..F */ if ( (c < '0') || (c > 'F') || ( (c > '9') && (c < 'A') ) ) { /* character not valid */ return 0; } /* convert character to 4-bit value (check ASCII table for more info) */ c -= '0'; if (c > 9) { c -= 7; } /* add it to the result */ result = (result << 4) + c; } /* return the results */ return result; } /*** end of FileLibHexStringToByte ***/ #endif /* BOOT_FILE_SYS_ENABLE > 0 */ /*********************************** end of file.c *************************************/