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

multiple clients to server message on Mesh

 in the code below. implemented on a mesh form multiple Clients (Publication addresses)  to the  server (subscriped) to all the clients.

The code reads beacon data, removes the Minor ID, combine it with the Client UUID . This needs to be sent to the server.

I would like to know 

1.  how to use the function :  access_model_reliable_publish(); to transmit the array Result[24]  from the code below 

2. Max clients that can send data to 1 server on a mesh.


/* Models */
#include "generic_onoff_client.h"

/* Logging and RTT */
#include "log.h"
#include "rtt_input.h"

/* Example specific includes */
#include "app_config.h"
#include "nrf_mesh_config_examples.h"
#include "light_switch_example_common.h"
#include "example_common.h"
#include "ble_softdevice_support.h"
#include "nrf_delay.h"
#include "string.h"
#define APP_STATE_OFF                (0)
#define APP_STATE_ON                 (1)

#define APP_UNACK_MSG_REPEAT_COUNT   (2)

static generic_onoff_client_t m_clients[CLIENT_MODEL_INSTANCE_COUNT];
static bool                   m_device_provisioned;
char scanner_UUID[17]; // scanner 2 bytes + 1



//for below also investigate ? nrf_mesh_rx_cb_t This callback can be used to receive raw advertisement packets
static void rx_cb(const nrf_mesh_adv_packet_rx_data_t * p_rx_data) // used for listening for incoming packets  with function nrf_mesh_rx_cb_set(rx_cb);
{
    LEDS_OFF(BSP_LED_0_MASK);  /* @c LED_RGB_RED_MASK on pca10031 */
    char msg[64];
    char beacon_Minor_ID[5]; // the length of the eMbeacon unique ID
    char Result[24]; // 5+16+1 for nul term
    char beacon_uuid[37]; // the length of EM microelectronics packet**** check this it may be shorter
 

// copy the UUID of the beacon
    memcpy(beacon_uuid,p_rx_data->p_payload, p_rx_data->length); // copy the UUID of the beacon
 // check if it is a EMbeacon Beacon make in bit 2:9
       if ((beacon_uuid[2]==0x45)|(beacon_uuid[3]==0x4D)|(beacon_uuid[4]==0x42)|(beacon_uuid[5]==0x65)
          |(beacon_uuid[6]==0x61)|(beacon_uuid[7]==0x63)|(beacon_uuid[8]==0x6f)|(beacon_uuid[9]==0x6e)) // EMBeacon name check
// if it is a beacon send PCA10059 (scanner) UUID and Beacon UUID to the client on the mesh
    {     
      memcpy (beacon_Minor_ID,beacon_uuid + 10,5); // move the 5 unique beacon ID bytes for use in mesh to identify the beacon
      memcpy(Result, (void*) &scanner_UUID[0], 16);       // combine Beacon Minor UUID and Scanner complete UUID 
      memcpy(&Result[16], (void*) &beacon_Minor_ID[0], 8); // Advertisement address 
 
 // Transmit Result on the mesh  to the gateway server.


access_model_reliable_publish();

Thanks in advance

Parents
  • Hello,

    You must have a model that can transfer your packet. "Model" = Bluetooth mesh "service". 

    The light switch example uses an on_off_model. This can only transfer a single byte, and it actually only holds a bool, so you need to modify this model to contain a string. See how the publish function is used in the light switch example, and see if you can modify/create a model that holds this array instead of just an on_off state.

    Depending on the number of nodes in your mesh network, using access_model_reliable_publish may not be a good idea. This requires the node that subscribes to the messages to send an ACK, doubling the amount of messages travelling around in your network. If you don't have too many nodes subscribing, this will probably be ok, but if it was a lighting system, and all the lightbulbs in a warehouse were to ACK all messages, the mesh will be flooded with messages.  That being said, there is no maximum number of nodes that can publish on a channel which the server subscribes to. Only the maximum number of nodes in a network will be the theoretical limit for this, which  is around 32 000 nodes.

    Best regards,

    Edvin

  • Thanks Edvin

    Will the simple_message_client work

    for me here? Mesh V3.00

    If so where do I declare m_central_handel -  im getting a compile error.

    //simple send message example
    void address_set(uint16_t addr)                 //function for setting address
    {
      uint32_t err_code;
      err_code = dsm_address_publish_add(addr, &m_central_handle); //NRF_ERROR_NO_MEM
      ERROR_CHECK(err_code);
      ERROR_CHECK(access_model_publish_address_set(m_clients[0].model_handle, m_central_handle));
    }
    
    
    void send_message(void)                         //function for sending a simple message
    {
        uint32_t status=0;
        uint8_t buffer[5] = "hello";
        uint8_t length;
        uint16_t address;
        access_message_tx_t msg; // declare variable access.h
        length = sizeof(buffer); //SEGGER_RTT_Read(0, buffer, sizeof(buffer));
        
        if(length)
        {
          //no-need:SEGGER_RTT_WriteString(0, "entering message field\n");
          msg.opcode.opcode = simple_message_OPCODE_SEND;
          msg.opcode.company_id = 0x0059; // Nordic's company ID
    
          msg.p_buffer = (const uint8_t *) &buffer[0];
          msg.length = length;
          address = 0xCAFE;
          address_set(address);
          printf(0,"Sending to group address 0x%04x\n", address);
        status= access_model_publish(m_clients[3].model_handle, &msg);
      
          if(status == NRF_ERROR_INVALID_STATE ||
          status == NRF_ERROR_BUSY||
          status == NRF_ERROR_NO_MEM)
          {
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Cannot send. Device is busy.\n");
            hal_led_blink_ms(LEDS_MASK, 50, 4);
          }
          else
          {
             ERROR_CHECK(status);
          }
        }
    }
    

  • sorry yes handle 'm_central_handle' undeclared (first use in this function)

    Where is this declared in my C and how?  If you can show me please.

  • This should not be used directly in main. But in config_server.c it is declared like:

    dsm_handle_t publish_address_handle = DSM_HANDLE_INVALID;

    This is just an empty handle that is populated in dsm_address_publish_add(publish_address, &publish_address_handle);

    If you have the address, you may do this manually, but as I mentioned, this should really (!) be done through the commissioning process. That is the reason why this function is not used in the main.c file in the examples.

    If you have not already, I suggest you read through the guide on how to run the light switch example here:

    https://www.nordicsemi.com/DocLib/Content/SDK_Doc/Mesh_SDK/v3-1-0/md_examples_light_switch_README

    Depending on whether you have 2 or 3 nRF devices, you can either use one device as the provisioner(evaluate using the static provisioner), or you can use the nRF Mesh app as the provisioner (evaluate using the nRFMesh mobile app).

    BR,

    Edvin

  • Thanks Edvin, I have removed it. I have 10 clients 1 server. I can provision them successfully with the client light switch example. Im trying to implement the following example https://devzone.nordicsemi.com/f/nordic-q-a/29836/send-and-receive-a-string-via-access-layer

    I have the following error   address_set(address)  error ;undefined reference to `address_set'

    Where do I need to set this?

    Does this simple message example work on mesh 3 or 3.1? is there no working example available, it will really help a lot.

    Thanks

  • Hello,

    I think that what Bjørn is explaining in the ticket that you linked to is important. It seems like the snippet is for Mesh SDK1.0.0, which is old, and there has been a lot (!) of improvements, so I suggest that you start with SDK for mesh >= 3.0.0, and use the information in this setup to convert the onoff model to a simple_message model.

    As long as you don't change anything with the address setup you don't have to worry about it, and let the provisioning handle the addresses. You should only need the generic_onoff_client_set() or generic_onoff_client_set_unack() (depending on whether you want the messages to be ACKed or not).

    The address is stored in the m_clients[].model_handle when you provision.

  • Edvin I have have gone through the simple_on_off_model in the models/vendor directory )(MESH 3.00) . I then compared it to the old simple_message example from Bjorn for MESH SDK_1. Surprisingly a lot of the code is the same with minor differences. I can provision my newly based  simple_message sample without any problems.

    When I send my simple message I get the following error 

    <t: 253118>, app_error_weak.c, 119, Mesh error 7 at 0x00026B33  (how do I know what this means)

    I also do the following check so I don't send a message when the device is unprovisioned

    if (m_device_provisioned) { send_message() }

    But I noticed that "m_device_provisioned" does not become "true" after initial provisioning, only once the device is provisioned and reset then  "m_device_provisioned" true. Is there another way for me to do this check during  the initial provisioning?

    thanks.

     

Reply
  • Edvin I have have gone through the simple_on_off_model in the models/vendor directory )(MESH 3.00) . I then compared it to the old simple_message example from Bjorn for MESH SDK_1. Surprisingly a lot of the code is the same with minor differences. I can provision my newly based  simple_message sample without any problems.

    When I send my simple message I get the following error 

    <t: 253118>, app_error_weak.c, 119, Mesh error 7 at 0x00026B33  (how do I know what this means)

    I also do the following check so I don't send a message when the device is unprovisioned

    if (m_device_provisioned) { send_message() }

    But I noticed that "m_device_provisioned" does not become "true" after initial provisioning, only once the device is provisioned and reset then  "m_device_provisioned" true. Is there another way for me to do this check during  the initial provisioning?

    thanks.

     

Children
  • Hello,

    Try to disable optimization on your project (set it to -O0), and then set a break point on line 115 in app_error_weak.c. When it stops there check the variables:

    p_info->err_code. // it looks like this is 7
    pc, 
    p_info->p_file_name, //this should contain the file name of the file that received an ERROR_CHECK(err_code) where err_code != 0.
    p_info->line_num // This should point to what line number in that file the ERROR_CHECK is located.

    Now, when you find this, try to look at what function that returned the return value passed into ERROR_CHECK, and what it means when this function returns 7.

    Best regards,

    Edvin

  • It seems to be inside my send message function. in access_model_publish

    status= access_model_publish(m_clients[0].model_handle, &msg);

  • Ok. so access_model_publish can return NRF_ERROR_INVALID_PARAM which you can see in access.h.

    If you look at access_model_publish in access.c, you see that it can either return NRF_ERROR_NULL, or it returns the return value of packet_tx().

    Maybe your check_tx_params returns NRF_ERROR_INVALIT_PARAM. Try to debug in this function to figure out where/what function call that returns this value.

    Best regards,

    Edvin

  • It seems to give Mesh error 7 when the  client does not have app bind key and a broadcast address set up. Once these are set up, the mesh error 7 is gone. But it now returns, Cannot send. Device is Busy

    I just need to add here, up to this point I have only been working on the client, The server has not been set up for simple_message yet and is running standard on_off_model. do don't know if it may have something to do with that. I will now switch over to the server side.

  • If you are sending acknowledged messages, then it will matter, because it can only queue so many packets. I suggest you start with the server side, so that you have something that is actually acknowledging the messages. Start to set it up so that you can send one simple message between the two, and take it from there.

    BR,

    Edvin

Related