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

Mesh SAR time-out

Hello everyone.

My project is getting quite complex so I will try to abridge. (Mesh SDK 3.2.0)

I am trying to send wifi credentials from an android application (derived from the Android-nRF-Mesh-Library) to a mesh server node
(said node being connected to an Arduino, it will send the packet over serial for it to establish a connection)
We are currently using nRF52840 DK for both server and client nodes. I have tried using both a config message and generic message but the same problem seems to surface.

If the android device is connected directly to the server, the messages passes without any hurdle. (e.g. upon provisioning the server)
However, if I am connected to a client, the server never gets my mesh packets. (unless the packet is small enough)
Now, I don't want to force my user to connect to the server. If, let's say, the wifi password changed after provisioning happened, as they may have many server nodes, they would need to connect to every single one of them one by one and send the new wifi settings packet.

So on the server, I am getting the first segment in transport.c : trs_seg_packet_in()
but then fires NRF_MESH_EVT_SAR_FAILED with as reason : 0 (NRF_MESH_SAR_CANCEL_REASON_TIMEOUT)

----------

Now, on the client side receiving the mesh packets over proxy, I am of course receiving every segments from the android application.

Inside transport_packet_in(), nrf_mesh_rx_address_get() leads to address_nonvirtual_subscription_exists() in device_state_manager.c
What is weird is that it finds the subscription address but seems to think the subscription count is 0 (even though this very client has been sending app packets to the server subscribing to this address) and then seems to discard the packet.
[EDIT] Ok. This client node is not subscribed to this address so it will drop the packet. Nvm, it all makes sense. I would be glad if anyone could point me where is it it actually relays that packet though. [EDIT 2] Nvm, I found it comes later in network.c : network_packet_in()

I may have done something wrong... :S
Perhaps the server is just not sending confirmation upon receiving a segment?

I am welcoming any help I can get on this Slight smile

Parents
  • Hi,

    Sorry for the delayed response. Have you had any progress on this matter? Seems like there are some packet loss when sending packets to the server. If I understand this correctly, you hit SAR timeouts on the server when packets are retransmitted from the client?

  • What do you mean by "ask"? A message from the client can be retransmittet a number of times depending on your configuration, to ensure that the server receives this message. An ACK can be sent back from the server if a reliable message was sent. Have you tried increasing the retransmit count on the client? 

  • If it had, let's say, received segment 5 but did not get segment 4... I thought it could fetch it from the message's source.

    I would like to use an acknowledged message for sure. This is a priority as if the server cannot connect to wifi, the rest of the mesh network is pretty much useless.

    From the Nordic Android-nRF-Mesh-Library, I was using sendMeshMessage() of MeshManagerApi.java

    Its name changed in a recent version (2.0.3 ?) to :

    public void createMeshPdu(final int dst, @NonNull final MeshMessage meshMessage)

    but there doesn't seem to be any option to send it as an acknowledged message (nor does it have a retransmission count), or am I mistaken?

    Here's my message, if ever.. :

    public class ServerWifiSet extends GenericMessage {

    private static final String TAG = ServerWifiSet.class.getSimpleName();
    private static final int OP_CODE = ApplicationMessageOpCodes.SERVER_WIFI_SET;

    private final String mSSID;
    private final String mPass;

    /**
    * Constructs PublishServerWifi message.
    *
    * @param appKey application key for this message
    * @param SSID SSID
    * @param pass pass
    * @throws IllegalArgumentException if any illegal arguments are passed
    */
    public PublishServerWifi(@NonNull final ApplicationKey appKey, final String SSID, final String pass) {
    super(appKey);
    if (SSID.length()>32 || pass.length()>64) throw new IllegalArgumentException();
    this.mSSID = SSID;
    this.mPass = pass;
    assembleMessageParameters();
    }

    @Override
    public int getOpCode() {
    return OP_CODE;
    }

    @Override
    void assembleMessageParameters() {
    mAid = SecureUtils.calculateK4(mAppKey.getKey());

    final ByteBuffer paramsBuffer;
    paramsBuffer = ByteBuffer.allocate(this.mSSID.length() + 1 + this.mPass.length()).order(ByteOrder.LITTLE_ENDIAN);
    paramsBuffer.put(this.mSSID.getBytes());
    paramsBuffer.put(new byte[1]); // 1 empty byte for separation
    paramsBuffer.put(this.mPass.getBytes());
    mParameters = paramsBuffer.array();
    //Log.d("Publish mParameters", new String(mParameters));
    }
    }

    Then, again the device connected over proxy seems to receive everything. So should I make this message an acknowledged one only once i got the message on the client side?

Reply
  • If it had, let's say, received segment 5 but did not get segment 4... I thought it could fetch it from the message's source.

    I would like to use an acknowledged message for sure. This is a priority as if the server cannot connect to wifi, the rest of the mesh network is pretty much useless.

    From the Nordic Android-nRF-Mesh-Library, I was using sendMeshMessage() of MeshManagerApi.java

    Its name changed in a recent version (2.0.3 ?) to :

    public void createMeshPdu(final int dst, @NonNull final MeshMessage meshMessage)

    but there doesn't seem to be any option to send it as an acknowledged message (nor does it have a retransmission count), or am I mistaken?

    Here's my message, if ever.. :

    public class ServerWifiSet extends GenericMessage {

    private static final String TAG = ServerWifiSet.class.getSimpleName();
    private static final int OP_CODE = ApplicationMessageOpCodes.SERVER_WIFI_SET;

    private final String mSSID;
    private final String mPass;

    /**
    * Constructs PublishServerWifi message.
    *
    * @param appKey application key for this message
    * @param SSID SSID
    * @param pass pass
    * @throws IllegalArgumentException if any illegal arguments are passed
    */
    public PublishServerWifi(@NonNull final ApplicationKey appKey, final String SSID, final String pass) {
    super(appKey);
    if (SSID.length()>32 || pass.length()>64) throw new IllegalArgumentException();
    this.mSSID = SSID;
    this.mPass = pass;
    assembleMessageParameters();
    }

    @Override
    public int getOpCode() {
    return OP_CODE;
    }

    @Override
    void assembleMessageParameters() {
    mAid = SecureUtils.calculateK4(mAppKey.getKey());

    final ByteBuffer paramsBuffer;
    paramsBuffer = ByteBuffer.allocate(this.mSSID.length() + 1 + this.mPass.length()).order(ByteOrder.LITTLE_ENDIAN);
    paramsBuffer.put(this.mSSID.getBytes());
    paramsBuffer.put(new byte[1]); // 1 empty byte for separation
    paramsBuffer.put(this.mPass.getBytes());
    mParameters = paramsBuffer.array();
    //Log.d("Publish mParameters", new String(mParameters));
    }
    }

    Then, again the device connected over proxy seems to receive everything. So should I make this message an acknowledged one only once i got the message on the client side?

Children
  • Hi ,

    Yes the api was renamed to make it a little bit more sensible as the calling the api SendMeshMessage would be wrong as the library does not send anything but generate a mesh packet, hence the renaming to createMeshPdu. About acknowledged messages, If you check all configuration/generic messages are of of type MeshMessage. So basically you just have to create an acknowledged message and send it and the library will handle it for you. Unfortunately we are missing the retransmission in the Mesh library. Currenlty the library only retransmit segmented messages based on block acks.

    IMHO your message should just work out of the box.

    Hope this answers your question.

  • Hi ,
    Thank you for your enlightening reply.

    So simply creating a message PDU long enough should make it a reliable message with acknowledgement, is that right?

    As I said, the node connected to the android device over proxy is receiving every packets so I would suppose this part works correctly indeed. However, the next node receiving the relayed packets is often missing a few packets.

    So, how is it acknowledged over proxy but then is not over the rest of the mesh network?


    As  suggested, I tried increasing the retransmit count on the client; increasing it a bit still produced the error, but increasing it to 6 seemed to have every message pass (with only one relaying node in between).
    Wouldn't increasing the retransmit count on every client put an unnecessary burden on the network? What if, out of bad luck, one packet get lost for all retransmissions, I would still be missing the whole PDU for one lost packet.

    This PDU being important, I think it would be safer to make sure the proxy connection is directly onto the server node.

  • Hi,

    Increasing the retransmit count will help make sure that the receiving node get the message. All mesh devices maintain a message cache, which is used for filtering out packets that the device has already handled. This is to avoid messages being forwarded by the same realys over and over.

    Even though increasing the retransmit might help it doesn't ensure that there never will be packet loss. The best option would be to send a reliable(acknowledgeable) message. 

    Just to clarify, the client node in this case will act as a relay node? If so, then message should be relayed as it is, message PDU remains unchanged when message is relayed.

Related