From 36a87ec580afe8fb81d832124f5239129984c742 Mon Sep 17 00:00:00 2001 From: Frank Voorburg Date: Mon, 20 Feb 2017 19:59:57 +0000 Subject: [PATCH] Refs #154. Redesigned SerialBoot for improved run-time performance and modularity. git-svn-id: https://svn.code.sf.net/p/openblt/code/trunk@208 5dc33758-31d5-4daf-9ae8-b24bf3d40d73 --- Host/SerialBoot.exe | Bin 46592 -> 61440 bytes Host/Source/SerialBoot/CMakeLists.txt | 29 +- Host/Source/SerialBoot/firmware.c | 125 +++ .../SerialBoot/{srecord.h => firmware.h} | 159 ++-- Host/Source/SerialBoot/main.c | 695 ++++++++-------- .../Source/SerialBoot/port/linux/serialport.c | 208 +++++ Host/Source/SerialBoot/port/linux/timeutil.c | 138 ++-- .../SerialBoot/port/linux/xcptransport.c | 304 ------- .../SerialBoot/port/win32/xcptransport.c | 265 ------ .../SerialBoot/port/windows/serialport.c | 260 ++++++ .../port/{win32 => windows}/timeutil.c | 120 +-- .../SerialBoot/{xcpmaster.h => serialport.h} | 136 ++-- Host/Source/SerialBoot/srecord.c | 448 ----------- Host/Source/SerialBoot/srecparser.c | 751 +++++++++++++++++ .../{port/xcptransport.h => srecparser.h} | 103 +-- Host/Source/SerialBoot/{port => }/timeutil.h | 91 ++- Host/Source/SerialBoot/xcploader.c | 755 ++++++++++++++++++ Host/Source/SerialBoot/xcploader.h | 108 +++ Host/Source/SerialBoot/xcpmaster.c | 689 ---------------- Host/Source/SerialBoot/xcptpuart.c | 255 ++++++ .../SerialBoot/{sb_types.h => xcptpuart.h} | 131 +-- 21 files changed, 3303 insertions(+), 2467 deletions(-) create mode 100644 Host/Source/SerialBoot/firmware.c rename Host/Source/SerialBoot/{srecord.h => firmware.h} (52%) create mode 100644 Host/Source/SerialBoot/port/linux/serialport.c delete mode 100644 Host/Source/SerialBoot/port/linux/xcptransport.c delete mode 100644 Host/Source/SerialBoot/port/win32/xcptransport.c create mode 100644 Host/Source/SerialBoot/port/windows/serialport.c rename Host/Source/SerialBoot/port/{win32 => windows}/timeutil.c (82%) rename Host/Source/SerialBoot/{xcpmaster.h => serialport.h} (59%) delete mode 100644 Host/Source/SerialBoot/srecord.c create mode 100644 Host/Source/SerialBoot/srecparser.c rename Host/Source/SerialBoot/{port/xcptransport.h => srecparser.h} (69%) rename Host/Source/SerialBoot/{port => }/timeutil.h (76%) create mode 100644 Host/Source/SerialBoot/xcploader.c create mode 100644 Host/Source/SerialBoot/xcploader.h delete mode 100644 Host/Source/SerialBoot/xcpmaster.c create mode 100644 Host/Source/SerialBoot/xcptpuart.c rename Host/Source/SerialBoot/{sb_types.h => xcptpuart.h} (64%) diff --git a/Host/SerialBoot.exe b/Host/SerialBoot.exe index 20a4c7fe30e404443b6c784e3b89c983624fde4d..5d4e0a5450de0a752ad8e2d9ff06138b89d06984 100644 GIT binary patch literal 61440 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 EFOZD<18i&{W1JX#cxk`afv@rdeR> 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 R@laWC8~zP*;Ge{S{|}Y$$L0V4 literal 46592 zcmeHw3w+eYwf}6gfhBI(pov9=vM4Jk5O=ei$0pej9*a;}-8?~!geBRq33<5>9=)K% zP1JO7%W1$!&^1I(Nzu#^)3qI=g zb9?`{*?eYx^P4$y=FFKhXU?3N&Dw6;%;FhiN(514Y!9CFDd6#EM?EMWKjpdc?3r^gYNlA&*WYqe! z*WdQuvghe=SU=hM^cuXcpShT;{T;@8so`Py6_L zHGdY>RJsUPm~y+7u_cNz?Ck00W#POY7N@vGp=PWWIX6qW9pAt+8DSH>7f9(i#>UVq zKH(>03W-_Bi)RJR9FXc!W&VsjD3cvK!dM<9dhjGB$9@JF+mXPSwvDmu*s`eirtim$ z$zk9IDWCR9^E%ggQP@_4i0Goe#$oi24+8IA>iW z08df*0D=nPNrb3R0b}!`UPqIE2L}$)=TvtZIDDrb(TPcjreknVU7CdGky(iLQ0nw0 zh@K?4TdA~*qFbOjPPJ2NCza}_AUZc0QTKI-3h8wTm40{wqNh>7Tl*i4N`w7n!85Mp zUluSib={Ey=I>JGo)La(U<}!tW3s;^Wgm~pUMppn$7HXNvbE2Q#Jw2V%X9mMxp?03 za!hY!dg@~8q)MnxJUtTCc?=22+z|u)u9VGoj)XoeWiN`!epbrf9FzSRvWd)x@Ej%+ z^c9xvw+<26-PZH0+xiK@5c6+TDZOLUJ5J4m(&@H}iau4lRa7e4tfFR@P0Y2aG@)@Q z((Eb~_u$D^A7DYNI+(IqvsanuADr#GiQt~2qRx}NNZqE{n=--wag|T6*=0T7+ToiK z0XcFKmE%*|id@>~3z)DHa_8?-fgr`HM}Z*%w|XB7ma2p5cA!%DKc4Md3RL2=yp^|k zk@6nRUbV{q(Mn$)X#1q~sLuqB767a3-d`2~lMH_3Z6JzQ-%}{2HgPdgLrm_1;DQ5+ zzFB}90)^9JT8>w?+g*!@#Fu8vBn~M~ojfmsE7T=#GAex1`ifVD#)r_jGQFcOZiiwy ziDAF+b>I*F$1wK~9t8iJ`)7gvvZbLHj{(oKH=)0KXgE&)>(>5f3z+d&0qaokOf3rz ziK!bvYVMHmI{5RfmRS2Xi|@3Hsb1a%6}s>|iiER6qKNJl1+6N(a0Re}nVMY(T3_*L zgxXI;X~a$~#5xo_6HF!MNQ~!QbFm%6a+VB~E}#StsoSpXs4{A93CbjfJavwmQEGN| zfNxU)?}`GYIXD%dTvSdS!omcArWgPg)s8o+jN0i1yQOxvN$muzgZ_&Md~Z(lFVj`LW^Ss3DyV>J~&* zAnJCa0`I_54yly5Q40MH;3YA@Z3KMAWsk|e6WKz~MmTj zrU*a98^oYb0Qmhe;8UcA9*oIW5te-%%VA8JEYy4<2IN0x0>ljvp%PKhI%pR*N)1Up z`xlsQsMZxz?MYOFg!9n^%MU~q({%qX6{&6{jfC$K zV2~t$nzYA&EFq9LKSYzSA`03D3x!@JA{;phC539sVydM|4VK4bpNAbG1W{iaf*VkC zLk!4U1hSmkA|Y58)mGnnfVaeeKSAI(5IERH3al*(fTmp#0G#aE5-PxPMYkmeu9Dy& zm{Hlp@+HVNb`%8<*+Z!2dPcD<9NfY#mWIZd9iq0 z{*7w3W`$-~Qa{v<|C9pkHXi-(gSJvAwNer5Tasp10xuK7)-=?Aay*$E`7l>T^x{gg zKS9~dBY{#VeybR79fal6_s|Xn;6UcVX(L(sdGy|k!HM*n?E6R16Czpjt^1Gy+3$S@ z*}N=5wq{o<&v;Lf`|8H2L2ELIvlGFELI!xxJ3=cdvDe&pr3@hah!0g1>n9Uqz^0k| z0#>yPuqK^X4Ga0W~JyBDMmvf7l|xDc%#NgvPzkQY>9#%$CP{x~3tz#A+b(CoSg zE;0tQ{%d@TvHA!G9l7e{=8vd=Z;(Dhf^TzZ55o)nZ!3IbyAw`WErhBB_RM-_jdjmuQubuuvt(V(3trJ5

3IE0uQh5_EKQUYmo`!%+(w2`&8pb8W!?~sk!GsqM{iiHH zVWpEUY(*C6hdHU)bsra=qu$HIL;gxrW5(i(H3Jz}35(g#2VH&vU@0tcy zzK2|5Wl*HPb^#FbDUw_4Fw)VyBo*};^8@Nb&70mplJGNNa~-FV9gG>-^=MF*KFp_QDV0jFT=bVKzUg1hLDcsRfJ#3 zvix0Cmz+E5I*g&ORfI~<6$!uZj~ViX!js6N4%;yKFEZrFjUMvL<;fe5$=j|@ZsYnk z+@n3$phrLYI`zokm5jmv3(}E!)PYj$N4XpvMEXni=Qq*-O8rS3(H|_=>B1lT{+|B8 zxgm+LcN%E_1Dt+g+6~dPZ$N37_BNz1M!P&7&HX8mP4b8IlRw1DF5(Y?lwhAEuT^om zop)>G#VAU5T?2jN%H9JBUxp}J*ZmMw%EQ3ATT%zn%wax9J9}8WP1Sa90%di#zK@vo zY1$v41c@h4Xm;@e2&oD}ip48BH)vD0r%Y(OKjC9k>H8IDH4*FYh_i=6gtk!l!F#d{ zg%`&>p%z(z)&Ud;d92yh#+An_-YdgXF&Ls^&8`%M)W?wugk1~nSHPJ&y!Ut;Z_QoA zO9;~Acp*W;8&d(6D4`Zokd7V;=#MYP{{&jUh8LDwh}r$b?Br)hGW&Y89PUGR3+L=B z!>kQ))^;k|cp}0}j@>UPat{-Oqsw4*wW~2isUM*SeJ{xj=7va7sFk{97cx%8Xr(-1 z9I|8vKOpfjytH2#mV_|pBdhxe4P7-I3_gElG=n!?6~*BBcp(Od7So9ls{?qL$Lo-e z<}t~6`19Xc|BhU+{?Q)*RE$`I=xvcAmvHv`<= zas_c$UjM*pdHqA~uuks+U}XJ6I+m~CCyX9$RKbUGGggkyQxj$Ji-#fIriPiM>J*as zsB*p*UBe!tlC(3UAF_)Mu>wPv9lI?z6N4 zM$Iu4sgWi>W9$(v_(kWZ$FYb*i-D|iP8NAe9Y93~h_~Vy(O#UtpKq_h3D2=Di*)ib zBFv`VKUWDBlP=vK2aAN<0Q(DQa|5>1It{j~ii9n16OY55@kN^5wlk;^{|yzu1B+C^ zgKcu|1P{H#4iBi{G)IdAp(V-WJ<0usa?J$IZYxd#20|qYY9wG+_B}#J11b#BFjX5b zV@xtYr-7G^6Fg~HqfUMjox#z}1|`r`WT z4=a?_h-&&f;{rSp zZss{cLg+Q8t=#9-qq)qzkia{Df=4n9DMYX3e(b$}-|yIUy-BxrWuN6@+Z zHqH*VN)7Lk*sR&jtD|wUKzJE;2?3tyd*alKV9KX-bFGBn^Z9YJ+|n-a1M1|n`7t#N ze4z7f)#tJ#JT`q8HttX)*^8I>U8)Y;!?`%JQ|K_~;wdGtR|ncT7imPpT;%+y_IHAd zJPEdQF2XCgyNz@42)HNG=^&(hFHdL<}Ak`-^UZ2O%b7oKyuy-3Fv^VB8*36X(b8f zgHY}70PlHnSUNSk@8P^Z0N!&>77Ay-)eV*gx@;0WgJo)Xm3@Or!;o-(gFPWJD3jW_<}9DXH?=XeF{% z(mDY8ah`x1H-q#RIY~K3t1ZobE7TU$^aDTx217OvR|iUmuyzf>-*65tVB0x#n})R% ziye%X)eiDE3-vgkq`@I#`3Lkz-4_!1eIYso`h>0qeF7Rk@qZMz z@n1m8Cm;`3agt+yvuxJfb$TqK0ZEfP~#@I{*Z|3U5A zfLp=(9>d)q@KJ}XC@#v(9DR&(;C~qhFh836?}b93{Sr;5XRpD_1qLTPPsoPB8GTl> z-`c@5UkTW{0=5GI+rfbCaKLsfU^^a6?Zre1Jg^QJtG5bBW0~22m)e|K77E>kRH2Xu z)quk&Og`BBwYi~Ig2v2R6q$T~gd?7=!nrn~q1t#l`E?=H5eg9~EO~agfMJsE0^GJ9 zwBol=EOJXX6KWeI!pQ|3q0)|`tyBj56QxScsDzoV77~6Zim;5wkm-Qs)YjE)J&L=C z$Dr(f3w>~)`J@O-KTvugXg#14u~-GH2ZFW(&2NjpLD~j$@__&3Z~U(&6Udp6wZk4v zqNYIKB&n&(!%aPOj5qaT&?K`I2bXxkn^46cXQa0QdLy!XBV=nOT(82S2ifCnt& zB4{PL`OTw9!zmK*BVpjF60i=;P9@r)8^3q;o^&<-ov~#_0C2g?!Ls#559iRf^cp;_AGR2STf}!d6{`w7u4L6v7X?IG|p|? zt?IUW2428*N|^1oo<4PTu(U@q*h_n`y!K$}qBEzKy-~0jU^c^Lkqa$PN zJWmw52v3A$W@L zec+-KOxziesh8U7$9}E1&_%_Orc_c>$1%D%lg5F1f3CIHcPS1+2(0y$yT-~w#PN+6 zJZLl5ddy8L>4v_Ca703IfzsZv1=ZX+053k~C$F$Hnt;-NTsrFo5yuN-+ovrf+P@T+ z(&Fg|{x~R|Y3mQzdgXS{9T{#{*|#k$Ko90afS!kRkO29+W

fQriu*-cweJ_y-B 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 diff --git a/Host/Source/SerialBoot/CMakeLists.txt b/Host/Source/SerialBoot/CMakeLists.txt index 2d1305e2..7aea5017 100644 --- a/Host/Source/SerialBoot/CMakeLists.txt +++ b/Host/Source/SerialBoot/CMakeLists.txt @@ -6,7 +6,7 @@ #---------------------------------------------------------------------------------------- # C O P Y R I G H T #---------------------------------------------------------------------------------------- -# Copyright (c) 2014 by Feaser http://www.feaser.com All rights reserved +# Copyright (c) 2017 by Feaser http://www.feaser.com All rights reserved # #---------------------------------------------------------------------------------------- # L I C E N S E @@ -34,7 +34,7 @@ project(SerialBoot) # Set the port directory, which is platform specific IF(WIN32) - set(PROJECT_PORT_DIR ${PROJECT_SOURCE_DIR}/port/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) @@ -45,7 +45,22 @@ ENDIF(WIN32) set(CMAKE_BUILD_TYPE "Debug") # Set include directories -include_directories("${PROJECT_SOURCE_DIR}" "${PROJECT_PORT_DIR}" "${PROJECT_SOURCE_DIR}/port") +include_directories("${PROJECT_SOURCE_DIR}" "${PROJECT_PORT_DIR}") + +# 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 ) # Get header files file(GLOB_RECURSE INCS "*.h") @@ -53,10 +68,12 @@ file(GLOB_RECURSE INCS "*.h") # Add sources add_executable( SerialBoot + firmware.c main.c - xcpmaster.c - srecord.c - ${PROJECT_PORT_DIR}/xcptransport.c + srecparser.c + xcploader.c + xcptpuart.c + ${PROJECT_PORT_DIR}/serialport.c ${PROJECT_PORT_DIR}/timeutil.c ${INCS} ) diff --git a/Host/Source/SerialBoot/firmware.c b/Host/Source/SerialBoot/firmware.c new file mode 100644 index 00000000..1d4e095c --- /dev/null +++ b/Host/Source/SerialBoot/firmware.c @@ -0,0 +1,125 @@ +/************************************************************************************//** +* \file firmware.c +* \brief Firmware module source file. +* \ingroup SerialBoot +* \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 /* for NULL declaration */ +#include /* for assertions */ +#include "firmware.h" /* firmware module */ + + +/**************************************************************************************** +* Local data declarations +****************************************************************************************/ +/** \brief Pointer to the firmware parser that is linked. */ +static tFirmwareParser const * parserPtr = NULL; + + +/************************************************************************************//** +** \brief Initializes the firmware module. +** \param parser Pointer to the firmware parser to link. +** \return None. +** +****************************************************************************************/ +void FirmwareInit(tFirmwareParser const * const parser) +{ + /* verify parameters */ + assert(parser != NULL); + + /* link the firmware parser */ + parserPtr = parser; + /* initialize the firmware parser */ + parserPtr->Init(); +} /*** end of FirmwareInit ***/ + + +/************************************************************************************//** +** \brief Uninitializes the firmware module. +** \return None. +** +****************************************************************************************/ +void FirmwareDeinit(void) +{ + /* make sure the parser is linked */ + assert(parserPtr != NULL); + + /* uninitialize the parser */ + parserPtr->Deinit(); + /* unlink the parser */ + parserPtr = NULL; +} /*** end of FirmwareDeinit ***/ + + +/************************************************************************************//** +** \brief Loads the firmware data from the specified firmware file, using the linked +** parser. +** \return True is successful, false otherwise. +** +****************************************************************************************/ +bool FirmwareLoadFromFile(char *firmwareFile) +{ + /* make sure the parser is linked */ + assert(parserPtr != NULL); + /* make sure the filename is valid */ + assert(firmwareFile != NULL); + + return parserPtr->LoadFromFile(firmwareFile); +} /*** end of FirmwareLoadFromFile ***/ + + +/************************************************************************************//** +** \brief Returns the number of firmware segments that were loaded by the parser. +** \return Number of firmware segments. +** +****************************************************************************************/ +uint32_t FirmwareGetSegmentCount(void) +{ + /* make sure the parser is linked */ + assert(parserPtr != NULL); + + return parserPtr->GetSegmentCount(); +} /*** end of FirmwareGetSegmentCount ***/ + + +/************************************************************************************//** +** \brief Obtains a pointer to the firmware segment at the specified index. +** \return Pointer to firmware segment if successful, NULL otherwise. +** +****************************************************************************************/ +const tFirmwareSegment *FirmwareGetSegment(uint32_t segmentIdx) +{ + /* make sure the parser is linked */ + assert(parserPtr != NULL); + + return parserPtr->GetSegment(segmentIdx); +} /*** end of FirmwareGetSegment ***/ + + +/*********************************** end of firmware.c *********************************/ + diff --git a/Host/Source/SerialBoot/srecord.h b/Host/Source/SerialBoot/firmware.h similarity index 52% rename from Host/Source/SerialBoot/srecord.h rename to Host/Source/SerialBoot/firmware.h index 7c4fcfb5..a6ff7652 100644 --- a/Host/Source/SerialBoot/srecord.h +++ b/Host/Source/SerialBoot/firmware.h @@ -1,75 +1,84 @@ -/************************************************************************************//** -* \file srecord.h -* \brief Motorola S-record library header file. -* \ingroup SerialBoot -* \internal -*---------------------------------------------------------------------------------------- -* C O P Y R I G H T -*---------------------------------------------------------------------------------------- -* Copyright (c) 2014 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 SRECORD_H -#define SRECORD_H - - -/**************************************************************************************** -* Macro definitions -****************************************************************************************/ -/** \brief Maximum number of characters that can be on a line in the firmware file. */ -#define SRECORD_MAX_CHARS_PER_LINE (512) - -/** \brief Maximum number of data bytes that can be on a line in the firmware file - * (S-record). - */ -#define SRECORD_MAX_DATA_BYTES_PER_LINE (SRECORD_MAX_CHARS_PER_LINE/2) - - -/**************************************************************************************** -* Type definitions -****************************************************************************************/ -/** \brief Structure type for grouping the parsing results of an S-record file. */ -typedef struct -{ - sb_uint32 address_low; /**< lowest memory address */ - sb_uint32 address_high; /**< lowest memory address */ - sb_uint32 data_bytes_total; /**< total number of data bytes */ -} tSrecordParseResults; - -/** \brief Structure type for grouping the parsing results of an S-record line. */ -typedef struct -{ - sb_uint8 data[SRECORD_MAX_DATA_BYTES_PER_LINE]; /**< array for S1,S2 or S3 data bytes*/ - sb_uint32 address; /**< address on S1,S2 or S3 line */ - sb_uint16 length; /**< number of bytes written to array */ -} tSrecordLineParseResults; - - -/**************************************************************************************** -* Function prototypes -****************************************************************************************/ -sb_uint8 SrecordIsValid(const sb_char *srecordFile); -sb_file SrecordOpen(const sb_char *srecordFile); -void SrecordParse(sb_file srecordHandle, tSrecordParseResults *parseResults); -void SrecordClose(sb_file srecordHandle); -sb_uint8 SrecordParseNextDataLine(sb_file srecordHandle, tSrecordLineParseResults *parseResults); - - -#endif /* SRECORD_H */ -/*********************************** end of srecord.h **********************************/ +/************************************************************************************//** +* \file firmware.h +* \brief Firmware module header file. +* \ingroup SerialBoot +* \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 FIRMWARE_H +#define FIRMWARE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/**************************************************************************************** +* Include files +****************************************************************************************/ +#include /* for standard integer types */ +#include /* for boolean type */ + + +/**************************************************************************************** +* Type definitions +****************************************************************************************/ +/** \brief Groups information together of a firmware segments. */ +typedef struct t_firmware_segment +{ + uint32_t base; /**< Start memory address of the segment. */ + uint32_t length; /**< Number of data bytes in the segment. */ + uint8_t *data; /**< Pointer to array with the segment's data bytes. */ +} tFirmwareSegment; + +/** \brief Firmware file parser. */ +typedef struct t_firmware_parser +{ + /** \brief Initialization of the file parser. */ + void (*Init) (void); + /** \brief Uninitializes the file parser. */ + void (*Deinit) (void); + /** \brief Extract the firmware segments from the firmware file. */ + bool (*LoadFromFile) (char *firmwareFile); + /** \brief Obtains the number of segments. */ + uint32_t (*GetSegmentCount) (void); + /** \brief Obtains a segment. */ + const tFirmwareSegment * (*GetSegment) (uint32_t segmentIdx); +} tFirmwareParser; + + +/**************************************************************************************** +* Function prototypes +****************************************************************************************/ +void FirmwareInit(tFirmwareParser const * const parser); +void FirmwareDeinit(void); +bool FirmwareLoadFromFile(char *firmwareFile); +uint32_t FirmwareGetSegmentCount(void); +const tFirmwareSegment *FirmwareGetSegment(uint32_t segmentIdx); + +#ifdef __cplusplus +} +#endif + +#endif /* FIRMWARE_H */ +/********************************* end of firmware.h ***********************************/ + diff --git a/Host/Source/SerialBoot/main.c b/Host/Source/SerialBoot/main.c index 3fde7457..fa1d9b89 100644 --- a/Host/Source/SerialBoot/main.c +++ b/Host/Source/SerialBoot/main.c @@ -1,330 +1,365 @@ -/************************************************************************************//** -* \file main.c -* \brief SerialBoot command line demonstration program for OpenBLT. -* \ingroup SerialBoot -* \internal -*---------------------------------------------------------------------------------------- -* C O P Y R I G H T -*---------------------------------------------------------------------------------------- -* Copyright (c) 2014 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 /* assertion module */ -#include /* C types */ -#include /* standard I/O library */ -#include /* string library */ -#include "xcpmaster.h" /* XCP master protocol module */ -#include "srecord.h" /* S-record file handling */ -#include "timeutil.h" /* time utility module */ - - -/**************************************************************************************** -* Function prototypes -****************************************************************************************/ -static void DisplayProgramInfo(void); -static void DisplayProgramUsage(void); -static sb_uint8 ParseCommandLine(sb_int32 argc, sb_char *argv[]); - - -/**************************************************************************************** -* Macro definitions -****************************************************************************************/ -/** \brief Program return code if all went ok. */ -#define PROG_RESULT_OK (0) - -/** \brief Program return code if an error occurred. */ -#define PROG_RESULT_ERROR (1) - - -/**************************************************************************************** -* Local data declarations -****************************************************************************************/ -/** \brief Name of the serial device, such as COM4 or /dev/ttyUSB0. */ -static sb_char serialDeviceName[32]; - -/** \brief Serial communication speed in bits per second. */ -static sb_uint32 serialBaudrate; - -/** \brief Name of the S-record file. */ -static sb_char srecordFileName[128]; - - -/************************************************************************************//** -** \brief Program entry point. -** \param argc Number of program parameters. -** \param argv array to program parameter strings. -** \return 0 on success, > 0 on error. -** -****************************************************************************************/ -sb_int32 main(sb_int32 argc, sb_char *argv[]) -{ - sb_file hSrecord; - tSrecordParseResults fileParseResults; - tSrecordLineParseResults lineParseResults; - - /* disable buffering for the standard output to make sure printf does not wait until - * a newline character is detected before outputting text on the console. - */ - setbuf(stdout, SB_NULL); - - /* inform user about the program */ - DisplayProgramInfo(); - - /* start out by making sure program was started with the correct parameters */ - if (ParseCommandLine(argc, argv) == SB_FALSE) - { - /* parameters invalid. inform user about how this program works */ - DisplayProgramUsage(); - return PROG_RESULT_ERROR; - } - - /* -------------------- start the firmware update procedure ------------------------ */ - printf("Starting firmware update for \"%s\" using %s @ %u bits/s\n", srecordFileName, serialDeviceName, serialBaudrate); - - /* -------------------- validating the S-record file ------------------------------- */ - printf("Checking formatting of S-record file \"%s\"...", srecordFileName); - if (SrecordIsValid(srecordFileName) == SB_FALSE) - { - printf("ERROR\n"); - return PROG_RESULT_ERROR; - } - printf("OK\n"); - - /* -------------------- opening the S-record file ---------------------------------- */ - printf("Opening S-record file \"%s\"...", srecordFileName); - if ((hSrecord = SrecordOpen(srecordFileName)) == SB_NULL) - { - printf("ERROR\n"); - return PROG_RESULT_ERROR; - } - printf("OK\n"); - - /* -------------------- parsing the S-record file ---------------------------------- */ - printf("Parsing S-record file \"%s\"...", srecordFileName); - SrecordParse(hSrecord, &fileParseResults); - printf("OK\n"); - printf("-> Lowest memory address: 0x%08x\n", fileParseResults.address_low); - printf("-> Highest memory address: 0x%08x\n", fileParseResults.address_high); - printf("-> Total data bytes: %u\n", fileParseResults.data_bytes_total); - - /* -------------------- Open the serial port --------------------------------------- */ - printf("Opening serial port %s...", serialDeviceName); - if (XcpMasterInit(serialDeviceName, serialBaudrate) == SB_FALSE) - { - printf("ERROR\n"); - SrecordClose(hSrecord); - return PROG_RESULT_ERROR; - } - printf("OK\n"); - - /* -------------------- Connect to XCP slave --------------------------------------- */ - printf("Connecting to bootloader..."); - if (XcpMasterConnect() == SB_FALSE) - { - /* no response. prompt the user to reset the system */ - printf("TIMEOUT\nReset your microcontroller..."); - } - /* now keep retrying until we get a response */ - while (XcpMasterConnect() == SB_FALSE) - { - /* delay a bit to not pump up the CPU load */ - TimeUtilDelayMs(20); - } - printf("OK\n"); - - /* -------------------- Prepare the programming session ---------------------------- */ - printf("Initializing programming session..."); - if (XcpMasterStartProgrammingSession() == SB_FALSE) - { - printf("ERROR\n"); - XcpMasterDisconnect(); - XcpMasterDeinit(); - SrecordClose(hSrecord); - return PROG_RESULT_ERROR; - } - printf("OK\n"); - - /* -------------------- Erase memory ----------------------------------------------- */ - printf("Erasing %u bytes starting at 0x%08x...", fileParseResults.data_bytes_total, fileParseResults.address_low); - if (XcpMasterClearMemory(fileParseResults.address_low, (fileParseResults.address_high - fileParseResults.address_low)) == SB_FALSE) - { - printf("ERROR\n"); - XcpMasterDisconnect(); - XcpMasterDeinit(); - SrecordClose(hSrecord); - return PROG_RESULT_ERROR; - } - printf("OK\n"); - - /* -------------------- Program data ----------------------------------------------- */ - printf("Programming data. Please wait..."); - /* loop through all S-records with program data */ - while (SrecordParseNextDataLine(hSrecord, &lineParseResults) == SB_TRUE) - { - if (XcpMasterProgramData(lineParseResults.address, lineParseResults.length, lineParseResults.data) == SB_FALSE) - { - printf("ERROR\n"); - XcpMasterDisconnect(); - XcpMasterDeinit(); - SrecordClose(hSrecord); - return PROG_RESULT_ERROR; - } - } - printf("OK\n"); - - /* -------------------- Stop the programming session ------------------------------- */ - printf("Finishing programming session..."); - if (XcpMasterStopProgrammingSession() == SB_FALSE) - { - printf("ERROR\n"); - XcpMasterDisconnect(); - XcpMasterDeinit(); - SrecordClose(hSrecord); - return PROG_RESULT_ERROR; - } - printf("OK\n"); - - /* -------------------- Disconnect from XCP slave and perform software reset ------- */ - printf("Performing software reset..."); - if (XcpMasterDisconnect() == SB_FALSE) - { - printf("ERROR\n"); - XcpMasterDeinit(); - SrecordClose(hSrecord); - return PROG_RESULT_ERROR; - } - printf("OK\n"); - - /* -------------------- close the serial port -------------------------------------- */ - XcpMasterDeinit(); - printf("Closed serial port %s\n", serialDeviceName); - - /* -------------------- close the S-record file ------------------------------------ */ - SrecordClose(hSrecord); - printf("Closed S-record file \"%s\"\n", srecordFileName); - - /* all done */ - printf("Firmware successfully updated!\n"); - return PROG_RESULT_OK; -} /*** end of main ***/ - - -/************************************************************************************//** -** \brief Outputs information to the user about this program. -** \return none. -** -****************************************************************************************/ -static void DisplayProgramInfo(void) -{ - printf("-------------------------------------------------------------------------\n"); - printf("SerialBoot version 1.00. Performs firmware updates via the serial port\n"); - printf("for a microcontroller based system that runs the OpenBLT bootloader.\n\n"); - printf("Copyright (c) by Feaser http://www.feaser.com\n"); - printf("-------------------------------------------------------------------------\n"); -} /*** end of DisplayProgramInfo ***/ - - -/************************************************************************************//** -** \brief Outputs information to the user about how to use this program. -** \return none. -** -****************************************************************************************/ -static void DisplayProgramUsage(void) -{ - printf("Usage: SerialBoot -d[device] -b[baudrate] [s-record file]\n\n"); -#ifdef PLATFORM_WIN32 - printf("Example: SerialBoot -dCOM4 -b57600 myfirmware.s19\n"); - printf(" -> Connects to COM4, configures a communication speed of 57600\n"); -#else - printf("Example: SerialBoot -d/dev/ttyS0 -b57600 myfirmware.s19\n"); - printf(" -> Connects to ttyS0, configures a communication speed of 57600\n"); -#endif - printf(" bits/second and programs the myfirmware.s19 file in non-\n"); - printf(" volatile memory of the microcontroller using OpenBLT.\n"); - printf("-------------------------------------------------------------------------\n"); -} /*** end of DisplayProgramUsage ***/ - - -/************************************************************************************//** -** \brief Parses the command line arguments. A fixed amount of arguments is expected. -** The program should be called as: -** SerialBoot -d[device] -b[baudrate] [s-record file] -** \param argc Number of program parameters. -** \param argv array to program parameter strings. -** \return SB_TRUE on success, SB_FALSE otherwise. -** -****************************************************************************************/ -static sb_uint8 ParseCommandLine(sb_int32 argc, sb_char *argv[]) -{ - sb_uint8 paramIdx; - sb_uint8 paramDfound = SB_FALSE; - sb_uint8 paramBfound = SB_FALSE; - sb_uint8 srecordfound = SB_FALSE; - - /* make sure the right amount of arguments are given */ - if (argc != 4) - { - return SB_FALSE; - } - - /* loop through all the command lina parameters, just skip the 1st one because this - * is the name of the program, which we are not interested in. - */ - for (paramIdx=1; paramIdx /* standard I/O functions */ +#include /* for string library */ +#include "xcploader.h" /* XCP loader module */ +#include "xcptpuart.h" /* XCP transport layer for UART */ +#include "firmware.h" /* Firmware module */ +#include "srecparser.h" /* S-record parser */ +#include "timeutil.h" /* for time utilities module */ + + +/**************************************************************************************** +* Macro definitions +****************************************************************************************/ +/* Program return codes. */ +#define RESULT_OK (0) +#define RESULT_COMMANDLINE_ERROR (1) +#define RESULT_FIRMWARE_LOAD_ERROR (2) +#define RESULT_PROGRAM_START_ERROR (3) +#define RESULT_MEMORY_ERASE_ERROR (4) +#define RESULT_PROGRAM_STOP_ERROR (5) +#define RESULT_MEMORY_PROGRAM_ERROR (6) + + +/**************************************************************************************** +* Local data declarations +****************************************************************************************/ +/** \brief The firmware filename that is specified at the command line. */ +static char *firmwareFilename; + +/** \brief XCP loader settings. */ +static tXcpSettings xcpSettings = +{ + .timeoutT1 = 1000, + .timeoutT3 = 2000, + .timeoutT4 = 10000, + .timeoutT5 = 1000, + .timeoutT7 = 2000 +}; + +/** \brief XCP UART transport layer settings. */ +static tXcpTpUartSettings xcpTpUartSettings = +{ + .baudrate = SERIALPORT_BR57600, + .portname = "/dev/ttyS0" +}; + + +/**************************************************************************************** +* Function prototypes +****************************************************************************************/ +static void DisplayProgramInfo(void); +static void DisplayProgramUsage(void); +static bool ParseCommandLine(int argc, char *argv[]); + + +/************************************************************************************//** +** \brief This is the program entry point. +** \param argc Number of program arguments. +** \param argv Array with program arguments. +** \return Program return code. 0 for success, error code otherwise. +** +****************************************************************************************/ +int main(int argc, char *argv[]) +{ + int result = RESULT_OK; + uint32_t fwBaseAddress; + uint32_t fwTotalSize; + uint32_t segmentIdx; + const tFirmwareSegment *segment; + + /* -------------------- Display info ----------------------------------------------- */ + /* inform user about the program */ + DisplayProgramInfo(); + + /* -------------------- Process command line --------------------------------------- */ + /* start out by making sure program was started with the correct parameters */ + if (!ParseCommandLine(argc, argv)) + { + /* parameters invalid. inform user about how this program works */ + DisplayProgramUsage(); + return RESULT_COMMANDLINE_ERROR; + } + + /* -------------------- Initialization --------------------------------------------- */ + /* initialize the XCP loader module using the UART transport layer. */ + XcpLoaderInit(&xcpSettings, XcpTpUartGetTransport(), &xcpTpUartSettings); + /* initialize the firmware module and link the S-recorder parser */ + FirmwareInit(SRecParserGetParser()); + + /* -------------------- Parse the firmware file ------------------------------------ */ + /* attempt to load the firmware file */ + printf("Loading firmware file..."); fflush(stdout); + if (!FirmwareLoadFromFile(firmwareFilename)) + { + /* set error code and abort */ + printf("ERROR\n"); + result = RESULT_FIRMWARE_LOAD_ERROR; + goto finish; + } + printf("OK\n"); + /* determine firmware base address and total size */ + for (segmentIdx=0; segmentIdxbase; + fwTotalSize = segment->length; + } + else + { + /* update */ + if (segment->base < fwBaseAddress) + { + fwBaseAddress = segment->base; + } + fwTotalSize += segment->length; + } + } + /* display some firmware statistics */ + printf("-> Number of segments: %u\n", FirmwareGetSegmentCount()); + printf("-> Base memory address: 0x%08x\n", fwBaseAddress); + printf("-> Total data bytes: %u\n", fwTotalSize); + + /* -------------------- Connect to target ------------------------------------------ */ + printf("Connecting to bootloader..."); fflush(stdout); + if (!XcpLoaderConnect()) + { + /* no response. prompt the user to reset the system */ + printf("TIMEOUT\nReset your microcontroller..."); fflush(stdout); + /* now keep retrying until we get a response */ + while (!XcpLoaderConnect()) + { + /* delay a bit to not pump up the CPU load */ + TimeUtilDelayMs(20); + } + } + printf("OK\n"); + + /* -------------------- Start the programming session ------------------------------ */ + /* attempt to start the programming session */ + printf("Starting programming session..."); fflush(stdout); + if (!XcpLoaderStartProgrammingSession()) + { + /* set error code and abort */ + printf("ERROR\n"); + result = RESULT_PROGRAM_START_ERROR; + goto finish; + } + printf("OK\n"); + + /* -------------------- Erase memory ----------------------------------------------- */ + /* erase each segment one at a time */ + for (segmentIdx=0; segmentIdxlength, segment->base); fflush(stdout); + if (!XcpLoaderClearMemory(segment->base, segment->length)) + { + /* set error code and abort */ + printf("ERROR\n"); + result = RESULT_MEMORY_ERASE_ERROR; + goto finish; + } + printf("OK\n"); + } + + /* -------------------- Program data ----------------------------------------------- */ + /* program each segment one at a time */ + for (segmentIdx=0; segmentIdxlength, segment->base); fflush(stdout); + if (!XcpLoaderProgramData(segment->base, segment->length, segment->data)) + { + /* set error code and abort */ + printf("ERROR\n"); + result = RESULT_MEMORY_PROGRAM_ERROR; + goto finish; + } + printf("OK\n"); + } + + /* -------------------- Stop the programming session ------------------------------- */ + /* attempt to stop the programming session */ + printf("Finishing programming session..."); fflush(stdout); + if (!XcpLoaderStopProgrammingSession()) + { + /* set error code and abort */ + printf("ERROR\n"); + result = RESULT_PROGRAM_STOP_ERROR; + goto finish; + } + printf("OK\n"); + + /* -------------------- Cleanup ---------------------------------------------------- */ +finish: + /* uninitialize the firmware module */ + FirmwareDeinit(); + /* uninitialize the XCP loader module. note that this automatically disconnects the + * slave, if connected, by requesting it to perform a reset. + */ + XcpLoaderDeinit(); + /* give result back */ + return result; +} /*** end of main ***/ + + +/************************************************************************************//** +** \brief Outputs information to the user about this program. +** \return none. +** +****************************************************************************************/ +static void DisplayProgramInfo(void) +{ + printf("-------------------------------------------------------------------------\n"); + printf("SerialBoot version 2.00. Performs firmware updates via the serial port\n"); + printf("for a microcontroller based system that runs the OpenBLT bootloader.\n\n"); + printf("Copyright (c) by Feaser http://www.feaser.com\n"); + printf("-------------------------------------------------------------------------\n"); +} /*** end of DisplayProgramInfo ***/ + + +/************************************************************************************//** +** \brief Outputs information to the user about how to use this program. +** \return none. +** +****************************************************************************************/ +static void DisplayProgramUsage(void) +{ + printf("Usage: SerialBoot -d[device] -b[baudrate] [s-record file]\n\n"); +#ifdef PLATFORM_WIN32 + printf("Example: SerialBoot -dCOM4 -b57600 myfirmware.s19\n"); + printf(" -> Connects to COM4, configures a communication speed of 57600\n"); +#else + printf("Example: SerialBoot -d/dev/ttyS0 -b57600 myfirmware.s19\n"); + printf(" -> Connects to ttyS0, configures a communication speed of 57600\n"); +#endif + printf(" bits/second and programs the myfirmware.s19 file in non-\n"); + printf(" volatile memory of the microcontroller using OpenBLT.\n"); + printf(" Supported baudrates are: 9600, 19200, 38400, 57600 and\n"); + printf(" 115200 bits/second.\n"); + printf("-------------------------------------------------------------------------\n"); +} /*** end of DisplayProgramUsage ***/ + + +/************************************************************************************//** +** \brief Parses the command line arguments. A fixed amount of arguments is expected. +** The program should be called as: +** SerialBoot -d[device] -b[baudrate] [s-record file] +** \param argc Number of program parameters. +** \param argv array to program parameter strings. +** \return True if successful, false otherwise. +** +****************************************************************************************/ +static bool ParseCommandLine(int argc, char *argv[]) +{ + uint8_t paramIdx; + bool firmwareFileFound = false; + uint32_t baudrateValue; + + /* make sure that enough arguments were specified. this program needs at least 2. the + * first one is always the program name and the second one is the s-record file. + */ + if (argc < 2) + { + return false; + } + + /* loop through all the command line parameters, just skip the 1st one because this + * is the name of the program, which we are not interested in. + */ + for (paramIdx=1; paramIdx /* for NULL declaration */ +#include /* for assertions */ +#include /* UNIX standard functions */ +#include /* POSIX terminal control */ +#include /* file control definitions */ +#include /* 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 +****************************************************************************************/ +static int32_t portHandle = SERIALPORT_INVALID_HANDLE; + + +/**************************************************************************************** +* 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 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 *portname, tSerialPortBaudrate baudrate) +{ + struct termios options; + int32_t iFlags; + + /* check parameters */ + assert(portname != NULL); + + /* open the port */ + portHandle = open(portname, O_RDWR | O_NOCTTY | O_NDELAY); + /* check the result */ + if (portHandle == SERIALPORT_INVALID_HANDLE) + { + return false; + } + /* configure the device to block during read operations */ + if (fcntl(portHandle, F_SETFL, 0) == -1) + { + SerialPortClose(); + return false; + } + /* get the current options for the port */ + if (tcgetattr(portHandle, &options) == -1) + { + SerialPortClose(); + return false; + } + /* configure the baudrate */ + if (cfsetispeed(&options, baudrateLookup[baudrate]) == -1) + { + SerialPortClose(); + return false; + } + if (cfsetospeed(&options, baudrateLookup[baudrate]) == -1) + { + SerialPortClose(); + return false; + } + + /* 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(); + return false; + } + /* turn on DTR */ + iFlags = TIOCM_DTR; + ioctl(portHandle, TIOCMBIS, &iFlags); + /* success */ + return true; +} /*** end of SerialPortOpen ***/ + + +/************************************************************************************//** +** \brief Closes the connection with the serial port. +** \return None. +** +****************************************************************************************/ +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 *data, uint32_t length) +{ + size_t bytesWritten; + + /* check parameters */ + assert(data != NULL); + assert(length > 0); + + /* submit the data for sending */ + bytesWritten = write(portHandle, data, length); + /* check and return the result */ + return (bytesWritten == length); +} /*** 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) +{ + size_t bytesRead; + + /* check parameters */ + assert(data != NULL); + assert(length > 0); + + /* attempt to read the requested data */ + bytesRead = read(portHandle, data, length); + /* check and return the result */ + return (bytesRead == length); +} /*** end of SerialPortRead ***/ + + +/*********************************** end of serialport.c *******************************/ + diff --git a/Host/Source/SerialBoot/port/linux/timeutil.c b/Host/Source/SerialBoot/port/linux/timeutil.c index 79a6db15..7b0d2baa 100644 --- a/Host/Source/SerialBoot/port/linux/timeutil.c +++ b/Host/Source/SerialBoot/port/linux/timeutil.c @@ -1,69 +1,69 @@ -/************************************************************************************//** -* \file port\linux\timeutil.c -* \brief Time utility source file. -* \ingroup SerialBoot -* \internal -*---------------------------------------------------------------------------------------- -* C O P Y R I G H T -*---------------------------------------------------------------------------------------- -* Copyright (c) 2014 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 /* assertion module */ -#include /* C types */ -#include /* UNIX standard functions */ -#include /* file control definitions */ -#include /* time definitions */ - - -/************************************************************************************//** -** \brief Get the system time in milliseconds. -** \return Time in milliseconds. -** -****************************************************************************************/ -sb_uint32 TimeUtilGetSystemTimeMs(void) -{ - struct timeval tv; - - if (gettimeofday(&tv, SB_NULL) != 0) - { - return 0; - } - - return (sb_uint32)((tv.tv_sec * 1000ul) + (tv.tv_usec / 1000ul)); -} /*** end of XcpTransportClose ***/ - - -/************************************************************************************//** -** \brief Performs a delay of the specified amount of milliseconds. -** \param delay Delay time in milliseconds. -** \return none. -** -****************************************************************************************/ -void TimeUtilDelayMs(sb_uint16 delay) -{ - usleep(1000 * delay); -} /*** end of TimeUtilDelayMs **/ - - -/*********************************** end of xcptransport.c *****************************/ +/************************************************************************************//** +* \file port\linux\timeutil.c +* \brief Time utility source file. +* \ingroup SerialBoot +* \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 /* for NULL declaration */ +#include /* UNIX standard functions */ +#include /* time definitions */ +#include "timeutil.h" /* for time utilities module */ + + +/************************************************************************************//** +** \brief Get the system time in milliseconds. +** \return Time in milliseconds. +** +****************************************************************************************/ +uint32_t TimeUtilGetSystemTimeMs(void) +{ + struct timeval tv; + + if (gettimeofday(&tv, NULL) != 0) + { + return 0; + } + + return (uint32_t)((tv.tv_sec * 1000ul) + (tv.tv_usec / 1000ul)); +} /*** end of XcpTransportClose ***/ + + +/************************************************************************************//** +** \brief Performs a delay of the specified amount of milliseconds. +** \param delay Delay time in milliseconds. +** \return none. +** +****************************************************************************************/ +void TimeUtilDelayMs(uint16_t delay) +{ + usleep(1000 * delay); +} /*** end of TimeUtilDelayMs **/ + + +/*********************************** end of timeutil.c *********************************/ + diff --git a/Host/Source/SerialBoot/port/linux/xcptransport.c b/Host/Source/SerialBoot/port/linux/xcptransport.c deleted file mode 100644 index 40229aa9..00000000 --- a/Host/Source/SerialBoot/port/linux/xcptransport.c +++ /dev/null @@ -1,304 +0,0 @@ -/************************************************************************************//** -* \file port\linux\xcptransport.c -* \brief XCP transport layer interface source file. -* \ingroup SerialBoot -* \internal -*---------------------------------------------------------------------------------------- -* C O P Y R I G H T -*---------------------------------------------------------------------------------------- -* Copyright (c) 2014 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 /* assertion module */ -#include /* C types */ -#include /* standard I/O library */ -#include /* string function definitions */ -#include /* UNIX standard functions */ -#include /* file control definitions */ -#include /* error number definitions */ -#include /* POSIX terminal control */ -#include /* system I/O control */ -#include "xcpmaster.h" /* XCP master protocol module */ -#include "timeutil.h" /* time utility module */ - - - -/**************************************************************************************** -* Macro definitions -****************************************************************************************/ -/** \brief Invalid UART device/file handle. */ -#define UART_INVALID_HANDLE (-1) - -/** \brief maximum number of bytes in a transmit/receive XCP packet in UART. */ -#define XCP_MASTER_UART_MAX_DATA ((XCP_MASTER_TX_MAX_DATA>XCP_MASTER_RX_MAX_DATA) ? \ - (XCP_MASTER_TX_MAX_DATA+1) : (XCP_MASTER_RX_MAX_DATA+1)) - -/** \brief The smallest time in millisecond that the UART is configured for. */ -#define UART_RX_TIMEOUT_MIN_MS (100) - - -/**************************************************************************************** -* Function prototypes -****************************************************************************************/ -static speed_t XcpTransportGetBaudrateMask(sb_uint32 baudrate); - - -/**************************************************************************************** -* Local data declarations -****************************************************************************************/ -static tXcpTransportResponsePacket responsePacket; -static sb_int32 hUart = UART_INVALID_HANDLE; - - -/************************************************************************************//** -** \brief Initializes the communication interface used by this transport layer. -** \param device Serial communication device name. For example "COM4". -** \param baudrate Communication speed in bits/sec. -** \return SB_TRUE if successful, SB_FALSE otherwise. -** -****************************************************************************************/ -sb_uint8 XcpTransportInit(sb_char *device, sb_uint32 baudrate) -{ - struct termios options; - int iFlags; - - /* open the port */ - hUart = open(device, O_RDWR | O_NOCTTY | O_NDELAY); - /* verify the result */ - if (hUart == UART_INVALID_HANDLE) - { - return SB_FALSE; - } - /* configure the device to block during read operations */ - if (fcntl(hUart, F_SETFL, 0) == -1) - { - XcpTransportClose(); - return SB_FALSE; - } - /* get the current options for the port */ - if (tcgetattr(hUart, &options) == -1) - { - XcpTransportClose(); - return SB_FALSE; - } - /* configure the baudrate */ - if (cfsetispeed(&options, XcpTransportGetBaudrateMask(baudrate)) == -1) - { - XcpTransportClose(); - return SB_FALSE; - } - if (cfsetospeed(&options, XcpTransportGetBaudrateMask(baudrate)) == -1) - { - XcpTransportClose(); - return SB_FALSE; - } - /* enable the receiver and set local mode */ - options.c_cflag |= (CLOCAL | CREAD); - /* configure 8-n-1 */ - options.c_cflag &= ~PARENB; - options.c_cflag &= ~CSTOPB; - options.c_cflag &= ~CSIZE; - options.c_cflag |= CS8; - /* disable hardware flow control */ - options.c_cflag &= ~CRTSCTS; - /* configure raw input */ - options.c_lflag &= ~(ICANON | ISIG | ECHO | ECHOE); - /* configure raw output */ - options.c_oflag &= ~OPOST; - /* configure timeouts */ - options.c_cc[VMIN] = 0; - options.c_cc[VTIME] = UART_RX_TIMEOUT_MIN_MS/100; /* 1/10th of a second */ - /* set the new options for the port */ - if (tcsetattr(hUart, TCSAFLUSH, &options) == -1) - { - XcpTransportClose(); - return SB_FALSE; - } - /* turn on DTR */ - iFlags = TIOCM_DTR; - ioctl(hUart, TIOCMBIS, &iFlags); - /* success */ - return SB_TRUE; -} /*** end of XcpTransportInit ***/ - - -/************************************************************************************//** -** \brief Transmits an XCP packet on the transport layer and attemps to receive the -** response within the given timeout. The data in the response packet is -** stored in an internal data buffer that can be obtained through function -** XcpTransportReadResponsePacket(). -** \return SB_TRUE is the response packet was successfully received and stored, -** SB_FALSE otherwise. -** -****************************************************************************************/ -sb_uint8 XcpTransportSendPacket(sb_uint8 *data, sb_uint8 len, sb_uint16 timeOutMs) -{ - sb_uint16 cnt; - static sb_uint8 xcpUartBuffer[XCP_MASTER_UART_MAX_DATA]; /* static to lower stack load */ - sb_uint16 xcpUartLen; - sb_int32 bytesSent; - sb_int32 bytesToRead; - sb_int32 bytesRead; - sb_uint8 *uartReadDataPtr; - sb_uint32 timeoutTime; - sb_uint32 nowTime; - ssize_t result; - - /* ------------------------ XCP packet transmission -------------------------------- */ - /* 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. - */ - xcpUartLen = len+1; - xcpUartBuffer[0] = len; - for (cnt=0; cnt 0) - { - result = read(hUart, &responsePacket.len, bytesToRead); - if (result != -1) - { - bytesRead = result; - /* one byte should be read and it should contain the packet length, which cannot be 0 */ - if ((bytesRead == bytesToRead) && (responsePacket.len > 0)) - { - /* valid packet length received so stop this loop to continue with the reception - * remaining packet bytes - */ - bytesToRead = 0; - } - } - /* check for timeout if not yet done */ - if ( (bytesToRead > 0) && (TimeUtilGetSystemTimeMs() >= timeoutTime) ) - { - /* timeout occurred */ - return SB_FALSE; - } - } - - /* read the rest of the packet */ - bytesToRead = responsePacket.len; - uartReadDataPtr = &responsePacket.data[0]; - while(bytesToRead > 0) - { - result = read(hUart, uartReadDataPtr, bytesToRead); - if (result != -1) - { - bytesRead = result; - /* update the bytes that were already read */ - uartReadDataPtr += bytesRead; - bytesToRead -= bytesRead; - } - /* check for timeout if not yet done */ - if ( (bytesToRead > 0) && (TimeUtilGetSystemTimeMs() >= timeoutTime) ) - { - /* timeout occurred */ - return SB_FALSE; - } - } - /* still here so the complete packet was received */ - return SB_TRUE; -} /*** end of XcpMasterTpSendPacket ***/ - - -/************************************************************************************//** -** \brief Reads the data from the response packet. Make sure to not call this -** function while XcpTransportSendPacket() is active, because the data won't be -** valid then. -** \return Pointer to the response packet data. -** -****************************************************************************************/ -tXcpTransportResponsePacket *XcpTransportReadResponsePacket(void) -{ - return &responsePacket; -} /*** end of XcpTransportReadResponsePacket ***/ - - -/************************************************************************************//** -** \brief Closes the communication channel. -** \return none. -** -****************************************************************************************/ -void XcpTransportClose(void) -{ - /* close the COM port handle if valid */ - if (hUart != UART_INVALID_HANDLE) - { - close(hUart); - } - - /* set handles to invalid */ - hUart = UART_INVALID_HANDLE; -} /*** end of XcpTransportClose ***/ - - -/************************************************************************************//** -** \brief Converts the baudrate value to a bitmask value used by termios. Currently -** supports the most commonly used baudrates. -** \return none. -** -****************************************************************************************/ -static speed_t XcpTransportGetBaudrateMask(sb_uint32 baudrate) -{ - speed_t result; - - switch (baudrate) - { - case 115200: - result = B115200; - break; - case 57600: - result = B57600; - break; - case 38400: - result = B38400; - break; - case 19200: - result = B19200; - break; - case 9600: - default: - result = B9600; - break; - } - return result; -} /*** end of XcpTransportGetBaudrateMask ***/ - - -/*********************************** end of xcptransport.c *****************************/ diff --git a/Host/Source/SerialBoot/port/win32/xcptransport.c b/Host/Source/SerialBoot/port/win32/xcptransport.c deleted file mode 100644 index 3ea1323d..00000000 --- a/Host/Source/SerialBoot/port/win32/xcptransport.c +++ /dev/null @@ -1,265 +0,0 @@ -/************************************************************************************//** -* \file port\win32\xcptransport.c -* \brief XCP transport layer interface source file. -* \ingroup SerialBoot -* \internal -*---------------------------------------------------------------------------------------- -* C O P Y R I G H T -*---------------------------------------------------------------------------------------- -* Copyright (c) 2014 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 /* assertion module */ -#include /* C types */ -#include /* for WIN32 library */ -#include /* string library */ -#include "xcpmaster.h" /* XCP master protocol module */ -#include "timeutil.h" /* time utility module */ - - -/**************************************************************************************** -* Macro definitions -****************************************************************************************/ -#define UART_TX_BUFFER_SIZE (1024) /**< transmission buffer size */ -#define UART_RX_BUFFER_SIZE (1024) /**< reception buffer size */ - -/** \brief maximum number of bytes in a transmit/receive XCP packet in UART. */ -#define XCP_MASTER_UART_MAX_DATA ((XCP_MASTER_TX_MAX_DATA>XCP_MASTER_RX_MAX_DATA) ? \ - (XCP_MASTER_TX_MAX_DATA+1) : (XCP_MASTER_RX_MAX_DATA+1)) - - -/**************************************************************************************** -* Local data declarations -****************************************************************************************/ -static tXcpTransportResponsePacket responsePacket; -static HANDLE hUart = INVALID_HANDLE_VALUE; - - -/************************************************************************************//** -** \brief Initializes the communication interface used by this transport layer. -** \param device Serial communication device name. For example "COM4". -** \param baudrate Communication speed in bits/sec. -** \return SB_TRUE if successful, SB_FALSE otherwise. -** -****************************************************************************************/ -sb_uint8 XcpTransportInit(sb_char *device, sb_uint32 baudrate) -{ - COMMTIMEOUTS timeouts = { 0 }; - DCB dcbSerialParams = { 0 }; - char portStr[64] = "\\\\.\\\0"; - - /* construct the COM port name as a string */ - strcat_s(portStr, 59, device); - - /* 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) - { - return SB_FALSE; - } - - /* get current COM port configuration */ - dcbSerialParams.DCBlength = sizeof(dcbSerialParams); - if (!GetCommState(hUart, &dcbSerialParams)) - { - XcpTransportClose(); - return SB_FALSE; - } - - /* configure the baudrate and 8,n,1 */ - dcbSerialParams.BaudRate = 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)) - { - XcpTransportClose(); - return SB_FALSE; - } - - /* set communication timeout parameters */ - timeouts.ReadIntervalTimeout = 0; - timeouts.ReadTotalTimeoutConstant = 0; - timeouts.ReadTotalTimeoutMultiplier = 100; - timeouts.WriteTotalTimeoutConstant = 0; - timeouts.WriteTotalTimeoutMultiplier = 100; - - if (!SetCommTimeouts(hUart, &timeouts)) - { - XcpTransportClose(); - return SB_FALSE; - } - - /* set transmit and receive buffer sizes */ - if(!SetupComm(hUart, UART_RX_BUFFER_SIZE, UART_TX_BUFFER_SIZE)) - { - XcpTransportClose(); - return SB_FALSE; - } - - /* empty the transmit and receive buffers */ - if (!FlushFileBuffers(hUart)) - { - XcpTransportClose(); - return SB_FALSE; - } - /* successfully connected to the serial device */ - return SB_TRUE; -} /*** end of XcpTransportInit ***/ - - -/************************************************************************************//** -** \brief Transmits an XCP packet on the transport layer and attemps to receive the -** response within the given timeout. The data in the response packet is -** stored in an internal data buffer that can be obtained through function -** XcpTransportReadResponsePacket(). -** \return SB_TRUE is the response packet was successfully received and stored, -** SB_FALSE otherwise. -** -****************************************************************************************/ -sb_uint8 XcpTransportSendPacket(sb_uint8 *data, sb_uint8 len, sb_uint16 timeOutMs) -{ - sb_uint32 dwWritten = 0; - sb_uint32 dwRead = 0; - sb_uint32 dwToRead; - sb_uint16 cnt; - static sb_uint8 xcpUartBuffer[XCP_MASTER_UART_MAX_DATA]; /* static to lower stack load */ - sb_uint16 xcpUartLen; - sb_uint8 *uartReadDataPtr; - sb_uint32 timeoutTime; - - /* ------------------------ XCP packet transmission -------------------------------- */ - /* 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. - */ - xcpUartLen = len+1; - xcpUartBuffer[0] = len; - for (cnt=0; cnt 0) - { - dwRead = 0; - if (ReadFile(hUart, &responsePacket.len, dwToRead, &dwRead, NULL)) - { - /* one byte should be read and it should contain the packet length, which cannot be 0 */ - if ((dwRead == dwToRead) && (responsePacket.len > 0)) - { - /* valid packet length received so stop this loop to continue with the reception - * remaining packet bytes - */ - dwToRead = 0; - } - } - /* check for timeout if not yet done */ - if ( (dwToRead > 0) && (TimeUtilGetSystemTimeMs() >= timeoutTime) ) - { - /* timeout occurred */ - return SB_FALSE; - } - } - - /* read the rest of the packet */ - dwToRead = responsePacket.len; - uartReadDataPtr = &responsePacket.data[0]; - while(dwToRead > 0) - { - dwRead = 0; - if (ReadFile(hUart, uartReadDataPtr, dwToRead, &dwRead, NULL)) - { - /* update the bytes that were already read */ - uartReadDataPtr += dwRead; - dwToRead -= dwRead; - } - /* check for timeout if not yet done */ - if ( (dwToRead > 0) && (TimeUtilGetSystemTimeMs() >= timeoutTime) ) - { - /* timeout occurred */ - return SB_FALSE; - } - } - /* still here so the complete packet was received */ - return SB_TRUE; -} /*** end of XcpMasterTpSendPacket ***/ - - -/************************************************************************************//** -** \brief Reads the data from the response packet. Make sure to not call this -** function while XcpTransportSendPacket() is active, because the data won't be -** valid then. -** \return Pointer to the response packet data. -** -****************************************************************************************/ -tXcpTransportResponsePacket *XcpTransportReadResponsePacket(void) -{ - return &responsePacket; -} /*** end of XcpTransportReadResponsePacket ***/ - - -/************************************************************************************//** -** \brief Closes the communication channel. -** \return none. -** -****************************************************************************************/ -void XcpTransportClose(void) -{ - /* close the COM port handle if valid */ - if (hUart != INVALID_HANDLE_VALUE) - { - CloseHandle(hUart); - } - - /* set handles to invalid */ - hUart = INVALID_HANDLE_VALUE; -} /*** end of XcpTransportClose ***/ - - -/*********************************** end of xcptransport.c *****************************/ diff --git a/Host/Source/SerialBoot/port/windows/serialport.c b/Host/Source/SerialBoot/port/windows/serialport.c new file mode 100644 index 00000000..bc2f1f9c --- /dev/null +++ b/Host/Source/SerialBoot/port/windows/serialport.c @@ -0,0 +1,260 @@ +/************************************************************************************//** +* \file port\windows\serialport.c +* \brief Serial port source file. +* \ingroup SerialBoot +* \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 /* for NULL declaration */ +#include /* for windows library */ +#include /* for assertions */ +#include "serialport.h" /* serial port module */ + + +/**************************************************************************************** +* Macro definitions +****************************************************************************************/ +#define UART_TX_BUFFER_SIZE (1024) /**< transmission buffer size */ +#define UART_RX_BUFFER_SIZE (1024) /**< reception buffer size */ + + +/**************************************************************************************** +* Local data declarations +****************************************************************************************/ +static HANDLE hUart = INVALID_HANDLE_VALUE; + + +/**************************************************************************************** +* Function prototypes +****************************************************************************************/ +static uint32_t SerialConvertBaudrate(tSerialPortBaudrate baudrate); + + +/************************************************************************************//** +** \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 *portname, tSerialPortBaudrate baudrate) +{ + COMMTIMEOUTS timeouts = { 0 }; + DCB dcbSerialParams = { 0 }; + char portStr[64] = "\\\\.\\\0"; + + /* check parameters */ + assert(portname != NULL); + + /* construct the COM port name as a string */ + strcat_s(portStr, 59, 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) + { + return false; + } + + /* get current COM port configuration */ + dcbSerialParams.DCBlength = sizeof(dcbSerialParams); + if (!GetCommState(hUart, &dcbSerialParams)) + { + CloseHandle(hUart); + return false; + } + + /* configure the baudrate and 8,n,1 */ + 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)) + { + CloseHandle(hUart); + return false; + } + + /* set communication timeout parameters */ + timeouts.ReadIntervalTimeout = 0; + timeouts.ReadTotalTimeoutConstant = 0; + timeouts.ReadTotalTimeoutMultiplier = 100; + timeouts.WriteTotalTimeoutConstant = 0; + timeouts.WriteTotalTimeoutMultiplier = 100; + + if (!SetCommTimeouts(hUart, &timeouts)) + { + CloseHandle(hUart); + return false; + } + + /* set transmit and receive buffer sizes */ + if (!SetupComm(hUart, UART_RX_BUFFER_SIZE, UART_TX_BUFFER_SIZE)) + { + CloseHandle(hUart); + return false; + } + + /* empty the transmit and receive buffers */ + if (!FlushFileBuffers(hUart)) + { + CloseHandle(hUart); + return false; + } + /* successfully connected to the serial device */ + return true; +} /*** end of SerialPortOpen ***/ + + +/************************************************************************************//** +** \brief Closes the connection with the serial port. +** \return None. +** +****************************************************************************************/ +void SerialPortClose(void) +{ + /* close the COM port handle if valid */ + if (hUart != INVALID_HANDLE_VALUE) + { + 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 *data, uint32_t length) +{ + uint32_t dwWritten = 0; + + /* check parameters */ + assert(data != NULL); + assert(length > 0); + + /* submit the data for transmission with the serial port */ + if (!WriteFile(hUart, data, length, &dwWritten, NULL)) + { + return false; + } + /* double check that all bytes were actually transmitted */ + if (dwWritten != length) + { + return false; + } + + /* success */ + return true; +} /*** 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) +{ + uint32_t dwRead = 0; + + /* check parameters */ + assert(data != NULL); + assert(length > 0); + + /* attempt to read data from the serial port */ + if (!ReadFile(hUart, data, length, &dwRead, NULL)) + { + return false; + } + /* double check that all bytes were actually read */ + if (dwRead != length) + { + return false; + } + + /* success */ + return true; +} /*** end of SerialPortRead ***/ + + +/************************************************************************************//** +** \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. +** +****************************************************************************************/ +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 *******************************/ + diff --git a/Host/Source/SerialBoot/port/win32/timeutil.c b/Host/Source/SerialBoot/port/windows/timeutil.c similarity index 82% rename from Host/Source/SerialBoot/port/win32/timeutil.c rename to Host/Source/SerialBoot/port/windows/timeutil.c index 95f9a7bd..714b761c 100644 --- a/Host/Source/SerialBoot/port/win32/timeutil.c +++ b/Host/Source/SerialBoot/port/windows/timeutil.c @@ -1,60 +1,60 @@ -/************************************************************************************//** -* \file port\win32\timeutil.c -* \brief Time utility source file. -* \ingroup SerialBoot -* \internal -*---------------------------------------------------------------------------------------- -* C O P Y R I G H T -*---------------------------------------------------------------------------------------- -* Copyright (c) 2014 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 /* assertion module */ -#include /* C types */ -#include /* for WIN32 library */ - - -/************************************************************************************//** -** \brief Get the system time in milliseconds. -** \return Time in milliseconds. -** -****************************************************************************************/ -sb_uint32 TimeUtilGetSystemTimeMs(void) -{ - return GetTickCount(); -} /*** end of XcpTransportClose ***/ - - -/************************************************************************************//** -** \brief Performs a delay of the specified amount of milliseconds. -** \param delay Delay time in milliseconds. -** \return none. -** -****************************************************************************************/ -void TimeUtilDelayMs(sb_uint16 delay) -{ - Sleep(delay); -} /*** end of TimeUtilDelayMs **/ - - -/*********************************** end of timeutil.c *********************************/ +/************************************************************************************//** +* \file port\windows\timeutil.c +* \brief Time utility source file. +* \ingroup SerialBoot +* \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 /* for windows library */ +#include "timeutil.h" /* for time utilities module */ + + +/************************************************************************************//** +** \brief Get the system time in milliseconds. +** \return Time in milliseconds. +** +****************************************************************************************/ +uint32_t TimeUtilGetSystemTimeMs(void) +{ + return GetTickCount(); +} /*** end of XcpTransportClose ***/ + + +/************************************************************************************//** +** \brief Performs a delay of the specified amount of milliseconds. +** \param delay Delay time in milliseconds. +** \return none. +** +****************************************************************************************/ +void TimeUtilDelayMs(uint16_t delay) +{ + Sleep(delay); +} /*** end of TimeUtilDelayMs **/ + + +/*********************************** end of timeutil.c *********************************/ + diff --git a/Host/Source/SerialBoot/xcpmaster.h b/Host/Source/SerialBoot/serialport.h similarity index 59% rename from Host/Source/SerialBoot/xcpmaster.h rename to Host/Source/SerialBoot/serialport.h index c9fa33e0..e82ab8dd 100644 --- a/Host/Source/SerialBoot/xcpmaster.h +++ b/Host/Source/SerialBoot/serialport.h @@ -1,66 +1,70 @@ -/************************************************************************************//** -* \file xcpmaster.h -* \brief XCP Master header file. -* \ingroup SerialBoot -* \internal -*---------------------------------------------------------------------------------------- -* C O P Y R I G H T -*---------------------------------------------------------------------------------------- -* Copyright (c) 2014 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 XCPMASTER_H -#define XCPMASTER_H - -/**************************************************************************************** -* Macro definitions -****************************************************************************************/ -/** \brief Configure number of bytes in the master->slave data packet. Should be at least - * equal or larger than that configured on the slave. - */ -#define XCP_MASTER_TX_MAX_DATA (255) - -/** \brief Configure number of bytes in the slave->master data packet. Should be at least - * equal or larger than that configured on the slave. - */ -#define XCP_MASTER_RX_MAX_DATA (255) - - -/**************************************************************************************** -* Include files -****************************************************************************************/ -#include "xcptransport.h" /* XCP transport layer */ - - -/**************************************************************************************** -* Function prototypes -****************************************************************************************/ -sb_uint8 XcpMasterInit(sb_char *device, sb_uint32 baudrate); -void XcpMasterDeinit(void); -sb_uint8 XcpMasterConnect(void); -sb_uint8 XcpMasterDisconnect(void); -sb_uint8 XcpMasterStartProgrammingSession(void); -sb_uint8 XcpMasterStopProgrammingSession(void); -sb_uint8 XcpMasterClearMemory(sb_uint32 addr, sb_uint32 len); -sb_uint8 XcpMasterReadData(sb_uint32 addr, sb_uint32 len, sb_uint8 data[]); -sb_uint8 XcpMasterProgramData(sb_uint32 addr, sb_uint32 len, sb_uint8 data[]); - - -#endif /* XCPMASTER_H */ -/*********************************** end of xcpmaster.h ********************************/ +/************************************************************************************//** +* \file serialport.h +* \brief Serial port header file. +* \ingroup SerialBoot +* \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 + +/**************************************************************************************** +* Include files +****************************************************************************************/ +#include /* for standard integer types */ +#include /* for boolean type */ + + +/**************************************************************************************** +* Typde 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 +****************************************************************************************/ +bool SerialPortOpen(char *portname, tSerialPortBaudrate baudrate); +void SerialPortClose(void); +bool SerialPortWrite(uint8_t *data, uint32_t length); +bool SerialPortRead(uint8_t *data, uint32_t length); + +#ifdef __cplusplus +} +#endif + +#endif /* SERIALPORT_H */ +/********************************* end of serialport.h *********************************/ + diff --git a/Host/Source/SerialBoot/srecord.c b/Host/Source/SerialBoot/srecord.c deleted file mode 100644 index 0faffb23..00000000 --- a/Host/Source/SerialBoot/srecord.c +++ /dev/null @@ -1,448 +0,0 @@ -/************************************************************************************//** -* \file srecord.c -* \brief Motorola S-record library header file. -* \ingroup SerialBoot -* \internal -*---------------------------------------------------------------------------------------- -* C O P Y R I G H T -*---------------------------------------------------------------------------------------- -* Copyright (c) 2014 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 /* assertion module */ -#include /* C types */ -#include /* for strcpy etc. */ -#include /* for toupper() etc. */ -#include "srecord.h" /* S-record library */ - - -/**************************************************************************************** -* Type definitions -****************************************************************************************/ -/** \brief Enumeration for the different S-record line types. */ -typedef enum -{ - LINE_TYPE_S1, /**< 16-bit address line */ - LINE_TYPE_S2, /**< 24-bit address line */ - LINE_TYPE_S3, /**< 32-bit address line */ - LINE_TYPE_UNSUPPORTED /**< unsupported line */ -} tSrecordLineType; - - -/**************************************************************************************** -* Function prototypes -****************************************************************************************/ -static tSrecordLineType SrecordGetLineType(const sb_char *line); -static sb_uint8 SrecordVerifyChecksum(const sb_char *line); -static sb_uint8 SrecordHexStringToByte(const sb_char *hexstring); -static sb_uint8 SrecordReadLine(sb_file srecordHandle, sb_char *line); - - -/************************************************************************************//** -** \brief Checks if the specified srecordFile exists and contains s-records. -** \param srecordFile The S-record file with full path if applicable. -** \return SB_TRUE on the S-record is valid, SB_FALSE otherwise. -** -****************************************************************************************/ -sb_uint8 SrecordIsValid(const sb_char *srecordFile) -{ - sb_file tempHandle; - sb_char line[SRECORD_MAX_CHARS_PER_LINE]; - - /* attempt to open the file */ - tempHandle = SrecordOpen(srecordFile); - /* is the file available? */ - if (tempHandle == SB_NULL) - { - /* cannot open the file */ - return SB_FALSE; - } - /* all lines should be formatted as S-records. read the first one to check this */ - if (SrecordReadLine(tempHandle, line) == SB_FALSE) - { - /* could not read a line. file must be empty */ - SrecordClose(tempHandle); - return SB_FALSE; - } - /* check if the line starts with the 'S' character, followed by a digit */ - if ( (toupper(line[0]) != 'S') || (isdigit(line[1]) == 0) ) - { - SrecordClose(tempHandle); - return SB_FALSE; - } - - /* still here so it is a valid s-record */ - SrecordClose(tempHandle); - return SB_TRUE; -} /*** end of SrecordIsValid ***/ - - -/************************************************************************************//** -** \brief Opens the S-record file for reading. -** \param srecordFile The S-record file with full path if applicable. -** \return The filehandle if successful, SB_NULL otherwise. -** -****************************************************************************************/ -sb_file SrecordOpen(const sb_char *srecordFile) -{ - /* open the file for reading */ - return fopen(srecordFile, "r"); -} /*** end of SrecordOpen ***/ - - -/************************************************************************************//** -** \brief Parse the S-record file to obtain information about its contents. -** \param srecordHandle The S-record file handle. It is returned by SrecordOpen. -** \param parseResults Pointer to where the parse results should be stored. -** \return none. -** -****************************************************************************************/ -void SrecordParse(sb_file srecordHandle, tSrecordParseResults *parseResults) -{ - tSrecordLineParseResults lineResults; - - /* start at the beginning of the file */ - rewind(srecordHandle); - - /* init data structure */ - parseResults->address_high = 0; - parseResults->address_low = 0xffffffff; - parseResults->data_bytes_total = 0; - - /* loop through all S-records with program data */ - while (SrecordParseNextDataLine(srecordHandle, &lineResults) == SB_TRUE) - { - /* update byte total */ - parseResults->data_bytes_total += lineResults.length; - /* is this a new lowest address? */ - if (lineResults.address < parseResults->address_low) - { - parseResults->address_low = lineResults.address; - } - /* is this a new highest address? */ - if ((lineResults.address + lineResults.length - 1) > parseResults->address_high) - { - parseResults->address_high = (lineResults.address + lineResults.length - 1); - } - } - /* reset to the beginning of the file again */ - rewind(srecordHandle); -} /*** end of SrecordParse ***/ - - -/************************************************************************************//** -** \brief Closes the S-record file. -** \param srecordHandle The S-record file handle. It is returned by SrecordOpen. -** \return none. -** -****************************************************************************************/ -void SrecordClose(sb_file srecordHandle) -{ - /* close the file handle if valid */ - if (srecordHandle != SB_NULL) - { - fclose(srecordHandle); - } -} /*** end of SrecordClose ***/ - - -/************************************************************************************//** -** \brief Reads the next S-record with program data, parses it and returns the -** results. -** \param srecordHandle The S-record file handle. It is returned by SrecordOpen. -** \param parseResults Pointer to where the parse results should be stored. -** \return SB_TRUE is valid parse results were stored. SB_FALSE in case of end-of- -** file. -** -****************************************************************************************/ -sb_uint8 SrecordParseNextDataLine(sb_file srecordHandle, tSrecordLineParseResults *parseResults) -{ - sb_char line[SRECORD_MAX_CHARS_PER_LINE]; - sb_uint8 data_line_found = SB_FALSE; - tSrecordLineType lineType; - sb_uint16 bytes_on_line; - sb_uint16 i; - sb_char *linePtr; - - /* first set the length paramter to 0 */ - parseResults->length = 0; - - while (data_line_found == SB_FALSE) - { - /* read the next line from the file */ - if (SrecordReadLine(srecordHandle, line) == SB_FALSE) - { - /* end-of-file encountered */ - return SB_FALSE; - } - /* we now have a line. check if it is a S-record data line */ - lineType = SrecordGetLineType(line); - if (lineType != LINE_TYPE_UNSUPPORTED) - { - /* check if the checksum on the line is correct */ - if (SrecordVerifyChecksum(line) == SB_TRUE) - { - /* found a valid line that can be parsed. loop will stop */ - data_line_found = SB_TRUE; - break; - } - } - } - - /* still here so we have a valid S-record data line. start parsing */ - linePtr = &line[0]; - /* all good so far, now read out the address and databytes for the line */ - switch (lineType) - { - /* ---------------------------- S1 line type ------------------------------------- */ - case LINE_TYPE_S1: - /* adjust pointer to point to byte count value */ - linePtr += 2; - /* read out the number of byte values that follow on the line */ - bytes_on_line = SrecordHexStringToByte(linePtr); - /* read out the 16-bit address */ - linePtr += 2; - parseResults->address = SrecordHexStringToByte(linePtr) << 8; - linePtr += 2; - parseResults->address += SrecordHexStringToByte(linePtr); - /* adjust pointer to point to the first data byte after the address */ - linePtr += 2; - /* determine how many data bytes are on the line */ - parseResults->length = bytes_on_line - 3; /* -2 bytes address, -1 byte checksum */ - /* read and store data bytes if requested */ - for (i=0; ilength; i++) - { - parseResults->data[i] = SrecordHexStringToByte(linePtr); - linePtr += 2; - } - break; - - /* ---------------------------- S2 line type ------------------------------------- */ - case LINE_TYPE_S2: - /* adjust pointer to point to byte count value */ - linePtr += 2; - /* read out the number of byte values that follow on the line */ - bytes_on_line = SrecordHexStringToByte(linePtr); - /* read out the 32-bit address */ - linePtr += 2; - parseResults->address = SrecordHexStringToByte(linePtr) << 16; - linePtr += 2; - parseResults->address += SrecordHexStringToByte(linePtr) << 8; - linePtr += 2; - parseResults->address += SrecordHexStringToByte(linePtr); - /* adjust pointer to point to the first data byte after the address */ - linePtr += 2; - /* determine how many data bytes are on the line */ - parseResults->length = bytes_on_line - 4; /* -3 bytes address, -1 byte checksum */ - /* read and store data bytes if requested */ - for (i=0; ilength; i++) - { - parseResults->data[i] = SrecordHexStringToByte(linePtr); - linePtr += 2; - } - break; - - /* ---------------------------- S3 line type ------------------------------------- */ - case LINE_TYPE_S3: - /* adjust pointer to point to byte count value */ - linePtr += 2; - /* read out the number of byte values that follow on the line */ - bytes_on_line = SrecordHexStringToByte(linePtr); - /* read out the 32-bit address */ - linePtr += 2; - parseResults->address = SrecordHexStringToByte(linePtr) << 24; - linePtr += 2; - parseResults->address += SrecordHexStringToByte(linePtr) << 16; - linePtr += 2; - parseResults->address += SrecordHexStringToByte(linePtr) << 8; - linePtr += 2; - parseResults->address += SrecordHexStringToByte(linePtr); - /* adjust pointer to point to the first data byte after the address */ - linePtr += 2; - /* determine how many data bytes are on the line */ - parseResults->length = bytes_on_line - 5; /* -4 bytes address, -1 byte checksum */ - /* read and store data bytes if requested */ - for (i=0; ilength; i++) - { - parseResults->data[i] = SrecordHexStringToByte(linePtr); - linePtr += 2; - } - break; - - default: - /* will not happen */ - break; - } - - /* parsing all done */ - return SB_TRUE; -} /*** end of SrecordParseNextDataLine ***/ - - -/************************************************************************************//** -** \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 tSrecordLineType SrecordGetLineType(const sb_char *line) -{ - /* check if the line starts with the 'S' character, followed by a digit */ - if ( (toupper(line[0]) != 'S') || (isdigit(line[1]) == 0) ) - { - /* not a valid S-Record line type */ - return LINE_TYPE_UNSUPPORTED; - } - /* determine the line type */ - if (line[1] == '1') - { - return LINE_TYPE_S1; - } - if (line[1] == '2') - { - return LINE_TYPE_S2; - } - if (line[1] == '3') - { - return LINE_TYPE_S3; - } - /* still here so not a supported line type found */ - return LINE_TYPE_UNSUPPORTED; -} /*** end of SrecordGetLineType ***/ - - -/************************************************************************************//** -** \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 SB_TRUE if the checksum is correct, SB_FALSE otherwise. -** -****************************************************************************************/ -static sb_uint8 SrecordVerifyChecksum(const sb_char *line) -{ - sb_uint16 bytes_on_line; - sb_uint8 checksum = 0; - - /* adjust pointer to point to byte count value */ - line += 2; - /* read out the number of byte values that follow on the line */ - bytes_on_line = SrecordHexStringToByte(line); - /* byte count is part of checksum */ - checksum += bytes_on_line; - /* adjust pointer to the first byte of the address */ - line += 2; - /* add byte values of address and data, but not the final checksum */ - do - { - /* add the next byte value to the checksum */ - checksum += SrecordHexStringToByte(line); - /* update counter */ - bytes_on_line--; - /* point to next hex string in the line */ - line += 2; - } - while (bytes_on_line > 1); - /* the checksum is calculated by summing up the values of the byte count, address and - * databytes and then taking the 1-complement of the sum's least signigicant byte */ - checksum = ~checksum; - /* finally verify the calculated checksum with the one at the end of the line */ - if (checksum != SrecordHexStringToByte(line)) - { - /* checksum incorrect */ - return SB_FALSE; - } - /* still here so the checksum was correct */ - return SB_TRUE; -} /*** end of SrecordVerifyChecksum ***/ - - -/************************************************************************************//** -** \brief Helper function to convert a sequence of 2 characters that represent -** a hexadecimal value to the actual byte value. -** Example: SrecordHexStringToByte("2f") --> returns 47. -** \param hexstring String beginning with 2 characters that represent a hexa- -** decimal value. -** \return The resulting byte value. -** -****************************************************************************************/ -static sb_uint8 SrecordHexStringToByte(const sb_char *hexstring) -{ - sb_uint8 result = 0; - sb_char c; - sb_uint8 counter; - - /* a hexadecimal character is 2 characters long (i.e 0x4F minus the 0x part) */ - for (counter=0; counter < 2; counter++) - { - /* read out the character */ - c = toupper(hexstring[counter]); - /* check that the character is 0..9 or A..F */ - if ( (c < '0') || (c > 'F') || ( (c > '9') && (c < 'A') ) ) - { - /* character not valid */ - return 0; - } - /* convert character to 4-bit value (check ASCII table for more info) */ - c -= '0'; - if (c > 9) - { - c -= 7; - } - /* add it to the result */ - result = (result << 4) + c; - } - /* return the results */ - return result; -} /*** end of SrecordHexStringToByte ***/ - - -/************************************************************************************//** -** \brief Reads the next line from the S-record file handle. -** \param srecordHandle The S-record file handle. It is returned by SrecordOpen. -** \param line Destination buffer for the line characters. Should be of size -** SRECORD_MAX_CHARS_PER_LINE. -** \return SB_TRUE if successful, SB_FALSE otherwise. -** -****************************************************************************************/ -static sb_uint8 SrecordReadLine(sb_file srecordHandle, sb_char *line) -{ - /* init the line as an empty line */ - line[0] = '\0'; - - /* loop as long as we find a non-empty line or end-of-file */ - while (line[0] == '\0') - { - if (fgets(line, SRECORD_MAX_CHARS_PER_LINE, srecordHandle) == SB_NULL) - { - /* no more lines available */ - return SB_FALSE; - } - /* replace the line termination with a string termination */ - line[strcspn(line, "\n")] = '\0'; - } - /* still here so not EOF and not and empty line, so success */ - return SB_TRUE; -} /*** end of SrecordReadLine ***/ - - -/*********************************** end of srecord.c **********************************/ diff --git a/Host/Source/SerialBoot/srecparser.c b/Host/Source/SerialBoot/srecparser.c new file mode 100644 index 00000000..d0e089cb --- /dev/null +++ b/Host/Source/SerialBoot/srecparser.c @@ -0,0 +1,751 @@ +/************************************************************************************//** +* \file srecparser.c +* \brief S-record parser source file. +* \ingroup SerialBoot +* \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 /* for NULL declaration */ +#include /* for standard I/O library */ +#include /* for standard library */ +#include /* for string library */ +#include /* for character testing */ +#include /* for assertions */ +#include "srecparser.h" /* S-record parser */ + + +/**************************************************************************************** +* Macro definitions +****************************************************************************************/ +/** \brief Maximum number of characters that can be on a line in the firmware file. */ +#define SRECORD_MAX_CHARS_PER_LINE (512) + +/** \brief Maximum number of data bytes that can be on a line in the firmware file + * (S-record). + */ +#define SRECORD_MAX_DATA_BYTES_PER_LINE (SRECORD_MAX_CHARS_PER_LINE/2) + + +/**************************************************************************************** +* Type definitions +****************************************************************************************/ +/** \brief Layout of a firmware segment node in the linked list. */ +typedef struct t_segment_node +{ + /** \brief The firmware segment stored in this node. */ + tFirmwareSegment segment; + /** \brief Pointer to the next node, or NULL if it is the last one. */ + struct t_segment_node *next; +} tSegmentNode; + +/** \brief Enumeration for the different S-record line types. */ +typedef enum +{ + LINE_TYPE_S1, /**< 16-bit address line */ + LINE_TYPE_S2, /**< 24-bit address line */ + LINE_TYPE_S3, /**< 32-bit address line */ + LINE_TYPE_UNSUPPORTED /**< unsupported line */ +} tSrecordLineType; + +/** \brief Structure type for grouping the parsing results of an S-record line. */ +typedef struct +{ + uint8_t data[SRECORD_MAX_DATA_BYTES_PER_LINE]; /**< array for S1,S2 or S3 data bytes */ + uint32_t address; /**< address on S1,S2 or S3 line */ + uint16_t length; /**< number of bytes written to array */ +} tSrecordLineParseResults; + + +/**************************************************************************************** +* Function prototypes +****************************************************************************************/ +static void SRecParserInit(void); +static void SRecParserDeinit(void); +static bool SRecParserLoadFromFile(char *firmwareFile); +static uint32_t SRecParserGetSegmentCount(void); +static const tFirmwareSegment *SRecParserGetSegment(uint32_t segmentIdx); +static void SRecParserSegmentListInit(void); +static void SRecParserSegmentListDeinit(void); +static tSegmentNode *SRecParserSegmentListCreateNode(void); +static uint32_t SRecParserSegmentListGetNodeCount(void); +static tSegmentNode *SRecParserSegmentListGetNode(uint32_t nodeIdx); +/* S-record utility functions */ +static bool SrecordParseNextDataLine(FILE* srecordHandle, tSrecordLineParseResults *parseResults); +static tSrecordLineType SrecordGetLineType(const char *line); +static bool SrecordVerifyChecksum(const char *line); +static uint8_t SrecordHexStringToByte(const char *hexstring); +static bool SrecordReadLine(FILE *srecordHandle, char *line); + + + +/**************************************************************************************** +* Local constant declarations +****************************************************************************************/ +/** \brief XCP transport structure filled with CAN specifics. */ +static const tFirmwareParser srecParser = +{ + SRecParserInit, + SRecParserDeinit, + SRecParserLoadFromFile, + SRecParserGetSegmentCount, + SRecParserGetSegment +}; + + +/**************************************************************************************** +* Local data declarations +****************************************************************************************/ +/** \brief Linked list with firmware segments. */ +static tSegmentNode *segmentList; + + +/***********************************************************************************//** +** \brief Obtains a pointer to the parser structure, so that it can be linked to the +** firmware loader module. +** \return Pointer to firmware parser structure. +** +****************************************************************************************/ +tFirmwareParser const * const SRecParserGetParser(void) +{ + return &srecParser; +} /*** end of SRecParserGetParser ***/ + + +/************************************************************************************//** +** \brief Initializes the parser. +** \return None. +** +****************************************************************************************/ +static void SRecParserInit(void) +{ + /* initialize the segment list */ + SRecParserSegmentListInit(); +} /*** end of SRecParserInit ***/ + + +/************************************************************************************//** +** \brief Uninitializes the parser. +** \return None. +** +****************************************************************************************/ +static void SRecParserDeinit(void) +{ + /* uninitialize the segment list */ + SRecParserSegmentListDeinit(); +} /*** end of SRecParserDeinit ***/ + + +/************************************************************************************//** +** \brief Parses the data in the specified firmware file into firmware segments that +** are stored internally in this module. +** \return True is successful, false otherwise. +** +****************************************************************************************/ +static bool SRecParserLoadFromFile(char *firmwareFile) +{ + FILE *fp; + char line[SRECORD_MAX_CHARS_PER_LINE]; + tSrecordLineParseResults lineResults; + tSegmentNode *node; + uint32_t nodeIdx; + bool matchFound; + uint32_t byteIdx; + uint32_t byteOffset; + + /* verify parameters */ + assert(firmwareFile != NULL); + + /* open the file for reading */ + fp = fopen(firmwareFile, "r"); + if (fp == NULL) + { + /* could not open the file */ + return false; + } + /* start at the beginning of the file */ + rewind(fp); + + /* -------------------------- file type validation --------------------------------- */ + /* validate S-record file. all lines should be formatted as S-records. read the first + * one to check this. + */ + if (!SrecordReadLine(fp, line)) + { + /* could not read a line. file must be empty */ + fclose(fp); + return false; + } + /* check if the line starts with the 'S' character, followed by a digit */ + if ( (toupper(line[0]) != 'S') || (isdigit(line[1]) == 0) ) + { + fclose(fp); + return false; + } + + /* -------------------------- extract segment info --------------------------------- */ + /* start at the beginning of the file */ + rewind(fp); + + /* loop through all S-records with program data to obtain segment info */ + while (SrecordParseNextDataLine(fp, &lineResults)) + { + /* reset flag that indicates that the line data was matched to an existing segment */ + matchFound = false; + /* loop through all segment nodes */ + for (nodeIdx=0; nodeIdx < SRecParserSegmentListGetNodeCount(); nodeIdx++) + { + /* get node access */ + node = SRecParserSegmentListGetNode(nodeIdx); + + /* does the line data fit at the start of this node's segment? */ + if ((lineResults.address + lineResults.length) == node->segment.base) + { + /* update the node's segment */ + node->segment.base -= lineResults.length; + node->segment.length += lineResults.length; + /* match found so continue with the next line */ + matchFound = true; + break; + } + /* does the line data fit at the end of this node's segment? */ + else if (lineResults.address == (node->segment.base + node->segment.length)) + { + /* update the node's segment */ + node->segment.length += lineResults.length; + /* match found so continue with the next line */ + matchFound = true; + break; + } + } + /* check if the line data was matched and added to an existing segment */ + if (!matchFound) + { + /* create a new segment */ + node = SRecParserSegmentListCreateNode(); + node->segment.base = lineResults.address; + node->segment.length = lineResults.length; + } + } + + /* -------------------------- allocate data memory --------------------------------- */ + /* loop through all segment nodes */ + for (nodeIdx=0; nodeIdx < SRecParserSegmentListGetNodeCount(); nodeIdx++) + { + /* get node access */ + node = SRecParserSegmentListGetNode(nodeIdx); + /* sanity check */ + assert(node->segment.length > 0); + /* allocate data */ + node->segment.data = malloc(node->segment.length); + /* check results */ + if (node->segment.data == NULL) + { + fclose(fp); + return false; + } + } + + /* -------------------------- extract segment data --------------------------------- */ + /* start at the beginning of the file */ + rewind(fp); + + /* loop through all S-records with program data to obtain segment info */ + while (SrecordParseNextDataLine(fp, &lineResults)) + { + /* loop through all segment nodes */ + for (nodeIdx=0; nodeIdx < SRecParserSegmentListGetNodeCount(); nodeIdx++) + { + /* get node access */ + node = SRecParserSegmentListGetNode(nodeIdx); + /* does the line data belong in this segment? */ + if ( (lineResults.address >= node->segment.base) && \ + ((lineResults.address+lineResults.length) <= (node->segment.base+node->segment.length)) ) + { + /* determine offset of the line data into the segment */ + byteOffset = lineResults.address - node->segment.base; + /* store bytes in this segment */ + for (byteIdx=0; byteIdxsegment.data[byteOffset + byteIdx] = lineResults.data[byteIdx]; + } + /* line data stored, so continue with the next S-record */ + break; + } + } + } + + /* close the file */ + fclose(fp); + /* s-record successfully loaded and parsed */ + return true; +} /*** end of SRecParserLoadFromFile ***/ + + +/************************************************************************************//** +** \brief Returns the number of firmware segments that were loaded by this parser. +** \return Number of firmware segments. +** +****************************************************************************************/ +static uint32_t SRecParserGetSegmentCount(void) +{ + return SRecParserSegmentListGetNodeCount(); +} /*** end of SRecParserGetSegmentCount ***/ + + +/************************************************************************************//** +** \brief Obtains a pointer to the firmware segment at the specified index. +** \return Pointer to firmware segment. +** +****************************************************************************************/ +static const tFirmwareSegment *SRecParserGetSegment(uint32_t segmentIdx) +{ + /* validate the parameter */ + assert(segmentIdx < SRecParserSegmentListGetNodeCount()); + + return &(SRecParserSegmentListGetNode(segmentIdx)->segment); +} /*** end of SRecParserGetSegment ***/ + + +/************************************************************************************//** +** \brief Initializes the linked list with firmware segments. +** \return None. +** +****************************************************************************************/ +static void SRecParserSegmentListInit(void) +{ + segmentList = NULL; +} /*** end of SRecParserSegmentListInit ***/ + + +/************************************************************************************//** +** \brief Uninitializes the linked list with firmware segments. +** \return None. +** +****************************************************************************************/ +static void SRecParserSegmentListDeinit(void) +{ + tSegmentNode *currentNode; + tSegmentNode *nodeToFree; + + /* free all nodes */ + if (segmentList != NULL) + { + currentNode = segmentList; + do + { + /* store pointer to the node that should be released for later usage */ + nodeToFree = currentNode; + /* move to the next node before freeing it */ + currentNode = currentNode->next; + /* sanity check */ + assert(nodeToFree != NULL); + /* free the node */ + if (nodeToFree->segment.data != NULL) + { + free(nodeToFree->segment.data); + } + free(nodeToFree); + } + while(currentNode != NULL); + } +} /*** end of SRecParserSegmentListDeinit ***/ + + +/************************************************************************************//** +** \brief Creates a new node in the linked list with firmware segments. +** \return Pointer to the new node. +** +****************************************************************************************/ +static tSegmentNode *SRecParserSegmentListCreateNode(void) +{ + tSegmentNode *newNode; + tSegmentNode *currentNode; + + /* allocate memory for the node */ + newNode = malloc(sizeof(tSegmentNode)); + assert(newNode != NULL); + + /* initialize the node */ + newNode->next = NULL; + newNode->segment.base = 0x00000000; + newNode->segment.length = 0; + newNode->segment.data = NULL; + + /* add the first node if the list is empty */ + if (segmentList == NULL) + { + segmentList = newNode; + } + /* add the node to the end of the list */ + else + { + /* find last entry in to list */ + currentNode = segmentList; + while(currentNode->next != NULL) + { + currentNode = currentNode->next; + } + /* add the now */ + currentNode->next = newNode; + } + + return newNode; +} /*** end of SRecParserSegmentListCreateNode ***/ + + +/************************************************************************************//** +** \brief Obtains the number of nodes in the linked list with firmware segments. +** \return Number of nodes. +** +****************************************************************************************/ +static uint32_t SRecParserSegmentListGetNodeCount(void) +{ + tSegmentNode *currentNode; + uint32_t nodeCount = 0; + + /* iterate over all nodes to determine to total count */ + if (segmentList != NULL) + { + currentNode = segmentList; + do + { + nodeCount++; + currentNode = currentNode->next; + } + while(currentNode != NULL); + } + + return nodeCount; +} /*** end of SRecParserSegmentListGetNodeCount ***/ + + +/************************************************************************************//** +** \brief Obtains the node at the specified index from the linked list with firmware +** segments. +** \return Pointer to the node. +** +****************************************************************************************/ +static tSegmentNode *SRecParserSegmentListGetNode(uint32_t nodeIdx) +{ + tSegmentNode *currentNode = NULL; + uint32_t currentIdx = 0; + + /* validate the parameter */ + assert(nodeIdx < SRecParserSegmentListGetNodeCount()); + + /* iterate until the specified index is found */ + currentNode = segmentList; + for (currentIdx=0; currentIdxnext; + } + + return currentNode; +} /*** end of SRecParserSegmentListGetNode ***/ + + +/************************************************************************************//** +** \brief Reads the next S-record with program data, parses it and returns the +** results. +** \param srecordHandle The S-record file handle. It is returned by SrecordOpen. +** \param parseResults Pointer to where the parse results should be stored. +** \return SB_TRUE is valid parse results were stored. SB_FALSE in case of end-of- +** file. +** +****************************************************************************************/ +static bool SrecordParseNextDataLine(FILE* srecordHandle, tSrecordLineParseResults *parseResults) +{ + char line[SRECORD_MAX_CHARS_PER_LINE]; + bool data_line_found = false; + tSrecordLineType lineType; + uint16_t bytes_on_line; + uint16_t i; + char *linePtr; + + /* first set the length paramter to 0 */ + parseResults->length = 0; + + while (!data_line_found) + { + /* read the next line from the file */ + if (!SrecordReadLine(srecordHandle, line)) + { + /* end-of-file encountered */ + return false; + } + /* we now have a line. check if it is a S-record data line */ + lineType = SrecordGetLineType(line); + if (lineType != LINE_TYPE_UNSUPPORTED) + { + /* check if the checksum on the line is correct */ + if (SrecordVerifyChecksum(line)) + { + /* found a valid line that can be parsed. loop will stop */ + data_line_found = true; + break; + } + } + } + + /* still here so we have a valid S-record data line. start parsing */ + linePtr = &line[0]; + /* all good so far, now read out the address and databytes for the line */ + switch (lineType) + { + /* ---------------------------- S1 line type ------------------------------------- */ + case LINE_TYPE_S1: + /* adjust pointer to point to byte count value */ + linePtr += 2; + /* read out the number of byte values that follow on the line */ + bytes_on_line = SrecordHexStringToByte(linePtr); + /* read out the 16-bit address */ + linePtr += 2; + parseResults->address = SrecordHexStringToByte(linePtr) << 8; + linePtr += 2; + parseResults->address += SrecordHexStringToByte(linePtr); + /* adjust pointer to point to the first data byte after the address */ + linePtr += 2; + /* determine how many data bytes are on the line */ + parseResults->length = bytes_on_line - 3; /* -2 bytes address, -1 byte checksum */ + /* read and store data bytes if requested */ + for (i=0; ilength; i++) + { + parseResults->data[i] = SrecordHexStringToByte(linePtr); + linePtr += 2; + } + break; + + /* ---------------------------- S2 line type ------------------------------------- */ + case LINE_TYPE_S2: + /* adjust pointer to point to byte count value */ + linePtr += 2; + /* read out the number of byte values that follow on the line */ + bytes_on_line = SrecordHexStringToByte(linePtr); + /* read out the 32-bit address */ + linePtr += 2; + parseResults->address = SrecordHexStringToByte(linePtr) << 16; + linePtr += 2; + parseResults->address += SrecordHexStringToByte(linePtr) << 8; + linePtr += 2; + parseResults->address += SrecordHexStringToByte(linePtr); + /* adjust pointer to point to the first data byte after the address */ + linePtr += 2; + /* determine how many data bytes are on the line */ + parseResults->length = bytes_on_line - 4; /* -3 bytes address, -1 byte checksum */ + /* read and store data bytes if requested */ + for (i=0; ilength; i++) + { + parseResults->data[i] = SrecordHexStringToByte(linePtr); + linePtr += 2; + } + break; + + /* ---------------------------- S3 line type ------------------------------------- */ + case LINE_TYPE_S3: + /* adjust pointer to point to byte count value */ + linePtr += 2; + /* read out the number of byte values that follow on the line */ + bytes_on_line = SrecordHexStringToByte(linePtr); + /* read out the 32-bit address */ + linePtr += 2; + parseResults->address = SrecordHexStringToByte(linePtr) << 24; + linePtr += 2; + parseResults->address += SrecordHexStringToByte(linePtr) << 16; + linePtr += 2; + parseResults->address += SrecordHexStringToByte(linePtr) << 8; + linePtr += 2; + parseResults->address += SrecordHexStringToByte(linePtr); + /* adjust pointer to point to the first data byte after the address */ + linePtr += 2; + /* determine how many data bytes are on the line */ + parseResults->length = bytes_on_line - 5; /* -4 bytes address, -1 byte checksum */ + /* read and store data bytes if requested */ + for (i=0; ilength; i++) + { + parseResults->data[i] = SrecordHexStringToByte(linePtr); + linePtr += 2; + } + break; + + default: + /* will not happen */ + break; + } + + /* parsing all done */ + return true; +} /*** end of SrecordParseNextDataLine ***/ + + +/************************************************************************************//** +** \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 tSrecordLineType SrecordGetLineType(const char *line) +{ + /* check if the line starts with the 'S' character, followed by a digit */ + if ( (toupper(line[0]) != 'S') || (isdigit(line[1]) == 0) ) + { + /* not a valid S-Record line type */ + return LINE_TYPE_UNSUPPORTED; + } + /* determine the line type */ + if (line[1] == '1') + { + return LINE_TYPE_S1; + } + if (line[1] == '2') + { + return LINE_TYPE_S2; + } + if (line[1] == '3') + { + return LINE_TYPE_S3; + } + /* still here so not a supported line type found */ + return LINE_TYPE_UNSUPPORTED; +} /*** end of SrecordGetLineType ***/ + + +/************************************************************************************//** +** \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 SB_TRUE if the checksum is correct, SB_FALSE otherwise. +** +****************************************************************************************/ +static bool SrecordVerifyChecksum(const char *line) +{ + uint16_t bytes_on_line; + uint8_t checksum = 0; + + /* adjust pointer to point to byte count value */ + line += 2; + /* read out the number of byte values that follow on the line */ + bytes_on_line = SrecordHexStringToByte(line); + /* byte count is part of checksum */ + checksum += bytes_on_line; + /* adjust pointer to the first byte of the address */ + line += 2; + /* add byte values of address and data, but not the final checksum */ + do + { + /* add the next byte value to the checksum */ + checksum += SrecordHexStringToByte(line); + /* update counter */ + bytes_on_line--; + /* point to next hex string in the line */ + line += 2; + } + while (bytes_on_line > 1); + /* the checksum is calculated by summing up the values of the byte count, address and + * databytes and then taking the 1-complement of the sum's least signigicant byte */ + checksum = ~checksum; + /* finally verify the calculated checksum with the one at the end of the line */ + if (checksum != SrecordHexStringToByte(line)) + { + /* checksum incorrect */ + return false; + } + /* still here so the checksum was correct */ + return true; +} /*** end of SrecordVerifyChecksum ***/ + + +/************************************************************************************//** +** \brief Helper function to convert a sequence of 2 characters that represent +** a hexadecimal value to the actual byte value. +** Example: SrecordHexStringToByte("2f") --> returns 47. +** \param hexstring String beginning with 2 characters that represent a hexa- +** decimal value. +** \return The resulting byte value. +** +****************************************************************************************/ +static uint8_t SrecordHexStringToByte(const char *hexstring) +{ + uint8_t result = 0; + char c; + uint8_t counter; + + /* a hexadecimal character is 2 characters long (i.e 0x4F minus the 0x part) */ + for (counter=0; counter < 2; counter++) + { + /* read out the character */ + c = toupper(hexstring[counter]); + /* check that the character is 0..9 or A..F */ + if ( (c < '0') || (c > 'F') || ( (c > '9') && (c < 'A') ) ) + { + /* character not valid */ + return 0; + } + /* convert character to 4-bit value (check ASCII table for more info) */ + c -= '0'; + if (c > 9) + { + c -= 7; + } + /* add it to the result */ + result = (result << 4) + c; + } + /* return the results */ + return result; +} /*** end of SrecordHexStringToByte ***/ + + +/************************************************************************************//** +** \brief Reads the next line from the S-record file handle. +** \param srecordHandle The S-record file handle. It is returned by SrecordOpen. +** \param line Destination buffer for the line characters. Should be of size +** SRECORD_MAX_CHARS_PER_LINE. +** \return SB_TRUE if successful, SB_FALSE otherwise. +** +****************************************************************************************/ +static bool SrecordReadLine(FILE *srecordHandle, char *line) +{ + /* init the line as an empty line */ + line[0] = '\0'; + + /* loop as long as we find a non-empty line or end-of-file */ + while (line[0] == '\0') + { + if (fgets(line, SRECORD_MAX_CHARS_PER_LINE, srecordHandle) == NULL) + { + /* no more lines available */ + return false; + } + /* replace the line termination with a string termination */ + line[strcspn(line, "\n")] = '\0'; + } + /* still here so not EOF and not and empty line, so success */ + return true; +} /*** end of SrecordReadLine ***/ + + +/*********************************** end of srecparser.c *******************************/ + diff --git a/Host/Source/SerialBoot/port/xcptransport.h b/Host/Source/SerialBoot/srecparser.h similarity index 69% rename from Host/Source/SerialBoot/port/xcptransport.h rename to Host/Source/SerialBoot/srecparser.h index 52e5186a..b38e0a2f 100644 --- a/Host/Source/SerialBoot/port/xcptransport.h +++ b/Host/Source/SerialBoot/srecparser.h @@ -1,51 +1,52 @@ -/************************************************************************************//** -* \file port\xcptransport.h -* \brief XCP transport layer interface header file. -* \ingroup SerialBoot -* \internal -*---------------------------------------------------------------------------------------- -* C O P Y R I G H T -*---------------------------------------------------------------------------------------- -* Copyright (c) 2014 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 XCPTRANSPORT_H -#define XCPTRANSPORT_H - -/**************************************************************************************** -* Type definitions -****************************************************************************************/ -typedef struct -{ - sb_uint8 data[XCP_MASTER_RX_MAX_DATA]; - sb_uint8 len; -} tXcpTransportResponsePacket; - - -/**************************************************************************************** -* EFunction prototypes -****************************************************************************************/ -sb_uint8 XcpTransportInit(sb_char *device, sb_uint32 baudrate); -sb_uint8 XcpTransportSendPacket(sb_uint8 *data, sb_uint8 len, sb_uint16 timeOutMs); -tXcpTransportResponsePacket *XcpTransportReadResponsePacket(void); -void XcpTransportClose(void); - - -#endif /* XCPTRANSPORT_H */ -/*********************************** end of xcptransport.h *****************************/ +/************************************************************************************//** +* \file srecparser.h +* \brief S-record parser header file. +* \ingroup SerialBoot +* \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 + +/**************************************************************************************** +* Include files +****************************************************************************************/ +#include "firmware.h" /* firmware module */ + + +/**************************************************************************************** +* Function prototypes +****************************************************************************************/ +tFirmwareParser const * const SRecParserGetParser(void); + +#ifdef __cplusplus +} +#endif + +#endif /* SRECPARSER_H */ +/********************************* end of srecparser.h *********************************/ + diff --git a/Host/Source/SerialBoot/port/timeutil.h b/Host/Source/SerialBoot/timeutil.h similarity index 76% rename from Host/Source/SerialBoot/port/timeutil.h rename to Host/Source/SerialBoot/timeutil.h index bb40a8db..911b0d17 100644 --- a/Host/Source/SerialBoot/port/timeutil.h +++ b/Host/Source/SerialBoot/timeutil.h @@ -1,39 +1,52 @@ -/************************************************************************************//** -* \file port\timeutil.h -* \brief Time utility header file. -* \ingroup SerialBoot -* \internal -*---------------------------------------------------------------------------------------- -* C O P Y R I G H T -*---------------------------------------------------------------------------------------- -* Copyright (c) 2014 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 TIMEUTIL_H -#define TIMEUTIL_H - -/**************************************************************************************** -* Function prototypes -****************************************************************************************/ -sb_uint32 TimeUtilGetSystemTimeMs(void); -void TimeUtilDelayMs(sb_uint16 delay); - - -#endif /* TIMEUTIL_H */ -/*********************************** end of timeutil.h *********************************/ +/************************************************************************************//** +* \file timeutil.h +* \brief Time utility header file. +* \ingroup SerialBoot +* \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 TIMEUTIL_H +#define TIMEUTIL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/**************************************************************************************** +* Include files +****************************************************************************************/ +#include /* for standard integer types */ + + +/**************************************************************************************** +* Function prototypes +****************************************************************************************/ +uint32_t TimeUtilGetSystemTimeMs(void); +void TimeUtilDelayMs(uint16_t delay); + +#ifdef __cplusplus +} +#endif + +#endif /* TIMEUTIL_H */ +/*********************************** end of timeutil.h *********************************/ diff --git a/Host/Source/SerialBoot/xcploader.c b/Host/Source/SerialBoot/xcploader.c new file mode 100644 index 00000000..40f63b86 --- /dev/null +++ b/Host/Source/SerialBoot/xcploader.c @@ -0,0 +1,755 @@ +/************************************************************************************//** +* \file xcploader.c +* \brief XCP Loader module source file. +* \ingroup SerialBoot +* \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 /* for NULL declaration */ +#include /* for assertions */ +#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 (0xFF) /**< XCP connect command code. */ +#define XCPLOADER_CMD_DISCONNECT (0xFE) /**< XCP disconnect command code. */ +#define XCPLOADER_CMD_SET_MTA (0xF6) /**< XCP set mta command code. */ +#define XCPLOADER_CMD_UPLOAD (0xF5) /**< XCP upload command code. */ +#define XCPLOADER_CMD_PROGRAM_START (0xD2) /**< XCP program start command code. */ +#define XCPLOADER_CMD_PROGRAM_CLEAR (0xD1) /**< XCP program clear command code. */ +#define XCPLOADER_CMD_PROGRAM (0xD0) /**< XCP program command code. */ +#define XCPLOADER_CMD_PROGRAM_RESET (0xCF) /**< XCP program reset command code. */ +#define XCPLOADER_CMD_PROGRAM_MAX (0xC9) /**< XCP program max command code. */ + +/* XCP response packet IDs as defined by the protocol. */ +#define XCPLOADER_CMD_PID_RES (0xFF) /**< positive response */ + +/** \brief Maximum timeout for the XCP connect command. */ +#define XCPLOADER_CONNECT_TIMEOUT_MS (20) + +/** \brief Number of retries to connect to the XCP slave. */ +#define XCPLOADER_CONNECT_RETRIES (5) + + +/**************************************************************************************** +* Function prototypes +****************************************************************************************/ +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 *data); +static bool XcpLoaderSendCmdProgramMax(uint8_t *data); +static bool XcpLoaderSendCmdProgramClear(uint32_t length); +static void XcpLoaderSetOrderedLong(uint32_t value, uint8_t *data); + + +/**************************************************************************************** +* Local data declarations +****************************************************************************************/ +/** \brief Pointer to the XCP transport layer that is linked. */ +static tXcpTransport const * transportPtr = NULL; + +/** \brief The settings that should be used by the XCP loader. */ +static tXcpSettings 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 Initializes the loader module. +** \param settings Pointer to settings structure. +** \param transport Pointer to the transport layer to link. +** \param tpsettings Pointer to transport layer settings structure. +** \return None. +** +****************************************************************************************/ +void XcpLoaderInit(tXcpSettings *settings, tXcpTransport const * const transport, void *tpsettings) +{ + /* verify parameters */ + assert(transport != NULL); + assert(tpsettings != NULL); + assert(settings != NULL); + + /* shallow copy the XCP settings for later usage */ + xcpSettings = *settings; + /* link the XCP transport layer */ + transportPtr = transport; + /* initialize the transport layer */ + transportPtr->Init(tpsettings); + /* init locals */ + xcpConnected = false; + xcpSlaveIsIntel = false; + xcpMaxCto = 0; + xcpMaxProgCto = 0; + xcpMaxDto = 0; +} /*** end of XcpLoaderInit ***/ + + +/************************************************************************************//** +** \brief Uninitializes the loader module. +** \return None. +** +****************************************************************************************/ +void XcpLoaderDeinit(void) +{ + /* make sure the XCP transport layer is linked */ + assert(transportPtr != NULL); + + /* disconnect */ + XcpLoaderDisconnect(); + /* uninitialize the transport layer */ + transportPtr->Deinit(); + /* unlink the transport layer */ + transportPtr = NULL; +} /*** end of XcpLoaderDeinit ***/ + + +/************************************************************************************//** +** \brief Connect to the XCP slave. +** \return True is successful, false otherwise. +** +****************************************************************************************/ +bool XcpLoaderConnect(void) +{ + uint8_t retryCnt; + + /* make sure the XCP transport layer is linked */ + assert(transportPtr != NULL); + + /* make sure that we are disconnected before connecting */ + XcpLoaderDisconnect(); + + /* connect the transport layer */ + if (!transportPtr->Connect()) + { + return false; + } + + /* try to connect with a finite amount of retries */ + for (retryCnt=0; retryCntDisconnect(); + return false; +} /*** end of XcpLoaderConnect ***/ + + +/***********************************************************************************//** +** \brief Disconnect from the XCP slave. +** \return None. +** +****************************************************************************************/ +void XcpLoaderDisconnect(void) +{ + /* make sure the XCP transport layer is linked */ + assert(transportPtr != NULL); + + /* only disconnect if actually connected */ + if (xcpConnected) + { + /* send reset command instead of the disconnect. this causes the user program on the + * slave to automatically start again if present. + */ + XcpLoaderSendCmdProgramReset(); + /* disconnect the transport layer */ + transportPtr->Disconnect(); + /* reset connection status */ + xcpConnected = false; + } +} /*** end of XcpLoaderDisconnect ***/ + + +/************************************************************************************//** +** \brief Puts a connected slave in programming session. +** \return True is successful, false otherwise. +** +****************************************************************************************/ +bool XcpLoaderStartProgrammingSession(void) +{ + /* make sure the XCP transport layer is linked */ + assert(transportPtr != NULL); + + /* place the slave in programming mode */ + return XcpLoaderSendCmdProgramStart(); +} /*** end of XcpLoaderStartProgrammingSession ***/ + + +/************************************************************************************//** +** \brief Stops the programming session by sending a program command with size 0 and +** then resetting the slave. +** \return True is successful, false otherwise. +** +****************************************************************************************/ +bool XcpLoaderStopProgrammingSession(void) +{ + /* make sure the XCP transport layer is linked */ + assert(transportPtr != NULL); + + /* stop programming by sending the program command with size 0 */ + return XcpLoaderSendCmdProgram(0, NULL); +} /*** end of XcpLoaderStopProgrammingSession ***/ + + +/************************************************************************************//** +** \brief Erases non volatile memory on the slave. +** \param addr Base memory address for the erase operation. +** \param len Number of bytes to erase. +** \return True is successful, false otherwise. +** +****************************************************************************************/ +bool XcpLoaderClearMemory(uint32_t addr, uint32_t len) +{ + /* make sure the XCP transport layer is linked */ + assert(transportPtr != NULL); + /* verify parameters */ + assert(len > 0); + + /* first set the MTA pointer */ + if (!XcpLoaderSendCmdSetMta(addr)) + { + return false; + } + /* now perform the erase operation */ + return XcpLoaderSendCmdProgramClear(len); +} /*** end of XcpLoaderClearMemory ***/ + + +/***********************************************************************************//** +** \brief Reads data from the slave's memory. +** \param addr Base memory address for the read operation +** \param len Number of bytes to read. +** \param data Destination buffer for storing the read data bytes. +** \return True is successful, false otherwise. +** +****************************************************************************************/ +bool XcpLoaderReadData(uint32_t addr, uint32_t len, uint8_t *data) +{ + uint8_t currentReadCnt; + uint32_t bufferOffset = 0; + + /* make sure the XCP transport layer is linked */ + assert(transportPtr != NULL); + /* verify parameters */ + assert(data != NULL); + assert(len > 0); + + /* first set the MTA pointer */ + if (!XcpLoaderSendCmdSetMta(addr)) + { + return false; + } + /* perform segmented upload of the data */ + while (len > 0) + { + /* set the current read length to make optimal use of the available packet data. */ + currentReadCnt = len % (xcpMaxDto - 1); + if (currentReadCnt == 0) + { + currentReadCnt = (xcpMaxDto - 1); + } + /* upload some data */ + if (!XcpLoaderSendCmdUpload(&data[bufferOffset], currentReadCnt)) + { + return false; + } + /* update loop variables */ + len -= currentReadCnt; + bufferOffset += currentReadCnt; + } + /* still here so all data successfully read from the slave */ + return true; +} /*** end of XcpLoaderReadData ***/ + + +/************************************************************************************//** +** \brief Programs data to the slave's non volatile memory. Note that it must be +** erased first. +** \param addr Base memory address for the program operation +** \param len Number of bytes to program. +** \param data Source buffer with the to be programmed bytes. +** \return True is successful, false otherwise. +** +****************************************************************************************/ +bool XcpLoaderProgramData(uint32_t addr, uint32_t len, uint8_t *data) +{ + uint8_t currentWriteCnt; + uint32_t bufferOffset = 0; + + /* make sure the XCP transport layer is linked */ + assert(transportPtr != NULL); + /* verify parameters */ + assert(data != NULL); + assert(len > 0); + + /* first set the MTA pointer */ + if (!XcpLoaderSendCmdSetMta(addr)) + { + return false; + } + /* perform segmented programming of the data */ + while (len > 0) + { + /* set the current read length to make optimal use of the available packet data. */ + currentWriteCnt = len % (xcpMaxProgCto - 1); + if (currentWriteCnt == 0) + { + currentWriteCnt = (xcpMaxProgCto - 1); + } + /* prepare the packed data for the program command */ + if (currentWriteCnt < (xcpMaxProgCto - 1)) + { + /* program data */ + if (!XcpLoaderSendCmdProgram(currentWriteCnt, &data[bufferOffset])) + { + return false; + } + } + else + { + /* program max data */ + if (!XcpLoaderSendCmdProgramMax(&data[bufferOffset])) + { + return false; + } + } + /* update loop variables */ + len -= currentWriteCnt; + bufferOffset += currentWriteCnt; + } + /* still here so all data successfully programmed */ + return true; +} /*** end of XcpLoaderProgramData ***/ + + +/************************************************************************************//** +** \brief Sends the XCP Connect command. +** \return True if successful, false otherwise. +** +****************************************************************************************/ +static bool XcpLoaderSendCmdConnect(void) +{ + tXcpPacket cmdPacket; + tXcpPacket resPacket; + + /* prepare the command packet */ + cmdPacket.data[0] = XCPLOADER_CMD_CONNECT; + cmdPacket.data[1] = 0; /* normal mode */ + cmdPacket.len = 2; + + /* send the packet */ + if (!transportPtr->SendPacket(&cmdPacket, &resPacket, XCPLOADER_CONNECT_TIMEOUT_MS)) + { + /* could not send packet or receive response within the specified timeout */ + return false; + } + + /* still here so a response was received. check if the reponse was valid */ + if ( (resPacket.len == 0) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) ) + { + /* not a valid or positive response */ + return false; + } + + /* process response data */ + if ((resPacket.data[2] & 0x01) == 0) + { + /* store slave's byte ordering information */ + xcpSlaveIsIntel = true; + } + /* 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 */ + assert(XCPLOADER_PACKET_SIZE_MAX >= xcpMaxCto); + assert(XCPLOADER_PACKET_SIZE_MAX >= xcpMaxDto); + + /* still here so all went well */ + return true; +} /*** 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) +{ + tXcpPacket cmdPacket; + tXcpPacket resPacket; + + /* 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 (!transportPtr->SendPacket(&cmdPacket, &resPacket, xcpSettings.timeoutT1)) + { + /* could not send packet or receive response within the specified timeout */ + return false; + } + + /* still here so a response was received. check if the reponse was valid */ + if ( (resPacket.len == 0) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) ) + { + /* not a valid or positive response */ + return false; + } + + /* still here so all went well */ + return true; +} /*** 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) +{ + tXcpPacket cmdPacket; + tXcpPacket resPacket; + uint8_t data_index; + + /* cannot request more data then the max rx data - 1 */ + assert(length < XCPLOADER_PACKET_SIZE_MAX); + assert(data != NULL); + + /* prepare the command packet */ + cmdPacket.data[0] = XCPLOADER_CMD_UPLOAD; + cmdPacket.data[1] = length; + cmdPacket.len = 2; + + /* send the packet */ + if (!transportPtr->SendPacket(&cmdPacket, &resPacket, xcpSettings.timeoutT1)) + { + /* could not send packet or receive response within the specified timeout */ + return false; + } + + /* still here so a response was received. check if the reponse was valid */ + if ( (resPacket.len == 0) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) ) + { + /* not a valid or positive response */ + return false; + } + + /* now store the uploaded data */ + for (data_index=0; data_indexSendPacket(&cmdPacket, &resPacket, xcpSettings.timeoutT3)) + { + /* could not send packet or receive response within the specified timeout */ + return false; + } + + /* still here so a response was received. check if the reponse was valid */ + if ( (resPacket.len == 0) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) ) + { + /* not a valid or positive response */ + return false; + } + + /* store max number of bytes the slave allows for master->slave packets during the + * programming session + */ + xcpMaxProgCto = resPacket.data[3]; + + /* still here so all went well */ + return true; +} /*** 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) +{ + tXcpPacket cmdPacket; + tXcpPacket resPacket; + + /* prepare the command packet */ + cmdPacket.data[0] = XCPLOADER_CMD_PROGRAM_RESET; + cmdPacket.len = 1; + + /* send the packet, assume the sending itself is ok and check if a response was + * received. + */ + if (!transportPtr->SendPacket(&cmdPacket, &resPacket, xcpSettings.timeoutT5)) + { + /* probably no response received within the specified timeout, but that is allowed + * for the reset command. + */ + return true; + } + + /* still here so a response was received. check if the reponse was valid */ + if ( (resPacket.len == 0) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) ) + { + /* not a valid or positive response */ + return false; + } + + /* still here so all went well */ + return true; +} /*** 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 *data) +{ + tXcpPacket cmdPacket; + tXcpPacket resPacket; + uint8_t cnt; + + /* verify that this number of bytes actually first in this command */ + assert(length <= (xcpMaxProgCto-2) && (xcpMaxProgCto <= XCPLOADER_PACKET_SIZE_MAX)); + if (length > 0) + { + assert(data != NULL); + } + + /* prepare the command packet */ + cmdPacket.data[0] = XCPLOADER_CMD_PROGRAM; + cmdPacket.data[1] = length; + for (cnt=0; cntSendPacket(&cmdPacket, &resPacket, xcpSettings.timeoutT5)) + { + /* could not send packet or receive response within the specified timeout */ + return false; + } + + /* still here so a response was received. check if the reponse was valid */ + if ( (resPacket.len == 0) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) ) + { + /* not a valid or positive response */ + return false; + } + + /* still here so all went well */ + return true; +} /*** 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 *data) +{ + tXcpPacket cmdPacket; + tXcpPacket resPacket; + uint8_t cnt; + + /* verify that this number of bytes actually first in this command */ + assert(xcpMaxProgCto <= XCPLOADER_PACKET_SIZE_MAX); + assert(data != NULL); + + /* 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 (!transportPtr->SendPacket(&cmdPacket, &resPacket, xcpSettings.timeoutT5)) + { + /* could not send packet or receive response within the specified timeout */ + return false; + } + + /* still here so a response was received. check if the reponse was valid */ + if ( (resPacket.len == 0) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) ) + { + /* not a valid or positive response */ + return false; + } + + /* still here so all went well */ + return true; +} /*** 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) +{ + tXcpPacket cmdPacket; + tXcpPacket resPacket; + + /* prepare 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 (!transportPtr->SendPacket(&cmdPacket, &resPacket, xcpSettings.timeoutT4)) + { + /* could not send packet or receive response within the specified timeout */ + return false; + } + + /* still here so a response was received. check if the reponse was valid */ + if ( (resPacket.len == 0) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) ) + { + /* not a valid or positive response */ + return false; + } + + /* still here so all went well */ + return true; +} /*** end of XcpLoaderSendCmdProgramClear ***/ + + +/************************************************************************************//** +** \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. +** \return None. +** +****************************************************************************************/ +static void XcpLoaderSetOrderedLong(uint32_t value, uint8_t *data) +{ + 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 ***/ + + +/*********************************** end of xcploader.c ********************************/ + diff --git a/Host/Source/SerialBoot/xcploader.h b/Host/Source/SerialBoot/xcploader.h new file mode 100644 index 00000000..da586aee --- /dev/null +++ b/Host/Source/SerialBoot/xcploader.h @@ -0,0 +1,108 @@ +/************************************************************************************//** +* \file xcploader.h +* \brief XCP Loader module header file. +* \ingroup SerialBoot +* \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 XCPLOADER_H +#define XCPLOADER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/**************************************************************************************** +* Include files +****************************************************************************************/ +#include /* for standard integer types */ +#include /* for boolean type */ + + +/**************************************************************************************** +* 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 (255) + + +/**************************************************************************************** +* Type definitions +****************************************************************************************/ +/** \brief XCP protocol specific settings. */ +typedef struct t_xcp_settings +{ + 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. */ +} tXcpSettings; + + +/** \brief XCP packet type. */ +typedef struct t_xcp_packet +{ + uint8_t data[XCPLOADER_PACKET_SIZE_MAX]; /**< Packet data. */ + uint8_t len; /**< Packet length. */ +} tXcpPacket; + + +/** \brief XCP transport layer. */ +typedef struct t_xcp_transport +{ + /** \brief Initialization of the XCP transpor layer. */ + void (*Init) (void *settings); + /** \brief Uninitializes the XCP transpor layer. */ + void (*Deinit) (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) (tXcpPacket *txPacket, tXcpPacket *rxPacket, uint16_t timeout); +} tXcpTransport; + + +/**************************************************************************************** +* Function prototypes +****************************************************************************************/ +void XcpLoaderInit(tXcpSettings *settings, tXcpTransport const * const transport, void *tpsettings); +void XcpLoaderDeinit(void); +bool XcpLoaderConnect(void); +void XcpLoaderDisconnect(void); +bool XcpLoaderStartProgrammingSession(void); +bool XcpLoaderStopProgrammingSession(void); +bool XcpLoaderClearMemory(uint32_t addr, uint32_t len); +bool XcpLoaderReadData(uint32_t addr, uint32_t len, uint8_t *data); +bool XcpLoaderProgramData(uint32_t addr, uint32_t len, uint8_t *data); + +#ifdef __cplusplus +} +#endif + +#endif /* XCPLOADER_H */ +/********************************* end of xcploader.h **********************************/ + diff --git a/Host/Source/SerialBoot/xcpmaster.c b/Host/Source/SerialBoot/xcpmaster.c deleted file mode 100644 index 62f1ccd8..00000000 --- a/Host/Source/SerialBoot/xcpmaster.c +++ /dev/null @@ -1,689 +0,0 @@ -/************************************************************************************//** -* \file xcpmaster.c -* \brief XCP Master source file. -* \ingroup SerialBoot -* \internal -*---------------------------------------------------------------------------------------- -* C O P Y R I G H T -*---------------------------------------------------------------------------------------- -* Copyright (c) 2014 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 /* assertion module */ -#include /* C types */ -#include "xcpmaster.h" /* XCP master protocol module */ - - -/**************************************************************************************** -* Macro definitions -****************************************************************************************/ -/* XCP command codes as defined by the protocol currently supported by this module */ -#define XCP_MASTER_CMD_CONNECT (0xFF) -#define XCP_MASTER_CMD_DISCONNECT (0xFE) -#define XCP_MASTER_CMD_SET_MTA (0xF6) -#define XCP_MASTER_CMD_UPLOAD (0xF5) -#define XCP_MASTER_CMD_PROGRAM_START (0xD2) -#define XCP_MASTER_CMD_PROGRAM_CLEAR (0xD1) -#define XCP_MASTER_CMD_PROGRAM (0xD0) -#define XCP_MASTER_CMD_PROGRAM_RESET (0xCF) -#define XCP_MASTER_CMD_PROGRAM_MAX (0xC9) - -/* XCP response packet IDs as defined by the protocol */ -#define XCP_MASTER_CMD_PID_RES (0xFF) /* positive response */ - -/* timeout values */ -#define XCP_MASTER_CONNECT_TIMEOUT_MS (20) -#define XCP_MASTER_TIMEOUT_T1_MS (1000) /* standard command timeout */ -#define XCP_MASTER_TIMEOUT_T2_MS (2000) /* build checksum timeout */ -#define XCP_MASTER_TIMEOUT_T3_MS (2000) /* program start timeout */ -#define XCP_MASTER_TIMEOUT_T4_MS (10000) /* erase timeout */ -#define XCP_MASTER_TIMEOUT_T5_MS (1000) /* write and reset timeout */ -#define XCP_MASTER_TIMEOUT_T6_MS (1000) /* user specific connect connect timeout */ -#define XCP_MASTER_TIMEOUT_T7_MS (2000) /* wait timer timeout */ - -/** \brief Number of retries to connect to the XCP slave. */ -#define XCP_MASTER_CONNECT_RETRIES (5) - - -/**************************************************************************************** -* Function prototypes -****************************************************************************************/ -static sb_uint8 XcpMasterSendCmdConnect(void); -static sb_uint8 XcpMasterSendCmdSetMta(sb_uint32 address); -static sb_uint8 XcpMasterSendCmdUpload(sb_uint8 data[], sb_uint8 length); -static sb_uint8 XcpMasterSendCmdProgramStart(void); -static sb_uint8 XcpMasterSendCmdProgramReset(void); -static sb_uint8 XcpMasterSendCmdProgram(sb_uint8 length, sb_uint8 data[]); -static sb_uint8 XcpMasterSendCmdProgramMax(sb_uint8 data[]); -static sb_uint8 XcpMasterSendCmdProgramClear(sb_uint32 length); -static void XcpMasterSetOrderedLong(sb_uint32 value, sb_uint8 data[]); - - -/**************************************************************************************** -* Local data declarations -****************************************************************************************/ -/** \brief Store the byte ordering of the XCP slave. */ -static sb_uint8 xcpSlaveIsIntel = SB_FALSE; - -/** \brief The max number of bytes in the command transmit object (master->slave). */ -static sb_uint8 xcpMaxCto; - -/** \brief The max number of bytes in the command transmit object (master->slave) during - * a programming session. - */ -static sb_uint8 xcpMaxProgCto = 0; - -/** \brief The max number of bytes in the data transmit object (slave->master). */ -static sb_uint8 xcpMaxDto; - -/** \brief Internal data buffer for storing the data of the XCP response packet. */ -static tXcpTransportResponsePacket responsePacket; - - -/************************************************************************************//** -** \brief Initializes the XCP master protocol layer. -** \param device Serial communication device name. For example "COM4". -** \param baudrate Communication speed in bits/sec. -** \return SB_TRUE is successful, SB_FALSE otherwise. -** -****************************************************************************************/ -sb_uint8 XcpMasterInit(sb_char *device, sb_uint32 baudrate) -{ - /* initialize the underlying transport layer that is used for the communication */ - return XcpTransportInit(device, baudrate); -} /*** end of XcpMasterInit ***/ - - -/************************************************************************************//** -** \brief Uninitializes the XCP master protocol layer. -** \return none. -** -****************************************************************************************/ -void XcpMasterDeinit(void) -{ - XcpTransportClose(); -} /*** end of XcpMasterDeinit ***/ - - -/************************************************************************************//** -** \brief Connect to the XCP slave. -** \return SB_TRUE is successfull, SB_FALSE otherwise. -** -****************************************************************************************/ -sb_uint8 XcpMasterConnect(void) -{ - sb_uint8 cnt; - - /* try to connect with a finite amount of retries */ - for (cnt=0; cnt 0) - { - /* set the current read length to make optimal use of the available packet data. */ - currentReadCnt = len % (xcpMaxDto - 1); - if (currentReadCnt == 0) - { - currentReadCnt = (xcpMaxDto - 1); - } - /* upload some data */ - if (XcpMasterSendCmdUpload(&data[bufferOffset], currentReadCnt) == SB_FALSE) - { - return SB_FALSE; - } - /* update loop variables */ - len -= currentReadCnt; - bufferOffset += currentReadCnt; - } - /* still here so all data successfully read from the slave */ - return SB_TRUE; -} /*** end of XcpMasterReadData ***/ - - -/************************************************************************************//** -** \brief Programs data to the slave's non volatile memory. Note that it must be -** erased first. -** \param addr Base memory address for the program operation -** \param len Number of bytes to program. -** \param data Source buffer with the to be programmed bytes. -** \return SB_TRUE is successfull, SB_FALSE otherwise. -** -****************************************************************************************/ -sb_uint8 XcpMasterProgramData(sb_uint32 addr, sb_uint32 len, sb_uint8 data[]) -{ - sb_uint8 currentWriteCnt; - sb_uint32 bufferOffset = 0; - - /* first set the MTA pointer */ - if (XcpMasterSendCmdSetMta(addr) == SB_FALSE) - { - return SB_FALSE; - } - /* perform segmented programming of the data */ - while (len > 0) - { - /* set the current read length to make optimal use of the available packet data. */ - currentWriteCnt = len % (xcpMaxProgCto - 1); - if (currentWriteCnt == 0) - { - currentWriteCnt = (xcpMaxProgCto - 1); - } - /* prepare the packed data for the program command */ - if (currentWriteCnt < (xcpMaxProgCto - 1)) - { - /* program data */ - if (XcpMasterSendCmdProgram(currentWriteCnt, &data[bufferOffset]) == SB_FALSE) - { - return SB_FALSE; - } - } - else - { - /* program max data */ - if (XcpMasterSendCmdProgramMax(&data[bufferOffset]) == SB_FALSE) - { - return SB_FALSE; - } - } - /* update loop variables */ - len -= currentWriteCnt; - bufferOffset += currentWriteCnt; - } - /* still here so all data successfully programmed */ - return SB_TRUE; -} /*** end of XcpMasterProgramData ***/ - - -/************************************************************************************//** -** \brief Sends the XCP Connect command. -** \return SB_TRUE is successfull, SB_FALSE otherwise. -** -****************************************************************************************/ -static sb_uint8 XcpMasterSendCmdConnect(void) -{ - sb_uint8 packetData[2]; - tXcpTransportResponsePacket *responsePacketPtr; - - /* prepare the command packet */ - packetData[0] = XCP_MASTER_CMD_CONNECT; - packetData[1] = 0; /* normal mode */ - - /* send the packet */ - if (XcpTransportSendPacket(packetData, 2, XCP_MASTER_CONNECT_TIMEOUT_MS) == SB_FALSE) - { - /* cound not set packet or receive response within the specified timeout */ - return SB_FALSE; - } - /* still here so a response was received */ - responsePacketPtr = XcpTransportReadResponsePacket(); - - /* check if the reponse was valid */ - if ( (responsePacketPtr->len == 0) || (responsePacketPtr->data[0] != XCP_MASTER_CMD_PID_RES) ) - { - /* not a valid or positive response */ - return SB_FALSE; - } - - /* process response data */ - if ((responsePacketPtr->data[2] & 0x01) == 0) - { - /* store slave's byte ordering information */ - xcpSlaveIsIntel = SB_TRUE; - } - /* store max number of bytes the slave allows for master->slave packets. */ - xcpMaxCto = responsePacketPtr->data[3]; - xcpMaxProgCto = xcpMaxCto; - /* store max number of bytes the slave allows for slave->master packets. */ - if (xcpSlaveIsIntel == SB_TRUE) - { - xcpMaxDto = responsePacketPtr->data[4] + (responsePacketPtr->data[5] << 8); - } - else - { - xcpMaxDto = responsePacketPtr->data[5] + (responsePacketPtr->data[4] << 8); - } - - /* double check size configuration of the master */ - assert(XCP_MASTER_TX_MAX_DATA >= xcpMaxCto); - assert(XCP_MASTER_RX_MAX_DATA >= xcpMaxDto); - - /* still here so all went well */ - return SB_TRUE; -} /*** end of XcpMasterSendCmdConnect ***/ - - -/************************************************************************************//** -** \brief Sends the XCP Set MTA command. -** \param address New MTA address for the slave. -** \return SB_TRUE is successfull, SB_FALSE otherwise. -** -****************************************************************************************/ -static sb_uint8 XcpMasterSendCmdSetMta(sb_uint32 address) -{ - sb_uint8 packetData[8]; - tXcpTransportResponsePacket *responsePacketPtr; - - /* prepare the command packet */ - packetData[0] = XCP_MASTER_CMD_SET_MTA; - packetData[1] = 0; /* reserved */ - packetData[2] = 0; /* reserved */ - packetData[3] = 0; /* address extension not supported */ - - /* set the address taking into account byte ordering */ - XcpMasterSetOrderedLong(address, &packetData[4]); - - /* send the packet */ - if (XcpTransportSendPacket(packetData, 8, XCP_MASTER_TIMEOUT_T1_MS) == SB_FALSE) - { - /* cound not set packet or receive response within the specified timeout */ - return SB_FALSE; - } - /* still here so a response was received */ - responsePacketPtr = XcpTransportReadResponsePacket(); - - /* check if the reponse was valid */ - if ( (responsePacketPtr->len == 0) || (responsePacketPtr->data[0] != XCP_MASTER_CMD_PID_RES) ) - { - /* not a valid or positive response */ - return SB_FALSE; - } - - /* still here so all went well */ - return SB_TRUE; -} /*** end of XcpMasterSendCmdSetMta ***/ - - -/************************************************************************************//** -** \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 sb_uint8 XcpMasterSendCmdUpload(sb_uint8 data[], sb_uint8 length) -{ - sb_uint8 packetData[2]; - tXcpTransportResponsePacket *responsePacketPtr; - sb_uint8 data_index; - - /* cannot request more data then the max rx data - 1 */ - assert(length < XCP_MASTER_RX_MAX_DATA); - - /* prepare the command packet */ - packetData[0] = XCP_MASTER_CMD_UPLOAD; - packetData[1] = length; - - /* send the packet */ - if (XcpTransportSendPacket(packetData, 2, XCP_MASTER_TIMEOUT_T1_MS) == SB_FALSE) - { - /* cound not set packet or receive response within the specified timeout */ - return SB_FALSE; - } - /* still here so a response was received */ - responsePacketPtr = XcpTransportReadResponsePacket(); - - /* check if the reponse was valid */ - if ( (responsePacketPtr->len == 0) || (responsePacketPtr->data[0] != XCP_MASTER_CMD_PID_RES) ) - { - /* not a valid or positive response */ - return SB_FALSE; - } - - /* now store the uploaded data */ - for (data_index=0; data_indexdata[data_index+1]; - } - - /* still here so all went well */ - return SB_TRUE; -} /*** end of XcpMasterSendCmdUpload ***/ - - -/************************************************************************************//** -** \brief Sends the XCP PROGRAM START command. -** \return SB_TRUE is successfull, SB_FALSE otherwise. -** -****************************************************************************************/ -static sb_uint8 XcpMasterSendCmdProgramStart(void) -{ - sb_uint8 packetData[1]; - tXcpTransportResponsePacket *responsePacketPtr; - - /* prepare the command packet */ - packetData[0] = XCP_MASTER_CMD_PROGRAM_START; - - /* send the packet */ - if (XcpTransportSendPacket(packetData, 1, XCP_MASTER_TIMEOUT_T3_MS) == SB_FALSE) - { - /* cound not set packet or receive response within the specified timeout */ - return SB_FALSE; - } - /* still here so a response was received */ - responsePacketPtr = XcpTransportReadResponsePacket(); - - /* check if the reponse was valid */ - if ( (responsePacketPtr->len == 0) || (responsePacketPtr->data[0] != XCP_MASTER_CMD_PID_RES) ) - { - /* not a valid or positive response */ - return SB_FALSE; - } - - /* store max number of bytes the slave allows for master->slave packets during the - * programming session - */ - xcpMaxProgCto = responsePacketPtr->data[3]; - - /* still here so all went well */ - return SB_TRUE; -} /*** end of XcpMasterSendCmdProgramStart ***/ - - -/************************************************************************************//** -** \brief Sends the XCP PROGRAM RESET command. Note that this command is a bit -** different as in it does not require a response. -** \return SB_TRUE is successfull, SB_FALSE otherwise. -** -****************************************************************************************/ -static sb_uint8 XcpMasterSendCmdProgramReset(void) -{ - sb_uint8 packetData[1]; - tXcpTransportResponsePacket *responsePacketPtr; - - /* prepare the command packet */ - packetData[0] = XCP_MASTER_CMD_PROGRAM_RESET; - - /* send the packet, assume the sending itself is ok and check if a response was - * received. - */ - if (XcpTransportSendPacket(packetData, 1, XCP_MASTER_TIMEOUT_T5_MS) == SB_FALSE) - { - /* probably no response received within the specified timeout, but that is allowed - * for the reset command. - */ - return SB_TRUE; - } - /* still here so a response was received */ - responsePacketPtr = XcpTransportReadResponsePacket(); - - /* check if the reponse was valid */ - if ( (responsePacketPtr->len == 0) || (responsePacketPtr->data[0] != XCP_MASTER_CMD_PID_RES) ) - { - /* not a valid or positive response */ - return SB_FALSE; - } - - /* still here so all went well */ - return SB_TRUE; -} /*** end of XcpMasterSendCmdProgramReset ***/ - - -/************************************************************************************//** -** \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 SB_TRUE is successfull, SB_FALSE otherwise. -** -****************************************************************************************/ -static sb_uint8 XcpMasterSendCmdProgram(sb_uint8 length, sb_uint8 data[]) -{ - sb_uint8 packetData[XCP_MASTER_TX_MAX_DATA]; - tXcpTransportResponsePacket *responsePacketPtr; - sb_uint8 cnt; - - /* verify that this number of bytes actually first in this command */ - assert(length <= (xcpMaxProgCto-2) && (xcpMaxProgCto <= XCP_MASTER_TX_MAX_DATA)); - - /* prepare the command packet */ - packetData[0] = XCP_MASTER_CMD_PROGRAM; - packetData[1] = length; - for (cnt=0; cntlen == 0) || (responsePacketPtr->data[0] != XCP_MASTER_CMD_PID_RES) ) - { - /* not a valid or positive response */ - return SB_FALSE; - } - - /* still here so all went well */ - return SB_TRUE; -} /*** end of XcpMasterSendCmdProgram ***/ - - -/************************************************************************************//** -** \brief Sends the XCP PROGRAM MAX command. -** \param data Array with data bytes to program. -** \return SB_TRUE is successfull, SB_FALSE otherwise. -** -****************************************************************************************/ -static sb_uint8 XcpMasterSendCmdProgramMax(sb_uint8 data[]) -{ - sb_uint8 packetData[XCP_MASTER_TX_MAX_DATA]; - tXcpTransportResponsePacket *responsePacketPtr; - sb_uint8 cnt; - - /* verify that this number of bytes actually first in this command */ - assert(xcpMaxProgCto <= XCP_MASTER_TX_MAX_DATA); - - /* prepare the command packet */ - packetData[0] = XCP_MASTER_CMD_PROGRAM_MAX; - for (cnt=0; cnt<(xcpMaxProgCto-1); cnt++) - { - packetData[cnt+1] = data[cnt]; - } - - /* send the packet */ - if (XcpTransportSendPacket(packetData, xcpMaxProgCto, XCP_MASTER_TIMEOUT_T5_MS) == SB_FALSE) - { - /* cound not set packet or receive response within the specified timeout */ - return SB_FALSE; - } - /* still here so a response was received */ - responsePacketPtr = XcpTransportReadResponsePacket(); - - /* check if the reponse was valid */ - if ( (responsePacketPtr->len == 0) || (responsePacketPtr->data[0] != XCP_MASTER_CMD_PID_RES) ) - { - /* not a valid or positive response */ - return SB_FALSE; - } - - /* still here so all went well */ - return SB_TRUE; -} /*** end of XcpMasterSendCmdProgramMax ***/ - - -/************************************************************************************//** -** \brief Sends the XCP PROGRAM CLEAR command. -** \return SB_TRUE is successfull, SB_FALSE otherwise. -** -****************************************************************************************/ -static sb_uint8 XcpMasterSendCmdProgramClear(sb_uint32 length) -{ - sb_uint8 packetData[8]; - tXcpTransportResponsePacket *responsePacketPtr; - - /* prepare the command packet */ - packetData[0] = XCP_MASTER_CMD_PROGRAM_CLEAR; - packetData[1] = 0; /* use absolute mode */ - packetData[2] = 0; /* reserved */ - packetData[3] = 0; /* reserved */ - - /* set the erase length taking into account byte ordering */ - XcpMasterSetOrderedLong(length, &packetData[4]); - - - /* send the packet */ - if (XcpTransportSendPacket(packetData, 8, XCP_MASTER_TIMEOUT_T4_MS) == SB_FALSE) - { - /* cound not set packet or receive response within the specified timeout */ - return SB_FALSE; - } - /* still here so a response was received */ - responsePacketPtr = XcpTransportReadResponsePacket(); - - /* check if the reponse was valid */ - if ( (responsePacketPtr->len == 0) || (responsePacketPtr->data[0] != XCP_MASTER_CMD_PID_RES) ) - { - /* not a valid or positive response */ - return SB_FALSE; - } - - /* still here so all went well */ - return SB_TRUE; -} /*** end of XcpMasterSendCmdProgramClear ***/ - - -/************************************************************************************//** -** \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. -** \return none. -** -****************************************************************************************/ -static void XcpMasterSetOrderedLong(sb_uint32 value, sb_uint8 data[]) -{ - if (xcpSlaveIsIntel == SB_TRUE) - { - data[3] = (sb_uint8)(value >> 24); - data[2] = (sb_uint8)(value >> 16); - data[1] = (sb_uint8)(value >> 8); - data[0] = (sb_uint8)value; - } - else - { - data[0] = (sb_uint8)(value >> 24); - data[1] = (sb_uint8)(value >> 16); - data[2] = (sb_uint8)(value >> 8); - data[3] = (sb_uint8)value; - } -} /*** end of XcpMasterSetOrderedLong ***/ - - -/*********************************** end of xcpmaster.c ********************************/ diff --git a/Host/Source/SerialBoot/xcptpuart.c b/Host/Source/SerialBoot/xcptpuart.c new file mode 100644 index 00000000..d3347d55 --- /dev/null +++ b/Host/Source/SerialBoot/xcptpuart.c @@ -0,0 +1,255 @@ +/************************************************************************************//** +* \file xcptpuart.c +* \brief XCP transport layer module for UART source file. +* \ingroup SerialBoot +* \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 /* for NULL declaration */ +#include /* for standard library */ +#include /* for string library */ +#include /* for assertions */ +#include "xcptpuart.h" /* XCP transport layer for UART */ +#include "timeutil.h" /* for time utilities module */ + + +/**************************************************************************************** +* Macro definitions +****************************************************************************************/ +/** \brief Maximum amount of data bytes that this module supports for XCP packets. */ +#define XCP_TP_UART_MAX_DATA_LEN (256) + + +/**************************************************************************************** +* Function prototypes +****************************************************************************************/ +static void XcpTpUartInit(void *settings); +static void XcpTpUartDeinit(void); +static bool XcpTpUartConnect(void); +static void XcpTpUartDisconnect(void); +static bool XcpTpUartSendPacket(tXcpPacket *txPacket, tXcpPacket *rxPacket, uint16_t timeout); + + +/**************************************************************************************** +* Local constant declarations +****************************************************************************************/ +/** \brief XCP transport structure filled with UART specifics. */ +static const tXcpTransport uartTransport = +{ + XcpTpUartInit, + XcpTpUartDeinit, + XcpTpUartConnect, + XcpTpUartDisconnect, + XcpTpUartSendPacket +}; + + +/**************************************************************************************** +* Local data declarations +****************************************************************************************/ +/** \brief The settings to use in this transport layer. */ +static tXcpTpUartSettings tpUartSettings; + + +/***********************************************************************************//** +** \brief Obtains a pointer to the XCP UART transport structure, so that it can +** be linked to the XCP loader module. +** \return Pointer to XCP UART transport structure. +** +****************************************************************************************/ +tXcpTransport const * const XcpTpUartGetTransport(void) +{ + return &uartTransport; +} /*** end of XcpTpUartGetTransport ***/ + + +/************************************************************************************//** +** \brief Initializes the transport layer. +** \param settings Pointer to settings structure. +** \return None. +** +****************************************************************************************/ +static void XcpTpUartInit(void *settings) +{ + /* verify parameters */ + assert(settings != NULL); + + /* 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. + */ + tpUartSettings.portname = malloc(strlen(((tXcpTpUartSettings *)settings)->portname) + 1); + strcpy(tpUartSettings.portname, ((tXcpTpUartSettings *)settings)->portname); +} /*** end of XcpTpUartInit ***/ + + +/************************************************************************************//** +** \brief Uninitializes the transport layer. +** \return None. +** +****************************************************************************************/ +static void XcpTpUartDeinit(void) +{ + /* release memory that was allocated for storing the port name */ + if (tpUartSettings.portname != NULL) + { + free(tpUartSettings.portname); + } +} /*** end of XcpTpUartDeinit ***/ + + +/************************************************************************************//** +** \brief Connects to the transport layer. +** \return True is connected, false otherwise. +** +****************************************************************************************/ +static bool XcpTpUartConnect(void) +{ + /* connect to the serial port */ + return SerialPortOpen(tpUartSettings.portname, tpUartSettings.baudrate); +} /*** end of XcpTpUartConnect ***/ + + +/************************************************************************************//** +** \brief Disconnects from the transport layer. +** \return None. +** +****************************************************************************************/ +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. +** \return True is successful and a response packet was received, false otherwise. +** +****************************************************************************************/ +static bool XcpTpUartSendPacket(tXcpPacket *txPacket, tXcpPacket *rxPacket, uint16_t timeout) +{ + static uint8_t uartBuffer[XCP_TP_UART_MAX_DATA_LEN + 1]; /* static to lower stack load */ + uint8_t byteIdx; + uint32_t responseTimeoutTime; + bool packetReceptionComplete; + + /* verify parameters */ + assert(txPacket != NULL); + assert(txPacket->len <= XCP_TP_UART_MAX_DATA_LEN); + assert(rxPacket != NULL); + assert(timeout > 0); + + + /* 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; byteIdxlen; byteIdx++) + { + uartBuffer[byteIdx + 1] = txPacket->data[byteIdx]; + } + + /* transmit the packet */ + if (!SerialPortWrite(uartBuffer, txPacket->len + 1)) + { + return false; + } + + /* determine timeout time for the response packet */ + responseTimeoutTime = TimeUtilGetSystemTimeMs() + timeout; + + /* initialize packet reception length */ + uartBuffer[0] = 0; + /* poll with timeout detection to receive the first byte. this one contains the + * packet length and cannot be zero. + */ + while (TimeUtilGetSystemTimeMs() < responseTimeoutTime) + { + if (SerialPortRead(&uartBuffer[0], 1)) + { + /* length received. validate it before accepting it */ + if (uartBuffer[0] > 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 */ + if (uartBuffer[0] == 0) + { + /* no valid start of packet received, so a timeout occurred. */ + return false; + } + + /* continue with reception of the packet */ + packetReceptionComplete = false; + byteIdx = 1; + /* poll with timeout detection to receive the full packet */ + while (TimeUtilGetSystemTimeMs() < responseTimeoutTime) + { + /* check if the next byte was received */ + if (SerialPortRead(&uartBuffer[byteIdx], 1)) + { + /* check if the packet reception is now complete */ + if (byteIdx == uartBuffer[0]) + { + /* set flag and stop the loop */ + packetReceptionComplete = true; + break; + } + /* increment indexer to the next byte */ + byteIdx++; + } + } + + /* check if a timeout occurred */ + if (!packetReceptionComplete) + { + return false; + } + + /* still here so a full packet was received. copy its contents except the length info + * which is stored in the first byte + */ + for (byteIdx=0; byteIdxdata[byteIdx] = uartBuffer[byteIdx + 1]; + } + rxPacket->len = uartBuffer[0]; + + return true; +} /*** end of XcpTpUartSendPacket ***/ + + +/*********************************** end of xcptpuart.c ********************************/ + diff --git a/Host/Source/SerialBoot/sb_types.h b/Host/Source/SerialBoot/xcptpuart.h similarity index 64% rename from Host/Source/SerialBoot/sb_types.h rename to Host/Source/SerialBoot/xcptpuart.h index 1317ff1f..b227dc93 100644 --- a/Host/Source/SerialBoot/sb_types.h +++ b/Host/Source/SerialBoot/xcptpuart.h @@ -1,65 +1,66 @@ -/************************************************************************************//** -* \file sb_types.h -* \brief Serial Boot type definitions header file. -* \ingroup SerialBoot -* \internal -*---------------------------------------------------------------------------------------- -* C O P Y R I G H T -*---------------------------------------------------------------------------------------- -* Copyright (c) 2014 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 SB_TYPES_H -#define SB_TYPES_H - -/**************************************************************************************** -* Include files -****************************************************************************************/ -#include /* standard I/O library */ - - -/**************************************************************************************** -* Macro definitions -****************************************************************************************/ -/** \brief Generic boolean true value. */ -#define SB_TRUE (1u) - -/** \brief Ceneric boolean false value. */ -#define SB_FALSE (0u) - -/** \brief NULL pointer value. */ -#define SB_NULL ((void *)0) - - -/**************************************************************************************** -* Type definitions -****************************************************************************************/ -typedef signed char sb_char; -typedef signed char sb_int8; -typedef signed short sb_int16; -typedef signed int sb_int32; -typedef unsigned char sb_uint8; -typedef unsigned short sb_uint16; -typedef unsigned int sb_uint32; -typedef FILE * sb_file; - - - -#endif /* SB_TYPES_H */ -/*********************************** end of sb_types.h *********************************/ +/************************************************************************************//** +* \file xcptpuart.h +* \brief XCP transport layer module for UART header file. +* \ingroup SerialBoot +* \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 + +/**************************************************************************************** +* Include files +****************************************************************************************/ +#include "xcploader.h" /* XCP loader module */ +#include "serialport.h" /* serial port module */ + + +/*************************************************************************************** +* Type definitions +****************************************************************************************/ +/** \brief Layout of structure with settings specific to the XCP transport layer module + * for UART. + */ +typedef struct t_xcp_tp_uart_settings +{ + tSerialPortBaudrate baudrate; /**< UART communication speed. */ + char *portname; /**< interface port name, i.e. /dev/ttyUSB0. */ +} tXcpTpUartSettings; + + +/*************************************************************************************** +* Function prototypes +****************************************************************************************/ +tXcpTransport const * const XcpTpUartGetTransport(void); + +#ifdef __cplusplus +} +#endif + +#endif /* XCPTPUART_H */ +/********************************* end of xcptpuart.h **********************************/ +