2 * Copyright 2017, Adrien Destugues, pulkomandy@pulkomandy.tk
3 * Distributed under terms of the MIT license.
17 // ASCII control characters used in XMODEM protocol
18 static const char kSOH
= 1;
19 static const char kEOT
= 4;
20 static const char kACK
= 6;
21 static const char kNAK
= 21;
22 static const char kCAN
= 24;
23 static const char kSUB
= 26;
25 static const int kBlockSize
= 128;
28 XModemSender::XModemSender(BDataIO
* source
, BSerialPort
* sink
, BHandler
* listener
)
36 fStatus
= "Waiting for receiver" B_UTF8_ELLIPSIS
;
38 BPositionIO
* pos
= dynamic_cast<BPositionIO
*>(source
);
40 pos
->GetSize(&fSourceSize
);
48 XModemSender::~XModemSender()
55 XModemSender::BytesReceived(const uint8_t* data
, size_t length
)
59 for (i
= 0; i
< length
; i
++)
64 // A 'C' to request the first block is a request to use a CRC
65 // in place of an 8-bit checksum.
66 // In any other place, it is ignored.
67 if (fBlockNumber
<= 1) {
68 fStatus
= "CRC requested";
75 fSink
->Write(&kEOT
, 1);
77 fStatus
= "Checksum error, re-send block";
87 if (NextBlock() == B_OK
) {
88 fStatus
= "Sending" B_UTF8_ELLIPSIS
;
91 fStatus
= "Everything sent, waiting for acknowledge";
92 fSink
->Write(&kEOT
, 1);
99 BMessage
msg(kMsgProgress
);
100 msg
.AddInt32("pos", 0);
101 msg
.AddInt32("size", 0);
102 msg
.AddString("info", "Remote cancelled transfer");
103 fListener
.SendMessage(&msg
);
117 XModemSender::SendBlock()
120 uint8_t checksum
= 0;
124 header
[1] = fBlockNumber
;
125 header
[2] = 255 - fBlockNumber
;
127 fSink
->Write(header
, 3);
128 fSink
->Write(fBuffer
, kBlockSize
);
131 uint16_t crc
= CRC(fBuffer
, kBlockSize
);
133 crcBuf
[0] = crc
>> 8;
134 crcBuf
[1] = crc
& 0xFF;
135 fSink
->Write(crcBuf
, 2);
137 // Use a traditional (and fragile) checksum
138 for (i
= 0; i
< kBlockSize
; i
++)
139 checksum
+= fBuffer
[i
];
141 fSink
->Write(&checksum
, 1);
147 XModemSender::NextBlock()
149 memset(fBuffer
, kSUB
, kBlockSize
);
151 if (fSource
->Read(fBuffer
, kBlockSize
) > 0) {
152 // Notify for progress bar update
153 BMessage
msg(kMsgProgress
);
154 msg
.AddInt32("pos", fBlockNumber
);
155 msg
.AddInt32("size", fSourceSize
/ kBlockSize
);
156 msg
.AddString("info", fStatus
);
157 fListener
.SendMessage(&msg
);
159 // Remember that we moved to next block
166 uint16_t XModemSender::CRC(const uint8_t *buf
, size_t len
)
171 crc
^= ((uint16_t)(*buf
++)) << 8;
172 for( i
= 0; i
< 8; ++i
) {
174 crc
= (crc
<< 1) ^ 0x1021;