Refs #268. Merged /hostlib branch back into the trunk.

git-svn-id: https://svn.code.sf.net/p/openblt/code/trunk@270 5dc33758-31d5-4daf-9ae8-b24bf3d40d73
This commit is contained in:
Frank Voorburg 2017-05-26 14:01:14 +00:00
parent 4a09db8197
commit f469148355
65 changed files with 17572 additions and 0 deletions

6
Doc/UM_BootCommander.URL Normal file
View File

@ -0,0 +1,6 @@
[InternetShortcut]
URL=https://www.feaser.com/openblt/doku.php?id=manual:bootcommander
IDList=
HotKey=0
IconFile=
IconIndex=0

6
Doc/UM_LibOpenBLT.URL Normal file
View File

@ -0,0 +1,6 @@
[InternetShortcut]
URL=https://www.feaser.com/openblt/doku.php?id=manual:libopenblt
IDList=
HotKey=0
IconFile=
IconIndex=0

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,15 @@
:: Batch file to generate a reference manual from the comments in the source code, with
:: Doxygen. The following tools should be installed and added to the path:
:: - DoxyGen (doxygen.exe)
:: - Graphviz (dot.exe)
:: - MikTex (pdflatex.exe)
:: - HTML Help Workshop compiler (hhc.exe)
if exist ..\RM_BootCommander.pdf del ..\RM_BootCommander.pdf
if exist ..\RM_BootCommander.chm del ..\RM_BootCommander.chm
doxygen.exe DoxyfileBootCommander
call .\output\BootCommander\latex\make.bat
call copy .\output\BootCommander\latex\refman.pdf ..\RM_BootCommander.pdf
:: Remove the comment on the next line to automatically open the generated PDF file
:: call start "C:\Program Files (x86)\Adobe\Reader 11.0\Reader\AcroRd32.exe" ..\RM_BootCommander.pdf
:: Remove the comment on the next line to automatically open the generated CHM file
:: start .\..\RM_BootCommander.chm

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,15 @@
:: Batch file to generate a reference manual from the comments in the source code, with
:: Doxygen. The following tools should be installed and added to the path:
:: - DoxyGen (doxygen.exe)
:: - Graphviz (dot.exe)
:: - MikTex (pdflatex.exe)
:: - HTML Help Workshop compiler (hhc.exe)
if exist ..\RM_LibOpenBLT.pdf del ..\RM_LibOpenBLT.pdf
if exist ..\RM_LibOpenBLT.chm del ..\RM_LibOpenBLT.chm
doxygen.exe DoxyfileLibOpenBLT
call .\output\LibOpenBLT\latex\make.bat
call copy .\output\LibOpenBLT\latex\refman.pdf ..\RM_LibOpenBLT.pdf
:: Remove the comment on the next line to automatically open the generated PDF file
:: call start "C:\Program Files (x86)\Adobe\Reader 11.0\Reader\AcroRd32.exe" ..\RM_LibOpenBLT.pdf
:: Remove the comment on the next line to automatically open the generated CHM file
:: start .\..\RM_LibOpenBLT.chm

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 93 KiB

View File

@ -0,0 +1,148 @@
#****************************************************************************************
# \file CMakeLists.txt
# \brief CMake descriptor file for BootCommander command line program.
# \internal
#----------------------------------------------------------------------------------------
# C O P Y R I G H T
#----------------------------------------------------------------------------------------
# Copyright (c) 2017 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 have received a copy of the GNU General Public License along with OpenBLT. It
# should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
#
# \endinternal
#****************************************************************************************
# Specify the version being used aswell as the language
cmake_minimum_required(VERSION 2.8)
#****************************************************************************************
# Project configuration
#****************************************************************************************
# Specify the project name
project(BootCommander)
# Build debug version by default
set(CMAKE_BUILD_TYPE "Debug")
#****************************************************************************************
# Options
#****************************************************************************************
# Add option with default value to disable the generation of the PC-lint target. It can
# be overridden on the command line when CMake is called using the following parameter:
# -DLINT_ENABLED=ON
option(LINT_ENABLED "Configurable to enable/disable the PC-lint target" OFF)
#****************************************************************************************
# Directories
#****************************************************************************************
# Set the output directory
set (PROJECT_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../../..)
# Set the output directory for the generic no-config case (e.g. with mingw)
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_OUTPUT_DIRECTORY} )
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_OUTPUT_DIRECTORY} )
set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_OUTPUT_DIRECTORY} )
# Set the output directory for multi-config builds (e.g. msvc)
foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} )
string( TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG )
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${PROJECT_OUTPUT_DIRECTORY} )
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${PROJECT_OUTPUT_DIRECTORY} )
set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${PROJECT_OUTPUT_DIRECTORY} )
endforeach( OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES )
# Set OpenBLT library related directory locations
set(LIBOPENBLT_INC ${PROJECT_SOURCE_DIR}/../LibOpenBLT)
set(LIBOPENBLT_LIB ${PROJECT_OUTPUT_DIRECTORY})
#****************************************************************************************
# Compiler flags
#****************************************************************************************
# Set platform specific compiler macro PLATFORM_XXX
if(WIN32)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DPLATFORM_WIN32 -D_CRT_SECURE_NO_WARNINGS")
elseif(UNIX)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DPLATFORM_LINUX")
endif(WIN32)
#***************************************************************************************
# Includes
#****************************************************************************************
# Set include directories
include_directories("${PROJECT_SOURCE_DIR}" "${LIBOPENBLT_INC}")
# Add search path for the linker
link_directories("${LIBOPENBLT_LIB}")
#***************************************************************************************
# Files
#****************************************************************************************
# Get header files from the root directory
file(GLOB INCS_ROOT "*.h")
set(INCS ${INCS_ROOT})
# Add sources
set(
PROG_SRCS
main.c
${LIBOPENBLT_INC}/openblt.h
${INCS}
)
# Set library name. When GNU GCC is used, the name to the static library file is used,
# otherwise the shared library is used by default. This works fine too, but the static
# library makes it a bit easier to move the target executable around on the file system.
if(CMAKE_C_COMPILER_ID MATCHES GNU)
set (LIBOPENBLT_LIBNAME libopenblt.a)
else()
set (LIBOPENBLT_LIBNAME openblt)
endif()
#***************************************************************************************
# Targets
#****************************************************************************************
# Set main target. Use "make BootCommander" to individually build the program.
add_executable(
BootCommander
${PROG_SRCS}
)
# Add libraries
target_link_libraries(BootCommander ${LIBOPENBLT_LIBNAME})
# Only generate the PC-lint taget if the option is enabled. Use "make BootCommander_LINT"
# to lint the project sources
if(LINT_ENABLED)
# Include PC-lint configuration file for the correct compiler. Currently GNU GCC and
# Microsoft Visual Studio are supported.
if(CMAKE_C_COMPILER_ID MATCHES GNU)
include(${PROJECT_SOURCE_DIR}/lint/gnu/pc_lint.cmake)
elseif(CMAKE_C_COMPILER_ID MATCHES MSVC)
include(${PROJECT_SOURCE_DIR}/lint/msvc/pc_lint.cmake)
endif()
# Generate the PC-lint target.
if(COMMAND add_pc_lint)
add_pc_lint(BootCommander ${PROG_SRCS})
endif(COMMAND add_pc_lint)
endif(LINT_ENABLED)
#*********************************** end of CMakeLists.txt ******************************

View File

@ -0,0 +1,129 @@
// ---------------------------------------------------------------------
// This file is provided by Gimpel Software (www.gimpel.com) for use with
// its products PC-lint and FlexeLint.
//
// Redistribution and use of this file, with or without modification, is
// permitted provided that any such redistribution retains this notice.
// ---------------------------------------------------------------------
#ifndef CO_GCC_H_
#define CO_GCC_H_
/*lint -save -w1 */
#ifdef _lint /* Make sure no compiler comes this way */
#ifdef __cplusplus
extern "C" {
#endif
/* Standard library headers typically define the assert macro so that it
expands to a complicated conditional expression that uses special
funtions that Lint does not know about by default. For linting
purposes, we can simplify things a bit by forcing assert() to expand to
a call to a special function that has the appropriate 'assert'
semantics.
*/
//lint -function( __assert, __lint_assert )
void __lint_assert( int );
//lint ++d"assert(e)=__lint_assert(!!(e))"
//(++d makes this definition permanently immutable for the Lint run.)
//Now that we've made our own 'assert', we need to keep people from being
//punished when the marco in 'assert.h' appears not to be used:
//lint -efile(766,*assert.h)
typedef char *__builtin_va_list;
/*lint -e{171} */
__builtin_va_list __lint_init_va(...);
void __builtin_va_end( __builtin_va_list );
/*lint
++d"__builtin_va_start(ap,parmN)=((ap)=__lint_init_va(parmN))"
++d"__builtin_va_arg(a,b)=(*( ((b) *) ( (((a) += sizeof(b)) - sizeof(b) )))"
*/
/*
The headers included below must be generated; For C++, generate
with:
g++ [usual build options] -E -dM t.cpp >lint_cppmac.h
For C, generate with:
gcc [usual build options] -E -dM t.c >lint_cmac.h
...where "t.cpp" and "t.c" are empty source files.
It's important to use the same compiler options used when compiling
project code because they can affect the existence and precise
definitions of certain predefined macros. See gcc-readme.txt for
details and a tutorial.
*/
#if defined(__cplusplus)
# include "lint_cppmac.h" // DO NOT COMMENT THIS OUT. DO NOT SUPPRESS ERROR 322. (If you see an error here, your Lint configuration is broken; check -i options and ensure that you have generated lint_cppmac.h as documented in gcc-readme.txt. Otherwise Gimpel Software cannot support your configuration.)
#else
# include "lint_cmac.h" // DO NOT COMMENT THIS OUT. DO NOT SUPPRESS ERROR 322. (If you see an error here, your Lint configuration is broken; check -i options and ensure that you have generated lint_cmac.h as documented in gcc-readme.txt. Otherwise Gimpel Software cannot support your configuration.)
#endif
/* If the macro set given by the generated macro files must be adjusted in
order for Lint to cope, then you can make those adjustments here.
*/
#define LINT_CO_GCC_H_GCC_VERSION ( __GNUC__ * 10000 + \
__GNUC_MINOR__ * 100 + \
__GNUC_PATCHLEVEL__ )
/* The following is a workaround for versions of GCC with bug 25717, in
which the preprocessor does not dump a #define directive for __STDC__
when -dM is given:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=25717
We know the unconditional definition of __STDC__ was introduced no
later than version 3.0; the preprocessor bug was fixed no later than
version 4.1.0.
*/
#if ( LINT_CO_GCC_H_GCC_VERSION >= 30000 && \
LINT_CO_GCC_H_GCC_VERSION < 40100 )
# define __STDC__ 1
#endif
#if !__cplusplus && !__STRICT_ANSI__ && __STDC_VERSION__ < 199901L
/* apparently, the code is compiled with -std=gnu89 (as opposed to -std=c89),
so: */
/*lint -rw_asgn(inline,__inline) */
#endif
#if LINT_CO_GCC_H_GCC_VERSION >= 40300
# define __COUNTER__ __lint__COUNTER__
//lint +rw( *type_traits ) // Enable type traits support
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif
#if _lint >= 909 // For 9.00i and later:
//// __attribute__ is GCC's __attribute__:
//
//lint -rw_asgn(__attribute__,__gcc_attribute__)
//lint -rw_asgn(__attribute, __gcc_attribute__)
//
//// Prevent "__attribute__" from being defined as a macro:
//
//lint --u"__attribute__"
//lint --u"__attribute"
//
//// Because an attribute-specifier is a form of
//// declaration-modifier, and because it can appear at the
//// beginning of a decl-specifier-seq, we must enable "Early
//// Modifiers":
//
//lint +fem
#else // for 9.00h and earlier:
//lint -d__attribute__()=
//lint -d__attribute()=
#endif
#endif /* _lint */
/*lint -restore */
#endif /* CO_GCC_H_ */

View File

@ -0,0 +1,209 @@
/* Date Stamp */ -d"_lint_co_gcc_lnt=co-gcc.lnt modified 12-Jun-2014"
/* To document usage use: -message( "Using " _lint_co_gcc_lnt ) */
// ---------------------------------------------------------------------
// This file is provided by Gimpel Software (www.gimpel.com) for use with
// its products PC-lint and FlexeLint.
//
// Redistribution and use of this file, with or without modification, is
// permitted provided that any such redistribution retains this notice.
// ---------------------------------------------------------------------
/* co-gcc.lnt: This is the seed file for configuring Lint for use with
GCC versions 2.95.3 and later.
Like all compiler options files this file is intended to be used
as follows:
lint co-gcc.lnt source-files-to-be-linted
Some of the information that co-gcc.lnt requires needs to be furnished
with the help of the gcc system itself. The easiest way to generate
this information is to use the makefile co-gcc.mak (supplied with the
Lint distribution) in an invocation of GNU Make; for details, see the
commentary at the top of co-gcc.mak.
*/
-cgnu // Notifies FlexeLint that gcc is being used.
// ===========================
// Preprocessor Configuration:
+fdi // GCC starts its #include search in the directory of the including
// file.
++fln // Allow:
// # digit-sequence " [s-char-sequence] " new-line
// as a synonym for:
// # line digit-sequence " [s-char-sequence] " new-line
// GCC additionally allows flag values to follow the
// s-char-sequence, but currently Lint ignores them.
-header(co-gcc.h) // Includes headers generated by GCC (bringing in
// predefined macros).
+libh(co-gcc.h) // Marks that header as library code.
gcc-include-path.lnt // This .lnt file should contain --i options
// and should be generated by invoking gcc with its '-v' option.
// (GCC's implicit #include search path is presented in the output.)
// This happens automatically when 'make -f co-gcc.mak' is invoked.
// Assertion directives (a feature of GCC's preprocessor) have been
// considered obsolete in GCC's documentation since version 3.0, so we do
// not use them here. If support for #assert is needed in the form of a
// lint option, one may use '-a#' like so:
// -a#machine(i386) // #assert's machine(i386) (SVR4 facility).
// File extensions:
// From the GCC man page:
//
// file.cc
// file.cp
// file.cxx
// file.cpp
// file.CPP
// file.c++
// file.C
// C++ source code that must be preprocessed. Note that in .cxx, the
// last two letters must both be literally x. Likewise, .C refers to
// a literal capital C.
//
// We emulate this with:
+cpp(.cc)
+cpp(.cp)
+cpp(.cxx)
+cpp(.cpp)
+cpp(.c++)
// Note the exceptions:
// +cpp(.CPP)
// +cpp(.C)
// These are commented out for the default config because they seem to
// cause trouble more often than not. For starters, it is problematic
// with filesystems that are case-insensitive (which has become common
// even on some POSIX systems).
// =============
// Size Options:
// +fwc // wchar_t might be builtin; if so, uncomment this option. (NOTE:
// // this option needs to be set before a size option is given for
// // wchar_t; see the documentation for -sw# in the Lint manual.)
size-options.lnt // This .lnt file should be generated (preferrably
// by a program created by invoking GCC with the compile options that
// are used in the compilation of the project to be linted). This
// happens automatically when 'make -f co-gcc.mak' is invoked.
// ===========================================
// +rw and -d options to cope with GNU syntax:
+ppw(ident) // Tolerate #ident
+ppw(warning)
// GCC provides alternative spellings of certain keywords:
+rw(__inline)
-rw_asgn(__inline__,__inline)
-rw_asgn(__header_always_inline,__inline)
-rw_asgn(__header_inline,__inline)
-rw_asgn(__signed__,signed)
-rw_asgn(__signed,signed)
-rw_asgn( __volatile__, volatile )
-rw_asgn( __volatile, volatile )
+rw(restrict)
-rw_asgn(__restrict,restrict)
-rw_asgn(__restrict__,restrict)
++d"__const=const" // gconv.h uses __const rather than const
++d"const=const" // ensure const expands to const.
-rw_asgn( asm, _up_to_brackets )
-rw_asgn( __asm, _up_to_brackets )
-rw_asgn( __asm__, _up_to_brackets )
// This re-definition of the various spellings of the asm keyword enables
// Lint to pass gracefully over expression-statements like:
// __asm __volatile ("fsqrt" : "=t" (__result) : "0" (__x));
// But it may be necessary to suppress certain error messages that are
// triggered by tokens that are part of an assembly declaration or
// statement. For example:
-d"__asm__(p...)=/*lint -e{19}*/ __asm__(p)"
// ...causes Lint to be quiet about the semicolon that follows an
// __asm__() declaration. Note, the -e{N} form of suppression takes
// effect only for the forward-declaration, definition or
// [possibly-compound] statement that immediately follows. Because a
// semicolon is seen as a declaration-terminator, Error 19 will be
// re-enabled immediately after the semicolon in '__asm__(...);'.
// (The elipsis after the macro parameter p allows zero or more commas to
// appear in the operand.)
//
// If you encounter other diagnostics that appear to need suppression in
// or near assembly regions, please let us know!
//
-esym(123,__asm__)
-rw_asgn(__alignof__,__alignof)
// "__extension__" is GCC's way of allowing the use of non-standard
// constructs in a strict Standard-conforming mode. We don't currently
// have explicit support for it, but we can use local suppressions. For
// example, we can use -e(160) so that we will not see any Errors about
// GNU statement-expressions wrapped in __extension__().
++d"__extension__=/*lint -e(160) */"
++d"__null=0"
+rw(_to_semi) // needed for the two macros above.
+rw(__typeof__) // activate __typeof__ keyword
-d"__typeof=__typeof__" // an alternative to using __typeof__
-rw(__except) // This MS reserved word is used as an identifier
+rw( __complex__, __real__, __imag__ ) // reserved words that can be ignored.
++d"__builtin_strchr=(char*)" // permits the inline definition ...
++d"__builtin_strpbrk=(char*)" // of these functions to be linted ...
++d"__builtin_strrchr=(char*)" // without drawing a complaint
++d"__builtin_strstr=(char*)" // about the use of a non-standard name
++d"__PRETTY_FUNCTION__=___function___" // lint defines ___function___ internally
++d"__FUNCTION__=___function___" // lint defines ___function___ internally
++d"__func__=___function___" // Some C++ modes suport the implicit __func__
// identifier.
-ident($)
// =========================================================
// Other options supporting GNU C/C++ syntax:
+fld // enables the processing of _L_abel _D_esignators E.g.:
// union { double d; int i; } u = { d: 3.141 };
// =========================================================
// Generally useful suppressions:
-wlib(1) // sets the warning level within library headers to 1
// (no warnings, just syntax errors). Comment out if you
// are actually linting library headers.
-elib(123) // 123 is really a warning, but it's in the "Error" range.
-elib(93) // allow newlines within quoted string arguments to macros
-elib(46) // allow bit fields to have integral types other than
// '_Bool' and 'int'.
-elibsym(628) // Suppress 628 for __builtin symbols.
-esym(528,__huge_val,__nan,__qnan,__qnanf,__snan,__snanf)
// We don't care if we don't reference some GNU functions
-esym(528,__gnu_malloc,__gnu_calloc)
// The following functions exhibit variable return modes.
// That is, they may equally-usefully be called for a value
// as called just for their effects. Accordingly we inhibit
// Warning 534 for these functions.
// Feel free to add to or subtract from this list.
-esym(534,close,creat,fclose,fprintf,fputc)
-esym(534,fputs,fscanf,fseek,fwrite,lseek,memcpy,memmove,memset)
-esym(534,printf,puts,scanf,sprintf,sscanf,strcat,strcpy)
-esym(534,strncat,strncpy,unlink,write)
// For non-ANSI compilers we suppress messages 515 and 516
// for functions known to have variable argument lists.
// For ANSI compilers, header files should take care of this.
-esym(515,fprintf,printf,sprintf,fscanf,scanf,sscanf)
-esym(516,fprintf,printf,sprintf,fscanf,scanf,sscanf)
-esym(1702,*operator<<,*operator>>)
-esym(534,*operator<<,*operator>>)
-esym(1055,*__builtin*)
-esym(718,*__builtin*) // The compiler does not need these ...
-esym(746,*__builtin*) // declared and it knows their prototypes.

View File

@ -0,0 +1,5 @@
--i/usr/lib/gcc/x86_64-pc-linux-gnu/6.3.1/include
--i/usr/local/include
--i/usr/lib/gcc/x86_64-pc-linux-gnu/6.3.1/include-fixed
--i/usr/include

View File

@ -0,0 +1,319 @@
Using FlexeLint with GCC
These notes describe how to use the option file co-gcc.lnt which serves
as a replacement for the older co-gnu.lnt and co-gnu3.lnt options files.
--- Quick Start ---
If you just want a quick-and-dirty Lint configuration (one that enables
you to use Standard Library headers and system headers) then use the
makefile 'co-gcc.mak' (supplied with the Lint distribution) in an
invocation of GNU Make like so:
make -f co-gcc.mak
... which should generate the following files (provided that 'gcc', 'g++'
and 'awk' are each found in your $PATH):
lint_cmac.h
lint_cppmac.h
gcc-include-path.lnt
size-options.lnt
(co-gcc.lnt depends on these files, so they must be generated before you
do anything else.)
That's it! You should now be able to run:
flint co-gcc.lnt [source files]
Note that Lint must be able to find co-gcc.lnt and the files referenced
therein. If you want to keep them in a separate directory (e.g.,
/usr/local/etc/flint) from the one where you will invoke Lint (e.g.,
~/some-project/src), you'll need to specify the former with a '-i' option
so that Lint will know where to look. In that case, the invocation would
look like:
flint -i /usr/local/etc/flint co-gcc.lnt [source files]
If your project is compiled without any explicit command-line switches
other than '-c' then this invocation alone might be all that you need to
get started linting your project. Otherwise it probably won't suffice.
For a Lint configuration that better matches the way you compile your
code, you should at least read the 'usage' note at the top of co-gcc.mak.
For a motivation for the contents of co-gcc.mak, and to better understand
the configuration issues in general, please read on.
--- Introduction ---
The configuration of Lint for use with GCC-compiled sources is complicated
by two major issues:
First, GCC defines a large number of preprocessor macros internally (i.e.,
it defines a lot of macros for which there are no '#define' directives in
any source file that Lint can read.). Unless this issue is resolved for
each project, Lint will not see the same sequence of C/C++ tokens as GCC
when it tries to analyze your program, and as a result it will not see the
same set of declarations; consequently you'll see lots of spurious
messages because the analysis will reflect that of a program that is
truly ill-formed (unlike the program seen by GCC).
Second, GCC is aware of several built-in functions. Most of them can be
presented to Lint as ordinary forward-declarations of functions so as to
avoid undesired diagnostics claiming that these functions were not
declared before the first point of use. Note, these declarations do not
necessarily need to be presented to GCC.
--- Solving the Preprocessor Problem ---
Before we get started, we'll need an empty C source file. Call it
'empty.c' and save it to disk. Next, use your favorite command
interpreter environment (such as sh in Unix-like environments or cmd.exe
on Windows) and go to the directory containing 'empty.c'. Verify that you
can run GCC by doing the following:
gcc -v
If your environment is properly set up you should see a version string.
(You'll also want to verify that this is the same GCC executable used to
compile your sources; check the PATH environment variable or try running
'which gcc'.)
Assuming that worked, you can now try the following (and note that case,
as with C/C++ identifiers, is important.):
gcc -E -dM empty.c
On one system, we then see definitions like:
#define __DBL_MIN_EXP__ (-1021)
#define __FLT_MIN__ 1.17549435e-38F
#define __DEC64_DEN__ 0.000000000000001E-383DD
... followed by about a hundred more '#define' directives. What just
happened? We passed two options to gcc; the first one, '-E', means,
"don't run the compiler; just run the preprocessor". The option '-dM'
(not to be confused with '-DM', which is completely different) means,
"don't generate preprocessor output; instead, only dump all macro
definitions, including those defined internally".
With this output, we are now halfway to the point of having a preprocessor
configuration for Lint. First, let's redirect those macros to a file:
gcc -E -dM empty.c >lint_cmac.h
Next, let's test our configuration: make a simple C source file
containing the "Hello, world" program in a file called 't.c' (in the same
directory as 'empty.c')
#include <stdio.h>
int main () {
printf( "hello, world!\n" );
}
To lint this program, first copy the lnt file (co-gcc.lnt) and the
associated header (co-gcc.h) into the same directory. Next, create two
new empty files:
size-options.lnt
gcc-include-path.lnt
... and save them to disk. Then make a file called 'std.lnt' which will
(at first) contain only:
co-gcc.lnt
This tells Lint, "process the arguments in co-gcc.lnt". Two of those
arguments are:
-header(co-gcc.h) // #include's headers generated by GCC.
+libh(co-gcc.h) // Marks co-gcc.h as library code.
'-header(co-gcc.h)' means "behave as if each primary source file began
with '#include "co-gcc.h"'. (Note that co-gcc.h includes "lint_cmac.h"
when Lint runs in C language mode.)
Finally, try running:
/path/to/flint std.lnt t.c
... or, on Windows:
[drive-letter]:\path\to\lint-nt std.lnt t.c
Next we'll see output similar to the following:
FlexeLint for C/C++ (Unix/386) Vers. 9.00c, Copyright Gimpel Software
1985-2009
--- Module: t.c (C)
_
#include <stdio.h>
t.c 3 Error 322: Unable to open include file 'stdio.h'
What went wrong? The problem is that we haven't yet addressed the other
half of the preprocessor configuration, namely: the ordered sequence of
directories to search for system headers. Fortunately GCC already knows
this list and gives us a way to discover it. Just run:
gcc -c -v empty.c
On one system (specifically, Mac OS X on Intel), that yields a lot of
verbose output including these lines:
#include "..." search starts here:
#include <...> search starts here:
/usr/local/include
/usr/lib/gcc/i686-apple-darwin8/4.0.1/include
/usr/include
/System/Library/Frameworks
/Library/Frameworks
End of search list.
(Naturally, that list will look a bit different in different
environments.) To make Lint search for system headers in the same way, we
need to take that output from GCC and use it to make a set of options of
the form --i[directory]. E.g. on the same system, that means that in
gcc-include-path.lnt, I should place the following --i options:
--i/usr/local/include
--i/usr/lib/gcc/i686-apple-darwin8/4.0.1/include
--i/usr/include
--i/System/Library/Frameworks
--i/Library/Frameworks
(Note, arguments to Lint are processed in order, so the --i options must
appear before t.c or they will not take effect in time.)
In this case, none of the directory names contains a space, but if one of
them did we would have to surround its name with quotes as in:
--i"/usr/local/include"
Now let's try linting "hello, world" again:
/path/to/flint std.lnt t.c
This time we should see no error messages. Are we done yet? Not quite.
First, let's test our configuration against all of the C Standard Library
headers. Modify t.c to:
#include <assert.h>
#include <iso646.h>
#include <setjmp.h>
#include <stdio.h>
#include <time.h>
#include <ctype.h>
#include <limits.h>
#include <signal.h>
#include <stdlib.h>
#include <wchar.h>
#include <errno.h>
#include <locale.h>
#include <stdarg.h>
#include <string.h>
#include <wctype.h>
#include <float.h>
#include <math.h>
#include <stddef.h>
int main () {
printf( "hello, world!\n" );
}
... and try linting again:
/path/to/flint std.lnt t.c
This time you should see a number of messages; in particular, you should
see Info 766 issued for most of these headers since they were not used.
you may also see some legitimate warnings, and you may see an Error or two
about 'wchar_t'. (Note, if it seems as though your port of GCC recognizes
wchar_t as a keyword instead of an identifier then uncomment the use of
'+fwc' in your copy of co-gcc.lnt).
[NOTE: we should point out that the option -wlib(1) is in co-gcc.lnt for a
reason. Please note that we *strongly* recommend against the use of
options like -wlib(0) or -elib(*). If you see syntax error messages about
library header code, odds are that something is wrong with the Lint
configuration; so you'll do yourself no favors by silencing Lint when it
sees constructs that Lint's parser doesn't know how to handle. If you need
help with correcting your configuration, please check the Lint manual or
contact us.]
We should really be done now, right? Well, not quite. A remaining issue
is that the set of predefined macros (dumped into "lint_cmac.h" earlier)
depends not only on things like the target system and the version of GCC;
it also depends on the options that you pass to GCC when you compile your
program. E.g., if we invoke:
gcc -O3 -E -dM empty.c >lint_cmac.h
... then (with the version of GCC we tested) lint_cmac.h will no longer
contain a definition for the macro '__NO_INLINE__' and contains a new
definition for '__OPTIMIZE__'. So when you generate macros, you should be
careful to pass in the full set of options used when you compile.
Ideally, you should establish a target in your build system that
re-generates the predefined macro header whenever your build configuration
changes; that way you'll seldom need to think about it again and Lint's
preprocessor configuration will always match the compiler's.
Assuming you've generated the right set of predefined macros for your
build settings, you should now try Linting a single primary source file in
your project. Since we're just starting out, let's run with -w1 (i.e.,
with the warning level set to one) so that we can deal with any syntax
errors that pop up:
flint std.lnt -u -w1 some-project-file.c
Again, remember that syntax errors at this stage are likely due to a
misconfiguration; please check the Lint manual for likely remedies or
contact us if the solution is not obvious.
Once you've taken care of all syntax errors, try doing the same with all
project files. We recommend placing the name of each project file in a
.lnt file (often called project.lnt); e.g.:
file1.c
file2.c
[...etc.]
... and invoke Lint like so:
flint std.lnt -w1 project.lnt
When all syntax errors are resolved, you can begin turning on Warning
messages (i.e., those listed in section 17.4 of the Lint manual). You can
turn them on individually after '-w1' or you can instead use '-w2' and
then suppress the Warnings that are less severe. (For details on message
suppression, see section 5.2 of the Lint manual.)
At this point, you should be well-equipped to Lint any C program compiled
with GCC. However, C++ users have a couple more points to consider.
The command used to invoke GCC also affects the set of predefined macros.
Observe the difference in '#define' output when you invoke:
g++ -O3 -E -dM empty.c >lint_cppmac.h
diff lint_cmac.h lint_cppmac.h
Also, note that the list of directories to search for Standard Library
headers has some new additions when you use 'g++ -v -c empty.c' instead of
'gcc -v -c empty.c'. Your sequence of --i options should be set
accordingly.
That's about it for the preprocessor.
--- Size options ---
Finally, you'll need to establish sizes of primitive types. E.g. for a
64-bit platform this includes setting '-sp8' (indicating that pointers are
8 bytes wide). It often also involves setting '-sl8' (indicating that
'long' is eight bytes wide). As suggested earlier, the makefile
co-gcc.mak can generate these options for you.
If you find this tutorial to be lacking in some way, please contact us
(support@gimpel.com) with your suggestions for improvement.

View File

@ -0,0 +1,250 @@
#define __DBL_MIN_EXP__ (-1021)
#define __UINT_LEAST16_MAX__ 0xffff
#define __ATOMIC_ACQUIRE 2
#define __FLT_MIN__ 1.17549435082228750797e-38F
#define __GCC_IEC_559_COMPLEX 2
#define __UINT_LEAST8_TYPE__ unsigned char
#define __SIZEOF_FLOAT80__ 16
#define __INTMAX_C(c) c ## L
#define __CHAR_BIT__ 8
#define __UINT8_MAX__ 0xff
#define __WINT_MAX__ 0xffffffffU
#define __ORDER_LITTLE_ENDIAN__ 1234
#define __SIZE_MAX__ 0xffffffffffffffffUL
#define __WCHAR_MAX__ 0x7fffffff
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1
#define __DBL_DENORM_MIN__ ((double)4.94065645841246544177e-324L)
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1
#define __GCC_ATOMIC_CHAR_LOCK_FREE 2
#define __GCC_IEC_559 2
#define __FLT_EVAL_METHOD__ 0
#define __unix__ 1
#define __GCC_ATOMIC_CHAR32_T_LOCK_FREE 2
#define __x86_64 1
#define __UINT_FAST64_MAX__ 0xffffffffffffffffUL
#define __SIG_ATOMIC_TYPE__ int
#define __DBL_MIN_10_EXP__ (-307)
#define __FINITE_MATH_ONLY__ 0
#define __GNUC_PATCHLEVEL__ 1
#define __UINT_FAST8_MAX__ 0xff
#define __has_include(STR) __has_include__(STR)
#define __DEC64_MAX_EXP__ 385
#define __INT8_C(c) c
#define __UINT_LEAST64_MAX__ 0xffffffffffffffffUL
#define __SHRT_MAX__ 0x7fff
#define __LDBL_MAX__ 1.18973149535723176502e+4932L
#define __UINT_LEAST8_MAX__ 0xff
#define __GCC_ATOMIC_BOOL_LOCK_FREE 2
#define __UINTMAX_TYPE__ long unsigned int
#define __linux 1
#define __DEC32_EPSILON__ 1E-6DF
#define __unix 1
#define __UINT32_MAX__ 0xffffffffU
#define __LDBL_MAX_EXP__ 16384
#define __WINT_MIN__ 0U
#define __linux__ 1
#define __SCHAR_MAX__ 0x7f
#define __WCHAR_MIN__ (-__WCHAR_MAX__ - 1)
#define __INT64_C(c) c ## L
#define __DBL_DIG__ 15
#define __GCC_ATOMIC_POINTER_LOCK_FREE 2
#define __SIZEOF_INT__ 4
#define __SIZEOF_POINTER__ 8
#define __USER_LABEL_PREFIX__
#define __STDC_HOSTED__ 1
#define __LDBL_HAS_INFINITY__ 1
#define __FLT_EPSILON__ 1.19209289550781250000e-7F
#define __LDBL_MIN__ 3.36210314311209350626e-4932L
#define __STDC_UTF_16__ 1
#define __DEC32_MAX__ 9.999999E96DF
#define __INT32_MAX__ 0x7fffffff
#define __SIZEOF_LONG__ 8
#define __STDC_IEC_559__ 1
#define __STDC_ISO_10646__ 201505L
#define __UINT16_C(c) c
#define __DECIMAL_DIG__ 21
#define __gnu_linux__ 1
#define __has_include_next(STR) __has_include_next__(STR)
#define __LDBL_HAS_QUIET_NAN__ 1
#define __GNUC__ 6
#define __MMX__ 1
#define __FLT_HAS_DENORM__ 1
#define __SIZEOF_LONG_DOUBLE__ 16
#define __BIGGEST_ALIGNMENT__ 16
#define __DBL_MAX__ ((double)1.79769313486231570815e+308L)
#define __INT_FAST32_MAX__ 0x7fffffffffffffffL
#define __DBL_HAS_INFINITY__ 1
#define __DEC32_MIN_EXP__ (-94)
#define __INT_FAST16_TYPE__ long int
#define __LDBL_HAS_DENORM__ 1
#define __DEC128_MAX__ 9.999999999999999999999999999999999E6144DL
#define __INT_LEAST32_MAX__ 0x7fffffff
#define __DEC32_MIN__ 1E-95DF
#define __DBL_MAX_EXP__ 1024
#define __DEC128_EPSILON__ 1E-33DL
#define __SSE2_MATH__ 1
#define __ATOMIC_HLE_RELEASE 131072
#define __PTRDIFF_MAX__ 0x7fffffffffffffffL
#define __amd64 1
#define __STDC_NO_THREADS__ 1
#define __ATOMIC_HLE_ACQUIRE 65536
#define __LONG_LONG_MAX__ 0x7fffffffffffffffLL
#define __SIZEOF_SIZE_T__ 8
#define __SIZEOF_WINT_T__ 4
#define __GCC_HAVE_DWARF2_CFI_ASM 1
#define __GXX_ABI_VERSION 1010
#define __FLT_MIN_EXP__ (-125)
#define __INT_FAST64_TYPE__ long int
#define __DBL_MIN__ ((double)2.22507385850720138309e-308L)
#define __LP64__ 1
#define __DECIMAL_BID_FORMAT__ 1
#define __DEC128_MIN__ 1E-6143DL
#define __REGISTER_PREFIX__
#define __UINT16_MAX__ 0xffff
#define __DBL_HAS_DENORM__ 1
#define __UINT8_TYPE__ unsigned char
#define __NO_INLINE__ 1
#define __FLT_MANT_DIG__ 24
#define __VERSION__ "6.3.1 20170306"
#define __UINT64_C(c) c ## UL
#define _STDC_PREDEF_H 1
#define __GCC_ATOMIC_INT_LOCK_FREE 2
#define __FLOAT_WORD_ORDER__ __ORDER_LITTLE_ENDIAN__
#define __STDC_IEC_559_COMPLEX__ 1
#define __INT32_C(c) c
#define __DEC64_EPSILON__ 1E-15DD
#define __ORDER_PDP_ENDIAN__ 3412
#define __DEC128_MIN_EXP__ (-6142)
#define __INT_FAST32_TYPE__ long int
#define __UINT_LEAST16_TYPE__ short unsigned int
#define unix 1
#define __INT16_MAX__ 0x7fff
#define __SIZE_TYPE__ long unsigned int
#define __UINT64_MAX__ 0xffffffffffffffffUL
#define __INT8_TYPE__ signed char
#define __ELF__ 1
#define __GCC_ASM_FLAG_OUTPUTS__ 1
#define __FLT_RADIX__ 2
#define __INT_LEAST16_TYPE__ short int
#define __LDBL_EPSILON__ 1.08420217248550443401e-19L
#define __UINTMAX_C(c) c ## UL
#define __SSE_MATH__ 1
#define __k8 1
#define __SIG_ATOMIC_MAX__ 0x7fffffff
#define __GCC_ATOMIC_WCHAR_T_LOCK_FREE 2
#define __SIZEOF_PTRDIFF_T__ 8
#define __x86_64__ 1
#define __DEC32_SUBNORMAL_MIN__ 0.000001E-95DF
#define __INT_FAST16_MAX__ 0x7fffffffffffffffL
#define __UINT_FAST32_MAX__ 0xffffffffffffffffUL
#define __UINT_LEAST64_TYPE__ long unsigned int
#define __FLT_HAS_QUIET_NAN__ 1
#define __FLT_MAX_10_EXP__ 38
#define __LONG_MAX__ 0x7fffffffffffffffL
#define __DEC128_SUBNORMAL_MIN__ 0.000000000000000000000000000000001E-6143DL
#define __FLT_HAS_INFINITY__ 1
#define __UINT_FAST16_TYPE__ long unsigned int
#define __DEC64_MAX__ 9.999999999999999E384DD
#define __CHAR16_TYPE__ short unsigned int
#define __PRAGMA_REDEFINE_EXTNAME 1
#define __SEG_FS 1
#define __INT_LEAST16_MAX__ 0x7fff
#define __DEC64_MANT_DIG__ 16
#define __INT64_MAX__ 0x7fffffffffffffffL
#define __UINT_LEAST32_MAX__ 0xffffffffU
#define __SEG_GS 1
#define __GCC_ATOMIC_LONG_LOCK_FREE 2
#define __INT_LEAST64_TYPE__ long int
#define __INT16_TYPE__ short int
#define __INT_LEAST8_TYPE__ signed char
#define __STDC_VERSION__ 201112L
#define __DEC32_MAX_EXP__ 97
#define __INT_FAST8_MAX__ 0x7f
#define __INTPTR_MAX__ 0x7fffffffffffffffL
#define linux 1
#define __SSE2__ 1
#define __LDBL_MANT_DIG__ 64
#define __DBL_HAS_QUIET_NAN__ 1
#define __SIG_ATOMIC_MIN__ (-__SIG_ATOMIC_MAX__ - 1)
#define __code_model_small__ 1
#define __k8__ 1
#define __INTPTR_TYPE__ long int
#define __UINT16_TYPE__ short unsigned int
#define __WCHAR_TYPE__ int
#define __SIZEOF_FLOAT__ 4
#define __UINTPTR_MAX__ 0xffffffffffffffffUL
#define __DEC64_MIN_EXP__ (-382)
#define __INT_FAST64_MAX__ 0x7fffffffffffffffL
#define __GCC_ATOMIC_TEST_AND_SET_TRUEVAL 1
#define __FLT_DIG__ 6
#define __UINT_FAST64_TYPE__ long unsigned int
#define __INT_MAX__ 0x7fffffff
#define __amd64__ 1
#define __INT64_TYPE__ long int
#define __FLT_MAX_EXP__ 128
#define __ORDER_BIG_ENDIAN__ 4321
#define __DBL_MANT_DIG__ 53
#define __SIZEOF_FLOAT128__ 16
#define __INT_LEAST64_MAX__ 0x7fffffffffffffffL
#define __GCC_ATOMIC_CHAR16_T_LOCK_FREE 2
#define __DEC64_MIN__ 1E-383DD
#define __WINT_TYPE__ unsigned int
#define __UINT_LEAST32_TYPE__ unsigned int
#define __SIZEOF_SHORT__ 2
#define __SSE__ 1
#define __LDBL_MIN_EXP__ (-16381)
#define __INT_LEAST8_MAX__ 0x7f
#define __SIZEOF_INT128__ 16
#define __LDBL_MAX_10_EXP__ 4932
#define __ATOMIC_RELAXED 0
#define __DBL_EPSILON__ ((double)2.22044604925031308085e-16L)
#define _LP64 1
#define __UINT8_C(c) c
#define __INT_LEAST32_TYPE__ int
#define __SIZEOF_WCHAR_T__ 4
#define __UINT64_TYPE__ long unsigned int
#define __INT_FAST8_TYPE__ signed char
#define __GNUC_STDC_INLINE__ 1
#define __DBL_DECIMAL_DIG__ 17
#define __STDC_UTF_32__ 1
#define __FXSR__ 1
#define __DEC_EVAL_METHOD__ 2
#define __UINT32_C(c) c ## U
#define __INTMAX_MAX__ 0x7fffffffffffffffL
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
#define __FLT_DENORM_MIN__ 1.40129846432481707092e-45F
#define __INT8_MAX__ 0x7f
#define __UINT_FAST32_TYPE__ long unsigned int
#define __CHAR32_TYPE__ unsigned int
#define __FLT_MAX__ 3.40282346638528859812e+38F
#define __INT32_TYPE__ int
#define __SIZEOF_DOUBLE__ 8
#define __FLT_MIN_10_EXP__ (-37)
#define __INTMAX_TYPE__ long int
#define __DEC128_MAX_EXP__ 6145
#define __ATOMIC_CONSUME 1
#define __GNUC_MINOR__ 3
#define __UINTMAX_MAX__ 0xffffffffffffffffUL
#define __DEC32_MANT_DIG__ 7
#define __DBL_MAX_10_EXP__ 308
#define __LDBL_DENORM_MIN__ 3.64519953188247460253e-4951L
#define __INT16_C(c) c
#define __STDC__ 1
#define __PTRDIFF_TYPE__ long int
#define __ATOMIC_SEQ_CST 5
#define __UINT32_TYPE__ unsigned int
#define __UINTPTR_TYPE__ long unsigned int
#define __DEC64_SUBNORMAL_MIN__ 0.000000000000001E-383DD
#define __DEC128_MANT_DIG__ 34
#define __LDBL_MIN_10_EXP__ (-4931)
#define __SIZEOF_LONG_LONG__ 8
#define __GCC_ATOMIC_LLONG_LOCK_FREE 2
#define __LDBL_DIG__ 18
#define __FLT_DECIMAL_DIG__ 9
#define __UINT_FAST16_MAX__ 0xffffffffffffffffUL
#define __GCC_ATOMIC_SHORT_LOCK_FREE 2
#define __UINT_FAST8_TYPE__ unsigned char
#define __ATOMIC_ACQ_REL 4
#define __ATOMIC_RELEASE 3

View File

@ -0,0 +1,85 @@
# This file contains functions and configurations for generating PC-Lint build
# targets for your CMake projects.
set(PC_LINT_EXECUTABLE "lint-nt.exe" CACHE STRING "full path to the pc-lint executable. NOT the generated lin.bat")
set(PC_LINT_CONFIG_DIR "${PROJECT_SOURCE_DIR}/lint/gnu" CACHE STRING "full path to the directory containing pc-lint configuration files")
set(PC_LINT_USER_FLAGS "-b" CACHE STRING "additional pc-lint command line options -- some flags of pc-lint cannot be set in option files (most notably -b)")
# a phony target which causes all available *_LINT targets to be executed
add_custom_target(ALL_LINT)
# add_pc_lint(target source1 [source2 ...])
#
# Takes a list of source files and generates a build target which can be used
# for linting all files
#
# The generated lint commands assume that a top-level config file named
# 'std.lnt' resides in the configuration directory 'PC_LINT_CONFIG_DIR'. This
# config file must include all other config files. This is standard lint
# behaviour.
#
# Parameters:
# - target: the name of the target to which the sources belong. You will get a
# new build target named ${target}_LINT
# - source1 ... : a list of source files to be linted. Just pass the same list
# as you passed for add_executable or add_library. Everything except
# C and CPP files (*.c, *.cpp, *.cxx) will be filtered out.
#
# Example:
# If you have a CMakeLists.txt which generates an executable like this:
#
# set(MAIN_SOURCES main.c foo.c bar.c)
# add_executable(main ${MAIN_SOURCES})
#
# include this file
#
# include(/path/to/pc_lint.cmake)
#
# and add a line to generate the main_LINT target
#
# if(COMMAND add_pc_lint)
# add_pc_lint(main ${MAIN_SOURCES})
# endif(COMMAND add_pc_lint)
#
function(add_pc_lint target)
get_directory_property(lint_include_directories INCLUDE_DIRECTORIES)
get_directory_property(lint_defines COMPILE_DEFINITIONS)
# let's get those elephants across the alps
# prepend each include directory with "-i"; also quotes the directory
set(lint_include_directories_transformed)
foreach(include_dir ${lint_include_directories})
list(APPEND lint_include_directories_transformed -i"${include_dir}")
endforeach(include_dir)
# prepend each definition with "-d"
set(lint_defines_transformed)
foreach(definition ${lint_defines})
list(APPEND lint_defines_transformed -d${definition})
endforeach(definition)
# list of all commands, one for each given source file
set(pc_lint_commands)
foreach(sourcefile ${ARGN})
# only include c and cpp files
if( sourcefile MATCHES \\.c$|\\.cxx$|\\.cpp$ )
# make filename absolute
get_filename_component(sourcefile_abs ${sourcefile} ABSOLUTE)
# create command line for linting one source file and add it to the list of commands
list(APPEND pc_lint_commands
COMMAND ${PC_LINT_EXECUTABLE}
-i"${PC_LINT_CONFIG_DIR}" std.lnt
"-u" ${PC_LINT_USER_FLAGS}
${lint_include_directories_transformed}
${lint_defines_transformed}
${sourcefile_abs})
endif()
endforeach(sourcefile)
# add a custom target consisting of all the commands generated above
add_custom_target(${target}_LINT ${pc_lint_commands} VERBATIM)
# make the ALL_LINT target depend on each and every *_LINT target
add_dependencies(ALL_LINT ${target}_LINT)
endfunction(add_pc_lint)

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@
co-gcc.lnt

View File

@ -0,0 +1,42 @@
// ---------------------------------------------------------------------
// This file is provided by Gimpel Software (www.gimpel.com) for use with
// its products PC-lint and FlexeLint.
//
// Redistribution and use of this file, with or without modification, is
// permitted provided that any such redistribution retains this notice.
// ---------------------------------------------------------------------
#ifndef LINT_SUPPORT_CO_MSC100_H_
#define LINT_SUPPORT_CO_MSC100_H_
// co-msc100.h --
// This header is automatically included in every module if you use
// co-msc100.lnt. (There is a -header(co-msc100.h) option therein
// for this purpose.)
// Microsoft's C++11 implementation does not yet include built-in support
// for the new character types, so we need to disable the relevant
// keywords here. (This must be done before the inclusion of any other
// header file because Microsoft's library headers contain declarations of
// typedef names with the same spelling.)
//lint -rw(char16_t,char32_t)
// Next we must compensate for the fact that class typeinfo is available
// for use in the MSC compilers without an explicit definition. According
// to the standard this class definition is not (available by default).
#ifdef __cplusplus
#include <typeinfo>
#else // C mode
// co-msc100.lnt defines some macros that the Microsoft compiler defines
// in C++ modes but not in C mode; we must un-define them here:
#undef _CPPRTTI
#undef _NATIVE_WCHAR_T_DEFINED
#undef _WCHAR_T_DEFINED
#undef _NATIVE_NULLPTR_SUPPORTED
#endif
#endif /* LINT_SUPPORT_CO_MSC100_H_ */

View File

@ -0,0 +1,459 @@
/* Date Stamp */ -d"_lint_co_msc100_lnt=co-msc100.lnt modified 19-Sep-2013"
/* To document usage use: -message( "Using " _lint_co_msc100_lnt ) */
// ---------------------------------------------------------------------
// This file is provided by Gimpel Software (www.gimpel.com) for use with
// its products PC-lint and FlexeLint.
//
// Redistribution and use of this file, with or without modification, is
// permitted provided that any such redistribution retains this notice.
// ---------------------------------------------------------------------
// co-msc100.lnt
// Compiler Options for Visual Studio for C/C++ Version 10.00
// (Visual Studio 2010)
// This file contains options to allow PC-lint to process source
// files for your compiler. It is used as follows:
//
// lint co-msc100.lnt source-file(s)
//
// (See macros-msc.c and/or macros-msc.cpp for details.)
// Section 1: options independent of the use of the automatic macro
// generator (macros-msc.cpp)
//
-cmsc
-A(C++2011)
+compiler(search_actively_including_stack)
-si4 // integers are 4 bytes
-sp4 // pointers are 4 bytes too.
// We now support __declspec directly so that the following
// option is now commented out. If trouble ensues you can
// once again disable __declspec through this option.
// -d__declspec()= // ignore this construct
-d_declspec=__declspec // the single '_' version is occasionally used
// while processing compiler (library) header files ...
-wlib(1) // sets the warning level within library headers to 1
// (no warnings, just syntax errors). Comment out if you
// are actually linting library headers. This
// option makes obsolete options of the form -elib(axxx) where
// xxx >= 400 which may be retained for historical reasons.
-elib(1111) // Some VC++ headers contain explicit specializations at class
// scope.
-elib(19) // useless declarations (lone semicolons)
-elib(123) // function-like macro name used as non macro
-elib(652) // suppress message about #define of earlier declared symbols
-elib(762) // suppress message about multiple identical declarations and
-elib(760) // suppress message about multiple identical macro defs
-elib(514) // allow #if <boolean> | <boolean>
-elib(553) // undefined preprocessor variables assumed 0
-elib(1081) // suspicious object argument to an object parameter
-elib(726) // extraneous comma in enum definition
// SREGS, WORDREGS, BYTEREGS are defined in both bios.h and dos.h
// and accordingly you MAY get type differences based on 'origin'.
// If so, use the following options:
// -etd(origin)
// -elib(770)
-format=%(%f(%l)\s:\s%)%t\s%n:\s%m
// error format similar to MSC
// Note that %c can also be used to specify column
-e46 // allows bit-fields to be other than int or unsigned
+fan // allow anonymous unions
+fdi // Use directory of the including file
+fbo // enable the bool type
+fwm // wprintf format codes are not standard
-fdh // do not append a .h to header names
-esym(123,min,max) // allows users to use min, max as variables
+rw(__inline) // activate the __inline keyword
-rw_asgn(__nullptr,nullptr)
-e19 // Suppress errors about lone semicolons
+ppw(import) // activate #import
-d_inline=__inline // _inline is the same as __inline
-sld8 // sizeof(long double) is 8.
-function(exit,_exit) // _exit() is like exit()
-function(exit,_assert) // _assert() is like exit()
-emacro(506,assert) // don't warn about constant value Boolean
-emacro(734,putc) // don't complain about items being too large.
-emacro(415,_FP_SEG) // access of out-of-bounds pointer
-emacro(740,FP_SEG,FP_OFF) // unusual casts
-emacro((???),va_arg) // the va_arg() macro can yield 415, 416, 661, 662
// 796 and 797 (out-of-bounds errors).
-emacro((???),va_start) // the same applies to va_start
-emacro(413,offsetof) // use of NULL pointer creates a stir
-emacro(545,offsetof) // addressing an array member is OK
-emacro(845,RGB) // a common use of RGB uses a operator that produces a 0
-e793 // inhibit 'ANSI limit reached' --
// limits are impractically low with MSVC headers
-esym(628,eof) // failure to provide argument information for eof()
-esym(773,L_tmpnam) // defined with an unparenthesized '+'
-esym(438,_acp) // USES_CONVERSION assigns to _acp.
-emacro(571,__isascii) // don't warn about the unusual cast
-emacro(522,UNREFERENCED_PARAMETER) // don't complain about a lack of
// side-effects
-emacro(648,CDN_*) // ignore unsigned overflow
-emacro(648,OIVN_*) // ignore unsigned overflow
-emacro(648,TTN_*) // ignore unsigned overflow
-emacro(648,TVN_*) // ignore unsigned overflow
-emacro(648,TBN_*) // ignore unsigned overflow
// The following functions exhibit variable return modes.
// That is, they may equally-usefully be called for a value
// as called just for their effects. Accordingly we inhibit
// Warning 534 for these functions.
// Feel free to add to or subtract from this list.
-esym(534,close,creat,fclose,fflush,_flsbuf,fprintf,fputc)
-esym(534,fputs,fscanf,fseek,fwrite,lseek,memcpy,memmove,memset)
-esym(534,printf,puts,scanf,sprintf,sscanf,strcat,strcpy)
-esym(534,strncat,strncpy,unlink,write)
// These are the wide char variants of printf-scanf family
-wprintf( 1, wprintf )
-wprintf( 3, fwprintf, swprintf )
-wscanf( 1, wscanf )
-wscanf( 2, fwscanf, swscanf )
// These are substitutions for sprintf
-printf( 3, StringCbPrintfA )
-printf( 3, StringCchPrintfA )
-wprintf( 3, StringCbPrintfW )
-wprintf( 3, StringCchPrintfW )
// The following options are used to adjust our function mimicry to
// the actual library as provided by MS.
-function( wcstombs(1) ) // remove the check for a NULL first arg to wcstombs()
// The following options are required by most compilers to
// noiselessly process iostream.h
-elib(1717) // empty prototypes
-elib(522) // function return value ignored
-elib(1053) // prototypes cannot be distinguished
-elib(1721) // unusual operator =() declaration
-elib(1720) // assignment op has non-const parameter
-elib(655) // bitwise operator combining compatible enum's
-elib(641) // converting enum's to int
-elib(537) // repeated include file (ios.h)
-elib(1511) // member (rdbuf) hides nonvirtual member
-elib(1712) // default constructor not defined for class
-elib(1736) // redundant access specifier
-esym(1702,operator<<,operator>>) // both a member and an ordinary function
// These functions return things that are frequently ignored.
-esym(534,*operator<<,*operator>>)
// The following additional options seem to be needed.
-elib(506) // constant value Boolean
-elib(620) // el or one? (some constants end in 'l' not 'L')
-elib(648) // overflow in computing constant (3<<16)
-elib(659) // nothing fold_NATIVE_WCHAR_T_DEFINEDlows '}' on some line
-elib(723) // suspicious use of '='
-elib(747) // significant prototype coercion
-elib(740) // unusual pointer casts
-elib(1007) // virtual functions within extern "C" block
-elib(1029) // default argument repeated -- can't dist. char, signed char
-elib(1055) // call to rdbuf() questioned?
-elib(1504) // apparently useless structs
-elib(1708,1709) // minor C/C++ declaration conflict
-elib(1707) // operator new declared w/o 'static'
-elib(1722) // assignment op does not return reference
-elib(149) // default argument found in C code.
-elib(578) // declaration of time hides delaration of global time().
-elib(761) // two equivalent typedef declarations
-elib(1065) // same name declared as "C" and not "C"
-elib(1066) // same name declared as "C" and not "C"
-elib(1704) // constructor with private access declaration
-elib(1735) // default parameter within virtual function
-elib(773) // macros that look like unparenthesized expressions
-elib(806) // 1-bit bitfields typed int
-elib(1501) // 0-length data members
-elib(1510) // base class has no destructor
-elib(1516) // data member hides inherited member
-elib(1509) // base class destructor is not virtual
// Special Notice: You may be receiving mysterious 1058 errors
// when you use "iomanipulator"s. For example:
// cout << setw(4) << 4;
// results in Error 1058 (assigning a const to a ref) because the
// manipulator setw returns a non-lvalue which is assigned to a reference.
// This reflects an oversight in the Microsoft header file: iomanip.h
// Therein you may change the declaration:
// friend ostream& operator<<(iostream& s, IOMANIP(T) & sm) { ...
// to:
// friend ostream& operator<<(iostream& s, const IOMANIP(T) & sm) { ...
// to reflect the fact that sm is not modified by this function.
+fll // enable long long
// In the following option we define __uuidof() and suppress
// Errors 50 and 69 and 1924 in exprs. containing same
-d"__uuidof()= /*lint --e(50,69,1924) */ (_GUID)0"
-esym(123,FD_SET) // defined as macro and as typedef
-esym(1726,endl,ends) // taking the address of an overloaded function
-esym(18,Data_t::Data_t) // definition not matching declaration
-elib(10) // expecting ')' -- comdef.h has a: #if defined( id
-elib(43) // vacuous array within _MIDL_FORMAT_STRING
-elib(602) // benign comment within comment
-elib(657) // declaring "anonymous struct" in union _LARGE_INTEGER
-elib(799) // long numerical constant for max. __int64
-elib(1502) // nothrow has no data members
-elib(1505) // no access specifier in base class specifier
-elib(1515) // AFX_THREAD_STATE member has no default constructor
-elib(1706) // Unusual declaration with a scope operator
-elib(1725) // data member is a reference
-elib(1548) // conflicting exception specifications
-elib(1737) // hiding global operator new
-elib(1739) // binary operator should be non-member function
-elib(1748) // non-virtual base class included twice
-elib(1759) // post-fix operator returns a reference
// Add elements of ole automation
lib-ole.lnt
// Options required for .net
-d_stdcall=__stdcall // make _stdcall equivalent to __stdcall
-d__interface=class // treat an interface the same as a class
-d__unaligned= // pass over the __unaligned keyword
-d__w64= // ignore this identifier
-esym(40,DLGPROC) // used before being defined
-elib(146) // assuming binary constant
-elib(1015) // GetDefaultThreads not found in class
+ppw(using) // ignore #using for now.
-d__pragma(x)= // ignore the pragma extension
+rw(__ptr64) // additional qualifier
+rw_asgn(__thiscall,fortran) // additional qualifier
-"d__identifier(x)=___identifier x"
// treat C++ keyword x as an identifier
-elibsym(1512) // base class destructor not virtual
-d__TIMESTAMP__="Mon Jan 01 00:00:00 2010"
-d__COUNTER__=__lint__COUNTER__
-d__FUNCDNAME__="MyFunc"
-d__FUNCSIG__="MyFunc"
-d__FUNCTION__=___function___
-dinitonly= // Compiler should catch miss-uses.
// Lint can just skip over it.
-"dliteral=static const" // Documentation says they are
// equivalent for member data.
// __try_cast is like dynamic_cast (except the former throws where
// the latter returns 0).
-d__try_cast=dynamic_cast
+rw(__restrict) // reserved word
// Partial support for the "old" (VC++ 2003) Managed Extensions
// syntax:
+rw( __gc, __value, __nogc, __pin, __ptr32, __ptr64 )
-$ // $ can be used in identifiers
+rw( __allowed_on_parameter )
+rw( __allowed_on_function )
+rw( __allowed_on_typedecl )
+rw( __allowed_on_return )
+rw( __allowed_on_struct )
+rw( __allowed_on_function_or_typedecl )
+rw( __allowed_on_field )
+rw( __allowed_on_parameter_or_return )
+rw( __allowed_on_function )
+rw( *type_traits ) //type traits support
+e1942 // This Elective Note alerts the user to the non-standard
// way in which MS handles originally-dependent base classes.
// E.g. template<class T> class A : T { ... x ... };
// Should T be searched for "x" during instantiation?
// the standard says "no", MS does.
-header(co-msc100.h) // implicitly includes <typeinfo>. (Needed because
// MSVC 9 implicitly declares class type_info.)
// Section 2: options that should be commented out if you use the
// automatic macro generator (macros-msc.cpp)
// Note, a macro option of the form:
// -dA{1}
// has the same effect as:
// -dA=1
// or:
// -d"A=1"
// The curly-brace version of the syntax is appropriate for
// macro-scavenging (the method we used to generate the macro options
// below). For details, see notes on the -scavenge() option in section
// 5.8.3 in the Lint manual. See also the macro generator file,
// macros-msc.cpp, which follows the form of -scavenge() output.
// We generated the options in this section with the following commands:
// %VSInstallDir%\vc\bin\vcvars32.bat
// cl /EP /C macros-msc.cpp
// The options for other build configurations will probably differ (which
// is why you should comment out the following if you use the macro
// generator).
// Also note: some of the following are defined for C++ mode but not for C
// mode; but there's no need to comment them out here because they are
// conditionally #undef'd in co-msc100.h.
-d_CPPRTTI{1}
//
// Defined for code compiled with /GR (Enable Run-Time Type
// Information).
//
-d_INTEGRAL_MAX_BITS{64}
//
// Reports the maximum size (in bits) for an integral type.
//
// NOTE:
// When generating 64-bit code, the definition for _M_IX86 must be
// commented out.
-d_M_IX86{600}
//
// Defined for x86 processors. See the "Values for _M_IX86 table" (in
// Microsoft's preprocessor documentation) for more information. This
// is not defined for x64 processors.
//
-d_M_IX86_FP{0}
//
// Expands to a value indicating which /arch compiler option was used:
//
// 0 if /arch was not used.
//
// 1 if /arch:SSE was used.
//
// 2 if /arch:SSE2 was used.
//
// See /arch (Minimum CPU Architecture) for more information.
//
-d_MSC_BUILD{1}
//
// Evaluates to the revision number component of the compiler's
// version number. The revision number is the fourth component of the
// period-delimited version number. For example, if the version number
// of the Visual C++ compiler is 15.00.20706.01, the _MSC_BUILD macro
// evaluates to 1.
//
-d_MSC_EXTENSIONS{1}
//
// This macro is defined when you compile with the /Ze compiler option
// (the default). Its value, when defined, is 1.
//
-d_MSC_FULL_VER{160030319}
//
// Evaluates to the major, minor, and build number components of the
// compiler's version number. The major number is the first component
// of the period-delimited version number, the minor number is the
// second component, and the build number is the third component. For
// example, if the version number of the Visual C++ compiler is
// 15.00.20706.01, the _MSC_FULL_VER macro evaluates to 150020706.
// Type cl /? at the command line to view the compiler's version
// number.
//
-d_MSC_VER{1600}
//
// Evaluates to the major and minor number components of the
// compiler's version number. The major number is the first component
// of the period-delimited version number and the minor number is the
// second component.
//
// For example, if the version number of the Visual C++ compiler is
// 15.00.20706.01, the _MSC_VER macro evaluates to 1500.
//
// In Visual Studio 2010, _MSC_VER is defined as 1600.
//
-d_MT{1}
//
// Defined when /MD or /MDd (Multithreaded DLL) or /MT or /MTd
// (Multithreaded) is specified.
//
-d_NATIVE_WCHAR_T_DEFINED{1}
//
// Defined when /Zc:wchar_t is used.
//
-d_WCHAR_T_DEFINED{1}
//
// Defined when /Zc:wchar_t is used or if wchar_t is defined in a
// system header file included in your project.
//
-d_WIN32{1}
//
// Defined for applications for Win32 and Win64. Always defined.
//
/**** Undocumented predefined macros follow ****/
-d_NATIVE_NULLPTR_SUPPORTED{1}
// Section 3: options that should remain commented out if you use the
// automatic macro generator (macros-msc.cpp)
// When compiling with /J, use:
//+fcu // Plain char is unsigned
//-d_CHAR_UNSIGNED
// When compiling with /clr, /clr:pure or /clr:safe, use:
//-d__cplusplus_cli=200406 // for all 3
//-d_M_CEE_PURE // for /clr:pure
//-d_M_CEE_SAFE // for /clr:safe
//-d_MANAGED // for /clr
// When using any /clr form, use:
//-d_M_CEE
// When compiling with /GX or /EH, use:
//-d_CPPUNWIND // Enable Exception Handling
// When compiling for Win64, use:
//-d_WIN64
// When compiling with /Wp64, use:
//-d_Wp64 // 64-bit portability
// Be sure to define your platform if any of the following apply:
//-d_M_ALPHA // For DEC ALPHA platforms
//-d_M_IA64 // For Itanium 64-bit processors
//-d_M_X64 // For x64 processors
// When compiling with the /RTC option, use:
//-d__MSVC_RUNTIME_CHECKS // Using such checks
// When compiling with /openmp, use:
//-d_OPENMP=200203 // OpenMP specification date
// When compiling with /Zl, use:
//-d_VC_NODEFAULTLIB // Omit default library name in *.obj file
/* DLL's or Multithreads? Enable the following:
-d_AFXDLL // making a DLL
-d_DLL // ditto
*/

View File

@ -0,0 +1,221 @@
/* Date Stamp */ -d"_lint_env_vc10_lnt=env-vc10.lnt modified 22-Feb-2012"
/* To document usage use: -message( "Using " _lint_env_vc10_lnt ) */
// ---------------------------------------------------------------------
// This file is provided by Gimpel Software (www.gimpel.com) for use with
// its products PC-lint and FlexeLint.
//
// Redistribution and use of this file, with or without modification, is
// permitted provided that any such redistribution retains this notice.
// ---------------------------------------------------------------------
/*
env-vc10.lnt: environment parameters for Microsoft's Visual C++ 10.0
If you are using Microsoft Visual Studio 2010 and you wish to invoke
PC-lint from that environment then add one or more commands to the
Tools menu as follows.
Simple Check
------------
For example, to add a simple facility to lint the current file you
may do the following:
1. From the Tools Menu choose "External Tools ..."
2. Click the "Add" button.
3. You will now be able to enter the fields of this Tool.
Modify them so that they approximate the following:
Title: PC-lint (Simple Check)
Command: c:\lint\lint-nt.exe
Arguments:
-i"c:\lint" std.lnt env-vc10.lnt "$(ItemFileName)$(ItemExt)"
Initial Directory: $(ItemDir)
X_Use Output Window __Prompt for arguments __Close on exit
Please note that you will have to change the "Command:" path if
the PC-lint Installation Directory is anything other than c:\lint
and you will have to change the "Arguments:" line if the
Configuration Directory is anything other than c:\lint
4. Select OK to return to the main environment.
This will result in the Tools menu containing the additional item
"PC-lint (Simple Check)". Checking 'X' on 'Use Output Window' is
important because in this way you can advance from error to error
using the F8 key (Shift F8 to reverse).
Strings of the form $(...) are called macros and can be typed in
directly as shown or can be selected from a menu by clicking
a right arrow in the dialog box. $(ItemFileName) refers to the
file name of the currently edited file without its path and without
its extension. $(ItemExt) is its extension. $(ItemDir) represents
the file's directory.
You will probably want to advance your new tool upward into the
initial position of all tools while you are testing and modifying the
command. You can do this by using the "Move Up" button that appears
on the External Tools dialog.
The benefits of using "Initial Directory" are that file-names in lint
error messages will not be so long, and, also, this directory can
contain a std.lnt that overrides the global std.lnt in the
Configuration Directory.
This Simple Check is fine to check stand-alone modules but to check
projects or to unit check modules that are in projects we need to
go a bit further ...
Project Creation
----------------
To lint an entire project we will need the names of all the modules
in the project. Visual Studio keeps these names (as well as some
appropriate options such as define options (-d...) and include options
(-i...) in a file named NAME.vcproj in the current project directory.
NAME is the name of the project and is identified by the macro
$(TargetName). PC-lint can read the .vcproj file and generate the
appropriate .lnt file. We recommend creating a tool for this purpose.
For this tool follow the steps 1-4 doing exactly the same thing as
above except in step 3, the information entered should be:
Title: PC-lint (Project Creation)
Command: c:\lint\lint-nt.exe
Arguments: -v -os("$(TargetName).lnt") "$(ProjectFileName)"
Init. Dir.: $(ProjectDir)
__Use Output Window __Prompt for arguments x_Close on exit
You will need to have an active project before this will work.
If you don't already have one you can obtain an active project
from the Solutions Explorer. You then click the newly added
"PC-lint (Project Creation)" tool on the tools menu to create
NAME.lnt.
The file created is an ASCII file and we recommend that you open it
within the IDE and examine it for any obvious flaws. This is your
chance to make any necessary modifications to the file as the process
of conversion may be less than perfect.
Project Check
-------------
Interestingly, by opening up the NAME.lnt file created above and
running the Simple Check described earlier you have the equivalent
of a full project check. However, we prefer to create a special
Project Check tool.
Now that we have a project file we can create a new tool called
"PC-lint (project check)". For this tool again follow steps 1-4 doing
exactly the same thing as above except in step 3, the information
entered should be:
Title: PC-lint (Project Check)
Command: c:\lint\lint-nt.exe
Arguments: -i"c:\lint" std.lnt env-vc10.lnt "$(TargetName).lnt"
Init. Dir.: $(ProjectDir)
X_Use Output Window __Prompt for arguments __Close on exit
Unit Check
----------
You can almost do a unit check on any single module by using the
Simple Check scheme suggested above. The only problems are that you
will need a -u option and you will not have the benefit of any -d or
-i options that have been placed into NAME.lnt created in the Project
Creation step. For this reason we suggest the following tool for
doing a unit check of any module that is part of a project and for
which a .lnt project file has been generated.
Title: PC-lint (Unit Check)
Command: c:\lint\lint-nt.exe
Arguments:
-i"c:\lint" std.lnt env-vc10.lnt --u "$(TargetName).lnt" "$(ItemPath)"
Init. Dir.: $(ProjectDir)
X_Use Output Window __Prompt for arguments __Close on exit
Note that $(ItemPath) will provide a complete path name and in the
absence of a project.lnt file it would cause full path names to
appear in messages. But a side effect of using the project file
with the --u option means that we adopt the shorter names used
in the project file.
Suppressing Messages
----------- --------
Suppressing messages is normally done by adding message suppression
options to a file. For example, -e550 will suppress message 550.
There are numerous other options to suppress messages.
As the documentation indicates, the file
c:\lint\options.lnt
(where c:\lint\ is the Configuration Directory) is the presumed
container of your overall suppression policy. (Note: options.lnt is
referenced by std.lnt). Add a message suppression here and you will
affect all linting employing that configuration.
To suppress messages for a particular project (or for all projects
within a given project directory) you may do the following:
Create a file std.lnt that is contained in the project directory.
Make it refer back to the std.lnt in the Configuration Directory.
Then add additional message suppression options or indeed any options
you want. For example it might contain:
c:\lint\std.lnt // reference to original std.lnt
-e550 // project-specific option
In this way suppression is limited to a particular project.
Tool Bar
--------
You also have the option of creating a PC-lint toolbar within your
Visual C++ IDE. First, create one or more tools as described above.
You will need to know the number(s) of the tool(s) you want to place
on the tool bar. This can only be done by the painful and laborious
task of counting. Using the list provided by "Tools"/"External
Tools", jot down the numbers (starting with 1 at the top) of all the
tools to be added to the tool bar. We recommend placing all the
PC-lint tools on a single tool bar. Then select Customize from the
Tools menu. Select the Toolbars tab and click the New... button.
Give the Toolbar a name (E.g., PC-lint) in the dialog box provided
and click "OK". Confirm that the new toolbar is now floating on
the desktop and that a check has been placed in the check box next
to the new toolbar name. Then click on the Commands tab and
select the "Toolbar:" radio button. Open the drop down list and
select "PC-Lint" from the choices. Click the "Add Command..."
button to reveal the "Add Command" window. In the "Categories:"
box scroll down to and select the "Tools" item. In the
"Commands:" box scroll down to and select the appropriate
"External Command" numbered item that corresponds to the desired
PC-Lint command, then click the OK button to add the selected item
to the PC-Lint toolbar. Repeat the "Add Command..." process for
each desired PC-Lint command the you wish to place on the PC-Lint
toolbar.
If you want to add a button image to the toolbar, you can choose one
via the Modify Selection button. Click Close and you now have your
own PC-lint for C/C++ button. (Note: If you change the location of
the PC-lint menu item on the Tools menu, you will change the subscript
and you will need to change the button(s) on the toolbar.)
*/
-"format=%(%F(%l):%) error %n: (%t -- %m)" // Messages will contain
// file information (%F), the line number (%l), the
// message number (%n), message type (%t) and message text (%m).
-hF2 // Make sure we ALWAYS provide file information ('F') and use 2
// lines (one for the source line in error and one for the
// message).
-width(0) // don't break messages at any particular width
-t4 // Presume that tabs are every 4 stops
//+e900 // issue a message at termination.

View File

@ -0,0 +1,17 @@
/* Date Stamp */ -d"_lint_lib_ole_lnt=lib-ole.lnt modified 23-Mar-2004"
/* To document usage use: -message( "Using " _lint_lib_ole_lnt ) */
// ---------------------------------------------------------------------
// This file is provided by Gimpel Software (www.gimpel.com) for use with
// its products PC-lint and FlexeLint.
//
// Redistribution and use of this file, with or without modification, is
// permitted provided that any such redistribution retains this notice.
// ---------------------------------------------------------------------
// BSTR functions (part of OLE Automation)
-sem( SysAllocString, @p == malloc(1p) || @p == 0, 1p )
-sem( SysAllocStringByteLen, @P == malloc(2n+1) || @p == 0 )
-sem( SysAllocStringLen, @p == malloc(2n+1) || @p == 0 )
-sem( SysStringLen, 1p ? @n == 1p - 1 : @n == 0 )
-function( free, SysFreeString )

View File

@ -0,0 +1,56 @@
/* Date Stamp */ -d"_lint_lib_w32_lnt=lib-w32.lnt modified 2-Mar-1999"
/* To document usage use: -message( "Using " _lint_lib_w32_lnt ) */
// ---------------------------------------------------------------------
// This file is provided by Gimpel Software (www.gimpel.com) for use with
// its products PC-lint and FlexeLint.
//
// Redistribution and use of this file, with or without modification, is
// permitted provided that any such redistribution retains this notice.
// ---------------------------------------------------------------------
// lib-w32.lnt
// PC-lint Library Options File for 32-bit mode windows.h
-d__FLAT__
-d_WIN32
-si4
-sp4
-esym(14,pLocalHeap) // variable defined in windows.h
-e740 // remove 'suspicious cast' messages because these must be
// routinely done within Windows.
-elib(46) // windows.h uses a BYTE as base of bit field.
-e793 // windows breaks ANSI limits
// the following functions have their return value typically ignored.
// add or subtract from this list as desired.
-esym(534,RegisterClass,ShowWindow,TranslateMessage,DispatchMessage)
-esym(534,DrawText,GetTextMetrics,ReleaseDC,TextOut,SetTextAlign)
-esym(534,SetScrollPos,SelectObject,SetBkMode,SendMessage,MessageBox)
-esym(534,MessageBoxA,MessageBoxW,PostMessageA,PostMessageW)
-esym(534,PatBlt,DeleteDC,SetCapture,SetCursor,StretchBlt)
-esym(534,Rectangle,MoveTo,LineTo,ShowCursor,MoveWindow,SetWindowWord)
-esym(534,SetPixel,FillRect,DeleteObject,KillTimer,GetProfileString)
-esym(534,SetWindowLong,SetFocus,SetBkColor,SetTextColor,SetBrushOrg)
-esym(534,UnrealizeObject,_lclose,Polygon,FrameRect,LoadString)
-esym(534,GetInstanceData,GlobalUnlock,FreeResource,LoadString)
-esym(534,DrawIcon,AppendMenu,GetObject,CheckMenuItem,SetClassWord)
-esym(534,EnableMenuItem,SetMenu,DestroyMenu,TrackPopupMenu)
-esym(534,AnsiUpper,Arc,BeginPaint,BitBlt,ChangeClipboardChain,Chord)
-esym(534,CloseClipboard,CombineRgn,DdeClientTransaction,DdeDisconnect)
-esym(534,DdeFreeStringHandle,DdeGetData,DdeNameService,DdePostAdvise)
-esym(534,DdeQueryString,DdeUninitialize,DeleteMenu,DeleteMetaFile)
-esym(534,DestroyWindow,DialogBox,DPtoLP,Ellipse,EmptyClipboard,EnableWindow)
-esym(534,EnumChildWindows,EnumWindows,Escape,GetClassName,GetDlgItemText)
-esym(534,GetFileTitle,GetMenuString,GetStrings,GetSystemMenu,GetTextFace)
-esym(534,GetWindowText,GlobalDeleteAtom,GlobalFree,GlobalGetAtomName)
-esym(534,LocalFree,LocalUnlock,LockResource,lstrcpy,OpenClipboard)
-esym(534,Pie,PlayMetaFile,PopFindNextText,PostDataMessage,PostMessage)
-esym(534,RestoreDC,SaveDC,SelectClipRgn,SendDlgItemMessage,SetClipboardData)
-esym(534,SetDIBitsToDevice,SetMapMode,SetMapperFlags,SetROP2,SetStretchBltMode)
-esym(534,SetTextJustification,SetTimer,SetViewportExt,SetViewportOrg)
-esym(534,SetWindowExt,SetWindowOrg,StretchDIBits,WinExec)
// Ignored parameters
-esym(715,lpszCmdParam,lpszCmdLine)
-emacro(648,PSN_*) // ignore unsigned overflow (0-200U)

View File

@ -0,0 +1,85 @@
# This file contains functions and configurations for generating PC-Lint build
# targets for your CMake projects.
set(PC_LINT_EXECUTABLE "C:/Lint/lint-nt.exe" CACHE STRING "full path to the pc-lint executable. NOT the generated lin.bat")
set(PC_LINT_CONFIG_DIR "${PROJECT_SOURCE_DIR}/lint/msvc" CACHE STRING "full path to the directory containing pc-lint configuration files")
set(PC_LINT_USER_FLAGS "-b" CACHE STRING "additional pc-lint command line options -- some flags of pc-lint cannot be set in option files (most notably -b)")
# a phony target which causes all available *_LINT targets to be executed
add_custom_target(ALL_LINT)
# add_pc_lint(target source1 [source2 ...])
#
# Takes a list of source files and generates a build target which can be used
# for linting all files
#
# The generated lint commands assume that a top-level config file named
# 'std.lnt' resides in the configuration directory 'PC_LINT_CONFIG_DIR'. This
# config file must include all other config files. This is standard lint
# behaviour.
#
# Parameters:
# - target: the name of the target to which the sources belong. You will get a
# new build target named ${target}_LINT
# - source1 ... : a list of source files to be linted. Just pass the same list
# as you passed for add_executable or add_library. Everything except
# C and CPP files (*.c, *.cpp, *.cxx) will be filtered out.
#
# Example:
# If you have a CMakeLists.txt which generates an executable like this:
#
# set(MAIN_SOURCES main.c foo.c bar.c)
# add_executable(main ${MAIN_SOURCES})
#
# include this file
#
# include(/path/to/pc_lint.cmake)
#
# and add a line to generate the main_LINT target
#
# if(COMMAND add_pc_lint)
# add_pc_lint(main ${MAIN_SOURCES})
# endif(COMMAND add_pc_lint)
#
function(add_pc_lint target)
get_directory_property(lint_include_directories INCLUDE_DIRECTORIES)
get_directory_property(lint_defines COMPILE_DEFINITIONS)
# let's get those elephants across the alps
# prepend each include directory with "-i"; also quotes the directory
set(lint_include_directories_transformed)
foreach(include_dir ${lint_include_directories})
list(APPEND lint_include_directories_transformed -i"${include_dir}")
endforeach(include_dir)
# prepend each definition with "-d"
set(lint_defines_transformed)
foreach(definition ${lint_defines})
list(APPEND lint_defines_transformed -d${definition})
endforeach(definition)
# list of all commands, one for each given source file
set(pc_lint_commands)
foreach(sourcefile ${ARGN})
# only include c and cpp files
if( sourcefile MATCHES \\.c$|\\.cxx$|\\.cpp$ )
# make filename absolute
get_filename_component(sourcefile_abs ${sourcefile} ABSOLUTE)
# create command line for linting one source file and add it to the list of commands
list(APPEND pc_lint_commands
COMMAND ${PC_LINT_EXECUTABLE}
-i"${PC_LINT_CONFIG_DIR}" std.lnt
"-u" ${PC_LINT_USER_FLAGS}
${lint_include_directories_transformed}
${lint_defines_transformed}
${sourcefile_abs})
endif()
endforeach(sourcefile)
# add a custom target consisting of all the commands generated above
add_custom_target(${target}_LINT ${pc_lint_commands} VERBATIM)
# make the ALL_LINT target depend on each and every *_LINT target
add_dependencies(ALL_LINT ${target}_LINT)
endfunction(add_pc_lint)

View File

@ -0,0 +1,4 @@
co-msc100.lnt
env-vc10.lnt
lib-w32.lnt

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,52 @@
/**
\mainpage BootCommander - Command Line Firmware Update Tool
\details
\tableofcontents
\section into Introduction
BootCommander is a command line program for performing a firmware update on a connected
microcontroller target that runs the OpenBLT bootloader. It is written in the C
programming language (C99) and is cross-platform. It has been successfully tested on a
Windows PC, Linux PC and even embedded Linux systems such as a Raspberry Pi and a Beagle
Board.
BootCommander is built on top of the OpenBLT Host Library (LibOpenBLT), which embeds all
functionality needed to communicate with the OpenBLT bootloader on the microcontroller
target.
\image html bootcommander_architecture.png
\image latex bootcommander_architecture.png
This program is specifically developed for those that prefer a command line program over
a program with a graphical user interface, such as MicroBoot. Additionally, it can
serve as a reference on how to use LibOpenBLT.
Refer to the OpenBLT website for additional information regarding the usage of the
BootCommander program, including a description of the available command line parameters
and step-by-step instructions on how to build the BootCommander program from sources:
https://www.feaser.com/openblt/doku.php?id=manual:bootcommander.
\verbatim
----------------------------------------------------------------------------------------
C O P Y R I G H T
----------------------------------------------------------------------------------------
Copyright (c) 2017 Feaser. 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 have received a copy of the GNU General Public License along with OpenBLT. It
should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
----------------------------------------------------------------------------------------
\endverbatim
*/

View File

@ -0,0 +1,160 @@
#****************************************************************************************
# \file CMakeLists.txt
# \brief CMake descriptor file for the OpenBLT host library.
# \internal
#----------------------------------------------------------------------------------------
# C O P Y R I G H T
#----------------------------------------------------------------------------------------
# Copyright (c) 2017 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 have received a copy of the GNU General Public License along with OpenBLT. It
# should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
#
# \endinternal
#****************************************************************************************
# Specify the version being used aswell as the language
cmake_minimum_required(VERSION 2.8)
#****************************************************************************************
# Project configuration
#****************************************************************************************
# Specify the project name
project(LibOpenBLT)
# Build debug version by default
set(CMAKE_BUILD_TYPE "Debug")
#****************************************************************************************
# Options
#****************************************************************************************
# Add option with default value to enable the generation and building of the static
# library. It can be overridden on the command line when CMake is called using the
# following parameter: -DBUILD_STATIC=OFF
option(BUILD_STATIC "Configurable to enable/disable building of the static library" ON)
# Add option with default value to enable the generation and building of the shared
# library. It can be overridden on the command line when CMake is called using the
# following parameter: -DBUILD_SHARED=OFF
option(BUILD_SHARED "Configurable to enable/disable building of the shared library" ON)
# Add option with default value to disable the generation of the PC-lint target. It can
# be overridden on the command line when CMake is called using the following parameter:
# -DLINT_ENABLED=ON
option(LINT_ENABLED "Configurable to enable/disable the PC-lint target" OFF)
#****************************************************************************************
# Directories
#****************************************************************************************
# Set the port directory, which is platform specific
if(WIN32)
set(PROJECT_PORT_DIR ${PROJECT_SOURCE_DIR}/port/windows)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DPLATFORM_WIN32 -D_CRT_SECURE_NO_WARNINGS")
elseif(UNIX)
set(PROJECT_PORT_DIR ${PROJECT_SOURCE_DIR}/port/linux)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DPLATFORM_LINUX")
endif(WIN32)
# Set the output directory
set (PROJECT_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../../..)
# Set the output directory for the generic no-config case (e.g. with mingw)
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_OUTPUT_DIRECTORY} )
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_OUTPUT_DIRECTORY} )
set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_OUTPUT_DIRECTORY} )
# Set the output directory for multi-config builds (e.g. msvc)
foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} )
string( TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG )
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${PROJECT_OUTPUT_DIRECTORY} )
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${PROJECT_OUTPUT_DIRECTORY} )
set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${PROJECT_OUTPUT_DIRECTORY} )
endforeach( OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES )
#***************************************************************************************
# Includes
#****************************************************************************************
# Set include directories
include_directories("${PROJECT_SOURCE_DIR}" "${PROJECT_PORT_DIR}")
#***************************************************************************************
# Files
#****************************************************************************************
# Get header files from the root directory and the port directory.
file(GLOB INCS_ROOT "*.h")
file(GLOB INCS_PORT "${PROJECT_PORT_DIR}/*.h")
set(INCS ${INCS_ROOT} ${INCS_PORT})
# Add sources
set(
LIB_SRCS
openblt.c
session.c
xcploader.c
xcptpuart.c
firmware.c
srecparser.c
util.c
${PROJECT_PORT_DIR}/timeutil.c
${PROJECT_PORT_DIR}/serialport.c
${INCS}
)
#***************************************************************************************
# Targets
#****************************************************************************************
# Only generate the static library taget if the option is enabled. Use
# "make openblt_static" to individually build the static library.
if(BUILD_STATIC)
add_library(openblt_static STATIC ${LIB_SRCS})
SET_TARGET_PROPERTIES(openblt_static PROPERTIES OUTPUT_NAME openblt CLEAN_DIRECT_OUTPUT 1)
endif(BUILD_STATIC)
# Only generate the shared library taget if the option is enabled. Use
# "make openblt_shared" to build individually shared library.
if(BUILD_SHARED)
add_library(openblt_shared SHARED ${LIB_SRCS})
if(CMAKE_C_COMPILER_ID MATCHES MSVC)
# Microsoft Visual Studio does not add "lib" to the name of the DLL, whereas GCC
# (including MinGW) does. Correct this here.
SET_TARGET_PROPERTIES(openblt_shared PROPERTIES OUTPUT_NAME libopenblt CLEAN_DIRECT_OUTPUT 1)
else()
SET_TARGET_PROPERTIES(openblt_shared PROPERTIES OUTPUT_NAME openblt CLEAN_DIRECT_OUTPUT 1)
endif()
endif(BUILD_SHARED)
# Only generate the PC-lint taget if the option is enabled. Use "make openblt_LINT" to
# lint the project sources
if(LINT_ENABLED)
# Include PC-lint configuration file for the correct compiler. Currently GNU GCC and
# Microsoft Visual Studio are supported.
if(CMAKE_C_COMPILER_ID MATCHES GNU)
include(${PROJECT_SOURCE_DIR}/lint/gnu/pc_lint.cmake)
elseif(CMAKE_C_COMPILER_ID MATCHES MSVC)
include(${PROJECT_SOURCE_DIR}/lint/msvc/pc_lint.cmake)
endif()
# Generate the PC-lint target.
if(COMMAND add_pc_lint)
add_pc_lint(openblt ${LIB_SRCS})
endif(COMMAND add_pc_lint)
endif(LINT_ENABLED)
#*********************************** end of CMakeLists.txt ******************************

View File

@ -0,0 +1,874 @@
/************************************************************************************//**
* \file firmware.c
* \brief Firmware data module source file.
* \ingroup Firmware
* \internal
*----------------------------------------------------------------------------------------
* C O P Y R I G H T
*----------------------------------------------------------------------------------------
* Copyright (c) 2017 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 have received a copy of the GNU General Public License along with OpenBLT. It
* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
*
* \endinternal
****************************************************************************************/
/****************************************************************************************
* Include files
****************************************************************************************/
#include <assert.h> /* for assertions */
#include <stdint.h> /* for standard integer types */
#include <stddef.h> /* for NULL declaration */
#include <stdbool.h> /* for boolean type */
#include <stdlib.h> /* for standard library */
#include <string.h> /* for string library */
#include "firmware.h" /* Firmware data module */
/****************************************************************************************
* Local data declarations
****************************************************************************************/
/** \brief Pointer to the firmware parser that is linked. */
static tFirmwareParser const * parserPtr;
/** \brief Linked list with firmware segments. */
static tFirmwareSegment * segmentList;
/****************************************************************************************
* Function prototypes
****************************************************************************************/
static void FirmwareCreateSegment(uint32_t address, uint32_t len, uint8_t const * data);
static void FirmwareDeleteSegment(tFirmwareSegment const * segment);
static void FirmwareTrimSegment(tFirmwareSegment const * segment, uint32_t address,
uint32_t len);
static void FirmwareSortSegments(void);
static void FirmwareMergeSegments(void);
static uint32_t FirmwareGetFirstAddress(void);
static uint32_t FirmwareGetLastAddress(void);
/************************************************************************************//**
** \brief Initializes the module.
** \param parser The firmware file parser to link. It is okay to specify NULL if no
** file parser is needed.
**
****************************************************************************************/
void FirmwareInit(tFirmwareParser const * parser)
{
/* Link the firmware parser. */
parserPtr = parser;
/* Start with an empty segment list. */
segmentList = NULL;
} /*** end of FirmwareInit ***/
/************************************************************************************//**
** \brief Terminates the module.
**
****************************************************************************************/
void FirmwareTerminate(void)
{
/* Clear all data and segments from the linked list. */
FirmwareClearData();
/* Unlink the firmware parser. */
parserPtr = NULL;
} /*** end of FirmwareTerminate ***/
/************************************************************************************//**
** \brief Uses the linked parser to load the firmware data from the specified file
** into the linked list of segments.
** \param firmwareFile Filename of the firmware file to load.
** \return True if successful, false otherwise.
**
****************************************************************************************/
bool FirmwareLoadFromFile(char const * firmwareFile)
{
bool result = false;
/* Verify parameters. */
assert(firmwareFile != NULL);
/* Only continue if parameters are valid. */
if (firmwareFile != NULL) /*lint !e774 */
{
/* Check if a parser is linked. */
if (parserPtr != NULL)
{
/* Check if a LoadFromFile method is linked. */
if (parserPtr->LoadFromFile != NULL)
{
/* Request the parser to perform the load operation. */
result = parserPtr->LoadFromFile(firmwareFile);
}
}
}
/* Give the result back to the caller. */
return result;
} /*** end of FirmwareLoadFromFile ***/
/************************************************************************************//**
** \brief Uses the linked parser to save the dat stored in the segments of the linked
** list to the specified file.
** \param firmwareFile Filename of the firmware file to write to.
** \return True if successful, false otherwise.
**
****************************************************************************************/
bool FirmwareSaveToFile(char const * firmwareFile)
{
bool result = false;
/* Verify parameters. */
assert(firmwareFile != NULL);
/* Only continue if parameters are valid. */
if (firmwareFile != NULL) /*lint !e774 */
{
/* Check if a parser is linked. */
if (parserPtr != NULL)
{
/* Check if a SaveToFile method is linked. */
if (parserPtr->SaveToFile != NULL)
{
/* Request the parser to perform the save operation. */
result = parserPtr->SaveToFile(firmwareFile);
}
}
}
/* Give the result back to the caller. */
return result;
} /*** end of FirmwareSaveToFile ***/
/************************************************************************************//**
** \brief Obtains the total number of segments in the linked list with firmware data.
** \return Total number of segments.
**
****************************************************************************************/
uint32_t FirmwareGetSegmentCount(void)
{
tFirmwareSegment * currentSegment;
uint32_t segmentCount = 0;
/* Iterate over all segments to determine the total count. */
if (segmentList != NULL)
{
currentSegment = segmentList;
do
{
segmentCount++;
currentSegment = currentSegment->next;
}
while (currentSegment != NULL);
}
/* Give segment count back to the caller. */
return segmentCount;
} /*** end of FirmwareGetSegmentCount ***/
/************************************************************************************//**
** \brief Obtains the segment as the specified index from the linked list with
** firmware data.
** \param segmentIdx The segment index. It should be a value greater or equal to zero
** and smaller than the value returned by \ref FirmwareGetSegmentCount.
** \return The segment if successful, NULL otherwise.
**
****************************************************************************************/
tFirmwareSegment * FirmwareGetSegment(uint32_t segmentIdx)
{
tFirmwareSegment * currentSegment = NULL;
uint32_t currentIdx;
/* Validate parameters. */
assert(segmentIdx < FirmwareGetSegmentCount());
/* Only continue if parameters are valid. */
if (segmentIdx < FirmwareGetSegmentCount())
{
/* Iterate over the segments until the specified index is found. */
if (segmentList != NULL)
{
currentSegment = segmentList;
for (currentIdx = 0; currentIdx < segmentIdx; currentIdx++)
{
/* Move on to the next segment. */
currentSegment = currentSegment->next;
/* Make sure the segment is valid. */
assert(currentSegment != NULL);
if (currentSegment == NULL) /*lint !e774 */
{
/* The specified index tries to index a non-existing segment. Abort. */
break;
}
}
}
}
/* Give the requested segment back to the caller, if found. */
return currentSegment;
} /*** end of FirmwareGetSegment ***/
/************************************************************************************//**
** \brief Adds data to the segments that are currently present in the firmware data
** module. If the data overlaps with already existing data, the existing data
** gets overwritten. The size of a segment is automatically adjusted or a new
** segment gets created, if necessary.
** \param address Base address of the firmware data.
** \param len Number of bytes to add.
** \param data Pointer to array with data bytes that should be added.
** \return True if successful, false otherwise.
**
****************************************************************************************/
bool FirmwareAddData(uint32_t address, uint32_t len, uint8_t const * data)
{
bool result = false;
/* Verify parameters. */
assert(len > 0);
assert(data != NULL);
(void)address;
/* Only continue if parameters are valid. */
if ( (len > 0) && (data != NULL) ) /*lint !e774 */
{
/* The to be added data could span several existing segments, eithe partially or
* completely. If is therefore faster to first remove the same range, and then
* add the data as one new segment.
*/
if (FirmwareRemoveData(address, len))
{
/* Next add the new data as a new segment. */
FirmwareCreateSegment(address, len, data);
/* Merge the segments after adding a new one. Note that this automatically sorts
* the segments as well.
*/
FirmwareMergeSegments();
/* Data successfully added. */
result = true;
}
}
/* Give the result back to the caller. */
return result;
} /*** end of FirmwareAddData ***/
/************************************************************************************//**
** \brief Removes data from the segments that are currently present in the firmware
** data module. The size of a segment is automatically adjusted or removed, if
** necessary. Note that it is safe to assume in this function that the
** segments are already ordered in the linked list by ascending base memory
** address.
** \param address Base address of the firmware data.
** \param len Number of bytes to remove.
** \return True if successful, false otherwise.
**
****************************************************************************************/
bool FirmwareRemoveData(uint32_t address, uint32_t len)
{
bool result = false;
tFirmwareSegment * startSegment = NULL;
tFirmwareSegment * endSegment = NULL;
uint32_t startSegmentIdx;
uint32_t endSegmentIdx;
tFirmwareSegment * currentSegment;
/* Verify parameters. */
assert(len > 0);
/* Only continue if parameters are valid. */
if (len > 0)
{
/* In case there are no segments yet in the list, there is nothing extra to do. */
if (segmentList == NULL)
{
result = true;
}
/* At least one segment in the list. Check if the to be erased data falls outside the
* range of the segments that are currently in the linked list. In this case there
* is nothing extra to do.
*/
else if ( ((address + len - 1u) < FirmwareGetFirstAddress()) ||
(address > FirmwareGetLastAddress()) )
{
result = true;
}
/* At least one segment in the list and the to be erased data overlaps one or more
* segments.
*/
else
{
/* Find the segment with the lowest index that contains data to remove. */
currentSegment = segmentList;
startSegmentIdx = 0;
do
{
/* Is there to be removed data in this segment? */
if (address < (currentSegment->base + currentSegment->length))
{
/* Start segment found. Store it and stop looping. */
startSegment = currentSegment;
break;
}
/* Continue with the next segment. */
currentSegment = currentSegment->next;
startSegmentIdx++;
}
while (currentSegment != NULL);
/* Find the segment with the highest index that contains data to remove. */
currentSegment = FirmwareGetSegment(FirmwareGetSegmentCount() - 1u);
endSegmentIdx = FirmwareGetSegmentCount() - 1u;
do
{
/* Is there to be removed data in this segment? */
if (currentSegment->base < (address + len))
{
/* End segment found. Store it and stop looping. */
endSegment = currentSegment;
break;
}
/* Continue with the previous segment. */
currentSegment = currentSegment->prev;
endSegmentIdx--;
}
while (currentSegment != NULL);
/* Sanity check. The start- and endSegments must be valid now. */
assert((startSegment != NULL) && (endSegment != NULL));
/* Only continue if segment pointers are valid. */
if ((startSegment != NULL) && (endSegment != NULL)) /*lint !e774 */
{
/* Check if the endSegmentIdx is smaller than the startSegmentIdx. This indicates
* that the to be erased data falls in a gap between 2 segments and that is
* nothing to remove.
*/
if (endSegmentIdx < startSegmentIdx)
{
/* Nothing to remove, so we are all done. */
result = true;
}
else
{
/* Remove all segments in between the start- and endSegments, if any */
if (startSegment != endSegment)
{
/* Delete the segments until the endSegment is reached. */
while (startSegment->next != endSegment)
{
/* Note that this automatically updates the next-member to the segment after
* the one that got deleted.
*/
FirmwareDeleteSegment(startSegment->next);
}
}
/* Segments between the start- and endSegment are now removed. Now trim the
* start- and endSegments.
*/
FirmwareTrimSegment(startSegment, address, len);
/* Only trim endSegment if it is different from the startSegment. */
if (startSegment != endSegment)
{
FirmwareTrimSegment(endSegment, address, len);
}
/* Resort the segments because new segments might have been added during
* the trim operation.
*/
FirmwareSortSegments();
/* Segment removal completed successfully. */
result = true;
}
}
}
}
/* Give the result back to the caller. */
return result;
} /*** end of FirmwareRemoveData ***/
/************************************************************************************//**
** \brief Clears all data and segments that are currently present in the linked list.
**
****************************************************************************************/
void FirmwareClearData(void)
{
tFirmwareSegment * currentSegment;
tFirmwareSegment * segmentToFree;
/* Free al the segments in the segment list. */
if (segmentList != NULL)
{
currentSegment = segmentList;
do
{
/* Store pointer to the segment that should be released for later usage. */
segmentToFree = currentSegment;
/* Move to the next segment before freeing it. */
currentSegment = currentSegment->next;
/* Sanity check. */
assert(segmentToFree != NULL);
/* Only access the segment if it is not NULL. */
if (segmentToFree != NULL) /*lint !e774 */
{
/* Free the segment data. */
if (segmentToFree->data != NULL)
{
free(segmentToFree->data);
}
/* Free the segment. */
free(segmentToFree);
}
}
while (currentSegment != NULL);
/* Set the segment list to empty. */
segmentList = NULL;
}
} /*** end of FirmwareClearData ***/
/************************************************************************************//**
** \brief Creates and adds a new segment to the linked list. It allocates memory for
** the segment data and copies the data to it.
** \param address Base address of the firmware data.
** \param len Number of bytes to add to the new segment.
** \param data Pointer to the byte array with data for the segment.
**
****************************************************************************************/
static void FirmwareCreateSegment(uint32_t address, uint32_t len, uint8_t const * data)
{
/*lint -esym(593, newSegment) newSegment pointer is freed when the segment is removed
* from the linked list.
*/
tFirmwareSegment * newSegment;
tFirmwareSegment * currentSegment;
/* Verify parameters. */
assert(len > 0);
assert(data != NULL);
/* Only continue if parameters are valid. */
if ( (len > 0) && (data != NULL) ) /*lint !e774 */
{
/* Allocate memory for the new segment. */
newSegment = malloc(sizeof(tFirmwareSegment));
/* Verify allocation result. */
assert(newSegment != NULL);
/* Only continue if allocation was successful. */
if (newSegment != NULL) /*lint !e774 */
{
/* Allocate memory for the segment data. */
newSegment->data = malloc(len);
/* Verify allocation result. */
assert(newSegment->data != NULL);
/* Only continue if allocation was successful. */
if (newSegment->data != NULL) /*lint !e774 */
{
/* Copy the data to the segment. */
memcpy(newSegment->data, data, len);
/* Set other segment fields. */
newSegment->base = address;
newSegment->length = len;
newSegment->next = NULL;
/* Add the new segment as the first segment if the linked list is empty. */
if (segmentList == NULL)
{
newSegment->prev = NULL;
segmentList = newSegment;
}
/* Add the segment to the end of the list. */
else
{
/* Find the last entry in the list. */
currentSegment = segmentList;
while (currentSegment->next != NULL)
{
currentSegment = currentSegment->next;
}
/* Add the new segment. */
newSegment->prev = currentSegment;
currentSegment->next = newSegment;
}
}
}
}
} /*** end of FirmwareCreateSegment ***/
/************************************************************************************//**
** \brief Deletes the specified segment from the linked list and handles
** the release of the segment's allocated memory.
** \param segment Pointer to the segment.
**
****************************************************************************************/
static void FirmwareDeleteSegment(tFirmwareSegment const * segment)
{
tFirmwareSegment * currentSegment = NULL;
/* Validate parameters. */
assert(segment != NULL);
/* Only continue if parameters are valid and the linked list is not empty. */
if ( (segment != NULL) && (segmentList != NULL) ) /*lint !e774 */
{
/* Iterate over the segments in the linked list, just to verify that it is a valid
* segment pointer.
*/
currentSegment = segmentList;
do
{
/* Is this the segment that is requested to be deleted? */
if (currentSegment == segment)
{
/* Is the segment the first one in the linked list? */
if (currentSegment->prev == NULL)
{
/* Make the next segment the start of the linked list, if present. */
if (currentSegment->next != NULL)
{
currentSegment->next->prev = NULL;
segmentList = currentSegment->next;
}
/* The to be deleted segment was the only segment in the list. So set the
* list to empty now.
*/
else
{
segmentList = NULL;
}
}
/* Is the segment the last one in the linked list? Note that we already know that
* it is not the first one due to the previous check. This automatically means
* there are at least 2 segments in the list, so there is no need to check its
* previous entry pointer for NULL.
*/
else if (currentSegment->next == NULL)
{
/* Make the previous segment the end of the linked list. */
currentSegment->prev->next = NULL;
}
/* It is a segment somewhere in the middle of the list. Note that we already know
* that it is not the first or the last segment. This means that there are at
* least three or more segments in the list, so there is no need to check the
* next and previous entry pointers for NULL.
*/
else
{
/* Update links of adjacent segments as to remove ourselves. */
currentSegment->prev->next = currentSegment->next;
currentSegment->next->prev = currentSegment->prev;
}
/* The segment was removed from the list. Now its allocated memory should be
* released.
*/
if (currentSegment->data != NULL)
{
free(currentSegment->data);
}
free(currentSegment);
/* No need to continue looping as we are done already. */
break;
}
/* Move on to the next segment. */
currentSegment = currentSegment->next;
}
while (currentSegment != NULL);
}
} /*** end of FirmwareDeleteSegment ***/
/************************************************************************************//**
** \brief Removes the specified data range (address to address + len) from the
** segment. If if overlaps the entire segment, the segment will be deleted.
** Otherwise, the segment will be trimmed and, if needed, split into multiple
** segments.
** \param segment Pointer to the segment to trim.
** \param address Start address of the data that should be removed.
** \param len Total number of data bytes that should be removed.
**
****************************************************************************************/
static void FirmwareTrimSegment(tFirmwareSegment const * segment, uint32_t address,
uint32_t len)
{
tFirmwareSegment * currentSegment = NULL;
bool segmentValid = false;
uint32_t newLength1, newLength2;
uint32_t newBase1, newBase2;
uint8_t *newData1, *newData2;
/* Validate parameters. */
assert(segment != NULL);
assert(len > 0);
/* Only continue if parameters are valid and the linked list is not empty. */
if ( (segment != NULL) && (len > 0) && (segmentList != NULL) ) /*lint !e774 */
{
/* Iterate over the segments in the linked list, just to verify that it is a valid
* segment pointer.
*/
currentSegment = segmentList;
do
{
/* Is this the segment that is requested to be trimmed? */
if (currentSegment == segment)
{
/* Set flag that the specified segment is valid. */
segmentValid = true;
break;
}
/* Move on to the next segment. */
currentSegment = currentSegment->next;
}
while (currentSegment != NULL);
/* Only continue if the segment was successfully validated. */
if (segmentValid)
{
/* Does the data range to trim cover the entire segment? */
if ((address <= segment->base) &&
((address + len) >= (segment->base + segment->length)))
{
/* Delete the entire segment. */
FirmwareDeleteSegment(segment);
}
/* Does the data range cover the start of the segment, but does not go all the way
* to the end?
*/
else if (address <= segment->base)
{
/* Create a new segment with the data that should remain in the segment. */
newBase1 = address + len;
newLength1 = (segment->base + segment->length) - (address + len);
newData1 = &(segment->data[newBase1 - segment->base]);
FirmwareCreateSegment(newBase1, newLength1, newData1);
/* The original segment can now be deleted. */
FirmwareDeleteSegment(segment);
}
/* does the data range cover the end of the segment, but does not go all the way to
* the start?
*/
else if ((address + len) >= (segment->base + segment->length))
{
/* Create a new segment with the data that should remain in the segment. */
newBase1 = segment->base;
newLength1 = address - segment->base;
newData1 = segment->data;
FirmwareCreateSegment(newBase1, newLength1, newData1);
/* The original segment can now be deleted. */
FirmwareDeleteSegment(segment);
}
/* The data range covers a part in the middle of the segment. A split is needed. */
else
{
/* Create a new segment with the data that should remain in the segment that is
* currently before the to be removed range and create a new segment with the data
* that should remain in the segment that is currently after the to be removed
* range.
*/
newBase1 = segment->base;
newLength1 = address - segment->base;
newData1 = segment->data;
newBase2 = address + len;
newLength2 = (segment->base + segment->length) - (address + len);
newData2 = &(segment->data[newBase2 - segment->base]);
FirmwareCreateSegment(newBase1, newLength1, newData1);
FirmwareCreateSegment(newBase2, newLength2, newData2);
/* The original segment can now be deleted. */
FirmwareDeleteSegment(segment);
}
}
}
} /*** end of FirmwareTrimSegment ***/
/************************************************************************************//**
** \brief Helper function to sort the segments in the linked list in order of
** ascending base address. It uses a bubble sort algorithm.
**
****************************************************************************************/
static void FirmwareSortSegments(void)
{
tFirmwareSegment * currentSegment;
uint32_t i;
uint32_t tempBase;
uint32_t tempLength;
uint8_t *tempData;
/* Only continue if the list is not empty and has at least 2 segments. */
if (FirmwareGetSegmentCount() > 1)
{
/* Repeat bubbling for the total amount of segments - 1. */
for (i = 1; i < FirmwareGetSegmentCount(); i++)
{
/* Beging at the start of the list. */
currentSegment = segmentList;
while ( (currentSegment != NULL) && (currentSegment->next != NULL) )
{
/* Is the first one's base address higher then the next one's? */
if (currentSegment->base > currentSegment->next->base)
{
/* Swap the contents of these segments, excluding the next and prev fields. */
tempBase = currentSegment->next->base;
tempLength = currentSegment->next->length;
tempData = currentSegment->next->data;
currentSegment->next->base = currentSegment->base;
currentSegment->next->length = currentSegment->length;
currentSegment->next->data = currentSegment->data;
currentSegment->base = tempBase;
currentSegment->length = tempLength;
currentSegment->data = tempData;
}
/* Continue with the next pair. */
currentSegment = currentSegment->next;
}
}
}
} /*** end of FirmwareSortSegments ***/
/************************************************************************************//**
** \brief Helper function to merge the segments in the linked list. When the firmware
** data in two adjacent segments also holds an adjacent range, then the
** firmware data from both segments are combined into one new one. Note that
** this function only works properly if the segments are already ordered. For
** this reasonse, the segments are explicitely sorted at the start.
**
****************************************************************************************/
static void FirmwareMergeSegments(void)
{
tFirmwareSegment * currentSegment;
tFirmwareSegment * removeSegment;
/* Only continue if the list is not empty and has at least 2 segments. */
if (FirmwareGetSegmentCount() > 1)
{
/* This function only works properly if the segments are correctly ordered. Perform
* sorting here to make sure this is the case.
*/
FirmwareSortSegments();
/* Begin as the start of the linked list. */
currentSegment = segmentList;
/* Iterate through the segments until the end of the list. */
while ( (currentSegment != NULL) && (currentSegment->next != NULL) )
{
/* Are these segments adjacent? */
if ((currentSegment->base + currentSegment->length) == currentSegment->next->base)
{
/* Increase the size of the allocated data array such that it can hold the data
* of both segments.
*/
currentSegment->data = realloc(currentSegment->data, currentSegment->length +
currentSegment->next->length);
/* Assert reallocation. */
assert(currentSegment->data != NULL);
/* Only continue if reallocation was successful. */
if (currentSegment->data != NULL)
{
/* Append the data from the next segment. */
memcpy(&(currentSegment->data[currentSegment->length]),
currentSegment->next->data, currentSegment->next->length);
currentSegment->length += currentSegment->next->length;
/* Store the segment pointer that should be removed. */
removeSegment = currentSegment->next;
/* Remove the segment now that is has been merged with the previous one. */
FirmwareDeleteSegment(removeSegment);
/* After removing the current segment's higher address sibling we have a new
* sibling. This one could also be adjacent and in need of merging. So do not
* update the currentSegment pointer to the next one. Instead repeat the loop
* iteration for the same currentSegment pointer. We just need to check that
* the new sibling is actually there and not the end of the list. This would
* cause a problem when accessing currentSegment->next in the while-loop
* condition. If there is no sibling, then we can simply stop the loop because
* merging is all done then.
*/
if (currentSegment->next == NULL)
{
/* End of the linked list reached. Merging is done. */
break;
}
}
else
{
/* Merge skipped due to memory allocation issue. Just continue with the next
* segment then.
*/
currentSegment = currentSegment->next;
}
}
else
{
/* Continue with the next one. */
currentSegment = currentSegment->next;
}
}
}
} /*** end of FirmwareMergeSegments ***/
/************************************************************************************//**
** \brief Helper function to obtain the first memory address of the firmware data
** that is present in the linked list with segments.
** \return The first memory address.
**
****************************************************************************************/
static uint32_t FirmwareGetFirstAddress(void)
{
uint32_t result = 0;
tFirmwareSegment * firstSegment;
/* Obtain first segment in the linked list. */
firstSegment = FirmwareGetSegment(0u);
/* Sanity check. Make sure a valid segment was found. */
assert(firstSegment != NULL);
/* Only continue if a valid segment was found. */
if (firstSegment != NULL) /*lint !e774 */
{
/* Set the first address in this segment as the result. */
result = firstSegment->base;
}
/* Give the result back to the caller. */
return result;
} /*** end of FirmwareGetFirstAddress ***/
/************************************************************************************//**
** \brief Helper function to obtain the last memory address of the firmware data
** that is present in the linked list with segments.
** \return The last memory address.
**
****************************************************************************************/
static uint32_t FirmwareGetLastAddress(void)
{
uint32_t result = 0;
tFirmwareSegment * lastSegment;
/* Obtain last segment in the linked list. */
lastSegment = FirmwareGetSegment(FirmwareGetSegmentCount() - 1u);
/* Sanity check. Make sure a valid segment was found. */
assert(lastSegment != NULL);
/* Only continue if a valid segment was found. */
if (lastSegment != NULL) /*lint !e774 */
{
/* Calculate the last address in this segment. */
result = lastSegment->base + lastSegment->length - 1u;
}
/* Give the result back to the caller. */
return result;
} /*** end of FirmwareGetLastAddress ***/
/*********************************** end of firmware.c *********************************/

View File

@ -0,0 +1,101 @@
/************************************************************************************//**
* \file firmware.h
* \brief Firmware data module header file.
* \ingroup Firmware
* \internal
*----------------------------------------------------------------------------------------
* C O P Y R I G H T
*----------------------------------------------------------------------------------------
* Copyright (c) 2017 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 have received a copy of the GNU General Public License along with OpenBLT. It
* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
*
* \endinternal
****************************************************************************************/
/************************************************************************************//**
* \defgroup Firmware Firmware Data Module
* \brief Module with functionality to load, manipulate and store firmware data.
* \ingroup Library
* \details
* The Firmwarwe Data module contains functionality to load, manipulate and store firmware
* data. It contains an interface for linking firmware file parsers that handle the
* loading and saving the firmware data from and to a file in the correct format. For
* example the Motorola S-record format.
****************************************************************************************/
#ifndef FIRMWARE_H
#define FIRMWARE_H
#ifdef __cplusplus
extern "C" {
#endif
/****************************************************************************************
* Type definitions
****************************************************************************************/
/** \brief Groups information together of a firmware segment, such that it can be used
* as a node in a linked list.
*/
typedef struct t_firmware_segment
{
/** \brief Start memory address of the segment. */
uint32_t base;
/** \brief Number of data bytes in the segment. */
uint32_t length;
/** \brief Pointer to array with the segment's data bytes. */
uint8_t *data;
/** \brief Pointer to the previous node, or NULL if it is the first one. */
struct t_firmware_segment * prev;
/** \brief Pointer to the next node, or NULL if it is the last one. */
struct t_firmware_segment * next;
} tFirmwareSegment;
/** \brief Firmware file parser. */
typedef struct t_firmware_parser
{
/** \brief Extract the firmware segments from the firmware file and add them as nodes
* to the linked list.
*/
bool (* LoadFromFile) (char const * firmwareFile);
/** \brief Write all the firmware segments from the linked list to the specified
* firmware file.
*/
bool (* SaveToFile) (char const * firmwareFile);
} tFirmwareParser;
/****************************************************************************************
* Function prototypes
****************************************************************************************/
void FirmwareInit(tFirmwareParser const * parser);
void FirmwareTerminate(void);
bool FirmwareLoadFromFile(char const * firmwareFile);
bool FirmwareSaveToFile(char const * firmwareFile);
uint32_t FirmwareGetSegmentCount(void);
tFirmwareSegment * FirmwareGetSegment(uint32_t segmentIdx);
bool FirmwareAddData(uint32_t address, uint32_t len, uint8_t const * data);
bool FirmwareRemoveData(uint32_t address, uint32_t len);
void FirmwareClearData(void);
#ifdef __cplusplus
}
#endif
#endif /* FIRMWARE_H */
/********************************* end of firmware.h ***********************************/

View File

@ -0,0 +1,129 @@
// ---------------------------------------------------------------------
// This file is provided by Gimpel Software (www.gimpel.com) for use with
// its products PC-lint and FlexeLint.
//
// Redistribution and use of this file, with or without modification, is
// permitted provided that any such redistribution retains this notice.
// ---------------------------------------------------------------------
#ifndef CO_GCC_H_
#define CO_GCC_H_
/*lint -save -w1 */
#ifdef _lint /* Make sure no compiler comes this way */
#ifdef __cplusplus
extern "C" {
#endif
/* Standard library headers typically define the assert macro so that it
expands to a complicated conditional expression that uses special
funtions that Lint does not know about by default. For linting
purposes, we can simplify things a bit by forcing assert() to expand to
a call to a special function that has the appropriate 'assert'
semantics.
*/
//lint -function( __assert, __lint_assert )
void __lint_assert( int );
//lint ++d"assert(e)=__lint_assert(!!(e))"
//(++d makes this definition permanently immutable for the Lint run.)
//Now that we've made our own 'assert', we need to keep people from being
//punished when the marco in 'assert.h' appears not to be used:
//lint -efile(766,*assert.h)
typedef char *__builtin_va_list;
/*lint -e{171} */
__builtin_va_list __lint_init_va(...);
void __builtin_va_end( __builtin_va_list );
/*lint
++d"__builtin_va_start(ap,parmN)=((ap)=__lint_init_va(parmN))"
++d"__builtin_va_arg(a,b)=(*( ((b) *) ( (((a) += sizeof(b)) - sizeof(b) )))"
*/
/*
The headers included below must be generated; For C++, generate
with:
g++ [usual build options] -E -dM t.cpp >lint_cppmac.h
For C, generate with:
gcc [usual build options] -E -dM t.c >lint_cmac.h
...where "t.cpp" and "t.c" are empty source files.
It's important to use the same compiler options used when compiling
project code because they can affect the existence and precise
definitions of certain predefined macros. See gcc-readme.txt for
details and a tutorial.
*/
#if defined(__cplusplus)
# include "lint_cppmac.h" // DO NOT COMMENT THIS OUT. DO NOT SUPPRESS ERROR 322. (If you see an error here, your Lint configuration is broken; check -i options and ensure that you have generated lint_cppmac.h as documented in gcc-readme.txt. Otherwise Gimpel Software cannot support your configuration.)
#else
# include "lint_cmac.h" // DO NOT COMMENT THIS OUT. DO NOT SUPPRESS ERROR 322. (If you see an error here, your Lint configuration is broken; check -i options and ensure that you have generated lint_cmac.h as documented in gcc-readme.txt. Otherwise Gimpel Software cannot support your configuration.)
#endif
/* If the macro set given by the generated macro files must be adjusted in
order for Lint to cope, then you can make those adjustments here.
*/
#define LINT_CO_GCC_H_GCC_VERSION ( __GNUC__ * 10000 + \
__GNUC_MINOR__ * 100 + \
__GNUC_PATCHLEVEL__ )
/* The following is a workaround for versions of GCC with bug 25717, in
which the preprocessor does not dump a #define directive for __STDC__
when -dM is given:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=25717
We know the unconditional definition of __STDC__ was introduced no
later than version 3.0; the preprocessor bug was fixed no later than
version 4.1.0.
*/
#if ( LINT_CO_GCC_H_GCC_VERSION >= 30000 && \
LINT_CO_GCC_H_GCC_VERSION < 40100 )
# define __STDC__ 1
#endif
#if !__cplusplus && !__STRICT_ANSI__ && __STDC_VERSION__ < 199901L
/* apparently, the code is compiled with -std=gnu89 (as opposed to -std=c89),
so: */
/*lint -rw_asgn(inline,__inline) */
#endif
#if LINT_CO_GCC_H_GCC_VERSION >= 40300
# define __COUNTER__ __lint__COUNTER__
//lint +rw( *type_traits ) // Enable type traits support
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif
#if _lint >= 909 // For 9.00i and later:
//// __attribute__ is GCC's __attribute__:
//
//lint -rw_asgn(__attribute__,__gcc_attribute__)
//lint -rw_asgn(__attribute, __gcc_attribute__)
//
//// Prevent "__attribute__" from being defined as a macro:
//
//lint --u"__attribute__"
//lint --u"__attribute"
//
//// Because an attribute-specifier is a form of
//// declaration-modifier, and because it can appear at the
//// beginning of a decl-specifier-seq, we must enable "Early
//// Modifiers":
//
//lint +fem
#else // for 9.00h and earlier:
//lint -d__attribute__()=
//lint -d__attribute()=
#endif
#endif /* _lint */
/*lint -restore */
#endif /* CO_GCC_H_ */

View File

@ -0,0 +1,209 @@
/* Date Stamp */ -d"_lint_co_gcc_lnt=co-gcc.lnt modified 12-Jun-2014"
/* To document usage use: -message( "Using " _lint_co_gcc_lnt ) */
// ---------------------------------------------------------------------
// This file is provided by Gimpel Software (www.gimpel.com) for use with
// its products PC-lint and FlexeLint.
//
// Redistribution and use of this file, with or without modification, is
// permitted provided that any such redistribution retains this notice.
// ---------------------------------------------------------------------
/* co-gcc.lnt: This is the seed file for configuring Lint for use with
GCC versions 2.95.3 and later.
Like all compiler options files this file is intended to be used
as follows:
lint co-gcc.lnt source-files-to-be-linted
Some of the information that co-gcc.lnt requires needs to be furnished
with the help of the gcc system itself. The easiest way to generate
this information is to use the makefile co-gcc.mak (supplied with the
Lint distribution) in an invocation of GNU Make; for details, see the
commentary at the top of co-gcc.mak.
*/
-cgnu // Notifies FlexeLint that gcc is being used.
// ===========================
// Preprocessor Configuration:
+fdi // GCC starts its #include search in the directory of the including
// file.
++fln // Allow:
// # digit-sequence " [s-char-sequence] " new-line
// as a synonym for:
// # line digit-sequence " [s-char-sequence] " new-line
// GCC additionally allows flag values to follow the
// s-char-sequence, but currently Lint ignores them.
-header(co-gcc.h) // Includes headers generated by GCC (bringing in
// predefined macros).
+libh(co-gcc.h) // Marks that header as library code.
gcc-include-path.lnt // This .lnt file should contain --i options
// and should be generated by invoking gcc with its '-v' option.
// (GCC's implicit #include search path is presented in the output.)
// This happens automatically when 'make -f co-gcc.mak' is invoked.
// Assertion directives (a feature of GCC's preprocessor) have been
// considered obsolete in GCC's documentation since version 3.0, so we do
// not use them here. If support for #assert is needed in the form of a
// lint option, one may use '-a#' like so:
// -a#machine(i386) // #assert's machine(i386) (SVR4 facility).
// File extensions:
// From the GCC man page:
//
// file.cc
// file.cp
// file.cxx
// file.cpp
// file.CPP
// file.c++
// file.C
// C++ source code that must be preprocessed. Note that in .cxx, the
// last two letters must both be literally x. Likewise, .C refers to
// a literal capital C.
//
// We emulate this with:
+cpp(.cc)
+cpp(.cp)
+cpp(.cxx)
+cpp(.cpp)
+cpp(.c++)
// Note the exceptions:
// +cpp(.CPP)
// +cpp(.C)
// These are commented out for the default config because they seem to
// cause trouble more often than not. For starters, it is problematic
// with filesystems that are case-insensitive (which has become common
// even on some POSIX systems).
// =============
// Size Options:
// +fwc // wchar_t might be builtin; if so, uncomment this option. (NOTE:
// // this option needs to be set before a size option is given for
// // wchar_t; see the documentation for -sw# in the Lint manual.)
size-options.lnt // This .lnt file should be generated (preferrably
// by a program created by invoking GCC with the compile options that
// are used in the compilation of the project to be linted). This
// happens automatically when 'make -f co-gcc.mak' is invoked.
// ===========================================
// +rw and -d options to cope with GNU syntax:
+ppw(ident) // Tolerate #ident
+ppw(warning)
// GCC provides alternative spellings of certain keywords:
+rw(__inline)
-rw_asgn(__inline__,__inline)
-rw_asgn(__header_always_inline,__inline)
-rw_asgn(__header_inline,__inline)
-rw_asgn(__signed__,signed)
-rw_asgn(__signed,signed)
-rw_asgn( __volatile__, volatile )
-rw_asgn( __volatile, volatile )
+rw(restrict)
-rw_asgn(__restrict,restrict)
-rw_asgn(__restrict__,restrict)
++d"__const=const" // gconv.h uses __const rather than const
++d"const=const" // ensure const expands to const.
-rw_asgn( asm, _up_to_brackets )
-rw_asgn( __asm, _up_to_brackets )
-rw_asgn( __asm__, _up_to_brackets )
// This re-definition of the various spellings of the asm keyword enables
// Lint to pass gracefully over expression-statements like:
// __asm __volatile ("fsqrt" : "=t" (__result) : "0" (__x));
// But it may be necessary to suppress certain error messages that are
// triggered by tokens that are part of an assembly declaration or
// statement. For example:
-d"__asm__(p...)=/*lint -e{19}*/ __asm__(p)"
// ...causes Lint to be quiet about the semicolon that follows an
// __asm__() declaration. Note, the -e{N} form of suppression takes
// effect only for the forward-declaration, definition or
// [possibly-compound] statement that immediately follows. Because a
// semicolon is seen as a declaration-terminator, Error 19 will be
// re-enabled immediately after the semicolon in '__asm__(...);'.
// (The elipsis after the macro parameter p allows zero or more commas to
// appear in the operand.)
//
// If you encounter other diagnostics that appear to need suppression in
// or near assembly regions, please let us know!
//
-esym(123,__asm__)
-rw_asgn(__alignof__,__alignof)
// "__extension__" is GCC's way of allowing the use of non-standard
// constructs in a strict Standard-conforming mode. We don't currently
// have explicit support for it, but we can use local suppressions. For
// example, we can use -e(160) so that we will not see any Errors about
// GNU statement-expressions wrapped in __extension__().
++d"__extension__=/*lint -e(160) */"
++d"__null=0"
+rw(_to_semi) // needed for the two macros above.
+rw(__typeof__) // activate __typeof__ keyword
-d"__typeof=__typeof__" // an alternative to using __typeof__
-rw(__except) // This MS reserved word is used as an identifier
+rw( __complex__, __real__, __imag__ ) // reserved words that can be ignored.
++d"__builtin_strchr=(char*)" // permits the inline definition ...
++d"__builtin_strpbrk=(char*)" // of these functions to be linted ...
++d"__builtin_strrchr=(char*)" // without drawing a complaint
++d"__builtin_strstr=(char*)" // about the use of a non-standard name
++d"__PRETTY_FUNCTION__=___function___" // lint defines ___function___ internally
++d"__FUNCTION__=___function___" // lint defines ___function___ internally
++d"__func__=___function___" // Some C++ modes suport the implicit __func__
// identifier.
-ident($)
// =========================================================
// Other options supporting GNU C/C++ syntax:
+fld // enables the processing of _L_abel _D_esignators E.g.:
// union { double d; int i; } u = { d: 3.141 };
// =========================================================
// Generally useful suppressions:
-wlib(1) // sets the warning level within library headers to 1
// (no warnings, just syntax errors). Comment out if you
// are actually linting library headers.
-elib(123) // 123 is really a warning, but it's in the "Error" range.
-elib(93) // allow newlines within quoted string arguments to macros
-elib(46) // allow bit fields to have integral types other than
// '_Bool' and 'int'.
-elibsym(628) // Suppress 628 for __builtin symbols.
-esym(528,__huge_val,__nan,__qnan,__qnanf,__snan,__snanf)
// We don't care if we don't reference some GNU functions
-esym(528,__gnu_malloc,__gnu_calloc)
// The following functions exhibit variable return modes.
// That is, they may equally-usefully be called for a value
// as called just for their effects. Accordingly we inhibit
// Warning 534 for these functions.
// Feel free to add to or subtract from this list.
-esym(534,close,creat,fclose,fprintf,fputc)
-esym(534,fputs,fscanf,fseek,fwrite,lseek,memcpy,memmove,memset)
-esym(534,printf,puts,scanf,sprintf,sscanf,strcat,strcpy)
-esym(534,strncat,strncpy,unlink,write)
// For non-ANSI compilers we suppress messages 515 and 516
// for functions known to have variable argument lists.
// For ANSI compilers, header files should take care of this.
-esym(515,fprintf,printf,sprintf,fscanf,scanf,sscanf)
-esym(516,fprintf,printf,sprintf,fscanf,scanf,sscanf)
-esym(1702,*operator<<,*operator>>)
-esym(534,*operator<<,*operator>>)
-esym(1055,*__builtin*)
-esym(718,*__builtin*) // The compiler does not need these ...
-esym(746,*__builtin*) // declared and it knows their prototypes.

View File

@ -0,0 +1,5 @@
--i/usr/lib/gcc/x86_64-pc-linux-gnu/6.3.1/include
--i/usr/local/include
--i/usr/lib/gcc/x86_64-pc-linux-gnu/6.3.1/include-fixed
--i/usr/include

View File

@ -0,0 +1,319 @@
Using FlexeLint with GCC
These notes describe how to use the option file co-gcc.lnt which serves
as a replacement for the older co-gnu.lnt and co-gnu3.lnt options files.
--- Quick Start ---
If you just want a quick-and-dirty Lint configuration (one that enables
you to use Standard Library headers and system headers) then use the
makefile 'co-gcc.mak' (supplied with the Lint distribution) in an
invocation of GNU Make like so:
make -f co-gcc.mak
... which should generate the following files (provided that 'gcc', 'g++'
and 'awk' are each found in your $PATH):
lint_cmac.h
lint_cppmac.h
gcc-include-path.lnt
size-options.lnt
(co-gcc.lnt depends on these files, so they must be generated before you
do anything else.)
That's it! You should now be able to run:
flint co-gcc.lnt [source files]
Note that Lint must be able to find co-gcc.lnt and the files referenced
therein. If you want to keep them in a separate directory (e.g.,
/usr/local/etc/flint) from the one where you will invoke Lint (e.g.,
~/some-project/src), you'll need to specify the former with a '-i' option
so that Lint will know where to look. In that case, the invocation would
look like:
flint -i /usr/local/etc/flint co-gcc.lnt [source files]
If your project is compiled without any explicit command-line switches
other than '-c' then this invocation alone might be all that you need to
get started linting your project. Otherwise it probably won't suffice.
For a Lint configuration that better matches the way you compile your
code, you should at least read the 'usage' note at the top of co-gcc.mak.
For a motivation for the contents of co-gcc.mak, and to better understand
the configuration issues in general, please read on.
--- Introduction ---
The configuration of Lint for use with GCC-compiled sources is complicated
by two major issues:
First, GCC defines a large number of preprocessor macros internally (i.e.,
it defines a lot of macros for which there are no '#define' directives in
any source file that Lint can read.). Unless this issue is resolved for
each project, Lint will not see the same sequence of C/C++ tokens as GCC
when it tries to analyze your program, and as a result it will not see the
same set of declarations; consequently you'll see lots of spurious
messages because the analysis will reflect that of a program that is
truly ill-formed (unlike the program seen by GCC).
Second, GCC is aware of several built-in functions. Most of them can be
presented to Lint as ordinary forward-declarations of functions so as to
avoid undesired diagnostics claiming that these functions were not
declared before the first point of use. Note, these declarations do not
necessarily need to be presented to GCC.
--- Solving the Preprocessor Problem ---
Before we get started, we'll need an empty C source file. Call it
'empty.c' and save it to disk. Next, use your favorite command
interpreter environment (such as sh in Unix-like environments or cmd.exe
on Windows) and go to the directory containing 'empty.c'. Verify that you
can run GCC by doing the following:
gcc -v
If your environment is properly set up you should see a version string.
(You'll also want to verify that this is the same GCC executable used to
compile your sources; check the PATH environment variable or try running
'which gcc'.)
Assuming that worked, you can now try the following (and note that case,
as with C/C++ identifiers, is important.):
gcc -E -dM empty.c
On one system, we then see definitions like:
#define __DBL_MIN_EXP__ (-1021)
#define __FLT_MIN__ 1.17549435e-38F
#define __DEC64_DEN__ 0.000000000000001E-383DD
... followed by about a hundred more '#define' directives. What just
happened? We passed two options to gcc; the first one, '-E', means,
"don't run the compiler; just run the preprocessor". The option '-dM'
(not to be confused with '-DM', which is completely different) means,
"don't generate preprocessor output; instead, only dump all macro
definitions, including those defined internally".
With this output, we are now halfway to the point of having a preprocessor
configuration for Lint. First, let's redirect those macros to a file:
gcc -E -dM empty.c >lint_cmac.h
Next, let's test our configuration: make a simple C source file
containing the "Hello, world" program in a file called 't.c' (in the same
directory as 'empty.c')
#include <stdio.h>
int main () {
printf( "hello, world!\n" );
}
To lint this program, first copy the lnt file (co-gcc.lnt) and the
associated header (co-gcc.h) into the same directory. Next, create two
new empty files:
size-options.lnt
gcc-include-path.lnt
... and save them to disk. Then make a file called 'std.lnt' which will
(at first) contain only:
co-gcc.lnt
This tells Lint, "process the arguments in co-gcc.lnt". Two of those
arguments are:
-header(co-gcc.h) // #include's headers generated by GCC.
+libh(co-gcc.h) // Marks co-gcc.h as library code.
'-header(co-gcc.h)' means "behave as if each primary source file began
with '#include "co-gcc.h"'. (Note that co-gcc.h includes "lint_cmac.h"
when Lint runs in C language mode.)
Finally, try running:
/path/to/flint std.lnt t.c
... or, on Windows:
[drive-letter]:\path\to\lint-nt std.lnt t.c
Next we'll see output similar to the following:
FlexeLint for C/C++ (Unix/386) Vers. 9.00c, Copyright Gimpel Software
1985-2009
--- Module: t.c (C)
_
#include <stdio.h>
t.c 3 Error 322: Unable to open include file 'stdio.h'
What went wrong? The problem is that we haven't yet addressed the other
half of the preprocessor configuration, namely: the ordered sequence of
directories to search for system headers. Fortunately GCC already knows
this list and gives us a way to discover it. Just run:
gcc -c -v empty.c
On one system (specifically, Mac OS X on Intel), that yields a lot of
verbose output including these lines:
#include "..." search starts here:
#include <...> search starts here:
/usr/local/include
/usr/lib/gcc/i686-apple-darwin8/4.0.1/include
/usr/include
/System/Library/Frameworks
/Library/Frameworks
End of search list.
(Naturally, that list will look a bit different in different
environments.) To make Lint search for system headers in the same way, we
need to take that output from GCC and use it to make a set of options of
the form --i[directory]. E.g. on the same system, that means that in
gcc-include-path.lnt, I should place the following --i options:
--i/usr/local/include
--i/usr/lib/gcc/i686-apple-darwin8/4.0.1/include
--i/usr/include
--i/System/Library/Frameworks
--i/Library/Frameworks
(Note, arguments to Lint are processed in order, so the --i options must
appear before t.c or they will not take effect in time.)
In this case, none of the directory names contains a space, but if one of
them did we would have to surround its name with quotes as in:
--i"/usr/local/include"
Now let's try linting "hello, world" again:
/path/to/flint std.lnt t.c
This time we should see no error messages. Are we done yet? Not quite.
First, let's test our configuration against all of the C Standard Library
headers. Modify t.c to:
#include <assert.h>
#include <iso646.h>
#include <setjmp.h>
#include <stdio.h>
#include <time.h>
#include <ctype.h>
#include <limits.h>
#include <signal.h>
#include <stdlib.h>
#include <wchar.h>
#include <errno.h>
#include <locale.h>
#include <stdarg.h>
#include <string.h>
#include <wctype.h>
#include <float.h>
#include <math.h>
#include <stddef.h>
int main () {
printf( "hello, world!\n" );
}
... and try linting again:
/path/to/flint std.lnt t.c
This time you should see a number of messages; in particular, you should
see Info 766 issued for most of these headers since they were not used.
you may also see some legitimate warnings, and you may see an Error or two
about 'wchar_t'. (Note, if it seems as though your port of GCC recognizes
wchar_t as a keyword instead of an identifier then uncomment the use of
'+fwc' in your copy of co-gcc.lnt).
[NOTE: we should point out that the option -wlib(1) is in co-gcc.lnt for a
reason. Please note that we *strongly* recommend against the use of
options like -wlib(0) or -elib(*). If you see syntax error messages about
library header code, odds are that something is wrong with the Lint
configuration; so you'll do yourself no favors by silencing Lint when it
sees constructs that Lint's parser doesn't know how to handle. If you need
help with correcting your configuration, please check the Lint manual or
contact us.]
We should really be done now, right? Well, not quite. A remaining issue
is that the set of predefined macros (dumped into "lint_cmac.h" earlier)
depends not only on things like the target system and the version of GCC;
it also depends on the options that you pass to GCC when you compile your
program. E.g., if we invoke:
gcc -O3 -E -dM empty.c >lint_cmac.h
... then (with the version of GCC we tested) lint_cmac.h will no longer
contain a definition for the macro '__NO_INLINE__' and contains a new
definition for '__OPTIMIZE__'. So when you generate macros, you should be
careful to pass in the full set of options used when you compile.
Ideally, you should establish a target in your build system that
re-generates the predefined macro header whenever your build configuration
changes; that way you'll seldom need to think about it again and Lint's
preprocessor configuration will always match the compiler's.
Assuming you've generated the right set of predefined macros for your
build settings, you should now try Linting a single primary source file in
your project. Since we're just starting out, let's run with -w1 (i.e.,
with the warning level set to one) so that we can deal with any syntax
errors that pop up:
flint std.lnt -u -w1 some-project-file.c
Again, remember that syntax errors at this stage are likely due to a
misconfiguration; please check the Lint manual for likely remedies or
contact us if the solution is not obvious.
Once you've taken care of all syntax errors, try doing the same with all
project files. We recommend placing the name of each project file in a
.lnt file (often called project.lnt); e.g.:
file1.c
file2.c
[...etc.]
... and invoke Lint like so:
flint std.lnt -w1 project.lnt
When all syntax errors are resolved, you can begin turning on Warning
messages (i.e., those listed in section 17.4 of the Lint manual). You can
turn them on individually after '-w1' or you can instead use '-w2' and
then suppress the Warnings that are less severe. (For details on message
suppression, see section 5.2 of the Lint manual.)
At this point, you should be well-equipped to Lint any C program compiled
with GCC. However, C++ users have a couple more points to consider.
The command used to invoke GCC also affects the set of predefined macros.
Observe the difference in '#define' output when you invoke:
g++ -O3 -E -dM empty.c >lint_cppmac.h
diff lint_cmac.h lint_cppmac.h
Also, note that the list of directories to search for Standard Library
headers has some new additions when you use 'g++ -v -c empty.c' instead of
'gcc -v -c empty.c'. Your sequence of --i options should be set
accordingly.
That's about it for the preprocessor.
--- Size options ---
Finally, you'll need to establish sizes of primitive types. E.g. for a
64-bit platform this includes setting '-sp8' (indicating that pointers are
8 bytes wide). It often also involves setting '-sl8' (indicating that
'long' is eight bytes wide). As suggested earlier, the makefile
co-gcc.mak can generate these options for you.
If you find this tutorial to be lacking in some way, please contact us
(support@gimpel.com) with your suggestions for improvement.

View File

@ -0,0 +1,250 @@
#define __DBL_MIN_EXP__ (-1021)
#define __UINT_LEAST16_MAX__ 0xffff
#define __ATOMIC_ACQUIRE 2
#define __FLT_MIN__ 1.17549435082228750797e-38F
#define __GCC_IEC_559_COMPLEX 2
#define __UINT_LEAST8_TYPE__ unsigned char
#define __SIZEOF_FLOAT80__ 16
#define __INTMAX_C(c) c ## L
#define __CHAR_BIT__ 8
#define __UINT8_MAX__ 0xff
#define __WINT_MAX__ 0xffffffffU
#define __ORDER_LITTLE_ENDIAN__ 1234
#define __SIZE_MAX__ 0xffffffffffffffffUL
#define __WCHAR_MAX__ 0x7fffffff
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1
#define __DBL_DENORM_MIN__ ((double)4.94065645841246544177e-324L)
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1
#define __GCC_ATOMIC_CHAR_LOCK_FREE 2
#define __GCC_IEC_559 2
#define __FLT_EVAL_METHOD__ 0
#define __unix__ 1
#define __GCC_ATOMIC_CHAR32_T_LOCK_FREE 2
#define __x86_64 1
#define __UINT_FAST64_MAX__ 0xffffffffffffffffUL
#define __SIG_ATOMIC_TYPE__ int
#define __DBL_MIN_10_EXP__ (-307)
#define __FINITE_MATH_ONLY__ 0
#define __GNUC_PATCHLEVEL__ 1
#define __UINT_FAST8_MAX__ 0xff
#define __has_include(STR) __has_include__(STR)
#define __DEC64_MAX_EXP__ 385
#define __INT8_C(c) c
#define __UINT_LEAST64_MAX__ 0xffffffffffffffffUL
#define __SHRT_MAX__ 0x7fff
#define __LDBL_MAX__ 1.18973149535723176502e+4932L
#define __UINT_LEAST8_MAX__ 0xff
#define __GCC_ATOMIC_BOOL_LOCK_FREE 2
#define __UINTMAX_TYPE__ long unsigned int
#define __linux 1
#define __DEC32_EPSILON__ 1E-6DF
#define __unix 1
#define __UINT32_MAX__ 0xffffffffU
#define __LDBL_MAX_EXP__ 16384
#define __WINT_MIN__ 0U
#define __linux__ 1
#define __SCHAR_MAX__ 0x7f
#define __WCHAR_MIN__ (-__WCHAR_MAX__ - 1)
#define __INT64_C(c) c ## L
#define __DBL_DIG__ 15
#define __GCC_ATOMIC_POINTER_LOCK_FREE 2
#define __SIZEOF_INT__ 4
#define __SIZEOF_POINTER__ 8
#define __USER_LABEL_PREFIX__
#define __STDC_HOSTED__ 1
#define __LDBL_HAS_INFINITY__ 1
#define __FLT_EPSILON__ 1.19209289550781250000e-7F
#define __LDBL_MIN__ 3.36210314311209350626e-4932L
#define __STDC_UTF_16__ 1
#define __DEC32_MAX__ 9.999999E96DF
#define __INT32_MAX__ 0x7fffffff
#define __SIZEOF_LONG__ 8
#define __STDC_IEC_559__ 1
#define __STDC_ISO_10646__ 201505L
#define __UINT16_C(c) c
#define __DECIMAL_DIG__ 21
#define __gnu_linux__ 1
#define __has_include_next(STR) __has_include_next__(STR)
#define __LDBL_HAS_QUIET_NAN__ 1
#define __GNUC__ 6
#define __MMX__ 1
#define __FLT_HAS_DENORM__ 1
#define __SIZEOF_LONG_DOUBLE__ 16
#define __BIGGEST_ALIGNMENT__ 16
#define __DBL_MAX__ ((double)1.79769313486231570815e+308L)
#define __INT_FAST32_MAX__ 0x7fffffffffffffffL
#define __DBL_HAS_INFINITY__ 1
#define __DEC32_MIN_EXP__ (-94)
#define __INT_FAST16_TYPE__ long int
#define __LDBL_HAS_DENORM__ 1
#define __DEC128_MAX__ 9.999999999999999999999999999999999E6144DL
#define __INT_LEAST32_MAX__ 0x7fffffff
#define __DEC32_MIN__ 1E-95DF
#define __DBL_MAX_EXP__ 1024
#define __DEC128_EPSILON__ 1E-33DL
#define __SSE2_MATH__ 1
#define __ATOMIC_HLE_RELEASE 131072
#define __PTRDIFF_MAX__ 0x7fffffffffffffffL
#define __amd64 1
#define __STDC_NO_THREADS__ 1
#define __ATOMIC_HLE_ACQUIRE 65536
#define __LONG_LONG_MAX__ 0x7fffffffffffffffLL
#define __SIZEOF_SIZE_T__ 8
#define __SIZEOF_WINT_T__ 4
#define __GCC_HAVE_DWARF2_CFI_ASM 1
#define __GXX_ABI_VERSION 1010
#define __FLT_MIN_EXP__ (-125)
#define __INT_FAST64_TYPE__ long int
#define __DBL_MIN__ ((double)2.22507385850720138309e-308L)
#define __LP64__ 1
#define __DECIMAL_BID_FORMAT__ 1
#define __DEC128_MIN__ 1E-6143DL
#define __REGISTER_PREFIX__
#define __UINT16_MAX__ 0xffff
#define __DBL_HAS_DENORM__ 1
#define __UINT8_TYPE__ unsigned char
#define __NO_INLINE__ 1
#define __FLT_MANT_DIG__ 24
#define __VERSION__ "6.3.1 20170306"
#define __UINT64_C(c) c ## UL
#define _STDC_PREDEF_H 1
#define __GCC_ATOMIC_INT_LOCK_FREE 2
#define __FLOAT_WORD_ORDER__ __ORDER_LITTLE_ENDIAN__
#define __STDC_IEC_559_COMPLEX__ 1
#define __INT32_C(c) c
#define __DEC64_EPSILON__ 1E-15DD
#define __ORDER_PDP_ENDIAN__ 3412
#define __DEC128_MIN_EXP__ (-6142)
#define __INT_FAST32_TYPE__ long int
#define __UINT_LEAST16_TYPE__ short unsigned int
#define unix 1
#define __INT16_MAX__ 0x7fff
#define __SIZE_TYPE__ long unsigned int
#define __UINT64_MAX__ 0xffffffffffffffffUL
#define __INT8_TYPE__ signed char
#define __ELF__ 1
#define __GCC_ASM_FLAG_OUTPUTS__ 1
#define __FLT_RADIX__ 2
#define __INT_LEAST16_TYPE__ short int
#define __LDBL_EPSILON__ 1.08420217248550443401e-19L
#define __UINTMAX_C(c) c ## UL
#define __SSE_MATH__ 1
#define __k8 1
#define __SIG_ATOMIC_MAX__ 0x7fffffff
#define __GCC_ATOMIC_WCHAR_T_LOCK_FREE 2
#define __SIZEOF_PTRDIFF_T__ 8
#define __x86_64__ 1
#define __DEC32_SUBNORMAL_MIN__ 0.000001E-95DF
#define __INT_FAST16_MAX__ 0x7fffffffffffffffL
#define __UINT_FAST32_MAX__ 0xffffffffffffffffUL
#define __UINT_LEAST64_TYPE__ long unsigned int
#define __FLT_HAS_QUIET_NAN__ 1
#define __FLT_MAX_10_EXP__ 38
#define __LONG_MAX__ 0x7fffffffffffffffL
#define __DEC128_SUBNORMAL_MIN__ 0.000000000000000000000000000000001E-6143DL
#define __FLT_HAS_INFINITY__ 1
#define __UINT_FAST16_TYPE__ long unsigned int
#define __DEC64_MAX__ 9.999999999999999E384DD
#define __CHAR16_TYPE__ short unsigned int
#define __PRAGMA_REDEFINE_EXTNAME 1
#define __SEG_FS 1
#define __INT_LEAST16_MAX__ 0x7fff
#define __DEC64_MANT_DIG__ 16
#define __INT64_MAX__ 0x7fffffffffffffffL
#define __UINT_LEAST32_MAX__ 0xffffffffU
#define __SEG_GS 1
#define __GCC_ATOMIC_LONG_LOCK_FREE 2
#define __INT_LEAST64_TYPE__ long int
#define __INT16_TYPE__ short int
#define __INT_LEAST8_TYPE__ signed char
#define __STDC_VERSION__ 201112L
#define __DEC32_MAX_EXP__ 97
#define __INT_FAST8_MAX__ 0x7f
#define __INTPTR_MAX__ 0x7fffffffffffffffL
#define linux 1
#define __SSE2__ 1
#define __LDBL_MANT_DIG__ 64
#define __DBL_HAS_QUIET_NAN__ 1
#define __SIG_ATOMIC_MIN__ (-__SIG_ATOMIC_MAX__ - 1)
#define __code_model_small__ 1
#define __k8__ 1
#define __INTPTR_TYPE__ long int
#define __UINT16_TYPE__ short unsigned int
#define __WCHAR_TYPE__ int
#define __SIZEOF_FLOAT__ 4
#define __UINTPTR_MAX__ 0xffffffffffffffffUL
#define __DEC64_MIN_EXP__ (-382)
#define __INT_FAST64_MAX__ 0x7fffffffffffffffL
#define __GCC_ATOMIC_TEST_AND_SET_TRUEVAL 1
#define __FLT_DIG__ 6
#define __UINT_FAST64_TYPE__ long unsigned int
#define __INT_MAX__ 0x7fffffff
#define __amd64__ 1
#define __INT64_TYPE__ long int
#define __FLT_MAX_EXP__ 128
#define __ORDER_BIG_ENDIAN__ 4321
#define __DBL_MANT_DIG__ 53
#define __SIZEOF_FLOAT128__ 16
#define __INT_LEAST64_MAX__ 0x7fffffffffffffffL
#define __GCC_ATOMIC_CHAR16_T_LOCK_FREE 2
#define __DEC64_MIN__ 1E-383DD
#define __WINT_TYPE__ unsigned int
#define __UINT_LEAST32_TYPE__ unsigned int
#define __SIZEOF_SHORT__ 2
#define __SSE__ 1
#define __LDBL_MIN_EXP__ (-16381)
#define __INT_LEAST8_MAX__ 0x7f
#define __SIZEOF_INT128__ 16
#define __LDBL_MAX_10_EXP__ 4932
#define __ATOMIC_RELAXED 0
#define __DBL_EPSILON__ ((double)2.22044604925031308085e-16L)
#define _LP64 1
#define __UINT8_C(c) c
#define __INT_LEAST32_TYPE__ int
#define __SIZEOF_WCHAR_T__ 4
#define __UINT64_TYPE__ long unsigned int
#define __INT_FAST8_TYPE__ signed char
#define __GNUC_STDC_INLINE__ 1
#define __DBL_DECIMAL_DIG__ 17
#define __STDC_UTF_32__ 1
#define __FXSR__ 1
#define __DEC_EVAL_METHOD__ 2
#define __UINT32_C(c) c ## U
#define __INTMAX_MAX__ 0x7fffffffffffffffL
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
#define __FLT_DENORM_MIN__ 1.40129846432481707092e-45F
#define __INT8_MAX__ 0x7f
#define __UINT_FAST32_TYPE__ long unsigned int
#define __CHAR32_TYPE__ unsigned int
#define __FLT_MAX__ 3.40282346638528859812e+38F
#define __INT32_TYPE__ int
#define __SIZEOF_DOUBLE__ 8
#define __FLT_MIN_10_EXP__ (-37)
#define __INTMAX_TYPE__ long int
#define __DEC128_MAX_EXP__ 6145
#define __ATOMIC_CONSUME 1
#define __GNUC_MINOR__ 3
#define __UINTMAX_MAX__ 0xffffffffffffffffUL
#define __DEC32_MANT_DIG__ 7
#define __DBL_MAX_10_EXP__ 308
#define __LDBL_DENORM_MIN__ 3.64519953188247460253e-4951L
#define __INT16_C(c) c
#define __STDC__ 1
#define __PTRDIFF_TYPE__ long int
#define __ATOMIC_SEQ_CST 5
#define __UINT32_TYPE__ unsigned int
#define __UINTPTR_TYPE__ long unsigned int
#define __DEC64_SUBNORMAL_MIN__ 0.000000000000001E-383DD
#define __DEC128_MANT_DIG__ 34
#define __LDBL_MIN_10_EXP__ (-4931)
#define __SIZEOF_LONG_LONG__ 8
#define __GCC_ATOMIC_LLONG_LOCK_FREE 2
#define __LDBL_DIG__ 18
#define __FLT_DECIMAL_DIG__ 9
#define __UINT_FAST16_MAX__ 0xffffffffffffffffUL
#define __GCC_ATOMIC_SHORT_LOCK_FREE 2
#define __UINT_FAST8_TYPE__ unsigned char
#define __ATOMIC_ACQ_REL 4
#define __ATOMIC_RELEASE 3

View File

@ -0,0 +1,85 @@
# This file contains functions and configurations for generating PC-Lint build
# targets for your CMake projects.
set(PC_LINT_EXECUTABLE "lint-nt.exe" CACHE STRING "full path to the pc-lint executable. NOT the generated lin.bat")
set(PC_LINT_CONFIG_DIR "${PROJECT_SOURCE_DIR}/lint/gnu" CACHE STRING "full path to the directory containing pc-lint configuration files")
set(PC_LINT_USER_FLAGS "-b" CACHE STRING "additional pc-lint command line options -- some flags of pc-lint cannot be set in option files (most notably -b)")
# a phony target which causes all available *_LINT targets to be executed
add_custom_target(ALL_LINT)
# add_pc_lint(target source1 [source2 ...])
#
# Takes a list of source files and generates a build target which can be used
# for linting all files
#
# The generated lint commands assume that a top-level config file named
# 'std.lnt' resides in the configuration directory 'PC_LINT_CONFIG_DIR'. This
# config file must include all other config files. This is standard lint
# behaviour.
#
# Parameters:
# - target: the name of the target to which the sources belong. You will get a
# new build target named ${target}_LINT
# - source1 ... : a list of source files to be linted. Just pass the same list
# as you passed for add_executable or add_library. Everything except
# C and CPP files (*.c, *.cpp, *.cxx) will be filtered out.
#
# Example:
# If you have a CMakeLists.txt which generates an executable like this:
#
# set(MAIN_SOURCES main.c foo.c bar.c)
# add_executable(main ${MAIN_SOURCES})
#
# include this file
#
# include(/path/to/pc_lint.cmake)
#
# and add a line to generate the main_LINT target
#
# if(COMMAND add_pc_lint)
# add_pc_lint(main ${MAIN_SOURCES})
# endif(COMMAND add_pc_lint)
#
function(add_pc_lint target)
get_directory_property(lint_include_directories INCLUDE_DIRECTORIES)
get_directory_property(lint_defines COMPILE_DEFINITIONS)
# let's get those elephants across the alps
# prepend each include directory with "-i"; also quotes the directory
set(lint_include_directories_transformed)
foreach(include_dir ${lint_include_directories})
list(APPEND lint_include_directories_transformed -i"${include_dir}")
endforeach(include_dir)
# prepend each definition with "-d"
set(lint_defines_transformed)
foreach(definition ${lint_defines})
list(APPEND lint_defines_transformed -d${definition})
endforeach(definition)
# list of all commands, one for each given source file
set(pc_lint_commands)
foreach(sourcefile ${ARGN})
# only include c and cpp files
if( sourcefile MATCHES \\.c$|\\.cxx$|\\.cpp$ )
# make filename absolute
get_filename_component(sourcefile_abs ${sourcefile} ABSOLUTE)
# create command line for linting one source file and add it to the list of commands
list(APPEND pc_lint_commands
COMMAND ${PC_LINT_EXECUTABLE}
-i"${PC_LINT_CONFIG_DIR}" std.lnt
"-u" ${PC_LINT_USER_FLAGS}
${lint_include_directories_transformed}
${lint_defines_transformed}
${sourcefile_abs})
endif()
endforeach(sourcefile)
# add a custom target consisting of all the commands generated above
add_custom_target(${target}_LINT ${pc_lint_commands} VERBATIM)
# make the ALL_LINT target depend on each and every *_LINT target
add_dependencies(ALL_LINT ${target}_LINT)
endfunction(add_pc_lint)

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@
co-gcc.lnt

View File

@ -0,0 +1,42 @@
// ---------------------------------------------------------------------
// This file is provided by Gimpel Software (www.gimpel.com) for use with
// its products PC-lint and FlexeLint.
//
// Redistribution and use of this file, with or without modification, is
// permitted provided that any such redistribution retains this notice.
// ---------------------------------------------------------------------
#ifndef LINT_SUPPORT_CO_MSC100_H_
#define LINT_SUPPORT_CO_MSC100_H_
// co-msc100.h --
// This header is automatically included in every module if you use
// co-msc100.lnt. (There is a -header(co-msc100.h) option therein
// for this purpose.)
// Microsoft's C++11 implementation does not yet include built-in support
// for the new character types, so we need to disable the relevant
// keywords here. (This must be done before the inclusion of any other
// header file because Microsoft's library headers contain declarations of
// typedef names with the same spelling.)
//lint -rw(char16_t,char32_t)
// Next we must compensate for the fact that class typeinfo is available
// for use in the MSC compilers without an explicit definition. According
// to the standard this class definition is not (available by default).
#ifdef __cplusplus
#include <typeinfo>
#else // C mode
// co-msc100.lnt defines some macros that the Microsoft compiler defines
// in C++ modes but not in C mode; we must un-define them here:
#undef _CPPRTTI
#undef _NATIVE_WCHAR_T_DEFINED
#undef _WCHAR_T_DEFINED
#undef _NATIVE_NULLPTR_SUPPORTED
#endif
#endif /* LINT_SUPPORT_CO_MSC100_H_ */

View File

@ -0,0 +1,461 @@
/* Date Stamp */ -d"_lint_co_msc100_lnt=co-msc100.lnt modified 19-Sep-2013"
/* To document usage use: -message( "Using " _lint_co_msc100_lnt ) */
// ---------------------------------------------------------------------
// This file is provided by Gimpel Software (www.gimpel.com) for use with
// its products PC-lint and FlexeLint.
//
// Redistribution and use of this file, with or without modification, is
// permitted provided that any such redistribution retains this notice.
// ---------------------------------------------------------------------
// co-msc100.lnt
// Compiler Options for Visual Studio for C/C++ Version 10.00
// (Visual Studio 2010)
// This file contains options to allow PC-lint to process source
// files for your compiler. It is used as follows:
//
// lint co-msc100.lnt source-file(s)
//
// (See macros-msc.c and/or macros-msc.cpp for details.)
// Section 1: options independent of the use of the automatic macro
// generator (macros-msc.cpp)
//
-cmsc
-A(C++2011)
+compiler(search_actively_including_stack)
-si4 // integers are 4 bytes
-sp4 // pointers are 4 bytes too.
// We now support __declspec directly so that the following
// option is now commented out. If trouble ensues you can
// once again disable __declspec through this option.
// -d__declspec()= // ignore this construct
-d_declspec=__declspec // the single '_' version is occasionally used
// while processing compiler (library) header files ...
-wlib(1) // sets the warning level within library headers to 1
// (no warnings, just syntax errors). Comment out if you
// are actually linting library headers. This
// option makes obsolete options of the form -elib(axxx) where
// xxx >= 400 which may be retained for historical reasons.
-elib(1111) // Some VC++ headers contain explicit specializations at class
// scope.
-elib(19) // useless declarations (lone semicolons)
-elib(123) // function-like macro name used as non macro
-elib(652) // suppress message about #define of earlier declared symbols
-elib(762) // suppress message about multiple identical declarations and
-elib(760) // suppress message about multiple identical macro defs
-elib(514) // allow #if <boolean> | <boolean>
-elib(553) // undefined preprocessor variables assumed 0
-elib(1081) // suspicious object argument to an object parameter
-elib(726) // extraneous comma in enum definition
-elib(157) // suppress message about no data may follow an incomplete array
-elib(91) // suppress message about line exceeds 598 characters
// SREGS, WORDREGS, BYTEREGS are defined in both bios.h and dos.h
// and accordingly you MAY get type differences based on 'origin'.
// If so, use the following options:
// -etd(origin)
// -elib(770)
-format=%(%f(%l)\s:\s%)%t\s%n:\s%m
// error format similar to MSC
// Note that %c can also be used to specify column
-e46 // allows bit-fields to be other than int or unsigned
+fan // allow anonymous unions
+fdi // Use directory of the including file
+fbo // enable the bool type
+fwm // wprintf format codes are not standard
-fdh // do not append a .h to header names
-esym(123,min,max) // allows users to use min, max as variables
+rw(__inline) // activate the __inline keyword
-rw_asgn(__nullptr,nullptr)
-e19 // Suppress errors about lone semicolons
+ppw(import) // activate #import
-d_inline=__inline // _inline is the same as __inline
-sld8 // sizeof(long double) is 8.
-function(exit,_exit) // _exit() is like exit()
-function(exit,_assert) // _assert() is like exit()
-emacro(506,assert) // don't warn about constant value Boolean
-emacro(734,putc) // don't complain about items being too large.
-emacro(415,_FP_SEG) // access of out-of-bounds pointer
-emacro(740,FP_SEG,FP_OFF) // unusual casts
-emacro((???),va_arg) // the va_arg() macro can yield 415, 416, 661, 662
// 796 and 797 (out-of-bounds errors).
-emacro((???),va_start) // the same applies to va_start
-emacro(413,offsetof) // use of NULL pointer creates a stir
-emacro(545,offsetof) // addressing an array member is OK
-emacro(845,RGB) // a common use of RGB uses a operator that produces a 0
-e793 // inhibit 'ANSI limit reached' --
// limits are impractically low with MSVC headers
-esym(628,eof) // failure to provide argument information for eof()
-esym(773,L_tmpnam) // defined with an unparenthesized '+'
-esym(438,_acp) // USES_CONVERSION assigns to _acp.
-emacro(571,__isascii) // don't warn about the unusual cast
-emacro(522,UNREFERENCED_PARAMETER) // don't complain about a lack of
// side-effects
-emacro(648,CDN_*) // ignore unsigned overflow
-emacro(648,OIVN_*) // ignore unsigned overflow
-emacro(648,TTN_*) // ignore unsigned overflow
-emacro(648,TVN_*) // ignore unsigned overflow
-emacro(648,TBN_*) // ignore unsigned overflow
// The following functions exhibit variable return modes.
// That is, they may equally-usefully be called for a value
// as called just for their effects. Accordingly we inhibit
// Warning 534 for these functions.
// Feel free to add to or subtract from this list.
-esym(534,close,creat,fclose,fflush,_flsbuf,fprintf,fputc)
-esym(534,fputs,fscanf,fseek,fwrite,lseek,memcpy,memmove,memset)
-esym(534,printf,puts,scanf,sprintf,sscanf,strcat,strcpy)
-esym(534,strncat,strncpy,unlink,write)
// These are the wide char variants of printf-scanf family
-wprintf( 1, wprintf )
-wprintf( 3, fwprintf, swprintf )
-wscanf( 1, wscanf )
-wscanf( 2, fwscanf, swscanf )
// These are substitutions for sprintf
-printf( 3, StringCbPrintfA )
-printf( 3, StringCchPrintfA )
-wprintf( 3, StringCbPrintfW )
-wprintf( 3, StringCchPrintfW )
// The following options are used to adjust our function mimicry to
// the actual library as provided by MS.
-function( wcstombs(1) ) // remove the check for a NULL first arg to wcstombs()
// The following options are required by most compilers to
// noiselessly process iostream.h
-elib(1717) // empty prototypes
-elib(522) // function return value ignored
-elib(1053) // prototypes cannot be distinguished
-elib(1721) // unusual operator =() declaration
-elib(1720) // assignment op has non-const parameter
-elib(655) // bitwise operator combining compatible enum's
-elib(641) // converting enum's to int
-elib(537) // repeated include file (ios.h)
-elib(1511) // member (rdbuf) hides nonvirtual member
-elib(1712) // default constructor not defined for class
-elib(1736) // redundant access specifier
-esym(1702,operator<<,operator>>) // both a member and an ordinary function
// These functions return things that are frequently ignored.
-esym(534,*operator<<,*operator>>)
// The following additional options seem to be needed.
-elib(506) // constant value Boolean
-elib(620) // el or one? (some constants end in 'l' not 'L')
-elib(648) // overflow in computing constant (3<<16)
-elib(659) // nothing fold_NATIVE_WCHAR_T_DEFINEDlows '}' on some line
-elib(723) // suspicious use of '='
-elib(747) // significant prototype coercion
-elib(740) // unusual pointer casts
-elib(1007) // virtual functions within extern "C" block
-elib(1029) // default argument repeated -- can't dist. char, signed char
-elib(1055) // call to rdbuf() questioned?
-elib(1504) // apparently useless structs
-elib(1708,1709) // minor C/C++ declaration conflict
-elib(1707) // operator new declared w/o 'static'
-elib(1722) // assignment op does not return reference
-elib(149) // default argument found in C code.
-elib(578) // declaration of time hides delaration of global time().
-elib(761) // two equivalent typedef declarations
-elib(1065) // same name declared as "C" and not "C"
-elib(1066) // same name declared as "C" and not "C"
-elib(1704) // constructor with private access declaration
-elib(1735) // default parameter within virtual function
-elib(773) // macros that look like unparenthesized expressions
-elib(806) // 1-bit bitfields typed int
-elib(1501) // 0-length data members
-elib(1510) // base class has no destructor
-elib(1516) // data member hides inherited member
-elib(1509) // base class destructor is not virtual
// Special Notice: You may be receiving mysterious 1058 errors
// when you use "iomanipulator"s. For example:
// cout << setw(4) << 4;
// results in Error 1058 (assigning a const to a ref) because the
// manipulator setw returns a non-lvalue which is assigned to a reference.
// This reflects an oversight in the Microsoft header file: iomanip.h
// Therein you may change the declaration:
// friend ostream& operator<<(iostream& s, IOMANIP(T) & sm) { ...
// to:
// friend ostream& operator<<(iostream& s, const IOMANIP(T) & sm) { ...
// to reflect the fact that sm is not modified by this function.
+fll // enable long long
// In the following option we define __uuidof() and suppress
// Errors 50 and 69 and 1924 in exprs. containing same
-d"__uuidof()= /*lint --e(50,69,1924) */ (_GUID)0"
-esym(123,FD_SET) // defined as macro and as typedef
-esym(1726,endl,ends) // taking the address of an overloaded function
-esym(18,Data_t::Data_t) // definition not matching declaration
-elib(10) // expecting ')' -- comdef.h has a: #if defined( id
-elib(43) // vacuous array within _MIDL_FORMAT_STRING
-elib(602) // benign comment within comment
-elib(657) // declaring "anonymous struct" in union _LARGE_INTEGER
-elib(799) // long numerical constant for max. __int64
-elib(1502) // nothrow has no data members
-elib(1505) // no access specifier in base class specifier
-elib(1515) // AFX_THREAD_STATE member has no default constructor
-elib(1706) // Unusual declaration with a scope operator
-elib(1725) // data member is a reference
-elib(1548) // conflicting exception specifications
-elib(1737) // hiding global operator new
-elib(1739) // binary operator should be non-member function
-elib(1748) // non-virtual base class included twice
-elib(1759) // post-fix operator returns a reference
// Add elements of ole automation
lib-ole.lnt
// Options required for .net
-d_stdcall=__stdcall // make _stdcall equivalent to __stdcall
-d__interface=class // treat an interface the same as a class
-d__unaligned= // pass over the __unaligned keyword
-d__w64= // ignore this identifier
-esym(40,DLGPROC) // used before being defined
-elib(146) // assuming binary constant
-elib(1015) // GetDefaultThreads not found in class
+ppw(using) // ignore #using for now.
-d__pragma(x)= // ignore the pragma extension
+rw(__ptr64) // additional qualifier
+rw_asgn(__thiscall,fortran) // additional qualifier
-"d__identifier(x)=___identifier x"
// treat C++ keyword x as an identifier
-elibsym(1512) // base class destructor not virtual
-d__TIMESTAMP__="Mon Jan 01 00:00:00 2010"
-d__COUNTER__=__lint__COUNTER__
-d__FUNCDNAME__="MyFunc"
-d__FUNCSIG__="MyFunc"
-d__FUNCTION__=___function___
-dinitonly= // Compiler should catch miss-uses.
// Lint can just skip over it.
-"dliteral=static const" // Documentation says they are
// equivalent for member data.
// __try_cast is like dynamic_cast (except the former throws where
// the latter returns 0).
-d__try_cast=dynamic_cast
+rw(__restrict) // reserved word
// Partial support for the "old" (VC++ 2003) Managed Extensions
// syntax:
+rw( __gc, __value, __nogc, __pin, __ptr32, __ptr64 )
-$ // $ can be used in identifiers
+rw( __allowed_on_parameter )
+rw( __allowed_on_function )
+rw( __allowed_on_typedecl )
+rw( __allowed_on_return )
+rw( __allowed_on_struct )
+rw( __allowed_on_function_or_typedecl )
+rw( __allowed_on_field )
+rw( __allowed_on_parameter_or_return )
+rw( __allowed_on_function )
+rw( *type_traits ) //type traits support
+e1942 // This Elective Note alerts the user to the non-standard
// way in which MS handles originally-dependent base classes.
// E.g. template<class T> class A : T { ... x ... };
// Should T be searched for "x" during instantiation?
// the standard says "no", MS does.
-header(co-msc100.h) // implicitly includes <typeinfo>. (Needed because
// MSVC 9 implicitly declares class type_info.)
// Section 2: options that should be commented out if you use the
// automatic macro generator (macros-msc.cpp)
// Note, a macro option of the form:
// -dA{1}
// has the same effect as:
// -dA=1
// or:
// -d"A=1"
// The curly-brace version of the syntax is appropriate for
// macro-scavenging (the method we used to generate the macro options
// below). For details, see notes on the -scavenge() option in section
// 5.8.3 in the Lint manual. See also the macro generator file,
// macros-msc.cpp, which follows the form of -scavenge() output.
// We generated the options in this section with the following commands:
// %VSInstallDir%\vc\bin\vcvars32.bat
// cl /EP /C macros-msc.cpp
// The options for other build configurations will probably differ (which
// is why you should comment out the following if you use the macro
// generator).
// Also note: some of the following are defined for C++ mode but not for C
// mode; but there's no need to comment them out here because they are
// conditionally #undef'd in co-msc100.h.
-d_CPPRTTI{1}
//
// Defined for code compiled with /GR (Enable Run-Time Type
// Information).
//
-d_INTEGRAL_MAX_BITS{64}
//
// Reports the maximum size (in bits) for an integral type.
//
// NOTE:
// When generating 64-bit code, the definition for _M_IX86 must be
// commented out.
-d_M_IX86{600}
//
// Defined for x86 processors. See the "Values for _M_IX86 table" (in
// Microsoft's preprocessor documentation) for more information. This
// is not defined for x64 processors.
//
-d_M_IX86_FP{0}
//
// Expands to a value indicating which /arch compiler option was used:
//
// 0 if /arch was not used.
//
// 1 if /arch:SSE was used.
//
// 2 if /arch:SSE2 was used.
//
// See /arch (Minimum CPU Architecture) for more information.
//
-d_MSC_BUILD{1}
//
// Evaluates to the revision number component of the compiler's
// version number. The revision number is the fourth component of the
// period-delimited version number. For example, if the version number
// of the Visual C++ compiler is 15.00.20706.01, the _MSC_BUILD macro
// evaluates to 1.
//
-d_MSC_EXTENSIONS{1}
//
// This macro is defined when you compile with the /Ze compiler option
// (the default). Its value, when defined, is 1.
//
-d_MSC_FULL_VER{160030319}
//
// Evaluates to the major, minor, and build number components of the
// compiler's version number. The major number is the first component
// of the period-delimited version number, the minor number is the
// second component, and the build number is the third component. For
// example, if the version number of the Visual C++ compiler is
// 15.00.20706.01, the _MSC_FULL_VER macro evaluates to 150020706.
// Type cl /? at the command line to view the compiler's version
// number.
//
-d_MSC_VER{1600}
//
// Evaluates to the major and minor number components of the
// compiler's version number. The major number is the first component
// of the period-delimited version number and the minor number is the
// second component.
//
// For example, if the version number of the Visual C++ compiler is
// 15.00.20706.01, the _MSC_VER macro evaluates to 1500.
//
// In Visual Studio 2010, _MSC_VER is defined as 1600.
//
-d_MT{1}
//
// Defined when /MD or /MDd (Multithreaded DLL) or /MT or /MTd
// (Multithreaded) is specified.
//
-d_NATIVE_WCHAR_T_DEFINED{1}
//
// Defined when /Zc:wchar_t is used.
//
-d_WCHAR_T_DEFINED{1}
//
// Defined when /Zc:wchar_t is used or if wchar_t is defined in a
// system header file included in your project.
//
-d_WIN32{1}
//
// Defined for applications for Win32 and Win64. Always defined.
//
/**** Undocumented predefined macros follow ****/
-d_NATIVE_NULLPTR_SUPPORTED{1}
// Section 3: options that should remain commented out if you use the
// automatic macro generator (macros-msc.cpp)
// When compiling with /J, use:
//+fcu // Plain char is unsigned
//-d_CHAR_UNSIGNED
// When compiling with /clr, /clr:pure or /clr:safe, use:
//-d__cplusplus_cli=200406 // for all 3
//-d_M_CEE_PURE // for /clr:pure
//-d_M_CEE_SAFE // for /clr:safe
//-d_MANAGED // for /clr
// When using any /clr form, use:
//-d_M_CEE
// When compiling with /GX or /EH, use:
//-d_CPPUNWIND // Enable Exception Handling
// When compiling for Win64, use:
//-d_WIN64
// When compiling with /Wp64, use:
//-d_Wp64 // 64-bit portability
// Be sure to define your platform if any of the following apply:
//-d_M_ALPHA // For DEC ALPHA platforms
//-d_M_IA64 // For Itanium 64-bit processors
//-d_M_X64 // For x64 processors
// When compiling with the /RTC option, use:
//-d__MSVC_RUNTIME_CHECKS // Using such checks
// When compiling with /openmp, use:
//-d_OPENMP=200203 // OpenMP specification date
// When compiling with /Zl, use:
//-d_VC_NODEFAULTLIB // Omit default library name in *.obj file
/* DLL's or Multithreads? Enable the following:
-d_AFXDLL // making a DLL
-d_DLL // ditto
*/

View File

@ -0,0 +1,221 @@
/* Date Stamp */ -d"_lint_env_vc10_lnt=env-vc10.lnt modified 22-Feb-2012"
/* To document usage use: -message( "Using " _lint_env_vc10_lnt ) */
// ---------------------------------------------------------------------
// This file is provided by Gimpel Software (www.gimpel.com) for use with
// its products PC-lint and FlexeLint.
//
// Redistribution and use of this file, with or without modification, is
// permitted provided that any such redistribution retains this notice.
// ---------------------------------------------------------------------
/*
env-vc10.lnt: environment parameters for Microsoft's Visual C++ 10.0
If you are using Microsoft Visual Studio 2010 and you wish to invoke
PC-lint from that environment then add one or more commands to the
Tools menu as follows.
Simple Check
------------
For example, to add a simple facility to lint the current file you
may do the following:
1. From the Tools Menu choose "External Tools ..."
2. Click the "Add" button.
3. You will now be able to enter the fields of this Tool.
Modify them so that they approximate the following:
Title: PC-lint (Simple Check)
Command: c:\lint\lint-nt.exe
Arguments:
-i"c:\lint" std.lnt env-vc10.lnt "$(ItemFileName)$(ItemExt)"
Initial Directory: $(ItemDir)
X_Use Output Window __Prompt for arguments __Close on exit
Please note that you will have to change the "Command:" path if
the PC-lint Installation Directory is anything other than c:\lint
and you will have to change the "Arguments:" line if the
Configuration Directory is anything other than c:\lint
4. Select OK to return to the main environment.
This will result in the Tools menu containing the additional item
"PC-lint (Simple Check)". Checking 'X' on 'Use Output Window' is
important because in this way you can advance from error to error
using the F8 key (Shift F8 to reverse).
Strings of the form $(...) are called macros and can be typed in
directly as shown or can be selected from a menu by clicking
a right arrow in the dialog box. $(ItemFileName) refers to the
file name of the currently edited file without its path and without
its extension. $(ItemExt) is its extension. $(ItemDir) represents
the file's directory.
You will probably want to advance your new tool upward into the
initial position of all tools while you are testing and modifying the
command. You can do this by using the "Move Up" button that appears
on the External Tools dialog.
The benefits of using "Initial Directory" are that file-names in lint
error messages will not be so long, and, also, this directory can
contain a std.lnt that overrides the global std.lnt in the
Configuration Directory.
This Simple Check is fine to check stand-alone modules but to check
projects or to unit check modules that are in projects we need to
go a bit further ...
Project Creation
----------------
To lint an entire project we will need the names of all the modules
in the project. Visual Studio keeps these names (as well as some
appropriate options such as define options (-d...) and include options
(-i...) in a file named NAME.vcproj in the current project directory.
NAME is the name of the project and is identified by the macro
$(TargetName). PC-lint can read the .vcproj file and generate the
appropriate .lnt file. We recommend creating a tool for this purpose.
For this tool follow the steps 1-4 doing exactly the same thing as
above except in step 3, the information entered should be:
Title: PC-lint (Project Creation)
Command: c:\lint\lint-nt.exe
Arguments: -v -os("$(TargetName).lnt") "$(ProjectFileName)"
Init. Dir.: $(ProjectDir)
__Use Output Window __Prompt for arguments x_Close on exit
You will need to have an active project before this will work.
If you don't already have one you can obtain an active project
from the Solutions Explorer. You then click the newly added
"PC-lint (Project Creation)" tool on the tools menu to create
NAME.lnt.
The file created is an ASCII file and we recommend that you open it
within the IDE and examine it for any obvious flaws. This is your
chance to make any necessary modifications to the file as the process
of conversion may be less than perfect.
Project Check
-------------
Interestingly, by opening up the NAME.lnt file created above and
running the Simple Check described earlier you have the equivalent
of a full project check. However, we prefer to create a special
Project Check tool.
Now that we have a project file we can create a new tool called
"PC-lint (project check)". For this tool again follow steps 1-4 doing
exactly the same thing as above except in step 3, the information
entered should be:
Title: PC-lint (Project Check)
Command: c:\lint\lint-nt.exe
Arguments: -i"c:\lint" std.lnt env-vc10.lnt "$(TargetName).lnt"
Init. Dir.: $(ProjectDir)
X_Use Output Window __Prompt for arguments __Close on exit
Unit Check
----------
You can almost do a unit check on any single module by using the
Simple Check scheme suggested above. The only problems are that you
will need a -u option and you will not have the benefit of any -d or
-i options that have been placed into NAME.lnt created in the Project
Creation step. For this reason we suggest the following tool for
doing a unit check of any module that is part of a project and for
which a .lnt project file has been generated.
Title: PC-lint (Unit Check)
Command: c:\lint\lint-nt.exe
Arguments:
-i"c:\lint" std.lnt env-vc10.lnt --u "$(TargetName).lnt" "$(ItemPath)"
Init. Dir.: $(ProjectDir)
X_Use Output Window __Prompt for arguments __Close on exit
Note that $(ItemPath) will provide a complete path name and in the
absence of a project.lnt file it would cause full path names to
appear in messages. But a side effect of using the project file
with the --u option means that we adopt the shorter names used
in the project file.
Suppressing Messages
----------- --------
Suppressing messages is normally done by adding message suppression
options to a file. For example, -e550 will suppress message 550.
There are numerous other options to suppress messages.
As the documentation indicates, the file
c:\lint\options.lnt
(where c:\lint\ is the Configuration Directory) is the presumed
container of your overall suppression policy. (Note: options.lnt is
referenced by std.lnt). Add a message suppression here and you will
affect all linting employing that configuration.
To suppress messages for a particular project (or for all projects
within a given project directory) you may do the following:
Create a file std.lnt that is contained in the project directory.
Make it refer back to the std.lnt in the Configuration Directory.
Then add additional message suppression options or indeed any options
you want. For example it might contain:
c:\lint\std.lnt // reference to original std.lnt
-e550 // project-specific option
In this way suppression is limited to a particular project.
Tool Bar
--------
You also have the option of creating a PC-lint toolbar within your
Visual C++ IDE. First, create one or more tools as described above.
You will need to know the number(s) of the tool(s) you want to place
on the tool bar. This can only be done by the painful and laborious
task of counting. Using the list provided by "Tools"/"External
Tools", jot down the numbers (starting with 1 at the top) of all the
tools to be added to the tool bar. We recommend placing all the
PC-lint tools on a single tool bar. Then select Customize from the
Tools menu. Select the Toolbars tab and click the New... button.
Give the Toolbar a name (E.g., PC-lint) in the dialog box provided
and click "OK". Confirm that the new toolbar is now floating on
the desktop and that a check has been placed in the check box next
to the new toolbar name. Then click on the Commands tab and
select the "Toolbar:" radio button. Open the drop down list and
select "PC-Lint" from the choices. Click the "Add Command..."
button to reveal the "Add Command" window. In the "Categories:"
box scroll down to and select the "Tools" item. In the
"Commands:" box scroll down to and select the appropriate
"External Command" numbered item that corresponds to the desired
PC-Lint command, then click the OK button to add the selected item
to the PC-Lint toolbar. Repeat the "Add Command..." process for
each desired PC-Lint command the you wish to place on the PC-Lint
toolbar.
If you want to add a button image to the toolbar, you can choose one
via the Modify Selection button. Click Close and you now have your
own PC-lint for C/C++ button. (Note: If you change the location of
the PC-lint menu item on the Tools menu, you will change the subscript
and you will need to change the button(s) on the toolbar.)
*/
-"format=%(%F(%l):%) error %n: (%t -- %m)" // Messages will contain
// file information (%F), the line number (%l), the
// message number (%n), message type (%t) and message text (%m).
-hF2 // Make sure we ALWAYS provide file information ('F') and use 2
// lines (one for the source line in error and one for the
// message).
-width(0) // don't break messages at any particular width
-t4 // Presume that tabs are every 4 stops
//+e900 // issue a message at termination.

View File

@ -0,0 +1,17 @@
/* Date Stamp */ -d"_lint_lib_ole_lnt=lib-ole.lnt modified 23-Mar-2004"
/* To document usage use: -message( "Using " _lint_lib_ole_lnt ) */
// ---------------------------------------------------------------------
// This file is provided by Gimpel Software (www.gimpel.com) for use with
// its products PC-lint and FlexeLint.
//
// Redistribution and use of this file, with or without modification, is
// permitted provided that any such redistribution retains this notice.
// ---------------------------------------------------------------------
// BSTR functions (part of OLE Automation)
-sem( SysAllocString, @p == malloc(1p) || @p == 0, 1p )
-sem( SysAllocStringByteLen, @P == malloc(2n+1) || @p == 0 )
-sem( SysAllocStringLen, @p == malloc(2n+1) || @p == 0 )
-sem( SysStringLen, 1p ? @n == 1p - 1 : @n == 0 )
-function( free, SysFreeString )

View File

@ -0,0 +1,56 @@
/* Date Stamp */ -d"_lint_lib_w32_lnt=lib-w32.lnt modified 2-Mar-1999"
/* To document usage use: -message( "Using " _lint_lib_w32_lnt ) */
// ---------------------------------------------------------------------
// This file is provided by Gimpel Software (www.gimpel.com) for use with
// its products PC-lint and FlexeLint.
//
// Redistribution and use of this file, with or without modification, is
// permitted provided that any such redistribution retains this notice.
// ---------------------------------------------------------------------
// lib-w32.lnt
// PC-lint Library Options File for 32-bit mode windows.h
-d__FLAT__
-d_WIN32
-si4
-sp4
-esym(14,pLocalHeap) // variable defined in windows.h
-e740 // remove 'suspicious cast' messages because these must be
// routinely done within Windows.
-elib(46) // windows.h uses a BYTE as base of bit field.
-e793 // windows breaks ANSI limits
// the following functions have their return value typically ignored.
// add or subtract from this list as desired.
-esym(534,RegisterClass,ShowWindow,TranslateMessage,DispatchMessage)
-esym(534,DrawText,GetTextMetrics,ReleaseDC,TextOut,SetTextAlign)
-esym(534,SetScrollPos,SelectObject,SetBkMode,SendMessage,MessageBox)
-esym(534,MessageBoxA,MessageBoxW,PostMessageA,PostMessageW)
-esym(534,PatBlt,DeleteDC,SetCapture,SetCursor,StretchBlt)
-esym(534,Rectangle,MoveTo,LineTo,ShowCursor,MoveWindow,SetWindowWord)
-esym(534,SetPixel,FillRect,DeleteObject,KillTimer,GetProfileString)
-esym(534,SetWindowLong,SetFocus,SetBkColor,SetTextColor,SetBrushOrg)
-esym(534,UnrealizeObject,_lclose,Polygon,FrameRect,LoadString)
-esym(534,GetInstanceData,GlobalUnlock,FreeResource,LoadString)
-esym(534,DrawIcon,AppendMenu,GetObject,CheckMenuItem,SetClassWord)
-esym(534,EnableMenuItem,SetMenu,DestroyMenu,TrackPopupMenu)
-esym(534,AnsiUpper,Arc,BeginPaint,BitBlt,ChangeClipboardChain,Chord)
-esym(534,CloseClipboard,CombineRgn,DdeClientTransaction,DdeDisconnect)
-esym(534,DdeFreeStringHandle,DdeGetData,DdeNameService,DdePostAdvise)
-esym(534,DdeQueryString,DdeUninitialize,DeleteMenu,DeleteMetaFile)
-esym(534,DestroyWindow,DialogBox,DPtoLP,Ellipse,EmptyClipboard,EnableWindow)
-esym(534,EnumChildWindows,EnumWindows,Escape,GetClassName,GetDlgItemText)
-esym(534,GetFileTitle,GetMenuString,GetStrings,GetSystemMenu,GetTextFace)
-esym(534,GetWindowText,GlobalDeleteAtom,GlobalFree,GlobalGetAtomName)
-esym(534,LocalFree,LocalUnlock,LockResource,lstrcpy,OpenClipboard)
-esym(534,Pie,PlayMetaFile,PopFindNextText,PostDataMessage,PostMessage)
-esym(534,RestoreDC,SaveDC,SelectClipRgn,SendDlgItemMessage,SetClipboardData)
-esym(534,SetDIBitsToDevice,SetMapMode,SetMapperFlags,SetROP2,SetStretchBltMode)
-esym(534,SetTextJustification,SetTimer,SetViewportExt,SetViewportOrg)
-esym(534,SetWindowExt,SetWindowOrg,StretchDIBits,WinExec)
// Ignored parameters
-esym(715,lpszCmdParam,lpszCmdLine)
-emacro(648,PSN_*) // ignore unsigned overflow (0-200U)

View File

@ -0,0 +1,85 @@
# This file contains functions and configurations for generating PC-Lint build
# targets for your CMake projects.
set(PC_LINT_EXECUTABLE "C:/Lint/lint-nt.exe" CACHE STRING "full path to the pc-lint executable. NOT the generated lin.bat")
set(PC_LINT_CONFIG_DIR "${PROJECT_SOURCE_DIR}/lint/msvc" CACHE STRING "full path to the directory containing pc-lint configuration files")
set(PC_LINT_USER_FLAGS "-b" CACHE STRING "additional pc-lint command line options -- some flags of pc-lint cannot be set in option files (most notably -b)")
# a phony target which causes all available *_LINT targets to be executed
add_custom_target(ALL_LINT)
# add_pc_lint(target source1 [source2 ...])
#
# Takes a list of source files and generates a build target which can be used
# for linting all files
#
# The generated lint commands assume that a top-level config file named
# 'std.lnt' resides in the configuration directory 'PC_LINT_CONFIG_DIR'. This
# config file must include all other config files. This is standard lint
# behaviour.
#
# Parameters:
# - target: the name of the target to which the sources belong. You will get a
# new build target named ${target}_LINT
# - source1 ... : a list of source files to be linted. Just pass the same list
# as you passed for add_executable or add_library. Everything except
# C and CPP files (*.c, *.cpp, *.cxx) will be filtered out.
#
# Example:
# If you have a CMakeLists.txt which generates an executable like this:
#
# set(MAIN_SOURCES main.c foo.c bar.c)
# add_executable(main ${MAIN_SOURCES})
#
# include this file
#
# include(/path/to/pc_lint.cmake)
#
# and add a line to generate the main_LINT target
#
# if(COMMAND add_pc_lint)
# add_pc_lint(main ${MAIN_SOURCES})
# endif(COMMAND add_pc_lint)
#
function(add_pc_lint target)
get_directory_property(lint_include_directories INCLUDE_DIRECTORIES)
get_directory_property(lint_defines COMPILE_DEFINITIONS)
# let's get those elephants across the alps
# prepend each include directory with "-i"; also quotes the directory
set(lint_include_directories_transformed)
foreach(include_dir ${lint_include_directories})
list(APPEND lint_include_directories_transformed -i"${include_dir}")
endforeach(include_dir)
# prepend each definition with "-d"
set(lint_defines_transformed)
foreach(definition ${lint_defines})
list(APPEND lint_defines_transformed -d${definition})
endforeach(definition)
# list of all commands, one for each given source file
set(pc_lint_commands)
foreach(sourcefile ${ARGN})
# only include c and cpp files
if( sourcefile MATCHES \\.c$|\\.cxx$|\\.cpp$ )
# make filename absolute
get_filename_component(sourcefile_abs ${sourcefile} ABSOLUTE)
# create command line for linting one source file and add it to the list of commands
list(APPEND pc_lint_commands
COMMAND ${PC_LINT_EXECUTABLE}
-i"${PC_LINT_CONFIG_DIR}" std.lnt
"-u" ${PC_LINT_USER_FLAGS}
${lint_include_directories_transformed}
${lint_defines_transformed}
${sourcefile_abs})
endif()
endforeach(sourcefile)
# add a custom target consisting of all the commands generated above
add_custom_target(${target}_LINT ${pc_lint_commands} VERBATIM)
# make the ALL_LINT target depend on each and every *_LINT target
add_dependencies(ALL_LINT ${target}_LINT)
endfunction(add_pc_lint)

View File

@ -0,0 +1,4 @@
co-msc100.lnt
env-vc10.lnt
lib-w32.lnt

View File

@ -0,0 +1,625 @@
/************************************************************************************//**
* \file openblt.c
* \brief OpenBLT host library source file.
* \ingroup Library
* \internal
*----------------------------------------------------------------------------------------
* C O P Y R I G H T
*----------------------------------------------------------------------------------------
* Copyright (c) 2017 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 have received a copy of the GNU General Public License along with OpenBLT. It
* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
*
* \endinternal
****************************************************************************************/
/****************************************************************************************
* Include files
****************************************************************************************/
#include <assert.h> /* for assertions */
#include <stddef.h> /* for NULL declaration */
#include <stdbool.h> /* for boolean type */
#include "openblt.h" /* OpenBLT host library */
#include "util.h" /* Utility module */
#include "firmware.h" /* Firmware data module */
#include "srecparser.h" /* S-record parser */
#include "session.h" /* Communication session module */
#include "xcploader.h" /* XCP loader module */
#include "xcptpuart.h" /* XCP UART transport layer */
/****************************************************************************************
* Macro definitions
****************************************************************************************/
/** \brief The version number of the library as an integer. The number has two digits
* for major-, minor-, and build-version. Version 1.05.12 would for example be
* 10512.
*/
#define BLT_VERSION_NUMBER (10000u)
/** \brief The version number of the library as a null-terminated string. */
#define BLT_VERSION_STRING "1.00.00"
/****************************************************************************************
* Local constant declarations
****************************************************************************************/
/** \brief Constant null-terminated string with the version number of the library. */
char const bltVersionString[] = BLT_VERSION_STRING;
/****************************************************************************************
* V E R S I O N I N F O R M A T I O N
****************************************************************************************/
/************************************************************************************//**
** \brief Obtains the version number of the library as an integer. The number has two
** digits for major-, minor-, and build-version. Version 1.05.12 would for
** example return 10512.
** \return Library version number as an integer.
**
****************************************************************************************/
LIBOPENBLT_EXPORT uint32_t BltVersionGetNumber(void)
{
return BLT_VERSION_NUMBER;
} /*** end of BltVersionGetNumber ***/
/************************************************************************************//**
** \brief Obtains the version number of the library as a null-terminated string.
** Version 1.05.12 would for example return "1.05.12".
** \return Library version number as a null-terminated string.
**
****************************************************************************************/
LIBOPENBLT_EXPORT char const * BltVersionGetString(void)
{
return BLT_VERSION_STRING;
} /*** end of BltVersionGetString ***/
/****************************************************************************************
* S E S S I O N / T R A N S P O R T L A Y E R S
****************************************************************************************/
/************************************************************************************//**
** \brief Initializes the firmware update session for a specific communication
** protocol and transport layer. This function is typically called once at
** the start of the firmware update.
** \param sessionType The communication protocol to use for this session. It should
** be a BLT_SESSION_xxx value.
** \param sessionSettings Pointer to a structure with communication protocol specific
** settings.
** \param transportType The transport layer to use for the specified communication
** protocol. It should be a BLT_TRANSPORT_xxx value.
** \param transportSettings Pointer to a structure with transport layer specific
** settings.
**
****************************************************************************************/
LIBOPENBLT_EXPORT void BltSessionInit(uint32_t sessionType,
void const * sessionSettings,
uint32_t transportType,
void const * transportSettings)
{
/* Check parameters. Note that the settings-pointers are allowed to be NULL in case
* no additional settings are needed for the specified session or transport type.
*/
assert(sessionType == BLT_SESSION_XCP_V10);
assert( (transportType == BLT_TRANSPORT_XCP_V10_RS232) || \
(transportType == BLT_TRANSPORT_XCP_V10_CAN) );
/* Initialize the correct session. */
if (sessionType == BLT_SESSION_XCP_V10) /*lint !e774 */
{
/* Verify settingsSettings parameter because the XCP loader requires them. */
assert(sessionSettings != NULL);
/* Only continue if the settingsSettings parameter is valid. */
if (sessionSettings != NULL) /*lint !e774 */
{
/* Cast session settings to the correct type. */
tBltSessionSettingsXcpV10 * bltSessionSettingsXcpV10Ptr;
bltSessionSettingsXcpV10Ptr = ((tBltSessionSettingsXcpV10 *)sessionSettings);
/* Convert session settings to the format supported by the XCP loader module. */
tXcpLoaderSettings xcpLoaderSettings;
xcpLoaderSettings.timeoutT1 = bltSessionSettingsXcpV10Ptr->timeoutT1;
xcpLoaderSettings.timeoutT3 = bltSessionSettingsXcpV10Ptr->timeoutT3;
xcpLoaderSettings.timeoutT4 = bltSessionSettingsXcpV10Ptr->timeoutT4;
xcpLoaderSettings.timeoutT5 = bltSessionSettingsXcpV10Ptr->timeoutT5;
xcpLoaderSettings.timeoutT7 = bltSessionSettingsXcpV10Ptr->timeoutT7;
xcpLoaderSettings.transport = NULL;
xcpLoaderSettings.transportSettings = NULL;
/* Link the correct transport layer. */
if (transportType == BLT_TRANSPORT_XCP_V10_RS232)
{
/* Verify transportSettings parameters because the XCP UART transport layer
* requires them.
*/
assert(transportSettings != NULL);
/* Only continue if the transportSettings parameter is valid. */
if (transportSettings != NULL) /*lint !e774 */
{
/* Cast transport settings to the correct type. */
tBltTransportSettingsXcpV10Rs232 * bltTransportSettingsXcpV10Rs232Ptr;
bltTransportSettingsXcpV10Rs232Ptr =
(tBltTransportSettingsXcpV10Rs232 * )transportSettings;
/* Convert transport settings to the format supported by the XCP UART transport
* layer. It was made static to make sure it doesn't get out of scope when
* used in xcpLoaderSettings.
*/
static tXcpTpUartSettings xcpTpUartSettings;
xcpTpUartSettings.baudrate = bltTransportSettingsXcpV10Rs232Ptr->baudrate;
xcpTpUartSettings.portname = bltTransportSettingsXcpV10Rs232Ptr->portName;
/* Store transport layer settings in the XCP loader settings. */
xcpLoaderSettings.transportSettings = &xcpTpUartSettings;
/* Link the transport layer to the XCP loader settings. */
xcpLoaderSettings.transport = XcpTpUartGetTransport();
}
}
/* Perform actual session initialization. */
SessionInit(XcpLoaderGetProtocol(), &xcpLoaderSettings);
}
}
} /*** end of BltSessionInit ***/
/************************************************************************************//**
** \brief Terminates the firmware update session. This function is typically called
** once at the end of the firmware update.
**
****************************************************************************************/
LIBOPENBLT_EXPORT void BltSessionTerminate(void)
{
/* Terminate the session. */
SessionTerminate();
} /*** end of BltSessionTerminate ***/
/************************************************************************************//**
** \brief Starts the firmware update session. This is were the library attempts to
** activate and connect with the bootloader running on the target, through
** the transport layer that was specified during the session's initialization.
** \return BLT_RESULT_OK if successful, BLT_RESULT_ERROR_xxx otherwise.
**
****************************************************************************************/
LIBOPENBLT_EXPORT uint32_t BltSessionStart(void)
{
uint32_t result = BLT_RESULT_ERROR_GENERIC;
/* Start the session. */
if (SessionStart())
{
result = BLT_RESULT_OK;
}
/* Give the result back to the caller. */
return result;
} /*** end of BltSessionStart ***/
/************************************************************************************//**
** \brief Stops the firmware update session. This is there the library disconnects
** the transport layer as well.
**
****************************************************************************************/
LIBOPENBLT_EXPORT void BltSessionStop(void)
{
/* Stop the session. */
SessionStop();
} /*** end of BltSessionStop ***/
/************************************************************************************//**
** \brief Requests the target to erase the specified range of memory on the target.
** Note that the target automatically aligns this to the erasable memory
** block sizes. This typically results in more memory being erased that the
** range that was specified here. Refer to the target implementation for
** details.
** \param address The starting memory address for the erase operation.
** \param len The total number of bytes to erase from memory.
** \return BLT_RESULT_OK if successful, BLT_RESULT_ERROR_xxx otherwise.
**
****************************************************************************************/
LIBOPENBLT_EXPORT uint32_t BltSessionClearMemory(uint32_t address, uint32_t len)
{
uint32_t result = BLT_RESULT_ERROR_GENERIC;
/* Check parameters. */
assert(len > 0);
/* Only continue if the parameters are valid. */
if (len > 0)
{
/* Pass the request on to the session module. */
if (SessionClearMemory(address, len))
{
result = BLT_RESULT_OK;
}
}
/* Give the result back to the caller. */
return result;
} /*** end of BltSessionClearMemory ***/
/************************************************************************************//**
** \brief Requests the target to program the specified data to memory. Note that it
** is the responsibility of the application to make sure the memory range was
** erased beforehand.
** \param address The starting memory address for the write operation.
** \param len The number of bytes in the data buffer that should be written.
** \param data Pointer to the byte array with data to write.
** \return BLT_RESULT_OK if successful, BLT_RESULT_ERROR_xxx otherwise.
**
****************************************************************************************/
LIBOPENBLT_EXPORT uint32_t BltSessionWriteData(uint32_t address, uint32_t len,
uint8_t const * data)
{
uint32_t result = BLT_RESULT_ERROR_GENERIC;
/* Check parameters. */
assert(data != NULL);
assert(len > 0);
/* Only continue if the parameters are valid. */
if ( (data != NULL) && (len > 0) ) /*lint !e774 */
{
/* Pass the request on to the session module. */
if (SessionWriteData(address, len, data))
{
result = BLT_RESULT_OK;
}
}
/* Give the result back to the caller. */
return result;
} /*** end of BltSessionWriteData ***/
/************************************************************************************//**
** \brief Requests the target to upload the specified range from memory and store its
** contents in the specified data buffer.
** \param address The starting memory address for the read operation.
** \param len The number of bytes to upload from the target and store in the data
** buffer.
** \param data Pointer to the byte array where the uploaded data should be stored.
** \return BLT_RESULT_OK if successful, BLT_RESULT_ERROR_xxx otherwise.
**
****************************************************************************************/
LIBOPENBLT_EXPORT uint32_t BltSessionReadData(uint32_t address, uint32_t len,
uint8_t * data)
{
uint32_t result = BLT_RESULT_ERROR_GENERIC;
/* Check parameters. */
assert(data != NULL);
assert(len > 0);
/* Only continue if the parameters are valid. */
if ( (data != NULL) && (len > 0) ) /*lint !e774 */
{
/* Pass the request on to the session module. */
if (SessionReadData(address, len, data))
{
result = BLT_RESULT_OK;
}
}
/* Give the result back to the caller. */
return result;
} /*** end of BltSessionReadData ***/
/****************************************************************************************
* F I R M W A R E D A T A
****************************************************************************************/
/************************************************************************************//**
** \brief Initializes the firmware data module for a specified firmware file parser.
** \param parserType The firmware file parser to use in this module. It should be a
** BLT_FIRMWARE_PARSER_xxx value.
**
****************************************************************************************/
LIBOPENBLT_EXPORT void BltFirmwareInit(uint32_t parserType)
{
tFirmwareParser const * firmwareParser = NULL;
/* Verify parameters. */
assert(parserType == BLT_FIRMWARE_PARSER_SRECORD);
/* Set the parser pointer. */
if (parserType == BLT_FIRMWARE_PARSER_SRECORD) /*lint !e774 */
{
firmwareParser = SRecParserGetParser();
}
/* Initialize the firmware data module by linking the firmware file parser. */
FirmwareInit(firmwareParser);
} /*** end of BltFirmwareInit ***/
/************************************************************************************//**
** \brief Terminates the firmware data module. Typically called at the end of the
** program when the firmware data module is no longer needed.
**
****************************************************************************************/
LIBOPENBLT_EXPORT void BltFirmwareTerminate(void)
{
/* Terminate the firmware data module. */
FirmwareTerminate();
} /*** end of BltFirmwareTerminate ***/
/************************************************************************************//**
** \brief Loads firmware data from the specified file using the firmware file parser
** that was specified during the initialization of this module.
** \param firmwareFile Filename of the firmware file to load.
** \return BLT_RESULT_OK if successful, BLT_RESULT_ERROR_xxx otherwise.
**
****************************************************************************************/
LIBOPENBLT_EXPORT uint32_t BltFirmwareLoadFromFile(char const * firmwareFile)
{
uint32_t result = BLT_RESULT_ERROR_GENERIC;
/* Verify parameters. */
assert(firmwareFile != NULL);
/* Only continue if parameters are valid. */
if (firmwareFile != NULL) /*lint !e774 */
{
/* Pass the request on to the firmware data module. */
if (FirmwareLoadFromFile(firmwareFile))
{
result = BLT_RESULT_OK;
}
}
/* Give the result back to the caller. */
return result;
} /*** end of BltFirmwareLoadFromFile ***/
/************************************************************************************//**
** \brief Writes firmware data to the specified file using the firmware file parser
** that was specified during the initialization of this module.
** \param firmwareFile Filename of the firmware file to write to.
** \return BLT_RESULT_OK if successful, BLT_RESULT_ERROR_xxx otherwise.
**
****************************************************************************************/
LIBOPENBLT_EXPORT uint32_t BltFirmwareSaveToFile(char const * firmwareFile)
{
uint32_t result = BLT_RESULT_ERROR_GENERIC;
/* Verify parameters. */
assert(firmwareFile != NULL);
/* Only continue if parameters are valid. */
if (firmwareFile != NULL) /*lint !e774 */
{
/* Pass the request on to the firmware data module. */
if (FirmwareSaveToFile(firmwareFile))
{
result = BLT_RESULT_OK;
}
}
/* Give the result back to the caller. */
return result;
} /*** end of BltFirmwareSaveToFile ***/
/************************************************************************************//**
** \brief Obtains the number of firmware data segments that are currently present
** in the firmware data module.
** \return The total number of segments.
**
****************************************************************************************/
LIBOPENBLT_EXPORT uint32_t BltFirmwareGetSegmentCount(void)
{
/* Pass the request on to the firmware data module. */
return FirmwareGetSegmentCount();
} /*** end of BltFirmwareGetSegmentCount ***/
/************************************************************************************//**
** \brief Obtains the contents of the firmware data segment that was specified by the
** index parameter.
** \param idx The segment index. It should be a value greater or equal to zero and
** smaller than the value returned by \ref BltFirmwareGetSegmentCount.
** \param address Pointer to where the segment's base address will be written to.
** \param len Pointer to where the segment's length will be written to.
** \return Pointer to the segment data if successful, NULL otherwise.
**
****************************************************************************************/
LIBOPENBLT_EXPORT uint8_t * BltFirmwareGetSegment(uint32_t idx, uint32_t * address,
uint32_t * len)
{
uint8_t * result = NULL;
tFirmwareSegment *segmentPtr;
/* Verify parameters. Note that it is okay for the data parameter to be NULL. */
assert(idx < FirmwareGetSegmentCount());
assert(address != NULL);
assert(len != NULL);
/* Only continue if parameters are valid. */
if ((address != NULL) && (len != NULL) &&
(idx < FirmwareGetSegmentCount()) ) /*lint !e774 */
{
/* Pass the request on to the firmware data module. */
segmentPtr = FirmwareGetSegment(idx);
/* Process the result. */
if (segmentPtr != NULL)
{
*address = segmentPtr->base;
*len = segmentPtr->length;
result = segmentPtr->data;
}
}
/* Give the result back to the caller. */
return result;
} /*** end of BltFirmwareGetSegment ***/
/************************************************************************************//**
** \brief Adds data to the segments that are currently present in the firmware data
** module. If the data overlaps with already existing data, the existing data
** gets overwritten. The size of a segment is automatically adjusted or a new
** segment gets created, if necessary.
** \param address Base address of the firmware data.
** \param len Number of bytes to add.
** \param data Pointer to array with data bytes that should be added.
** \return BLT_RESULT_OK if successful, BLT_RESULT_ERROR_xxx otherwise.
**
****************************************************************************************/
LIBOPENBLT_EXPORT uint32_t BltFirmwareAddData(uint32_t address, uint32_t len,
uint8_t const * data)
{
uint32_t result = BLT_RESULT_ERROR_GENERIC;
/* Verify parameters. */
assert(len > 0);
assert(data != NULL);
/* Only continue if parameters are valid. */
if ( (len > 0) && (data != NULL) ) /*lint !e774 */
{
/* Pass the request on to the firmware data module. */
if (FirmwareAddData(address, len, data))
{
result = BLT_RESULT_OK;
}
}
/* Give the result back to the caller. */
return result;
} /*** end of BltFirmwareAddData ***/
/************************************************************************************//**
** \brief Removes data from the segments that are currently present in the firmware
** data module. The size of a segment is automatically adjusted or removed, if
** necessary.
** \param address Base address of the firmware data.
** \param len Number of bytes to remove.
** \return BLT_RESULT_OK if successful, BLT_RESULT_ERROR_xxx otherwise.
**
****************************************************************************************/
LIBOPENBLT_EXPORT uint32_t BltFirmwareRemoveData(uint32_t address, uint32_t len)
{
uint32_t result = BLT_RESULT_ERROR_GENERIC;
/* Verify parameters. */
assert(len > 0);
/* Only continue if parameters are valid. */
if (len > 0)
{
/* Pass the request on to the firmware data module. */
if (FirmwareRemoveData(address, len))
{
result = BLT_RESULT_OK;
}
}
/* Give the result back to the caller. */
return result;
} /*** end of BltFirmwareRemoveData ***/
/************************************************************************************//**
** \brief Clears all data and segments that are currently present in the firmware
** data module.
**
****************************************************************************************/
LIBOPENBLT_EXPORT void BltFirmwareClearData(void)
{
/* Pass the request on to the firmware data module. */
FirmwareClearData();
} /*** end of BltFirmwareClearData ***/
/****************************************************************************************
* G E N E R I C U T I L I T I E S
****************************************************************************************/
/************************************************************************************//**
** \brief Calculates a 16-bit CRC value over the specified data.
** \param data Array with bytes over which the CRC16 should be calculated.
** \param len Number of bytes in the data array.
** \return The 16-bit CRC value.
**
****************************************************************************************/
LIBOPENBLT_EXPORT uint16_t BltUtilCrc16Calculate(uint8_t const * data, uint32_t len)
{
uint16_t result = 0;
/* Check parameters. */
assert(data != NULL);
assert(len > 0);
/* Only continue if parameters are valid. */
if ( (data != NULL) && (len > 0) ) /*lint !e774 */
{
/* Perform checksum calculation. */
result = UtilChecksumCrc16Calculate(data, len);
}
/* Give the result back to the caller. */
return result;
} /*** end of BltUtilCrc16Calculate ***/
/************************************************************************************//**
** \brief Calculates a 32-bit CRC value over the specified data.
** \param data Array with bytes over which the CRC32 should be calculated.
** \param len Number of bytes in the data array.
** \return The 32-bit CRC value.
**
****************************************************************************************/
LIBOPENBLT_EXPORT uint32_t BltUtilCrc32Calculate(uint8_t const * data, uint32_t len)
{
uint32_t result = 0;
/* Check parameters. */
assert(data != NULL);
assert(len > 0);
/* Only continue if parameters are valid. */
if ( (data != NULL) && (len > 0) ) /*lint !e774 */
{
/* Perform checksum calculation. */
result = UtilChecksumCrc32Calculate(data, len);
}
/* Give the result back to the caller. */
return result;
} /*** end of BltUtilCrc32Calculate ***/
/************************************************************************************//**
** \brief Get the system time in milliseconds.
** \return Time in milliseconds.
**
****************************************************************************************/
LIBOPENBLT_EXPORT uint32_t BltUtilTimeGetSystemTime(void)
{
uint32_t result;
/* Pass the request on to the utility module. */
result = UtilTimeGetSystemTimeMs();
/* Give the result back to the caller. */
return result;
} /*** end of BltUtilTimeGetSystemTime ***/
/************************************************************************************//**
** \brief Performs a delay of the specified amount of milliseconds.
** \param delay Delay time in milliseconds.
**
****************************************************************************************/
LIBOPENBLT_EXPORT void BltUtilTimeDelayMs(uint16_t delay)
{
/* Pass the request on to the utility module. */
UtilTimeDelayMs(delay);
} /*** end of BltUtilTimeDelayMs ***/
/*********************************** end of openblt.c **********************************/

View File

@ -0,0 +1,224 @@
/************************************************************************************//**
* \file openblt.h
* \brief OpenBLT host library header file.
* \ingroup Library
* \internal
*----------------------------------------------------------------------------------------
* C O P Y R I G H T
*----------------------------------------------------------------------------------------
* Copyright (c) 2017 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 have received a copy of the GNU General Public License along with OpenBLT. It
* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
*
* \endinternal
****************************************************************************************/
/************************************************************************************//**
* \defgroup Library Library API
* \brief OpenBLT Library API.
* \details
* The Library API contains the application programming interface for the OpenBLT libary.
* it defines the functions and definitions that an external program uses to access the
* library's functionality.
****************************************************************************************/
#ifndef OPENBLT_H
#define OPENBLT_H
#ifdef __cplusplus
extern "C" {
#endif
/****************************************************************************************
* Include files
****************************************************************************************/
#include <stdint.h> /* for standard integer types */
/****************************************************************************************
* Macro definitions
****************************************************************************************/
/* CMake automatically defines macro openblt_shared_EXPORTS when building the shared
* version of the library. When building under windows, this is used to set the export
* macro, which is needed to confige the library functions.
*/
#if defined(_WIN32) || defined(_WIN64)
#if defined(openblt_shared_EXPORTS)
#define LIBOPENBLT_EXPORT __declspec(dllexport)
#else
#define LIBOPENBLT_EXPORT
#endif /* openblt_shared_EXPORTS */
#else /* defined(_WIN32) || defined(_WIN64) */
#define LIBOPENBLT_EXPORT
#endif
/** \brief Function return value for when everything went okay. */
#define BLT_RESULT_OK (0u)
/** \brief Function return value for when a generic error occured. */
#define BLT_RESULT_ERROR_GENERIC (1u)
/****************************************************************************************
* V E R S I O N I N F O R M A T I O N
****************************************************************************************/
/****************************************************************************************
* Function prototypes
****************************************************************************************/
LIBOPENBLT_EXPORT uint32_t BltVersionGetNumber(void);
LIBOPENBLT_EXPORT char const * BltVersionGetString(void);
/****************************************************************************************
* S E S S I O N / T R A N S P O R T L A Y E R S
****************************************************************************************/
/****************************************************************************************
* Macro definitions
****************************************************************************************/
/** \brief XCP protocol version 1.0. XCP is a universal measurement and calibration
* communication protocol. It contains functionality for reading, programming,
* and erasing (non-volatile) memory making it a good fit for bootloader
* purposes.
*/
#define BLT_SESSION_XCP_V10 ((uint32_t)0u)
/** \brief Transport layer for the XCP v1.0 protocol that uses RS-232 serial
* communication for data exchange.
*/
#define BLT_TRANSPORT_XCP_V10_RS232 ((uint32_t)0u)
/** \brief Transport layer for the XCP v1.0 protocol that uses Controller Area Network
* (CAN) for data exchange.
*/
#define BLT_TRANSPORT_XCP_V10_CAN ((uint32_t)1u)
/****************************************************************************************
* Type definitions
****************************************************************************************/
/** \brief Structure layout of the XCP version 1.0 session settings. */
typedef struct t_blt_session_settings_xcp_v10
{
uint16_t timeoutT1; /**< Command response timeout in milliseconds. */
uint16_t timeoutT3; /**< Start programming timeout in milliseconds. */
uint16_t timeoutT4; /**< Erase memory timeout in milliseonds. */
uint16_t timeoutT5; /**< Program memory and reset timeout in milliseonds. */
uint16_t timeoutT7; /**< Busy wait timer timeout in milliseonds. */
char const * seedKeyFile; /**< Seed/key algorithm library filename. */
} tBltSessionSettingsXcpV10;
/** \brief Structure layout of the XCP version 1.0 RS232 transport layer settings. The
* portName field is platform dependent. On Linux based systems this should be
* the filename of the tty-device, such as "/dev/tty0". On Windows based systems
* it should be the name of the COM-port, such as "COM1".
*/
typedef struct t_blt_transport_settings_xcp_v10_rs232
{
char const * portName; /**< Communication port name such as /dev/tty0. */
uint32_t baudrate; /**< Communication speed in bits/sec. */
} tBltTransportSettingsXcpV10Rs232;
/** \brief Structure layout of the XCP version 1.0 CAN transport layer settings. The
* deviceName field is platform dependent. On Linux based systems this should be
* the socketCAN interface name such as "can0". The terminal command "ip addr"
* can be issued to view a list of interfaces that are up and available. Under
* Linux it is assumed that the socketCAN interface is already configured on the
* system, before using the OpenBLT library. When baudrate is configured when
* bringing up the system, so the baudrate field in this structure is don't care
* when using the library on a Linux was system.
* On Windows based systems, the device name is a name that is pre-defined by
* this library for the supported CAN adapters. The device name should be one of
* the following: "peak_pcanusb", "kvaser_leaflight", or "lawicel_canusb".
* Field use extended is a boolean field. When set to 0, the specified transmitId
* and receiveId are assumed to be 11-bit standard CAN identifier. It the field
* is 1, these identifiers are assumed to be 29-bit extended CAN identifiers.
*/
typedef struct t_blt_transport_settings_xcp_v10_can
{
char const * deviceName; /**< Device name such as can0. */
uint32_t deviceChannel; /**< Channel on the device to use. */
uint32_t baudrate; /**< Communication speed in bits/sec. */
uint32_t transmitId; /**< Transmit CAN identifier. */
uint32_t receiveId; /**< Receive CAN identifier. */
uint32_t useExtended; /**< Boolean to configure 29-bit CAN identifiers. */
} tBltTransportSettingsXcpV10Can;
/****************************************************************************************
* Function prototypes
****************************************************************************************/
LIBOPENBLT_EXPORT void BltSessionInit(uint32_t sessionType,
void const * sessionSettings,
uint32_t transportType,
void const * transportSettings);
LIBOPENBLT_EXPORT void BltSessionTerminate(void);
LIBOPENBLT_EXPORT uint32_t BltSessionStart(void);
LIBOPENBLT_EXPORT void BltSessionStop(void);
LIBOPENBLT_EXPORT uint32_t BltSessionClearMemory(uint32_t address, uint32_t len);
LIBOPENBLT_EXPORT uint32_t BltSessionWriteData(uint32_t address, uint32_t len,
uint8_t const * data);
LIBOPENBLT_EXPORT uint32_t BltSessionReadData(uint32_t address, uint32_t len,
uint8_t * data);
/****************************************************************************************
* F I R M W A R E D A T A
****************************************************************************************/
/****************************************************************************************
* Macro definitions
****************************************************************************************/
/** \brief The S-record parser enables writing and reading firmware data to and from
* file formatted as Motorola S-record. This is a widely known file format and
* pretty much all microcontroller compiler toolchains included functionality to
* output or convert the firmware's data as an S-record.
*/
#define BLT_FIRMWARE_PARSER_SRECORD ((uint32_t)0u)
/****************************************************************************************
* Function prototypes
****************************************************************************************/
LIBOPENBLT_EXPORT void BltFirmwareInit(uint32_t parserType);
LIBOPENBLT_EXPORT void BltFirmwareTerminate(void);
LIBOPENBLT_EXPORT uint32_t BltFirmwareLoadFromFile(char const * firmwareFile);
LIBOPENBLT_EXPORT uint32_t BltFirmwareSaveToFile(char const * firmwareFile);
LIBOPENBLT_EXPORT uint32_t BltFirmwareGetSegmentCount(void);
LIBOPENBLT_EXPORT uint8_t * BltFirmwareGetSegment(uint32_t idx, uint32_t * address,
uint32_t * len);
LIBOPENBLT_EXPORT uint32_t BltFirmwareAddData(uint32_t address, uint32_t len,
uint8_t const * data);
LIBOPENBLT_EXPORT uint32_t BltFirmwareRemoveData(uint32_t address, uint32_t len);
LIBOPENBLT_EXPORT void BltFirmwareClearData(void);
/****************************************************************************************
* G E N E R I C U T I L I T I E S
****************************************************************************************/
/****************************************************************************************
* Function prototypes
****************************************************************************************/
LIBOPENBLT_EXPORT uint16_t BltUtilCrc16Calculate(uint8_t const * data, uint32_t len);
LIBOPENBLT_EXPORT uint32_t BltUtilCrc32Calculate(uint8_t const * data, uint32_t len);
LIBOPENBLT_EXPORT uint32_t BltUtilTimeGetSystemTime(void);
LIBOPENBLT_EXPORT void BltUtilTimeDelayMs(uint16_t delay);
#ifdef __cplusplus
}
#endif
#endif /* OPENBLT_H */
/********************************* end of openblt.h ************************************/

View File

@ -0,0 +1,173 @@
unit OpenBlt;
//***************************************************************************************
// Description: Unit for accessing the OpenBLT shared library.
// File Name: openblt.pas
//
//---------------------------------------------------------------------------------------
// C O P Y R I G H T
//---------------------------------------------------------------------------------------
// Copyright (c) 2017 by Feaser http://www.feaser.com All rights reserved
//
// This software has been carefully tested, but is not guaranteed for any particular
// purpose. The author does not offer any warranties and does not guarantee the accuracy,
// adequacy, or completeness of the software and is not responsible for any errors or
// omissions or the results obtained from use of the software.
//
//---------------------------------------------------------------------------------------
// 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 have received a copy of the GNU General Public License along with OpenBLT. It
// should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
//
//***************************************************************************************
{$IFDEF FPC}
{$MODE objfpc}{$H+}
{$ENDIF}
interface
//***************************************************************************************
// Global Includes
//***************************************************************************************
uses
Classes, SysUtils;
//***************************************************************************************
// Global Constant Declarations
//***************************************************************************************
const
// Name of the external library.
LIBOPENBLT_LIBNAME = 'libopenblt';
// Function return value for when everything went okay.
BLT_RESULT_OK = 0;
// Function return value for when a generic error occured.
BLT_RESULT_ERROR_GENERIC = 1;
//***************************************************************************************
// V E R S I O N I N F O R M A T I O N
//***************************************************************************************
function BltVersionGetNumber: LongWord; cdecl; external LIBOPENBLT_LIBNAME;
function BltVersionGetString: PAnsiChar; cdecl; external LIBOPENBLT_LIBNAME;
//***************************************************************************************
// S E S S I O N / T R A N S P O R T L A Y E R S
//***************************************************************************************
const
// XCP protocol version 1.0. XCP is a universal measurement and calibration communica-
// tion protocol. It contains functionality for reading, programming, and erasing
// (non-volatile) memory making it a good fit for bootloader purposes.
BLT_SESSION_XCP_V10: LongWord = 0;
// Transport layer for the XCP v1.0 protocol that uses RS-232 serial communication for
// data exchange.
BLT_TRANSPORT_XCP_V10_RS232: LongWord = 0;
// Transport layer for the XCP v1.0 protocol that uses Controller Area Network (CAN)
// for data exchange.
BLT_TRANSPORT_XCP_V10_CAN: LongWord = 1;
type
// Structure layout of the XCP version 1.0 session settings.
tBltSessionSettingsXcpV10 = record
timeoutT1: Word; // Command response timeout in milliseconds.
timeoutT3: Word; // Start programming timeout in milliseconds.
timeoutT4: Word; // Erase memory timeout in milliseonds.
timeoutT5: Word; // Program memory and reset timeout in milliseonds.
timeoutT7: Word; // Busy wait timer timeout in milliseonds.
seedKeyFile: PAnsiChar; // Seed/key algorithm library filename.
end;
// Structure layout of the XCP version 1.0 RS232 transport layer settings.
tBltTransportSettingsXcpV10Rs232 = record
portName: PAnsiChar; // Communication port name such as /dev/tty0.
baudrate: LongWord; // Communication speed in bits/sec.
end;
// Structure layout of the XCP version 1.0 CAN transport layer settings.
tBltTransportSettingsXcpV10Can = record
deviceName: PAnsiChar; // Device name such as /dev/can0.
deviceChannel: LongWord; // Channel on the device to use.
baudrate: LongWord; // Communication speed in bits/sec.
transmitId: LongWord; // Transmit CAN identifier.
receiveId: LongWord; // Receive CAN identifier.
useExtended: LongWord; // Boolean to configure 29-bit CAN identifiers.
end;
procedure BltSessionInit(sessionType: LongWord;
sessionSettings: Pointer;
transportType: LongWord;
transportSettings: Pointer);
cdecl; external LIBOPENBLT_LIBNAME;
procedure BltSessionTerminate; cdecl; external LIBOPENBLT_LIBNAME;
function BltSessionStart: LongWord; cdecl; external LIBOPENBLT_LIBNAME;
procedure BltSessionStop; cdecl; external LIBOPENBLT_LIBNAME;
function BltSessionClearMemory(address: LongWord;
len: LongWord): LongWord;
cdecl; external LIBOPENBLT_LIBNAME;
function BltSessionWriteData(address: LongWord;
len: LongWord;
data: PByte): LongWord;
cdecl; external LIBOPENBLT_LIBNAME;
function BltSessionReadData(address: LongWord;
len: LongWord;
data: PByte): LongWord;
cdecl; external LIBOPENBLT_LIBNAME;
//***************************************************************************************
// F I R M W A R E D A T A C O N T R O L
//***************************************************************************************
const
// The S-record parser enables writing and reading firmware data to and from file
// formatted as Motorola S-record. This is a widely known file format and pretty much
// all microcontroller compiler toolchains included functionality to output or convert
// the firmware's data as an S-record.
BLT_FIRMWARE_PARSER_SRECORD: LongWord = 0;
procedure BltFirmwareInit(parserType: LongWord); cdecl; external LIBOPENBLT_LIBNAME;
procedure BltFirmwareTerminate; cdecl; external LIBOPENBLT_LIBNAME;
function BltFirmwareLoadFromFile(firmwareFile: PAnsiChar): LongWord;
cdecl; external LIBOPENBLT_LIBNAME;
function BltFirmwareSaveToFile(firmwareFile: PAnsiChar): LongWord;
cdecl; external LIBOPENBLT_LIBNAME;
function BltFirmwareGetSegmentCount: LongWord; cdecl; external LIBOPENBLT_LIBNAME;
function BltFirmwareGetSegment(idx: LongWord;
var address: LongWord;
var len: LongWord): PByte;
cdecl; external LIBOPENBLT_LIBNAME;
function BltFirmwareAddData(address: LongWord;
len: LongWord;
data: PByte): LongWord;
cdecl; external LIBOPENBLT_LIBNAME;
function BltFirmwareRemoveData(address: LongWord;
len: LongWord): LongWord;
cdecl; external LIBOPENBLT_LIBNAME;
procedure BltFirmwareClearData; cdecl; external LIBOPENBLT_LIBNAME;
//***************************************************************************************
// G E N E R I C U T I L I T I E S
//***************************************************************************************
function BltUtilCrc16Calculate(data: PByte; len: LongWord): Word;
cdecl; external LIBOPENBLT_LIBNAME;
function BltUtilCrc32Calculate(data: PByte; len: LongWord): LongWord;
cdecl; external LIBOPENBLT_LIBNAME;
function BltUtilTimeGetSystemTime: LongWord; cdecl; external LIBOPENBLT_LIBNAME;
procedure BltUtilTimeDelayMs(delay: Word); cdecl; external LIBOPENBLT_LIBNAME;
implementation
end.
//******************************** end of openblt.pas ***********************************

View File

@ -0,0 +1,279 @@
/************************************************************************************//**
* \file port/linux/serialport.c
* \brief Serial port source file.
* \ingroup Session
* \internal
*----------------------------------------------------------------------------------------
* C O P Y R I G H T
*----------------------------------------------------------------------------------------
* Copyright (c) 2017 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 have received a copy of the GNU General Public License along with OpenBLT. It
* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
*
* \endinternal
****************************************************************************************/
/****************************************************************************************
* Include files
****************************************************************************************/
#include <assert.h> /* for assertions */
#include <stdint.h> /* for standard integer types */
#include <stddef.h> /* for NULL declaration */
#include <stdbool.h> /* for boolean type */
#include <unistd.h> /* UNIX standard functions */
#include <termios.h> /* POSIX terminal control */
#include <fcntl.h> /* file control definitions */
#include <sys/ioctl.h> /* system I/O control */
#include "serialport.h" /* serial port module */
/****************************************************************************************
* Macro definitions
****************************************************************************************/
/** \brief Invalid serial port device handle. */
#define SERIALPORT_INVALID_HANDLE (-1)
/****************************************************************************************
* Local data declarations
****************************************************************************************/
/** \brief Serial port handle. */
static int32_t portHandle;
/****************************************************************************************
* Local constant declarations
****************************************************************************************/
/** \brief Lookup table for converting this module's generic baudrate value to a value
* supported by the low level interface.
*/
static const speed_t baudrateLookup[] =
{
B9600, /**< Index 0 = SERIALPORT_BR9600 */
B19200, /**< Index 1 = SERIALPORT_BR19200 */
B38400, /**< Index 2 = SERIALPORT_BR38400 */
B57600, /**< Index 3 = SERIALPORT_BR57600 */
B115200 /**< Index 4 = SERIALPORT_BR115200 */
};
/************************************************************************************//**
** \brief Initializes the serial port module.
**
****************************************************************************************/
void SerialPortInit(void)
{
/* Invalidate the port handle. */
portHandle = SERIALPORT_INVALID_HANDLE;
} /*** end of SerialPortInit ***/
/************************************************************************************//**
** \brief Terminates the serial port module.
**
****************************************************************************************/
void SerialPortTerminate(void)
{
/* Make sure the serial port is closed. */
SerialPortClose();
} /*** end of SerialPortTerminate ***/
/************************************************************************************//**
** \brief Opens the connection with the serial port configured as 8,N,1 and no flow
** control.
** \param portname The name of the serial port to open, i.e. /dev/ttyUSB0.
** \param baudrate The desired communication speed.
** \return True if successful, false otherwise.
**
****************************************************************************************/
bool SerialPortOpen(char const * portname, tSerialPortBaudrate baudrate)
{
bool result = false;
struct termios options = { 0 };
int32_t iFlags;
/* Check parameters. */
assert(portname != NULL);
/* Only continue with valid parameters. */
if (portname != NULL) /*lint !e774 */
{
/* Assume the result to be okay from here on and only set it to error when a problem
* was detected.
*/
result = true;
/* Open the port. */
portHandle = open(portname, O_RDWR | O_NOCTTY | O_NDELAY);
/* Check the result */
if (portHandle == SERIALPORT_INVALID_HANDLE)
{
result = false;
}
/* Configure the device to block during read operations. */
if (result)
{
if (fcntl(portHandle, F_SETFL, 0) == -1)
{
SerialPortClose();
result = false;
}
}
/* Get the current options for the port. */
if (result)
{
if (tcgetattr(portHandle, &options) == -1)
{
SerialPortClose();
result = false;
}
}
/* Configure the baudrate. */
if (result)
{
if (cfsetispeed(&options, baudrateLookup[baudrate]) == -1)
{
SerialPortClose();
result = false;
}
}
if (result)
{
if (cfsetospeed(&options, baudrateLookup[baudrate]) == -1)
{
SerialPortClose();
result = false;
}
}
if (result)
{
/* Input modes - clear indicated ones giving: no break, no CR to NL,
* no parity check, no strip char, no start/stop output (sic) control.
*/
options.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
/* Output modes - clear giving: no post processing such as NL to CR+NL. */
options.c_oflag &= ~(OPOST);
/* Control modes - set 8 bit chars */
options.c_cflag |= (CS8);
/* Local modes - clear giving: echoing off, canonical off (no erase with
* backspace, ^U,...), no extended functions, no signal chars (^Z,^C).
*/
options.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
/* Configure timeouts. */
options.c_cc[VMIN] = 0;
options.c_cc[VTIME] = 1; /* in units of 1/10th of a second */
/* Set the new options for the port. */
if (tcsetattr(portHandle, TCSAFLUSH, &options) == -1)
{
SerialPortClose();
result = false;
}
}
/* Turn on DTR. */
if (result)
{
iFlags = TIOCM_DTR;
if (ioctl(portHandle, TIOCMBIS, &iFlags) == -1)
{
SerialPortClose();
result = false;
}
}
}
/* Give the result back to the caller. */
return result;
} /*** end of SerialPortOpen ***/
/************************************************************************************//**
** \brief Closes the connection with the serial port.
**
****************************************************************************************/
void SerialPortClose(void)
{
/* Close the port handle if valid. */
if (portHandle != SERIALPORT_INVALID_HANDLE)
{
close(portHandle);
}
/* Invalidate handle. */
portHandle = SERIALPORT_INVALID_HANDLE;
} /*** end of SerialPortClose ***/
/************************************************************************************//**
** \brief Writes data to the serial port.
** \param data Pointer to byte array with data to write.
** \param length Number of bytes to write.
** \return True if successful, false otherwise.
**
****************************************************************************************/
bool SerialPortWrite(uint8_t const * data, uint32_t length)
{
bool result = false;
/* Check parameters. */
assert(data != NULL);
assert(length > 0);
/* Only continue with valid parameters. */
if ( (data != NULL) && (length > 0) ) /*lint !e774 */
{
/* Submit the data for sending. */
if ((uint32_t)write(portHandle, data, length) == length)
{
result = true;
}
}
/* Give the result back to the caller. */
return result;
} /*** end of SerialPortWrite ***/
/************************************************************************************//**
** \brief Reads data from the serial port in a blocking manner.
** \param data Pointer to byte array to store read data.
** \param length Number of bytes to read.
** \return True if successful, false otherwise.
**
****************************************************************************************/
bool SerialPortRead(uint8_t * data, uint32_t length)
{
bool result = false;
/* Check parameters. */
assert(data != NULL);
assert(length > 0);
/* Only continue with valid parameters. */
if ( (data != NULL) && (length > 0) ) /*lint !e774 */
{
/* Attempt to read the requested data. */
if ((uint32_t)read(portHandle, data, length) == length)
{
result = true;
}
}
/* Give the result back to the caller. */
return result;
} /*** end of SerialPortRead ***/
/*********************************** end of serialport.c *******************************/

View File

@ -0,0 +1,71 @@
/************************************************************************************//**
* \file port/linux/timeutil.c
* \brief Time utility source file.
* \ingroup Utility
* \internal
*----------------------------------------------------------------------------------------
* C O P Y R I G H T
*----------------------------------------------------------------------------------------
* Copyright (c) 2017 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 have received a copy of the GNU General Public License along with OpenBLT. It
* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
*
* \endinternal
****************************************************************************************/
/****************************************************************************************
* Include files
****************************************************************************************/
#include <stdint.h> /* for standard integer types */
#include <stddef.h> /* for NULL declaration */
#include <stdbool.h> /* for boolean type */
#include <unistd.h> /* UNIX standard functions */
#include <sys/time.h> /* time definitions */
#include "util.h" /* Utility module */
/************************************************************************************//**
** \brief Get the system time in milliseconds.
** \return Time in milliseconds.
**
****************************************************************************************/
uint32_t UtilTimeGetSystemTimeMs(void)
{
uint32_t result = 0;
struct timeval tv;
if (gettimeofday(&tv, NULL) == 0)
{
result = (((uint32_t)tv.tv_sec * 1000ul) + ((uint32_t)tv.tv_usec / 1000ul));
}
/* Give the result back to the caller. */
return result;
} /*** end of UtilTimeGetSystemTimeMs ***/
/************************************************************************************//**
** \brief Performs a delay of the specified amount of milliseconds.
** \param delay Delay time in milliseconds.
**
****************************************************************************************/
void UtilTimeDelayMs(uint16_t delay)
{
(void)usleep(1000u * delay);
} /*** end of UtilTimeDelayMs **/
/*********************************** end of timeutil.c *********************************/

View File

@ -0,0 +1,310 @@
/************************************************************************************//**
* \file port/windows/serialport.c
* \brief Serial port source file.
* \ingroup Session
* \internal
*----------------------------------------------------------------------------------------
* C O P Y R I G H T
*----------------------------------------------------------------------------------------
* Copyright (c) 2017 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 have received a copy of the GNU General Public License along with OpenBLT. It
* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
*
* \endinternal
****************************************************************************************/
/****************************************************************************************
* Include files
****************************************************************************************/
#include <assert.h> /* for assertions */
#include <stdint.h> /* for standard integer types */
#include <stddef.h> /* for NULL declaration */
#include <stdbool.h> /* for boolean type */
#include <windows.h> /* for windows library */
#include "serialport.h" /* serial port module */
/****************************************************************************************
* Macro definitions
****************************************************************************************/
#define UART_TX_BUFFER_SIZE (1024u) /**< transmission buffer size */
#define UART_RX_BUFFER_SIZE (1024u) /**< reception buffer size */
/****************************************************************************************
* Local data declarations
****************************************************************************************/
/** \brief Serial port handle. */
static HANDLE hUart;
/****************************************************************************************
* Function prototypes
****************************************************************************************/
static uint32_t SerialConvertBaudrate(tSerialPortBaudrate baudrate);
/************************************************************************************//**
** \brief Initializes the serial port module.
**
****************************************************************************************/
void SerialPortInit(void)
{
/* Invalidate the port handle. */
hUart = INVALID_HANDLE_VALUE;
} /*** end of SerialPortInit ***/
/************************************************************************************//**
** \brief Terminates the serial port module.
**
****************************************************************************************/
void SerialPortTerminate(void)
{
/* Make sure the serial port is closed. */
SerialPortClose();
} /*** end of SerialPortTerminate ***/
/************************************************************************************//**
** \brief Opens the connection with the serial port configured as 8,N,1 and no flow
** control.
** \param portname The name of the serial port to open, i.e. COM4.
** \param baudrate The desired communication speed.
** \return True if successful, false otherwise.
**
****************************************************************************************/
bool SerialPortOpen(char const * portname, tSerialPortBaudrate baudrate)
{
bool result = false;
COMMTIMEOUTS timeouts = { 0 };
DCB dcbSerialParams = { 0 };
char portStr[64] = "\\\\.\\";
/* Check parameters. */
assert(portname != NULL);
/* Only continue if parameters are valid. */
if (portname != NULL)
{
/* Assume the result to be okay from here on and only set it to error when a problem
* was detected.
*/
result = true;
/* Construct the COM port name as a string. */
strcat(portStr, portname);
/* Obtain access to the COM port. */
hUart = CreateFile(portStr, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, 0);
/* Validate COM port handle. */
if (hUart == INVALID_HANDLE_VALUE)
{
result = false;
}
/* Get current COM port configuration. */
if (result)
{
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
if (!GetCommState(hUart, &dcbSerialParams))
{
(void)CloseHandle(hUart);
result = false;
}
}
/* Configure the baudrate and 8,n,1. */
if (result)
{
dcbSerialParams.BaudRate = SerialConvertBaudrate(baudrate);
dcbSerialParams.ByteSize = 8;
dcbSerialParams.StopBits = ONESTOPBIT;
dcbSerialParams.Parity = NOPARITY;
dcbSerialParams.fOutX = FALSE;
dcbSerialParams.fInX = FALSE;
dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE;
dcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE;
if (!SetCommState(hUart, &dcbSerialParams))
{
(void)CloseHandle(hUart);
result =false;
}
}
/* Set communication timeout parameters. */
if (result)
{
timeouts.ReadIntervalTimeout = 0;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.ReadTotalTimeoutMultiplier = 100;
timeouts.WriteTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier = 100;
if (!SetCommTimeouts(hUart, &timeouts))
{
(void)CloseHandle(hUart);
result = false;
}
}
/* Set transmit and receive buffer sizes. */
if (result)
{
if (!SetupComm(hUart, UART_RX_BUFFER_SIZE, UART_TX_BUFFER_SIZE))
{
(void)CloseHandle(hUart);
result = false;
}
}
/* Empty the transmit and receive buffers. */
if (result)
{
if (!FlushFileBuffers(hUart))
{
(void)CloseHandle(hUart);
result = false;
}
}
}
/* Give the result back to the caller. */
return result;
} /*** end of SerialPortOpen ***/
/************************************************************************************//**
** \brief Closes the connection with the serial port.
**
****************************************************************************************/
void SerialPortClose(void)
{
/* Close the COM port handle if valid. */
if (hUart != INVALID_HANDLE_VALUE)
{
(void)CloseHandle(hUart);
}
/* Set handles to invalid. */
hUart = INVALID_HANDLE_VALUE;
} /*** end of SerialPortClose ***/
/************************************************************************************//**
** \brief Writes data to the serial port.
** \param data Pointer to byte array with data to write.
** \param length Number of bytes to write.
** \return True if successful, false otherwise.
**
****************************************************************************************/
bool SerialPortWrite(uint8_t const * data, uint32_t length)
{
bool result = false;
DWORD dwWritten = 0;
/* Check parameters. */
assert(data != NULL);
assert(length > 0);
/* Only continue with valid parameters. */
if ( (data != NULL) && (length > 0) )
{
/* Submit the data for transmission with the serial port. */
if (WriteFile(hUart, data, length, &dwWritten, NULL))
{
/* Double check that all bytes were actually transmitted. */
if (dwWritten == length)
{
result = true;
}
}
}
/* Give the result back to the caller. */
return result;
} /*** end of SerialPortWrite ***/
/************************************************************************************//**
** \brief Reads data from the serial port in a blocking manner.
** \param data Pointer to byte array to store read data.
** \param length Number of bytes to read.
** \return True if successful, false otherwise.
**
****************************************************************************************/
bool SerialPortRead(uint8_t * data, uint32_t length)
{
bool result = false;
DWORD dwRead = 0;
/* Check parameters. */
assert(data != NULL);
assert(length > 0);
/* Only continue with valid parameters. */
if ( (data != NULL) && (length > 0) )
{
/* Attempt to read data from the serial port. */
if (ReadFile(hUart, data, length, &dwRead, NULL))
{
/* Double check that all bytes were actually read. */
if (dwRead == length)
{
result = true;
}
}
}
/* Give the result back to the caller. */
return result;
} /*** end of SerialPortRead ***/
/************************************************************************************//**
** \brief Opens the connection with the serial port configured as 8,N,1 and no flow
** control.
** \param baudrate The desired communication speed.
** \return True if successful, false otherwise.
**
****************************************************************************************/
static uint32_t SerialConvertBaudrate(tSerialPortBaudrate baudrate)
{
uint32_t result;
switch (baudrate)
{
case SERIALPORT_BR9600:
result = CBR_9600;
break;
case SERIALPORT_BR19200:
result = CBR_19200;
break;
case SERIALPORT_BR38400:
result = CBR_38400;
break;
case SERIALPORT_BR57600:
result = CBR_57600;
break;
case SERIALPORT_BR115200:
result = CBR_115200;
break;
default:
result = CBR_9600;
break;
}
return result;
} /*** end of SerialConvertBaudrate ***/
/*********************************** end of serialport.c *******************************/

View File

@ -0,0 +1,62 @@
/************************************************************************************//**
* \file port/windows/timeutil.c
* \brief Time utility source file.
* \ingroup Utility
* \internal
*----------------------------------------------------------------------------------------
* C O P Y R I G H T
*----------------------------------------------------------------------------------------
* Copyright (c) 2017 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 have received a copy of the GNU General Public License along with OpenBLT. It
* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
*
* \endinternal
****************************************************************************************/
/****************************************************************************************
* Include files
****************************************************************************************/
#include <stdint.h> /* for standard integer types */
#include <stdbool.h> /* for boolean type */
#include <windows.h> /* for windows library */
#include "util.h" /* Utility module */
/************************************************************************************//**
** \brief Get the system time in milliseconds.
** \return Time in milliseconds.
**
****************************************************************************************/
uint32_t UtilTimeGetSystemTimeMs(void)
{
return GetTickCount();
} /*** end of UtilTimeGetSystemTimeMs ***/
/************************************************************************************//**
** \brief Performs a delay of the specified amount of milliseconds.
** \param delay Delay time in milliseconds.
** \return none.
**
****************************************************************************************/
void UtilTimeDelayMs(uint16_t delay)
{
Sleep(delay);
} /*** end of UtilTimeDelayMs **/
/*********************************** end of timeutil.c *********************************/

View File

@ -0,0 +1,50 @@
/**
\mainpage OpenBLT Host Library (LibOpenBLT)
\details
\tableofcontents
\section into Introduction
LibOpenBLT is a host library for the OpenBLT bootloader. Its purpose is to allow quick and
easy creation of programs that can connect to and perform firmware updates on a
microcontroller that runs the OpenBLT bootloader.
LibOpenBLT is written in the C programming language (C99) and is cross-platform. It has
been successfully tested on a Windows PC, Linux PC and even embedded Linux systems such
as a Raspberry Pi and a Beagle Board.
\image html libopenblt_architecture.png
\image latex libopenblt_architecture.png
Both the MicroBoot (GUI) and BootCommander (CLI) firmware updater tools, which are part
of the OpenBLT bootloader package, make use of the OpenBLT Host Library. The source code
of these two tools serve as an additional reference on how to use the OpenBLT Host
Library when your are developing your own custom tool.
Refer to the OpenBLT website for additional information regarding the OpenBLT Host
Library, including step-by-step instructions on how to build both that shared and static
library from sources: https://www.feaser.com/openblt/doku.php?id=manual:libopenblt.
\verbatim
----------------------------------------------------------------------------------------
C O P Y R I G H T
----------------------------------------------------------------------------------------
Copyright (c) 2017 Feaser. 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 have received a copy of the GNU General Public License along with OpenBLT. It
should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
----------------------------------------------------------------------------------------
\endverbatim
*/

View File

@ -0,0 +1,65 @@
/************************************************************************************//**
* \file serialport.h
* \brief Serial port header file.
* \ingroup Session
* \internal
*----------------------------------------------------------------------------------------
* C O P Y R I G H T
*----------------------------------------------------------------------------------------
* Copyright (c) 2017 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 have received a copy of the GNU General Public License along with OpenBLT. It
* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
*
* \endinternal
****************************************************************************************/
#ifndef SERIALPORT_H
#define SERIALPORT_H
#ifdef __cplusplus
extern "C" {
#endif
/****************************************************************************************
* Type definitions
****************************************************************************************/
/** \brief Enumaration of the supported baudrates. */
typedef enum
{
SERIALPORT_BR9600 = 0, /**< 9600 bits/sec */
SERIALPORT_BR19200 = 1, /**< 19200 bits/sec */
SERIALPORT_BR38400 = 2, /**< 38400 bits/sec */
SERIALPORT_BR57600 = 3, /**< 57600 bits/sec */
SERIALPORT_BR115200 = 4 /**< 115200 bits/sec */
} tSerialPortBaudrate;
/****************************************************************************************
* Function prototypes
****************************************************************************************/
void SerialPortInit(void);
void SerialPortTerminate(void);
bool SerialPortOpen(char const * portname, tSerialPortBaudrate baudrate);
void SerialPortClose(void);
bool SerialPortWrite(uint8_t const * data, uint32_t length);
bool SerialPortRead(uint8_t * data, uint32_t length);
#ifdef __cplusplus
}
#endif
#endif /* SERIALPORT_H */
/********************************* end of serialport.h *********************************/

View File

@ -0,0 +1,206 @@
/************************************************************************************//**
* \file session.c
* \brief Communication session module source file.
* \ingroup Session
* \internal
*----------------------------------------------------------------------------------------
* C O P Y R I G H T
*----------------------------------------------------------------------------------------
* Copyright (c) 2017 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 have received a copy of the GNU General Public License along with OpenBLT. It
* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
*
* \endinternal
****************************************************************************************/
/****************************************************************************************
* Include files
****************************************************************************************/
#include <assert.h> /* for assertions */
#include <stdint.h> /* for standard integer types */
#include <stddef.h> /* for NULL declaration */
#include <stdbool.h> /* for boolean type */
#include "session.h" /* Communication session module */
/****************************************************************************************
* Local data declarations
****************************************************************************************/
/** \brief Pointer to the communication protocol that is linked. */
static tSessionProtocol const * protocolPtr;
/************************************************************************************//**
** \brief Initializes the communication session module for the specified protocol.
** \param protocol The session protocol module to link.
** \param protocolSettings Pointer to structure with protocol specific settings.
**
****************************************************************************************/
void SessionInit(tSessionProtocol const * protocol, void const * protocolSettings)
{
/* Check parameters. Note that the protocolSettings parameter is allowed to be NULL,
* because not every protocol might need additional settings.
*/
assert(protocol != NULL);
/* Link the protocol module. */
protocolPtr = protocol;
/* Initialize the protocol and pass on the settings pointer. */
if (protocolPtr != NULL)
{
protocolPtr->Init(protocolSettings);
}
} /*** end of SessionInit ***/
/************************************************************************************//**
** \brief Terminates the communication session module.
**
****************************************************************************************/
void SessionTerminate(void)
{
/* Terminate the linked protocol. */
if (protocolPtr != NULL)
{
protocolPtr->Terminate();
}
/* Unlink the protocol module. */
protocolPtr = NULL;
} /*** end of SessionTerminate ***/
/************************************************************************************//**
** \brief Starts the firmware update session. This is where the connection with the
** target is made and the bootloader on the target is activated.
** \return True if successful, false otherwise.
**
****************************************************************************************/
bool SessionStart(void)
{
bool result = false;
/* Pass the request on to the linked protocol module. */
if (protocolPtr != NULL)
{
result = protocolPtr->Start();
}
/* Give the result back to the caller. */
return result;
} /*** end of SessionStart ***/
/************************************************************************************//**
** \brief Stops the firmware update. This is where the bootloader starts the user
** program on the target if a valid one is present. After this the connection
** with the target is severed.
**
****************************************************************************************/
void SessionStop(void)
{
/* Pass the request on to the linked protocol module. */
if (protocolPtr != NULL)
{
protocolPtr->Stop();
}
} /*** end of SessionStop ***/
/************************************************************************************//**
** \brief Requests the bootloader to erase the specified range of memory on the
** target. The bootloader aligns this range to hardware specified erase
** blocks.
** \param address The starting memory address for the erase operation.
** \param len The total number of bytes to erase from memory.
** \return True if successful, false otherwise.
**
****************************************************************************************/
bool SessionClearMemory(uint32_t address, uint32_t len)
{
bool result = false;
/* Check parameters. */
assert(len > 0);
/* Only continue if the parameters are vald. */
if (len > 0)
{
/* Pass the request on to the linked protocol module. */
result = protocolPtr->ClearMemory(address, len);
}
/* Give the result back to the caller. */
return result;
} /*** end of SessionClearMemory ***/
/************************************************************************************//**
** \brief Requests the bootloader to program the specified data to memory. In case of
** non-volatile memory, the application needs to make sure the memory range
** was erased beforehand.
** \param address The starting memory address for the write operation.
** \param len The number of bytes in the data buffer that should be written.
** \param data Pointer to the byte array with data to write.
** \return True if successful, false otherwise.
**
****************************************************************************************/
bool SessionWriteData(uint32_t address, uint32_t len, uint8_t const * data)
{
bool result = false;
/* Check parameters. */
assert(data != NULL);
assert(len > 0);
/* Only continue if the parameters are valid. */
if ( (data != NULL) && (len > 0) ) /*lint !e774 */
{
/* Pass the request on to the linked protocol module. */
result = protocolPtr->WriteData(address, len, data);
}
/* Give the result back to the caller. */
return result;
} /*** end of SessionWriteData ***/
/************************************************************************************//**
** \brief Request the bootloader to upload the specified range of memory. The data is
** stored in the data byte array to which the pointer was specified.
** \param address The starting memory address for the read operation.
** \param len The number of bytes to upload from the target and store in the data
** buffer.
** \param data Pointer to the byte array where the uploaded data should be stored.
** \return True if successful, false otherwise.
**
****************************************************************************************/
bool SessionReadData(uint32_t address, uint32_t len, uint8_t * data)
{
bool result = false;
/* Check parameters. */
assert(data != NULL);
assert(len > 0);
/* Only continue if the parameters are valid. */
if ( (data != NULL) && (len > 0) ) /*lint !e774 */
{
/* Pass the request on to the linked protocol module. */
result = protocolPtr->ReadData(address, len, data);
}
/* Give the result back to the caller. */
return result;
} /*** end of SessionReadData ***/
/*********************************** end of session.c **********************************/

View File

@ -0,0 +1,101 @@
/************************************************************************************//**
* \file session.h
* \brief Communication session module header file.
* \ingroup Session
* \internal
*----------------------------------------------------------------------------------------
* C O P Y R I G H T
*----------------------------------------------------------------------------------------
* Copyright (c) 2017 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 have received a copy of the GNU General Public License along with OpenBLT. It
* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
*
* \endinternal
****************************************************************************************/
/************************************************************************************//**
* \defgroup Session Communication Session Module
* \brief Module with functionality to communicate with the bootloader on the target
* system.
* \ingroup Library
* \details
* The Communication Session module handles the communication with the bootloader during
* firmware updates on the target system. It contains an interface to link the desired
* communication protocol that should be used for the communication. For example the XCP
* protocol.
****************************************************************************************/
#ifndef SESSION_H
#define SESSION_H
#ifdef __cplusplus
extern "C" {
#endif
/****************************************************************************************
* Type definitions
****************************************************************************************/
/** \brief Session communication protocol interface. */
typedef struct t_session_protocol
{
/** \brief Initializes the protocol module. */
void (* Init) (void const * settings);
/** \brief Terminates the protocol module. */
void (* Terminate) (void);
/** \brief Starts the firmware update session. This is where the connection with the
* target is made and the bootloader on the target is activated.
*/
bool (* Start) (void);
/** \brief Stops the firmware update. This is where the bootloader starts the user
* program on the target if a valid one is present. After this the connection
* with the target is severed.
*/
void (* Stop) (void);
/** \brief Requests the bootloader to erase the specified range of memory on the
* target. The bootloader aligns this range to hardware specified erase blocks.
*/
bool (* ClearMemory) (uint32_t address, uint32_t len);
/** \brief Requests the bootloader to program the specified data to memory. In case of
* non-volatile memory, the application needs to make sure the memory range
* was erased beforehand.
*/
bool (* WriteData) (uint32_t address, uint32_t len, uint8_t const * data);
/** \brief Request the bootloader to upload the specified range of memory. The data is
* stored in the data byte array to which the pointer was specified.
*/
bool (* ReadData) (uint32_t address, uint32_t len, uint8_t * data);
} tSessionProtocol;
/****************************************************************************************
* Function prototypes
****************************************************************************************/
void SessionInit(tSessionProtocol const * protocol, void const * protocolSettings);
void SessionTerminate(void);
bool SessionStart(void);
void SessionStop(void);
bool SessionClearMemory(uint32_t address, uint32_t len);
bool SessionWriteData(uint32_t address, uint32_t len, uint8_t const * data);
bool SessionReadData(uint32_t address, uint32_t len, uint8_t * data);
#ifdef __cplusplus
}
#endif
#endif /* SESSION_H */
/********************************* end of session.h ************************************/

View File

@ -0,0 +1,800 @@
/************************************************************************************//**
* \file srecparser.c
* \brief Motorola S-record file parser source file.
* \ingroup Firmware
* \internal
*----------------------------------------------------------------------------------------
* C O P Y R I G H T
*----------------------------------------------------------------------------------------
* Copyright (c) 2017 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 have received a copy of the GNU General Public License along with OpenBLT. It
* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
*
* \endinternal
****************************************************************************************/
/****************************************************************************************
* Include files
****************************************************************************************/
#include <assert.h> /* for assertions */
#include <stdint.h> /* for standard integer types */
#include <stddef.h> /* for NULL declaration */
#include <stdbool.h> /* for boolean type */
#include <stdio.h> /* for standard I/O library */
#include <string.h> /* for string library */
#include <ctype.h> /* for toupper() etc. */
#include "util.h" /* Utility module */
#include "firmware.h" /* Firmware data module */
#include "srecparser.h" /* S-record parser */
/****************************************************************************************
* Type definitions
****************************************************************************************/
/** \brief Enumeration for the different supported S-record line types. */
typedef enum t_srec_parser_line_type
{
SREC_PARSER_LINE_TYPE_S0, /**< Header record. */
SREC_PARSER_LINE_TYPE_S1, /**< 16-bit address data record. */
SREC_PARSER_LINE_TYPE_S2, /**< 24-bit address data record. */
SREC_PARSER_LINE_TYPE_S3, /**< 32-bit address data record. */
SREC_PARSER_LINE_TYPE_S7, /**< 32-bit address termination. */
SREC_PARSER_LINE_TYPE_S8, /**< 24-bit address termination. */
SREC_PARSER_LINE_TYPE_S9, /**< 16-bit address termination. */
SREC_PARSER_LINE_TYPE_UNSUPPORTED /**< Unsupported line. */
} tSRecParserLineType;
/****************************************************************************************
* Function prototypes
****************************************************************************************/
static bool SRecParserLoadFromFile (char const * firmwareFile);
static bool SRecParserSaveToFile (char const * firmwareFile);
static bool SRecParserExtractLineData(char const * line, uint32_t * address,
uint32_t * len, uint8_t * data);
static tSRecParserLineType SRecParserGetLineType(char const * line);
static bool SRecParserVerifyChecksum(char const * line);
static bool SRecParserConstructLine(char * line, tSRecParserLineType lineType,
uint32_t address,
uint8_t const * data, uint8_t dataLen);
static uint8_t SRecParserHexStringToByte(char const * hexstring);
/****************************************************************************************
* Local constant declarations
****************************************************************************************/
/** \brief File parser structure filled with Motorola S-record parsing specifics. */
static const tFirmwareParser srecParser =
{
.LoadFromFile = SRecParserLoadFromFile,
.SaveToFile = SRecParserSaveToFile
};
/***********************************************************************************//**
** \brief Obtains a pointer to the parser structure, so that it can be linked to the
** firmware data module.
** \return Pointer to firmware parser structure.
**
****************************************************************************************/
tFirmwareParser const * SRecParserGetParser(void)
{
return &srecParser;
} /*** end of SRecParserGetParser ***/
/************************************************************************************//**
** \brief Parses the specified firmware file to extract firmware data and adds this
** data to the firmware data that is currently managed by the firmware data
** module.
** \param firmwareFile Filename of the firmware file to load.
** \return True if successful, false otherwise.
**
****************************************************************************************/
static bool SRecParserLoadFromFile (char const * firmwareFile)
{
bool result = false;
FILE *fp;
/* The bytes count entry on the S-record line is max 255 bytes. This include the
* address and the checksum. This would result in 255 * 2 = 510 characters. Another
* 4 characters are needed for the bytes count and line type characters. Then another
* two for possible line termination (new line + cariage return). This brings the total
* characters to 516. Note that this array was made static to lower the stack load.
*/
static char line[516];
/* The bytes count entry on the S-record line is max 255 bytes. This includes the
* address and checksum. This means the worst case max data bytes per line is 255 - 3.
* Note that this array was made static to lower the stack load.
*/
static uint8_t data[252];
uint32_t address;
uint32_t len;
/* Check parameters. */
assert(firmwareFile != NULL);
/* Only continue if the parameters are valid. */
if (firmwareFile != NULL) /*lint !e774 */
{
/* Open the file for reading. */
fp = fopen(firmwareFile, "r");
/* Only continue if the filepointer is valid. */
if (fp != NULL)
{
/* Start at the beginning of the file. */
rewind(fp);
/* Assume that everyting goes okay and then only set a negative result value upon
* detection of a problem.
*/
result = true;
/* Read the entire file, one line at a time. */
while (fgets(line, sizeof(line)/sizeof(line[0]), fp) != NULL )
{
/* Replace the line termination with a string termination. */
line[strcspn(line, "\n\r")] = '\0';
/* Extra data from the S-record line. */
if (SRecParserExtractLineData(line, &address, &len, data))
{
/* Only add data if there is actually something to add. */
if (len > 0)
{
/* Add the extracted data to the firmware data module. */
if (!FirmwareAddData(address, len, data))
{
/* Error detected. Flag it and abort. */
result = false;
break;
}
}
}
}
/* Close the file now that we are done with it. */
fclose(fp);
}
}
/* Give the result back to the caller. */
return result;
} /*** end of SRecParserLoadFromFile ***/
/************************************************************************************//**
** \brief Writes firmware data to the specified file in the correct file format.
** \param firmwareFile Filename of the firmware file to write to.
** \return True if successful, false otherwise.
**
****************************************************************************************/
static bool SRecParserSaveToFile (char const * firmwareFile)
{
bool result = false;
FILE *fp;
/* The bytes count entry on the S-record line is max 255 bytes. This include the
* address and the checksum. This would result in 255 * 2 = 510 characters. Another
* 4 characters are needed for the bytes count and line type characters. Then another
* two for possible line termination (new line + cariage return). This brings the total
* characters to 516. Note that this array was made static to lower the stack load.
*/
static char line[516];
/* The bytes count entry on the S-record line is max 255 bytes. This includes the
* address and checksum. This means the worst case max data bytes per line is 255 - 3.
* Note that this array was made static to lower the stack load.
*/
static uint8_t data[252];
tFirmwareSegment * segment;
uint32_t progDataLowestAddress = 0x00000000;
uint32_t progDataHighestAddress = 0xffffffff;
tSRecParserLineType dataLineType = SREC_PARSER_LINE_TYPE_S1;
tSRecParserLineType terminationLineType = SREC_PARSER_LINE_TYPE_S9;
uint32_t segmentIdx;
uint32_t currentAddress;
uint8_t currentByteCnt;
uint8_t const * currentDataPtr;
uint32_t segmentBytesLeft;
const uint8_t maxDataBytesPerLine = 32;
/* Check parameters. */
assert(firmwareFile != NULL);
/* Only continue if the parameters are valid and if there is something to save. */
if ( (firmwareFile != NULL) && (FirmwareGetSegmentCount() > 0) ) /*lint !e774 */
{
/* Open the file for writing. */
fp = fopen(firmwareFile, "w");
/* Only continue if the filepointer is valid. */
if (fp != NULL)
{
/* Init result value to okay at this point and only set it to error in case a
* problem was detected.
*/
result = true;
/* Determine the lowest memory address used in the program data. This address needs
* to be specified in the termination record at the end of the S-record file.
*/
segment = FirmwareGetSegment(0);
/* Sanity check. */
assert(segment != NULL);
if (segment == NULL) /*lint !e774 */
{
/* Flag error. */
result = false;
}
else
{
/* Store the lowest memory address. */
progDataLowestAddress = segment->base;
}
/* Determine the highest memory address used in the program data. This address
* is needed to determine the number of bits needed for the address in the
* S-record data lines (16, 24 or 32), which determines the type of S-record for
* the data lines (S1, S2, S3) and the termination line (S7, S8 or S9).
*/
if (result) /*lint !e774 */
{
segment = FirmwareGetSegment(FirmwareGetSegmentCount() - 1u);
/* Sanity check. */
assert(segment != NULL);
if (segment == NULL) /*lint !e774 */
{
/* Flag error. */
result = false;
}
else
{
progDataHighestAddress = segment->base + segment->length - 1u;
/* Does the address have more than 24 bits? */
if (progDataHighestAddress > 0xffffff)
{
dataLineType = SREC_PARSER_LINE_TYPE_S3;
terminationLineType = SREC_PARSER_LINE_TYPE_S7;
}
/* Does the address have more than 16 bits? */
else if (progDataHighestAddress > 0xffff)
{
dataLineType = SREC_PARSER_LINE_TYPE_S2;
terminationLineType = SREC_PARSER_LINE_TYPE_S8;
}
}
}
/* Extract just the filename and copy it to the data buffer. */
if (result) /*lint !e774 */
{
if (!UtilFileExtractFilename(firmwareFile, (char *)data))
{
/* Could not extract filename. */
result = false;
}
}
/* Construct and add the S0-record with the filename. */
if (result)
{
/* Construct the S0-record. */
result = SRecParserConstructLine(line, SREC_PARSER_LINE_TYPE_S0, 0x0000, data,
(uint8_t)strlen((char *)data));
if (result)
{
/* Add the S0-record. */
if (fprintf(fp, "%s\r\n", line) < 0)
{
/* Could not write line to the file. */
result = false;
}
}
}
/* Write all the program data records. Process one segment at a time. */
if (result)
{
/* Loop through all segments. */
for (segmentIdx = 0; segmentIdx < FirmwareGetSegmentCount(); segmentIdx++)
{
/* Obtain the segment. */
segment = FirmwareGetSegment(segmentIdx);
/* Sanity check. */
assert(segment != NULL);
if (segment == 0) /*lint !e774 */
{
/* Flag error and abort loop. */
result = false;
break;
}
/* Initialize base address, byte count and data pointer. */
currentAddress = segment->base;
currentDataPtr = segment->data;
segmentBytesLeft = segment->length;
/* Process al bytes in the segment. */
while (segmentBytesLeft > 0)
{
/* Determine the number of bytes that can be written. */
currentByteCnt = maxDataBytesPerLine;
if (segmentBytesLeft < maxDataBytesPerLine)
{
currentByteCnt = (uint8_t)segmentBytesLeft;
}
/* Construct the data record. */
result = SRecParserConstructLine(line, dataLineType, currentAddress,
currentDataPtr, currentByteCnt);
if (!result)
{
/* Error detected. No need to continue the loop. */
break;
}
/* Add the data record. */
if (fprintf(fp, "%s\r\n", line) < 0)
{
/* Could not write line to the file. Abort loop. */
result = false;
break;
}
/* Update loop variables. */
currentAddress += currentByteCnt;
currentDataPtr += currentByteCnt;
segmentBytesLeft -= currentByteCnt;
}
}
}
/* Write the termination record. */
if (result)
{
/* Construct the termination record. */
result = SRecParserConstructLine(line, terminationLineType,
progDataLowestAddress, data, 0u);
if (result)
{
/* Add the termination record. */
if (fprintf(fp, "%s\r\n", line) < 0)
{
/* Could not write line to the file. */
result = false;
}
}
}
}
}
/* Give the result back to the caller. */
return result;
} /*** end of SRecParserSaveToFile ***/
/************************************************************************************//**
** \brief Checks if the specified S-record line is of the type that contains program
** data. If it does, then the program data and base address are extracted and
** stored at the function parameter pointers.
** \param line Pointer to the line from an S-record file.
** \param address Pointer where the start address of the program data is stored.
** \param len Pointer for storing the number of extracted program data bytes.
** \param data Pointer to byte array where the extracted program data bytes are
** stored.
** \return True if successful, false otherwise.
**
****************************************************************************************/
static bool SRecParserExtractLineData(char const * line, uint32_t * address,
uint32_t * len, uint8_t * data)
{
bool result = false;
tSRecParserLineType lineType;
uint8_t dataByteCount = 0;
uint8_t bytesOnLine;
uint8_t idx;
/* Verify parameters. */
assert(line != NULL);
assert(address != NULL);
assert(len != NULL);
assert(data != NULL);
/* Only continue with valid parameters. */
if ( (line != NULL) && (address != NULL) && (len != NULL) &&
(data != NULL) ) /*lint !e774 */
{
/* Determine the line type. */
lineType = SRecParserGetLineType(line);
/* Only continue if the S-record line contains program data. */
if ( (lineType == SREC_PARSER_LINE_TYPE_S1) ||
(lineType == SREC_PARSER_LINE_TYPE_S2) ||
(lineType == SREC_PARSER_LINE_TYPE_S3) )
{
/* Verify the checksum of the line. */
if (SRecParserVerifyChecksum(line))
{
/* Adjust pointer to point to byte count value. */
line += 2u;
/* Read out the number of byte values that follow on the line. */
bytesOnLine = SRecParserHexStringToByte(line);
/* Process S1 line type. */
if (lineType == SREC_PARSER_LINE_TYPE_S1)
{
/* Read out the 16-bit address. */
line += 2u;
*address = (uint32_t)SRecParserHexStringToByte(line) << 8u;
line += 2u;
*address += (uint32_t)SRecParserHexStringToByte(line);
/* Determine how many data bytes are on the line. -2 bytes for address and
* -1 byte for the checksum.
*/
dataByteCount = bytesOnLine - 3u;
}
/* Process S2 line type. */
else if (lineType == SREC_PARSER_LINE_TYPE_S2)
{
/* Read out the 24-bit address. */
line += 2u;
*address = (uint32_t)SRecParserHexStringToByte(line) << 16u;
line += 2u;
*address += (uint32_t)SRecParserHexStringToByte(line) << 8u;
line += 2u;
*address += (uint32_t)SRecParserHexStringToByte(line);
/* Determine how many data bytes are on the line. -3 bytes for address and
* -1 byte for the checksum.
*/
dataByteCount = bytesOnLine - 4u;
}
/* Process S3 line type. */
else
{
/* Read out the 32-bit address. */
line += 2u;
*address = (uint32_t)SRecParserHexStringToByte(line) << 24u;
line += 2u;
*address += (uint32_t)SRecParserHexStringToByte(line) << 16u;
line += 2u;
*address += (uint32_t)SRecParserHexStringToByte(line) << 8u;
line += 2u;
*address += (uint32_t)SRecParserHexStringToByte(line);
/* Determine how many data bytes are on the line. -4 bytes for address and
* -1 byte for the checksum.
*/
dataByteCount = bytesOnLine - 5u;
}
/* Adjust pointer to point to the first data byte after the address. */
line += 2u;
/* Read and store data bytes. */
for (idx = 0; idx < dataByteCount; idx++)
{
data[idx] = SRecParserHexStringToByte(line);
line += 2u;
}
/* Store the number of data bytes that were copied to the array. */
*len = dataByteCount;
/* Data extraction complete. */
result = true;
}
}
}
/* Give the result back to the caller. */
return result;
} /*** end of SRecParserExtractLineData ***/
/************************************************************************************//**
** \brief Inspects a line from a Motorola S-Record file to determine its type.
** \param line A line from the S-Record.
** \return The S-Record line type.
**
****************************************************************************************/
static tSRecParserLineType SRecParserGetLineType(char const * line)
{
tSRecParserLineType result = SREC_PARSER_LINE_TYPE_UNSUPPORTED;
/* Verify parameters. */
assert(line != NULL);
/* Only continue with valid parameters. */
if (line != NULL) /*lint !e774 */
{
/* Check if the line starts with the 'S' character, followed by a digit */
if ( (toupper((int32_t)(line[0])) == 'S') && (isdigit((int32_t)(line[1]))) )
{
/* Check the digit that follows the 'S' character. Currently only line types that
* contain program data are needed.
*/
switch (line[1])
{
case '0':
result = SREC_PARSER_LINE_TYPE_S0;
break;
case '1':
result = SREC_PARSER_LINE_TYPE_S1;
break;
case '2':
result = SREC_PARSER_LINE_TYPE_S2;
break;
case '3':
result = SREC_PARSER_LINE_TYPE_S3;
break;
case '7':
result = SREC_PARSER_LINE_TYPE_S7;
break;
case '8':
result = SREC_PARSER_LINE_TYPE_S8;
break;
case '9':
result = SREC_PARSER_LINE_TYPE_S9;
break;
default:
result = SREC_PARSER_LINE_TYPE_UNSUPPORTED;
break;
}
}
}
/* Give the result back to the caller. */
return result;
} /*** end of SRecParserGetLineType ***/
/************************************************************************************//**
** \brief Inspects an S1, S2 or S3 line from a Motorola S-Record file to
** determine if the checksum at the end is corrrect.
** \param line An S1, S2 or S3 line from the S-Record.
** \return True if the checksum is correct, false otherwise.
**
****************************************************************************************/
static bool SRecParserVerifyChecksum(char const * line)
{
bool result = false;
uint8_t bytes_on_line;
uint8_t checksum = 0;
/* Verify parameters. */
assert(line != NULL);
/* Only continue with with valid parameters. */
if (line != NULL) /*lint !e774 */
{
/* Adjust pointer to point to byte count value. */
line += 2u;
/* Read out the number of byte values that follow on the line. */
bytes_on_line = SRecParserHexStringToByte(line);
/* An S-record will always have at least a 16-bit address and a checksum value. */
if (bytes_on_line >= 3u)
{
/* Byte count is part of checksum. */
checksum += bytes_on_line;
/* Adjust pointer to the first byte of the address. */
line += 2u;
/* Add byte values of address and data, but not the final checksum. */
do
{
/* Add the next byte value to the checksum. */
checksum += SRecParserHexStringToByte(line);
/* Update counter. */
bytes_on_line--;
/* Point to next hex string in the line. */
line += 2u;
}
while (bytes_on_line > 1u);
/* 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 == SRecParserHexStringToByte(line))
{
/* Checksum correct. */
result = true;
}
}
}
/* Give the result back to the caller. */
return result;
} /*** end of SRecParserVerifyChecksum ***/
/************************************************************************************//**
** \brief Creates a NUL terminated S-record line, given the specified line type,
** address and data bytes. The checksum at the end of the line is also
** calculated and added.
** \param line Pointer to character array where the string will be stored.
** \param lineType The type of S-record line to construct.
** \param address The address to embed into the line after the byte count.
** \param data Point to byte array with data bytes to add to the line.
** \param dataLen The number of data bytes present in the data-array.
** \return True if successful, false otherwise.
**
****************************************************************************************/
static bool SRecParserConstructLine(char * line, tSRecParserLineType lineType,
uint32_t address, uint8_t const * data,
uint8_t dataLen)
{
bool result = false;
uint8_t addressBits;
uint8_t byteVal;
char hexByteStr[3];
uint8_t cnt;
uint8_t checksumVal = 0;
/* Verify parameters. */
assert(line != NULL);
if (dataLen > 0)
{
assert(data != NULL);
}
/* Only continue with valid parameters. */
if (line != NULL) /*lint !e774 */
{
/* Set the result value to successful and only change this upon detection of an
* error.
*/
result = true;
/* Start of with an empty string. */
line[0] = '\0';
/* Add the record type based on the lineType and store the number of bits in the
* address.
*/
switch (lineType)
{
case SREC_PARSER_LINE_TYPE_S0:
strcat(line, "S0");
addressBits = 16;
break;
case SREC_PARSER_LINE_TYPE_S1:
strcat(line, "S1");
addressBits = 16;
break;
case SREC_PARSER_LINE_TYPE_S2:
strcat(line, "S2");
addressBits = 24;
break;
case SREC_PARSER_LINE_TYPE_S3:
strcat(line, "S3");
addressBits = 32;
break;
case SREC_PARSER_LINE_TYPE_S7:
strcat(line, "S7");
addressBits = 32;
break;
case SREC_PARSER_LINE_TYPE_S8:
strcat(line, "S8");
addressBits = 24;
break;
case SREC_PARSER_LINE_TYPE_S9:
strcat(line, "S9");
addressBits = 16;
break;
case SREC_PARSER_LINE_TYPE_UNSUPPORTED:
default:
/* Invalid line type specified. Should not happed. */
addressBits = 16;
assert(false); /*lint !e506 */
break;
}
/* Next, add the number of bytes that will follow on the line. This is the size in
* bytes of the address, the actual number of data bytes and the checksum.
*/
byteVal = (addressBits / 8u) + dataLen + 1u;
checksumVal += byteVal;
if (sprintf(hexByteStr, "%02X", byteVal) != 2)
{
/* Error occurred. */
result = false;
}
else
{
/* Append it to the line. */
strcat(line, hexByteStr);
}
/* Add the address. */
for (cnt = (addressBits / 8u); cnt > 0; cnt--)
{
byteVal = (uint8_t)(address >> ( (cnt - 1u) * 8u));
checksumVal += byteVal;
if (sprintf(hexByteStr, "%02X", byteVal) != 2)
{
/* Error occurred. */
result = false;
}
else
{
/* Append it to the line. */
strcat(line, hexByteStr);
}
}
/* Add the data bytes. */
for (cnt = 0; cnt < dataLen; cnt++)
{
byteVal = 0;
if (data != NULL)
{
byteVal = data[cnt];
}
checksumVal += byteVal;
if (sprintf(hexByteStr, "%02X", byteVal) != 2)
{
/* Error occurred. */
result = false;
}
else
{
/* Append it to the line. */
strcat(line, hexByteStr);
}
}
/* Calculate and add the checksum. */
checksumVal = ~checksumVal;
byteVal = checksumVal;
if (sprintf(hexByteStr, "%02X", byteVal) != 2)
{
/* Error occurred. */
result = false;
}
else
{
/* Append it to the line. */
strcat(line, hexByteStr);
}
}
/* Give the result back to the caller. */
return result;
} /*** end of SRecParserConstructLine ***/
/************************************************************************************//**
** \brief Helper function to convert a sequence of 2 characters that represent
** a hexadecimal value to the actual byte value.
** Example: SRecParserHexStringToByte("2f") --> returns 47.
** \param hexstring String beginning with 2 characters that represent a hexa-
** decimal value.
** \return The resulting byte value.
**
****************************************************************************************/
static uint8_t SRecParserHexStringToByte(char const * hexstring)
{
uint8_t result = 0;
int32_t c;
uint8_t counter;
/* Verify parameters. */
assert(hexstring != NULL);
/* Only continue with valid parameters. */
if (hexstring != NULL) /*lint !e774 */
{
/* A hexadecimal character is 2 characters long (i.e 0x4F minus the 0x part). */
for (counter = 0; counter < 2u; counter++)
{
/* Read out the character */
c = toupper((int32_t)(hexstring[counter]));
/* Check that the character is 0..9 or A..F */
if (isxdigit(c))
{
/* 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 = (uint8_t)((result << 4u) + c);
}
}
}
/* Give the result back to the caller. */
return result;
} /*** end of SRecParserHexStringToByte ***/
/*********************************** end of srecparser.c *******************************/

View File

@ -0,0 +1,49 @@
/************************************************************************************//**
* \file srecparser.h
* \brief Motorola S-record file parser header file.
* \ingroup Firmware
* \internal
*----------------------------------------------------------------------------------------
* C O P Y R I G H T
*----------------------------------------------------------------------------------------
* Copyright (c) 2017 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 have received a copy of the GNU General Public License along with OpenBLT. It
* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
*
* \endinternal
****************************************************************************************/
#ifndef SRECPARSER_H
#define SRECPARSER_H
#ifdef __cplusplus
extern "C" {
#endif
/****************************************************************************************
* Function prototypes
****************************************************************************************/
tFirmwareParser const * SRecParserGetParser(void);
#ifdef __cplusplus
}
#endif
#endif /* SRECPARSER_H */
/********************************* end of srecparser.h *********************************/

View File

@ -0,0 +1,258 @@
/************************************************************************************//**
* \file util.c
* \brief Utility module source file.
* \ingroup Utility
* \internal
*----------------------------------------------------------------------------------------
* C O P Y R I G H T
*----------------------------------------------------------------------------------------
* Copyright (c) 2017 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 have received a copy of the GNU General Public License along with OpenBLT. It
* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
*
* \endinternal
****************************************************************************************/
/****************************************************************************************
* Include files
****************************************************************************************/
#include <assert.h> /* for assertions */
#include <stdint.h> /* for standard integer types */
#include <stddef.h> /* for NULL declaration */
#include <stdbool.h> /* for boolean type */
#include <string.h> /* for string library */
#include "util.h" /* Utility module */
/****************************************************************************************
* Local constant declarations
****************************************************************************************/
/** \brief Lookup table for calculating a 16-bit CRC checksum. It was generated using an
* initial value of 0 and a polynomial of 0x8005.
*/
static const uint16_t utilChecksumCrc16Table[256] =
{
0x0000, 0x8005, 0x800F, 0x000A, 0x801B, 0x001E, 0x0014, 0x8011,
0x8033, 0x0036, 0x003C, 0x8039, 0x0028, 0x802D, 0x8027, 0x0022,
0x8063, 0x0066, 0x006C, 0x8069, 0x0078, 0x807D, 0x8077, 0x0072,
0x0050, 0x8055, 0x805F, 0x005A, 0x804B, 0x004E, 0x0044, 0x8041,
0x80C3, 0x00C6, 0x00CC, 0x80C9, 0x00D8, 0x80DD, 0x80D7, 0x00D2,
0x00F0, 0x80F5, 0x80FF, 0x00FA, 0x80EB, 0x00EE, 0x00E4, 0x80E1,
0x00A0, 0x80A5, 0x80AF, 0x00AA, 0x80BB, 0x00BE, 0x00B4, 0x80B1,
0x8093, 0x0096, 0x009C, 0x8099, 0x0088, 0x808D, 0x8087, 0x0082,
0x8183, 0x0186, 0x018C, 0x8189, 0x0198, 0x819D, 0x8197, 0x0192,
0x01B0, 0x81B5, 0x81BF, 0x01BA, 0x81AB, 0x01AE, 0x01A4, 0x81A1,
0x01E0, 0x81E5, 0x81EF, 0x01EA, 0x81FB, 0x01FE, 0x01F4, 0x81F1,
0x81D3, 0x01D6, 0x01DC, 0x81D9, 0x01C8, 0x81CD, 0x81C7, 0x01C2,
0x0140, 0x8145, 0x814F, 0x014A, 0x815B, 0x015E, 0x0154, 0x8151,
0x8173, 0x0176, 0x017C, 0x8179, 0x0168, 0x816D, 0x8167, 0x0162,
0x8123, 0x0126, 0x012C, 0x8129, 0x0138, 0x813D, 0x8137, 0x0132,
0x0110, 0x8115, 0x811F, 0x011A, 0x810B, 0x010E, 0x0104, 0x8101,
0x8303, 0x0306, 0x030C, 0x8309, 0x0318, 0x831D, 0x8317, 0x0312,
0x0330, 0x8335, 0x833F, 0x033A, 0x832B, 0x032E, 0x0324, 0x8321,
0x0360, 0x8365, 0x836F, 0x036A, 0x837B, 0x037E, 0x0374, 0x8371,
0x8353, 0x0356, 0x035C, 0x8359, 0x0348, 0x834D, 0x8347, 0x0342,
0x03C0, 0x83C5, 0x83CF, 0x03CA, 0x83DB, 0x03DE, 0x03D4, 0x83D1,
0x83F3, 0x03F6, 0x03FC, 0x83F9, 0x03E8, 0x83ED, 0x83E7, 0x03E2,
0x83A3, 0x03A6, 0x03AC, 0x83A9, 0x03B8, 0x83BD, 0x83B7, 0x03B2,
0x0390, 0x8395, 0x839F, 0x039A, 0x838B, 0x038E, 0x0384, 0x8381,
0x0280, 0x8285, 0x828F, 0x028A, 0x829B, 0x029E, 0x0294, 0x8291,
0x82B3, 0x02B6, 0x02BC, 0x82B9, 0x02A8, 0x82AD, 0x82A7, 0x02A2,
0x82E3, 0x02E6, 0x02EC, 0x82E9, 0x02F8, 0x82FD, 0x82F7, 0x02F2,
0x02D0, 0x82D5, 0x82DF, 0x02DA, 0x82CB, 0x02CE, 0x02C4, 0x82C1,
0x8243, 0x2046, 0x024C, 0x8249, 0x0258, 0x825D, 0x8257, 0x0252,
0x0270, 0x8275, 0x827F, 0x027A, 0x826B, 0x026E, 0x0264, 0x8261,
0x0220, 0x8225, 0x822F, 0x022A, 0x823B, 0x023E, 0x0234, 0x8231,
0x8213, 0x0216, 0x021C, 0x8219, 0x0208, 0x820D, 0x8207, 0x0202
};
/** \brief Lookup table for calculating a 32-bit CRC checksum. It was generated using an
* initial value of 0 and a polynomial of 0x04C11DB7
*/
static const uint32_t utilChecksumCrc32Table[256] =
{
0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2,
0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, 0x350C9B64, 0x31CD86D3,
0x3C8EA00A, 0x384FBDBD, 0x4C11DB70, 0x48D0C6C7, 0x4593E01E, 0x4152FDA9, 0x5F15ADAC,
0x5BD4B01B, 0x569796C2, 0x52568B75, 0x6A1936C8, 0x6ED82B7F, 0x639B0DA6, 0x675A1011,
0x791D4014, 0x7DDC5DA3, 0x709F7B7A, 0x745E66CD, 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E,
0x95609039, 0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, 0xBE2B5B58, 0xBAEA46EF,
0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033, 0xA4AD16EA, 0xA06C0B5D, 0xD4326D90,
0xD0F37027, 0xDDB056FE, 0xD9714B49, 0xC7361B4C, 0xC3F706FB, 0xCEB42022, 0xCA753D95,
0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1, 0xE13EF6F4, 0xE5FFEB43, 0xE8BCCD9A,
0xEC7DD02D, 0x34867077, 0x30476DC0, 0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C,
0x2E003DC5, 0x2AC12072, 0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16, 0x018AEB13,
0x054BF6A4, 0x0808D07D, 0x0CC9CDCA, 0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE,
0x6B93DDDB, 0x6F52C06C, 0x6211E6B5, 0x66D0FB02, 0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1,
0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA, 0xACA5C697, 0xA864DB20,
0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B, 0xBB60ADFC, 0xB6238B25, 0xB2E29692, 0x8AAD2B2F,
0x8E6C3698, 0x832F1041, 0x87EE0DF6, 0x99A95DF3, 0x9D684044, 0x902B669D, 0x94EA7B2A,
0xE0B41DE7, 0xE4750050, 0xE9362689, 0xEDF73B3E, 0xF3B06B3B, 0xF771768C, 0xFA325055,
0xFEF34DE2, 0xC6BCF05F, 0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34,
0xDC3ABDED, 0xD8FBA05A, 0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637, 0x7A089632,
0x7EC98B85, 0x738AAD5C, 0x774BB0EB, 0x4F040D56, 0x4BC510E1, 0x46863638, 0x42472B8F,
0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53, 0x251D3B9E, 0x21DC2629, 0x2C9F00F0,
0x285E1D47, 0x36194D42, 0x32D850F5, 0x3F9B762C, 0x3B5A6B9B, 0x0315D626, 0x07D4CB91,
0x0A97ED48, 0x0E56F0FF, 0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623, 0xF12F560E,
0xF5EE4BB9, 0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65, 0xEBA91BBC, 0xEF68060B,
0xD727BBB6, 0xD3E6A601, 0xDEA580D8, 0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD, 0xCDA1F604,
0xC960EBB3, 0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7, 0xAE3AFBA2, 0xAAFBE615,
0xA7B8C0CC, 0xA379DD7B, 0x9B3660C6, 0x9FF77D71, 0x92B45BA8, 0x9675461F, 0x8832161A,
0x8CF30BAD, 0x81B02D74, 0x857130C3, 0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640,
0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B, 0x43CDC09C, 0x7B827D21, 0x7F436096, 0x7200464F,
0x76C15BF8, 0x68860BFD, 0x6C47164A, 0x61043093, 0x65C52D24, 0x119B4BE9, 0x155A565E,
0x18197087, 0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC, 0x3793A651,
0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D, 0x2056CD3A, 0x2D15EBE3, 0x29D4F654,
0xC5A92679, 0xC1683BCE, 0xCC2B1D17, 0xC8EA00A0, 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB,
0xDBEE767C, 0xE3A1CBC1, 0xE760D676, 0xEA23F0AF, 0xEEE2ED18, 0xF0A5BD1D, 0xF464A0AA,
0xF9278673, 0xFDE69BC4, 0x89B8FD09, 0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5,
0x9E7D9662, 0x933EB0BB, 0x97FFAD0C, 0xAFB010B1, 0xAB710D06, 0xA6322BDF, 0xA2F33668,
0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4
};
/************************************************************************************//**
** \brief Calculates a 16-bit CRC value over the specified data using byte wise
** computation with a table.
** \param data Array with bytes over which the CRC16 should be calculated.
** \param len Number of bytes in the data array.
** \return The 16-bit CRC value.
**
****************************************************************************************/
uint16_t UtilChecksumCrc16Calculate(uint8_t const * data, uint32_t len)
{
uint16_t result = 0;
uint32_t byteIdx;
/* Verify parameters. */
assert(data != NULL);
assert(len > 0);
/* Only continue if parameters are valid. */
if ( (data != NULL) && (len > 0) ) /*lint !e774 */
{
/* Loop through all bytes. */
for (byteIdx = 0; byteIdx < len; byteIdx++)
{
result = ((uint16_t)(result << 8)) ^
utilChecksumCrc16Table[(uint8_t)(data[byteIdx] ^ (result >> 8))];
}
}
return result;
} /*** end of UtilChecksumCrc16Calculate ***/
/************************************************************************************//**
** \brief Calculates a 32-bit CRC value over the specified data using byte wise
** computation with a table.
** \param data Array with bytes over which the CRC32 should be calculated.
** \param len Number of bytes in the data array.
** \return The 32-bit CRC value.
**
****************************************************************************************/
uint32_t UtilChecksumCrc32Calculate(uint8_t const * data, uint32_t len)
{
uint32_t result = 0;
uint32_t byteIdx;
/* Verify parameters. */
assert(data != NULL);
assert(len > 0);
/* Only continue if parameters are valid. */
if ( (data != NULL) && (len > 0) ) /*lint !e774 */
{
/* Loop through all bytes. */
for (byteIdx = 0; byteIdx < len; byteIdx++)
{
result = ((uint32_t)(result << 8)) ^
utilChecksumCrc32Table[(uint8_t)(data[byteIdx] ^ (result >> 24))];
}
}
return result;
} /*** end of UtilChecksumCrc32Calculate ***/
/************************************************************************************//**
** \brief Extracts the filename including extention from the specified full filename,
** which could possible include a path. The function can handle both the
** backslash and forward slash path delimiter, to make it crossplatform.
** \param fullFilename The filename with path possible included.
** \param filenameBuffer Pointer to the character array where the resulting filename
** should be stored.
** \return True if successful, false otherwise.
**
****************************************************************************************/
bool UtilFileExtractFilename(char const * fullFilename, char * filenameBuffer)
{
bool result = false;
char const * filenamePtr;
/* Verify parameters. */
assert(fullFilename != NULL);
assert(filenameBuffer != NULL);
/* Only continue with valid parameters. */
if ( (fullFilename != NULL) && (filenameBuffer != NULL) ) /*lint !e774 */
{
/* Extract just the filename, so without its path from the firmware file. First
* assume a unix type path with forward slashes.
*/
filenamePtr = strrchr(fullFilename, '/');
/* Check if a forward slash was detected. */
if (filenamePtr != NULL)
{
/* Update the pointer so that it point to the start of the filename. */
filenamePtr++;
}
else
{
/* No unix type forward slash found. This can be because the path uses windows
* type backslashes or because there is no path present and it is already just
* the filename. Now check for a windows type path with backslashes.
*/
filenamePtr = strrchr(fullFilename, '\\');
/* Check if a forward slash was detected. */
if (filenamePtr != NULL)
{
/* Update the pointer so that it point to the start of the filename. */
filenamePtr++;
}
/* In case no slashes were found in the firmware file, then it is already just the
* filename.
*/
else
{
filenamePtr = fullFilename;
}
}
/* Copy the resulting filename to the buffer. */
strcpy(filenameBuffer, filenamePtr);
/* Success. */
result = true;
}
/* Give the result back to the caller. */
return result;
} /*** end of UtilFileExtractFilename ***/
/*********************************** end of util.c *************************************/

View File

@ -0,0 +1,62 @@
/************************************************************************************//**
* \file util.h
* \brief Utility module header file.
* \ingroup Utility
* \internal
*----------------------------------------------------------------------------------------
* C O P Y R I G H T
*----------------------------------------------------------------------------------------
* Copyright (c) 2017 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 have received a copy of the GNU General Public License along with OpenBLT. It
* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
*
* \endinternal
****************************************************************************************/
/************************************************************************************//**
* \defgroup Utility Generic Utilities
* \brief Generic utility functions and definitions.
* \ingroup Library
* \details
* The Utility module contains generic functions and definitions that can be handy for
* use internally in the library and also externally by another application that makes
* use of the library.
****************************************************************************************/
#ifndef UTIL_H
#define UTIL_H
#ifdef __cplusplus
extern "C" {
#endif
/****************************************************************************************
* Function prototypes
****************************************************************************************/
uint16_t UtilChecksumCrc16Calculate(uint8_t const * data, uint32_t len);
uint32_t UtilChecksumCrc32Calculate(uint8_t const * data, uint32_t len);
bool UtilFileExtractFilename(char const * fullFilename, char * filenameBuffer);
uint32_t UtilTimeGetSystemTimeMs(void);
void UtilTimeDelayMs(uint16_t delay);
#ifdef __cplusplus
}
#endif
#endif /* UTIL_H */
/********************************* end of util.h ***************************************/

View File

@ -0,0 +1,971 @@
/************************************************************************************//**
* \file xcploader.c
* \brief XCP Loader module source file.
* \ingroup XcpLoader
* \internal
*----------------------------------------------------------------------------------------
* C O P Y R I G H T
*----------------------------------------------------------------------------------------
* Copyright (c) 2017 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 have received a copy of the GNU General Public License along with OpenBLT. It
* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
*
* \endinternal
****************************************************************************************/
/****************************************************************************************
* Include files
****************************************************************************************/
#include <assert.h> /* for assertions */
#include <stdint.h> /* for standard integer types */
#include <stddef.h> /* for NULL declaration */
#include <stdbool.h> /* for boolean type */
#include "session.h" /* Communication session module */
#include "xcploader.h" /* XCP loader module */
/****************************************************************************************
* Macro definitions
****************************************************************************************/
/* XCP command codes as defined by the protocol currently supported by this module */
#define XCPLOADER_CMD_CONNECT (0xFFu) /**< XCP connect command code. */
#define XCPLOADER_CMD_SET_MTA (0xF6u) /**< XCP set mta command code. */
#define XCPLOADER_CMD_UPLOAD (0xF5u) /**< XCP upload command code. */
#define XCPLOADER_CMD_PROGRAM_START (0xD2u) /**< XCP program start command code. */
#define XCPLOADER_CMD_PROGRAM_CLEAR (0xD1u) /**< XCP program clear command code. */
#define XCPLOADER_CMD_PROGRAM (0xD0u) /**< XCP program command code. */
#define XCPLOADER_CMD_PROGRAM_RESET (0xCFu) /**< XCP program reset command code. */
#define XCPLOADER_CMD_PROGRAM_MAX (0xC9u) /**< XCP program max command code. */
/* XCP response packet IDs as defined by the protocol. */
#define XCPLOADER_CMD_PID_RES (0xFFu) /**< positive response */
/** \brief Maximum timeout for the XCP connect command. */
#define XCPLOADER_CONNECT_TIMEOUT_MS (20u)
/** \brief Number of retries to connect to the XCP slave. */
#define XCPLOADER_CONNECT_RETRIES (5u)
/****************************************************************************************
* Function prototypes
****************************************************************************************/
/* Protocol functions for linking to the session module. */
static void XcpLoaderInit(void const * settings);
static void XcpLoaderTerminate(void);
static bool XcpLoaderStart(void);
static void XcpLoaderStop(void);
static bool XcpLoaderClearMemory(uint32_t address, uint32_t len);
static bool XcpLoaderWriteData(uint32_t address, uint32_t len, uint8_t const * data);
static bool XcpLoaderReadData(uint32_t address, uint32_t len, uint8_t * data);
/* General module specific utility functions. */
static void XcpLoaderSetOrderedLong(uint32_t value, uint8_t *data);
/* XCP command functions. */
static bool XcpLoaderSendCmdConnect(void);
static bool XcpLoaderSendCmdSetMta(uint32_t address);
static bool XcpLoaderSendCmdUpload(uint8_t * data, uint8_t length);
static bool XcpLoaderSendCmdProgramStart(void);
static bool XcpLoaderSendCmdProgramReset(void);
static bool XcpLoaderSendCmdProgram(uint8_t length, uint8_t const * data);
static bool XcpLoaderSendCmdProgramMax(uint8_t const * data);
static bool XcpLoaderSendCmdProgramClear(uint32_t length);
/****************************************************************************************
* Local constant declarations
****************************************************************************************/
/** \brief Protocol structure filled with XCP loader specifics. */
static const tSessionProtocol xcpLoader =
{
.Init = XcpLoaderInit,
.Terminate = XcpLoaderTerminate,
.Start = XcpLoaderStart,
.Stop = XcpLoaderStop,
.ClearMemory = XcpLoaderClearMemory,
.WriteData = XcpLoaderWriteData,
.ReadData = XcpLoaderReadData
};
/****************************************************************************************
* Local data declarations
****************************************************************************************/
/** \brief The settings that should be used by the XCP loader. */
static tXcpLoaderSettings xcpSettings;
/** \brief Flag to keep track of the connection status. */
static bool xcpConnected;
/** \brief Store the byte ordering of the XCP slave. */
static bool xcpSlaveIsIntel;
/** \brief The max number of bytes in the command transmit object (master->slave). */
static uint8_t xcpMaxCto;
/** \brief The max number of bytes in the command transmit object (master->slave) during
* a programming session.
*/
static uint8_t xcpMaxProgCto;
/** \brief The max number of bytes in the data transmit object (slave->master). */
static uint16_t xcpMaxDto;
/***********************************************************************************//**
** \brief Obtains a pointer to the protocol structure, so that it can be linked to
** the communication session module.
** \return Pointer to protocol structure.
**
****************************************************************************************/
tSessionProtocol const * XcpLoaderGetProtocol(void)
{
return &xcpLoader;
} /*** end of XcpLoaderGetProtocol ***/
/************************************************************************************//**
** \brief Initializes the protocol module.
** \param settings Pointer to the structure with protocol settings.
**
****************************************************************************************/
static void XcpLoaderInit(void const * settings)
{
/* Initialize locals. */
xcpConnected = false;
xcpSlaveIsIntel = false;
xcpMaxCto = 0;
xcpMaxProgCto = 0;
xcpMaxDto = 0;
/* Check parameter. */
assert(settings != NULL);
/* Only continue with valid parameter. */
if (settings != NULL) /*lint !e774 */
{
/* shallow copy the XCP settings for later usage */
xcpSettings = *(tXcpLoaderSettings *)settings;
/* Check that a valid transport layer was specified. */
assert(xcpSettings.transport != NULL);
/* Only access the transport layer if it is valid. */
if (xcpSettings.transport != NULL) /*lint !e774 */
{
/* Initialize the transport layer. */
xcpSettings.transport->Init(xcpSettings.transportSettings);
}
/* Invalidate the transportSettings as it is probably no longer valid outside this
* function scope and should also not be used anymore.
*/
xcpSettings.transportSettings = NULL;
}
} /*** end of XcpLoaderInit ***/
/************************************************************************************//**
** \brief Terminates the protocol module.
**
****************************************************************************************/
static void XcpLoaderTerminate(void)
{
/* Make sure a valid transport layer is linked. */
assert(xcpSettings.transport != NULL);
/* Only continue with a valid transport layer. */
if (xcpSettings.transport != NULL) /*lint !e774 */
{
/* Stop the session. */
XcpLoaderStop();
/* Terminate the transport layer. */
xcpSettings.transport->Terminate();
/* Unlink the transport layer. */
xcpSettings.transport = NULL;
}
} /*** end of XcpLoaderTerminate ***/
/************************************************************************************//**
** \brief Starts the firmware update session. This is where the connection with the
** target is made and the bootloader on the target is activated.
** \return True if successful, false otherwise.
**
****************************************************************************************/
static bool XcpLoaderStart(void)
{
bool result = false;
uint8_t retryCnt;
/* Make sure a valid transport layer is linked. */
assert(xcpSettings.transport != NULL);
/* Only continue with a valid transport layer. */
if (xcpSettings.transport != NULL) /*lint !e774 */
{
/* Make sure the session is stopped before starting a new one. */
XcpLoaderStop();
/* Init the result value to okay and only set it to error when a problem occurred. */
result = true;
/* Connect the transport layer. */
if (!xcpSettings.transport->Connect())
{
/* Could not connect the transport layer. */
result = false;
}
/* Connect to the target with a finite amount of retries. */
if (result)
{
for (retryCnt=0; retryCnt<XCPLOADER_CONNECT_RETRIES; retryCnt++)
{
/* Send the connect command. */
if (XcpLoaderSendCmdConnect())
{
/* Update connection state. */
xcpConnected = true;
/* Connected so no need to retry. */
break;
}
}
}
/* Check if a connection with the target could be made within the finite amount
* of retries.
*/
if (!xcpConnected)
{
/* Disconnect the transport layer again. */
xcpSettings.transport->Disconnect();
/* Update the result. */
result = false;
}
/* Place the target in programming mode if connected. */
if (result)
{
if (!XcpLoaderSendCmdProgramStart())
{
result = false;
}
}
}
/* Give the result back to the caller. */
return result;
} /*** end of XcpLoaderStart ***/
/************************************************************************************//**
** \brief Stops the firmware update. This is where the bootloader starts the user
** program on the target if a valid one is present. After this the connection
** with the target is severed.
**
****************************************************************************************/
static void XcpLoaderStop(void)
{
/* Make sure a valid transport layer is linked. */
assert(xcpSettings.transport != NULL);
/* Only continue with a valid transport layer and if actually connected. */
if ( (xcpSettings.transport != NULL) && (xcpConnected) ) /*lint !e774 */
{
/* End the programming session by sending the program command with size 0. */
if (XcpLoaderSendCmdProgram(0, NULL))
{
/* Disconnect the target. Here the reset command is used instead of the disconnect
* command, because the bootloader should start the user program on the target.
*/
(void)XcpLoaderSendCmdProgramReset();
}
/* Disconnect the transport layer. */
xcpSettings.transport->Disconnect();
/* Reset connection status. */
xcpConnected = false;
}
} /*** end of XcpLoaderStop ***/
/************************************************************************************//**
** \brief Requests the bootloader to erase the specified range of memory on the
** target. The bootloader aligns this range to hardware specified erase
** blocks.
** \param address The starting memory address for the erase operation.
** \param len The total number of bytes to erase from memory.
** \return True if successful, false otherwise.
**
****************************************************************************************/
static bool XcpLoaderClearMemory(uint32_t address, uint32_t len)
{
bool result = false;
/* Check parameters. */
assert(len > 0);
/* Make sure a valid transport layer is linked. */
assert(xcpSettings.transport != NULL);
/* Only continue if a transport layer is linked and the parameters are valid. */
if ( (len > 0) && (xcpSettings.transport != NULL) && (xcpConnected) )
{
/* Init the result value to okay and only set it to error when a problem occurred. */
result = true;
/* First set the MTA pointer. */
if (!XcpLoaderSendCmdSetMta(address))
{
result = false;
}
/* Now perform the erase operation. */
if (result)
{
if (!XcpLoaderSendCmdProgramClear(len))
{
result = false;
}
}
}
/* Give the result back to the caller. */
return result;
} /*** end of XcpLoaderClearMemory ***/
/************************************************************************************//**
** \brief Requests the bootloader to program the specified data to memory. In case of
** non-volatile memory, the application needs to make sure the memory range
** was erased beforehand.
** \param address The starting memory address for the write operation.
** \param len The number of bytes in the data buffer that should be written.
** \param data Pointer to the byte array with data to write.
** \return True if successful, false otherwise.
**
****************************************************************************************/
static bool XcpLoaderWriteData(uint32_t address, uint32_t len, uint8_t const * data)
{
bool result = false;
uint8_t currentWriteCnt;
uint32_t bufferOffset = 0;
/* Check parameters. */
assert(data != NULL);
assert(len > 0);
/* Make sure a valid transport layer is linked. */
assert(xcpSettings.transport != NULL);
/* Only continue if the parameters are valid. */
if ( (data != NULL) && (len > 0) && (xcpSettings.transport != NULL) && /*lint !e774 */
(xcpConnected) )
{
/* Init the result value to okay and only set it to error when a problem occurred. */
result = true;
/* First set the MTA pointer. */
if (!XcpLoaderSendCmdSetMta(address))
{
result = false;
}
/* Perform segmented programming of the data. */
if (result)
{
while (len > 0)
{
/* Set the current write length to make optimal use of the available packet
* data.
*/
currentWriteCnt = len % (xcpMaxProgCto - 1u);
if (currentWriteCnt == 0)
{
currentWriteCnt = (xcpMaxProgCto - 1u);
}
/* Prepare the packed data for the program command. */
if (currentWriteCnt < (xcpMaxProgCto - 1u))
{
/* Program data. */
if (!XcpLoaderSendCmdProgram(currentWriteCnt, &data[bufferOffset]))
{
result = false;
break;
}
}
else
{
/* Program max data. */
if (!XcpLoaderSendCmdProgramMax(&data[bufferOffset]))
{
result = false;
break;
}
}
/* Update loop variables. */
len -= currentWriteCnt;
bufferOffset += currentWriteCnt;
}
}
}
/* Give the result back to the caller. */
return result;
} /*** end of XcpLoaderWriteData ***/
/************************************************************************************//**
** \brief Request the bootloader to upload the specified range of memory. The data is
** stored in the data byte array to which the pointer was specified.
** \param address The starting memory address for the read operation.
** \param len The number of bytes to upload from the target and store in the data
** buffer.
** \param data Pointer to the byte array where the uploaded data should be stored.
** \return True if successful, false otherwise.
**
****************************************************************************************/
static bool XcpLoaderReadData(uint32_t address, uint32_t len, uint8_t * data)
{
bool result = false;
uint8_t currentReadCnt;
uint32_t bufferOffset = 0;
/* Check parameters. */
assert(data != NULL);
assert(len > 0);
/* Make sure a valid transport layer is linked. */
assert(xcpSettings.transport != NULL);
/* Only continue if the parameters are valid. */
if ( (data != NULL) && (len > 0) && (xcpSettings.transport != NULL) && /*lint !e774 */
(xcpConnected) )
{
/* Init the result value to okay and only set it to error when a problem occurred. */
result = true;
/* First set the MTA pointer. */
if (!XcpLoaderSendCmdSetMta(address))
{
result = false;
}
/* Perform segmented upload of the data. */
if (result)
{
while (len > 0)
{
/* Set the current read length to make optimal use of the available packet
* data.
*/
currentReadCnt = len % (uint8_t)(xcpMaxDto - 1u);
if (currentReadCnt == 0)
{
currentReadCnt = (uint8_t)(xcpMaxDto - 1u);
}
/* Upload some data */
if (!XcpLoaderSendCmdUpload(&data[bufferOffset], currentReadCnt))
{
result = false;
break;
}
/* Update loop variables. */
len -= currentReadCnt;
bufferOffset += currentReadCnt;
}
}
}
/* Give the result back to the caller. */
return result;
} /*** end of XcpLoaderReadData ***/
/************************************************************************************//**
** \brief Stores a 32-bit value into a byte buffer taking into account Intel
** or Motorola byte ordering.
** \param value The 32-bit value to store in the buffer.
** \param data Array to the buffer for storage.
**
****************************************************************************************/
static void XcpLoaderSetOrderedLong(uint32_t value, uint8_t *data)
{
/* Check parameters. */
assert(data != NULL);
/* Only continue with valid parameters. */
if (data != NULL) /*lint !e774 */
{
if (xcpSlaveIsIntel)
{
data[3] = (uint8_t)(value >> 24);
data[2] = (uint8_t)(value >> 16);
data[1] = (uint8_t)(value >> 8);
data[0] = (uint8_t)value;
}
else
{
data[0] = (uint8_t)(value >> 24);
data[1] = (uint8_t)(value >> 16);
data[2] = (uint8_t)(value >> 8);
data[3] = (uint8_t)value;
}
}
} /*** end of XcpLoaderSetOrderedLong ***/
/************************************************************************************//**
** \brief Sends the XCP Connect command.
** \return True if successful, false otherwise.
**
****************************************************************************************/
static bool XcpLoaderSendCmdConnect(void)
{
bool result = false;
tXcpTransportPacket cmdPacket;
tXcpTransportPacket resPacket;
/* Make sure a valid transport layer is linked. */
assert(xcpSettings.transport != NULL);
/* Only continue with a valid transport layer. */
if (xcpSettings.transport != NULL) /*lint !e774 */
{
/* Init the result value to okay and only set it to error when a problem occurred. */
result = true;
/* Prepare the command packet. */
cmdPacket.data[0] = XCPLOADER_CMD_CONNECT;
cmdPacket.data[1] = 0; /* normal mode */
cmdPacket.len = 2;
/* Send the packet. */
if (!xcpSettings.transport->SendPacket(&cmdPacket, &resPacket,
XCPLOADER_CONNECT_TIMEOUT_MS))
{
/* Could not send packet or receive response within the specified timeout. */
result = false;
}
/* Only continue if a response was received. */
if (result)
{
/* Check if the response was valid. */
if ( (resPacket.len != 8) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) )
{
/* Not a valid or positive response. */
result = false;
}
}
/* Process the response data. */
if (result)
{
/* Store slave's byte ordering information. */
if ((resPacket.data[2] & 0x01) == 0)
{
xcpSlaveIsIntel = true;
}
else
{
xcpSlaveIsIntel = false;
}
/* Store max number of bytes the slave allows for master->slave packets. */
xcpMaxCto = resPacket.data[3];
xcpMaxProgCto = xcpMaxCto;
/* Store max number of bytes the slave allows for slave->master packets. */
if (xcpSlaveIsIntel)
{
xcpMaxDto = resPacket.data[4] + (resPacket.data[5] << 8);
}
else
{
xcpMaxDto = resPacket.data[5] + (resPacket.data[4] << 8);
}
/* Double check size configuration. CTO length can be adjusted. DTO not. */
if (xcpMaxCto > XCPLOADER_PACKET_SIZE_MAX) /*lint !e685 */
{
xcpMaxCto = XCPLOADER_PACKET_SIZE_MAX;
}
if (xcpMaxDto > XCPLOADER_PACKET_SIZE_MAX)
{
result = false;
}
if ( (xcpMaxCto == 0) || (xcpMaxDto == 0) )
{
result = false;
}
}
}
/* Give the result back to the caller. */
return result;
} /*** end of XcpLoaderSendCmdConnect ***/
/************************************************************************************//**
** \brief Sends the XCP Set MTA command.
** \param address New MTA address for the slave.
** \return True if successful, false otherwise.
**
****************************************************************************************/
static bool XcpLoaderSendCmdSetMta(uint32_t address)
{
bool result = false;
tXcpTransportPacket cmdPacket;
tXcpTransportPacket resPacket;
/* Make sure a valid transport layer is linked. */
assert(xcpSettings.transport != NULL);
/* Only continue with a valid transport layer. */
if (xcpSettings.transport != NULL) /*lint !e774 */
{
/* Init the result value to okay and only set it to error when a problem occurred. */
result = true;
/* Prepare the command packet. */
cmdPacket.data[0] = XCPLOADER_CMD_SET_MTA;
cmdPacket.data[1] = 0; /* Reserved. */
cmdPacket.data[2] = 0; /* Reserved. */
cmdPacket.data[3] = 0; /* Address extension not supported. */
/* Set the address taking into account byte ordering. */
XcpLoaderSetOrderedLong(address, &cmdPacket.data[4]);
cmdPacket.len = 8;
/* Send the packet. */
if (!xcpSettings.transport->SendPacket(&cmdPacket, &resPacket,
xcpSettings.timeoutT1))
{
/* Could not send packet or receive response within the specified timeout. */
result = false;
}
/* Only continue if a response was received. */
if (result)
{
/* Check if the response was valid. */
if ( (resPacket.len != 1) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) )
{
/* Not a valid or positive response. */
result = false;
}
}
}
/* Give the result back to the caller. */
return result;
} /*** end of XcpLoaderSendCmdSetMta ***/
/************************************************************************************//**
** \brief Sends the XCP UPLOAD command.
** \param data Destination data buffer.
** \param length Number of bytes to upload.
** \return SB_TRUE is successfull, SB_FALSE otherwise.
**
****************************************************************************************/
static bool XcpLoaderSendCmdUpload(uint8_t * data, uint8_t length)
{
bool result = false;
tXcpTransportPacket cmdPacket;
tXcpTransportPacket resPacket;
uint8_t dataIdx;
/* Cannot request more data then the max rx data - 1. */
assert(length < xcpMaxDto);
assert(data != NULL);
/* Make sure a valid transport layer is linked. */
assert(xcpSettings.transport != NULL);
/* Only continue with a valid transport layer and valid parameters. */
if ( (length < xcpMaxDto) && (data != NULL) &&
(xcpSettings.transport != NULL) ) /*lint !e774 */
{
/* Init the result value to okay and only set it to error when a problem occurred. */
result = true;
/* Prepare the command packet. */
cmdPacket.data[0] = XCPLOADER_CMD_UPLOAD;
cmdPacket.data[1] = length;
cmdPacket.len = 2;
/* Send the packet. */
if (!xcpSettings.transport->SendPacket(&cmdPacket, &resPacket,
xcpSettings.timeoutT1))
{
/* Could not send packet or receive response within the specified timeout. */
result = false;
}
/* Only continue if a response was received. */
if (result)
{
/* Check if the response was valid. */
if ( (resPacket.len == 0) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) )
{
/* Not a valid or positive response. */
result = false;
}
}
/* Now store the uploaded data. */
if (result)
{
for (dataIdx = 0; dataIdx < length; dataIdx++)
{
data[dataIdx] = resPacket.data[dataIdx + 1];
}
}
}
/* Give the result back to the caller. */
return result;
} /*** end of XcpLoaderSendCmdUpload ***/
/************************************************************************************//**
** \brief Sends the XCP PROGRAM START command.
** \return True if successful, false otherwise.
**
****************************************************************************************/
static bool XcpLoaderSendCmdProgramStart(void)
{
bool result = false;
tXcpTransportPacket cmdPacket;
tXcpTransportPacket resPacket;
/* Make sure a valid transport layer is linked. */
assert(xcpSettings.transport != NULL);
/* Only continue with a valid transport layer. */
if (xcpSettings.transport != NULL) /*lint !e774 */
{
/* Init the result value to okay and only set it to error when a problem occurred. */
result = true;
/* Prepare the command packet. */
cmdPacket.data[0] = XCPLOADER_CMD_PROGRAM_START;
cmdPacket.len = 1;
/* Send the packet. */
if (!xcpSettings.transport->SendPacket(&cmdPacket, &resPacket,
xcpSettings.timeoutT3))
{
/* Could not send packet or receive response within the specified timeout. */
result = false;
}
/* Only continue if a response was received. */
if (result)
{
/* Check if the response was valid. */
if ( (resPacket.len != 7) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) )
{
/* Not a valid or positive response. */
result = false;
}
}
/* Store max number of bytes the slave allows for master->slave packets during the
* programming session.
*/
xcpMaxProgCto = resPacket.data[3];
if (xcpMaxProgCto > XCPLOADER_PACKET_SIZE_MAX) /*lint !e685 */
{
xcpMaxProgCto = XCPLOADER_PACKET_SIZE_MAX;
}
}
/* Give the result back to the caller. */
return result;
} /*** end of XcpLoaderSendCmdProgramStart ***/
/************************************************************************************//**
** \brief Sends the XCP PROGRAM RESET command. Note that this command is a bit
** different as in it does not require a response.
** \return True if successful, false otherwise.
**
****************************************************************************************/
static bool XcpLoaderSendCmdProgramReset(void)
{
bool result = false;
tXcpTransportPacket cmdPacket;
tXcpTransportPacket resPacket;
/* Make sure a valid transport layer is linked. */
assert(xcpSettings.transport != NULL);
/* Only continue with a valid transport layer. */
if (xcpSettings.transport != NULL) /*lint !e774 */
{
/* Init the result value to okay and only set it to error when a problem occurred. */
result = true;
/* Prepare the command packet. */
cmdPacket.data[0] = XCPLOADER_CMD_PROGRAM_RESET;
cmdPacket.len = 1;
/* Send the packet. Note that it is okay if no response is received as this is
* allowed for the program reset command. Just make sure to only process the
* response if one was actually received.
*/
if (xcpSettings.transport->SendPacket(&cmdPacket, &resPacket,
xcpSettings.timeoutT5))
{
/* Still here so a response was received. check if the reponse was valid. */
if ( (resPacket.len != 1) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) )
{
/* Not a valid or positive response. */
result = false;
}
}
}
/* Give the result back to the caller. */
return result;
} /*** end of XcpLoaderSendCmdProgramReset ***/
/************************************************************************************//**
** \brief Sends the XCP PROGRAM command.
** \param length Number of bytes in the data array to program.
** \param data Array with data bytes to program.
** \return True if successful, false otherwise.
**
****************************************************************************************/
static bool XcpLoaderSendCmdProgram(uint8_t length, uint8_t const * data)
{
bool result = false;
tXcpTransportPacket cmdPacket;
tXcpTransportPacket resPacket;
uint8_t cnt;
/* Verify that this number of bytes actually fits in this command. */
assert((length <= (xcpMaxProgCto-2)) &&
(xcpMaxProgCto <= XCPLOADER_PACKET_SIZE_MAX)); /*lint !e685 */
if (length > 0)
{
assert(data != NULL);
}
/* Make sure a valid transport layer is linked. */
assert(xcpSettings.transport != NULL);
/* Only continue with a valid transport layer and valid parameters. */
if ( (length <= (xcpMaxProgCto-2)) &&
(xcpMaxProgCto <= XCPLOADER_PACKET_SIZE_MAX) && /*lint !e685 */
(xcpSettings.transport != NULL) )/*lint !e774 */
{
/* Init the result value to okay and only set it to error when a problem occurred. */
result = true;
/* Prepare the command packet */
cmdPacket.data[0] = XCPLOADER_CMD_PROGRAM;
cmdPacket.data[1] = length;
/* Only access data if it is not a NULL pointer. */
if (data != NULL)
{
for (cnt=0; cnt<length; cnt++)
{
cmdPacket.data[cnt+2] = data[cnt];
}
}
cmdPacket.len = length + 2;
/* Send the packet. */
if (!xcpSettings.transport->SendPacket(&cmdPacket, &resPacket,
xcpSettings.timeoutT5))
{
/* Could not send packet or receive response within the specified timeout. */
result = false;
}
/* Only continue if a response was received. */
if (result)
{
/* Check if the response was valid. */
if ( (resPacket.len != 1) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) )
{
/* Not a valid or positive response. */
result = false;
}
}
}
/* Give the result back to the caller. */
return result;
} /*** end of XcpLoaderSendCmdProgram ***/
/************************************************************************************//**
** \brief Sends the XCP PROGRAM MAX command.
** \param data Array with data bytes to program.
** \return True if successful, false otherwise.
**
****************************************************************************************/
static bool XcpLoaderSendCmdProgramMax(uint8_t const * data)
{
bool result = false;
tXcpTransportPacket cmdPacket;
tXcpTransportPacket resPacket;
uint8_t cnt;
/* verify that this number of bytes actually fits in this command */
assert(xcpMaxProgCto <= XCPLOADER_PACKET_SIZE_MAX); /*lint !e685 */
assert(data != NULL);
/* Only continue with a valid transport layer and valid parameters. */
if ( (xcpMaxProgCto <= XCPLOADER_PACKET_SIZE_MAX) && (data != NULL) && /*lint !e685 */
(xcpSettings.transport != NULL) )/*lint !e774 */
{
/* Init the result value to okay and only set it to error when a problem occurred. */
result = true;
/* Prepare the command packet. */
cmdPacket.data[0] = XCPLOADER_CMD_PROGRAM_MAX;
for (cnt = 0; cnt < (xcpMaxProgCto-1); cnt++)
{
cmdPacket.data[cnt+1] = data[cnt];
}
cmdPacket.len = xcpMaxProgCto;
/* Send the packet. */
if (!xcpSettings.transport->SendPacket(&cmdPacket, &resPacket,
xcpSettings.timeoutT5))
{
/* Could not send packet or receive response within the specified timeout. */
result = false;
}
/* Only continue if a response was received. */
if (result)
{
/* Check if the response was valid. */
if ( (resPacket.len != 1) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) )
{
/* Not a valid or positive response. */
result = false;
}
}
}
/* Give the result back to the caller. */
return result;
} /*** end of XcpLoaderSendCmdProgramMax ***/
/************************************************************************************//**
** \brief Sends the XCP PROGRAM CLEAR command.
** \param length Number of elements to clear starting at the MTA address.
** \return True if successful, false otherwise.
**
****************************************************************************************/
static bool XcpLoaderSendCmdProgramClear(uint32_t length)
{
bool result = false;
tXcpTransportPacket cmdPacket;
tXcpTransportPacket resPacket;
/* Only continue with a valid transport layer. */
if (xcpSettings.transport != NULL) /*lint !e774 */
{
/* Init the result value to okay and only set it to error when a problem occurred. */
result = true;
/*Pprepare the command packet. */
cmdPacket.data[0] = XCPLOADER_CMD_PROGRAM_CLEAR;
cmdPacket.data[1] = 0; /* Use absolute mode. */
cmdPacket.data[2] = 0; /* Reserved. */
cmdPacket.data[3] = 0; /* Reserved. */
/* Set the erase length taking into account byte ordering. */
XcpLoaderSetOrderedLong(length, &cmdPacket.data[4]);
cmdPacket.len = 8;
/* Send the packet. */
if (!xcpSettings.transport->SendPacket(&cmdPacket, &resPacket,
xcpSettings.timeoutT4))
{
/* Could not send packet or receive response within the specified timeout. */
result = false;
}
/* Only continue if a response was received. */
if (result)
{
/* Check if the response was valid. */
if ( (resPacket.len != 1) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) )
{
/* Not a valid or positive response. */
result = false;
}
}
}
/* Give the result back to the caller. */
return result;
} /*** end of XcpLoaderSendCmdProgramClear ***/
/*********************************** end of xcploader.c ********************************/

View File

@ -0,0 +1,112 @@
/************************************************************************************//**
* \file xcploader.h
* \brief XCP Loader module header file.
* \ingroup XcpLoader
* \internal
*----------------------------------------------------------------------------------------
* C O P Y R I G H T
*----------------------------------------------------------------------------------------
* Copyright (c) 2017 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 have received a copy of the GNU General Public License along with OpenBLT. It
* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
*
* \endinternal
****************************************************************************************/
/************************************************************************************//**
* \defgroup XcpLoader XCP version 1.0 protocol
* \brief This module implements the XCP communication protocol that can be linked
* to the Session module.
* \ingroup Session
* \details
* This XCP Loader module contains functionality according to the standardized XCP
* protocol version 1.0. XCP is a universal measurement and calibration communication
* protocol. Note that only those parts of the XCP master functionality are implemented
* that are applicable to performing a firmware update on the slave. This means
* functionality for reading, programming, and erasing (non-volatile) memory.
****************************************************************************************/
#ifndef XCPLOADER_H
#define XCPLOADER_H
#ifdef __cplusplus
extern "C" {
#endif
/****************************************************************************************
* Macro definitions
****************************************************************************************/
/** \brief Total number of bytes in a master<->slave data packet. It should be at least
* equal or larger than that configured on the slave.
*/
#define XCPLOADER_PACKET_SIZE_MAX (255u)
/****************************************************************************************
* Type definitions
****************************************************************************************/
/** \brief XCP transport layer packet type. */
typedef struct t_xcp_transport_packet
{
uint8_t data[XCPLOADER_PACKET_SIZE_MAX]; /**< Packet data. */
uint8_t len; /**< Packet length. */
} tXcpTransportPacket;
/** \brief XCP transport layer. */
typedef struct t_xcp_transport
{
/** \brief Initialization of the XCP transpor layer. */
void (*Init) (void const * settings);
/** \brief Termination the XCP transpor layer. */
void (*Terminate) (void);
/** \brief Connects the XCP transpor layer. */
bool (*Connect) (void);
/** \brief Disconnects the XCP transpor layer. */
void (*Disconnect) (void);
/** \brief Sends an XCP packet and waits for the response to come back. */
bool (*SendPacket) (tXcpTransportPacket const * txPacket,
tXcpTransportPacket * rxPacket, uint16_t timeout);
} tXcpTransport;
/** \brief XCP protocol specific settings. */
typedef struct t_xcp_loader_settings
{
/** \brief Command response timeout in milliseconds. */
uint16_t timeoutT1;
/** \brief Start programming timeout in milliseconds. */
uint16_t timeoutT3;
/** \brief Erase memory timeout in milliseonds. */
uint16_t timeoutT4;
/** \brief Program memory and reset timeout in milliseonds. */
uint16_t timeoutT5;
/** \brief Busy wait timer timeout in milliseonds. */
uint16_t timeoutT7;
/** \brief Pointer to the transport layer to use during protocol communications. */
tXcpTransport const * transport;
/** \brief Pointer to the settings for the transport layer. */
void const * transportSettings;
} tXcpLoaderSettings;
/****************************************************************************************
* Function prototypes
****************************************************************************************/
tSessionProtocol const * XcpLoaderGetProtocol(void);
#ifdef __cplusplus
}
#endif
#endif /* XCPLOADER_H */
/*********************************** end of xcploader.h ********************************/

View File

@ -0,0 +1,329 @@
/************************************************************************************//**
* \file xcptpuart.c
* \brief XCP UART transport layer source file.
* \ingroup XcpLoader
* \internal
*----------------------------------------------------------------------------------------
* C O P Y R I G H T
*----------------------------------------------------------------------------------------
* Copyright (c) 2017 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 have received a copy of the GNU General Public License along with OpenBLT. It
* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
*
* \endinternal
****************************************************************************************/
/****************************************************************************************
* Include files
****************************************************************************************/
#include <assert.h> /* for assertions */
#include <stdint.h> /* for standard integer types */
#include <stddef.h> /* for NULL declaration */
#include <stdbool.h> /* for boolean type */
#include <stdlib.h> /* for standard library */
#include <string.h> /* for string library */
#include "session.h" /* Communication session module */
#include "xcploader.h" /* XCP loader module */
#include "xcptpuart.h" /* XCP UART transport layer */
#include "util.h" /* Utility module */
#include "serialport.h" /* Serial port module */
/****************************************************************************************
* Function prototypes
****************************************************************************************/
static void XcpTpUartInit(void const * settings);
static void XcpTpUartTerminate(void);
static bool XcpTpUartConnect(void);
static void XcpTpUartDisconnect(void);
static bool XcpTpUartSendPacket(tXcpTransportPacket const * txPacket,
tXcpTransportPacket * rxPacket, uint16_t timeout);
/****************************************************************************************
* Local constant declarations
****************************************************************************************/
/** \brief XCP transport layer structure filled with UART specifics. */
static const tXcpTransport uartTransport =
{
XcpTpUartInit,
XcpTpUartTerminate,
XcpTpUartConnect,
XcpTpUartDisconnect,
XcpTpUartSendPacket
};
/****************************************************************************************
* Local data declarations
****************************************************************************************/
/** \brief The settings to use in this transport layer. */
static tXcpTpUartSettings tpUartSettings;
/***********************************************************************************//**
** \brief Obtains a pointer to the transport layer structure, so that it can be
** linked to the XCP protocol module.
** \return Pointer to transport layer structure.
**
****************************************************************************************/
tXcpTransport const * XcpTpUartGetTransport(void)
{
return &uartTransport;
} /*** end of XcpLoaderGetProtocol ***/
/************************************************************************************//**
** \brief Initializes the transport layer.
** \param settings Pointer to settings structure.
** \return None.
**
****************************************************************************************/
static void XcpTpUartInit(void const * settings)
{
char * uartPortName;
/* Reset transport layer settings. */
tpUartSettings.portname = NULL;
tpUartSettings.baudrate = 0;
/* Check parameters. */
assert(settings != NULL);
/* Only continue with valid parameters. */
if (settings != NULL) /*lint !e774 */
{
/* Shallow copy the transport layer settings for layer usage. */
tpUartSettings = *((tXcpTpUartSettings *)settings);
/* The portname is a pointer and it is not gauranteed that it stays valid so we need
* to deep copy this one. note the +1 for '\0' in malloc.
*/
assert(((tXcpTpUartSettings *)settings)->portname != NULL);
if (((tXcpTpUartSettings *)settings)->portname != NULL) /*lint !e774 */
{
uartPortName = malloc(strlen(((tXcpTpUartSettings *)settings)->portname) + 1);
assert(uartPortName != NULL);
if (uartPortName != NULL) /*lint !e774 */
{
strcpy(uartPortName, ((tXcpTpUartSettings *)settings)->portname);
tpUartSettings.portname = uartPortName;
}
}
}
/* Initialize the serial port. */
SerialPortInit();
} /*** end of XcpTpUartInit ***/
/************************************************************************************//**
** \brief Terminates the transport layer.
**
****************************************************************************************/
static void XcpTpUartTerminate(void)
{
/* Terminate the serial port. */
SerialPortTerminate();
/* Release memory that was allocated for storing the port name. */
if (tpUartSettings.portname != NULL)
{
free((char *)tpUartSettings.portname);
}
/* Reset transport layer settings. */
tpUartSettings.portname = NULL;
tpUartSettings.baudrate = 0;
} /*** end of XcpTpUartTerminate ***/
/************************************************************************************//**
** \brief Connects to the transport layer.
** \return True is connected, false otherwise.
**
****************************************************************************************/
static bool XcpTpUartConnect(void)
{
bool result = false;
bool baudrateSupported;
tSerialPortBaudrate baudrate;
/* Check if the specified baudrate is supported by the serial port driver. */
baudrateSupported = (tpUartSettings.baudrate == 9600) ||
(tpUartSettings.baudrate == 19200) ||
(tpUartSettings.baudrate == 38400) ||
(tpUartSettings.baudrate == 57600) ||
(tpUartSettings.baudrate == 115200);
/* Check transport layer settings. */
assert(tpUartSettings.portname != NULL);
assert(baudrateSupported);
/* Only continue if the transport layer settings are valid. */
if ( (tpUartSettings.portname != NULL) && (baudrateSupported) ) /*lint !e774 */
{
/* Convert the numeric baudrate to the one supported by the serial port driver. */
switch (tpUartSettings.baudrate)
{
case 115200:
baudrate = SERIALPORT_BR115200;
break;
case 57600:
baudrate = SERIALPORT_BR57600;
break;
case 38400:
baudrate = SERIALPORT_BR38400;
break;
case 19200:
baudrate = SERIALPORT_BR19200;
break;
case 9600:
default:
baudrate = SERIALPORT_BR9600;
break;
}
/* Connect to the serial port. */
result = SerialPortOpen(tpUartSettings.portname, baudrate);
}
/* Give the result back to the caller. */
return result;
} /*** end of XcpTpUartConnect ***/
/************************************************************************************//**
** \brief Disconnects from the transport layer.
**
****************************************************************************************/
static void XcpTpUartDisconnect(void)
{
/* Disconnect from the serial port. */
SerialPortClose();
} /*** end of XcpTpUartDisconnect ***/
/************************************************************************************//**
** \brief Transmits an XCP packet on the transport layer and attempts to receive the
** response packet within the specified timeout.
** \param txPacket Pointer to the packet to transmit.
** \param rxPacket Pointer where the received packet info is stored.
** \param timeout Maximum time in milliseconds to wait for the reception of the
** response packet.
** \return True is successful and a response packet was received, false otherwise.
**
****************************************************************************************/
static bool XcpTpUartSendPacket(tXcpTransportPacket const * txPacket,
tXcpTransportPacket * rxPacket, uint16_t timeout)
{
bool result = false;
uint16_t byteIdx;
/* uartBuffer is static to lower the stack load. +1 because the first byte for an XCP
* packet on the UART transport layer contains the packet lenght.
*/
static uint8_t uartBuffer[XCPLOADER_PACKET_SIZE_MAX + 1];
uint32_t responseTimeoutTime = 0;
bool packetReceptionComplete;
/* Check parameters. */
assert(txPacket != NULL);
assert(rxPacket != NULL);
/* Only continue with valid parameters. */
if ( (txPacket != NULL) && (rxPacket != NULL) ) /*lint !e774 */
{
/* Set result value to okay and only change it from now on if an error occurred. */
result = true;
/* Prepare the XCP packet for transmission on UART. This is basically the same as
* the XCP packet data but just the length of the packet is added to the first
* byte.
*/
uartBuffer[0] = txPacket->len;
for (byteIdx=0; byteIdx<txPacket->len; byteIdx++)
{
uartBuffer[byteIdx + 1] = txPacket->data[byteIdx];
}
/* Transmit the packet. */
if (!SerialPortWrite(uartBuffer, txPacket->len + 1))
{
result = false;
}
/* Only continue if the transmission was successful. */
if (result)
{
/* Determine timeout time for the response packet. */
responseTimeoutTime = UtilTimeGetSystemTimeMs() + timeout;
/* Initialize packet reception length. */
rxPacket->len = 0;
/* Poll with timeout detection to receive the first byte. This one contains the
* packet length and cannot be zero.
*/
while (UtilTimeGetSystemTimeMs() < responseTimeoutTime)
{
if (SerialPortRead(&rxPacket->len, 1))
{
/* Length received. Validate it before accepting it */
if (rxPacket->len > 0)
{
/* Start of packet received. Stop this loop to continue with the
* reception of the packet.
*/
break;
}
}
}
/* Check if a valid start of packet was received, in which case the first
* byte won't have a zero value.
*/
if (rxPacket->len == 0)
{
/* No valid start of packet received, so a timeout occurred. */
result = false;
}
}
/* Only continue with reception if a valid pacekt lenght was received. */
if (result)
{
/* Continue with reception of the packet. */
packetReceptionComplete = false;
byteIdx = 0;
/* Poll with timeout detection to receive the full packet. */
while (UtilTimeGetSystemTimeMs() < responseTimeoutTime)
{
/* Check if the next byte was received. */
if (SerialPortRead(&rxPacket->data[byteIdx], 1))
{
/* Check if the packet reception is now complete. */
if ((byteIdx + 1) == rxPacket->len)
{
/* Set flag and stop the loop. */
packetReceptionComplete = true;
break;
}
/* Increment indexer to the next byte. */
byteIdx++;
}
}
/* Check if a timeout occurred. */
if (!packetReceptionComplete)
{
result = false;
}
}
}
/* Give the result back to the caller. */
return result;
} /*** end of XcpTpUartSendPacket ***/
/*********************************** end of xcptpuart.c ********************************/

View File

@ -0,0 +1,58 @@
/************************************************************************************//**
* \file xcptpuart.h
* \brief XCP UART transport layer header file.
* \ingroup XcpLoader
* \internal
*----------------------------------------------------------------------------------------
* C O P Y R I G H T
*----------------------------------------------------------------------------------------
* Copyright (c) 2017 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 have received a copy of the GNU General Public License along with OpenBLT. It
* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
*
* \endinternal
****************************************************************************************/
#ifndef XCPTPUART_H
#define XCPTPUART_H
#ifdef __cplusplus
extern "C" {
#endif
/****************************************************************************************
* Type definitions
****************************************************************************************/
/** \brief Layout of structure with settings specific to the XCP transport layer module
* for UART.
*/
typedef struct t_xcp_tp_uart_settings
{
char const * portname; /**< Interface port name, i.e. /dev/ttyUSB0. */
uint32_t baudrate; /**< Communication speed in bits/sec. */
} tXcpTpUartSettings;
/***************************************************************************************
* Function prototypes
****************************************************************************************/
tXcpTransport const * XcpTpUartGetTransport(void);
#ifdef __cplusplus
}
#endif
#endif /* XCPTPUART_H */
/*********************************** end of xcptpuart.h ********************************/