Printf("%lxip") in FreeRTOS+TCP

thomask wrote on Monday, August 06, 2018:

Hi!

I just saw that FreeRTOS+TCP uses a custom “%lxip” format specifier to print IP adresses.

This format is not supported by newlib, and I can’t use the recommended printf-stdarg.c from the FreeRTOS demos either (LGPL license :confused: ).

So I would like to change that to a more portable “%d.%d.%d.%d”.

Has anyone done this already?

Would you accept a patch?

best regards,
Thomas

heinbali01 wrote on Monday, August 06, 2018:

Hi Thomas,
The format “%lxip” is supported by the module “printf-stdarg.c”, which was included in the original FreeRTOS+TCP distribution on FreeRTOS Plus TCP - A free thread aware TCP/IP stack for FreeRTOS
If that module is not included, the statement will print as e.g. “C0A80101ip”, instead of “192.168.1.1”.

This format is not supported by newlib, and I can’t use the recommended
printf-stdarg.c from the FreeRTOS demos either (LGPL license :confused: ).

I am not an expert on licensing, but I think that “printf-stdarg.c” has the same MIT-type licence as the FreeRTOS+TCP library.

thomask wrote on Monday, August 06, 2018:

The idea is to use a macro like this:

#define FreeRTOS_ntohl_ip_to_printf_args(IP) \
    (int)(FreeRTOS_ntohl(IP) >> 24) & 255,      \
    (int)(FreeRTOS_ntohl(IP) >> 16) & 255,      \
    (int)(FreeRTOS_ntohl(IP) >>  8) & 255,      \
    (int)(FreeRTOS_ntohl(IP) >>  0) & 255

and substitute:

FreeRTOS_debug_printf( ( "vDHCPProcess: acked %lxip\n", FreeRTOS_ntohl( xDHCPData.ulOfferedIPAddress ) ) );

with:

FreeRTOS_printf( ( "vDHCPProcess: acked %d.%d.%d.%d\n", FreeRTOS_ntohl_ip_to_printf_args( xDHCPData.ulOfferedIPAddress ) ) );

I noticed that there are a lot of places, where ntohl() is missing, and sometimes it’s even mixed in the same printf() (see FreeRTOS_TCP_IP.c, line 1028):

			FreeRTOS_debug_printf( ( "ARP for %lxip (using %lxip): rc=%d %02X:%02X:%02X %02X:%02X:%02X\n",
				pxSocket->u.xTCP.ulRemoteIP,
				FreeRTOS_ntohl( ulRemoteIP ),

Is this by purpose? I would have expected that +TCP uses a consistent format internally, or at least uses different variable names to identify host and network order.

I think I will use two different macros then. I’m also not so clear what names to use.

Perhaps
FreeRTOS_net_ip_to_printf_args () for network order and a plain
FreeRTOS_ip_to_printf_args () for native order IPs?

thomask wrote on Monday, August 06, 2018:

Unfortunately, it’s LGPL:

https://sourceforge.net/p/freertos/code/HEAD/tree/trunk/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/printf-stdarg.c

I think the %lxip debug specifier needs removing as it is not portable. I have also noticed many other printf format specifiers are incorrect (such as %lu for a uint32_t).

The Tasking Tricore compiler throws up about 150 printf warnings.

Hi Thomas, when I work on FreeRTOS+TCP, I often wanted to print IP-addresses for logging. Using the above expression with all shifts and AND’s would be cumbersome, a lot of typing. That is why I invented the ‘%xip’ syntax.

There is also a function ntoa(), but that is still not as easy to use as the ‘%xip’ format.

I have also noticed many other printf format specifiers are incorrect (such as %lu for a uint32_t)

Not really, they were incorrect for your compiler, but other compilers liked it this way. Some compilers will print a uint32_t with ‘%x’, others want to see the long flag as in ‘%lx’.

MISRA doesn’t like the use of int, long, unsigned, because those types do not specify the actual width. But using a cast to those those standard types would avoid the printf() format warnings:

    /* This will not cause a warning by the compiler,
     * but MISRA doesn't like it. */
    printf( "IP = %xip\n", ( unsigned ) ulIPAddress );

Earlier you wrote:

I noticed that there are a lot of places, where ntohl() is missing, and sometimes it’s even mixed in the same printf()

The reason is that some IP-addresses in the library are stored in native endian, others in network-endian. And if not, I must have been mistaken, as I used to work mostly on a big-endian platform.

Once your application is ready for production, you may as well undefine FreeRTOS_printf() and FreeRTOS_debug_printf(). That will also stop the compiler warnings.