Callbacks for Variables

I was looking for a way to have a callback dynamically set a variable only when it’s requested, and I didn’t come across anything, so included below is what I came up with as a test. It creates 3 variables and callbacks and tests overriding and modifying variables when queried from the cloud.

I don’t know how stable of an API this uses, or if there’s timing and/or threading issues, so YMMV. It was only tested on a Xenon.

These callbacks are already used for String, so if you try to create a dynamic one of those the callback has to return a the c_str() version (see https://github.com/particle-iot/device-os/blob/develop/wiring/inc/spark_wiring_cloud.h#L172-L179).

The idea is that you create a spark_variable_t and set it’s update field to a callback function that looks like 'const void* (*)(const char*, Spark_Data_TypeDef, const void*, void*), then create the variable manually with spark_variable().

When this callback is called you get a pointer to the original variable which you can modify and return, or simple return something different. I should also mention that you do need to pass a pointer as the second argument to spark_variable(), otherwise it isn’t actually created.

I’ve created a gist of this code at: https://gist.github.com/KenMacD/611172a2f7e57da07335f46b5d430eaa

#include <Particle.h>

static char* var_str = (char *)"ORIG STR";
static int var_int = 1;
static double var_double = 1.23;
static double override_double;

static const void* static_str_test(const char* name, Spark_Data_TypeDef type,
        const void* var, void *reserverd) {
    return "STATIC UPDATE";
}

static const void* dynamic_int_test(const char* name, Spark_Data_TypeDef type,
        const void* var, void *reserverd) {
    *((int *)var) += 1;
    return var;
}

static const void* static_double_test(const char* name, Spark_Data_TypeDef type,
        const void* var, void *reservered) {
    override_double = 2.34;
    return &override_double;
}
    
void setup() {

    spark_variable_t extra_str;
    extra_str.size = sizeof(extra_str);
    extra_str.update = static_str_test;
    spark_variable("str", (void *)var_str, CloudVariableTypeString::value(), &extra_str);

    spark_variable_t extra_int;
    extra_int.size = sizeof(extra_int);
    extra_int.update = dynamic_int_test;
    spark_variable("int", (void *)&var_int, CloudVariableTypeInt::value(), &extra_int);

    spark_variable_t extra_double;
    extra_double.size = sizeof(extra_double);
    extra_double.update = static_double_test;
    spark_variable("double", (void *)&var_double, CloudVariableTypeDouble::value(), &extra_double);
}

void loop() {
}
1 Like

For anyone that might stumble upon this older solution, it looks like firmware 1.5 adds support for functions: https://docs.particle.io/reference/device-os/firmware/photon/#particle-variable-calculated

1 Like