Wiznet W5500 library - No indication is given on transmit timeout with callback configured

After establishing a Modbus TCP connection between the Wiznet, acting as client and a peer acting as a server, if during a transmit from the client to server the connection is broken, i.e by removing the ethernet cable at the server end, no indication is given. Using Wireshark, we can see that the Wiznet attempts to re-transmit the packets and gives up after the configurable time period. Adding debug shows that the detected timeout is never propagated up to the caller who initiated the transmit.

With further debugging we noticed that the transmit callback handler is deleted immediately when the Sn_IR (Socket n Interrupt Register) [SEND_OK] bit is set. When the timeout later occurs, although the TIMEOUT bit in the Sn_IR register is set, it then attempts to call the callback handler but it has already been deleted by the SEND_OK case.

The following code shows a workaround for the above issue. The _transmitCallback has been moved from the SEND_COMPLETE to DATA_RECEIVED case and the callback is successfully called indicating timeout.

// ***************************************************************************
// _handleSocketInt, handles/clears the specified socket interrupt
// Returns: null
// Parameters: socket the interrupt occurred on
// **************************************************************************
function handleInterrupt(skip_timer = false) {

if (status.SEND_COMPLETE) {

    // server.log("Send complete on socket " + _socket);
    _driver.clearSocketInterrupt(_socket, W5500_SEND_COMPLETE_INT_TYPE);
    skip_timer = true;
}

if (status.DATA_RECEIVED) {

    // server.log("Data received on socket " + _socket);
    _driver.clearSocketInterrupt(_socket, W5500_DATA_RECEIVED_INT_TYPE);

    // At this point we know we have successfully transmited last message so we can
    // now safely remove the calling transmit callback handler
    local _transmitCallback = _getHandler("transmit");
    if (_transmitCallback) {
        _handlers["transmit"] <- null;

        imp.wakeup(0, function() {
            _transmitCallback(null);
        }.bindenv(this))
    }
    receive(); // process incoming data
}
...

}

@onio thank you for the catch! We’ll take care of it.