FreeRTOS+TCP logs: crc swap: 0000

yanvasilij wrote on Friday, January 27, 2017:


I use FreeRTOS+TCP on my STM32F429. I created project with modbus TCP slave and start to poll data from my PC. Sometimes I get modbus errors (time out). I turned on FreeRTOS+TCP logs and found there the follows:

usGenerateProtocolChecksum[TCP]: crc swap: 0000

What does mean this logs?


rtel wrote on Friday, January 27, 2017:

I think that is telling you a TCP checksum was correct (worked out to be
0). Not sure that is an error.

heinbali01 wrote on Saturday, January 28, 2017:

Do you think that the modbus errors occur at the moment that the TCP checksum equals to zero?

Beside logging, the code says:

	if( usChecksum == 0u )
		usChecksum = ipCORRECT_CRC; /* which is equal to 0xffff. */
		usChecksum = FreeRTOS_htons( usChecksum );

heinbali01 wrote on Sunday, January 29, 2017:

The reason that 0x0 was transmitted as 0xffff is because of the UDP rule, see rfc768 :

If the computed checksum is zero, it is transmitted as all ones (the
equivalent in one’s complement arithmetic). An all zero transmitted
checksum value means that the transmitter generated no checksum
(for debugging or for higher level protocols that don’t care)

But if I’m not mistaken, for other protocols this should not apply and thus:

    if( ( usChecksum == 0u ) && ( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP ) )
        #if( ipconfigHAS_DEBUG_PRINTF != 0 )
            if( xOutgoingPacket != pdFALSE )
                FreeRTOS_debug_printf( ( "usGenerateProtocolChecksum[%s]: crc swap: %04X\n", pcType, usChecksum ) );
        #endif    /* ipconfigHAS_DEBUG_PRINTF != 0 */
		/* In case of UDP, a calculated checksum of 0x0000 is transmitted
        as 0xffff. A value of zero would mean that the checksum is not used. */
        usChecksum = ( uint16_t )0xffffu;
        usChecksum = FreeRTOS_htons( usChecksum );

Does that stop the modbus errors?

heinbali01 wrote on Monday, January 30, 2017:

I did test the above change but I forgot that my board is calculating all checksums in hardware :frowning:

The change to usGenerateProtocolChecksum() is a bit more complex than in the sketch here above. The translation from 0x0 to 0xffff should take place in two cases:

● When checking a CRC on an incoming packet.
● When the CRC of an UDP packet turns out to be zero

Please find attached ‘protocol_checksum.c’ which contains the entire function usGenerateProtocolChecksum().


heinbali01 wrote on Wednesday, February 01, 2017:

Hi Vasilij,

I just tried out the original CRC method for TCP-packets which have a CRC of zero and trigger this message:

    usGenerateProtocolChecksum[TCP]: crc swap: 0000

so the CRC’s are sent as 0xFFFF.

It was not a fatal error, but it did trigger a warning in Wireshark: “TCP CHECKSUM 0xFFFF”.
I sent the TCP packets to both my Linux machine and a Windows-10 laptop. The packet were accepted by both OS’s.

Do you have any news? If you still get stuck, if you want, send me your current NetworkInterface.c for STM32F429.

yanvasilij wrote on Wednesday, February 01, 2017:

Hello Hein Tibosch,

I still have a problem. I figured out the follows: sometimes (about once in 2-4 minutes) tcp-response for request comes with big delay (it can be 100 ms, once a had delya 1500 ms!). Because of that reason ModbusPoll gets timeout error occurs, but tcp response comes. I turned off all task except freertos+tcp and network driver. Here my NetworkInterface.c.

heinbali01 wrote on Wednesday, February 01, 2017:

Hi Vasilij,
Would it also be possible that you send a PCAP of the communication?
If the data is not to be made publicly, you may also send a PCAP to my email asdress (h point tibosch at freertos point org).
I would like to see the packets from the beginning of a connection (SYN), if possible.

yanvasilij wrote on Wednesday, February 01, 2017:

Here it is:

heinbali01 wrote on Wednesday, February 01, 2017:

Hi Vasilij,

When I download your PCAP, it stops after 5,678,937 bytes. Is that the actual size? I wouldn’t mind if you compress it next time :slight_smile:

Within this PCAP, I don’t see any delays yet?

Within a TCP/Modbus connection, is it really necessary to poll so often? Why doesn’t the client report when it has some news? Or at least report zero’s after a longer period of time?

yanvasilij wrote on Friday, February 03, 2017:

Hello Hein Tibosch,

Sorry for big pcap - my fault. I promise to compress next time )).

There is difficult to see time-outs in pcap because there is too much request. There is about one 100 ms time-out in about 100k-200k requests/response pairs. So I wrote simple python script that sends modbus request to my modbus slave and measures delay between request and response. If delay is bigger than 50 ms it write delay value to text file (delay value in seconds). So the log in attachments.

Within a TCP/Modbus connection, is it really necessary to poll so often?

Yes it is. There is nothing I can do with it.

By the way. Here code with socket processing. May something wrong there:

static void createSockets (void * eMBRegInputCB, void * eMBRegHoldingCB, 
		void * eMBRegCoilsCB, void * eMBRegDiscreteCB)
	mbPollActivate = xSemaphoreCreateBinary();
	/* task for all sockets are created and never deleted. 
	 * They just blocks when sokets are closed */
	for (u32 i = 0; i < NUM_OF_SOCKETS; i++)
		socketTaskParams[i].queue = xQueueCreate (1, sizeof(Socket_t));
		modbusTcp[i].eMBRegInputCB = (RegInputCBType)eMBRegInputCB;
		modbusTcp[i].eMBRegHoldingCB = (RegHoldingCBType)eMBRegHoldingCB;
		modbusTcp[i].eMBRegCoilsCB = (RegCoilsCBType)eMBRegCoilsCB;
		modbusTcp[i].eMBRegDiscreteCB = (RegDiscreteCBType)eMBRegDiscreteCB;
		socketTaskParams[i].modbusTcp = &modbusTcp[i];
		socketTaskParams[i].modbusTcp->port.buf = socketTaskParams[i].buf;
		socketTaskParams[i].isOppened = 0;
		socketTaskParams[i].socketNum = i;
		DEBUG_LOG(("creating socket task %d\r\n", socketTaskParams[i].socketNum ));
		xTaskCreate( socketTask, "socketTask",
				configMINIMAL_STACK_SIZE*10, &socketTaskParams[i], 2, &socketTaskHandle[i]);

/* sockets processing task */
static void socketTask (void *p)
	static const TickType_t xReceiveTimeOut = pdMS_TO_TICKS( 5000 );
	static const TickType_t xSendTimeOut = pdMS_TO_TICKS( 5000 );
	int32_t inlen;
	Socket_t socket;
	SocketTaskParams * params;
	params = (SocketTaskParams*)p;
	u8 connectionIsOppened = 0;
	DEBUG_LOG(("socket %d task stated\r\n", params->socketNum));
		xQueueReceive(params->queue, &socket, portMAX_DELAY);
		FreeRTOS_setsockopt( socket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut,
			   	sizeof( xReceiveTimeOut ) );
		FreeRTOS_setsockopt( socket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut,
			   	sizeof( xReceiveTimeOut ) );
		DEBUG_LOG(("Socket %d oppened!\r\n", params->socketNum));
		connectionIsOppened = 1;
		while (connectionIsOppened)
			inlen = FreeRTOS_recv(socket, params->modbusTcp->port.buf, MAX_MODBUS_TCP_FRAME_LEN, 0);
			if (inlen)
				params->modbusTcp->port.bufLen = inlen;
				params->modbusTcp-> EV_FRAME_RECEIVED );
				u8 tmp[50];
				memset(tmp, 0, 50);
				// I just emulate response for 20 holding register request (so here no modbus stack processing at all)
				tmp[0] = params->modbusTcp->port.buf[0];
				tmp[1] = params->modbusTcp->port.buf[1];
				tmp[2] = 0x00;
				tmp[3] = 0x00;
				tmp[4] = 0x00;
				tmp[5] = 0x2B;
				tmp[6] = 0x01;
				tmp[7] = 0x03;
				tmp[8] = 0x28;
				FreeRTOS_send( socket, tmp, 49, 0);
			if (inlen < 0)
				connectionIsOppened = 0;
		FreeRTOS_shutdown( socket, FREERTOS_SHUT_RDWR );
			if(FreeRTOS_recv(socket, params->modbusTcp->port.buf, MAX_MODBUS_TCP_FRAME_LEN, 0)<0)
		} while( 1 );
		FreeRTOS_closesocket( socket );
		params->isOppened = 0;
		DEBUG_LOG(("Socket %d closed!\r\n", params->socketNum));

/* listenning task */
static void listeningTask (void *p)
	static const TickType_t timeOut = portMAX_DELAY;
	struct freertos_sockaddr bindAddress, clientParams;
	Socket_t listenSocket, connectedSocket;
	socklen_t clientParamsSize = sizeof( clientParams );

	WinProperties_t xWinProps;
	/* Fill in the buffer and window sizes that will be used by the socket. */
	xWinProps.lTxBufSize = 300;
	xWinProps.lTxWinSize = 2;
	xWinProps.lRxBufSize = 300;
	xWinProps.lRxWinSize = 2;


	FreeRTOS_setsockopt( listenSocket, 0,
		   	FREERTOS_SO_RCVTIMEO, &timeOut, sizeof(timeOut) );

	FreeRTOS_setsockopt( listenSocket, 0, FREERTOS_SO_WIN_PROPERTIES,
		   	( void * ) &xWinProps, sizeof( xWinProps ) );

	bindAddress.sin_port = MB_TCP_PORT;
	bindAddress.sin_port = FreeRTOS_htons( bindAddress.sin_port );
	FreeRTOS_bind( listenSocket, &bindAddress, sizeof( bindAddress ) );
	/* When connection established corresponding task is unblocked */
	FreeRTOS_listen( listenSocket, NUM_OF_SOCKETS );

	for (;;)
		connectedSocket = FreeRTOS_accept (listenSocket, &clientParams,
		runSocketTask (connectedSocket);

void initModbusTcpTask (void * eMBRegInputCB, void * eMBRegHoldingCB, 
		void * eMBRegCoilsCB, void * eMBRegDiscreteCB)
	createSockets (eMBRegInputCB, eMBRegHoldingCB, eMBRegCoilsCB, eMBRegDiscreteCB);
	xTaskCreate( listeningTask, "listeningTask", configMINIMAL_STACK_SIZE*10, NULL, 1, NULL);

heinbali01 wrote on Sunday, February 05, 2017:

Hi Vasilij,

Your code looks OK now.

Only two thing:

  • When an API returns negative, you can look-up this value in errno.h. A return value of -pdFREERTOS_ERRNO_EAGAIN is not fatail.
  • You write the TCP server and you will never actively close a connection. Therefore you never have to call shutdown().
-           if (inlen < 0)
+           if ((inlen < 0) && (inlen != pdFREERTOS_ERRNO_EAGAIN))
                connectionIsOppened = 0;
-       FreeRTOS_shutdown( socket, FREERTOS_SHUT_RDWR );
-       do
-       {
-           if(FreeRTOS_recv(socket, params->modbusTcp->port.buf, MAX_MODBUS_TCP_FRAME_LEN, 0)<0)
-               break;
-       } while( 1 );

Now about the time-outs:

I would think of missing or dropped packets. Please keep on checking uxGetMinimumFreeNetworkBuffers() : it should not drop below e.g. 3. It can be useful to study the time-outs: see if there were many other messages. See if those messages were broadcasts. Did the EMAC complain about overflows? Was there a temporary shortage of DMA descriptors?

The speed of polling can not be the problem: every 15 ms should be easy. Even if you have several simultaneous connections like this.