Message communication with application using "generic_onoff_server.c

Thank you for your assistance.
I am currently implementing a function for message communication between an application and a board using nrf52840.
Specifically, I have previously implemented a function to send 3 numbers (uint16_t) to control the LED color (rgb) using "generic_onoff_server.c". I am wondering if it is possible to implement this function by adding one variable for the node number of the base. The first is "main.c", or the main source file, the second is "app_onoff.h", the third is "app_onoff.c", and the fourth is "generic_onoff_server.c The fifth is "generic_onoff_message.h" and the sixth is a part of "generic_onoff_common.h". The sixth one is a part of "generic_onoff_common.h". As shown in the following program, we added one more onoff value and rewrote the program. I wrote these programs to the foundation and demonstrated communication with the application, but I can no longer communicate the numbers as before. Incidentally, the three color numbers previously implemented are also unable to communicate.
To be honest, I don't really understand how the programs (variables and functions in the source and header files) work together. Therefore, it is possible that this is due to a very elementary mistake.
Could you please give us some pointers regarding the cause of this problem? Thank you in advance for your consideration.

static void app_onoff_server_set_cb(const app_onoff_server_t * p_server, uint16_t color_num, uint16_t color_num2, uint16_t color_num3,uint16_t node_number1);
static void app_onoff_server_get_cb(const app_onoff_server_t * p_server, uint16_t * p_present_onoff);
static void app_onoff_server_transition_cb(const app_onoff_server_t * p_server,
                                                uint32_t transition_time_ms, bool target_onoff);

/*****************************************************************************
 * Forward declaration of static functions
 *****************************************************************************/


/*****************************************************************************
 * Static variables
 *****************************************************************************/
static bool m_device_provisioned;

/* Generic OnOff server structure definition and initialization */
APP_ONOFF_SERVER_DEF(m_onoff_server_0,
                     APP_FORCE_SEGMENTATION,
                     APP_MIC_SIZE,
                     app_onoff_server_set_cb,
                     app_onoff_server_get_cb,
                     app_onoff_server_transition_cb)


static void app_onoff_server_set_cb(const app_onoff_server_t * p_server, uint16_t color_num, uint16_t color_num2, uint16_t color_num3, uint16_t node_number)
{
    /* Resolve the server instance here if required, this example uses only 1 instance. */

    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "color_num: %d\n", color_num)
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "color_num2: %d\n", color_num2)
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "color_num3: %d\n", color_num3)
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "node_number: %d\n", node_number1)
    

    int new_color_num;
    
    if (node_number == 1)
    {
        new_color_num = (color_num % 10);
    }
    else if (node_number == 2)
    {
        new_color_num = (color_num % 100);
        new_color_num = (new_color_num / 10);
    }
    else if (node_number == 3)
    {
        new_color_num = (color_num % 1000);
        new_color_num = (new_color_num / 100);
    }
    else if (node_number == 4)
    {
        new_color_num = (color_num / 1000);
    }
    else if (node_number == 5)
    {
        new_color_num = (color_num2 % 10);
    }
    else if (node_number == 6)
    {
        new_color_num = (color_num2 % 100);
        new_color_num = (new_color_num / 10);
    }
    else if (node_number == 7)
    {
        new_color_num = (color_num2 % 1000);
        new_color_num = (new_color_num / 100);
    }
    else if (node_number == 8)
    {
        new_color_num = (color_num2 / 1000);
    }
    else if (node_number == 9)
    {
        new_color_num = (color_num3 % 10);
    }
    else if (node_number == 10)
    {
        new_color_num = (color_num3 % 100);
        new_color_num = (new_color_num / 10);
    }
    else if (node_number == 11)
    {
        new_color_num = (color_num3 % 1000);
        new_color_num = (new_color_num / 100);
    }
    else if (node_number == 12)
    {
        new_color_num = (color_num3 / 1000);
    }
    else 
    {
        
    }

    switch(new_color_num)
    {
    case 0:
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Power on \n")
        hal_led_pin_set(ONOFF_SERVER_R_LED, 1);
        hal_led_pin_set(ONOFF_SERVER_G_LED, 1);
        hal_led_pin_set(ONOFF_SERVER_B_LED, 1);
        hal_led_pin_set(POWER, 0);
        break;
    }
    case 1:
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Power on \n")
        hal_led_pin_set(ONOFF_SERVER_R_LED, 1);
        hal_led_pin_set(ONOFF_SERVER_G_LED, 1);
        hal_led_pin_set(ONOFF_SERVER_B_LED, 1);
        hal_led_pin_set(POWER, 1);
        break;
    }
    case 2:
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Red LED \n")
        hal_led_pin_set(ONOFF_SERVER_R_LED, 0);
        hal_led_pin_set(ONOFF_SERVER_G_LED, 1);
        hal_led_pin_set(ONOFF_SERVER_B_LED, 1);
        break;
    }
    case 3:
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Green LED \n")
        hal_led_pin_set(ONOFF_SERVER_R_LED, 1);
        hal_led_pin_set(ONOFF_SERVER_G_LED, 0);
        hal_led_pin_set(ONOFF_SERVER_B_LED, 1);
        break;
    }
    case 4:
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Blue LED \n")
        hal_led_pin_set(ONOFF_SERVER_R_LED, 1);
        hal_led_pin_set(ONOFF_SERVER_G_LED, 1);
        hal_led_pin_set(ONOFF_SERVER_B_LED, 0);
        break;
    }
    default:
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Out of case \n")
        break;
    }

}

/** Internal structure to hold state and timing information. */
typedef struct
{
    /** Present value of the OnOff state */
    uint16_t present_onoff;
    uint16_t present_onoff2;
    uint16_t present_onoff3;
    uint16_t present_onoff4;
    /** Initial value for transition */
    uint16_t initial_present_onoff;
    /** Target value of the OnOff state, as received from the model interface. */
    uint16_t target_onoff;
    // changed 
    uint16_t target_onoff2;
    uint16_t target_onoff3;
    uint16_t target_onoff4;
    /** Structure for using transition module functionality */
    app_transition_t transition;
} app_onoff_state_t;

/* Forward declaration */
typedef struct __app_onoff_server_t app_onoff_server_t;

/** Application state set callback prototype.
 *
 * This callback is called by the this module whenever application is required to
 * be informed to reflect the desired OnOff value, as a result of the received SET message. Depending
 * on the received Target OnOff value and timing parameters, this callback may be triggered after the
 * delay+transition time is over or instantly after the delay if the Target OnOff value is `1`, as
 * required by @tagMeshMdlSp.
 *
 * Note: Since the behavioral module encapsulates functionality required for the compliance with timing
 * behaviour, it is not possible to infer number of Generic OnOff Set messages received by the
 * node by counting the number of times this callback is triggered.
 *
 * @param[in]   p_app           Pointer to [app_onoff_server_t](@ref __app_onoff_server_t) context.
 * @param[in]   onoff           New onoff value to be used by the application
 * @param[in]   onoff2           New onoff value to be used by the application
 * @param[in]   onoff3           New onoff value to be used by the application
 * @param[in]   onoff4           New onoff value to be used by the application

 */
static void generic_onoff_state_set_cb(const generic_onoff_server_t * p_self,
                                       const access_message_rx_meta_t * p_meta,
                                       const generic_onoff_set_params_t * p_in,
                                       const model_transition_t * p_in_transition,
                                       generic_onoff_status_params_t * p_out)
{
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "msg: SET: %d\n", p_in->on_off);
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "msg: SET2: %d\n", p_in->on_off2);
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "msg: SET3: %d\n", p_in->on_off3);
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "msg: SET4: %d\n", p_in->on_off4);

    app_onoff_server_t   * p_app = PARENT_BY_FIELD_GET(app_onoff_server_t, server, p_self);

    bool present_on_off;
    p_app->onoff_get_cb(p_app, &present_on_off);
    /* Update internal representation of OnOff value, process timing */
    p_app->value_updated = false;
    p_app->state.target_onoff = p_in->on_off;
    p_app->state.target_onoff2 = p_in->on_off2;
    p_app->state.target_onoff3 = p_in->on_off3;
    p_app->state.target_onoff4 = p_in->on_off4;

    uint32_t transition_time_ms = 0;
    if (present_on_off != p_in->on_off || present_on_off != p_in->on_off2 || present_on_off != p_in->on_off3 || present_on_off != p_in->on_off4)
    {
        transition_parameters_set(p_app, p_in_transition);
        transition_time_ms = app_transition_requested_get(&p_app->state.transition)->transition_time_ms;
        app_transition_trigger(&p_app->state.transition);
    }

    /* Prepare response */
    if (p_out != NULL)
    {
        p_out->present_on_off = p_app->state.present_onoff;
        p_out->target_on_off = p_app->state.target_onoff;
        p_out->remaining_time_ms = transition_time_ms;
    }
}

static inline app_onoff_server_t * transition_to_app(const app_transition_t * p_transition)
{
    app_onoff_state_t * p_state = PARENT_BY_FIELD_GET(app_onoff_state_t,
                                  transition,
                                  p_transition);
    return PARENT_BY_FIELD_GET(app_onoff_server_t,
                               state,
                               p_state);
}

static void transition_start_cb(const app_transition_t * p_transition)
{
    app_onoff_server_t * p_app = transition_to_app(p_transition);
    app_transition_params_t * p_params = app_transition_ongoing_get(&p_app->state.transition);

    if (p_app->state.initial_present_onoff == 0 && p_app->state.target_onoff == 1)
    {
        p_app->state.present_onoff = p_app->state.target_onoff;
        onoff_current_value_update(p_app);
        generic_onoff_status_params_t status =
        {
            .present_on_off = p_app->state.present_onoff,
            .target_on_off = p_app->state.target_onoff,
        };
        status.remaining_time_ms = app_transition_ongoing_get(&p_app->state.transition)->transition_time_ms;
        (void) generic_onoff_server_status_publish(&p_app->server, &status);
    }
    /* Inform the application that transition have started. */
    if (p_app->onoff_transition_cb != NULL)
    {
        p_app->onoff_transition_cb(p_app, p_params->transition_time_ms, p_app->state.target_onoff);
    }
}

static void transition_complete_cb(const app_transition_t * p_transition)
{
    app_onoff_server_t * p_app = transition_to_app(p_transition);
    app_transition_params_t * p_params = app_transition_ongoing_get(&p_app->state.transition);

    if (p_app->state.present_onoff != p_app->state.target_onoff)
    {
        p_app->state.present_onoff = p_app->state.target_onoff;
        p_app->state.present_onoff2 = p_app->state.target_onoff2;
        p_app->state.present_onoff3 = p_app->state.target_onoff3;
        p_app->state.present_onoff4 = p_app->state.target_onoff4;

        onoff_current_value_update(p_app);

        generic_onoff_status_params_t status = {
                    .present_on_off = p_app->state.present_onoff,
                    .target_on_off = p_app->state.target_onoff,
                    .remaining_time_ms = 0
                };
        (void) generic_onoff_server_status_publish(&p_app->server, &status);
    }

    /* Inform the application that the transition is complete */
    if (p_app->onoff_transition_cb != NULL)
    {
        p_app->onoff_transition_cb(p_app, p_params->transition_time_ms, p_app->state.target_onoff);
    }
}

#include "generic_onoff_server.h"
#include "generic_onoff_common.h"
#include "generic_onoff_messages.h"

#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "access.h"
#include "access_config.h"
#include "nrf_mesh_assert.h"
#include "nrf_mesh_utils.h"
#include "nordic_common.h"

#include "log.h"

static uint32_t status_send(generic_onoff_server_t * p_server,
                            const access_message_rx_t * p_message,
                            const generic_onoff_status_params_t * p_params)
{
    generic_onoff_status_msg_pkt_t msg_pkt;

    if (p_params->present_on_off > GENERIC_ONOFF_MAX ||
        p_params->target_on_off  > GENERIC_ONOFF_MAX ||
        p_params->remaining_time_ms > TRANSITION_TIME_STEP_10M_MAX)
    {
        return NRF_ERROR_INVALID_PARAM;
    }

    msg_pkt.present_on_off = p_params->present_on_off;
    if (p_params->remaining_time_ms > 0)
    {
        msg_pkt.target_on_off = p_params->target_on_off;
        msg_pkt.remaining_time = model_transition_time_encode(p_params->remaining_time_ms);
    }

    access_message_tx_t reply =
    {
        .opcode = ACCESS_OPCODE_SIG(GENERIC_ONOFF_OPCODE_STATUS),
        .p_buffer = (const uint8_t *) &msg_pkt,
        .length = p_params->remaining_time_ms > 0 ? GENERIC_ONOFF_STATUS_MAXLEN : GENERIC_ONOFF_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);
    }
}

static void periodic_publish_cb(access_model_handle_t handle, void * p_args)
{
    generic_onoff_server_t * p_server = (generic_onoff_server_t *)p_args;
    generic_onoff_status_params_t out_data = {0};

    p_server->settings.p_callbacks->onoff_cbs.get_cb(p_server, NULL, &out_data);
    (void) status_send(p_server, NULL, &out_data);
}

/** Opcode Handlers */

static inline bool set_params_validate(const access_message_rx_t * p_rx_msg, const generic_onoff_set_msg_pkt_t * p_params)
{
    return (
            (p_rx_msg->length == GENERIC_ONOFF_SET_MINLEN || p_rx_msg->length == GENERIC_ONOFF_SET_MAXLEN) &&
            (p_params->on_off <= GENERIC_ONOFF_MAX)
           );
}

static void handle_set(access_model_handle_t model_handle, const access_message_rx_t * p_rx_msg, void * p_args)
{
    generic_onoff_server_t * p_server = (generic_onoff_server_t *) p_args;
    generic_onoff_set_params_t in_data = {0};
    model_transition_t in_data_tr = {0};
    generic_onoff_status_params_t out_data = {0};
    generic_onoff_set_msg_pkt_t * p_msg_params_packed = (generic_onoff_set_msg_pkt_t *) p_rx_msg->p_data;

    if (set_params_validate(p_rx_msg, p_msg_params_packed))
    {
        in_data.on_off = p_msg_params_packed->on_off;
        in_data.on_off2 = p_msg_params_packed->on_off2;
        in_data.on_off3 = p_msg_params_packed->on_off3;
        in_data.on_off4 = p_msg_params_packed->on_off4;
        in_data.tid = p_msg_params_packed->tid;
        if (model_tid_validate(&p_server->tid_tracker, &p_rx_msg->meta_data, GENERIC_ONOFF_OPCODE_SET, in_data.tid))
        {
            if (p_rx_msg->length == GENERIC_ONOFF_SET_MAXLEN)
            {
                if (!model_transition_time_is_valid(p_msg_params_packed->transition_time))
                {
                    return;
                }

                in_data_tr.transition_time_ms = model_transition_time_decode(p_msg_params_packed->transition_time);
                in_data_tr.delay_ms = model_delay_decode(p_msg_params_packed->delay);
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Server: transition_time_ms = %X\n", in_data_tr.transition_time_ms);
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Server: delay_ms = %X\n", in_data_tr.delay_ms);
            }

            p_server->settings.p_callbacks->onoff_cbs.set_cb(p_server,
                                                            &p_rx_msg->meta_data,
                                                            &in_data,
                                                            (p_rx_msg->length == GENERIC_ONOFF_SET_MINLEN) ? NULL : &in_data_tr,
                                                            (p_rx_msg->opcode.opcode == GENERIC_ONOFF_OPCODE_SET) ? &out_data : NULL);

            if (p_rx_msg->opcode.opcode == GENERIC_ONOFF_OPCODE_SET)
            {
                (void) status_send(p_server, p_rx_msg, &out_data);
            }
        }
    }
}
#ifndef GENERIC_ONOFF_MESSAGES_H__
#define GENERIC_ONOFF_MESSAGES_H__

#include <stdint.h>

/**
 * @internal
 * @defgroup GENERIC_ONOFF_MESSAGES Internal header
 * @ingroup GENERIC_ONOFF_MODEL
 * This internal header contains packed structures required for message parsing.
 * @{
 */

/** Shortest allowed length for the Set message. */
#define GENERIC_ONOFF_SET_MINLEN 7
/** Longest allowed length for the Set message. */
#define GENERIC_ONOFF_SET_MAXLEN 9

/** Shortest allowed length for the Status message. */
#define GENERIC_ONOFF_STATUS_MINLEN 2
/** Longest allowed length for the Status message. */
#define GENERIC_ONOFF_STATUS_MAXLEN 5

/** Generic On Off model message opcodes. */
typedef enum
{
    GENERIC_ONOFF_OPCODE_SET = 0x8202,
    GENERIC_ONOFF_OPCODE_SET_UNACKNOWLEDGED = 0x8203,
    GENERIC_ONOFF_OPCODE_GET = 0x8201,
    GENERIC_ONOFF_OPCODE_STATUS = 0x8204
} generic_onoff_opcode_t;

/** Packed message structure typedefs are used for packing and unpacking byte stream. */

/** Message format for the generic_onoff Set message. */
typedef struct __attribute((packed))
{
    uint16_t on_off;                                         /**< State to set */
    uint16_t on_off2;
    uint16_t on_off3;
    uint16_t on_off4;
    uint8_t tid;                                            /**< Transaction number for application */
    uint8_t transition_time;                                /**< Encoded transition time value */
    uint8_t delay;                                          /**< Encoded message execution delay in 5 millisecond steps */
} generic_onoff_set_msg_pkt_t;

/** Message format for the generic_onoff Status message. */
typedef struct __attribute((packed))
{
    uint16_t present_on_off;                                 /**< The present value of the Generic OnOff state */
    uint16_t target_on_off;                                  /**< The target value of the Generic OnOff state (optional) */
    uint8_t remaining_time;                                 /**< Encoded remaining time */
} generic_onoff_status_msg_pkt_t;

/**@} end of GENERIC_ONOFF_MODEL_INTENRAL */
#endif /* GENERIC_ONOFF_MESSAGES_H__ */

#ifndef GENERIC_ONOFF_COMMON_H__
#define GENERIC_ONOFF_COMMON_H__

#include <stdint.h>
#include "model_common.h"

/**
 * @defgroup GENERIC_ONOFF_MODEL Generic OnOff model
 * @ingroup MESH_API_GROUP_GENERIC_MODELS
 * This model implements the message based interface required to set the OnOff value on the server.
 * Server model itself is a stateless model. The state information resides in the user application.
 * This interface API takes care of validating the packet formats and field values.
 * These APIs should be used in combination with necessary behavioral implementation to create
 * a qualifiable model implementation.
 * @{
 */

/** Model Company ID */
#define GENERIC_ONOFF_COMPANY_ID 0xFFFF

/** Maximum value of the onoff state, as defined in @tagMeshMdlSp */
// #define GENERIC_ONOFF_MAX        (0x09)
#define GENERIC_ONOFF_MAX        (0x2710)

/**
 * Unpacked message structure typedefs are used for API interfaces and for implementing model code. This helps to minimize code
 * footprint.
 */

/** Structure containing value of the OnOff state */
typedef struct
{
    uint16_t on_off;                                            /**< State to set */
    uint16_t on_off2; 
    uint16_t on_off3; 
    uint16_t on_off4;
    uint8_t tid;                                            /**< Transaction ID */
} generic_onoff_state_t;

/** Mandatory parameters for the Generic OnOff Set message. */
typedef struct
{
    uint16_t on_off;
    uint16_t on_off2;                                            /**< State to set */
    uint16_t on_off3;  
    uint16_t on_off4;                                          /**< State to set */
    uint8_t tid;                                            /**< Transaction ID */
} generic_onoff_set_params_t;

/** Parameters for the Generic OnOff Status message. */
typedef struct
{
    uint16_t present_on_off;
    uint16_t present_on_off2;                                  /**< The present value of the Generic OnOff state */
    uint16_t present_on_off3;                                  /**< The present value of the Generic OnOff state */
    uint16_t present_on_off4;
    uint16_t target_on_off;
    // changed 
    uint16_t target_on_off2;                                  /**< The target value of the Generic OnOff state (optional) */
    uint16_t target_on_off3;                                  /**< The target value of the Generic OnOff state (optional) */
    uint16_t target_on_off4;
    uint32_t remaining_time_ms;                             /**< Remaining time value in milliseconds */
} generic_onoff_status_params_t;

/**@} end of GENERIC_ONOFF_MODEL */
#endif /* GENERIC_ONOFF_COMMON_H__ */

  • Hi

    I'm not sure I understand what you want to do, or what exactly the problem you're having is. I assume it is "node_number1" that you want to make show what node sent every message. In order to print something like this you need to make sure that each node actually transmit their name/information to the client device. Where exactly are you running into trouble?

    Best regards,

    Simon

Related