This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Reliable messages with long timeout

Hello,

Mesh SDK 4.0.0, PCA10040 x2

I want to develop next models:

  • Scan server: Waiting GET message with arguments, scan BLE beacons and reply STATUS message with results backward;
  • Scan client: Send GET message (with scan filter arguments) and receive reply with results of scaning;

In my case I need a long timeout reliable GET message at client side because scanning at server is not so fast operation.

static uint32_t send_reliable_message(const scan_client_t * p_client,
                                      scan_opcode_t opcode,
                                      const uint8_t * p_data,
                                      uint16_t length)
{
    access_reliable_t reliable;
    reliable.model_handle = p_client->model_handle;
    reliable.message.p_buffer = p_data;
    reliable.message.length = length;
    reliable.message.opcode.opcode = opcode;
    reliable.message.opcode.company_id = SCAN_COMPANY_ID;
    reliable.message.force_segmented = false;
    reliable.message.transmic_size = NRF_MESH_TRANSMIC_SIZE_DEFAULT;
    reliable.message.access_token = nrf_mesh_unique_token_get();
    reliable.reply_opcode.opcode = SCAN_OPCODE_STATUS;
    reliable.reply_opcode.company_id = SCAN_COMPANY_ID;
    reliable.timeout = SCAN_CLIENT_ACKED_TRANSACTION_TIMEOUT; // 60 seconds !!!
    reliable.status_cb = reliable_status_cb;

    return access_model_reliable_publish(&reliable);
}

But access_model_reliable_publish at 447 line call add_reliable_message

uint32_t access_model_reliable_publish(const access_reliable_t * p_reliable)
{
    uint32_t status;
    uint16_t index;

    if (NULL == p_reliable || NULL == p_reliable->status_cb)
    {
        return NRF_ERROR_NULL;
    }
    else if (ACCESS_MODEL_COUNT <= p_reliable->model_handle)
    {
        return NRF_ERROR_NOT_FOUND;
    }
    else if (ACCESS_RELIABLE_TIMEOUT_MIN > p_reliable->timeout  ||
             ACCESS_RELIABLE_TIMEOUT_MAX < p_reliable->timeout)
    {
        return NRF_ERROR_INVALID_PARAM;
    }
    else if (!available_context_get(p_reliable, &index, &status))
    {
        return status;
    }
    else
    {
        status = access_model_publish(p_reliable->model_handle, &p_reliable->message);
        if (NRF_SUCCESS == status || NRF_ERROR_NO_MEM == status || NRF_ERROR_INVALID_STATE == status)
        {
            /** @todo If we get @c NRF_ERROR_NO_MEM, we could be even "smarter" and retry in @ref
             * ACCESS_RELIABLE_RETRY_DELAY scaled based on advertising intervals or something.
             * Ref.: MBTLE-1542. */
            add_reliable_message(index, p_reliable); //WTF?
            return NRF_SUCCESS;
        }
        else
        {
            return status;
        }
    }
}

And add_reliable_message schedule next TX by calculated interval 800 000 us.

Client transmit next GET message while have not received STATUS from server.

At result I have duplicated GET messages on server side.

Could you please point me on mistake? Or suggest how can I make it?

  • Hi Batov, 

    Could you explain a little bit more on "scanning at server is not so fast operation."  ? Are you limiting the scanning window  ? 

    You can configure the reliable message timeout by defining MODEL_ACKNOWLEDGED_TRANSACTION_TIMEOUT (usually inside nrf_mesh_config_app.h) . This is the valued used when calling access_model_reliable_publish() in our light switch client example. 


    The access_reliable library automatically schedule a retransmission for reliable message with the interval calculated in calculate_interval(). It's based on ACCESS_RELIABLE_INTERVAL_DEFAULT and the TTL value. 

    You can adjust the timeout and the interval to fit better with your network configuration. 

    Another option is to use the access layer directly and skip the access_reliable.c library. This way you can choose what you want to do with the reliable message. 

  • I am using nrf_ble_scan_start for scan BLE beacons around server side device. It takes more time than expected for STATUS message with ack.

    I am using access_reliable_t.timeout field too (at light switch client example you copy MODEL_ACKNOWLEDGED_TRANSACTION_TIMEOUT there). Look at my first code sample at 17 line. But calculate_interval() ignores it because calculated interval (based on ACCESS_RELIABLE_INTERVAL_DEFAULT and the TTL) less than timeout.

    Change ACCESS_RELIABLE_INTERVAL_DEFAULT will help me, but I want to avoid modiging network stack.

    Skipping access_reliable is suitable case for me.

    Then again, I can add duplicate messages barrier on server model side.

    Thanks a lot for you answer. It's very useful for me. You prove my points!

Related