[bug #59049] MQTT in FreeRTOS tasks give error on TCP-write/output

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

[bug #59049] MQTT in FreeRTOS tasks give error on TCP-write/output

yuanjianmin
URL:
  <https://savannah.nongnu.org/bugs/?59049>

                 Summary: MQTT in FreeRTOS tasks give error on
TCP-write/output
                 Project: lwIP - A Lightweight TCP/IP stack
            Submitted by: klaasvortex
            Submitted on: Tue 01 Sep 2020 11:48:49 AM UTC
                Category: Contrib
                Severity: 3 - Normal
              Item Group: Faulty Behaviour
                  Status: None
                 Privacy: Public
             Assigned to: None
             Open/Closed: Open
         Discussion Lock: Any
         Planned Release: None
            lwIP version: 2.1.1

    _______________________________________________________

Details:

When using MQTT to sent data from *seperate* threads (FreeRTOS) I got errors
on LWIP. (and sometimes deadlocks in loops)

==
I am using MQTT to sent logging from multiple tasks to a MQTT server. My own
Logging writing function is protected by mutex and is thread safe.

However the LWIP-thread is NOT the same as my Logging thread. This gives
(occasionly) errors on LWIP-tcp-write and output functions.

Looking into mqtt.c, the public publish sub/un sub function do both call

  *mqtt_output_send(&client->output, client->conn);*

Which use tcp->write/output. This will cause the fault. Since these functions
are not protected (thread safe)and should only be called from the LWIP thread.
(I think)

Remember the publish/sub.unsub functions copy the data into a ringbuffer. Then
the sent function will transmit the ringbuffer data. So we can use this buffer
to do the next thing.

By removing the mqtt_output_send from these 2 public mqtt-functions, the
errors are gone and everything works. Since the tcp->poll function will take
over the transmission and is called from the LWIP-task. The poll function will
transmit any data from the ringbuffer.

But there will be a delay before sending since it is started when the poll
runs and not directly sent after call pusblish.

Subscribtions are no problem since they are called from the LWIP thread.


With this solution I can call mqtt_publish from every task. Which I would like
to do.

But I am not sure if this is the correct way to do so.

Is there a better way to do this ?















    _______________________________________________________

Reply to this item at:

  <https://savannah.nongnu.org/bugs/?59049>

_______________________________________________
  Message sent via Savannah
  https://savannah.nongnu.org/


_______________________________________________
lwip-devel mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/lwip-devel
Reply | Threaded
Open this post in threaded view
|

[bug #59049] MQTT in FreeRTOS tasks give error on TCP-write/output

yuanjianmin
Follow-up Comment #1, bug #59049 (project lwip):

Hi Andre,

You must call mqtt API from the LWIP thread context as it use the raw ALTCP
api.

To do that, you can use the tcpip_callback() or tcpip_callback_wait()
functions for example.

Regards,
David


    _______________________________________________________

Reply to this item at:

  <https://savannah.nongnu.org/bugs/?59049>

_______________________________________________
  Message posté via Savannah
  https://savannah.nongnu.org/


_______________________________________________
lwip-devel mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/lwip-devel
Reply | Threaded
Open this post in threaded view
|

[bug #59049] MQTT in FreeRTOS tasks give error on TCP-write/output

yuanjianmin
Follow-up Comment #2, bug #59049 (project lwip):

Hi David,

Ok, thank you very much. I will reformat the code into doing just that.



    _______________________________________________________

Reply to this item at:

  <https://savannah.nongnu.org/bugs/?59049>

_______________________________________________
  Message sent via Savannah
  https://savannah.nongnu.org/


_______________________________________________
lwip-devel mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/lwip-devel
Reply | Threaded
Open this post in threaded view
|

[bug #59049] MQTT in FreeRTOS tasks give error on TCP-write/output

yuanjianmin
Follow-up Comment #3, bug #59049 (project lwip):

Hi David, Andre,

I am having the same issue here. I am using Lwip + FreeRtos + Mqtt on
STM32F746 MCU. I have noticed strange behavior when packets to be sent by Mqtt
are bigger than one TCP packet (something like > 1450 bytes). Then in
mqtt_output_send() I have altcp_sndbuf(tcpb) returning ZERO. and nothing gets
send, and furthermore, my ringbuf gets filled-up by next consequential atempts
and eventualy I end up  with MEM ERROR (but this is product of the first
corruption of course.

However to make things even worse, this only happens sometimes, and only
happens on public networks. On local network connection (to localhost MQTT
Broker) things work just fine for days and days.

As soon as I connect to public network on a dedicated broker (broker listening
just my device - NOT a PUBLIC BROKER but proprietary located on DigitalOcean
servers) the system works until the first MCU soft reset... when the library
simply would not send packets bigger than 1450 bytes anymore, or in other
words segmenting the big packet paylod to several will not even start cause
mqtt_output_send has issues and I cannot seem to catch what exacly happens,
its hard to debug even why altcp_sndbuf(tcpb) is returning ZERO??...

Obviously it not thread safe to call mqtt functions from third-party thread in
freertos, but I dont know what minimum effort I need to make to restructure
the code ... which thread I need to call my mqtt functions from?

I have this list of threads running in freertos:
IDLE
TCP/IP
DHCP
EthIf
HTTP
myMQTT

The last two are my tasks, and I call mqtt lib functions from myMQTT.
I would happily restructure it and place it to any other thread but I would
appreciete any help on this on the minimal approach.

I am not at all an expert in lwip, so its even harder to trace things around
for me.

Please help


    _______________________________________________________

Reply to this item at:

  <https://savannah.nongnu.org/bugs/?59049>

_______________________________________________
  Message sent via Savannah
  https://savannah.nongnu.org/


_______________________________________________
lwip-devel mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/lwip-devel
Reply | Threaded
Open this post in threaded view
|

[bug #59049] MQTT in FreeRTOS tasks give error on TCP-write/output

yuanjianmin
Follow-up Comment #4, bug #59049 (project lwip):

Hi Dejan,

First I am not an expert, so keep that in mind.

I think the problem can be simular to mine, since crossing thread on LWIP
can/will mangle up the tcp/ip stack. It can take a while but it will.

First the TCP/IP is a REAL Freertos thread, lets call this task0, but DHCP is
running on the LWIP timers (which run in task0). This is also true for HTTPD.
So what I did is running the MQTT thread in a lwip timer, so MQTT runs from
task0. This solved my troubles.

There are CYCLIC timers in LWIP, but they are not accesibly to 'user-program'.
But you can add them into the source code.
I do prefer my one-shot timer, since it will not touch the LWIP code.

---------------------------

So for example. Something like this.

main()
{
  // This will start the MQTT System after 15 seconds
 sys_timeout(15000, MQTT_Task, NULL);
}

// So this is the task that does the workload and it will restart every
period
void MQTT_Task(void *arg)
{
    err_t err;
       
    (void) arg;

   // RESTART THE TASK
    tMS reloadTimer = 1000;

    if (dns_gethostbyname( dMQTT_SERVER_NAME, &mqttTask.serverIP,
MQTTServerFound, NULL) == ERR_OK)
    {
        switch (mqttTask.status)
        {
            case eMQTT_INIT:
                mqttTask.counterMS = dMS(0);
                mqtt_disconnect(mqttTask.client);
                err = mqtt_client_connect(mqttTask.client, &mqttTask.serverIP,
dMQTT_PORT, MQTT_ConnectionCB, 0, &ci);
                if(err == ERR_ISCONN)
}



    _______________________________________________________

Reply to this item at:

  <https://savannah.nongnu.org/bugs/?59049>

_______________________________________________
  Message sent via Savannah
  https://savannah.nongnu.org/


_______________________________________________
lwip-devel mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/lwip-devel