Skip to content

Commit 115cefc

Browse files
committed
Fix XModem for SecureCRT telnet client
1 parent 0ad8696 commit 115cefc

File tree

4 files changed

+89
-26
lines changed

4 files changed

+89
-26
lines changed

CHANGELOG.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ All notable changes to this project will be documented in this file.
77
### Added
88
- Command `JsonPP 0..7` to enable (>0) JSON Pretty Print on user interfaces and set number of indents
99
- Command `JsonPP <command>|backlog <command>;...` to enable JSON PP only once
10-
- WebUI status line for MQTT and TLS, added `FUNC_WEB_STATUS` event
10+
- WebUI status line for MQTT and TLS, added `FUNC_WEB_STATUS` event (#23326)
1111

1212
### Breaking Changed
1313

RELEASENOTES.md

+1
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm
118118
### Added
119119
- Command `JsonPP 0..7` to enable (>0) JSON Pretty Print on user interfaces and set number of indents
120120
- Command `JsonPP <command>|backlog <command>;...` to enable JSON PP only once
121+
- WebUI status line for MQTT and TLS, added `FUNC_WEB_STATUS` event [#23326](https://github.com/arendst/Tasmota/issues/23326)
121122

122123
### Breaking Changed
123124

tasmota/tasmota_support/support_command.ino

+4-1
Original file line numberDiff line numberDiff line change
@@ -912,6 +912,7 @@ void CmndStatus(void)
912912
char stemp[200];
913913
char stemp2[TOPSZ];
914914

915+
// Status
915916
if ((0 == payload) || (-99 == payload)) {
916917
uint32_t maxfn = (TasmotaGlobal.devices_present > MAX_FRIENDLYNAMES) ? MAX_FRIENDLYNAMES : (!TasmotaGlobal.devices_present) ? 1 : TasmotaGlobal.devices_present;
917918
#ifdef USE_SONOFF_IFAN
@@ -1111,6 +1112,7 @@ void CmndStatus(void)
11111112
CmndStatusResponse(6);
11121113
}
11131114

1115+
// Status 7 - StatusTIM
11141116
if ((0 == payload) || (7 == payload)) {
11151117
if (99 == Settings->timezone) {
11161118
snprintf_P(stemp, sizeof(stemp), PSTR("%d" ), Settings->timezone);
@@ -1133,6 +1135,7 @@ void CmndStatus(void)
11331135

11341136
#if defined(USE_ENERGY_SENSOR) && defined(USE_ENERGY_MARGIN_DETECTION)
11351137
if (TasmotaGlobal.energy_driver) {
1138+
// Status 9 - StatusPTH
11361139
if ((0 == payload) || (9 == payload)) {
11371140
EnergyMarginStatus();
11381141
CmndStatusResponse(9);
@@ -1169,7 +1172,7 @@ void CmndStatus(void)
11691172
#endif // FIRMWARE_MINIMAL
11701173

11711174
#ifdef USE_SHUTTER
1172-
// Status 13
1175+
// Status 13 - StatusSHT
11731176
if ((0 == payload) || (13 == payload)) {
11741177
if (ShutterStatus()) { CmndStatusResponse(13); }
11751178
}

tasmota/tasmota_xdrv_driver/xdrv_120_xyzmodem.ino

+83-24
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
*
1313
* Usage:
1414
* Use a tool able supporting XModem file transfer and to connect either using serial or telnet with Tasmota.
15-
* TeraTerm
15+
* TeraTerm (When using telnet enable non-bare CR support with Tasmota command `Teraterm 1`)
1616
* SyncTerm
17+
* SecureCRT (When using Telnet set all Telnet Advanced Options OFF EXCEPT 'Server requires bare CR`)
18+
*
1719
* To start XModem file transfer first execute Tasmota command XSend or XReceive,
1820
* then start tool XModem receive or send.
1921
*
@@ -37,6 +39,8 @@
3739

3840
#define XDRV_120 120
3941

42+
//#define XYZM_DEBUG
43+
4044
#define XYZM_SOH 0x01 // Start of 128 byte data
4145
#define XYZM_STX 0x02 // Start of 1024 byte data
4246
#define XYZM_EOT 0x04
@@ -51,7 +55,7 @@
5155
// Number of seconds until giving up hope of receiving sync packets from host.
5256
const uint8_t XYZMODEM_SYNC_TIMEOUT = 30;
5357
const uint8_t XYZMODEM_RECV_TIMEOUT_SHORT = 1; // Protocol = 10 seconds
54-
const uint8_t XYZMODEM_RECV_TIMEOUT_LONG = 20; // Protocol = 60 seconds
58+
const uint8_t XYZMODEM_RECV_TIMEOUT_LONG = 3; // Protocol = 60 seconds
5559

5660
// Number of times we try to send a packet to the host until we give up sending..
5761
const uint8_t XYZMODEM_MAX_RETRY = 4; // Protocol = 10 for total packets to be send. Here retry per packet
@@ -353,23 +357,51 @@ bool XYZModemReadAvailable(uint32_t timeout) {
353357
}
354358

355359
int XYZModemReadByte(void) {
356-
if (!XYZModemReadAvailable(XYZModem.receive_timeout)) {
357-
return -1;
358-
}
359-
int in_char = XYZModemRead();
360-
if (in_char >= 0) {
361-
if (TXMP_TELNET == XYZModem.protocol) {
362-
if (0xFF == in_char) { // Fix XModem over Telnet escape
363-
XYZModemRead();
364-
}
365-
if (XYZModem.teraterm && (0x0D == in_char)) { // Fix TeraTerm
366-
XYZModemRead();
360+
uint8_t telnet_buffer[3];
361+
while (true) {
362+
if (!XYZModemReadAvailable(XYZModem.receive_timeout)) {
363+
return -1;
364+
}
365+
int in_char = XYZModemRead();
366+
#ifdef XYZM_DEBUG
367+
Serial.printf("%02X",in_char);
368+
#endif
369+
if (in_char >= 0) {
370+
if (TXMP_TELNET == XYZModem.protocol) {
371+
if (0xFF == in_char) { // Telnet IAC - Fix XModem over Telnet escape
372+
telnet_buffer[0] = in_char;
373+
int in_char2 = XYZModemRead();
374+
#ifdef XYZM_DEBUG
375+
Serial.printf("[%02X]",in_char2);
376+
#endif
377+
if ((in_char2 >= 251) && (in_char2 <= 254)) { // Telnet IAC - WILL, DO, WONT, DONT
378+
if (251 == in_char2) { // 251 = 0xFB = WILL
379+
telnet_buffer[1] = 254; // 254 = 0xFE = DONT
380+
}
381+
else if (253 == in_char2) { // 253 = 0xFD = DO
382+
telnet_buffer[1] = 252; // 252 = 0xFC = WONT
383+
}
384+
int in_char3 = XYZModemRead();
385+
telnet_buffer[2] = in_char3;
386+
#ifdef XYZM_DEBUG
387+
Serial.printf("(%02X)",in_char3);
388+
#endif
389+
XYZModemWriteBuf(telnet_buffer, 3); // Send not supported telnet functions reponse(s)
390+
continue;
391+
}
392+
}
393+
if (XYZModem.teraterm && (0x0D == in_char)) { // Fix TeraTerm
394+
int in_char2 = XYZModemRead();
395+
#ifdef XYZM_DEBUG
396+
Serial.printf("[%02X]",in_char2);
397+
#endif
398+
}
367399
}
400+
return in_char;
368401
}
402+
break;
369403
}
370-
// AddLog(LOG_LEVEL_DEBUG, PSTR("XMD: Rcvd %d"), in_char);
371-
372-
return in_char;
404+
return -1;
373405
}
374406

375407
/*********************************************************************************************\
@@ -499,7 +531,7 @@ void XYZModemSendNakOrC(void) {
499531
XYZModemWrite(out_char);
500532
}
501533

502-
void XYZModemSendNak(void) {
534+
bool XYZModemSendNak(void) {
503535
// When the receiver wishes to <nak>, it should call a "PURGE" subroutine, to wait
504536
// for the line to clear. Recall the sender tosses any characters in its buffer
505537
// immediately upon completing sending a block, to ensure no glitches were mis-interpreted.
@@ -516,13 +548,14 @@ void XYZModemSendNak(void) {
516548
XYZModem.nak_count--;
517549
if (0 == XYZModem.nak_count) {
518550
XYZModemCancel(); // Cancel xfer
519-
return;
551+
return false;
520552
}
521553
}
522554

523555
XYZModemWrite(XYZM_NAK);
524556

525557
XYZModem.mode = XYZD_SOH;
558+
return true;
526559
}
527560

528561
bool XYZModemCheckPacket(uint8_t *buffer) {
@@ -630,21 +663,43 @@ int XYZModemReceive(uint32_t packet_no) {
630663
}
631664
case XYZD_BLK1: {
632665
// AddLog(LOG_LEVEL_DEBUG, PSTR("XMD: XYZD_BLK1"));
633-
666+
/*
667+
// Needed with SecureCRT unless Session Option - Telnet - Server requires bare CR is set
668+
if (TXMP_TELNET == XYZModem.protocol) {
669+
if (0x0D == in_char) {
670+
int in_char2 = XYZModemRead();
671+
#ifdef XYZM_DEBUG
672+
Serial.printf("[%02X]",in_char2);
673+
#endif
674+
}
675+
}
676+
*/
634677
xmodem_buffer[1] = in_char;
635678
XYZModem.mode = XYZD_BLK2;
636679
break;
637680
}
638681
case XYZD_BLK2: {
639682
// AddLog(LOG_LEVEL_DEBUG, PSTR("XMD: XYZD_BLK2 %02X, exor %02X"), in_char, (in_char ^ xmodem_buffer[1]));
640-
683+
/*
684+
// Needed with SecureCRT unless Session Option - Telnet - Server requires bare CR is set
685+
if (TXMP_TELNET == XYZModem.protocol) {
686+
if (0x0D == in_char) {
687+
int in_char2 = XYZModemRead();
688+
#ifdef XYZM_DEBUG
689+
Serial.printf("[%02X]",in_char2);
690+
#endif
691+
}
692+
}
693+
*/
641694
xmodem_buffer[2] = in_char;
642695
if (0xFF == (in_char ^ xmodem_buffer[1])) {
643696
xmodem_buffer_ptr = 3;
644697
packet_size = 3 + XYZModem.packet_size + ((XYZModem.oldChecksum) ? 1 : 2);
645698
XYZModem.mode = XYZD_DATA;
646699
} else {
647-
XYZModemSendNak();
700+
if (!XYZModemSendNak()) {
701+
return XYZS_PACKET;
702+
}
648703
}
649704
break;
650705
}
@@ -653,7 +708,6 @@ int XYZModemReceive(uint32_t packet_no) {
653708

654709
xmodem_buffer[xmodem_buffer_ptr++] = in_char;
655710
if (xmodem_buffer_ptr >= packet_size) {
656-
// XYZFile.byte_counter += XYZModem.packet_size;
657711
XYZFile.byte_counter = packet_no * XYZModem.packet_size;
658712
XYZModem.mode = XYZD_SOH;
659713
packet_ready = true;
@@ -806,6 +860,9 @@ bool XYZModemLoop(void) {
806860
}
807861
int result = XYZModemReceive(XYZModem.packet_no);
808862
if (result) {
863+
#ifdef XYZM_DEBUG
864+
Serial.println();
865+
#endif
809866
switch (result) {
810867
case XYZS_EOT: {
811868
XYZModemFileWriteEot(1);
@@ -824,6 +881,7 @@ bool XYZModemLoop(void) {
824881
// Receive character timeout - will retry
825882
AddLog(LOG_LEVEL_DEBUG, PSTR("XMD: Timeout - retry"));
826883
XYZModem.retry--;
884+
XYZFile.step = XYZM_RECEIVE;
827885
break;
828886
}
829887
case XYZS_OTHER: {
@@ -863,6 +921,9 @@ bool XYZModemLoop(void) {
863921
return true;
864922
}
865923
} else {
924+
#ifdef XYZM_DEBUG
925+
Serial.println();
926+
#endif
866927
XYZModem.packet_no++;
867928
}
868929
break;
@@ -916,7 +977,6 @@ void CmndXSend(void) {
916977
if (!strcasecmp_P(XdrvMailbox.data, PSTR("Settings"))) {
917978
XYZFile.size = sizeof(TSettings);
918979
XYZFile.file = false;
919-
// XYZModem.enabled = XYZM_SEND;
920980
ResponseCmndChar("Ready to start receive Settings");
921981
#ifdef USE_UFILESYS
922982
} else {
@@ -925,7 +985,6 @@ void CmndXSend(void) {
925985
XYZFile.size = TfsFileSize(XYZFile.file_name);
926986
if (XYZFile.size) {
927987
XYZFile.file = true;
928-
// XYZModem.enabled = XYZM_SEND;
929988
ResponseCmndChar("Ready to start receive file");
930989
} else {
931990
ResponseCmndChar("File is empty");

0 commit comments

Comments
 (0)