bifravst / cat-tracker-fw

Cat Tracker Firmware
https://bifravst.github.io/
3 stars 3 forks source link

Adding new message to mqtt comunication #54

Closed TjazVracko closed 4 years ago

TjazVracko commented 4 years ago

Hello,

I am trying to add my own custom message to be sent over MQTT. I tried copying the existing method that is present in the code, so I created a static struct k_delayed_work cloud_send_ram_data_work, wrote the corresponding function and added the work to the cloud_update_routine(void) function. When calling this function my function is called as well.

Im my function, static void cloud_send_ram_data(void), I fetch some samples from an ADC unit and I would like to send them over to aws. First, I created a new encoding function in cloud_codec.c, copying how other functions work, i.e: create a json object, add data to it, turn it into a string and add it to the msg struct. So far this works, except I can only add about 600 values, instead of the desired 1000. Is there some kind of msg encoding limit defined somewhere?

So, I manage to encode the data, but when sending it with err = cloud_send(cloud_backend, &msg); I get the following error:

Cloud send failed, err: -126

This is immediately followed by CLOUD_EVT_DISCONNECTED

How should I go about resolving this? Do I have to configure the message type somewhere to be able to send it, or do I maybe have to add something to the AWS config?

Thank you for the help.

Relevant code attached bellow:

added to main.c

static struct k_delayed_work cloud_send_ram_data_work;

static void work_init(void)
{
    k_delayed_work_init(&cloud_pair_work, cloud_pair_work_fn);
    k_delayed_work_init(&cloud_send_sensor_data_work,
                cloud_send_sensor_data_work_fn);
    k_delayed_work_init(&cloud_send_cfg_work, cloud_send_cfg_work_fn);
    k_delayed_work_init(&cloud_send_modem_data_work,
                cloud_send_modem_data_work_fn);
    k_delayed_work_init(&cloud_send_modem_data_dyn_work,
                cloud_send_modem_data_dyn_work_fn);
    k_delayed_work_init(&cloud_send_buffered_data_work,
                cloud_send_buffered_data_work_fn);
    k_delayed_work_init(&set_led_device_mode_work,
                set_led_device_mode_work_fn);
    k_delayed_work_init(&cloud_send_ram_data_work,
                cloud_send_ram_data_work_fn);  // I added this
}

static void cloud_update_routine(void)
{
    printk("CLOUD UPDATE\n");
    if (k_sem_count_get(&cloud_conn_sem) && cloud_connected) {
        k_delayed_work_submit(&cloud_send_sensor_data_work, K_NO_WAIT);
        k_delayed_work_submit(&cloud_send_cfg_work, K_SECONDS(5));
        k_delayed_work_submit(&cloud_send_modem_data_dyn_work,
                      K_SECONDS(5));
        k_delayed_work_submit(&cloud_send_buffered_data_work,
                      K_SECONDS(5));
        k_delayed_work_submit(&set_led_device_mode_work, K_SECONDS(5));
        k_delayed_work_submit(&cloud_send_ram_data_work, K_SECONDS(1)); // send ram values
    } else {
        printk("CLOUD UPDATE ERROR - cloud_connected: %i\n",
               cloud_connected);
    }
}

static void cloud_send_ram_data_work_fn(struct k_work *work)
{
    cloud_send_ram_data();
}

int ram_adc_data_int[ADC_BUFFER_SIZE];
static void cloud_send_ram_data(void)
{
    printk("---------------------------- cloud_send_ram_data() START\n");
    int err;

    ui_led_set_pattern(UI_CLOUD_PUBLISHING);

    struct cloud_msg msg = {
        .qos = CLOUD_QOS_AT_MOST_ONCE,
        .endpoint.type = CLOUD_EP_TOPIC_MSG,
    };

    // convert from int16_t to int
    size_t i = 0;
    for (i = 0; i < ADC_BUFFER_SIZE; i++) {
        ram_adc_data_int[i] = (int)m_sample_buffer[i];
        // printk("%d ", ram_adc_data_int[i]);
    }
    printk("\n");

    /* Encode and send buffer*/
    printk("--------------cloud_encode_ram_adc_buffer START\n");
    int timestamp = 1337; // TODO: how to get ts?
    err = cloud_encode_ram_adc_buffer(&msg, &ram_adc_data_int, 600,
                      timestamp);
    if (err) {
        printk("Error encoding ram buffer: %d\n", err);
        return;
    }
    printk("--------------cloud_encode_ram_adc_buffer DONE\n");

    printk("--------------cloud_send START\n");
    err = cloud_send(cloud_backend, &msg);  // THIS FAILS
    printk("--------------cloud_send END\n");
    printk("--------------cloud_release_data START\n");
    cloud_release_data(&msg);
    printk("--------------cloud_release_data END\n");

    if (err) {
        printk("Cloud send failed, err: %d\n", err);
        return;
    }

    printk("---------------------------- cloud_send_ram_data() DONE\n");
}

added to cloud_codec.c

static int json_add_IntArray(cJSON *parent, const char *str, int *item,
                 int count)
{
    cJSON *json_int_arr;

    json_int_arr = cJSON_CreateIntArray(item, count);
    if (json_int_arr == NULL) {
        printk("json_int_arr: is null\n");
        return -ENOMEM;
    }

    return json_add_obj(parent, str, json_int_arr);
}

int cloud_encode_ram_adc_buffer(struct cloud_msg *output, int *ram_adc_data,
                int count, int timestamp)
{
    int err = 0;
    char *buffer;
    // int encoded_counter = 0;

    cJSON *root_obj = cJSON_CreateObject();
    cJSON *state_obj = cJSON_CreateObject();

    if (root_obj == NULL) {
        cJSON_Delete(root_obj);
        return -ENOMEM;
    }

    err += json_add_IntArray(state_obj, "ramadc1", ram_adc_data, count / 3);
    err += json_add_IntArray(state_obj, "ramadc2",
                 ram_adc_data + 1 * (count / 3), count / 3);
    err += json_add_IntArray(root_obj, "ramadc3",
                 ram_adc_data + 2 * (count / 3), count / 3);

    err += json_add_number(state_obj, "ts", timestamp);

    if (err) {
        cJSON_Delete(root_obj);
        return -EAGAIN;
    }

    err += json_add_obj(root_obj, "state", state_obj);

    buffer = cJSON_Print(root_obj);
    cJSON_Delete(root_obj);

    printk("Encoded message: %s\n", buffer);

    output->buf = buffer;
    output->len = strlen(buffer);

    return 0;
}
TjazVracko commented 4 years ago

Alright,

so it turns out, I think, that it has to do with message size. I can send messages up to 2048 bytes long.

In bifravst_cloud.c you have the folowing code:

static char rx_buffer[CONFIG_BIFRAVST_CLOUD_MQTT_RX_TX_BUFFER_LEN];
static char tx_buffer[CONFIG_BIFRAVST_CLOUD_MQTT_RX_TX_BUFFER_LEN];
static char payload_buf[CONFIG_BIFRAVST_CLOUD_MQTT_PAYLOAD_BUFFER_LEN];

but I can not find definitions for CONFIG_BIFRAVST_CLOUD_MQTT_PAYLOAD_BUFFER_LEN or BIFRAVST_CLOUD_MQTT_PAYLOAD_BUFFER_LEN anywhere. Adding both defines to prj.conf and setting them to 4096 seems not to change anything.

The error when sending big messages is 126, which seems not to be the error related to size (90). So can the error be related to anything else? How can I adjust the message size limit?

Thank you for your help.

simensrostad commented 4 years ago

The modem drops messages exceeding ~2k bytes. Setting the aforementioned configurations to any greater than 2048 is redundant. Try reducing your packet sizes and see if that resolves the problem.

TjazVracko commented 4 years ago

Yes, smaller messages work fine. Can I increase the limit on the modem or is the size limit hard-coded?

TjazVracko commented 4 years ago

We can send the data in 2 parts using 2 separate messages. If ~2k bytes is a hard limit, then this is how we will do it.

Thanks

coderbyheart commented 4 years ago

Can I increase the limit on the modem or is the size limit hard-coded?

The nRF9160 has a size limit of 2303 bytes for sending and receiving TLS packages, which cannot be changed which is due to the limited memory of the device.