@@ -58,6 +58,8 @@ ESP8266::ESP8266(PinName tx, PinName rx, bool debug, PinName rts, PinName cts)
5858 _error(false ),
5959 _busy(false ),
6060 _reset_done(false ),
61+ _prev_send_ok_pending(false ),
62+ _send_fail_received(false ),
6163 _conn_status(NSAPI_STATUS_DISCONNECTED)
6264{
6365 _serial.set_baud (MBED_CONF_ESP8266_SERIAL_BAUDRATE);
@@ -614,7 +616,16 @@ bool ESP8266::dns_lookup(const char *name, char *ip)
614616
615617nsapi_error_t ESP8266::send (int id, const void *data, uint32_t amount)
616618{
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+
617624 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+
618629 // +CIPSEND supports up to 2048 bytes at a time
619630 // Data stream can be truncated
620631 if (amount > 2048 && _sock_i[id].proto == NSAPI_TCP) {
@@ -626,7 +637,6 @@ nsapi_error_t ESP8266::send(int id, const void *data, uint32_t amount)
626637 }
627638
628639 _smutex.lock ();
629- RETRY:
630640 set_timeout (ESP8266_SEND_TIMEOUT);
631641 _busy = false ;
632642 _error = false ;
@@ -635,50 +645,84 @@ nsapi_error_t ESP8266::send(int id, const void *data, uint32_t amount)
635645 goto END;
636646 }
637647
638- // We might receive "busy s/p..." and "OK" from modem, so we need to check that also
639- _ok_received = false ;
640- _parser.oob (" OK" , callback (this , &ESP8266::_oob_ok_received));
641-
642648 if (!_parser.recv (" >" )) {
643- _parser.remove_oob (" OK" );
644- if (_busy) {
645- if (_ok_received) {
646- goto RETRY;
647- } else if (_parser.recv (" OK" )) {
648- goto RETRY;
649- }
650- }
649+ // This means ESP8266 hasn't even started to receive data
651650 tr_debug (" send(): Didn't get \" >\" " );
652- 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;
663+ goto END;
664+ }
665+
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;
653674 goto END;
654675 }
655- _ok_received = false ;
656- _parser.remove_oob (" OK" );
657676
658- if (_parser.write ((char *)data, (int )amount) >= 0 && _parser.recv (" SEND OK" )) {
659- ret = NSAPI_ERROR_OK;
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+ }
660695 }
661696
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+
662702END:
663703 _process_oob (ESP8266_RECV_TIMEOUT, true ); // Drain USART receive register to avoid data overrun
664704
665705 // error hierarchy, from low to high
666706 if (_busy) {
667707 ret = NSAPI_ERROR_WOULD_BLOCK;
668- tr_debug (" send(): Modem busy. " );
669- }
670-
671- if (ret == NSAPI_ERROR_DEVICE_ERROR) {
672- ret = NSAPI_ERROR_WOULD_BLOCK;
673- tr_debug (" send(): Send failed." );
708+ tr_debug (" send(): Modem busy." );
674709 }
675710
676711 if (_error) {
677712 ret = NSAPI_ERROR_CONNECTION_LOST;
678713 tr_debug (" send(): Connection disrupted." );
679714 }
680715
681- 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 ) {
682726 ret = NSAPI_ERROR_CONNECTION_LOST;
683727 tr_debug (" send(): Socket closed abruptly." );
684728 }
@@ -1219,10 +1263,16 @@ void ESP8266::_oob_connection_status()
12191263 _conn_stat_cb ();
12201264}
12211265
1222- void ESP8266::_oob_ok_received ()
1266+ void ESP8266::_oob_send_ok_received ()
1267+ {
1268+ tr_debug (" _oob_send_ok_received called" );
1269+ _prev_send_ok_pending = false ;
1270+ }
1271+
1272+ void ESP8266::_oob_send_fail_received ()
12231273{
1224- tr_debug (" _oob_ok_received called" );
1225- _ok_received = true ;
1274+ tr_debug (" _oob_send_fail_received called" );
1275+ _send_fail_received = true ;
12261276}
12271277
12281278int8_t ESP8266::default_wifi_mode ()
0 commit comments