Date: Fri, 8 Feb 2019 13:20:11 +0100
Subject: [PATCH] MBTLE-0000: Demonstrate thread mode. Demonstrate delayed
 reply.

---
 examples/common/include/app_onoff.h           | 16 ++++++
 examples/common/src/app_onoff.c               | 21 +++++++
 examples/light_switch/server/CMakeLists.txt   |  2 +
 .../light_switch/server/include/app_config.h  |  4 ++
 examples/light_switch/server/src/main.c       | 57 ++++++++++++++++++-
 .../include/generic_onoff_server.h            | 18 ++++++
 .../generic_onoff/src/generic_onoff_server.c  | 17 ++++++
 7 files changed, 132 insertions(+), 3 deletions(-)

diff --git a/examples/common/include/app_onoff.h b/examples/common/include/app_onoff.h
index b5650f6c9..b5feac6b1 100644
--- a/examples/common/include/app_onoff.h
+++ b/examples/common/include/app_onoff.h
@@ -174,6 +174,20 @@ struct __app_onoff_server_t
  */
 void app_onoff_status_publish(app_onoff_server_t * p_server);
 
+/** Sends another but delayed status message in response to the previously received message from the
+ * certain source.
+ *
+ * The appkey_handle, subnet_handle, and dst address are obtained from the previously received
+ * access message meta data.
+ *
+ * Call to this function initiates value fetch from the user application by calling a get callback,
+ * updates internal state, and publishes the Generic OnOff Status message, if non-zero src address is
+ * available in the previously received metadata.
+ *
+ * @param[in] p_server              Pointer to @ref __app_onoff_server_t [app_onoff_server_t] context
+ */
+void app_onoff_delayed_status_reply(app_onoff_server_t * p_server);
+
 /** Initializes the behavioral module for the generic OnOff model
  *
  * @param[in] p_server               Pointer to the application OnOff server struture array.
@@ -188,5 +202,7 @@ void app_onoff_status_publish(app_onoff_server_t * p_server);
 */
 uint32_t app_onoff_init(app_onoff_server_t * p_server, uint8_t element_index);
 
+
+
 /** @} end of APP_ONOFF */
 #endif /* APP_ONOFF_H__ */
diff --git a/examples/common/src/app_onoff.c b/examples/common/src/app_onoff.c
index 50e094759..d36e413d9 100644
--- a/examples/common/src/app_onoff.c
+++ b/examples/common/src/app_onoff.c
@@ -251,6 +251,27 @@ void app_onoff_status_publish(app_onoff_server_t * p_server)
     (void) generic_onoff_server_status_publish(&p_server->server, &status);
 }
 
+void app_onoff_delayed_status_reply(app_onoff_server_t * p_server)
+{
+    if (p_server->server.last_access_meta.src.value == NRF_MESH_ADDR_UNASSIGNED)
+    {
+        return;
+    }
+
+    p_server->onoff_get_cb(p_server, &p_server->state.present_onoff);
+
+    p_server->state.target_onoff = p_server->state.present_onoff;
+    p_server->state.delay_ms = 0;
+    p_server->state.remaining_time_ms = 0;
+
+    generic_onoff_status_params_t status = {
+                .present_on_off = p_server->state.present_onoff,
+                .target_on_off = p_server->state.target_onoff,
+                .remaining_time_ms = p_server->state.remaining_time_ms
+            };
+    (void) generic_onoff_server_delayed_status_send(&p_server->server, &status);
+}
+
 uint32_t app_onoff_init(app_onoff_server_t * p_server, uint8_t element_index)
 {
     uint32_t status = NRF_ERROR_INTERNAL;
diff --git a/examples/light_switch/server/CMakeLists.txt b/examples/light_switch/server/CMakeLists.txt
index a05254243..1e858dde6 100644
--- a/examples/light_switch/server/CMakeLists.txt
+++ b/examples/light_switch/server/CMakeLists.txt
@@ -8,6 +8,7 @@ add_executable(${target}
     "${MBTLE_SOURCE_DIR}/examples/common/src/rtt_input.c"
     "${CMAKE_SOURCE_DIR}/examples/common/src/simple_hal.c"
     "${CMAKE_SOURCE_DIR}/examples/common/src/mesh_app_utils.c"
+    "${SDK_ROOT}/components/libraries/scheduler/app_scheduler.c"
     ${BLE_SOFTDEVICE_SUPPORT_SOURCE_FILES}
     ${WEAK_SOURCE_FILES}
     ${MESH_CORE_SOURCE_FILES}
@@ -30,6 +31,7 @@ target_include_directories(${target} PUBLIC
     "${CMAKE_CURRENT_SOURCE_DIR}/../include"
     "${CMAKE_SOURCE_DIR}/examples/common/include"
     "${CMAKE_SOURCE_DIR}/external/rtt/include"
+    "${SDK_ROOT}/components/libraries/scheduler"
     ${BLE_SOFTDEVICE_SUPPORT_INCLUDE_DIRS}
     ${CONFIG_SERVER_INCLUDE_DIRS}
     ${HEALTH_SERVER_INCLUDE_DIRS}
diff --git a/examples/light_switch/server/include/app_config.h b/examples/light_switch/server/include/app_config.h
index bea884968..867738ceb 100644
--- a/examples/light_switch/server/include/app_config.h
+++ b/examples/light_switch/server/include/app_config.h
@@ -77,6 +77,10 @@
 #define APP_TIMER_ENABLED 1
 #define APP_TIMER_KEEPS_RTC_ACTIVE 1
 
+#define APP_SCHEDULER_ENABLED 1
+#define NRF_SDH_DISPATCH_MODEL 1
+#define APP_TIMER_CONFIG_USE_SCHEDULER 1
+
 /** @} end of APP_SDK_CONFIG */
 
 #endif /* APP_CONFIG_H__ */
diff --git a/examples/light_switch/server/src/main.c b/examples/light_switch/server/src/main.c
index 5ccdf76fd..c1651b12b 100644
--- a/examples/light_switch/server/src/main.c
+++ b/examples/light_switch/server/src/main.c
@@ -71,10 +71,21 @@
 #include "light_switch_example_common.h"
 #include "app_onoff.h"
 #include "ble_softdevice_support.h"
+#include "app_scheduler.h"
 
 #define ONOFF_SERVER_0_LED          (BSP_LED_0)
 #define APP_ONOFF_ELEMENT_INDEX     (0)
 
+/* Select max event size. This must be large enough for app timer events as well.
+ * uint8_t => button number variable
+ * APP_TIMER_SCHED_EVENT_DATA_SIZE => App timer event
+ */
+#define APP_SCHED_EVENT_SIZE        MAX(sizeof(uint8_t), APP_TIMER_SCHED_EVENT_DATA_SIZE)
+#define APP_SCHED_QUEUE_SIZE        (50)
+
+#define APP_MAIN_AUTO_OFF_FACTOR    (1000)
+#define LED_OFF                     (0)
+
 static bool m_device_provisioned;
 
 /*************************************************************************************************/
@@ -147,6 +158,14 @@ static void button_event_handler(uint32_t button_number)
             break;
         }
 
+        /* Demonstration: Send a delayed status message */
+        case 1:
+        {
+            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Sending delayed response \n");
+            app_onoff_delayed_status_reply(&m_onoff_server_0);
+            break;
+        }
+
         /* Initiate node reset */
         case 3:
         {
@@ -171,6 +190,21 @@ static void button_event_handler(uint32_t button_number)
     }
 }
 
+static void button_event_handler_app_sched(void * p_event_data, uint16_t event_size)
+{
+    uint8_t * button_number = (uint8_t *) p_event_data;
+    NRF_MESH_ASSERT(event_size == 1);
+    button_event_handler(*button_number);
+}
+
+static void button_event_handler_irq(uint32_t button_number)
+{
+    static uint8_t bt_num;
+
+    bt_num = button_number;
+    app_sched_event_put((void *)&bt_num, sizeof(bt_num), button_event_handler_app_sched);
+}
+
 static void app_rtt_input_handler(int key)
 {
     if (key >= '0' && key <= '4')
@@ -223,7 +257,8 @@ static void mesh_init(void)
 {
     mesh_stack_init_params_t init_params =
     {
-        .core.irq_priority       = NRF_MESH_IRQ_PRIORITY_LOWEST,
+        .core.irq_priority       = NRF_MESH_IRQ_PRIORITY_THREAD,
+        //.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,
@@ -241,7 +276,7 @@ static void initialize(void)
     hal_leds_init();
 
 #if BUTTON_BOARD
-    ERROR_CHECK(hal_buttons_init(button_event_handler));
+    ERROR_CHECK(hal_buttons_init(button_event_handler_irq));
 #endif
 
     ble_stack_init();
@@ -283,11 +318,27 @@ static void start(void)
 
 int main(void)
 {
+    APP_SCHED_INIT(APP_SCHED_EVENT_SIZE, APP_SCHED_QUEUE_SIZE);
     initialize();
     start();
 
+    int i = 0;
     for (;;)
     {
-        (void)sd_app_evt_wait();
+        app_sched_execute();
+
+        bool done = nrf_mesh_process();
+        if (done)
+        {
+            (void)sd_app_evt_wait();
+        }
+        /* Demonstrate sending of messages from main loop, by automatically turning off the LED
+         * after few iterations. */
+        i++;
+        if ((i % APP_MAIN_AUTO_OFF_FACTOR) == 0)
+        {
+            hal_led_pin_set(ONOFF_SERVER_0_LED, LED_OFF);
+            app_onoff_status_publish(&m_onoff_server_0);
+        }
     }
 }
diff --git a/models/model_spec/generic_onoff/include/generic_onoff_server.h b/models/model_spec/generic_onoff/include/generic_onoff_server.h
index 5692ae6bb..11588f56c 100644
--- a/models/model_spec/generic_onoff/include/generic_onoff_server.h
+++ b/models/model_spec/generic_onoff/include/generic_onoff_server.h
@@ -126,6 +126,9 @@ struct __generic_onoff_server_t
 
     /** Model settings and callbacks for this instance. */
     generic_onoff_server_settings_t settings;
+
+    /** Holding variable for the access metadata for previously received message */
+    access_message_rx_meta_t last_access_meta;
 };
 
 /**
@@ -154,5 +157,20 @@ uint32_t generic_onoff_server_init(generic_onoff_server_t * p_server, uint8_t el
  */
 uint32_t generic_onoff_server_status_publish(generic_onoff_server_t * p_server, const generic_onoff_status_params_t * p_params);
 
+/**
+ * Publishes a delayed status message.
+ *
+ * This function can be used to publish a repeat delayed status message after user application has
+ * finished any custom processing on the received state value. This function will inturn fetch the
+ * current onoff state using get_cb callback.
+ *
+ * @param[in]     p_server                 Status server context pointer.
+ * @param[in]     p_params                 Message parameters.
+ *
+ */
+uint32_t generic_onoff_server_delayed_status_send(generic_onoff_server_t * p_server,
+                                                  const generic_onoff_status_params_t * p_params);
+
+
 /**@} end of GENERIC_ONOFF_SERVER */
 #endif /* GENERIC_ONOFF_SERVER_H__ */
diff --git a/models/model_spec/generic_onoff/src/generic_onoff_server.c b/models/model_spec/generic_onoff/src/generic_onoff_server.c
index 2448a9ad4..2cb7af275 100644
--- a/models/model_spec/generic_onoff/src/generic_onoff_server.c
+++ b/models/model_spec/generic_onoff/src/generic_onoff_server.c
@@ -137,6 +137,7 @@ static void handle_set(access_model_handle_t model_handle, const access_message_
                 __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Server: delay_ms = %X\n", in_data_tr.delay_ms);
             }
 
+            p_server->last_access_meta = p_rx_msg->meta_data;
             p_server->settings.p_callbacks->onoff_cbs.set_cb(p_server,
                                                             &p_rx_msg->meta_data,
                                                             &in_data,
@@ -163,6 +164,7 @@ static void handle_get(access_model_handle_t model_handle, const access_message_
 
     if (get_params_validate(p_rx_msg))
     {
+        p_server->last_access_meta = p_rx_msg->meta_data;
         p_server->settings.p_callbacks->onoff_cbs.get_cb(p_server, &p_rx_msg->meta_data, &out_data);
         (void) status_send(p_server, p_rx_msg, &out_data);
     }
@@ -217,3 +219,18 @@ uint32_t generic_onoff_server_status_publish(generic_onoff_server_t * p_server,
 
     return status_send(p_server, NULL, p_params);
 }
+
+uint32_t generic_onoff_server_delayed_status_send(generic_onoff_server_t * p_server,
+                                                  const generic_onoff_status_params_t * p_params)
+{
+    if (p_server == NULL ||
+        p_params == NULL)
+    {
+        return NRF_ERROR_NULL;
+    }
+
+    access_message_rx_t rx_message_ctx;
+
+    rx_message_ctx.meta_data = p_server->last_access_meta;
+    return status_send(p_server, &rx_message_ctx, p_params);
+}
\ No newline at end of file
-- 
2.17.1.windows.2

