Not getting response from Particle.function and Particle.variable

Hi everyone,

I’m doing some cloud testing and so far everything is working fine on the Boron->Cloud direction, status are been transmitted and Particle.publishs are flowing!

Unfortunately on the Cloud->Boron direction, I’m only able to Ping and Signal from the Particle Console. I have a simple Function and Variable available but every time I try to use it I get an error (Timed out).

Are you guys able to point me in the direction to solve this issue?

Without seeing how you’ve registered them and how the functions are implemented it’s hard to tell.

Fair enough!

So I have this as my Particle.Function callback:

// Cloud functions must return int and take one String
int funcName(String extra) {
  Serial.println("Data!!!");
  return 0;
}

I’m registering the function like this inside the setup() function

    success = Particle.function("funcKey", funcName);
    Particle.variable("Counter", counter);

TL;DR I’m using the example from the doc.

I also have this “counter” that is a global variable.

On the “uplink” side I have this inside my loop()

Particle.publish("FSM_TIMER", "RODOU", PRIVATE, NO_ACK);

The publish is working fine, but I get no response from the Particle.variable or Particle.function, although both show up in the Console.

Is your loop() free running or are you using longish delays?
For maximum responsiveness you should not use delay() or any blocking code.

Well, I actually have SYSTEM_THREAD(ENABLE) as I want to have some control over the time for my application thread, in fact I have FSM that run by events or a given tick provided by a Timer.

I though that since the application thread was running on this own thread the system functions like Paricle.function would still work and able to post a event to my FSM via the callback.

I have commented out my loop() here and both function and variable are working now.

Considering SYSTEM_THREAD(ENABLE) is possible to have a blocking loop without and function Particle.function and Particle.variable? I’m curious on why it would not work like this right way.

#include "Particle.h"

// This turns off optimization for this file which makes it easier to debug.
// Otherwise you can't break on some lines, and some local variables won't
// be available.
//#pragma GCC optimize ("O0")

#include "board_init.h"
#include "gpio_expander.h"
#include "output_ports.h"
#include "ext_rtc.h"
#include "ccu_messages.h"
#include "ccu_app.h"
#include "ccu_main.h"
#include <list>

SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(AUTOMATIC);

int counter{0};
os_queue_t main_queue;

void FSM_TICK(void)
{
    MainMessage *ptr = new MainMessage();
    ptr->type = MSG_TYPE::FSM_TIMER;
    ptr->data = nullptr;
    os_queue_put(main_queue, &ptr, 0, nullptr);
}

void TEST_CMD(void)
{
    MainMessage *ptr = new MainMessage();
    ptr->type = MSG_TYPE::SENSOR_CMD_MSG;
    SensorCmd *cmd{new SensorCmd()};
    cmd->sensor_id = 0;
    cmd->channel = 0;
    cmd->cmd = SENSOR_CMD::PUB_DATA;

    ptr->data = reinterpret_cast<uint8_t*>(cmd);


    os_queue_put(main_queue, &ptr, 0, nullptr);
}

int TEST_CMD_CLOUD(String extra)
{
    Serial.println("Cloud Command");
    TEST_CMD();
    return 0;
}

void setup()
{
    board_init();

    Serial.begin(115200);
    Serial.print("Main Task!!!!\r\n");

    //Init main queue
    if(0 != os_queue_create(&main_queue, sizeof(MainMessage*), 10, nullptr))
    {
        Serial.print("Main Task queue error!\r\n");
    }
    else
    {
        //Do nothing
    }

    // Add Cloud cmd
    bool success = Particle.function("RUN_RTC_CMD", TEST_CMD_CLOUD);
    Particle.variable("Counter", counter);
}

void loop()
{

    MainMessage *current_msg = nullptr;
    std::map<uint8_t, CCUSensor*> active_sensors;
    std::map<CCU_APP_ID, CCUApp*> active_apps;
    CCUConfig config;

    config.LoadConfigFromFlash();

    //Add RTC Sensor - TEST
    config.AddSensor(SENSOR_TYPE::RTC_SENSOR, 0, 0);

    LoadSensors(active_sensors, config.GetSensorList());
    LoadApps(active_apps, active_sensors, config.GetAppList());

    //Start FSM TICK
    Timer *fsm_tick = new Timer(1500, FSM_TICK);
    fsm_tick->start();

    while(true)
    {
        //Wait for next msg/event
        os_queue_take(main_queue, &current_msg, CONCURRENT_WAIT_FOREVER, nullptr);

        switch(current_msg->type)
        {
            case(MSG_TYPE::FSM_TIMER):
            {
                //Every single tick, we read data from sensors
                ReadAllSensors(active_sensors);
                //Next we run all apps using the sensor data and place commands in "command_queue"
                RunAllApps(active_apps, main_queue);
                Particle.publish("FSM_TIMER", "RODOU", PRIVATE, NO_ACK);
                counter++;
                break;
            }
            case(MSG_TYPE::SENSOR_CMD_MSG):
            {
                SensorCmd *cmd;
                cmd = reinterpret_cast<SensorCmd*>(current_msg->data);
                ExecuteSensorCmd(active_sensors, cmd, main_queue);
                //Free the command message
                delete cmd;
                break;
            }
            case(MSG_TYPE::ALARMS):
            {
                break;
            }
            default:
            {
                Serial.printf("Type: %d. Pointer: %p\r\n", current_msg->type, current_msg);
                break;
            }
        }

        delete current_msg;
    }
}

EDIT: I added some of the code so you can get an idea of what’s going on

Your use FreeRTOS semaphores might be interfering with the normal behaviour of SYSTEM_THREAD(ENABLED).

But for that I’d rather defer to @rickkas7 or @peekay123 :blush:

Yeah… You might be right, I’ll take a look on that and hopefully @rickkas7 or @peekay123 might have insight.

You should restructure your code to not have a while within loop, and use a non-blocking os_queue_take.

The reason is that functions and variables are dispatched between calls to loop() even if SYSTEM_THREAD(ENABLED). So you should try to return from loop as often as possible, even if threading is enabled.

1 Like

That means that some of the system operations are still handle by the application thread?

My take away from what I saw in the code was that a new FreeRTOS task was lunched for the loop with SYSTEM_THREAD(ENABLE) but what you said suggests that there’s some background been handling in the application thread. Is there a way to decouple this without launching another thread?

Functions and variables are always dispatched from the application thread, in between calls to loop(). The reason is that before threading existed, that’s the way it worked, and even with threading, it’s not clear that calling functions from the system thread would make sense. It would lead to concurrency issues and potentially stack size issues. Also it could cause the function to block the system thread, which would defeat the purpose of the system thread.

So, yes, if you want to block on the dequeueing, you should run that from a separate worker thread, not from the application thread, because you should always return from loop as often as possible.

2 Likes

Yeah… I can see having this user made call running from the system thread quickly becoming a issue.

Thanks for the help @rickkas7!