Combine sensor example with light_lightness example

Hi, I am using nrf52840 and Mesh V4.2.0 sensor and light_lightness examples.

I have been able to successfully combine the server side, but I have no idea how to start combining the client part. Is there anyone who has an idea?

Thank you.

Parents Reply Children
  • Hi,

    So I am stuck on trying to publish motion status from my server to client. Please let me know if any of my steps are wrong, thank you. 

    For my server side:

    In main.c, I added:

    /* Application variable for holding instantaneous lightness value */
    static uint16_t m_pwm0_present_actual_lightness;
    static uint8_t present_motion;
    .
    .
    /* Callback for reading the hardware state */
    static void get_lightness_cb(const app_light_lightness_setup_server_t * p_app, uint16_t * p_lightness, uint8_t * p_present_motion)
    {
        *p_lightness = (m_pwm0_present_actual_lightness);
        *p_present_motion = (present_motion);
    }
    .
    .
    static void button_event_handler(uint32_t button_number)
    {
        /* Increase button number because the buttons on the board is marked with 1 to 4 */
        button_number++;
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Button %u pressed\n", button_number);
        switch (button_number)
        {
            /* Sending value `1` or `2` via RTT will result in LED state to change and trigger
            the STATUS message to inform client about the state change. This is a demonstration of
            state change publication due to local event. */
            case 1:
            {
                m_pwm0_present_actual_lightness = MAX(0, (int32_t)m_pwm0_present_actual_lightness - APP_LIGHTNESS_STEP_SIZE);
                present_motion = (present_motion > 10)
                                      ? present_motion - 10
                                      : 0;
                break;
            }
    
            case 2:
            {
                m_pwm0_present_actual_lightness = MIN(UINT16_MAX,
                                                      (int32_t)m_pwm0_present_actual_lightness + APP_LIGHTNESS_STEP_SIZE);
                present_motion = (present_motion < 90)
                                      ? present_motion + 10
                                      : 100;
                break;
            }
    
            /* Initiate node reset */
            case 4:
            {
                /* Clear all the states to reset the node. */
                if (mesh_stack_is_device_provisioned())
                {
    #if MESH_FEATURE_GATT_PROXY_ENABLED
                    (void) proxy_stop();
    #endif
                    mesh_stack_config_clear();
                    node_reset();
                }
                else
                {
                    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "The device is unprovisioned. Resetting has no effect.\n");
                }
                break;
            }
    
            default:
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, m_usage_string);
                break;
        }
    
        if (button_number == 1 || button_number == 2)
        {
            pwm_utils_level_set(&m_pwm, light_lightness_utils_actual_to_generic_level(m_pwm0_present_actual_lightness));
            uint32_t status = app_light_lightness_current_value_publish(&m_light_lightness_server_0);
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "lightness: %d, motion: %d\n", m_pwm0_present_actual_lightness, present_motion);
            if ( status != NRF_SUCCESS)
            {
                __LOG(LOG_SRC_APP, LOG_LEVEL_WARN, "Unable to publish status message, status: %d\n", status);
            }
        }
    }
    

    In app_light_lightness.c, my app_light_lightness_current_value_publish:

    uint32_t app_light_lightness_current_value_publish(app_light_lightness_setup_server_t * p_app)
    {
        if (p_app == NULL)
        {
            return NRF_ERROR_NULL;
        }
    
        app_transition_abort(&p_app->state.transition);
        p_app->app_light_lightness_get_cb(p_app, &p_app->state.present_lightness, &p_app->state.present_motion);
    
        if (p_app->state.present_lightness >= LIGHT_LIGHTNESS_LAST_MIN)
        {
            ERROR_CHECK(light_lightness_mc_last_state_set(p_app->light_lightness_setup_server.state.handle,
                                                          p_app->state.present_lightness,
                                                          LIGHT_LIGHTNESS_MC_WRITE_DESTINATION_ALL));
        }
        ERROR_CHECK(light_lightness_mc_actual_state_set(p_app->light_lightness_setup_server.state.handle,
                                                        p_app->state.present_lightness));
    
        /* Notify anyone interested that we just got a command to set the lightness */
        if (p_app->app_add_notify.app_notify_set_cb != NULL)
        {
            p_app->app_add_notify.app_notify_set_cb(p_app->app_add_notify.p_app_notify_v, p_app->state.present_lightness);
        }
    
        return publish_lightness(p_app, 0);
    }

    In app_light_lightness.c, my publish_lightness:

    static uint32_t publish_lightness(app_light_lightness_setup_server_t * p_app, uint32_t remaining_time_ms)
    {
        light_lightness_status_params_t publication_data;
        light_lightness_server_t * p_light_lightness_srv;
    
        publication_data.present_lightness = p_app->state.present_lightness;
        publication_data.target_lightness  = p_app->state.target_lightness;
        publication_data.remaining_time_ms = remaining_time_ms;
        publication_data.present_motion = p_app->state.present_motion;
    
        /* Notify anyone interested that we are publishing lightness */
        if (p_app->app_add_notify.app_add_publish_cb != NULL)
        {
            p_app->app_add_notify.app_add_publish_cb(p_app->app_add_notify.p_app_publish_v, &publication_data);
        }
    
        p_light_lightness_srv = &p_app->light_lightness_setup_server.light_lightness_srv;
        return light_lightness_server_status_publish((const light_lightness_server_t * )p_light_lightness_srv,
                                                     (const light_lightness_status_params_t *)&publication_data);
    }

    In light_lightness_setup_server.c, my light_lightness_server_status_publish:

    uint32_t light_lightness_server_status_publish(const light_lightness_server_t * p_server,
                                                   const light_lightness_status_params_t * p_params)
    {
        if (p_server == NULL ||
            p_params == NULL)
        {
            return NRF_ERROR_NULL;
        }
    
        publish_bound_actual_states(p_server, p_params);
    
        return status_actual_send(p_server, NULL, p_params);
        return status_ll_send(p_server, NULL, p_params);
    }

    In light_lightness_setup_server.c, my status_ll_send:

    static uint32_t status_ll_send(const light_lightness_server_t * p_server,
                                       const access_message_rx_t * p_message,
                                       const light_lightness_status_params_t * p_params)
    {
        light_lightness_status_msg_pkt_t msg_pkt;
        msg_pkt.present_motion = p_params->present_motion;
        
        if (p_params->present_motion > LL_ONOFF_MAX)
        {
            return NRF_ERROR_INVALID_PARAM;
        }
    
        access_message_tx_t reply =
        {
            .opcode = ACCESS_OPCODE_SIG(LL_OPCODE_STATUS),
            .p_buffer = (const uint8_t *) &msg_pkt,
            .length = p_params->remaining_time_ms > 0 ? LIGHT_LIGHTNESS_STATUS_MAXLEN : LIGHT_LIGHTNESS_STATUS_MINLEN,
            .force_segmented = p_server->settings.force_segmented,
            .transmic_size = p_server->settings.transmic_size
        };
    
        if (p_message == NULL)
        {
            return access_model_publish(p_server->model_handle, &reply);
        }
        else
        {
            return access_model_reply(p_server->model_handle, p_message, &reply);
        }
    }

    To handle the opcode, I've also added handle_ll_get:

    static void handle_ll_get(access_model_handle_t model_handle,
                           const access_message_rx_t * p_rx_msg,
                           void * p_args)
    {
        light_lightness_server_t * p_server = (light_lightness_server_t *) p_args;
        light_lightness_setup_server_t * p_s_server = PARENT_BY_FIELD_GET(light_lightness_setup_server_t, light_lightness_srv, p_args);
        light_lightness_status_params_t out_data = {0};
    
        if (p_rx_msg->length == 0)
        {
            p_s_server->settings.p_callbacks->light_lightness_cbs.get_cb(p_s_server, &p_rx_msg->meta_data, &out_data);
            (void) status_ll_send(p_server, p_rx_msg, &out_data);
        }
    }

    Under the m_opcode_handlers:

    static const access_opcode_handler_t m_opcode_handlers[] =
    {
        {ACCESS_OPCODE_SIG(LIGHT_LIGHTNESS_OPCODE_GET), handle_get},
        {ACCESS_OPCODE_SIG(LL_OPCODE_GET), handle_ll_get},
    }

    For my client side, my main.c I've added:

    /* Light lightness client model interface: Process the received status message in this callback */
    static void app_light_lightness_client_status_cb(const light_lightness_client_t *p_self,
                                                     const access_message_rx_meta_t *p_meta,
                                                     const light_lightness_status_params_t *p_in)
    {
        if (p_in->remaining_time_ms > 0)
        {
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Lightness client: 0x%04x, Present Lightness: %d, Target Lightness: %d, Remaining Time: %d ms\n",
                  p_meta->src.value, p_in->present_lightness, p_in->target_lightness, p_in->remaining_time_ms);
        }
        else
        {
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Lightness client: 0x%04x, Present lightness: %d, Present motion: %d\n",
                  p_meta->src.value, p_in->present_lightness, p_in->present_motion);
        }
    }

    In light_lightness_client.c, to handle the opcode:

    static void status_ll_handle(access_model_handle_t handle, const access_message_rx_t * p_rx_msg, void * p_args)
    {
        light_lightness_client_t * p_client = (light_lightness_client_t *) p_args;
        light_lightness_status_params_t in_data = {0};
    
        if (p_rx_msg->length == LL_STATUS_MINLEN || p_rx_msg->length == LL_STATUS_MAXLEN)
        {
            light_lightness_status_msg_pkt_t * p_msg_params_packed = (light_lightness_status_msg_pkt_t *) p_rx_msg->p_data;
    
            if (p_rx_msg->length == LL_STATUS_MINLEN)
            {
                in_data.present_motion = p_msg_params_packed->present_motion;
            }
            else
            {
                in_data.present_motion = p_msg_params_packed->present_motion;
            }
    
            p_client->settings.p_callbacks->lightness_status_cb(p_client, &p_rx_msg->meta_data, &in_data);
        }
    }
    .
    .
    static const access_opcode_handler_t m_opcode_handlers[] =
    {
        {ACCESS_OPCODE_SIG(LIGHT_LIGHTNESS_OPCODE_STATUS), status_handle},
        {ACCESS_OPCODE_SIG(LL_OPCODE_STATUS), status_ll_handle},
    }
    .
    .
    uint32_t ll_client_get(light_lightness_client_t * p_client)
    {
        if (p_client == NULL)
        {
            return NRF_ERROR_NULL;
        }
    
        if (access_reliable_model_is_free(p_client->model_handle))
        {
            message_create(p_client, LL_OPCODE_GET, NULL, 0, &p_client->access_message.message);
            reliable_context_create(p_client, LL_OPCODE_STATUS, &p_client->access_message);
    
            return access_model_reliable_publish(&p_client->access_message);
        }
        else
        {
            return NRF_ERROR_BUSY;
        }
    }

    Sorry if this is a lot of codes, but I hope you are able to study what I'm trying to do and help me with them. Thank you in advance.

  • Thanks.

    I'll take a look at your code and get back to you.

    Br,
    Joakim

Related