cesanta / mongoose-os

Mongoose OS - an IoT Firmware Development Framework. Supported microcontrollers: ESP32, ESP8266, CC3220, CC3200, STM32F4, STM32L4, STM32F7. Amazon AWS IoT, Microsoft Azure, Google IoT Core integrated. Code in C or JavaScript.
https://mongoose-os.com
Other
2.51k stars 429 forks source link

Please extern descrs[] from mgos_deps_init.c #536

Closed Harvie closed 4 years ago

Harvie commented 4 years ago

Hello, i would like to get list of names of active mongoose modules during runtime. Can you please make data from descrs[] array accesible using some header file which can be included in my modules?

I want to use this to send JSON list of modules to my cloud/server, so i know what modules/capabilities each device provides and therefore i know which features i can use... Because i have several devices which share some of the modules, while other modules are specific. It makes more sense to me than using several "versions" of API for each device configuration. This way i would simply know what modules are present in the device, so i can write nice modular API on the server.

BTW if you add version of each module to the list, it might be usefull as well.

Thanks

rojer commented 4 years ago

Changes made, you can now examine mgos_libs_info to get information about libraries. This requires changes to mos CLI, i am pushing mos-latest now.

Harvie commented 4 years ago

Thanks a lot. I will take a look.

Harvie commented 4 years ago

We have managed to list all modules like this:

#include "mgos_app.h"

...

#ifdef MGOS_LIB_INFO_VERSION
    /* iterate over all mongoose modules compiled in firmware */
    for (const struct mgos_lib_info *l = mgos_libs_info; l->name != NULL; l++)
    {
        LOG(LL_INFO,("FHS DETECTED MODULE: %s version %s", l->name, l->version));
    }
#endif

I haven't checked yet that mgos_libs_info is actually NULL terminated. Also i am yet to modify the code to use json_printf_array() (from frozen) to convert the array to JSON...

Harvie commented 4 years ago

For some reason i wasn't able to iterate like this:

for(int i = 0; i < sizeof(mgos_libs_info) / sizeof(struct mgos_lib_info); i++) {...}

didn't compiled...

DrBomb commented 4 years ago

You can see by yourself the generated file by browsing the file contained inside build/gen/mgos_deps_init.c

Here's a snippet of the last part of mgos_libs_info :

    // "rpc-mqtt". deps: [ "aws" "core" "mqtt" "rpc-common" ]
    {.name = "rpc-mqtt", .version = "1.0", .init = mgos_rpc_mqtt_init},

    // "rpc-service-config". deps: [ "core" "rpc-common" ]
    {.name = "rpc-service-config", .version = "1.0", .init = mgos_rpc_service_config_init},

    // "rpc-service-fs". deps: [ "core" "rpc-common" ]
    {.name = "rpc-service-fs", .version = "1.0", .init = mgos_rpc_service_fs_init},

    // "rpc-service-gpio". deps: [ "core" "rpc-common" ]
    {.name = "rpc-service-gpio", .version = "1.0", .init = mgos_rpc_service_gpio_init},

    // "rpc-service-i2c". deps: [ "core" "i2c" "rpc-common" ]
    {.name = "rpc-service-i2c", .version = "1.0", .init = mgos_rpc_service_i2c_init},

    // "rpc-service-ota". deps: [ "core" "ota-http-client" "rpc-common" ]
    {.name = "rpc-service-ota", .version = "1.0", .init = mgos_rpc_service_ota_init},

    // "rpc-service-wifi". deps: [ "core" "rpc-common" "wifi" ]
    {.name = "rpc-service-wifi", .version = "1.0", .init = mgos_rpc_service_wifi_init},

    // "rpc-uart". deps: [ "core" "rpc-common" ]
    {.name = "rpc-uart", .version = "1.0", .init = mgos_rpc_uart_init},

    // Last entry.
    {.name = NULL},
};

As you can see, the last entry will have its name member as NULL, you can use that information to iterate over the array and stop once NULL is found.

Harvie commented 4 years ago

When i try to do sizeof(mgos_libs_info) / sizeof(struct mgos_lib_info), the compilation fails with following message: Invalid application of 'sizeof' to incomplete type 'constr struct mgos_lib_info[]';

Maybe it's caused by the struct being defined in ifndef block... Can you please check if this might cause some files being compiled only with struct name without full declaration?

#ifndef MGOS_LIB_INFO_VERSION
struct mgos_lib_info {
  const char *name;
  const char *version;
  bool (*init)(void);
};
#endif
DrBomb commented 4 years ago

Are you using this header? https://github.com/cesanta/mongoose-os/blob/master/include/mgos_app.h

nliviu commented 4 years ago

The size of mgos_libs_info can't be determined at compile time. It is declared extern const struct mgos_lib_info mgos_libs_info[];. Without the extern keyword the compile error would be array size missing.

The best way to iterate it is

  for (const struct mgos_lib_info *info = mgos_libs_info; info->name != NULL;
       info++) {
    LOG(LL_INFO, ("name: %s, version: %s", info->name, info->version));
  }
Harvie commented 4 years ago

@DrBomb yes. i am including mgos_app.h

@nliviu i am doing this, but i want to compile the list to JSON, so i can send it over network in reasonable format... I probably only need sizeof(mgos_libs_info) to preallocate enough space in buffer to fit whole JSON. I've figured that's about right. I probably should call strlen() on all elements in the first pass, allocate and compile json in second pass, but this seemed easier to do...

Originaly i was thinking that it can be done by frozen json library, but i was not able to figure that out ( see https://github.com/cesanta/frozen/issues/58 ). So i came up with this ugly hack, but it has the previously mentioned problem...

#ifdef MGOS_LIB_INFO_VERSION
        char mgos_libs_info_json[sizeof(mgos_libs_info)];

    /* iterate over all mongoose modules compiled in firmware and produce JSON object with the list */
    mgos_libs_info_json[0]=0;
        strcat(mgos_libs_info_json, "{\"mgos_libs\":{");
    for (const struct mgos_lib_info *l = mgos_libs_info; l->name != NULL; l++)
    {
        LOG(LL_INFO,("FHS DETECTED MODULE: %s version %s", l->name, l->version));
                strcat(mgos_libs_info_json, "\"");
                strcat(mgos_libs_info_json, l->name);
                strcat(mgos_libs_info_json, "\":\"");
                strcat(mgos_libs_info_json, l->version);
                strcat(mgos_libs_info_json, "\"");
                if((l+1)->name != NULL) strcat(mgos_libs_info_json, ",");
    }
    strcat(mgos_libs_info_json, "}}");
    LOG(LL_INFO,("FHS DETECTED MODULES SIZE %d JSON: %s", sizeof(mgos_libs_info), mgos_libs_info_json);
#endif
Harvie commented 4 years ago

Maybe i can try to include mgos_deps_init.c directly... That worked for me when i've been doing experiments outside of mongoose ecosystem (just plain gcc on linux).

rojer commented 4 years ago

Maybe i can try to include mgos_deps_init.c directly

oh god, no! please don't do that :)

I probably only need sizeof(mgos_libs_info) to preallocate enough space in buffer to fit whole JSON

no, you need to grow your output buffer as needed.

rojer commented 4 years ago
void list_libs(void) {
  struct mbuf mb;
  struct json_out out = JSON_OUT_MBUF(&mb);
  mbuf_init(&mb, 200);
  json_printf(&out, "[\n");
  for (const struct mgos_lib_info *li = mgos_libs_info; li->name != NULL; li++) {
    if (mb.len > 2) {
      json_printf(&out, ",\n");
    }
    json_printf(&out, "  {name: %Q, version: %Q}", li->name, li->version);
  }
  json_printf(&out, "\n]\n");
  printf("%.*s", (int) mb.len, mb.buf);
  mbuf_free(&mb);
}