3 months, 2 weeks ago.

mbed-os-tcp-server-example with Nucleo-F429ZI broken

Hi,

I am trying out the Ethernet functionality of my Nucleo-F429ZI board.

I used the example program:

Original example code

#if !FEATURE_LWIP
    #error [NOT_SUPPORTED] LWIP not supported for this target
#endif

#include "mbed.h"
#include "EthernetInterface.h"
#include "TCPServer.h"
#include "TCPSocket.h"

#define HTTP_STATUS_LINE "HTTP/1.0 200 OK"
#define HTTP_HEADER_FIELDS "Content-Type: text/html; charset=utf-8"
#define HTTP_MESSAGE_BODY ""                                     \
"<html>" "\r\n"                                                  \
"  <body style=\"display:flex;text-align:center\">" "\r\n"       \
"    <div style=\"margin:auto\">" "\r\n"                         \
"      <h1>Hello World</h1>" "\r\n"                              \
"      <p>It works !</p>" "\r\n"                                 \
"    </div>" "\r\n"                                              \
"  </body>" "\r\n"                                               \
"</html>"

#define HTTP_RESPONSE HTTP_STATUS_LINE "\r\n"   \
                      HTTP_HEADER_FIELDS "\r\n" \
                      "\r\n"                    \
                      HTTP_MESSAGE_BODY "\r\n"

int main()
{
    printf("Basic HTTP server example\n");
    
    EthernetInterface eth;
    eth.connect();
    
    printf("The target IP address is '%s'\n", eth.get_ip_address());
    
    TCPServer srv;
    TCPSocket clt_sock;
    SocketAddress clt_addr;
    
    /* Open the server on ethernet stack */
    srv.open(&eth);
    
    /* Bind the HTTP port (TCP 80) to the server */
    srv.bind(eth.get_ip_address(), 80);
    
    /* Can handle 5 simultaneous connections */
    srv.listen(5);
    
    while (true) {
        srv.accept(&clt_sock, &clt_addr);
        printf("accept %s:%d\n", clt_addr.get_ip_address(), clt_addr.get_port());
        clt_sock.send(HTTP_RESPONSE, strlen(HTTP_RESPONSE));
    }
}

When importing the program from:

https://os.mbed.com/teams/ST/code/mbed-os-tcp-server-example/

It does compile and work. But when the mbed-os is updated, the compilation fails with:

[NOT_SUPPORTED] LWIP not supported for this target

I have tried to backtrack it, and the last revision I could find of mbed-os, that works is version: 949cb49ab0, dating back to 10th of September, 2018.

Can I somehow compile this example on the latest mbed-os? Could it really be that LWIP is not supported anymore by this target?

Thank you and Best Regards: Balazs

Comment on this question

2 Answers

3 months, 2 weeks ago.

Hi there,

I tried to do same like you descripted with Nucleo-F767Zi and behavior was same but when I cutted out...

/*#if !FEATURE_LWIP
    #error [NOT_SUPPORTED] LWIP not supported for this target
#endif*/

it normaly works.

Maybe it will help

Best regards J.

Hi Jan,

Thank you for your suggestion! I have tried to do this at the beginning, and indeed it compiled, but with a ton of warnings (some of them really looked concerning, I have pasted only a fraction of them, because of the 3000 character limit):

Warning: 'TCPServer' is deprecated: TCPServer is deprecated, use TCPSocket [since mbed-os-5.10] [-Wdeprecated-declarations] in "main.cpp", Line: 36, Col: 15 Warning: 'accept' is deprecated: TCPServer::accept() is deprecated, use Socket *Socket::accept() instead [since mbed-os-5.10] [-Wdeprecated-declarations] in "main.cpp", Line: 50, Col: 13 Warning: Format specifies type 'long' but the argument has type 'std::int32_t' (aka 'int') [-Wformat] in "extras/mbed-os.lib/features/cellular/framework/AT/ATHandler.cpp", Line: 1182, Col: 52 Warning: 'PSA_SUCCESS' macro redefined [-Wmacro-redefined] in "extras/mbed-os.lib/features/frameworks/TARGET_PSA/pal/pal_client_api_intf.h", Line: 35, Col: 9 Warning: 'psa_its_set' is deprecated: PS specific types should not be used [-Wdeprecated-declarations] in "extras/mbed-os.lib/features/frameworks/TARGET_PSA/pal/pal_internal_trusted_storage_intf.c", Line: 45, Col: 16 Warning: 'psa_its_set' is deprecated: PS specific types should not be used [-Wdeprecated-declarations] in "extras/mbed-os.lib/features/mbedtls/mbed-crypto/platform/TARGET_PSA/COMPONENT_PSA_SRV_IMPL/psa_crypto_storage.c", Line: 149, Col: 14 Warning: 'psa_its_set' is deprecated: PS specific types should not be used [-Wdeprecated-declarations] in "extras/mbed-os.lib/features/mbedtls/platform/TARGET_PSA/COMPONENT_PSA_SRV_IMPL/src/default_random_seed.cpp", Line: 14, Col: 23 Warning: Null passed to a callee that requires a non-null argument [-Wnonnull] in "extras/mbed-os.lib/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bootstrap.c", Line: 2607, Col: 9 Warning: Equality comparison with extraneous parentheses [-Wparentheses-equality] in "extras/mbed-os.lib/features/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6.c", Line: 211, Col: 31 Warning: Equality comparison with extraneous parentheses [-Wparentheses-equality] in "extras/mbed-os.lib/features/nfc/stack/transceiver/pn512/pn512_rf.c", Line: 110, Col: 26 Warning: Equality comparison with extraneous parentheses [-Wparentheses-equality] in "extras/mbed-os.lib/features/nfc/stack/transceiver/pn512/pn512_poll.c", Line: 540, Col: 61 Warning: Format specifies type 'long' but the argument has type 'int32_t' (aka 'int') [-Wformat] in "extras/mbed-os.lib/platform/mbed_error.c", Line: 307, Col: 105

Warning: Format specifies type 'long' but the argument has type 'uint32_t' (aka 'unsigned int') [-Wformat] in "extras/mbed-os.lib/targets/TARGET_STM/gpio_irq_api.c", Line: 128, Col: 59 Warning: Implicitly declaring library function 'memset' with type 'void *(void *, int, unsigned int)' [-Wimplicit-function-declaration] in "extras/mbed-os.lib/targets/TARGET_STM/i2c_api.c", Line: 266, Col: 5

Thank you and Best Regards: Balazs

posted by Balazs Bornyasz 04 Jul 2019

Ignore the warnings, if it compiles and runs then its working. I have just tried it on a Disco-F746 board and runs fine.

You will find TCPServer is depreciated, however it does currently work, not sure how to resolve this, I can't find any examples.

posted by Paul Staron 04 Jul 2019

Hi,

The TCPSocket was reworked and the methods from TCPServer are in the TCPSocket https://os.mbed.com/docs/mbed-os/v5.13/apis/tcpsocket.html#server-socket

You can rewrite the code. It is not tested because I do not have a board here but can worked I think.

TCPSocket

#include "mbed.h"
#include "EthernetInterface.h"
 
#define HTTP_STATUS_LINE "HTTP/1.0 200 OK"
#define HTTP_HEADER_FIELDS "Content-Type: text/html; charset=utf-8"
#define HTTP_MESSAGE_BODY ""                                     \
"<html>" "\r\n"                                                  \
"  <body style=\"display:flex;text-align:center\">" "\r\n"       \
"    <div style=\"margin:auto\">" "\r\n"                         \
"      <h1>Hello World</h1>" "\r\n"                              \
"      <p>It works !</p>" "\r\n"                                 \
"    </div>" "\r\n"                                              \
"  </body>" "\r\n"                                               \
"</html>"
 
#define HTTP_RESPONSE HTTP_STATUS_LINE "\r\n"   \
                      HTTP_HEADER_FIELDS "\r\n" \
                      "\r\n"                    \
                      HTTP_MESSAGE_BODY "\r\n"
 
int main()
{
    printf("Basic HTTP server example\n");
    
    EthernetInterface eth;
    eth.connect();
    
    printf("The target IP address is '%s'\n", eth.get_ip_address());
    TCPSocket srv;
    TCPSocket *clt_sock;
    SocketAddress clt_addr;
    
    /* Open the server on ethernet stack */
    srv.open(&eth);
    
    /* Bind the HTTP port (TCP 80) to the server */
    srv.bind(eth.get_ip_address(), 80);
    
    /* Can handle 5 simultaneous connections */
    srv.listen(5);
    
    while (true) {
        clt_sock = srv.accept();
        clt_sock->getpeername(&clt_addr); //Edit add this line for correct function of the followed printf
        printf("accept %s:%d\n", clt_addr.get_ip_address(), clt_addr.get_port());
        clt_sock->send(HTTP_RESPONSE, strlen(HTTP_RESPONSE));
        clt_sock->close();  //Edit: add this line to prevent memory leak, that prevent a hard fault after a few connection
    }
}

But how Paul wrote, when the depreciated class and methods work you can use these old.

Best regards J.

posted by Jan Kamidra 04 Jul 2019

Hi Jan,

I have modified the code to try it on my F429ZI. It sure compiled, as you suggested, I have programmed the HW, and let it run. I have used a browser, and the static page opens. I closed this browser tab. I open another one, browse to the address shown in my serial terminal, the static page appears again, shortly followed by a hard fault on the mBed HW. The serial port log is as follows:

Basic HTTP server example
The target IP address is '192.168.88.248'
accept :0
accept :0
accept :0
accept :0

++ MbedOS Fault Handler ++

FaultType: HardFault

Context:
R0   : 20030000
R1   : 0801A88C
R2   : 000000E8
R3   : 080063F3
R4   : 00000000
R5   : 2000542C
R6   : 00000000
R7   : 0801A88C
R8   : 20005444
R9   : 0800F024
R10  : 00000000
R11  : 00000000
R12  : 0801437B
SP   : 20005420
LR   : 080025D5
PC   : 0800EFDE
xPSR : 01000000
PSP  : 200053B8
MSP  : 2002FFC0
CPUID: 410FC241
HFSR : 40000000
MMFSR: 00000000
BFSR : 00000082
UFSR : 00000000
DFSR : 00000008
AFSR : 00000000
BFAR : 20030010
Mode : Thread
Priv : Privileged
Stack: PSP

-- MbedOS Fault Handler --



++ MbedOS Error Info ++
Error Status: 0x80FF013D Code: 317 Module: 255
Error Message: Fault exception
Location: 0x800F3D9
Error Value: 0x800EFDE
Current Thread: main  Id: 0x20007FA0 Entry: 0x800F6F1 StackSize: 0x1000 StackMem: 0x20004570 SP: 0x2002FF18 
For more info, visit: https://mbed.com/s/error?error=0x80FF013D&tgt=NUCLEO_F429ZI
-- MbedOS Error Info --

= System will be rebooted due to a fatal error =
= Reboot count(=2) reached maximum, system will halt after rebooting

I am not sure what happened here, but the effect is reproducible. I have used the latest mbed-os release.

Thank you and Best Regards: Balazs

posted by Balazs Bornyasz 04 Jul 2019

Hello Balazs,

The documentation says that "Accepting a new connection returns a pointer to a new Socket object that you can use to communicate with the connected peer. Afterward, call this socket's close() function to shut down the connection and clean up the reserved resources." Otherwise the program will keep reserving more and more resources for each new connection and finally run out of memory.

#include "mbed.h"
#include "EthernetInterface.h"
 
#define HTTP_STATUS_LINE "HTTP/1.0 200 OK"
#define HTTP_HEADER_FIELDS "Content-Type: text/html; charset=utf-8"
#define HTTP_MESSAGE_BODY ""                                     \
"<html>" "\r\n"                                                  \
"  <body style=\"display:flex;text-align:center\">" "\r\n"       \
"    <div style=\"margin:auto\">" "\r\n"                         \
"      <h1>Hello World</h1>" "\r\n"                              \
"      <p>It works !</p>" "\r\n"                                 \
"    </div>" "\r\n"                                              \
"  </body>" "\r\n"                                               \
"</html>"
 
#define HTTP_RESPONSE HTTP_STATUS_LINE "\r\n"   \
                      HTTP_HEADER_FIELDS "\r\n" \
                      "\r\n"                    \
                      HTTP_MESSAGE_BODY "\r\n"
 
int main()

{
    printf("Basic HTTP server example\n");
    
    EthernetInterface eth;
    eth.connect();
    
    printf("The target IP address is '%s'\n", eth.get_ip_address());
    TCPSocket srv;
    TCPSocket *clt_sock;
    SocketAddress clt_addr;
    
    /* Open the server on ethernet stack */
    srv.open(&eth);
    
    /* Bind the HTTP port (TCP 80) to the server */
    srv.bind(eth.get_ip_address(), 80);
    
    /* Can handle 5 simultaneous connections */
    srv.listen(5);
    
    while (true) {
        clt_sock = srv.accept();
        printf("accept %s:%d\n", clt_addr.get_ip_address(), clt_addr.get_port());
        clt_sock->send(HTTP_RESPONSE, strlen(HTTP_RESPONSE));
        clt_sock->close();
    }
}
posted by Zoltan Hudak 04 Jul 2019

Zoltan is right of course.

However, for correct function of line 45 must be call method getpeername before line 45.

getpeername

//rest of code
     while (true) {
        clt_sock = srv.accept();
        clt_sock->getpeername(&clt_addr);
        printf("accept %s:%d\n", clt_addr.get_ip_address(), clt_addr.get_port());
        clt_sock->send(HTTP_RESPONSE, strlen(HTTP_RESPONSE));
        clt_sock->close();
    }
//rest of code
posted by Jan Kamidra 04 Jul 2019

Thank you Zoltan, Thank you Jan for your explanation.

I understand what you say, but I have the feeling that (maybe the original example is way too simplified) a hard fault is not the correct way of "handling" or "let these events happen". Should there not be a function to prevent this from happening? Or is it only the responsibility of the user of the library to prevent this?

Thank you all for your time and contribution!

Best Regards: Balazs

posted by Balazs Bornyasz 05 Jul 2019
3 months, 2 weeks ago.

Balazs, try putting this in the mbed_app.json file (nothing else) and see if it works.

{
    "target_overrides": {
        "*": {
            "target.features": ["LWIP"],
            "target.release_versions": ["2", "5"],
            "platform.stdio-baud-rate": 921600  // include and set this for a faster serial printf terminal if 9600 default is too slow 
        }
    }
}

Hi Paul,

Thank you for the hint. Just to clarify, what I did exactly: 1.) I have created the file mbed_app.json (the project didn't have this file before) 2.) I have filled it with the content you've suggested 3.) I switched back to the latest available mbed-os release 4.) try to compile it.

The compilation failed with the following error message:

Error: Could not parse mbed app configuration from /tmp/chroots/ch-0fd5abf2-fc9a-4c9f-8a9b-195aceba8e2b/src/mbed_app.json

I have put nothing else into the json file, only the suggested lines.

Do you have any idea, why it was unable to parse this file?

Thank you and Best Regards: Balazs

posted by Balazs Bornyasz 04 Jul 2019