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

simple_on_off vendor model on Mesh 3.1

I am converting the simple_on_off vendor model to send a message on mesh 3.1.

the server  implemented the simple_on_off model successfully. But but my client runs into  0>, app_error_weak.c,  119, Mesh error 8 at 0x00000000 (:0)  straight away.

I suspect the line below in mesh_init could be causing the problem

  .core.p_uuid = dev_uuid, 

NOTE: This is for the PCA10059 not the DK. LEDS and Buttons have been remapped. I have removed generic_on_off model .c and . h files. I have kept model_common.c

/* Copyright (c) 2010 - 2018, Nordic Semiconductor ASA
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form, except as embedded into a Nordic
 *    Semiconductor ASA integrated circuit in a product or a software update for
 *    such product, must reproduce the above copyright notice, this list of
 *    conditions and the following disclaimer in the documentation and/or other
 *    materials provided with the distribution.
 *
 * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
 *    contributors may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * 4. This software, with or without modification, must only be used with a
 *    Nordic Semiconductor ASA integrated circuit.
 *
 * 5. Any software provided in binary form under this license must not be reverse
 *    engineered, decompiled, modified and/or disassembled.
 *
 * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdint.h>
#include <string.h>

/* HAL */
#include "boards.h"
#include "simple_hal.h"
#include "app_timer.h"

/* Core */
#include "nrf_mesh_config_core.h"
#include "nrf_mesh_gatt.h"
#include "nrf_mesh_configure.h"
#include "nrf_mesh.h"
#include "mesh_stack.h"
#include "device_state_manager.h"
#include "access_config.h"

/* Provisioning and configuration */
#include "mesh_provisionee.h"
#include "mesh_app_utils.h"

/* Models */
//#include "generic_onoff_client.h"
#include "simple_on_off_client.h"
#include "simple_on_off_common.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"

#define RTT_INPUT_POLL_PERIOD_MS (100)
#define GROUP_MSG_REPEAT_COUNT (2)

#define LED_BLINK_INTERVAL_MS (200)
#define LED_BLINK_SHORT_INTERVAL_MS (50)
#define LED_BLINK_CNT_START (2)
#define LED_BLINK_CNT_RESET (3)
#define LED_BLINK_CNT_PROV (4)
#define LED_BLINK_CNT_NO_REPLY (6)



static simple_on_off_client_t m_clients[CLIENT_MODEL_INSTANCE_COUNT];
//static const uint8_t m_client_node_uuid[NRF_MESH_UUID_SIZE] = CLIENT_NODE_UUID;
static bool m_device_provisioned;

static void client_status_cb(const simple_on_off_client_t *p_self, simple_on_off_status_t status, uint16_t src);

static bool client_publication_configured(void) {
  dsm_handle_t pub_addr_handle;
  for (uint8_t i = 0; i < CLIENT_MODEL_INSTANCE_COUNT; i++) {
    if (access_model_publish_address_get(m_clients[i].model_handle, &pub_addr_handle) == NRF_SUCCESS) {
      if (pub_addr_handle == DSM_HANDLE_INVALID) {
        return false;
      }
    } else {
      return false;
    }
  }

  return true;
}

static void provisioning_complete_cb(void) {
  __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Successfully provisioned\n");

  dsm_local_unicast_address_t node_address;
  dsm_local_unicast_addresses_get(&node_address);
  __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Node Address: 0x%04x \n", node_address.address_start);

  hal_led_mask_set(LEDS_MASK, LED_MASK_STATE_OFF);
  hal_led_blink_ms(LEDS_MASK, LED_BLINK_INTERVAL_MS, LED_BLINK_CNT_PROV);
}

static uint32_t server_index_get(const simple_on_off_client_t *p_client) {
  uint32_t index = p_client - &m_clients[0];
  NRF_MESH_ASSERT(index < SERVER_NODE_COUNT);
  return index;
}

static void client_publish_timeout_cb(access_model_handle_t handle, void *p_self) {
  __LOG(LOG_SRC_APP, LOG_LEVEL_ERROR, "Acknowledged send timedout\n");
}

static void client_status_cb(const simple_on_off_client_t *p_self, simple_on_off_status_t status, uint16_t src) {
  uint32_t server_index = server_index_get(p_self);

  //__LOG(LOG_SRC_APP, LOG_LEVEL_ERROR, "server status received \n",p_self);
  switch (status) {
  case SIMPLE_ON_OFF_STATUS_ON:
    hal_led_pin_set(BSP_LED_0 + server_index, true);
    break;

  case SIMPLE_ON_OFF_STATUS_OFF:
    hal_led_pin_set(BSP_LED_0 + server_index, false);
    break;

  case SIMPLE_ON_OFF_STATUS_ERROR_NO_REPLY:
    hal_led_blink_ms(LEDS_MASK, LED_BLINK_SHORT_INTERVAL_MS, LED_BLINK_CNT_NO_REPLY);
    break;

  case SIMPLE_ON_OFF_STATUS_CANCELLED:
  default:
    __LOG(LOG_SRC_APP, LOG_LEVEL_ERROR, "Unknown status \n");
    break;
  }
}

static void node_reset(void) {
  __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "----- Node reset  -----\n");
  hal_led_blink_ms(LEDS_MASK, LED_BLINK_INTERVAL_MS, LED_BLINK_CNT_RESET);
  mesh_stack_device_reset();

}

static void config_server_evt_cb(const config_server_evt_t *p_evt) {
  if (p_evt->type == CONFIG_SERVER_EVT_NODE_RESET) {
    node_reset();
  }
}

static void button_event_handler(uint32_t button_number) {
  //__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Button %u pressed\n", button_number);

  if (client_publication_configured()) {
    uint32_t status = NRF_SUCCESS;
    switch (button_number) {
    case 0:
    case 1:
      /* send unicast message, with inverted GPIO pin value */
     
      status = simple_on_off_client_set(&m_clients[button_number],
          !hal_led_pin_get(BSP_LED_0 + button_number));

      break;

    case 2:
    case 3:
   
      /* send a group message to the ODD group, with inverted GPIO pin value */
      status = simple_on_off_client_set_unreliable(&m_clients[button_number],
          !hal_led_pin_get(BSP_LED_0 + button_number),
          GROUP_MSG_REPEAT_COUNT);
      hal_led_pin_set(BSP_LED_0 + button_number, !hal_led_pin_get(BSP_LED_0 + button_number));
      break;
    default:
      break;
    }

    if (status == NRF_ERROR_INVALID_STATE ||status == NRF_ERROR_NO_MEM ||status == NRF_ERROR_BUSY) {
      __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Cannot send. Device is busy.\n");
      hal_led_blink_ms(LEDS_MASK, LED_BLINK_SHORT_INTERVAL_MS, LED_BLINK_CNT_NO_REPLY);
    } else {
      ERROR_CHECK(status);
    }
  } else {
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Ignored. Node is not configured.\n");
  }
}
/*uint32_t send_command_client(simple_on_off_client_t *p_client, uint8_t *msg, uint16_t length) {
  //int i;
  send_command_msg_t command_msg;

  command_msg.length = length;
  strncpy(command_msg.command, msg, length);

  access_message_tx_t message;
  message.opcode.opcode = SEND_COMMAND;
  message.opcode.company_id = ACCESS_COMPANY_ID_NORDIC;
  message.p_buffer = (const uint8_t *)&command_msg;
  message.length = command_msg.length + 2;

  uint32_t status = NRF_SUCCESS;

  status = access_model_publish(p_client->model_handle, &message);

  Method for sending to all nodes!
  for (uint8_t i = 0; i < 3; ++i)
    {
        status = access_model_publish(p_client->model_handle, &message);
        if (status == NRF_SUCCESS) {
            break;
        }
    }
  return status;
}*/

static void rtt_input_handler(int key)
{
    if (key >= '0' && key <= '3')
    {
        uint32_t button_number = key - '0';
        button_event_handler(button_number);
    }
}

static void models_init_cb(void) {
  __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Initializing and adding models\n");

  for (uint32_t i = 0; i < CLIENT_MODEL_INSTANCE_COUNT; ++i) {
    m_clients[i].status_cb = client_status_cb;
    m_clients[i].timeout_cb = client_publish_timeout_cb;
    ERROR_CHECK(simple_on_off_client_init(&m_clients[i], i + 1));
    ERROR_CHECK(access_model_subscription_list_alloc(m_clients[i].model_handle));
  }
}

static void mesh_init(void) {

uint8_t dev_uuid[NRF_MESH_UUID_SIZE];
 uint8_t node_uuid_prefix[NODE_UUID_PREFIX_LEN] = CLIENT_NODE_UUID_PREFIX;
 
  mesh_stack_init_params_t init_params =
      {
          .core.irq_priority = NRF_MESH_IRQ_PRIORITY_LOWEST,
          .core.lfclksrc = DEV_BOARD_LF_CLK_CFG,
          .core.p_uuid = dev_uuid,
          .models.models_init_cb = models_init_cb,
          .models.config_server_cb = config_server_evt_cb};
  ERROR_CHECK(mesh_stack_init(&init_params, &m_device_provisioned));
}

static void initialize(void) {
  __LOG_INIT(LOG_SRC_APP | LOG_SRC_ACCESS, LOG_LEVEL_INFO, LOG_CALLBACK_DEFAULT);
  __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "----- BLE Mesh Light Switch Client Demo -----\n");

  hal_leds_init();
#if BUTTON_BOARD
  ERROR_CHECK(hal_buttons_init(button_event_handler));
#endif

 nrf_clock_lf_cfg_t lfc_cfg = DEV_BOARD_LF_CLK_CFG;
  
  mesh_init();
}

static void start(void) {
  rtt_input_enable(rtt_input_handler, RTT_INPUT_POLL_PERIOD_MS);
  ERROR_CHECK(mesh_stack_start());

  if (!m_device_provisioned) {
    static const uint8_t static_auth_data[NRF_MESH_KEY_SIZE] = STATIC_AUTH_DATA;
    mesh_provisionee_start_params_t prov_start_params =
        {
            .p_static_data = static_auth_data,
            .prov_complete_cb = provisioning_complete_cb};
    ERROR_CHECK(mesh_provisionee_prov_start(&prov_start_params));
  }

  const uint8_t *p_uuid = nrf_mesh_configure_device_uuid_get();
  __LOG_XB(LOG_SRC_APP, LOG_LEVEL_INFO, "Device UUID ", p_uuid, NRF_MESH_UUID_SIZE);

  hal_led_mask_set(LEDS_MASK, LED_MASK_STATE_OFF);
  hal_led_blink_ms(LEDS_MASK, LED_BLINK_INTERVAL_MS, LED_BLINK_CNT_START);
}

int main(void) {
  bsp_board_init(BSP_INIT_LEDS); // leds fro pca10059
  initialize();
  start();

  for (;;) {
    (void)sd_app_evt_wait();
  }
}

If someone could shed some light as to why im getting error 8

thanks in advance

Parents Reply Children
  • Hi.

    Have you read about creating new models for your mesh network?

    melt said:
    Can this model now send messages?

    Do you mean packages or string messages?

    Best regards,

    Andreas

  • Yip strings. I have read how to create models and  go over it almost every day.  Can you please share how these functions are structured for the vendor simple_on_off model.

    static void mesh_init(void)

    and

    static void models_init_cb(void)

    thank you.

  • Hi.

    I'm a bit unsure what your question is, are you looking for the implementation of mesh_init() and models_init_cb() where the simple_on_off model were used?

    The simple_on_off model was used up to Mesh SDK 2.0.0, after this the generic_on_off model is used, which should be used in real applications using the mesh.

    The implementation of mesh_init() and models_init_cb() in Mesh SDK 2.0.0 are for example:

    (examples\enocean_switch example)

    mesh_init() :

    static void mesh_init(void)
    {
        uint8_t dev_uuid[NRF_MESH_UUID_SIZE] = CLIENT_NODE_UUID;
    
        mesh_stack_init_params_t init_params =
        {
            .core.irq_priority       = NRF_MESH_IRQ_PRIORITY_LOWEST,
            .core.lfclksrc           = DEV_BOARD_LF_CLK_CFG,
            .core.p_uuid             = dev_uuid,
            .models.models_init_cb   = models_init_cb,
            .models.config_server_cb = config_server_evt_cb
        };
        ERROR_CHECK(mesh_stack_init(&init_params, &m_device_provisioned));
    
        /* Register event handler to receive NRF_MESH_EVT_FLASH_STABLE. Application functionality will
        be started after this event */
        nrf_mesh_evt_handler_add(&m_mesh_core_event_handler);
    }

    models_init_cb() :

    static void models_init_cb(void)
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Initializing and adding models\n");
    
        /* Model initialization */
        for (uint32_t i = 0; i < LIGHT_SWITCH_CLIENTS; ++i)
        {
            m_clients[i].status_cb = client_status_cb;
            ERROR_CHECK(simple_on_off_client_init(&m_clients[i], i + 1));
            ERROR_CHECK(access_model_subscription_list_alloc(m_clients[i].model_handle));
        }
    }

    The implementation of mesh_init() and models_init_cb() in Mesh SDK 3.1.0 are for example:

    (examples\enocean_switch example)

    mesh_init() :

    static void mesh_init(void)
    {
        mesh_stack_init_params_t init_params =
        {
            .core.irq_priority       = NRF_MESH_IRQ_PRIORITY_LOWEST,
            .core.lfclksrc           = DEV_BOARD_LF_CLK_CFG,
            .core.p_uuid             = NULL,
            .models.models_init_cb   = models_init_cb,
            .models.config_server_cb = config_server_evt_cb
        };
        ERROR_CHECK(mesh_stack_init(&init_params, &m_device_provisioned));
    
        /* Register event handler to receive NRF_MESH_EVT_FLASH_STABLE. Application functionality will
        be started after this event */
        nrf_mesh_evt_handler_add(&m_mesh_core_event_handler);
    }

    models_init_cb() :

    static void models_init_cb(void)
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Initializing and adding models\n");
    
        /* Model initialization */
        for (uint32_t i = 0; i < LIGHT_SWITCH_CLIENTS; ++i)
        {
            m_clients[i].settings.p_callbacks = &client_cbs;
            m_clients[i].settings.timeout = 0;
            m_clients[i].settings.force_segmented = APP_CONFIG_FORCE_SEGMENTATION;
            m_clients[i].settings.transmic_size = APP_CONFIG_MIC_SIZE;
    
            ERROR_CHECK(generic_onoff_client_init(&m_clients[i], i + 1));
        }
    }
    

    Is this what you are looking for?

    Best regards,

    Andreas

  • Thanks Andreas, these are for the Generic model. Im looking for a sample of the functions or sample main.c for simple_on_off model in the vendor directory

    They don't work together

  • Hi.

    The first models_init_cb() has an initialization call inside it for the simple_on_off model, if you look closly.

    Are you looking for the source file for this implementation? You can find it in Mesh SDK 2.0.0 under models\simple_on_off\src\simple_on_off_client.c

    Here it is:

    /* Copyright (c) 2010 - 2018, Nordic Semiconductor ASA
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice, this
     * list of conditions and the following disclaimer.
     *
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     *
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     *
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     *
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     *
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    #include "simple_on_off_client.h"
    #include "simple_on_off_common.h"
    
    #include <stdint.h>
    #include <stddef.h>
    
    #include "access.h"
    #include "access_config.h"
    #include "access_reliable.h"
    #include "device_state_manager.h"
    #include "nrf_mesh.h"
    #include "nrf_mesh_assert.h"
    #include "log.h"
    
    /*****************************************************************************
     * Static variables
     *****************************************************************************/
    
    /** Keeps a single global TID for all transfers. */
    static uint8_t m_tid;
    
    /*****************************************************************************
     * Static functions
     *****************************************************************************/
    
    static void reliable_status_cb(access_model_handle_t model_handle,
                                   void * p_args,
                                   access_reliable_status_t status)
    {
        simple_on_off_client_t * p_client = p_args;
        NRF_MESH_ASSERT(p_client->status_cb != NULL);
    
        p_client->state.reliable_transfer_active = false;
        switch (status)
        {
            case ACCESS_RELIABLE_TRANSFER_SUCCESS:
                /* Ignore */
                break;
            case ACCESS_RELIABLE_TRANSFER_TIMEOUT:
                p_client->status_cb(p_client, SIMPLE_ON_OFF_STATUS_ERROR_NO_REPLY, NRF_MESH_ADDR_UNASSIGNED);
                break;
            case ACCESS_RELIABLE_TRANSFER_CANCELLED:
                p_client->status_cb(p_client, SIMPLE_ON_OFF_STATUS_CANCELLED, NRF_MESH_ADDR_UNASSIGNED);
                break;
            default:
                /* Should not be possible. */
                NRF_MESH_ASSERT(false);
                break;
        }
    }
    
    /** Returns @c true if the message received was from the address corresponding to the clients
     * publish address. */
    static bool is_valid_source(const simple_on_off_client_t * p_client,
                                const access_message_rx_t * p_message)
    {
        /* Check the originator of the status. */
        dsm_handle_t publish_handle;
        nrf_mesh_address_t publish_address;
        if (access_model_publish_address_get(p_client->model_handle, &publish_handle) != NRF_SUCCESS ||
            publish_handle == DSM_HANDLE_INVALID ||
            dsm_address_get(publish_handle, &publish_address) != NRF_SUCCESS ||
            publish_address.value != p_message->meta_data.src.value)
        {
            return false;
        }
        else
        {
            return true;
        }
    }
    
    static uint32_t send_reliable_message(const simple_on_off_client_t * p_client,
                                          simple_on_off_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 = SIMPLE_ON_OFF_COMPANY_ID;
        reliable.message.force_segmented = false;
        reliable.message.transmic_size = NRF_MESH_TRANSMIC_SIZE_DEFAULT;
        reliable.reply_opcode.opcode = SIMPLE_ON_OFF_OPCODE_STATUS;
        reliable.reply_opcode.company_id = SIMPLE_ON_OFF_COMPANY_ID;
        reliable.timeout = ACCESS_RELIABLE_TIMEOUT_MIN;
        reliable.status_cb = reliable_status_cb;
    
        return access_model_reliable_publish(&reliable);
    }
    
    /*****************************************************************************
     * Opcode handler callback(s)
     *****************************************************************************/
    
    static void handle_status_cb(access_model_handle_t handle, const access_message_rx_t * p_message, void * p_args)
    {
        simple_on_off_client_t * p_client = p_args;
        NRF_MESH_ASSERT(p_client->status_cb != NULL);
    
        if (!is_valid_source(p_client, p_message))
        {
            return;
        }
    
        simple_on_off_msg_status_t * p_status =
            (simple_on_off_msg_status_t *) p_message->p_data;
        simple_on_off_status_t on_off_status = (p_status->present_on_off ?
                                                  SIMPLE_ON_OFF_STATUS_ON : SIMPLE_ON_OFF_STATUS_OFF);
        p_client->status_cb(p_client, on_off_status, p_message->meta_data.src.value);
    }
    
    static const access_opcode_handler_t m_opcode_handlers[] =
    {
        {{SIMPLE_ON_OFF_OPCODE_STATUS, SIMPLE_ON_OFF_COMPANY_ID}, handle_status_cb}
    };
    
    static void handle_publish_timeout(access_model_handle_t handle, void * p_args)
    {
        simple_on_off_client_t * p_client = p_args;
    
        if (p_client->timeout_cb != NULL)
        {
            p_client->timeout_cb(handle, p_args);
        }
    }
    /*****************************************************************************
     * Public API
     *****************************************************************************/
    
    uint32_t simple_on_off_client_init(simple_on_off_client_t * p_client, uint16_t element_index)
    {
        if (p_client == NULL ||
            p_client->status_cb == NULL)
        {
            return NRF_ERROR_NULL;
        }
    
        access_model_add_params_t init_params;
        init_params.model_id.model_id = SIMPLE_ON_OFF_CLIENT_MODEL_ID;
        init_params.model_id.company_id = SIMPLE_ON_OFF_COMPANY_ID;
        init_params.element_index = element_index;
        init_params.p_opcode_handlers = &m_opcode_handlers[0];
        init_params.opcode_count = sizeof(m_opcode_handlers) / sizeof(m_opcode_handlers[0]);
        init_params.p_args = p_client;
        init_params.publish_timeout_cb = handle_publish_timeout;
        return access_model_add(&init_params, &p_client->model_handle);
    }
    
    uint32_t simple_on_off_client_set(simple_on_off_client_t * p_client, bool on_off)
    {
        if (p_client == NULL || p_client->status_cb == NULL)
        {
            return NRF_ERROR_NULL;
        }
        else if (p_client->state.reliable_transfer_active)
        {
            return NRF_ERROR_INVALID_STATE;
        }
    
        p_client->state.data.on_off = on_off ? 1 : 0;
        p_client->state.data.tid = m_tid++;
    
        uint32_t status = send_reliable_message(p_client,
                                                SIMPLE_ON_OFF_OPCODE_SET,
                                                (const uint8_t *)&p_client->state.data,
                                                sizeof(simple_on_off_msg_set_t));
        if (status == NRF_SUCCESS)
        {
            p_client->state.reliable_transfer_active = true;
        }
        return status;
    
    }
    
    uint32_t simple_on_off_client_set_unreliable(simple_on_off_client_t * p_client, bool on_off, uint8_t repeats)
    {
        simple_on_off_msg_set_unreliable_t set_unreliable;
        set_unreliable.on_off = on_off ? 1 : 0;
        set_unreliable.tid = m_tid++;
    
        access_message_tx_t message;
        message.opcode.opcode = SIMPLE_ON_OFF_OPCODE_SET_UNRELIABLE;
        message.opcode.company_id = SIMPLE_ON_OFF_COMPANY_ID;
        message.p_buffer = (const uint8_t*) &set_unreliable;
        message.length = sizeof(set_unreliable);
        message.force_segmented = false;
        message.transmic_size = NRF_MESH_TRANSMIC_SIZE_DEFAULT;
    
        uint32_t status = NRF_SUCCESS;
        for (uint8_t i = 0; i < repeats; ++i)
        {
            status = access_model_publish(p_client->model_handle, &message);
            if (status != NRF_SUCCESS)
            {
                break;
            }
        }
        return status;
    }
    
    uint32_t simple_on_off_client_get(simple_on_off_client_t * p_client)
    {
        if (p_client == NULL || p_client->status_cb == NULL)
        {
            return NRF_ERROR_NULL;
        }
        else if (p_client->state.reliable_transfer_active)
        {
            return NRF_ERROR_INVALID_STATE;
        }
    
        uint32_t status = send_reliable_message(p_client,
                                                SIMPLE_ON_OFF_OPCODE_GET,
                                                NULL,
                                                0);
        if (status == NRF_SUCCESS)
        {
            p_client->state.reliable_transfer_active = true;
        }
        return status;
    }
    
    /**
     * Cancel any ongoing reliable message transfer.
     *
     * @param[in] p_client Pointer to the client instance structure.
     */
    void simple_on_off_client_pending_msg_cancel(simple_on_off_client_t * p_client)
    {
        (void)access_model_reliable_cancel(p_client->model_handle);
    }
    

    Best regards,

    Andreas

Related