WIZnet Developer Forum

How to detect receive of ACK packet?

Is any way to detect moment when W5500 got acknowledge (ACK) after sent data?
Because Sn_IR_SENDOK only mean - data is gone, but not show about data is received by second side. Watch to absent Sn_IR_TIMEOUT during RCR&RTC timeout it’s ugly and slow method. How to be sure about that the data is delivered fully?

Are you talking about a TCP packet? The fact that a TCP packet can be successfully sent means the packet has been successfully delivered.

I am using Wiznet’s ioLibrary, the TCP send() API says:

/**
 * @ingroup WIZnet_socket_APIs
 * @brief	Send data to the connected peer in TCP socket.
 * @details It is used to send outgoing data to the connected socket.
 * @note    It is valid only in TCP server or client mode. It can't send data greater than socket buffer size. \n
 *          In block io mode, It doesn't return until data send is completed - socket buffer size is greater than data. \n
 *          In non-block io mode, It return @ref SOCK_BUSY immediately when socket buffer is not enough. \n
 * @param sn Socket number. It should be <b>0 ~ @ref \_WIZCHIP_SOCK_NUM_</b>.
 * @param buf Pointer buffer containing data to be sent.
 * @param len The byte length of data in buf.
 * @return	@b Success : The sent data size \n
 *          @b Fail    : \n @ref SOCKERR_SOCKSTATUS - Invalid socket status for socket operation \n
 *                          @ref SOCKERR_TIMEOUT    - Timeout occurred \n
 *                          @ref SOCKERR_SOCKMODE 	- Invalid operation in the socket \n
 *                          @ref SOCKERR_SOCKNUM    - Invalid socket number \n
 *                          @ref SOCKERR_DATALEN    - zero data length \n
 *                          @ref SOCK_BUSY          - Socket is busy.
 */
int32_t send(uint8_t sn, uint8_t * buf, uint16_t len);

actually, no. send() results show only - your data pushed to TX buffers memory.
just make test. connect your module according picture below
w5500-test_schema
pseudo-code for w5500:

//setup module IP and connect to your PC address and port 1234

//
uint8_t outbuf[100];
uint32_t pktcount = 0;
while (1) {
uint8_t socket_state = getSn_SR(socket_idx);
if (socket_state == SOCK_ESTABLISHED) {
printf(“sending pkt #%lu\r\n”, pktcount); //debug log w5500
uint16_t len = sprintf((char *) outbuf, “pkt #%lu\r\n”, pktcount);
if (len != send(socket_idx, outbuf, len)) {
printf(“error sending!!!\r\n”);
}
pktcount++;
} else {
break;
}
delay_ms(1000);
}

and exec on PC (ubuntu example):

nc -lkv 1234

and see what happends when you unplug wire B. Function send result still equal sending data lenght. And this be till timeout time, setted by regs RCR RTR. So, send() result is not show - “other side got your data”. Only ACK package means - “other side received your data”. And how to catch moment when module received this package - that is the my question.

You are correct - The immediate return from send() does not indicate the SEND command is completed. However, the subsequent send() will. This is because the real SEND status is checked at the beginning of the send() function.

int32_t send(uint8_t sn, uint8_t * buf, uint16_t len)

{
uint8_t tmp = 0;
uint16_t freesize = 0;

CHECK_SOCKNUM();
CHECK_SOCKMODE(Sn_MR_TCP);
CHECK_SOCKDATA();

tmp = getSn_SR(sn);
if (tmp != SOCK_ESTABLISHED && tmp != SOCK_CLOSE_WAIT) 
	return SOCKERR_SOCKSTATUS;
	
if (sock_is_sending & (1 << sn))
{
    tmp = getSn_IR(sn);
    if (tmp & Sn_IR_SENDOK)
    {
        setSn_IR(sn, Sn_IR_SENDOK);
        sock_is_sending &= ~(1 << sn);
    }
    else if (tmp & Sn_IR_TIMEOUT)
    {
        close(sn);
        return SOCKERR_TIMEOUT;
    }
    else 
	{
		return SOCK_BUSY;
	}
}


}

Seems Sn_IR_SENDOK flag sets when data sent, not then ACK packet received. I was make test - when i unplug cable “B” module still keep raising Sn_IR_SENDOK, till socket timeout. Module send test packet every second, socket timeout about 19 seconds (RCR=6, RTR=2000) . After cable unplug, module sends about 14 pakets and raise Sn_IR_SENDOK (was cleared every time by “setSn_IR(idx, Sn_IR_SENDOK);”) after every sending and then will disconnect on timeout. Of course the second side did not get anyone of this 14 packets.
I am saddened. :frowning_face:

You raised very interesting and useful question, and I think the only person able to have definite answer is the developer of the chip.

I guess that Sn_CR is also cleared on this event - when packet is went into the wire. So if packet is lost, like in your case, W5500 will not immediately know if it was not delivered.

This is actually a good thing - meaning that W5500 still monitors the ACK packets; not seeing them coming it assumes that media is broken and raises timeout (and closes the socket).

Another test would be more interesing though: you send a number of packets, and before timeout occurs, restore the connection so that another network device get the rest of the packets. That device, for sure, will stall saying to W5500 that it did not get [revious packets (as TCP keeps track of data/packet sequence). What will happen then? Will W5500 still have missing data to resend?

In my opinion, while SENDOK is being set, W5500 should NOT free data buffer until it gets acknowledge for data received by the remote network node. For example, initially TX has 2048 bytes free, you put 512 bytes in and perform SEND. W5500 says that SENDOK, but TX buffer is having 1536 bytes free until chip gets ACK for the packet send related to this data. But it is my guess how it should be implemented, and I hope it is done so.

But W5500 immediately know if data delivered (he got ACK packet) and i want to know this immediately too. :))
It’s interesting idea about look at TX buffers length changing, thanks

Eugeny, you was right. I was made some tests and had seen - it’s posible to use value of Sn_TX_FSR as indirect ACK-received flag.
This is not ideal solutions (couse no interrupts and you must check this register periodicaly), but is much better than nothing. Many thanks to you again.

1 Like

Copyright © 2017 WIZnet Co., Ltd. All Rights Reserved.