I created xmodem used in UART. This protocol have checksum of data payload in uint16_t. I tested this part of code showing below, but it is still stucked. Showing below in the picture.
Received chuck and another checksum calculated from the data payload is matched on the first,but failed on the second
Why can not be matched the received chuck and another checksum calculated from the data payload on the second?
This is a part of code calculating checksum.
Sender of xmodem.(xymodem_send)
chunk.crc = swap16(crc16(chunk.payload, sizeof(chunk.payload)));
Receiver of xmodem.(xmodem_receive)
uint16_t recChksum;
uint16_t recCRC;
// recData is data payload
ret = read(serial_fd, recData, sizeof(recData));
printf("Data buffer is %c\n", &recData);
fflush(stdout);
// processing up to 1024bytes
if (ret != sizeof(recData)) {
rec_chunk_data += ret;
while(rec_chunk_data < sizeof(recData)){
ret = read(serial_fd, recData + (sizeof(uint8_t) * rec_chunk_data), (sizeof(recData) - rec_chunk_data));
rec_chunk_data += ret;
printf("ret is proceeding: %d\n", ret);
fflush(stdout);
}
}
ret = read(serial_fd, &recChksum, sizeof(recChksum));
printf("Check sum is %d\n", recChksum);
fflush(stdout);
// Calculating checksum from data payload
recCRC = swap16(crc16(recData, sizeof(recData)));
// data integrity check
if(recChksum != recCRC){
printf("Check sum is %d and %d\n", recChksum, swap16(crc16(recData, sizeof(recData))));
perror("swap16");
return -errno;
}
And, This is full source code.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <string>
#define X_STX 0x02
#define X_ACK 0x06
#define X_NAK 0x15
#define X_EOF 0x04
#define MAX_RETRY (9)
#define min(a, b) ((a) < (b) ? (a) : (b))
struct xmodem_chunk {
uint8_t start;
uint8_t block;
uint8_t block_neg;
uint8_t payload[1024];
uint16_t crc;
} __attribute__((packed));
void printArray(const uint8_t *ptr, size_t length)
{
//for statment to print values using array
printf("*****This is payload*****\n");
size_t i = 0;
for( ; i < length; ++i )
printf("%c", ptr[i]);
printf("*****This is payload*****\n");
fflush(stdout);
}
#define CRC_POLY 0x1021
static uint16_t crc_update(uint16_t crc_in, int incr)
{
uint16_t xor1 = crc_in >> 15;
uint16_t out1 = crc_in << 1;
if(incr)
out1++;
if(xor1)
out1 ^= CRC_POLY; // xor 0b1000000100001
return out1;
}
static uint16_t crc16(const uint8_t *data, uint16_t size)
{
uint16_t crc, i;
printf("data size :%d\n",size);
printArray(data, size); // debug
for (crc = 0; size > 0; size--, data++)
for (i = 0x80; i; i >>= 1)
crc = crc_update(crc, *data & i);
for (i = 0; i < 16; i++)
crc = crc_update(crc, 0);
return crc;
}
static uint16_t swap16(uint16_t in)
{
return (in >> 8) | ((in & 0xff) << 8);
}
enum {
PROTOCOL_XMODEM,
PROTOCOL_YMODEM,
};
static int xmodem_receive(int serial_fd, char* filename, int _crc, int use_crc){
printf("serial_fd is ....%d\n", serial_fd);
fflush(stdout);
int skip = 0;
uint8_t sdCRC = 'C'; // Request-To-Send
uint8_t sdACK = X_ACK; //
uint8_t eof = X_EOF;
uint8_t stx = X_STX;
uint8_t sdNAK = X_NAK;
uint8_t recSTX; // receive SOH from chunk
uint8_t recBlk; // receive blk from chunk
uint8_t recNegBlk; // receive blk negative from chunk
uint8_t recData[1024]; // receive data from chunk
uint16_t recChksum;
uint16_t recCRC;
uint8_t heads_or_tails;
uint8_t expected_blkno;
int rec_chunk_data = 0;
FILE *fp;
int ret, fd;
struct stat stat;
// If we want to receive, We have to send NAK to Sendor.
if (use_crc)
use_crc = MAX_RETRY + 1;
/* Writing as binary */
fp = fopen(filename, "wb");
//Send NAK still read SOH that header of one data chunks
/*
CRC 16
Sending C
Sending NAK
*/
while(use_crc){
char status;
printf("Waiting for sender ping ...");
fflush(stdout);
//
if(_crc){
printf("Send C ping....\n");
ret = write(serial_fd, &sdCRC, sizeof(sdCRC));
}else{
// send NAK before read SOH
printf("Send NAK ping....\n");
ret = write(serial_fd, &sdNAK, sizeof(sdNAK));
} // after sending NAK,receiving SOH from chunk
fflush(stdout);
ret = read(serial_fd, &recSTX, sizeof(recSTX));
printf("serial_fd is ....%d\n", serial_fd);
fflush(stdout);
if(recSTX == X_STX){
printf("STX is %c::%c\n", &recSTX, X_STX);
break;
}else{
printf("Garabage payload %c\n", &recSTX);
}
fflush(stdout);
if (ret != sizeof(recSTX)) {
printf("Not working");
fflush(stdout);
perror("read");
return -errno;
}
use_crc--;
}
expected_blkno = 1;
while(ret != eof){
memset(recData, 0, sizeof(recData));
//So next, receiving blk
ret = read(serial_fd, &recBlk, sizeof(recBlk));
printf("serial_fd is ....%d\n", serial_fd);
fflush(stdout);
printf("ret is proceeding: %d\n", ret);
fflush(stdout);
printf("Block Num is %d\n", recBlk);
fflush(stdout);
if (ret != sizeof(recBlk)) {
perror("read");
return -errno;
}
ret = read(serial_fd, &recNegBlk, sizeof(recNegBlk));
printf("ret is proceeding: %d\n", ret);
fflush(stdout);
printf("serial_fd is ....%d\n", serial_fd);
fflush(stdout);
printf("Negative Block Num is %d\n", recNegBlk);
fflush(stdout);
if (ret != sizeof(recNegBlk)) {
perror("read");
return -errno;
}
ret = read(serial_fd, recData, sizeof(recData));
printf("Data buffer is %c\n", &recData);
fflush(stdout);
if (ret != sizeof(recData)) {
rec_chunk_data += ret;
while(rec_chunk_data < sizeof(recData)){
ret = read(serial_fd, recData + (sizeof(uint8_t) * rec_chunk_data), (sizeof(recData) - rec_chunk_data));
rec_chunk_data += ret;
printf("ret is proceeding: %d\n", ret);
fflush(stdout);
}
}
printf("ret is proceeding: %d\n", ret);
fflush(stdout);
ret = read(serial_fd, &recChksum, sizeof(recChksum));
printf("ret is proceeding: %d\n", ret);
fflush(stdout);
printf("Check sum is %d\n", recChksum);
fflush(stdout);
if (ret != sizeof(recChksum)) {
printf("Can't fetch the Check sum");
perror("read");
return -errno;
}
// data block number check
if(recBlk == 0xff - recNegBlk){
printf("valid block num :%d and %d\n", recBlk, recNegBlk);
fflush(stdout);
}
printf("serial_fd is ....%d\n", serial_fd);
fflush(stdout);
recCRC = swap16(crc16(recData, sizeof(recData)));
// data integrity check
if(recChksum != recCRC){
printf("Check sum is %d and %d, %d\n", recChksum, swap16(crc16(recData, sizeof(recData))), recCRC);
perror("swap16");
return -errno;
}
// check of appended "0xff" from end of data to end of chunk in chunk
unsigned char *ptr = recData;
ptr += sizeof(recData);
while(*ptr == 0xff){
ptr--;
}
fwrite(recData, (ptr - recData),1,fp); // write Datas bytes from our buffer
// set skip flag or end connect
ret = write(serial_fd, &sdACK, sizeof(sdACK));
ret = read(serial_fd, &heads_or_tails, sizeof(heads_or_tails));
if (ret != sizeof(eof) && ret != sizeof(X_STX)){
printf("sizeof eof :%d\n", sizeof(eof));
printf("sizeof STX :%d\n", sizeof(X_STX));
printf("sizeof uint8_t :%d\n", sizeof(uint8_t));
perror("STX EOF length check error");
return -errno;
}else{
if(heads_or_tails == stx){
printf("next chunk\n");
fflush(stdout);
expected_blkno++;
}else if(heads_or_tails == eof){
printf("EOF ...");
fflush(stdout);
break;
}else{
ret = write(serial_fd, &sdNAK, sizeof(sdNAK));
printf("Interruption\n");
fflush(stdout);
}
}
}
printf("done.\n");
fclose(fp);
return 0;
}
static int xymodem_send(int serial_fd, const char *filename, int protocol, int wait)
{
size_t len;
int ret, fd;
uint8_t answer;
struct stat stat;
const uint8_t *buf;
uint8_t eof = X_EOF;
struct xmodem_chunk chunk;
int skip_payload = 0;
fd = open(filename, O_RDONLY);
if (fd < 0) {
perror("open");
return -errno;
}
fstat(fd, &stat);
len = stat.st_size;
buf = static_cast<uint8_t*>(mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0));
if (!buf) {
perror("mmap");
return -errno;
}
if (wait) {
printf("Waiting for receiver ping ...");
fflush(stdout);
do {
ret = read(serial_fd, &answer, sizeof(answer));
if (ret != sizeof(answer)) {
perror("read");
return -errno;
}
} while (answer != 'C');
printf("done.\n");
fflush(stdout);
}
if (protocol == PROTOCOL_YMODEM) {
strncpy((char *) chunk.payload, filename, sizeof(chunk.payload));
chunk.block = 0;
skip_payload = 1;
} else {
chunk.block = 1;
}
chunk.start = X_STX;
int loops = 0;
printf("STX Setted.\n");
fflush(stdout);
while (len) {
printf(" round %d\n", loops);
fflush(stdout);
size_t z = 0;
int next = 0;
char status;
if (!skip_payload) {
z = min(len, sizeof(chunk.payload));
memcpy(chunk.payload, buf, z);
memset(chunk.payload + z, 0xff, sizeof(chunk.payload) - z);
printf("file chunk: %c\n", chunk.payload);
fflush(stdout);
} else {
skip_payload = 0;
}
printf("%d\n", swap16(crc16(chunk.payload, sizeof(chunk.payload))));
fflush(stdout);
chunk.crc = swap16(crc16(chunk.payload, sizeof(chunk.payload)));
chunk.block_neg = 0xff - chunk.block;
ret = write(serial_fd, &chunk, sizeof(chunk));
if (ret != sizeof(chunk))
return -errno;
ret = read(serial_fd, &answer, sizeof(answer));
if (ret != sizeof(answer))
return -errno;
switch (answer) {
case X_NAK:
status = 'N';
break;
case X_ACK:
status = '.';
next = 1;
break;
default:
status = '?';
break;
}
printf("%c", status);
fflush(stdout);
if (next) {
chunk.block++;
len -= z;
buf += z;
}
}
ret = write(serial_fd, &eof, sizeof(eof));
if (ret != sizeof(eof))
return -errno;
/* send EOT again for YMODEM */
if (protocol == PROTOCOL_YMODEM) {
ret = write(serial_fd, &eof, sizeof(eof));
if (ret != sizeof(eof))
return -errno;
}
printf("done.\n");
return 0;
}
static int open_serial(const char *path, int baud)
{
int fd;
struct termios tty;
fd = open(path, O_RDWR | O_SYNC);
if (fd < 0) {
perror("open");
return -errno;
}
memset(&tty, 0, sizeof(tty));
if (tcgetattr(fd, &tty) != 0) {
perror("tcgetattr");
return -errno;
}
cfsetospeed(&tty, baud);
cfsetispeed(&tty, baud);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
tty.c_iflag &= ~IGNBRK; // disable break processing
tty.c_lflag = 0; // no signaling chars, no echo,
// no canonical processing
tty.c_oflag = 0; // no remapping, no delays
tty.c_cc[VMIN] = 1; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
tty.c_cflag |= (CLOCAL | CREAD); // ignore modem controls,
// enable reading
tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS;
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
perror("tcsetattr");
return -errno;
}
return fd;
}
static void dump_serial(int serial_fd)
{
char in;
for (;;) {
read(serial_fd, &in, sizeof(in));
printf("%c", in);
fflush(stdout);
}
}
#ifdef TEST_XMODEM_RECEIVE
#endif // TEST_XMODEM_RECEIVE
int main(int argc, char **argv)
{
int a, ret, serial_fd;
std::string devs;
printf("args:3: %s\n", argv[3]);
printf("STX: %c\n", X_STX);
printf("ACK: %c\n", X_ACK);
printf("NAK: %c\n", X_NAK);
printf("EOF: %c\n", X_EOF);
fflush(stdout);
if(std::string(argv[3]) == "1"){
devs = "/dev/ttyUSB0";
}else{
devs = "/dev/ttyAMA0";
}
printf("devs: %s\n", devs.c_str());
fflush(stdout);
serial_fd = open_serial( devs.c_str(), 1200);
if (serial_fd < 0)
return -errno;
if(std::string(argv[2]) == "0"){
ret = xymodem_send(serial_fd, argv[1], PROTOCOL_XMODEM, 1);
if (ret < 0)
return ret;
}
if(std::string(argv[2]) == "1"){
ret = xmodem_receive(serial_fd, argv[1], 1, 1);
if (ret < 0)
return ret;
}
if(std::string(argv[2]) == "3"){
dump_serial(serial_fd);
if (ret < 0)
return ret;
}
return 0;
}
Postscript:
1)I send text.txt in Ubuntu,and receive text.txt in Raspibian jessie. Showing below text is text.txt in Ubuntu
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaasssssssssss
ssssssssssssssssssssd
and,This is in Raspibian.
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaasssssssssss
ssssssssssssssssssssd
ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
2)Changing "Receiver of xmodem" such as....
recCRC = swap16(crc16(recData, sizeof(recData)));
// data integrity check
if(recChksum /*!= recCRC*/){
printf("Check sum is %d and %d, %d\n", recChksum, swap16(crc16(recData, sizeof(recData))), recCRC);
perror("swap16");
return -errno;
}
are generates the correct checksum showing below
3)Too long text exceed 1024 bytes is only able to output a part of itself. Unless dumping the serial by "dump_serial" function, I can't make sure of others.
4)Lorem ipsum text of sender showing https://justpaste.it/12eoe
is 9 rows, but receiver is only 3 rows https://justpaste.it/12epe
and cut off.
Receiver payload is https://justpaste.it/12epk
.