From 2b2cbe655dacc20b80cb6291a8533da069b22132 Mon Sep 17 00:00:00 2001 From: Jaro Date: Tue, 24 Aug 2021 16:21:38 +0200 Subject: [PATCH] Add Ymodem transmit translated to boosts --- CMakeLists.txt | 5 +- Makefile | 30 - Thread.h | 44 ++ XModem.cpp | 369 ---------- XModem.h | 81 --- ...son => cache-v2-9de8371d03fa8cbf9def.json} | 122 +++- ...=> codemodel-v2-4167e22d1c847713af64.json} | 2 +- ...on => index-2021-08-24T14-20-32-0203.json} | 8 +- ...t-timeout-Debug-85a0f71a1db986bd99c5.json} | 73 +- build/Makefile | 60 +- build/compile_commands.json | 8 +- main.cpp | 87 ++- xymodem.c | 597 ---------------- xymodem.cpp | 585 +++++++++++++++ xymodem.h | 141 ++++ ymodem.cpp | 671 ------------------ 16 files changed, 1077 insertions(+), 1806 deletions(-) create mode 100644 Thread.h delete mode 100644 XModem.cpp delete mode 100644 XModem.h rename build/.cmake/api/v1/reply/{cache-v2-053ee6e25f83c56b3f05.json => cache-v2-9de8371d03fa8cbf9def.json} (90%) rename build/.cmake/api/v1/reply/{codemodel-v2-a67eb6c77230df2253b5.json => codemodel-v2-4167e22d1c847713af64.json} (92%) rename build/.cmake/api/v1/reply/{index-2021-08-22T19-41-54-0321.json => index-2021-08-24T14-20-32-0203.json} (83%) rename build/.cmake/api/v1/reply/{target-timeout-Debug-6fb942df9d75cf9b39de.json => target-timeout-Debug-85a0f71a1db986bd99c5.json} (57%) delete mode 100644 xymodem.c create mode 100644 xymodem.cpp create mode 100644 xymodem.h delete mode 100644 ymodem.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5eef2a4..6c1ea47 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,12 +4,13 @@ project(TEST) ## Target set(CMAKE_CXX_STANDARD 11) -set(TEST_SRCS main.cpp TimeoutSerial.cpp XModem.cpp) +set(TEST_SRCS main.cpp TimeoutSerial.cpp xymodem.cpp) +add_definitions(-DBOOST_LOG_DYN_LINK) add_executable(timeout ${TEST_SRCS}) set(CMAKE_BUILD_TYPE Debug) ## Link libraries -set(BOOST_LIBS date_time system) +set(BOOST_LIBS date_time system log) find_package(Boost COMPONENTS ${BOOST_LIBS} REQUIRED) target_link_libraries(timeout ${Boost_LIBRARIES}) find_package(Threads REQUIRED) diff --git a/Makefile b/Makefile index 9555637..1efcc5a 100644 --- a/Makefile +++ b/Makefile @@ -150,33 +150,6 @@ TimeoutSerial.cpp.s: $(MAKE) -f CMakeFiles/timeout.dir/build.make CMakeFiles/timeout.dir/TimeoutSerial.cpp.s .PHONY : TimeoutSerial.cpp.s -XModem.o: XModem.cpp.o - -.PHONY : XModem.o - -# target to build an object file -XModem.cpp.o: - $(MAKE) -f CMakeFiles/timeout.dir/build.make CMakeFiles/timeout.dir/XModem.cpp.o -.PHONY : XModem.cpp.o - -XModem.i: XModem.cpp.i - -.PHONY : XModem.i - -# target to preprocess a source file -XModem.cpp.i: - $(MAKE) -f CMakeFiles/timeout.dir/build.make CMakeFiles/timeout.dir/XModem.cpp.i -.PHONY : XModem.cpp.i - -XModem.s: XModem.cpp.s - -.PHONY : XModem.s - -# target to generate assembly for a file -XModem.cpp.s: - $(MAKE) -f CMakeFiles/timeout.dir/build.make CMakeFiles/timeout.dir/XModem.cpp.s -.PHONY : XModem.cpp.s - main.o: main.cpp.o .PHONY : main.o @@ -216,9 +189,6 @@ help: @echo "... TimeoutSerial.o" @echo "... TimeoutSerial.i" @echo "... TimeoutSerial.s" - @echo "... XModem.o" - @echo "... XModem.i" - @echo "... XModem.s" @echo "... main.o" @echo "... main.i" @echo "... main.s" diff --git a/Thread.h b/Thread.h new file mode 100644 index 0000000..47cf7d3 --- /dev/null +++ b/Thread.h @@ -0,0 +1,44 @@ +#ifndef THREAD_HH +#define THREAD_HH + +#include +#include + +using namespace std; + +template +class Thread { +private: + boost::thread* thread; + bool isRunning; +public: + // Ctor + Thread() : thread(NULL), isRunning(false) { + } + virtual ~Thread() { + kill(); + } + + void start() { + T* derived = dynamic_cast(this); + thread = new boost::thread(boost::bind(&Thread::doIt, this, boost::ref(*derived))); + } + void doIt(T& derived) { + } + bool isFinished() { + return isRunning; + } + void join() { + if(thread) { + thread->join(); + } + } + void kill() { + if(thread) { + thread->interrupt(); + delete thread; + thread = NULL; + } + } +}; +#endif \ No newline at end of file diff --git a/XModem.cpp b/XModem.cpp deleted file mode 100644 index 7ca5c2a..0000000 --- a/XModem.cpp +++ /dev/null @@ -1,369 +0,0 @@ -// This code was taken from: https://github.com/mgk/arduino-xmodem -// (https://code.google.com/archive/p/arduino-xmodem) -// which was released under GPL V3: -// -// This program 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. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -// ----------------------------------------------------------------------------- - -#include -#include - -#include "XModem.h" - -#ifdef UTEST -#include "CppUTestExt/MockSupport.h" -#endif -const unsigned char XModem::NACK = 21; -const unsigned char XModem::ACK = 6; - -const unsigned char XModem::SOH = 1; -const unsigned char XModem::EOT = 4; -const unsigned char XModem::CAN = 0x18; - -const int XModem::receiveDelay=7; -const int XModem::rcvRetryLimit = 10; - - -XModem::XModem(TimeoutSerial *serial) -{ - this->serial = serial; - this->dataHandler = NULL; -} - -XModem::XModem(TimeoutSerial *serial, - bool (*dataHandler)(unsigned long number, char *buffer, int len)) -{ - this->serial = serial; - this->dataHandler = dataHandler; -} - -bool XModem::dataAvail(int delay) -{ - if (this->byte != -1) - return true; - if ((this->byte = this->serial->readChar(delay)) != -1) - return true; - else - return false; - -} -int XModem::dataRead(int delay) -{ - int b; - if(this->byte != -1) - { - b = this->byte; - this->byte = -1; - return b; - } - return this->serial->readChar(delay); -} -void XModem::dataWrite(char symbol) -{ - this->serial->write(&symbol, 1); -} -bool XModem::receiveFrameNo() -{ - unsigned char num = - (unsigned char)this->dataRead(XModem::receiveDelay); - unsigned char invnum = - (unsigned char)this->dataRead(XModem::receiveDelay); - this->repeatedBlock = false; - //check for repeated block - if (invnum == (255-num) && num == this->blockNo-1) { - this->repeatedBlock = true; - return true; - } - - if(num != this-> blockNo || invnum != (255-num)) - return false; - else - return true; -} -bool XModem::receiveData() -{ - for(int i = 0; i < 128; i++) { - int byte = this->dataRead(XModem::receiveDelay); - if(byte != -1) - this->buffer[i] = (unsigned char)byte; - else - return false; - } - return true; -} -bool XModem::checkCrc() -{ - unsigned short frame_crc = ((unsigned char)this-> - dataRead(XModem::receiveDelay)) << 8; - - frame_crc |= (unsigned char)this->dataRead(XModem::receiveDelay); - //now calculate crc on data - unsigned short crc = this->crc16_ccitt(this->buffer, 128); - - if(frame_crc != crc) - return false; - else - return true; - -} -bool XModem::checkChkSum() -{ - unsigned char frame_chksum = (unsigned char)this-> - dataRead(XModem::receiveDelay); - //calculate chksum - unsigned char chksum = 0; - for(int i = 0; i< 128; i++) { - chksum += this->buffer[i]; - } - if(frame_chksum == chksum) - return true; - else - return false; -} -bool XModem::sendNack() -{ - this->dataWrite(XModem::NACK); - this->retries++; - if(this->retries < XModem::rcvRetryLimit) - return true; - else - return false; - -} -bool XModem::receiveFrames(transfer_t transfer) -{ - this->blockNo = 1; - this->blockNoExt = 1; - this->retries = 0; - while (1) { - char cmd = this->dataRead(10); - switch(cmd){ - case XModem::SOH: - if (!this->receiveFrameNo()) { - if (this->sendNack()) - break; - else - return false; - } - if (!this->receiveData()) { - if (this->sendNack()) - break; - else - return false; - - }; - if (transfer == Crc) { - if (!this->checkCrc()) { - if (this->sendNack()) - break; - else - return false; - } - } else { - if(!this->checkChkSum()) { - if (this->sendNack()) - break; - else - return false; - } - } - //callback - if(this->dataHandler != NULL && - this->repeatedBlock == false) - if(!this->dataHandler(this->blockNoExt, - this->buffer, 128)) { - return false; - } - //ack - this->dataWrite(XModem::ACK); - if(this->repeatedBlock == false) - { - this->blockNo++; - this->blockNoExt++; - } - this->retries = 0; - break; - case XModem::EOT: - this->dataWrite(XModem::ACK); - return true; - case XModem::CAN: - //wait second CAN - if(this->dataRead(XModem::receiveDelay) == - XModem::CAN) { - this->dataWrite(XModem::ACK); - //this->flushInput(); - return false; - } - //something wrong - this->dataWrite(XModem::CAN); - this->dataWrite(XModem::CAN); - this->dataWrite(XModem::CAN); - return false; - default: - //something wrong - this->dataWrite(XModem::CAN); - this->dataWrite(XModem::CAN); - this->dataWrite(XModem::CAN); - return false; - } - - } -} -void XModem::init() -{ - //set preread byte - this->byte = -1; -} -bool XModem::receive() -{ - this->init(); - - for (int i =0; i < 128; i++) - { - this->dataWrite('C'); - if (this->dataAvail(1000)) - return receiveFrames(Crc); - - } - for (int i =0; i < 128; i++) - { - this->dataWrite(XModem::NACK); - if (this->dataAvail(1000)) - return receiveFrames(ChkSum); - } - return false; -} -unsigned short XModem::crc16_ccitt(char *buf, int size) -{ - unsigned short crc = 0; - while (--size >= 0) { - int i; - crc ^= (unsigned short) *buf++ << 8; - for (i = 0; i < 8; i++) - if (crc & 0x8000) - crc = crc << 1 ^ 0x1021; - else - crc <<= 1; - } - return crc; -} -unsigned char XModem::generateChkSum(const char *buf, int len) -{ - //calculate chksum - unsigned char chksum = 0; - for(int i = 0; i< len; i++) { - chksum += buf[i]; - } - return chksum; - -} - -bool XModem::transmitFrames(transfer_t transfer) -{ - this->blockNo = 1; - this->blockNoExt = 1; - // use this only in unit tetsing - //memset(this->buffer, 'A', 128); - while(1) - { - //get data - if (this->dataHandler != NULL) - { - if( false == - this->dataHandler(this->blockNoExt, this->buffer+3, - 128)) - { - //end of transfer - this->dataWrite(XModem::EOT); - //wait ACK - if (this->dataRead(XModem::receiveDelay) == - XModem::ACK) - return true; - else - return false; - - } - - } - else - { - //cancel transfer - send CAN twice - this->dataWrite(XModem::CAN); - this->dataWrite(XModem::CAN); - //wait ACK - if (this->dataRead(XModem::receiveDelay) == - XModem::ACK) - return true; - else - return false; - } - //SOH - buffer[0] = XModem::SOH; - //frame number - buffer[1] = this->blockNo; - //inv frame number - buffer[2] = (unsigned char)(255-(this->blockNo)); - //(data is already in buffer starting at byte 3) - //checksum or crc - if (transfer == ChkSum) { - buffer[3+128] = this->generateChkSum(buffer+3, 128); - this->sendData(buffer, 3+128+1); - } else { - unsigned short crc; - crc = this->crc16_ccitt(this->buffer+3, 128); - buffer[3+128+0] = (unsigned char)(crc >> 8); - buffer[3+128+1] = (unsigned char)(crc);; - this->sendData(buffer, 3+128+2); - } - - //TO DO - wait NACK or CAN or ACK - int ret = this->dataRead(XModem::receiveDelay); - switch(ret) - { - case XModem::ACK: //data is ok - go to next chunk - this->blockNo++; - this->blockNoExt++; - continue; - case XModem::NACK: //resend data - continue; - case XModem::CAN: //abort transmision - return false; - - } - - } - return false; -} -bool XModem::transmit() -{ - int retry = 0; - int sym; - this->init(); - - //wait for CRC transfer - while(retry < 256) - { - if(this->dataAvail(1000)) - { - sym = this->dataRead(1); //data is here - no delay - if(sym == 'C') - return this->transmitFrames(Crc); - if(sym == XModem::NACK) - return this->transmitFrames(ChkSum); - } - retry++; - } - return false; -} diff --git a/XModem.h b/XModem.h deleted file mode 100644 index a091d86..0000000 --- a/XModem.h +++ /dev/null @@ -1,81 +0,0 @@ -// This code was taken from: https://code.google.com/archive/p/arduino-xmodem -// (https://code.google.com/archive/p/arduino-xmodem) -// which was released under GPL V3: -// -// This program 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. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -// ----------------------------------------------------------------------------- -#include "TimeoutSerial.h" - -typedef enum { - Crc, - ChkSum -} transfer_t; - - -class XModem { - private: - //delay when receive bytes in frame - 7 secs - static const int receiveDelay; - //retry limit when receiving - static const int rcvRetryLimit; - //holds readed byte (due to dataAvail()) - int byte; - //expected block number - unsigned char blockNo; - //extended block number, send to dataHandler() - unsigned long blockNoExt; - //retry counter for NACK - int retries; - //buffer - char buffer[133]; - //repeated block flag - bool repeatedBlock; - TimeoutSerial *serial; - - int (*recvChar)(int); - void (*sendData)(const char *data, int len); - bool (*dataHandler)(unsigned long number, char *buffer, int len); - unsigned short crc16_ccitt(char *buf, int size); - bool dataAvail(int delay); - int dataRead(int delay); - void dataWrite(char symbol); - bool receiveFrameNo(void); - bool receiveData(void); - bool checkCrc(void); - bool checkChkSum(void); - bool receiveFrames(transfer_t transfer); - bool sendNack(void); - void init(void); - void sendSerialData(const char *data, int len); - int recvSerialChar(int); - - bool transmitFrames(transfer_t); - unsigned char generateChkSum(const char *buffer, int len); - - public: - static const unsigned char NACK; - static const unsigned char ACK; - static const unsigned char SOH; - static const unsigned char EOT; - static const unsigned char CAN; - - XModem(TimeoutSerial *serial); - XModem(TimeoutSerial *serial,bool (*dataHandler)(unsigned long, char*, int)); - bool receive(); - bool transmit(); - - - -}; diff --git a/build/.cmake/api/v1/reply/cache-v2-053ee6e25f83c56b3f05.json b/build/.cmake/api/v1/reply/cache-v2-9de8371d03fa8cbf9def.json similarity index 90% rename from build/.cmake/api/v1/reply/cache-v2-053ee6e25f83c56b3f05.json rename to build/.cmake/api/v1/reply/cache-v2-9de8371d03fa8cbf9def.json index dad5f6e..0cfab9c 100644 --- a/build/.cmake/api/v1/reply/cache-v2-053ee6e25f83c56b3f05.json +++ b/build/.cmake/api/v1/reply/cache-v2-9de8371d03fa8cbf9def.json @@ -41,6 +41,18 @@ "type" : "PATH", "value" : "/usr/include" }, + { + "name" : "Boost_LOG_LIBRARY_RELEASE", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "" + } + ], + "type" : "STRING", + "value" : "/usr/lib/x86_64-linux-gnu/libboost_log.so.1.71.0" + }, { "name" : "Boost_SYSTEM_LIBRARY_RELEASE", "properties" : @@ -1231,7 +1243,7 @@ } ], "type" : "INTERNAL", - "value" : "[/usr/lib/x86_64-linux-gnu/cmake/Boost-1.71.0/BoostConfig.cmake][cfound components: date_time system ][v1.71.0()]" + "value" : "[/usr/lib/x86_64-linux-gnu/cmake/Boost-1.71.0/BoostConfig.cmake][cfound components: date_time system log ][v1.71.0()]" }, { "name" : "FIND_PACKAGE_MESSAGE_DETAILS_Threads", @@ -1269,6 +1281,38 @@ "type" : "STATIC", "value" : "/home/jaro/serialport-downloader" }, + { + "name" : "boost_atomic_DIR", + "properties" : + [ + { + "name" : "ADVANCED", + "value" : "1" + }, + { + "name" : "HELPSTRING", + "value" : "The directory containing a CMake configuration file for boost_atomic." + } + ], + "type" : "PATH", + "value" : "/usr/lib/x86_64-linux-gnu/cmake/boost_atomic-1.71.0" + }, + { + "name" : "boost_chrono_DIR", + "properties" : + [ + { + "name" : "ADVANCED", + "value" : "1" + }, + { + "name" : "HELPSTRING", + "value" : "The directory containing a CMake configuration file for boost_chrono." + } + ], + "type" : "PATH", + "value" : "/usr/lib/x86_64-linux-gnu/cmake/boost_chrono-1.71.0" + }, { "name" : "boost_date_time_DIR", "properties" : @@ -1285,6 +1329,22 @@ "type" : "PATH", "value" : "/usr/lib/x86_64-linux-gnu/cmake/boost_date_time-1.71.0" }, + { + "name" : "boost_filesystem_DIR", + "properties" : + [ + { + "name" : "ADVANCED", + "value" : "1" + }, + { + "name" : "HELPSTRING", + "value" : "The directory containing a CMake configuration file for boost_filesystem." + } + ], + "type" : "PATH", + "value" : "/usr/lib/x86_64-linux-gnu/cmake/boost_filesystem-1.71.0" + }, { "name" : "boost_headers_DIR", "properties" : @@ -1301,6 +1361,50 @@ "type" : "PATH", "value" : "/usr/lib/x86_64-linux-gnu/cmake/boost_headers-1.71.0" }, + { + "name" : "boost_log_DIR", + "properties" : + [ + { + "name" : "ADVANCED", + "value" : "1" + }, + { + "name" : "HELPSTRING", + "value" : "The directory containing a CMake configuration file for boost_log." + } + ], + "type" : "PATH", + "value" : "/usr/lib/x86_64-linux-gnu/cmake/boost_log-1.71.0" + }, + { + "name" : "boost_program_options_DIR", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "The directory containing a CMake configuration file for boost_program_options." + } + ], + "type" : "PATH", + "value" : "boost_program_options_DIR-NOTFOUND" + }, + { + "name" : "boost_regex_DIR", + "properties" : + [ + { + "name" : "ADVANCED", + "value" : "1" + }, + { + "name" : "HELPSTRING", + "value" : "The directory containing a CMake configuration file for boost_regex." + } + ], + "type" : "PATH", + "value" : "/usr/lib/x86_64-linux-gnu/cmake/boost_regex-1.71.0" + }, { "name" : "boost_system_DIR", "properties" : @@ -1316,6 +1420,22 @@ ], "type" : "PATH", "value" : "/usr/lib/x86_64-linux-gnu/cmake/boost_system-1.71.0" + }, + { + "name" : "boost_thread_DIR", + "properties" : + [ + { + "name" : "ADVANCED", + "value" : "1" + }, + { + "name" : "HELPSTRING", + "value" : "The directory containing a CMake configuration file for boost_thread." + } + ], + "type" : "PATH", + "value" : "/usr/lib/x86_64-linux-gnu/cmake/boost_thread-1.71.0" } ], "kind" : "cache", diff --git a/build/.cmake/api/v1/reply/codemodel-v2-a67eb6c77230df2253b5.json b/build/.cmake/api/v1/reply/codemodel-v2-4167e22d1c847713af64.json similarity index 92% rename from build/.cmake/api/v1/reply/codemodel-v2-a67eb6c77230df2253b5.json rename to build/.cmake/api/v1/reply/codemodel-v2-4167e22d1c847713af64.json index 513008a..84dec2f 100644 --- a/build/.cmake/api/v1/reply/codemodel-v2-a67eb6c77230df2253b5.json +++ b/build/.cmake/api/v1/reply/codemodel-v2-4167e22d1c847713af64.json @@ -38,7 +38,7 @@ { "directoryIndex" : 0, "id" : "timeout::@6890427a1f51a3e7e1df", - "jsonFile" : "target-timeout-Debug-6fb942df9d75cf9b39de.json", + "jsonFile" : "target-timeout-Debug-85a0f71a1db986bd99c5.json", "name" : "timeout", "projectIndex" : 0 } diff --git a/build/.cmake/api/v1/reply/index-2021-08-22T19-41-54-0321.json b/build/.cmake/api/v1/reply/index-2021-08-24T14-20-32-0203.json similarity index 83% rename from build/.cmake/api/v1/reply/index-2021-08-22T19-41-54-0321.json rename to build/.cmake/api/v1/reply/index-2021-08-24T14-20-32-0203.json index f854360..677b1e2 100644 --- a/build/.cmake/api/v1/reply/index-2021-08-22T19-41-54-0321.json +++ b/build/.cmake/api/v1/reply/index-2021-08-24T14-20-32-0203.json @@ -25,7 +25,7 @@ "objects" : [ { - "jsonFile" : "codemodel-v2-a67eb6c77230df2253b5.json", + "jsonFile" : "codemodel-v2-4167e22d1c847713af64.json", "kind" : "codemodel", "version" : { @@ -34,7 +34,7 @@ } }, { - "jsonFile" : "cache-v2-053ee6e25f83c56b3f05.json", + "jsonFile" : "cache-v2-9de8371d03fa8cbf9def.json", "kind" : "cache", "version" : { @@ -67,7 +67,7 @@ "responses" : [ { - "jsonFile" : "cache-v2-053ee6e25f83c56b3f05.json", + "jsonFile" : "cache-v2-9de8371d03fa8cbf9def.json", "kind" : "cache", "version" : { @@ -76,7 +76,7 @@ } }, { - "jsonFile" : "codemodel-v2-a67eb6c77230df2253b5.json", + "jsonFile" : "codemodel-v2-4167e22d1c847713af64.json", "kind" : "codemodel", "version" : { diff --git a/build/.cmake/api/v1/reply/target-timeout-Debug-6fb942df9d75cf9b39de.json b/build/.cmake/api/v1/reply/target-timeout-Debug-85a0f71a1db986bd99c5.json similarity index 57% rename from build/.cmake/api/v1/reply/target-timeout-Debug-6fb942df9d75cf9b39de.json rename to build/.cmake/api/v1/reply/target-timeout-Debug-85a0f71a1db986bd99c5.json index 23d42db..1409cbe 100644 --- a/build/.cmake/api/v1/reply/target-timeout-Debug-6fb942df9d75cf9b39de.json +++ b/build/.cmake/api/v1/reply/target-timeout-Debug-85a0f71a1db986bd99c5.json @@ -11,7 +11,8 @@ "commands" : [ "add_executable", - "target_link_libraries" + "target_link_libraries", + "add_definitions" ], "files" : [ @@ -25,13 +26,19 @@ { "command" : 0, "file" : 0, - "line" : 8, + "line" : 9, "parent" : 0 }, { "command" : 1, "file" : 0, - "line" : 14, + "line" : 15, + "parent" : 0 + }, + { + "command" : 2, + "file" : 0, + "line" : 8, "parent" : 0 } ] @@ -54,13 +61,37 @@ "backtrace" : 2, "define" : "BOOST_ALL_NO_LIB" }, + { + "backtrace" : 2, + "define" : "BOOST_ATOMIC_DYN_LINK" + }, + { + "backtrace" : 2, + "define" : "BOOST_CHRONO_DYN_LINK" + }, { "backtrace" : 2, "define" : "BOOST_DATE_TIME_DYN_LINK" }, + { + "backtrace" : 2, + "define" : "BOOST_FILESYSTEM_DYN_LINK" + }, + { + "backtrace" : 3, + "define" : "BOOST_LOG_DYN_LINK" + }, + { + "backtrace" : 2, + "define" : "BOOST_REGEX_DYN_LINK" + }, { "backtrace" : 2, "define" : "BOOST_SYSTEM_DYN_LINK" + }, + { + "backtrace" : 2, + "define" : "BOOST_THREAD_DYN_LINK" } ], "language" : "CXX", @@ -95,6 +126,40 @@ "fragment" : "/usr/lib/x86_64-linux-gnu/libboost_system.so.1.71.0", "role" : "libraries" }, + { + "backtrace" : 2, + "fragment" : "/usr/lib/x86_64-linux-gnu/libboost_log.so.1.71.0", + "role" : "libraries" + }, + { + "fragment" : "-lpthread", + "role" : "libraries" + }, + { + "backtrace" : 2, + "fragment" : "/usr/lib/x86_64-linux-gnu/libboost_date_time.so.1.71.0", + "role" : "libraries" + }, + { + "fragment" : "/usr/lib/x86_64-linux-gnu/libboost_chrono.so.1.71.0", + "role" : "libraries" + }, + { + "fragment" : "/usr/lib/x86_64-linux-gnu/libboost_filesystem.so.1.71.0", + "role" : "libraries" + }, + { + "fragment" : "/usr/lib/x86_64-linux-gnu/libboost_regex.so.1.71.0", + "role" : "libraries" + }, + { + "fragment" : "/usr/lib/x86_64-linux-gnu/libboost_thread.so.1.71.0", + "role" : "libraries" + }, + { + "fragment" : "/usr/lib/x86_64-linux-gnu/libboost_atomic.so.1.71.0", + "role" : "libraries" + }, { "fragment" : "-lpthread", "role" : "libraries" @@ -138,7 +203,7 @@ { "backtrace" : 1, "compileGroupIndex" : 0, - "path" : "XModem.cpp", + "path" : "xymodem.cpp", "sourceGroupIndex" : 0 } ], diff --git a/build/Makefile b/build/Makefile index 651af2f..bfc17ae 100644 --- a/build/Makefile +++ b/build/Makefile @@ -150,33 +150,6 @@ TimeoutSerial.cpp.s: $(MAKE) -f CMakeFiles/timeout.dir/build.make CMakeFiles/timeout.dir/TimeoutSerial.cpp.s .PHONY : TimeoutSerial.cpp.s -XModem.o: XModem.cpp.o - -.PHONY : XModem.o - -# target to build an object file -XModem.cpp.o: - $(MAKE) -f CMakeFiles/timeout.dir/build.make CMakeFiles/timeout.dir/XModem.cpp.o -.PHONY : XModem.cpp.o - -XModem.i: XModem.cpp.i - -.PHONY : XModem.i - -# target to preprocess a source file -XModem.cpp.i: - $(MAKE) -f CMakeFiles/timeout.dir/build.make CMakeFiles/timeout.dir/XModem.cpp.i -.PHONY : XModem.cpp.i - -XModem.s: XModem.cpp.s - -.PHONY : XModem.s - -# target to generate assembly for a file -XModem.cpp.s: - $(MAKE) -f CMakeFiles/timeout.dir/build.make CMakeFiles/timeout.dir/XModem.cpp.s -.PHONY : XModem.cpp.s - main.o: main.cpp.o .PHONY : main.o @@ -204,6 +177,33 @@ main.cpp.s: $(MAKE) -f CMakeFiles/timeout.dir/build.make CMakeFiles/timeout.dir/main.cpp.s .PHONY : main.cpp.s +xymodem.o: xymodem.cpp.o + +.PHONY : xymodem.o + +# target to build an object file +xymodem.cpp.o: + $(MAKE) -f CMakeFiles/timeout.dir/build.make CMakeFiles/timeout.dir/xymodem.cpp.o +.PHONY : xymodem.cpp.o + +xymodem.i: xymodem.cpp.i + +.PHONY : xymodem.i + +# target to preprocess a source file +xymodem.cpp.i: + $(MAKE) -f CMakeFiles/timeout.dir/build.make CMakeFiles/timeout.dir/xymodem.cpp.i +.PHONY : xymodem.cpp.i + +xymodem.s: xymodem.cpp.s + +.PHONY : xymodem.s + +# target to generate assembly for a file +xymodem.cpp.s: + $(MAKE) -f CMakeFiles/timeout.dir/build.make CMakeFiles/timeout.dir/xymodem.cpp.s +.PHONY : xymodem.cpp.s + # Help Target help: @echo "The following are some of the valid targets for this Makefile:" @@ -216,12 +216,12 @@ help: @echo "... TimeoutSerial.o" @echo "... TimeoutSerial.i" @echo "... TimeoutSerial.s" - @echo "... XModem.o" - @echo "... XModem.i" - @echo "... XModem.s" @echo "... main.o" @echo "... main.i" @echo "... main.s" + @echo "... xymodem.o" + @echo "... xymodem.i" + @echo "... xymodem.s" .PHONY : help diff --git a/build/compile_commands.json b/build/compile_commands.json index df3dc6b..7d389de 100644 --- a/build/compile_commands.json +++ b/build/compile_commands.json @@ -1,17 +1,17 @@ [ { "directory": "/home/jaro/serialport-downloader/build", - "command": "/bin/c++ -DBOOST_ALL_NO_LIB -DBOOST_DATE_TIME_DYN_LINK -DBOOST_SYSTEM_DYN_LINK -g -std=gnu++11 -o CMakeFiles/timeout.dir/main.cpp.o -c /home/jaro/serialport-downloader/main.cpp", + "command": "/bin/c++ -DBOOST_ALL_NO_LIB -DBOOST_ATOMIC_DYN_LINK -DBOOST_CHRONO_DYN_LINK -DBOOST_DATE_TIME_DYN_LINK -DBOOST_FILESYSTEM_DYN_LINK -DBOOST_LOG_DYN_LINK -DBOOST_REGEX_DYN_LINK -DBOOST_SYSTEM_DYN_LINK -DBOOST_THREAD_DYN_LINK -g -std=gnu++11 -o CMakeFiles/timeout.dir/main.cpp.o -c /home/jaro/serialport-downloader/main.cpp", "file": "/home/jaro/serialport-downloader/main.cpp" }, { "directory": "/home/jaro/serialport-downloader/build", - "command": "/bin/c++ -DBOOST_ALL_NO_LIB -DBOOST_DATE_TIME_DYN_LINK -DBOOST_SYSTEM_DYN_LINK -g -std=gnu++11 -o CMakeFiles/timeout.dir/TimeoutSerial.cpp.o -c /home/jaro/serialport-downloader/TimeoutSerial.cpp", + "command": "/bin/c++ -DBOOST_ALL_NO_LIB -DBOOST_ATOMIC_DYN_LINK -DBOOST_CHRONO_DYN_LINK -DBOOST_DATE_TIME_DYN_LINK -DBOOST_FILESYSTEM_DYN_LINK -DBOOST_LOG_DYN_LINK -DBOOST_REGEX_DYN_LINK -DBOOST_SYSTEM_DYN_LINK -DBOOST_THREAD_DYN_LINK -g -std=gnu++11 -o CMakeFiles/timeout.dir/TimeoutSerial.cpp.o -c /home/jaro/serialport-downloader/TimeoutSerial.cpp", "file": "/home/jaro/serialport-downloader/TimeoutSerial.cpp" }, { "directory": "/home/jaro/serialport-downloader/build", - "command": "/bin/c++ -DBOOST_ALL_NO_LIB -DBOOST_DATE_TIME_DYN_LINK -DBOOST_SYSTEM_DYN_LINK -g -std=gnu++11 -o CMakeFiles/timeout.dir/XModem.cpp.o -c /home/jaro/serialport-downloader/XModem.cpp", - "file": "/home/jaro/serialport-downloader/XModem.cpp" + "command": "/bin/c++ -DBOOST_ALL_NO_LIB -DBOOST_ATOMIC_DYN_LINK -DBOOST_CHRONO_DYN_LINK -DBOOST_DATE_TIME_DYN_LINK -DBOOST_FILESYSTEM_DYN_LINK -DBOOST_LOG_DYN_LINK -DBOOST_REGEX_DYN_LINK -DBOOST_SYSTEM_DYN_LINK -DBOOST_THREAD_DYN_LINK -g -std=gnu++11 -o CMakeFiles/timeout.dir/xymodem.cpp.o -c /home/jaro/serialport-downloader/xymodem.cpp", + "file": "/home/jaro/serialport-downloader/xymodem.cpp" } ] \ No newline at end of file diff --git a/main.cpp b/main.cpp index eddf5cd..7d61c77 100755 --- a/main.cpp +++ b/main.cpp @@ -6,10 +6,28 @@ */ #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + #include #include #include "TimeoutSerial.h" -#include "XModem.h" using namespace std; using namespace boost; @@ -27,6 +45,52 @@ bool dataHandler(unsigned long blockNo, char* buffer, int size) return true; } +static void init_log(void) +{ + /* init boost log + * 1. Add common attributes + * 2. set log filter to trace + */ + boost::log::add_common_attributes(); + boost::log::core::get()->add_global_attribute("Scope", + boost::log::attributes::named_scope()); + boost::log::core::get()->set_filter( + boost::log::trivial::severity >= boost::log::trivial::trace + ); + + /* log formatter: + * [TimeStamp] [ThreadId] [Severity Level] [Scope] Log message + */ + auto fmtTimeStamp = boost::log::expressions:: + format_date_time("TimeStamp", "%Y-%m-%d %H:%M:%S.%f"); + auto fmtThreadId = boost::log::expressions:: + attr("ThreadID"); + auto fmtSeverity = boost::log::expressions:: + attr("Severity"); + auto fmtScope = boost::log::expressions::format_named_scope("Scope", + boost::log::keywords::format = "%n(%f:%l)", + boost::log::keywords::iteration = boost::log::expressions::reverse, + boost::log::keywords::depth = 2); + boost::log::formatter logFmt = + boost::log::expressions::format("[%1%] (%2%) [%3%] [%4%] %5%") + % fmtTimeStamp % fmtThreadId % fmtSeverity % fmtScope + % boost::log::expressions::smessage; + + /* console sink */ + auto consoleSink = boost::log::add_console_log(std::clog); + consoleSink->set_formatter(logFmt); + + /* fs sink */ + auto fsSink = boost::log::add_file_log( + boost::log::keywords::file_name = "serial-dw_%Y-%m-%d_%H-%M-%S.%N.log", + boost::log::keywords::rotation_size = 10 * 1024 * 1024, + boost::log::keywords::min_free_space = 30 * 1024 * 1024, + boost::log::keywords::open_mode = std::ios_base::app); + fsSink->set_formatter(logFmt); + fsSink->locked_backend()->auto_flush(true); +} + + int main(int argc, char* argv[]) { string line; @@ -34,17 +98,16 @@ int main(int argc, char* argv[]) float humidity= NAN; float pressure = NAN; + init_log(); + try { - + + BOOST_LOG_TRIVIAL(debug) << "TEST"; TimeoutSerial serial("/dev/ttyUSB0",115200); serial.setTimeout(posix_time::seconds(10)); serial.setDTR(false); serial.setRTS(false); - sleep(5); - //Text test - - serial.writeString("?\r\n"); - + boost::this_thread::sleep(posix_time::milliseconds(5000)); line = serial.readStringUntil("\n"); trim(line); @@ -77,10 +140,10 @@ int main(int argc, char* argv[]) cout << "vlhkost = " << humidity << endl; cout << "tlak = " << pressure << endl; - XModem modem(&serial,dataHandler); + //XModem modem(&serial,dataHandler); serial.writeString("capture\r\n"); - sleep(1); + boost::this_thread::sleep(posix_time::milliseconds(100)); line = serial.readStringUntil("\r\n"); cout << line << endl; line = serial.readStringUntil("\r\n"); @@ -93,11 +156,11 @@ int main(int argc, char* argv[]) // cout << line << endl; serial.writeString("rb\r\n"); - sleep(1); + boost::this_thread::sleep(posix_time::milliseconds(100)); serial.readChar(1); serial.readChar(1); - modem.receive(); - sleep(1); + //modem.receive(); + boost::this_thread::sleep(posix_time::milliseconds(100)); serial.writeString("free\r\n"); serial.close(); diff --git a/xymodem.c b/xymodem.c deleted file mode 100644 index 37202e6..0000000 --- a/xymodem.c +++ /dev/null @@ -1,597 +0,0 @@ -/* - * Handles the X-Modem, Y-Modem and Y-Modem/G protocols - * - * Copyright (C) 2008 Robert Jarzmik - * - * This program 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 2 of the License, or - * (at your option) any later version. - * - * This program 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. - * - * This file provides functions to receive X-Modem or Y-Modem(/G) protocols. - * - * References: - * *-Modem: http://www.techfest.com/hardware/modem/xymodem.htm - * XMODEM/YMODEM PROTOCOL REFERENCE, Chuck Forsberg - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define xy_dbg(fmt, args...) - -/* Values magic to the protocol */ -#define SOH 0x01 -#define STX 0x02 -#define EOT 0x04 -#define ACK 0x06 -#define BSP 0x08 -#define NAK 0x15 -#define CAN 0x18 - -#define PROTO_XMODEM 0 -#define PROTO_YMODEM 1 -#define PROTO_YMODEM_G 2 -#define MAX_PROTOS 3 - -#define CRC_NONE 0 /* No CRC checking */ -#define CRC_ADD8 1 /* Add of all data bytes */ -#define CRC_CRC16 2 /* CCCIT CRC16 */ -#define MAX_CRCS 3 - -#define MAX_RETRIES 10 -#define MAX_RETRIES_WITH_CRC 5 -#define TIMEOUT_READ (1 * SECOND) -#define TIMEOUT_FLUSH (1 * SECOND) -#define MAX_CAN_BEFORE_ABORT 5 -#define INPUT_FIFO_SIZE (4 * 1024) /* Should always be > 1029 */ - -enum proto_state { - PROTO_STATE_GET_FILENAME = 0, - PROTO_STATE_NEGOCIATE_CRC, - PROTO_STATE_RECEIVE_BODY, - PROTO_STATE_FINISHED_FILE, - PROTO_STATE_FINISHED_XFER, -}; - -/** - * struct xyz_ctxt - context of a x/y modem (g) transfer - * - * @cdev: console device to support *MODEM transfer - * @fifo: fifo to buffer input from serial line - * This is necessary for low hardware FIFOs buffers as UARTs. - * @mode: protocol (XMODEM, YMODEM or YMODEM/G) - * @crc_mode: CRC_NONE, CRC_ADD8 or CRC_CRC16 - * @state: protocol state (as in "state machine") - * @buf: buffer to store the last tranfered buffer chunk - * @filename : filename transmitted by sender (YMODEM* only) - * @fd : file descriptor of the current stored file - * @file_len: length declared by sender (YMODEM* only) - * @nb_received: number of data bytes received since session open - * (this doesn't count resends) - * @total_SOH: number of SOH frames received (128 bytes chunks) - * @total_STX: number of STX frames received (1024 bytes chunks) - * @total_CAN: nubmer of CAN frames received (cancel frames) - */ -struct xyz_ctxt { - struct console_device *cdev; - struct kfifo *fifo; - int mode; - int crc_mode; - enum proto_state state; - char filename[1024]; - int fd; - int file_len; - int nb_received; - int next_blk; - int total_SOH, total_STX, total_CAN, total_retries; -}; - -/** - * struct xy_block - one unitary block of x/y modem (g) transfer - * - * @buf: data buffer - * @len: length of data buffer (can only be 128 or 1024) - * @seq: block sequence number (as in X/Y/YG MODEM protocol) - */ -struct xy_block { - unsigned char buf[1024]; - int len; - int seq; -}; - -/* - * For XMODEM/YMODEM, always try to use the CRC16 versions, called also - * XMODEM/CRC and YMODEM. - * Only fallback to additive CRC (8 bits) if sender doesn't cope with CRC16. - */ -static const char invite_filename_hdr[MAX_PROTOS][MAX_CRCS] = { - { 0, NAK, 'C' }, /* XMODEM */ - { 0, NAK, 'C' }, /* YMODEM */ - { 0, 'G', 'G' }, /* YMODEM-G */ -}; - -static const char invite_file_body[MAX_PROTOS][MAX_CRCS] = { - { 0, NAK, 'C' }, /* XMODEM */ - { 0, NAK, 'C' }, /* YMODEM */ - { 0, 'G', 'G' }, /* YMODEM-G */ -}; - -static const char block_ack[MAX_PROTOS][MAX_CRCS] = { - { 0, ACK, ACK }, /* XMODEM */ - { 0, ACK, ACK }, /* YMODEM */ - { 0, 0, 0 }, /* YMODEM-G */ -}; - -static const char block_nack[MAX_PROTOS][MAX_CRCS] = { - { 0, NAK, NAK }, /* XMODEM */ - { 0, NAK, NAK }, /* YMODEM */ - { 0, 0, 0 }, /* YMODEM-G */ -}; - -static int input_fifo_fill(struct console_device *cdev, struct kfifo *fifo) -{ - while (cdev->tstc(cdev) && kfifo_len(fifo) < INPUT_FIFO_SIZE) - kfifo_putc(fifo, (unsigned char)(cdev->getc(cdev))); - return kfifo_len(fifo); -} - -/* - * This function is optimized to : - * - maximize throughput (ie. read as much as is available in lower layer fifo) - * - minimize latencies (no delay or wait timeout if data available) - * - have a timeout - * This is why standard getc() is not used, and input_fifo_fill() exists. - */ -static int xy_gets(struct console_device *cdev, struct kfifo *fifo, - unsigned char *buf, int len, uint64_t timeout) -{ - int i, rc; - uint64_t start = get_time_ns(); - - for (i = 0, rc = 0; rc >= 0 && i < len; ) { - if (is_timeout(start, timeout)) { - rc = -ETIMEDOUT; - continue; - } - if (input_fifo_fill(cdev, fifo)) - kfifo_getc(fifo, &buf[i++]); - } - - return rc < 0 ? rc : i; -} - -static void xy_putc(struct console_device *cdev, unsigned char c) -{ - cdev->putc(cdev, c); -} - -static void xy_flush(struct console_device *cdev, struct kfifo *fifo) -{ - uint64_t start; - - start = get_time_ns(); - while (cdev->tstc(cdev) && - !is_timeout(start, TIMEOUT_FLUSH)) - cdev->getc(cdev); - mdelay(250); - while (cdev->tstc(cdev) && - !is_timeout(start, TIMEOUT_FLUSH)) - cdev->getc(cdev); - kfifo_reset(fifo); -} - -static int is_xmodem(struct xyz_ctxt *proto) -{ - return proto->mode == PROTO_XMODEM; -} - -static void xy_block_ack(struct xyz_ctxt *proto) -{ - unsigned char c = block_ack[proto->mode][proto->crc_mode]; - - if (c) - xy_putc(proto->cdev, c); -} - -static void xy_block_nack(struct xyz_ctxt *proto) -{ - unsigned char c = block_nack[proto->mode][proto->crc_mode]; - - if (c) - xy_putc(proto->cdev, c); - proto->total_retries++; -} - -static int check_crc(unsigned char *buf, int len, int crc, int crc_mode) -{ - unsigned char crc8 = 0; - uint16_t crc16; - int i; - - switch (crc_mode) { - case CRC_ADD8: - for (i = 0; i < len; i++) - crc8 += buf[i]; - return crc8 == crc ? 0 : -EBADMSG; - case CRC_CRC16: - crc16 = cyg_crc16(buf, len); - xy_dbg("crc16: received = %x, calculated=%x\n", crc, crc16); - return crc16 == crc ? 0 : -EBADMSG; - case CRC_NONE: - return 0; - default: - return -EBADMSG; - } -} - -/** - * xy_read_block - read a X-Modem or Y-Modem(G) block - * @proto: protocol control structure - * @blk: block read - * @timeout: maximal time to get data - * - * This is the pivotal function for block receptions. It attempts to receive one - * block, ie. one 128 bytes or one 1024 bytes block. The received data can also - * be an end of transmission, or a cancel. - * - * Returns : - * >0 : size of the received block - * 0 : last block, ie. end of transmission, ie. EOT - * -EBADMSG : malformed message (ie. sequence bi-bytes are not - * complementary), or CRC check error - * -EILSEQ : block sequence number error wrt previously received block - * -ETIMEDOUT : block not received before timeout passed - * -ECONNABORTED : transfer aborted by sender, ie. CAN - */ -static ssize_t xy_read_block(struct xyz_ctxt *proto, struct xy_block *blk, - uint64_t timeout) -{ - ssize_t rc, data_len = 0; - unsigned char hdr, seqs[2], crcs[2]; - int crc = 0; - bool hdr_found = 0; - uint64_t start = get_time_ns(); - - while (!hdr_found) { - rc = xy_gets(proto->cdev, proto->fifo, &hdr, 1, timeout); - xy_dbg("read 0x%x(%c) -> %d\n", hdr, hdr, rc); - if (rc < 0) - goto out; - if (is_timeout(start, timeout)) - goto timeout; - switch (hdr) { - case SOH: - data_len = 128; - hdr_found = 1; - proto->total_SOH++; - break; - case STX: - data_len = 1024; - hdr_found = 1; - proto->total_STX++; - break; - case CAN: - rc = -ECONNABORTED; - if (proto->total_CAN++ > MAX_CAN_BEFORE_ABORT) - goto out; - break; - case EOT: - rc = 0; - blk->len = 0; - goto out; - default: - break; - } - } - - blk->seq = 0; - rc = xy_gets(proto->cdev, proto->fifo, seqs, 2, timeout); - if (rc < 0) - goto out; - blk->seq = seqs[0]; - if (255 - seqs[0] != seqs[1]) - return -EBADMSG; - - rc = xy_gets(proto->cdev, proto->fifo, blk->buf, data_len, timeout); - if (rc < 0) - goto out; - blk->len = rc; - - switch (proto->crc_mode) { - case CRC_ADD8: - rc = xy_gets(proto->cdev, proto->fifo, crcs, 1, timeout); - crc = crcs[0]; - break; - case CRC_CRC16: - rc = xy_gets(proto->cdev, proto->fifo, crcs, 2, timeout); - crc = (crcs[0] << 8) + crcs[1]; - break; - case CRC_NONE: - rc = 0; - break; - } - if (rc < 0) - goto out; - - rc = check_crc(blk->buf, data_len, crc, proto->crc_mode); - if (rc < 0) - goto out; - return data_len; -timeout: - return -ETIMEDOUT; -out: - return rc; -} - -static int check_blk_seq(struct xyz_ctxt *proto, struct xy_block *blk, - int read_rc) -{ - if (blk->seq == ((proto->next_blk - 1) % 256)) - return -EALREADY; - if (blk->seq != proto->next_blk) - return -EILSEQ; - return read_rc; -} - -static int parse_first_block(struct xyz_ctxt *proto, struct xy_block *blk) -{ - int filename_len; - char *str_num; - - filename_len = strlen(blk->buf); - if (filename_len > blk->len) - return -EINVAL; - strlcpy(proto->filename, blk->buf, sizeof(proto->filename)); - str_num = blk->buf + filename_len + 1; - strsep(&str_num, " "); - proto->file_len = simple_strtoul(blk->buf + filename_len + 1, NULL, 10); - return 1; -} - -static int xy_get_file_header(struct xyz_ctxt *proto) -{ - struct xy_block blk; - int tries, rc = 0; - - memset(&blk, 0, sizeof(blk)); - proto->state = PROTO_STATE_GET_FILENAME; - proto->crc_mode = CRC_CRC16; - for (tries = 0; tries < MAX_RETRIES; tries++) { - xy_putc(proto->cdev, - invite_filename_hdr[proto->mode][proto->crc_mode]); - rc = xy_read_block(proto, &blk, 3 * SECOND); - xy_dbg("read block returned %d\n", rc); - switch (rc) { - case -ECONNABORTED: - goto fail; - case -ETIMEDOUT: - case -EBADMSG: - if (proto->mode != PROTO_YMODEM_G) - xy_flush(proto->cdev, proto->fifo); - break; - case -EALREADY: - default: - proto->next_blk = 1; - xy_block_ack(proto); - proto->state = PROTO_STATE_NEGOCIATE_CRC; - rc = parse_first_block(proto, &blk); - return rc; - } - - if (rc < 0 && tries++ >= MAX_RETRIES_WITH_CRC) - proto->crc_mode = CRC_ADD8; - } - rc = -ETIMEDOUT; -fail: - proto->total_retries += tries; - return rc; -} - -static int xy_await_header(struct xyz_ctxt *proto) -{ - int rc; - - rc = xy_get_file_header(proto); - if (rc < 0) - return rc; - proto->state = PROTO_STATE_NEGOCIATE_CRC; - xy_dbg("header received, filename=%s, file length=%d\n", - proto->filename, proto->file_len); - if (proto->filename[0]) - proto->fd = open(proto->filename, O_WRONLY | O_CREAT); - else - proto->state = PROTO_STATE_FINISHED_XFER; - proto->nb_received = 0; - return rc; -} - -static void xy_finish_file(struct xyz_ctxt *proto) -{ - close(proto->fd); - proto->fd = 0; - proto->state = PROTO_STATE_FINISHED_FILE; -} - -static struct xyz_ctxt *xymodem_open(struct console_device *cdev, - int proto_mode, int xmodem_fd) -{ - struct xyz_ctxt *proto; - - proto = xzalloc(sizeof(struct xyz_ctxt)); - proto->fifo = kfifo_alloc(INPUT_FIFO_SIZE); - proto->mode = proto_mode; - proto->cdev = cdev; - proto->crc_mode = CRC_CRC16; - - if (is_xmodem(proto)) { - proto->fd = xmodem_fd; - proto->state = PROTO_STATE_NEGOCIATE_CRC; - } else { - proto->state = PROTO_STATE_GET_FILENAME; - } - xy_flush(proto->cdev, proto->fifo); - return proto; -} - -static int xymodem_handle(struct xyz_ctxt *proto) -{ - int rc = 0, xfer_max, len = 0, again = 1, remain; - int crc_tries = 0, same_blk_retries = 0; - unsigned char invite; - struct xy_block blk; - - while (again) { - switch (proto->state) { - case PROTO_STATE_GET_FILENAME: - crc_tries = 0; - rc = xy_await_header(proto); - if (rc < 0) - goto fail; - continue; - case PROTO_STATE_FINISHED_FILE: - if (is_xmodem(proto)) - proto->state = PROTO_STATE_FINISHED_XFER; - else - proto->state = PROTO_STATE_GET_FILENAME; - xy_putc(proto->cdev, ACK); - continue; - case PROTO_STATE_FINISHED_XFER: - again = 0; - rc = 0; - goto out; - case PROTO_STATE_NEGOCIATE_CRC: - invite = invite_file_body[proto->mode][proto->crc_mode]; - proto->next_blk = 1; - if (crc_tries++ > MAX_RETRIES_WITH_CRC) - proto->crc_mode = CRC_ADD8; - xy_putc(proto->cdev, invite); - /* Fall through */ - case PROTO_STATE_RECEIVE_BODY: - rc = xy_read_block(proto, &blk, 3 * SECOND); - if (rc > 0) { - rc = check_blk_seq(proto, &blk, rc); - proto->state = PROTO_STATE_RECEIVE_BODY; - } - break; - } - - if (proto->state != PROTO_STATE_RECEIVE_BODY) - continue; - - switch (rc) { - case -ECONNABORTED: - goto fail; - case -ETIMEDOUT: - if (proto->mode == PROTO_YMODEM_G) - goto fail; - xy_flush(proto->cdev, proto->fifo); - xy_block_nack(proto); - break; - case -EBADMSG: - case -EILSEQ: - if (proto->mode == PROTO_YMODEM_G) - goto fail; - xy_flush(proto->cdev, proto->fifo); - xy_block_nack(proto); - break; - case -EALREADY: - xy_block_ack(proto); - break; - case 0: - xy_finish_file(proto); - break; - default: - remain = proto->file_len - proto->nb_received; - if (is_xmodem(proto)) - xfer_max = blk.len; - else - xfer_max = min(blk.len, remain); - rc = write(proto->fd, blk.buf, xfer_max); - proto->next_blk = ((blk.seq + 1) % 256); - proto->nb_received += rc; - len += rc; - xy_block_ack(proto); - break; - } - if (rc < 0) - same_blk_retries++; - else - same_blk_retries = 0; - if (same_blk_retries > MAX_RETRIES) - goto fail; - } -out: - return rc; -fail: - if (proto->fd) - close(proto->fd); - return rc; -} - -static void xymodem_close(struct xyz_ctxt *proto) -{ - xy_flush(proto->cdev, proto->fifo); - printf("\nxyModem - %d(SOH)/%d(STX)/%d(CAN) packets," - " %d retries\n", - proto->total_SOH, proto->total_STX, - proto->total_CAN, proto->total_retries); - kfifo_free(proto->fifo); -} - -int do_load_serial_xmodem(struct console_device *cdev, int fd) -{ - struct xyz_ctxt *proto; - int rc; - - proto = xymodem_open(cdev, PROTO_XMODEM, fd); - do { - rc = xymodem_handle(proto); - } while (rc > 0); - xymodem_close(proto); - return rc < 0 ? rc : 0; -} -EXPORT_SYMBOL(do_load_serial_xmodem); - -int do_load_serial_ymodem(struct console_device *cdev) -{ - struct xyz_ctxt *proto; - int rc; - - proto = xymodem_open(cdev, PROTO_YMODEM, 0); - do { - rc = xymodem_handle(proto); - } while (rc > 0); - xymodem_close(proto); - return rc < 0 ? rc : 0; -} -EXPORT_SYMBOL(do_load_serial_ymodem); - -int do_load_serial_ymodemg(struct console_device *cdev) -{ - struct xyz_ctxt *proto; - int rc; - - proto = xymodem_open(cdev, PROTO_YMODEM_G, 0); - do { - rc = xymodem_handle(proto); - } while (rc > 0); - xymodem_close(proto); - return rc < 0 ? rc : 0; -} -EXPORT_SYMBOL(do_load_serial_ymodemg); diff --git a/xymodem.cpp b/xymodem.cpp new file mode 100644 index 0000000..d46aa9d --- /dev/null +++ b/xymodem.cpp @@ -0,0 +1,585 @@ +/* + * xymodem file transferts + * + * (C) Copyright 2011 Angelo Dureghello + * + * This program 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 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xymodem.h" +#include "Thread.h" + +using namespace std; +using namespace boost; + +static const unsigned char ZPAD = 0x2a; +static const unsigned char ZDLE = 0x18; +static const unsigned char ZBIN = 0x41; +static const unsigned char ZHEX = 0x42; +static const unsigned char XON = 0x11; + +static const unsigned char ZMABORT[] = {ZDLE,ZDLE,ZDLE,ZDLE,ZDLE}; + +static const unsigned char ESC_HEXHDR[] = {ZPAD,ZPAD,ZDLE,ZHEX}; +static const unsigned char ZRQINIT[] = "0000000000195E"; +static const unsigned char ZTERM[]= {0x0d,0x0a,XON}; + + +class __tools { +public: + __tools () {} + +public: + unsigned short crc16_ccitt( char *buf, int len ) + { + unsigned short crc = 0; + while( len-- ) { + int i; + crc ^= *(char *)buf++ << 8; + for( i = 0; i < 8; ++i ) { + if( crc & 0x8000 ) + crc = (crc << 1) ^ 0x1021; + else + crc = crc << 1; + } + } + return crc; + } + unsigned char calc_xmodem_checksum (unsigned char *buf, int sz) + { + int i; + int cks = 0; + + for (i = 0; i < sz; ++i) { + cks += (int)buf[i]; + } + return cks%256; + } +}; + + +/* XMODEM */ +static const unsigned char SOH = 0x01; +static const unsigned char STX = 0x02; +static const unsigned char EOT = 0x04; +static const unsigned char ACK = 0x06; +static const unsigned char NAK = 0x15; +static const unsigned char ETB = 0x17; +static const unsigned char CAN = 0x18; +static const unsigned char SYN = 0x43; +static const unsigned char CPMEOF = 0x1a; + +Operator::Operator (TimeoutSerial &c) : com(&c) +{ + obuff.resize (512 , 0); + obuff.resize (2048, 0); +} + +void Operator::SessionStartup (const string &file) +{ + fname = file; + + f.open(file.c_str(), fstream::binary | fstream::in); + + /* adding a cr, C was probably on the screen */ + if (!f.is_open()) + { + BOOST_LOG_TRIVIAL(debug) << "Cannot open file " << file << " please check the path"; + } + BOOST_LOG_TRIVIAL(debug) << "File: " << file; + + /* getting file size */ + f.seekg (0, ios::end); + fsize = f.tellg(); + f.seekg (0, ios::beg); + + stringstream ss; + string size; + + ss << fsize; + ss >> size; + BOOST_LOG_TRIVIAL(debug) << "Size: " << size << " bytes"; +} + +void Operator::StartTransfert () +{ + BOOST_LOG_TRIVIAL(debug) << "Starting file transfer ..."; + + Entry(); +} + +void Operator::SendBlock(char *block, int size) +{ + int hsz, csz; + + /* prepare block header */ + hsz = SetupBlockHdr(); + + /* prepare block binary data */ + memcpy (&obuff[hsz], block, size); + csz = SetupCheckSum (&obuff[hsz], &obuff[hsz+size]); + + q->write (&obuff[0], hsz+size+csz); +} + +/* + * A thread process the entire transfert and allows UI to be free of operating + */ + +enum states { + SESSION_START, + SESSION_BLOCKS, + SESSION_CLOSE, + SESSION_CLOSE_WAIT_ACK, + SESSION_END, +}; + +bool Operator::GetChar() +{ + try { + q->read(&ibuff[0], 1); + return true; + } catch(boost::system::system_error& e) + { + return false; + } +} + +bool Operator::IsChar () +{ return (ibuff[0]!=0); } + +bool Operator::IsAck () +{ + return (ibuff[0] == GetAck()); +} + +bool Operator::IsSync () +{ + return (ibuff[0] == GetSync()); +} + +bool Operator::IsNack () +{ + return (ibuff[0] == GetNack()); +} + +bool Operator::IsCan () +{ + return (ibuff[0] == GetCan()); +} + +void Operator::SendEot () +{ + char c[2]; + + c[0] = GetEot(); + q->write (c, 1); +} + +void Operator::SetupInfoBlock (string &block) +{ + stringstream ss; + + unsigned int i = fname.rfind('/'); + + if (i==string::npos) + i = fname.rfind('\\'); + + if (i!=string::npos) + { + fname = fname.substr(i+1); + } + + i=fname.size(); + + ss << fsize; + pkt = 0; + + /* prepare first block */ + memcpy(&block[0],&fname[0], i); + block[i++]=0; + memcpy(&block[i],ss.str().c_str(),ss.str().size()); + /* + * space after length should be needed only if mod date is sent + * but some receiver (u-boot) need it. + */ + block[i+ss.str().size()] = ' '; +} + +void Operator::UpdateProgress (int size) +{ + stringstream ss; + + if (!size) { + psize = GetBlockSize() * count++; + } else + psize += size; + + ss << psize << "/" << fsize; + + // EvtDel (); + // EvtMsg (ss.str()); +} + +int Operator::Entry() +{ + string block(1024,0); + + struct y_modem_data ymd; + + int state = SESSION_START; + int bsize = GetBlockSize(); + int blnum = fsize / bsize; + int reminder=0; + + count=1; + + /* progress size */ + psize=0; + + stringstream ss; + string ascii_bsize; + + ss << bsize; + ss >> ascii_bsize; + + /* clone */ + q = com; + + pkt = 1; + + if (GetProto()=='Y') + { + /* + * always sending file size allows a faster close of + * the session from the receiver. + * + * = SPEC = + * The pathname (conventionally, the file name) is sent as a null + * terminated ASCII string. + * No spaces are included in the pathname. Normally only the file name + * stem (no directory prefix) is transmitted unless the sender has + * selected YAM's f option to send the full pathname. The source drive + * (A:, B:, etc.) is not sent. + * + */ + SetupInfoBlock(block); + blnum++; + + /* signal to skip update progress for first info block */ + ymd.first_pkt = true; + } + else + /* read first block from file*/ + f.read(&block[0], bsize); + + for (;;) { + /* always, wait for tranfert occour and proper replies */ + boost::this_thread::sleep(posix_time::milliseconds(10)); + + if (GetChar()==false) continue; + + switch (state) { + case SESSION_START: + if (IsSync()) { + if (ymd.first_ack) { + BOOST_LOG_TRIVIAL(debug) << "Entry() : YMODEM FIRST C after ACK"; + /* + * YMODEM, as per spec we expect receiver + * sends this furhter 'C' + */ + state++; + /* + * clear rx data for walkthrough and + * send 1st block + */ + ibuff[0]=0; + } + else { + if (GetProto()=='X') + { + /* + * C here mean receiver wants + * 16bit CRC mode and + * assumes we know it if we send + * a block + */ + SetMode(XMODEMCRC); + /* send and promote */ + state++; + } + /* received SYN */ + BOOST_LOG_TRIVIAL(debug) << "Sync received, transfert start"; + /* + * resend same initial packet + * note: non sense for Y-MODEM use 1024 + */ + SetSize(128); + SendBlock (&block[0], 128); + if (GetProto()=='Y') SetSize(1024); + boost::this_thread::sleep(posix_time::milliseconds(10));; + + continue; + } + } + else + if (IsAck()) { + if (GetProto()=='Y') { + BOOST_LOG_TRIVIAL(debug) << "Entry() : YMODEM FIRST ACK"; + + ymd.first_ack=true; + /* back up to get C after ack */ + continue; + } + else + state++; + } + else + if (IsNack()) { + /* + * note ! programs as rx or lrz need filename as + * additional parameter, otherwise they sends + * C.. C and a CAN just after. + */ + if (GetProto()=='X') { + + BOOST_LOG_TRIVIAL(debug) << "Nack received, transfert start\r\n"; + /* resend same initial packet*/ + SendBlock (&block[0], bsize); + boost::this_thread::sleep(posix_time::milliseconds(10)); + /* promoted */ + state++; + } + else + { + BOOST_LOG_TRIVIAL(debug) << "Entry() : NACK FIRST"; + } + } + // NO BREAK, + // FALL THROUGH IS INTENTIONAL + case SESSION_BLOCKS: + if (IsChar() && !IsAck()) { + if (IsSync()) { + if (GetProto()=='Y') + { + /* + * first synch after first + * block sent, do nothing here + */ + } + } + else + if (IsNack()) { + //EvtMsg("Nack/Sync\r\n"); + /* resend */ + if (GetProto()=='Y' || + (GetProto()=='X' && pkt!=1)) + { + BOOST_LOG_TRIVIAL(debug) << "entry() : NACK, RESEND"; + SendBlock (&block[0], bsize); + boost::this_thread::sleep(posix_time::milliseconds(10)); + } + } + else + if (IsCan()) + { + BOOST_LOG_TRIVIAL(debug) << "Transfert canceled from receiver"; + boost::this_thread::sleep(posix_time::milliseconds(100)); + /* destroy object and the thread */ + return (void*)1; + } + else + { + /* to do, if some other chances */ + } + continue; + } + // ACK received, so progress + if (blnum) + { + if (GetProto()=='Y') + { + if (ymd.first_pkt) ymd.first_pkt=false; + else + UpdateProgress(); + } + else + // XMODEM, always + UpdateProgress(); + + /* if multiple of 256/1024 close */ + if (blnum==1 && psize==fsize) { + blnum--; + goto close_session; + } + } + else + { +close_session: + /* completed */ + UpdateProgress (reminder); + BOOST_LOG_TRIVIAL(debug) << "Closing session ..."; + SendEot(); + if (GetProto()=='X') state=SESSION_END; else state++; + continue; + } + blnum--; + pkt++; + /* end of blocks ? */ + if (blnum>0) { + f.read(&block[0], bsize); + SendBlock (&block[0], bsize); + } + else { + reminder=fsize%bsize; + if (reminder) + { + f.read(&block[0], reminder); + memset (&block[reminder],CPMEOF,bsize-reminder); + SendBlock (&block[0], bsize); + } + } + break; + case SESSION_CLOSE: + /* YMODEM ONLY */ + if (IsAck()) state++; + else + if (IsNack()) + { + /* + * in YMODEM termination is EOT-> NACK<-, + * EOT-> ACK<- + */ + SendEot(); + } + break; + case SESSION_CLOSE_WAIT_ACK: + /* YMODEM ONLY */ + if (IsSync()) + { + /* Synch, terminating.. */ + memset (&block[0], 0, 128); + SetSize(128); + pkt=0; + SendBlock (&block[0], 128); + + state++; + } + break; + case SESSION_END: + if (!IsAck()) continue; + BOOST_LOG_TRIVIAL(debug) << "Transfert complete"; + boost::this_thread::sleep(posix_time::milliseconds(100)); + /* destroy object and the thread */ + //delete q; + //EvtEnd (); + return (void*)1; + + break; + } + } + + return 0; +} + +XModem::XModem (TimeoutSerial &c) : Operator (c), t(*new __tools) +{ + xmodem_mode = 0; + psize = LEN_B_XMODEM; +} + +int XModem::SetupBlockHdr() +{ + obuff[0]=(xmodem_mode&XMODEM1K)?STX:SOH; + obuff[1]=pkt; + obuff[2]=0xff-pkt; + + return 3; +} + +int XModem::SetupCheckSum (char *data, char *dest) +{ + if (xmodem_mode&XMODEMCRC) + { + unsigned short crc = t.crc16_ccitt(data, psize); + + *(unsigned short*)dest = (unsigned short) + ((crc<<8)&0xFF00) | ((crc>>8)&0xff); + + return 2; + } + else + { + unsigned char crc = + t.calc_xmodem_checksum((unsigned char*)data, psize); + + *dest = crc; + + return 1; + } +} + +inline char XModem::GetSync () { return SYN; } +inline char XModem::GetAck () { return ACK; } +inline char XModem::GetNack () { return NAK; } +inline char XModem::GetCan () { return CAN; } +inline char XModem::GetEot () { return EOT; } +inline char XModem::GetProto() { return 'X'; } + +inline void XModem::SetSize (int size) { psize = size; } + +YModem::YModem (TimeoutSerial &c) : Operator (c), t(*new __tools) +{ + psize = LEN_B_YMODEM; +} + +/* YModem allows 128 (std) blocks or 1024 + */ +int YModem::SetupBlockHdr() +{ + obuff[0]=(psize==LEN_B_YMODEM)?STX:SOH; + obuff[1]=pkt; + obuff[2]=0xff-pkt; + + return 3; +} + +int YModem::SetupCheckSum (char *data, char *dest) +{ + unsigned short crc = t.crc16_ccitt(data, psize); + + *(unsigned short*)dest = (unsigned short)((crc<<8)&0xFF00) | ((crc>>8)&0xff); + + return 2; +} + +inline char YModem::GetSync () { return SYN; } +inline char YModem::GetAck () { return ACK; } +inline char YModem::GetNack () { return NAK; } +inline char YModem::GetCan () { return CAN; } +inline char YModem::GetEot () { return EOT; } +inline char YModem::GetProto() { return 'Y'; } + +inline void YModem::SetSize (int size) { psize = size; } diff --git a/xymodem.h b/xymodem.h new file mode 100644 index 0000000..54939ff --- /dev/null +++ b/xymodem.h @@ -0,0 +1,141 @@ +#ifndef modem_HH +#define modem_HH + +#include +#include +#include "Thread.h" +#include "TimeoutSerial.h" + +using std::fstream; +using std::string; + +class __tools; + +struct y_modem_data +{ + y_modem_data() : first_ack(false) {} + + bool first_ack; + bool first_pkt; +}; + +class Operator: public Thread< Operator > +{ +public: + Operator (TimeoutSerial &c); +private: + int Entry(); //Strting point + + void SetupInfoBlock (string &block); + void UpdateProgress (int = 0); + + bool GetChar(); + bool IsChar (); + bool IsAck (); + bool IsSync (); + bool IsNack (); + bool IsCan (); + +protected: + void SendBlock(char *p, int size); + void SendEot (); + + virtual int GetBlockSize () = 0; + virtual int SetupBlockHdr () = 0; + virtual int SetupCheckSum (char *data, char *dest) = 0; + virtual char GetSync () = 0; + virtual char GetAck () = 0; + virtual char GetCan () = 0; + virtual char GetNack () = 0; + virtual char GetEot () = 0; + virtual char GetProto() = 0; + + virtual void SetSize (int) {} + virtual void SetMode (int) {} + virtual int GetMode () { return 0; } + + +public: + void SessionStartup (const string &); + void StartTransfert (); + +protected: + TimeoutSerial *com, *q; + fstream f; + int pkt; + int fsize,psize; + int count; + string fname; + string ibuff; + string obuff; +}; + + +static const int LEN_B_XMODEM = 128; + +// bitmask +enum { + XMODEM1K=0x01, + XMODEMCRC=0x02, +}; + +class XModem : public Operator { +public: + XModem (TimeoutSerial &c); + +private: + int GetBlockSize () { return psize; } + int SetupBlockHdr (); + int SetupCheckSum (char *data, char *dest); + + char GetSync (); + char GetAck (); + char GetNack (); + char GetCan (); + char GetProto(); + char GetEot (); + int GetMode () {return xmodem_mode;} + + void SetSize (int size); + void SetMode (int mode) { + xmodem_mode|=mode; + if (mode&XMODEM1K) psize=1024; + } + +public: + int xmodem_mode; + +private: + __tools &t; + int psize; +}; + +/* we don't use the standard 128 block but 1024 only + */ +static const int LEN_B_YMODEM = 1024; + +class YModem : public Operator { +public: + YModem (TimeoutSerial &c); + +private: + int GetBlockSize () { return psize; } + int SetupBlockHdr (); + int SetupCheckSum (char *data, char *dest); + + char GetSync (); + char GetAck (); + char GetNack (); + char GetCan (); + char GetProto(); + char GetEot (); + + void SetSize (int size); + +private: + __tools &t; + int psize; +}; + + +#endif // modem_HH diff --git a/ymodem.cpp b/ymodem.cpp deleted file mode 100644 index b1d4314..0000000 --- a/ymodem.cpp +++ /dev/null @@ -1,671 +0,0 @@ -/** - ****************************************************************************** - * @file IAP/src/ymodem.c - * @author MCD Application Team - * @version V3.3.0 - * @date 10/15/2010 - * @brief This file provides all the software functions related to the ymodem - * protocol. - ****************************************************************************** - * @copy - * - * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS - * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE - * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY - * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING - * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE - * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. - * - *

© COPYRIGHT 2010 STMicroelectronics

- */ - -#include -#include -#include -#include -#include -#include "ymodem.h" - -uint8_t file_name[FILE_NAME_LENGTH]; -uint32_t FlashDestination = ApplicationAddress; /* Flash user program offset */ -uint16_t PageSize = PAGE_SIZE; -uint32_t EraseCounter = 0x0; -uint32_t NbrOfPage = 0; -FLASH_Status FLASHStatus = FLASH_COMPLETE; -uint32_t RamSource; -extern uint8_t tab_1024[1024]; - -/* Private function prototypes -----------------------------------------------*/ -/* Private functions ---------------------------------------------------------*/ - -/** - * @brief Receive byte from sender - * @param c: Character - * @param timeout: Timeout - * @retval 0: Byte received - * -1: Timeout - */ -static int32_t Receive_Byte (uint8_t *c, uint32_t timeout) -{ - while (timeout-- > 0) - { - if (SerialKeyPressed(c) == 1) - { - return 0; - } - } - return -1; -} - -/** - * @brief Send a byte - * @param c: Character - * @retval 0: Byte sent - */ -static uint32_t Send_Byte (uint8_t c) -{ - SerialPutChar(c); - return 0; -} - -/** - * @brief Receive a packet from sender - * @param data - * @param length - * @param timeout - * 0: end of transmission - * -1: abort by sender - * >0: packet length - * @retval 0: normally return - * -1: timeout or packet error - * 1: abort by user - */ -static int32_t Receive_Packet (uint8_t *data, int32_t *length, uint32_t timeout) -{ - uint16_t i, packet_size; - uint8_t c; - *length = 0; - if (Receive_Byte(&c, timeout) != 0) - { - return -1; - } - switch (c) - { - case SOH: - packet_size = PACKET_SIZE; - break; - case STX: - packet_size = PACKET_1K_SIZE; - break; - case EOT: - return 0; - case CA: - if ((Receive_Byte(&c, timeout) == 0) && (c == CA)) - { - *length = -1; - return 0; - } - else - { - return -1; - } - case ABORT1: - case ABORT2: - return 1; - default: - return -1; - } - *data = c; - for (i = 1; i < (packet_size + PACKET_OVERHEAD); i ++) - { - if (Receive_Byte(data + i, timeout) != 0) - { - return -1; - } - } - if (data[PACKET_SEQNO_INDEX] != ((data[PACKET_SEQNO_COMP_INDEX] ^ 0xff) & 0xff)) - { - return -1; - } - *length = packet_size; - return 0; -} - -/** - * @brief Receive a file using the ymodem protocol - * @param buf: Address of the first byte - * @retval The size of the file - */ -int32_t Ymodem_Receive (uint8_t *buf) -{ - uint8_t packet_data[PACKET_1K_SIZE + PACKET_OVERHEAD], file_size[FILE_SIZE_LENGTH], *file_ptr, *buf_ptr; - int32_t i, j, packet_length, session_done, file_done, packets_received, errors, session_begin, size = 0; - - /* Initialize FlashDestination variable */ - FlashDestination = ApplicationAddress; - - for (session_done = 0, errors = 0, session_begin = 0; ;) - { - for (packets_received = 0, file_done = 0, buf_ptr = buf; ;) - { - switch (Receive_Packet(packet_data, &packet_length, NAK_TIMEOUT)) - { - case 0: - errors = 0; - switch (packet_length) - { - /* Abort by sender */ - case - 1: - Send_Byte(ACK); - return 0; - /* End of transmission */ - case 0: - Send_Byte(ACK); - file_done = 1; - break; - /* Normal packet */ - default: - if ((packet_data[PACKET_SEQNO_INDEX] & 0xff) != (packets_received & 0xff)) - { - Send_Byte(NAK); - } - else - { - if (packets_received == 0) - { - /* Filename packet */ - if (packet_data[PACKET_HEADER] != 0) - { - /* Filename packet has valid data */ - for (i = 0, file_ptr = packet_data + PACKET_HEADER; (*file_ptr != 0) && (i < FILE_NAME_LENGTH);) - { - file_name[i++] = *file_ptr++; - } - file_name[i++] = '\0'; - for (i = 0, file_ptr ++; (*file_ptr != ' ') && (i < FILE_SIZE_LENGTH);) - { - file_size[i++] = *file_ptr++; - } - file_size[i++] = '\0'; - Str2Int(file_size, &size); - - /* Test the size of the image to be sent */ - /* Image size is greater than Flash size */ - if (size > (FLASH_SIZE - 1)) - { - /* End session */ - Send_Byte(CA); - Send_Byte(CA); - return -1; - } - - /* Erase the needed pages where the user application will be loaded */ - /* Define the number of page to be erased */ - NbrOfPage = FLASH_PagesMask(size); - - /* Erase the FLASH pages */ - for (EraseCounter = 0; (EraseCounter < NbrOfPage) && (FLASHStatus == FLASH_COMPLETE); EraseCounter++) - { - FLASHStatus = FLASH_ErasePage(FlashDestination + (PageSize * EraseCounter)); - } - Send_Byte(ACK); - Send_Byte(CRC16); - } - /* Filename packet is empty, end session */ - else - { - Send_Byte(ACK); - file_done = 1; - session_done = 1; - break; - } - } - /* Data packet */ - else - { - memcpy(buf_ptr, packet_data + PACKET_HEADER, packet_length); - RamSource = (uint32_t)buf; - for (j = 0;(j < packet_length) && (FlashDestination < ApplicationAddress + size);j += 4) - { - /* Program the data received into STM32F10x Flash */ - FLASH_ProgramWord(FlashDestination, *(uint32_t*)RamSource); - - if (*(uint32_t*)FlashDestination != *(uint32_t*)RamSource) - { - /* End session */ - Send_Byte(CA); - Send_Byte(CA); - return -2; - } - FlashDestination += 4; - RamSource += 4; - } - Send_Byte(ACK); - } - packets_received ++; - session_begin = 1; - } - } - break; - case 1: - Send_Byte(CA); - Send_Byte(CA); - return -3; - default: - if (session_begin > 0) - { - errors ++; - } - if (errors > MAX_ERRORS) - { - Send_Byte(CA); - Send_Byte(CA); - return 0; - } - Send_Byte(CRC16); - break; - } - if (file_done != 0) - { - break; - } - } - if (session_done != 0) - { - break; - } - } - return (int32_t)size; -} - -/** - * @brief check response using the ymodem protocol - * @param buf: Address of the first byte - * @retval The size of the file - */ -int32_t Ymodem_CheckResponse(uint8_t c) -{ - return 0; -} - -/** - * @brief Prepare the first block - * @param timeout - * 0: end of transmission - */ -void Ymodem_PrepareIntialPacket(uint8_t *data, const uint8_t* fileName, uint32_t *length) -{ - uint16_t i, j; - uint8_t file_ptr[10]; - - /* Make first three packet */ - data[0] = SOH; - data[1] = 0x00; - data[2] = 0xff; - - /* Filename packet has valid data */ - for (i = 0; (fileName[i] != '\0') && (i < FILE_NAME_LENGTH);i++) - { - data[i + PACKET_HEADER] = fileName[i]; - } - - data[i + PACKET_HEADER] = 0x00; - - Int2Str (file_ptr, *length); - for (j =0, i = i + PACKET_HEADER + 1; file_ptr[j] != '\0' ; ) - { - data[i++] = file_ptr[j++]; - } - - for (j = i; j < PACKET_SIZE + PACKET_HEADER; j++) - { - data[j] = 0; - } -} - -/** - * @brief Prepare the data packet - * @param timeout - * 0: end of transmission - */ -void Ymodem_PreparePacket(uint8_t *SourceBuf, uint8_t *data, uint8_t pktNo, uint32_t sizeBlk) -{ - uint16_t i, size, packetSize; - uint8_t* file_ptr; - - /* Make first three packet */ - packetSize = sizeBlk >= PACKET_1K_SIZE ? PACKET_1K_SIZE : PACKET_SIZE; - size = sizeBlk < packetSize ? sizeBlk :packetSize; - if (packetSize == PACKET_1K_SIZE) - { - data[0] = STX; - } - else - { - data[0] = SOH; - } - data[1] = pktNo; - data[2] = (~pktNo); - file_ptr = SourceBuf; - - /* Filename packet has valid data */ - for (i = PACKET_HEADER; i < size + PACKET_HEADER;i++) - { - data[i] = *file_ptr++; - } - if ( size <= packetSize) - { - for (i = size + PACKET_HEADER; i < packetSize + PACKET_HEADER; i++) - { - data[i] = 0x1A; /* EOF (0x1A) or 0x00 */ - } - } -} - -/** - * @brief Update CRC16 for input byte - * @param CRC input value - * @param input byte - * @retval None - */ -uint16_t UpdateCRC16(uint16_t crcIn, uint8_t byte) -{ - uint32_t crc = crcIn; - uint32_t in = byte|0x100; - do - { - crc <<= 1; - in <<= 1; - if(in&0x100) - ++crc; - if(crc&0x10000) - crc ^= 0x1021; - } - while(!(in&0x10000)); - return crc&0xffffu; -} - - -/** - * @brief Cal CRC16 for YModem Packet - * @param data - * @param length - * @retval None - */ -uint16_t Cal_CRC16(const uint8_t* data, uint32_t size) -{ - uint32_t crc = 0; - const uint8_t* dataEnd = data+size; - while(data> 8); - Send_Byte(tempCRC & 0xFF); - } - else - { - tempCheckSum = CalChecksum (&packet_data[3], PACKET_SIZE); - Send_Byte(tempCheckSum); - } - - /* Wait for Ack and 'C' */ - if (Receive_Byte(&receivedC[0], 10000) == 0) - { - if (receivedC[0] == ACK) - { - /* Packet transfered correctly */ - ackReceived = 1; - } - } - else - { - errors++; - } - }while (!ackReceived && (errors < 0x0A)); - - if (errors >= 0x0A) - { - return errors; - } - buf_ptr = buf; - size = sizeFile; - blkNumber = 0x01; - /* Here 1024 bytes package is used to send the packets */ - - - /* Resend packet if NAK for a count of 10 else end of commuincation */ - while (size) - { - /* Prepare next packet */ - Ymodem_PreparePacket(buf_ptr, &packet_data[0], blkNumber, size); - ackReceived = 0; - receivedC[0]= 0; - errors = 0; - do - { - /* Send next packet */ - if (size >= PACKET_1K_SIZE) - { - pktSize = PACKET_1K_SIZE; - - } - else - { - pktSize = PACKET_SIZE; - } - Ymodem_SendPacket(packet_data, pktSize + PACKET_HEADER); - /* Send CRC or Check Sum based on CRC16_F */ - /* Send CRC or Check Sum based on CRC16_F */ - if (CRC16_F) - { - tempCRC = Cal_CRC16(&packet_data[3], pktSize); - Send_Byte(tempCRC >> 8); - Send_Byte(tempCRC & 0xFF); - } - else - { - tempCheckSum = CalChecksum (&packet_data[3], pktSize); - Send_Byte(tempCheckSum); - } - - /* Wait for Ack */ - if ((Receive_Byte(&receivedC[0], 100000) == 0) && (receivedC[0] == ACK)) - { - ackReceived = 1; - if (size > pktSize) - { - buf_ptr += pktSize; - size -= pktSize; - if (blkNumber == (FLASH_IMAGE_SIZE/1024)) - { - return 0xFF; /* error */ - } - else - { - blkNumber++; - } - } - else - { - buf_ptr += pktSize; - size = 0; - } - } - else - { - errors++; - } - }while(!ackReceived && (errors < 0x0A)); - /* Resend packet if NAK for a count of 10 else end of commuincation */ - - if (errors >= 0x0A) - { - return errors; - } - - } - ackReceived = 0; - receivedC[0] = 0x00; - errors = 0; - do - { - Send_Byte(EOT); - /* Send (EOT); */ - /* Wait for Ack */ - if ((Receive_Byte(&receivedC[0], 10000) == 0) && receivedC[0] == ACK) - { - ackReceived = 1; - } - else - { - errors++; - } - }while (!ackReceived && (errors < 0x0A)); - - if (errors >= 0x0A) - { - return errors; - } - - /* Last packet preparation */ - ackReceived = 0; - receivedC[0] = 0x00; - errors = 0; - - packet_data[0] = SOH; - packet_data[1] = 0; - packet_data [2] = 0xFF; - - for (i = PACKET_HEADER; i < (PACKET_SIZE + PACKET_HEADER); i++) - { - packet_data [i] = 0x00; - } - - do - { - /* Send Packet */ - Ymodem_SendPacket(packet_data, PACKET_SIZE + PACKET_HEADER); - /* Send CRC or Check Sum based on CRC16_F */ - tempCRC = Cal_CRC16(&packet_data[3], PACKET_SIZE); - Send_Byte(tempCRC >> 8); - Send_Byte(tempCRC & 0xFF); - - /* Wait for Ack and 'C' */ - if (Receive_Byte(&receivedC[0], 10000) == 0) - { - if (receivedC[0] == ACK) - { - /* Packet transfered correctly */ - ackReceived = 1; - } - } - else - { - errors++; - } - - }while (!ackReceived && (errors < 0x0A)); - /* Resend packet if NAK for a count of 10 else end of commuincation */ - if (errors >= 0x0A) - { - return errors; - } - - do - { - Send_Byte(EOT); - /* Send (EOT); */ - /* Wait for Ack */ - if ((Receive_Byte(&receivedC[0], 10000) == 0) && receivedC[0] == ACK) - { - ackReceived = 1; - } - else - { - errors++; - } - }while (!ackReceived && (errors < 0x0A)); - - if (errors >= 0x0A) - { - return errors; - } - return 0; /* file trasmitted successfully */ -} - -/** - * @} - */ - -/*******************(C)COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/