12
12
*
13
13
* Usage:
14
14
* 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`)
16
16
* SyncTerm
17
+ * SecureCRT (When using Telnet set all Telnet Advanced Options OFF EXCEPT 'Server requires bare CR`)
18
+ *
17
19
* To start XModem file transfer first execute Tasmota command XSend or XReceive,
18
20
* then start tool XModem receive or send.
19
21
*
37
39
38
40
#define XDRV_120 120
39
41
42
+ // #define XYZM_DEBUG
43
+
40
44
#define XYZM_SOH 0x01 // Start of 128 byte data
41
45
#define XYZM_STX 0x02 // Start of 1024 byte data
42
46
#define XYZM_EOT 0x04
51
55
// Number of seconds until giving up hope of receiving sync packets from host.
52
56
const uint8_t XYZMODEM_SYNC_TIMEOUT = 30 ;
53
57
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
55
59
56
60
// Number of times we try to send a packet to the host until we give up sending..
57
61
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) {
353
357
}
354
358
355
359
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
+ }
367
399
}
400
+ return in_char;
368
401
}
402
+ break ;
369
403
}
370
- // AddLog(LOG_LEVEL_DEBUG, PSTR("XMD: Rcvd %d"), in_char);
371
-
372
- return in_char;
404
+ return -1 ;
373
405
}
374
406
375
407
/* ********************************************************************************************\
@@ -499,7 +531,7 @@ void XYZModemSendNakOrC(void) {
499
531
XYZModemWrite (out_char);
500
532
}
501
533
502
- void XYZModemSendNak (void ) {
534
+ bool XYZModemSendNak (void ) {
503
535
// When the receiver wishes to <nak>, it should call a "PURGE" subroutine, to wait
504
536
// for the line to clear. Recall the sender tosses any characters in its buffer
505
537
// immediately upon completing sending a block, to ensure no glitches were mis-interpreted.
@@ -516,13 +548,14 @@ void XYZModemSendNak(void) {
516
548
XYZModem.nak_count --;
517
549
if (0 == XYZModem.nak_count ) {
518
550
XYZModemCancel (); // Cancel xfer
519
- return ;
551
+ return false ;
520
552
}
521
553
}
522
554
523
555
XYZModemWrite (XYZM_NAK);
524
556
525
557
XYZModem.mode = XYZD_SOH;
558
+ return true ;
526
559
}
527
560
528
561
bool XYZModemCheckPacket (uint8_t *buffer) {
@@ -630,21 +663,43 @@ int XYZModemReceive(uint32_t packet_no) {
630
663
}
631
664
case XYZD_BLK1: {
632
665
// 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
+ */
634
677
xmodem_buffer[1 ] = in_char;
635
678
XYZModem.mode = XYZD_BLK2;
636
679
break ;
637
680
}
638
681
case XYZD_BLK2: {
639
682
// 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
+ */
641
694
xmodem_buffer[2 ] = in_char;
642
695
if (0xFF == (in_char ^ xmodem_buffer[1 ])) {
643
696
xmodem_buffer_ptr = 3 ;
644
697
packet_size = 3 + XYZModem.packet_size + ((XYZModem.oldChecksum ) ? 1 : 2 );
645
698
XYZModem.mode = XYZD_DATA;
646
699
} else {
647
- XYZModemSendNak ();
700
+ if (!XYZModemSendNak ()) {
701
+ return XYZS_PACKET;
702
+ }
648
703
}
649
704
break ;
650
705
}
@@ -653,7 +708,6 @@ int XYZModemReceive(uint32_t packet_no) {
653
708
654
709
xmodem_buffer[xmodem_buffer_ptr++] = in_char;
655
710
if (xmodem_buffer_ptr >= packet_size) {
656
- // XYZFile.byte_counter += XYZModem.packet_size;
657
711
XYZFile.byte_counter = packet_no * XYZModem.packet_size ;
658
712
XYZModem.mode = XYZD_SOH;
659
713
packet_ready = true ;
@@ -806,6 +860,9 @@ bool XYZModemLoop(void) {
806
860
}
807
861
int result = XYZModemReceive (XYZModem.packet_no );
808
862
if (result) {
863
+ #ifdef XYZM_DEBUG
864
+ Serial.println ();
865
+ #endif
809
866
switch (result) {
810
867
case XYZS_EOT: {
811
868
XYZModemFileWriteEot (1 );
@@ -824,6 +881,7 @@ bool XYZModemLoop(void) {
824
881
// Receive character timeout - will retry
825
882
AddLog (LOG_LEVEL_DEBUG, PSTR (" XMD: Timeout - retry" ));
826
883
XYZModem.retry --;
884
+ XYZFile.step = XYZM_RECEIVE;
827
885
break ;
828
886
}
829
887
case XYZS_OTHER: {
@@ -863,6 +921,9 @@ bool XYZModemLoop(void) {
863
921
return true ;
864
922
}
865
923
} else {
924
+ #ifdef XYZM_DEBUG
925
+ Serial.println ();
926
+ #endif
866
927
XYZModem.packet_no ++;
867
928
}
868
929
break ;
@@ -916,7 +977,6 @@ void CmndXSend(void) {
916
977
if (!strcasecmp_P (XdrvMailbox.data , PSTR (" Settings" ))) {
917
978
XYZFile.size = sizeof (TSettings);
918
979
XYZFile.file = false ;
919
- // XYZModem.enabled = XYZM_SEND;
920
980
ResponseCmndChar (" Ready to start receive Settings" );
921
981
#ifdef USE_UFILESYS
922
982
} else {
@@ -925,7 +985,6 @@ void CmndXSend(void) {
925
985
XYZFile.size = TfsFileSize (XYZFile.file_name );
926
986
if (XYZFile.size ) {
927
987
XYZFile.file = true ;
928
- // XYZModem.enabled = XYZM_SEND;
929
988
ResponseCmndChar (" Ready to start receive file" );
930
989
} else {
931
990
ResponseCmndChar (" File is empty" );
0 commit comments