From 6d6bbc040568bb466d6d288af69fb62471920a09 Mon Sep 17 00:00:00 2001 From: Jaro Date: Wed, 18 Aug 2021 06:46:02 +0200 Subject: [PATCH] Pridanie xmodemu --- XModem.cpp | 375 +++++++++++++++++++++++++++++++++++++++++++++++++++++ XModem.h | 78 +++++++++++ 2 files changed, 453 insertions(+) create mode 100644 XModem.cpp create mode 100644 XModem.h diff --git a/XModem.cpp b/XModem.cpp new file mode 100644 index 0000000..79eac40 --- /dev/null +++ b/XModem.cpp @@ -0,0 +1,375 @@ +// 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=7000; +const int XModem::rcvRetryLimit = 10; + + + + +XModem::XModem(int (*recvChar)(int msDelay), + void (*sendData)(const char *data, int len)) +{ + this->sendData = sendData; + this->recvChar = recvChar; + this->dataHandler = NULL; + +} +XModem::XModem(int (*recvChar)(int msDelay), + void (*sendData)(const char *data, int len), + bool (*dataHandler)(unsigned long number, char *buffer, int len)) +{ + this->sendData = sendData; + this->recvChar = recvChar; + this->dataHandler = dataHandler; + +} + +bool XModem::dataAvail(int delay) +{ + if (this->byte != -1) + return true; + if ((this->byte = this->recvChar(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->recvChar(delay); +} +void XModem::dataWrite(char symbol) +{ + this->sendData(&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(1000); + 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 new file mode 100644 index 0000000..e6344ec --- /dev/null +++ b/XModem.h @@ -0,0 +1,78 @@ +// 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 +// ----------------------------------------------------------------------------- + +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; + + 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); + + 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(int (*recvChar)(int), void (*sendData)(const char *data, int len)); + XModem(int (*recvChar)(int), void (*sendData)(const char *data, int len), + bool (*dataHandler)(unsigned long, char*, int)); + bool receive(); + bool transmit(); + + + +};