@@ -58,6 +58,8 @@ ESP8266::ESP8266(PinName tx, PinName rx, bool debug, PinName rts, PinName cts)
58
58
_error(false ),
59
59
_busy(false ),
60
60
_reset_done(false ),
61
+ _prev_send_ok_pending(false ),
62
+ _send_fail_received(false ),
61
63
_conn_status(NSAPI_STATUS_DISCONNECTED)
62
64
{
63
65
_serial.set_baud (MBED_CONF_ESP8266_SERIAL_BAUDRATE);
@@ -614,7 +616,16 @@ bool ESP8266::dns_lookup(const char *name, char *ip)
614
616
615
617
nsapi_error_t ESP8266::send (int id, const void *data, uint32_t amount)
616
618
{
619
+ if (_prev_send_ok_pending && _sock_i[id].proto == NSAPI_TCP) {
620
+ tr_debug (" send(): Previous packet was not ACK-ed with SEND OK." );
621
+ return NSAPI_ERROR_WOULD_BLOCK;
622
+ }
623
+
617
624
nsapi_error_t ret = NSAPI_ERROR_DEVICE_ERROR;
625
+ _send_fail_received = false ;
626
+ int bytes_confirmed = 0 ;
627
+ constexpr unsigned int send_ack_retries = 3 ;
628
+
618
629
// +CIPSEND supports up to 2048 bytes at a time
619
630
// Data stream can be truncated
620
631
if (amount > 2048 && _sock_i[id].proto == NSAPI_TCP) {
@@ -635,35 +646,83 @@ nsapi_error_t ESP8266::send(int id, const void *data, uint32_t amount)
635
646
}
636
647
637
648
if (!_parser.recv (" >" )) {
649
+ // This means ESP8266 hasn't even started to receive data
638
650
tr_debug (" send(): Didn't get \" >\" " );
639
- ret = NSAPI_ERROR_WOULD_BLOCK;
651
+ if (_sock_i[id].proto == NSAPI_TCP) {
652
+ ret = NSAPI_ERROR_WOULD_BLOCK; // Not neccesarily critical error.
653
+ } else if (_sock_i[id].proto == NSAPI_UDP) {
654
+ ret = NSAPI_ERROR_NO_MEMORY;
655
+ }
656
+ goto END;
657
+ }
658
+
659
+ if (_parser.write ((char *)data, (int )amount) < 0 ) {
660
+ tr_debug (" send(): Failed to write serial data" );
661
+ // Serial is not working, serious error, reset needed.
662
+ ret = NSAPI_ERROR_DEVICE_ERROR;
640
663
goto END;
641
664
}
642
665
643
- if (_parser.write ((char *)data, (int )amount) >= 0 && _parser.recv (" SEND OK" )) {
644
- ret = NSAPI_ERROR_OK;
666
+ // The "Recv X bytes" is not documented.
667
+ if (!_parser.recv (" Recv %d bytes" , &bytes_confirmed)) {
668
+ tr_debug (" send(): Bytes not confirmed." );
669
+ ret = NSAPI_ERROR_DEVICE_ERROR;
670
+ goto END;
671
+ } else if (bytes_confirmed != amount) {
672
+ tr_debug (" send(): Error: confirmed %d bytes, but expected %d." , bytes_confirmed, amount);
673
+ ret = NSAPI_ERROR_DEVICE_ERROR;
674
+ goto END;
675
+ }
676
+
677
+ // We might receive "busy s/p...", "SEND OK" or "SEND FAIL" from modem, so we need to check that also
678
+ _parser.oob (" SEND FAIL" , callback (this , &ESP8266::_oob_send_fail_received));
679
+ for (unsigned int i = send_ack_retries; i > 0 ; i--) {
680
+ if (!_parser.recv (" SEND OK" )) {
681
+ if (_error || _send_fail_received) {
682
+ _parser.remove_oob (" SEND FAIL" );
683
+ goto END;
684
+ }
685
+ if (_busy) {
686
+ _busy = false ;
687
+ tr_debug (" send(): Busy, %d retries left..." , i - 1 );
688
+ } else {
689
+ tr_debug (" send(): Not busy, but no SEND OK. %d retries left..." , i - 1 );
690
+ }
691
+ } else {
692
+ ret = amount; // Got "SEND OK" - return number of bytes.
693
+ goto END;
694
+ }
645
695
}
646
696
697
+ // ESP8266 ACKed data over serial, but did not ACK over TCP or report any error.
698
+ _prev_send_ok_pending = true ;
699
+ _parser.oob (" SEND OK" , callback (this , &ESP8266::_oob_send_ok_received));
700
+ ret = amount;
701
+
647
702
END:
648
703
_process_oob (ESP8266_RECV_TIMEOUT, true ); // Drain USART receive register to avoid data overrun
649
704
650
705
// error hierarchy, from low to high
651
706
if (_busy) {
652
707
ret = NSAPI_ERROR_WOULD_BLOCK;
653
- tr_debug (" send(): Modem busy. " );
654
- }
655
-
656
- if (ret == NSAPI_ERROR_DEVICE_ERROR) {
657
- ret = NSAPI_ERROR_WOULD_BLOCK;
658
- tr_debug (" send(): Send failed." );
708
+ tr_debug (" send(): Modem busy." );
659
709
}
660
710
661
711
if (_error) {
662
712
ret = NSAPI_ERROR_CONNECTION_LOST;
663
713
tr_debug (" send(): Connection disrupted." );
664
714
}
665
715
666
- if (!_sock_i[id].open && ret != NSAPI_ERROR_OK) {
716
+ if (_send_fail_received) {
717
+ if (_sock_i[id].proto == NSAPI_TCP) {
718
+ ret = NSAPI_ERROR_DEVICE_ERROR;
719
+ } else {
720
+ ret = NSAPI_ERROR_NO_MEMORY;
721
+ }
722
+ tr_debug (" send(): SEND FAIL received." );
723
+ }
724
+
725
+ if (!_sock_i[id].open && ret < 0 ) {
667
726
ret = NSAPI_ERROR_CONNECTION_LOST;
668
727
tr_debug (" send(): Socket closed abruptly." );
669
728
}
@@ -1205,6 +1264,18 @@ void ESP8266::_oob_connection_status()
1205
1264
_conn_stat_cb ();
1206
1265
}
1207
1266
1267
+ void ESP8266::_oob_send_ok_received ()
1268
+ {
1269
+ tr_debug (" _oob_send_ok_received called" );
1270
+ _prev_send_ok_pending = false ;
1271
+ }
1272
+
1273
+ void ESP8266::_oob_send_fail_received ()
1274
+ {
1275
+ tr_debug (" _oob_send_fail_received called" );
1276
+ _send_fail_received = true ;
1277
+ }
1278
+
1208
1279
int8_t ESP8266::default_wifi_mode ()
1209
1280
{
1210
1281
int8_t mode;
0 commit comments