Statistics
| Branch: | Tag: | Revision:

amiro-blt / Target / Source / file.c @ 470d0567

History | View | Annotate | Download (32.316 KB)

1 69661903 Thomas Schöpping
/************************************************************************************//**
2
* \file         Source\file.c
3
* \brief        Bootloader file system interface source file.
4
* \ingroup      Core
5
* \internal
6
*----------------------------------------------------------------------------------------
7
*                          C O P Y R I G H T
8
*----------------------------------------------------------------------------------------
9
*   Copyright (c) 2013  by Feaser    http://www.feaser.com    All rights reserved
10
*
11
*----------------------------------------------------------------------------------------
12
*                            L I C E N S E
13
*----------------------------------------------------------------------------------------
14
* This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or
15
* modify it under the terms of the GNU General Public License as published by the Free
16
* Software Foundation, either version 3 of the License, or (at your option) any later
17
* version.
18
*
19
* OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
20
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
21
* PURPOSE. See the GNU General Public License for more details.
22
*
23
* You should have received a copy of the GNU General Public License along with OpenBLT.
24
* If not, see <http://www.gnu.org/licenses/>.
25
*
26
* A special exception to the GPL is included to allow you to distribute a combined work 
27
* that includes OpenBLT without being obliged to provide the source code for any 
28
* proprietary components. The exception text is included at the bottom of the license
29
* file <license.html>.
30
* 
31
* \endinternal
32
****************************************************************************************/
33
34
/****************************************************************************************
35
* Include files
36
****************************************************************************************/
37
#include "boot.h"                                     /* bootloader generic header     */
38
#include <string.h>                                   /* for strcpy etc.               */
39
#include <ctype.h>                                    /* for toupper() etc.            */
40
41
42
#if (BOOT_FILE_SYS_ENABLE > 0)
43
/****************************************************************************************
44
* Type definitions
45
****************************************************************************************/
46
/** \brief Enumeration for the different internal module states. */
47
typedef enum 
48
{ 
49
  FIRMWARE_UPDATE_STATE_IDLE,                    /**< idle state                       */
50
  FIRMWARE_UPDATE_STATE_STARTING,                /**< starting state                   */
51
  FIRMWARE_UPDATE_STATE_ERASING,                 /**< erasing state                    */
52
  FIRMWARE_UPDATE_STATE_PROGRAMMING              /**< programming state                */
53
} tFirmwareUpdateState;
54
55
/** \brief Structure type with information for the memory erase opeartion. */
56
typedef struct 
57
{
58
  blt_addr   start_address;                      /**< erase start address              */
59
  blt_int32u total_size;                         /**< total number of bytes to erase   */
60
} tFileEraseInfo;
61
62
/** \brief Structure type for grouping FATFS related objects used by this module. */
63
typedef struct 
64
{
65
  FATFS fs;                                      /**< file system object for mouting   */
66
  FIL   file;                                    /**< file object for firmware file    */
67
} tFatFsObjects;
68
69
/****************************************************************************************
70
* Function prototypes
71
****************************************************************************************/
72
#if (BOOT_FILE_LOGGING_ENABLE > 0)
73
static blt_char      FileLibByteNibbleToChar(blt_int8u nibble);
74
static blt_char     *FileLibByteToHexString(blt_int8u byte_val, blt_char *destination);
75
static blt_char     *FileLibLongToIntString(blt_int32u long_val, blt_char *destination);
76
#endif
77
static blt_int8u     FileLibHexStringToByte(const blt_char *hexstring);
78
79
80
/****************************************************************************************
81
* Hook functions
82
****************************************************************************************/
83
extern blt_bool        FileIsFirmwareUpdateRequestedHook(void);
84
extern const blt_char *FileGetFirmwareFilenameHook(void);
85
extern void            FileFirmwareUpdateStartedHook(void);
86
extern void            FileFirmwareUpdateCompletedHook(void);
87
extern void            FileFirmwareUpdateErrorHook(blt_int8u error_code);
88
extern void            FileFirmwareUpdateLogHook(blt_char *info_string);
89
90
91
/****************************************************************************************
92
* Local data declarations
93
****************************************************************************************/
94
/** \brief Local variable that holds the internal module state. */
95
static tFirmwareUpdateState firmwareUpdateState;
96
/** \brief Local variable for the used FATFS objects in this module. */
97
static tFatFsObjects        fatFsObjects;
98
/** \brief Local variable for storing S-record line parsing results. */
99
static tSrecLineParseObject lineParseObject;
100
/** \brief Local variable for storing information regarding the memory erase operation.*/
101
static tFileEraseInfo       eraseInfo;
102
#if (BOOT_FILE_LOGGING_ENABLE > 0)
103
/** \brief Local character buffer for storing the string with log information. */
104
static blt_char             loggingStr[64];
105
#endif
106
107
108
/***********************************************************************************//**
109
** \brief     Initializes the file system interface module. The initial firmware
110
**            update state is set to idle and the file system is mounted as 
111
**            logical disk 0.
112
** \return    none
113
**
114
****************************************************************************************/
115
void FileInit(void)
116
{
117
  FRESULT fresult;
118
    
119
  /* set the initial state */
120
  firmwareUpdateState = FIRMWARE_UPDATE_STATE_IDLE;
121
  /* mount the file system, using logical disk 0 */
122
  fresult = f_mount(0, &fatFsObjects.fs);
123
  /* mounting does not access the disk and should succeed unless misconfigured */
124
  ASSERT_RT(fresult == FR_OK);
125
} /*** end of FileInit ***/
126
127
128
/***********************************************************************************//**
129
** \brief     This function checks if a firmware update through the locally attached
130
**            storage is in progress or not (idle).
131
** \return    BLT_TRUE when in idle state, BLT_FALSE otherwise.
132
**
133
****************************************************************************************/
134
blt_bool FileIsIdle(void)
135
{
136
  if (firmwareUpdateState == FIRMWARE_UPDATE_STATE_IDLE)
137
  {
138
    return BLT_TRUE;
139
  }
140
  return BLT_FALSE;
141
} /*** end of FileIsIdle ***/
142
143
144
/***********************************************************************************//**
145
** \brief     This function checks if a firmware update through the locally attached
146
**            storage is requested to be started and if so processes this request
147
**            by transitioning from the IDLE to the STARTING state.
148
** \return    BLT_TRUE when a firmware update is requested, BLT_FALSE otherwise.
149
**
150
****************************************************************************************/
151
blt_bool FileHandleFirmwareUpdateRequest(void)
152
{
153
  #if (BOOT_COM_ENABLE > 0)
154
  /* make sure that there is no connection with a remote host to prevent two firmware
155
   * updates happening at the same time
156
   */
157
  if (ComIsConnected() == BLT_TRUE)
158
  {
159
    return BLT_FALSE;
160
  }
161
  #endif
162
  /* a new firmware update request can only be handled if not already busy with one */
163
  if (firmwareUpdateState != FIRMWARE_UPDATE_STATE_IDLE)
164
  {
165
    return BLT_FALSE;
166
  }
167
  /* check if a firmware update is requested */
168
  if (FileIsFirmwareUpdateRequestedHook() == BLT_TRUE)
169
  {
170
    /* transition from IDLE to STARTING state, which kicks off the update sequence */
171
    firmwareUpdateState = FIRMWARE_UPDATE_STATE_STARTING;
172
    return BLT_TRUE;
173
  }
174
  /* still here so no update request pending */
175
  return BLT_FALSE;
176
} /*** end of FileHandleFirmwareUpdateRequest ***/
177
178
179
/***********************************************************************************//**
180
** \brief     File system task function for managing the firmware updates from
181
**                 locally attached storage.
182
** \return    none.
183
**
184
****************************************************************************************/
185
void FileTask(void)
186
{
187
  blt_int16s  parse_result;
188
  blt_char   *read_line_ptr;
189
  
190
  /* ------------------------------- idle -------------------------------------------- */
191
  if (firmwareUpdateState == FIRMWARE_UPDATE_STATE_IDLE)
192
  {
193
    /* currently, nothings need to be done while idling */
194
  }
195
  /* ------------------------------- starting ---------------------------------------- */
196
  else if (firmwareUpdateState == FIRMWARE_UPDATE_STATE_STARTING)
197
  {
198
    #if (BOOT_FILE_STARTED_HOOK_ENABLE > 0)
199
    /* inform application about update started event via hook function */
200
    FileFirmwareUpdateStartedHook();
201
    #endif
202
    #if (BOOT_FILE_LOGGING_ENABLE > 0)
203
    FileFirmwareUpdateLogHook("Firmware update request detected\n\r");
204
    FileFirmwareUpdateLogHook("Opening firmware file for reading...");
205
    #endif
206
    /* attempt to obtain a file object for the firmware file */
207
    if (f_open(&fatFsObjects.file, FileGetFirmwareFilenameHook(), FA_OPEN_EXISTING | FA_READ) != FR_OK)
208
    {
209
      /* can't open file */
210
      #if (BOOT_FILE_LOGGING_ENABLE > 0)
211
      FileFirmwareUpdateLogHook("ERROR\n\r");
212
      #endif
213
      #if (BOOT_FILE_ERROR_HOOK_ENABLE > 0)
214
      FileFirmwareUpdateErrorHook(FILE_ERROR_CANNOT_OPEN_FIRMWARE_FILE);
215
      #endif        
216
      /* nothing left to do now */
217
      return;
218
    }
219
    #if (BOOT_FILE_LOGGING_ENABLE > 0)
220
    FileFirmwareUpdateLogHook("OK\n\r");
221
    FileFirmwareUpdateLogHook("Starting the programming sequence\n\r");
222
    FileFirmwareUpdateLogHook("Parsing firmware file to obtain erase size...");
223
    #endif
224
    /* prepare data objects for the erasing state */
225
    eraseInfo.start_address = 0;
226
    eraseInfo.total_size = 0;
227
    /* transition from idle to erasing state */
228
    firmwareUpdateState = FIRMWARE_UPDATE_STATE_ERASING;
229
  }
230
  /* ------------------------------- erasing ----------------------------------------- */
231
  else if (firmwareUpdateState == FIRMWARE_UPDATE_STATE_ERASING)
232
  {
233
    /* read a line from the file */
234
    read_line_ptr = f_gets(lineParseObject.line, sizeof(lineParseObject.line), &fatFsObjects.file);
235
    /* check if an error occurred */
236
    if (f_error(&fatFsObjects.file) > 0)
237
    {
238
      #if (BOOT_FILE_LOGGING_ENABLE > 0)
239
      FileFirmwareUpdateLogHook("ERROR\n\r");
240
      #endif
241
      #if (BOOT_FILE_ERROR_HOOK_ENABLE > 0)
242
      FileFirmwareUpdateErrorHook(FILE_ERROR_CANNOT_READ_FROM_FILE);
243
      #endif       
244
      /* close the file */
245
      f_close(&fatFsObjects.file);
246
      /* cannot continue with firmware update so go back to idle state */
247
      firmwareUpdateState = FIRMWARE_UPDATE_STATE_IDLE;
248
      return;
249
    }
250
    /* parse the S-Record line without copying the data values if the line is not empty */
251
    if (read_line_ptr != BLT_NULL)
252
    {
253
      parse_result = FileSrecParseLine(lineParseObject.line, &lineParseObject.address, BLT_NULL);
254
      /* check parsing result */
255
      if (parse_result == ERROR_SREC_INVALID_CHECKSUM)
256
      {
257
        #if (BOOT_FILE_LOGGING_ENABLE > 0)
258
        FileFirmwareUpdateLogHook("ERROR\n\r");
259
        #endif
260
        #if (BOOT_FILE_ERROR_HOOK_ENABLE > 0)
261
        FileFirmwareUpdateErrorHook(FILE_ERROR_INVALID_CHECKSUM_IN_FILE);
262
        #endif       
263
        /* close the file */
264
        f_close(&fatFsObjects.file);
265
        /* cannot continue with firmware update so go back to idle state */
266
        firmwareUpdateState = FIRMWARE_UPDATE_STATE_IDLE;
267
        return;
268
      }
269
    }
270
    /* only process parsing results if the line contained address/data info */
271
    if (parse_result > 0)
272
    {
273
      /* is this the first address/data info we encountered? */
274
      if (eraseInfo.total_size == 0)
275
      {
276
        /* store the start_address and byte count */
277
        eraseInfo.start_address = lineParseObject.address;
278
        eraseInfo.total_size = parse_result;
279
      }
280
      else
281
      {
282
        /* update the start_address and byte count */
283
        if (lineParseObject.address < eraseInfo.start_address)
284
        {
285
          eraseInfo.start_address = lineParseObject.address;
286
        }
287
        eraseInfo.total_size += parse_result;
288
      }
289
    }
290
    /* check if the end of the file was reached */
291
    if (f_eof(&fatFsObjects.file) > 0)
292
    {
293
      /* rewind the file in preparation for the programming state */
294
      if (f_lseek(&fatFsObjects.file, 0) != FR_OK)
295
      {
296
        #if (BOOT_FILE_LOGGING_ENABLE > 0)
297
        FileFirmwareUpdateLogHook("ERROR\n\r");
298
        #endif
299
        #if (BOOT_FILE_ERROR_HOOK_ENABLE > 0)
300
        FileFirmwareUpdateErrorHook(FILE_ERROR_REWINDING_FILE_READ_POINTER);
301
        #endif       
302
        /* close the file */
303
        f_close(&fatFsObjects.file);
304
        /* cannot continue with firmware update so go back to idle state */
305
        firmwareUpdateState = FIRMWARE_UPDATE_STATE_IDLE;
306
        return;
307
      }
308
      #if (BOOT_FILE_LOGGING_ENABLE > 0)
309
      FileFirmwareUpdateLogHook("OK\n\r");
310
      FileFirmwareUpdateLogHook("Erasing ");
311
      /* convert size to string  */
312
      FileLibLongToIntString(eraseInfo.total_size, loggingStr);
313
      FileFirmwareUpdateLogHook(loggingStr);
314
      FileFirmwareUpdateLogHook(" bytes from memory at 0x");
315
      /* convert address to hex-string  */
316
      FileLibByteToHexString((blt_int8u)(eraseInfo.start_address >> 24), &loggingStr[0]);
317
      FileLibByteToHexString((blt_int8u)(eraseInfo.start_address >> 16), &loggingStr[2]);
318
      FileLibByteToHexString((blt_int8u)(eraseInfo.start_address >> 8), &loggingStr[4]);
319
      FileLibByteToHexString((blt_int8u)eraseInfo.start_address, &loggingStr[6]);
320
      FileFirmwareUpdateLogHook(loggingStr);
321
      FileFirmwareUpdateLogHook("...");
322
      #endif
323
      /* still here so we are ready to perform the memory erase operation */
324
      if (NvmErase(eraseInfo.start_address, eraseInfo.total_size) == BLT_FALSE)
325
      {
326
        #if (BOOT_FILE_LOGGING_ENABLE > 0)
327
        FileFirmwareUpdateLogHook("ERROR\n\r");
328
        #endif
329
        #if (BOOT_FILE_ERROR_HOOK_ENABLE > 0)
330
        FileFirmwareUpdateErrorHook(FILE_ERROR_CANNOT_ERASE_MEMORY);
331
        #endif       
332
        /* close the file */
333
        f_close(&fatFsObjects.file);
334
        /* cannot continue with firmware update so go back to idle state */
335
        firmwareUpdateState = FIRMWARE_UPDATE_STATE_IDLE;
336
        return;
337
      }
338
      #if (BOOT_FILE_LOGGING_ENABLE > 0)
339
      FileFirmwareUpdateLogHook("OK\n\r");
340
      #endif
341
      /* all okay, then go to programming state */
342
      firmwareUpdateState = FIRMWARE_UPDATE_STATE_PROGRAMMING;
343
    }
344
  }
345
  /* ------------------------------- programming ------------------------------------- */
346
  else if (firmwareUpdateState == FIRMWARE_UPDATE_STATE_PROGRAMMING)
347
  {
348
    /* read a line from the file */
349
    read_line_ptr = f_gets(lineParseObject.line, sizeof(lineParseObject.line), &fatFsObjects.file);
350
    /* check if an error occurred */
351
    if (f_error(&fatFsObjects.file) > 0)
352
    {
353
      #if (BOOT_FILE_LOGGING_ENABLE > 0)
354
      FileFirmwareUpdateLogHook("Reading line from file...ERROR\n\r");
355
      #endif
356
      #if (BOOT_FILE_ERROR_HOOK_ENABLE > 0)
357
      FileFirmwareUpdateErrorHook(FILE_ERROR_CANNOT_READ_FROM_FILE);
358
      #endif       
359
      /* close the file */
360
      f_close(&fatFsObjects.file);
361
      /* cannot continue with firmware update so go back to idle state */
362
      firmwareUpdateState = FIRMWARE_UPDATE_STATE_IDLE;
363
      return;
364
    }
365
    /* parse the S-Record line if the line is not empty */
366
    if (read_line_ptr != BLT_NULL)
367
    {
368
      parse_result = FileSrecParseLine(lineParseObject.line, &lineParseObject.address, lineParseObject.data);
369
      /* check parsing result */
370
      if (parse_result == ERROR_SREC_INVALID_CHECKSUM)
371
      {
372
        #if (BOOT_FILE_LOGGING_ENABLE > 0)
373
        FileFirmwareUpdateLogHook("Invalid checksum found...ERROR\n\r");
374
        #endif
375
        #if (BOOT_FILE_ERROR_HOOK_ENABLE > 0)
376
        FileFirmwareUpdateErrorHook(FILE_ERROR_INVALID_CHECKSUM_IN_FILE);
377
        #endif       
378
        /* close the file */
379
        f_close(&fatFsObjects.file);
380
        /* cannot continue with firmware update so go back to idle state */
381
        firmwareUpdateState = FIRMWARE_UPDATE_STATE_IDLE;
382
        return;
383
      }
384
    }
385
    /* only process parsing results if the line contained address/data info */
386
    if (parse_result > 0)
387
    {
388
      #if (BOOT_FILE_LOGGING_ENABLE > 0)
389
      FileFirmwareUpdateLogHook("Programming ");
390
      /* convert size to string  */
391
      FileLibLongToIntString(parse_result, loggingStr);
392
      FileFirmwareUpdateLogHook(loggingStr);
393
      FileFirmwareUpdateLogHook(" bytes to memory at 0x");
394
      /* convert address to hex-string  */
395
      FileLibByteToHexString((blt_int8u)(lineParseObject.address >> 24), &loggingStr[0]);
396
      FileLibByteToHexString((blt_int8u)(lineParseObject.address >> 16), &loggingStr[2]);
397
      FileLibByteToHexString((blt_int8u)(lineParseObject.address >> 8), &loggingStr[4]);
398
      FileLibByteToHexString((blt_int8u)lineParseObject.address, &loggingStr[6]);
399
      FileFirmwareUpdateLogHook(loggingStr);
400
      FileFirmwareUpdateLogHook("...");
401
      #endif
402
      /* program the data */
403
      if (NvmWrite(lineParseObject.address, parse_result, lineParseObject.data) == BLT_FALSE)
404
      {
405
        #if (BOOT_FILE_LOGGING_ENABLE > 0)
406
        FileFirmwareUpdateLogHook("ERROR\n\r");
407
        #endif
408
        #if (BOOT_FILE_ERROR_HOOK_ENABLE > 0)
409
        FileFirmwareUpdateErrorHook(FILE_ERROR_CANNOT_PROGRAM_MEMORY);
410
        #endif       
411
        /* close the file */
412
        f_close(&fatFsObjects.file);
413
        /* cannot continue with firmware update so go back to idle state */
414
        firmwareUpdateState = FIRMWARE_UPDATE_STATE_IDLE;
415
        return;
416
      }
417
      #if (BOOT_FILE_LOGGING_ENABLE > 0)
418
      FileFirmwareUpdateLogHook("OK\n\r");
419
      #endif
420
    }
421
    /* check if the end of the file was reached */
422
    if (f_eof(&fatFsObjects.file) > 0)
423
    {
424
      #if (BOOT_FILE_LOGGING_ENABLE > 0)
425
      FileFirmwareUpdateLogHook("Writing program checksum...");
426
      #endif
427
      /* finish the programming by writing the checksum */
428
      if (NvmDone() == BLT_FALSE)
429
      {
430
        #if (BOOT_FILE_LOGGING_ENABLE > 0)
431
        FileFirmwareUpdateLogHook("ERROR\n\r");
432
        #endif
433
        #if (BOOT_FILE_ERROR_HOOK_ENABLE > 0)
434
        FileFirmwareUpdateErrorHook(FILE_ERROR_CANNOT_WRITE_CHECKSUM);
435
        #endif       
436
        /* close the file */
437
        f_close(&fatFsObjects.file);
438
        /* cannot continue with firmware update so go back to idle state */
439
        firmwareUpdateState = FIRMWARE_UPDATE_STATE_IDLE;
440
        return;
441
      }
442
      #if (BOOT_FILE_LOGGING_ENABLE > 0)
443
      FileFirmwareUpdateLogHook("OK\n\r");
444
      FileFirmwareUpdateLogHook("Closing firmware file\n\r");
445
      #endif
446
      /* close the file */
447
      f_close(&fatFsObjects.file);
448
      #if (BOOT_FILE_LOGGING_ENABLE > 0)
449
      FileFirmwareUpdateLogHook("Firmware update successfully completed\n\r");
450
      #endif
451
      /* all done so transistion back to idle mode */
452
      firmwareUpdateState = FIRMWARE_UPDATE_STATE_IDLE;
453
      #if (BOOT_FILE_COMPLETED_HOOK_ENABLE > 0)
454
      /* inform application about update completed event via hook function */
455
      FileFirmwareUpdateCompletedHook();
456
      #endif
457
      /* attempt to start the user program now that programming is done. note that
458
       * a call to CpuReset() won't work correctly here, because if the same firmware
459
       * file is still on the locally attached storage, it will just restart the
460
       * firmware update again and again..
461
       */
462
      CpuStartUserProgram();
463
    }
464
  }
465
} /*** end of FileTask ***/
466
467
468
/************************************************************************************//**
469
** \brief     Inspects a line from a Motorola S-Record file to determine its type.
470
** \param     line A line from the S-Record.
471
** \return    the S-Record line type.
472
**
473
****************************************************************************************/
474
tSrecLineType FileSrecGetLineType(const blt_char *line)
475
{
476
  /* check if the line starts with the 'S' character, followed by a digit */
477
  if ( (toupper(line[0]) != 'S') || (isdigit(line[1]) == 0) )
478
  {
479
    /* not a valid S-Record line type */
480
    return LINE_TYPE_UNSUPPORTED;
481
  }
482
  /* determine the line type */
483
  if (line[1] == '1')
484
  {
485
    return LINE_TYPE_S1;
486
  }
487
  if (line[1] == '2')
488
  {
489
    return LINE_TYPE_S2;
490
  }
491
  if (line[1] == '3')
492
  {
493
    return LINE_TYPE_S3;
494
  }
495
  /* still here so not a supported line type found */
496
  return LINE_TYPE_UNSUPPORTED;
497
} /*** end of FileSrecGetLineType ***/
498
499
500
/************************************************************************************//**
501
** \brief     Inspects an S1, S2 or S3 line from a Motorola S-Record file to
502
**            determine if the checksum at the end is corrrect.
503
** \param     line An S1, S2 or S3 line from the S-Record.
504
** \return    BLT_TRUE if the checksum is correct, BLT_FALSE otherwise.
505
**
506
****************************************************************************************/
507
blt_bool FileSrecVerifyChecksum(const blt_char *line)
508
{
509
  blt_int16u bytes_on_line;
510
  blt_int8u  checksum = 0;
511
  
512
  /* adjust pointer to point to byte count value */
513
  line += 2;
514
  /* read out the number of byte values that follow on the line */
515
  bytes_on_line = FileLibHexStringToByte(line);
516
  /* byte count is part of checksum */
517
  checksum += bytes_on_line;
518
  /* adjust pointer to the first byte of the address */
519
  line += 2;
520
  /* add byte values of address and data, but not the final checksum */
521
  do 
522
  {
523
    /* add the next byte value to the checksum */
524
    checksum += FileLibHexStringToByte(line);
525
    /* update counter */
526
    bytes_on_line--;
527
    /* point to next hex string in the line */
528
    line += 2;
529
  } 
530
  while (bytes_on_line > 1);
531
  /* the checksum is calculated by summing up the values of the byte count, address and
532
   * databytes and then taking the 1-complement of the sum's least signigicant byte */
533
  checksum = ~checksum;
534
  /* finally verify the calculated checksum with the one at the end of the line */
535
  if (checksum != FileLibHexStringToByte(line))
536
  {
537
    /* checksum incorrect */
538
    return BLT_FALSE;
539
  }
540
  /* still here so the checksum was correct */
541
  return BLT_TRUE;
542
} /*** end of FileSrecVerifyChecksum ***/
543
544
545
/************************************************************************************//**
546
** \brief     Parses a line from a Motorola S-Record file and looks for S1, S2 or S3 
547
**            lines with data. Note that if a null pointer is passed as the data
548
**            parameter, then no data is extracted from the line.
549
** \param     line    A line from the S-Record.
550
** \param     address Address found in the S-Record data line.
551
** \param     data    Byte array where the data bytes from the S-Record data line
552
**                    are stored.
553
** \return    The number of data bytes found on the S-record data line, 0 in case 
554
**            the line is not an S1, S2 or S3 line or ERROR_SREC_INVALID_CHECKSUM
555
**            in case the checksum validation failed.
556
**
557
****************************************************************************************/
558
blt_int16s FileSrecParseLine(const blt_char *line, blt_addr *address, blt_int8u *data)
559
{
560
  tSrecLineType lineType;
561
  blt_int16s    data_byte_count = 0;
562
  blt_int16u    bytes_on_line;
563
  blt_int16u    i;
564
  
565
  /* check pointers and not that data can be a null pointer */
566
  ASSERT_RT((address != BLT_NULL) && (line != BLT_NULL));
567
  /* figure out what type of line we are dealing with */
568
  lineType = FileSrecGetLineType(line);
569
  /* make sure it is one that we can parse */
570
  if (lineType == LINE_TYPE_UNSUPPORTED)
571
  {
572
    /* not a parsing error, but simply no data on this line */
573
    return 0;
574
  }
575
  /* verify the checksum */
576
  if (FileSrecVerifyChecksum(line) == BLT_FALSE)
577
  {
578
    /* error on data line encountered */
579
    return ERROR_SREC_INVALID_CHECKSUM;
580
  }
581
  /* all good so far, now read out the address and databytes for the line */
582
  switch (lineType)
583
  {
584
    /* ---------------------------- S1 line type ------------------------------------- */
585
    case LINE_TYPE_S1:
586
      /* adjust pointer to point to byte count value */
587
      line += 2;
588
      /* read out the number of byte values that follow on the line */
589
      bytes_on_line = FileLibHexStringToByte(line);
590
      /* read out the 16-bit address */
591
      line += 2;
592
      *address = FileLibHexStringToByte(line) << 8;
593
      line += 2;
594
      *address += FileLibHexStringToByte(line);
595
      /* adjust pointer to point to the first data byte after the address */
596
      line += 2;
597
      /* determine how many data bytes are on the line */
598
      data_byte_count = bytes_on_line - 3; /* -2 bytes address, -1 byte checksum */
599
      /* read and store data bytes if requested */
600
      if (data != BLT_NULL)
601
      {
602
        for (i=0; i<data_byte_count; i++)
603
        {
604
          data[i] = FileLibHexStringToByte(line);
605
          line += 2;
606
        }
607
      }
608
      break;
609
      
610
    /* ---------------------------- S2 line type ------------------------------------- */
611
    case LINE_TYPE_S2:
612
      /* adjust pointer to point to byte count value */
613
      line += 2;
614
      /* read out the number of byte values that follow on the line */
615
      bytes_on_line = FileLibHexStringToByte(line);
616
      /* read out the 32-bit address */
617
      line += 2;
618
      *address = FileLibHexStringToByte(line) << 16;
619
      line += 2;
620
      *address += FileLibHexStringToByte(line) << 8;
621
      line += 2;
622
      *address += FileLibHexStringToByte(line);
623
      /* adjust pointer to point to the first data byte after the address */
624
      line += 2;
625
      /* determine how many data bytes are on the line */
626
      data_byte_count = bytes_on_line - 4; /* -3 bytes address, -1 byte checksum */
627
      /* read and store data bytes if requested */
628
      if (data != BLT_NULL)
629
      {
630
        for (i=0; i<data_byte_count; i++)
631
        {
632
          data[i] = FileLibHexStringToByte(line);
633
          line += 2;
634
        }
635
      }
636
      break;
637
      
638
    /* ---------------------------- S3 line type ------------------------------------- */
639
    case LINE_TYPE_S3:
640
      /* adjust pointer to point to byte count value */
641
      line += 2;
642
      /* read out the number of byte values that follow on the line */
643
      bytes_on_line = FileLibHexStringToByte(line);
644
      /* read out the 32-bit address */
645
      line += 2;
646
      *address = FileLibHexStringToByte(line) << 24;
647
      line += 2;
648
      *address += FileLibHexStringToByte(line) << 16;
649
      line += 2;
650
      *address += FileLibHexStringToByte(line) << 8;
651
      line += 2;
652
      *address += FileLibHexStringToByte(line);
653
      /* adjust pointer to point to the first data byte after the address */
654
      line += 2;
655
      /* determine how many data bytes are on the line */
656
      data_byte_count = bytes_on_line - 5; /* -4 bytes address, -1 byte checksum */
657
      /* read and store data bytes if requested */
658
      if (data != BLT_NULL)
659
      {
660
        for (i=0; i<data_byte_count; i++)
661
        {
662
          data[i] = FileLibHexStringToByte(line);
663
          line += 2;
664
        }
665
      }
666
      break;
667
668
    default:
669
      break;
670
  }
671
  
672
  return data_byte_count;
673
} /*** end of FileSrecParseLine ***/
674
675
676
#if (BOOT_FILE_LOGGING_ENABLE > 0)
677
/************************************************************************************//**
678
** \brief     Helper function to convert a 4-bit value to a character that represents its
679
**            value in hexadecimal format.
680
**              Example: FileLibByteNibbleToChar(11)  --> returns 'B'.
681
** \param     nibble 4-bit value to convert.
682
** \return    The resulting byte value.
683
**
684
****************************************************************************************/
685
static blt_char FileLibByteNibbleToChar(blt_int8u nibble)
686
{
687
  blt_char  c;
688
  
689
  /* convert to ASCII value */
690
  c = (nibble & 0x0f) + '0';
691
  if (nibble > 9)
692
  {
693
    c += 7;
694
  }
695
  else
696
  {
697
    c = toupper(c);
698
  }
699
  /* return the character */
700
  return c;
701
} /*** end of FileLibByteNibbleToChar ***/
702
703
704
/************************************************************************************//**
705
** \brief     Helper function to convert a byte value to a string representing the
706
**            value in hexadecimal format.
707
**              Example: FileLibByteToHexString(28, strBuffer)  --> returns "1C".
708
** \param     byte_val    8-bit value to convert.
709
** \param     destination Pointer to character buffer for storing the results.
710
** \return    The resulting string.
711
**
712
****************************************************************************************/
713
static blt_char *FileLibByteToHexString(blt_int8u byte_val, blt_char *destination)
714
{
715
  /* first the most significant n-bit nibble */
716
  destination[0] = FileLibByteNibbleToChar(byte_val >> 4);
717
  /* next the least significant n-bit nibble */
718
  destination[1] = FileLibByteNibbleToChar(byte_val & 0x0f);
719
  /* add string termination */
720
  destination[2] = '\0';
721
  /* return pointer to resulting string */
722
  return destination;
723
} /*** end of FileLibByteToHexString ***/
724
725
726
/************************************************************************************//**
727
** \brief     Helper function to convert a 32-bit unsigned number to a string that
728
**            represents its decimal value.
729
**              Example: FileLibLongToIntString(1234, strBuffer)  --> returns "1234".
730
** \param     long_val    32-bit value to convert.
731
** \param     destination Pointer to character buffer for storing the results.
732
** \return    The resulting string.
733
**
734
****************************************************************************************/
735
static blt_char *FileLibLongToIntString(blt_int32u long_val, blt_char *destination)
736
{
737
  blt_int32u long_val_cpy = long_val;
738
  
739
  /* first determine how many digits there will be */
740
  do
741
  {
742
    destination++;
743
    long_val_cpy /= 10;
744
  }
745
  while (long_val_cpy > 0);
746
  /* add space for the string termination and add it */
747
  *destination = '\0';
748
  /* now add the digits from right to left */  
749
  long_val_cpy = long_val;
750
  do
751
  {
752
    /* set write pointer to where the next character should go */
753
    destination--;
754
    /* write digit in ASCII format */
755
    *destination = long_val_cpy % 10 + '0';
756
    /* move on to the next digit */
757
    long_val_cpy /= 10;
758
  }
759
  while (long_val_cpy > 0);
760
761
  return destination;
762
} /*** end of FileLibLongToIntString ***/
763
#endif /* (BOOT_FILE_LOGGING_ENABLE > 0) */
764
765
766
/************************************************************************************//**
767
** \brief     Helper function to convert a sequence of 2 characters that represent
768
**            a hexadecimal value to the actual byte value.
769
**              Example: FileLibHexStringToByte("2f")  --> returns 47.
770
** \param     hexstring String beginning with 2 characters that represent a hexa-
771
**                      decimal value.
772
** \return    The resulting byte value.
773
**
774
****************************************************************************************/
775
static blt_int8u FileLibHexStringToByte(const blt_char *hexstring)
776
{
777
  blt_int8u result = 0;
778
  blt_char  c;
779
  blt_int8u counter;
780
  
781
  /* a hexadecimal character is 2 characters long (i.e 0x4F minus the 0x part) */
782
  for (counter=0; counter < 2; counter++)
783
  {
784
    /* read out the character */
785
    c = toupper(hexstring[counter]);
786
    /* check that the character is 0..9 or A..F */
787
    if ( (c < '0') || (c > 'F') || ( (c > '9') && (c < 'A') ) )
788
    {
789
      /* character not valid */
790
      return 0;
791
    }
792
    /* convert character to 4-bit value (check ASCII table for more info) */
793
    c -= '0';
794
    if (c > 9) 
795
    {
796
      c -= 7;
797
    }
798
    /* add it to the result */
799
    result = (result << 4) + c;
800
  }
801
  /* return the results */
802
  return result;
803
} /*** end of FileLibHexStringToByte ***/
804
805
#endif /* BOOT_FILE_SYS_ENABLE > 0 */
806
807
808
/*********************************** end of file.c *************************************/